diff --git a/.github/workflows/dashboards-observability-test-and-build-workflow.yml b/.github/workflows/dashboards-observability-test-and-build-workflow.yml index 608f6d1fb..4921cdbd4 100644 --- a/.github/workflows/dashboards-observability-test-and-build-workflow.yml +++ b/.github/workflows/dashboards-observability-test-and-build-workflow.yml @@ -6,13 +6,15 @@ on: [pull_request, push] env: PLUGIN_NAME: dashboards-observability OPENSEARCH_VERSION: 'main' - OPENSEARCH_PLUGIN_VERSION: 2.0.0.0 + OPENSEARCH_PLUGIN_VERSION: 3.0.0.0 jobs: build: - - runs-on: ubuntu-latest + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} steps: - name: Checkout Plugin @@ -57,13 +59,13 @@ jobs: yarn test --coverage - name: Upload coverage + if: ${{ matrix.os == 'ubuntu-latest' }} uses: codecov/codecov-action@v1 with: flags: dashboards-observability directory: ./OpenSearch-Dashboards/plugins/dashboards-observability token: ${{ secrets.CODECOV_TOKEN }} - # TODO remove hard coded version when observability is ready - name: Build Artifact run: | cd OpenSearch-Dashboards/plugins/dashboards-observability @@ -73,6 +75,5 @@ jobs: - name: Upload Artifact uses: actions/upload-artifact@v1 with: - name: dashboards-observability - path: ./OpenSearch-Dashboards/plugins/dashboards-observability/build - + name: dashboards-observability-${{ matrix.os }} + path: ./OpenSearch-Dashboards/plugins/dashboards-observability/build \ No newline at end of file diff --git a/.github/workflows/opensearch-observability-test-and-build-workflow.yml b/.github/workflows/opensearch-observability-test-and-build-workflow.yml index 5990f2b8e..9d70144f3 100644 --- a/.github/workflows/opensearch-observability-test-and-build-workflow.yml +++ b/.github/workflows/opensearch-observability-test-and-build-workflow.yml @@ -4,13 +4,18 @@ on: [pull_request, push] jobs: build: + env: + BUILD_ARGS: ${{ matrix.os_build_args }} strategy: matrix: - java: - - 11 - - 17 - - runs-on: ubuntu-latest + java: [11, 17] + os: [ubuntu-latest, windows-latest, macos-latest] + include: + - os: windows-latest + os_build_args: -x integTest -x jacocoTestReport + - os: macos-latest + os_build_args: -x integTest -x jacocoTestReport + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 @@ -21,6 +26,8 @@ jobs: java-version: ${{ matrix.java }} - name: Run Backwards Compatibility Tests + # Temporarily only do this for linux + if: ${{ matrix.os == 'ubuntu-latest' }} run: | cd opensearch-observability echo "Running backwards compatibility tests ..." @@ -29,9 +36,10 @@ jobs: - name: Build with Gradle run: | cd opensearch-observability - ./gradlew build + ./gradlew build ${{ env.BUILD_ARGS }} - name: Upload coverage + if: ${{ matrix.os == 'ubuntu-latest' }} uses: codecov/codecov-action@v1 with: flags: opensearch-observability @@ -46,5 +54,5 @@ jobs: - name: Upload Artifacts uses: actions/upload-artifact@v1 with: - name: opensearch-observability - path: opensearch-observability-builds + name: opensearch-observability-${{ matrix.os }} + path: opensearch-observability-builds \ No newline at end of file diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 7a1fde32a..d9a257399 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -14,14 +14,13 @@ By default, tests use the same runtime as `JAVA_HOME`. ### Setup -1. Download OpenSearch for the version that matches the [OpenSearch Dashboards version specified in package.json](./dashboards-observability/package.json#L5). -1. Download the OpenSearch Dashboards source code for the [version specified in package.json](./dashboards-observability/package.json#L5) you want to set up. - +1. Download OpenSearch for the version that matches the [OpenSearch Dashboards version specified in opensearch_dashboards.json](./dashboards-observability/opensearch_dashboards.json#L4) from [opensearch.org](https://opensearch.org/downloads.html). +1. Download the OpenSearch Dashboards source code for the [version specified in opensearch_dashboards.json](./dashboards-observability/opensearch_dashboards.json#L4) you want to set up. 1. Change your node version to the version specified in `.node-version` inside the OpenSearch Dashboards root directory. -1. cd into `plugins` directory in the OpenSearch Dashboards source code directory. -1. Check out this package from version control into the `plugins` directory. +1. cd into `OpenSearch-Dashboards` and remove the `plugins` directory. +1. Check out this package from version control as the `plugins` directory. ```bash -git clone git@github.com:opensearch-project/observability.git plugins --no-checkout +git clone https://github.com/opensearch-project/observability plugins --no-checkout cd plugins echo 'dashboards-observability/*' >> .git/info/sparse-checkout git config core.sparseCheckout true @@ -46,9 +45,7 @@ Example output: `./build/observability*.zip` ### Run -- `yarn start` - - Starts OpenSearch Dashboards and includes this plugin. OpenSearch Dashboards will be available on `localhost:5601`. +cd back to `OpenSearch-Dashboards` directory and run `yarn start` to start OpenSearch Dashboards including this plugin. OpenSearch Dashboards will be available on `localhost:5601`. ### Submitting Changes @@ -60,4 +57,4 @@ The Github workflow in [`backport.yml`](.github/workflows/backport.yml) creates with an appropriate label `backport ` is merged to main with the backport workflow run successfully on the PR. For example, if a PR on main needs to be backported to `1.x` branch, add a label `backport 1.x` to the PR and make sure the backport workflow runs on the PR along with other checks. Once this PR is merged to main, the workflow will create a backport PR -to the `1.x` branch. \ No newline at end of file +to the `1.x` branch. diff --git a/README.md b/README.md index 87feb1c1e..ed0aa2544 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ See [developer guide](DEVELOPER_GUIDE.md) and [how to contribute to this project If you find a bug, or have a feature request, please don't hesitate to open an issue in this repository. -For more information, see [project website](https://opensearch.org/) and [documentation](https://opensearch.org/docs). If you need help and are unsure where to open an issue, try [forums](https://discuss.opendistrocommunity.dev/). +For more information, see [project website](https://opensearch.org/) and [documentation](https://opensearch.org/docs). If you need help and are unsure where to open an issue, try the [Forum](https://forum.opensearch.org/c/plugins/observability/49). ## Code of Conduct diff --git a/dashboards-observability/.cypress/integration/event_analytics.spec.js b/dashboards-observability/.cypress/integration/1_event_analytics.spec.js similarity index 53% rename from dashboards-observability/.cypress/integration/event_analytics.spec.js rename to dashboards-observability/.cypress/integration/1_event_analytics.spec.js index 981b10b53..3f43a6eb7 100644 --- a/dashboards-observability/.cypress/integration/event_analytics.spec.js +++ b/dashboards-observability/.cypress/integration/1_event_analytics.spec.js @@ -17,10 +17,68 @@ import { landOnEventHome, landOnEventExplorer, landOnEventVisualizations, - landOnPanels + landOnPanels, + renderTreeMapchart, + renderPieChart, + renderLineChartForDataConfig, + renderDataConfig, + aggregationValues, + DataConfigLineChart, + renderAddParent, + renderGaugeChart, + renderAddParent } from '../utils/event_constants'; import { supressResizeObserverIssue } from '../utils/constants'; +const renderHistogramChart = () => { + querySearch(TEST_QUERIES[5].query, TEST_QUERIES[5].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').type('Histogram').type('{enter}'); + cy.wait(delay); + cy.get('g.draglayer.cursor-crosshair').should('exist'); + cy.get('#configPanel__panelOptions .euiFieldText').click().type('Histogram chart'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]').click().type('This is the description for Histogram chart'); + cy.get('.euiIEFlexWrapFix').eq(1).contains('Chart Styles').should('exist'); + cy.get('.euiFormLabel.euiFormRow__label').eq(2).contains('Bucket Size'); + cy.get('.euiFieldNumber').eq(0).type('4'); + cy.get('.euiFormLabel.euiFormRow__label').eq(3).contains('Bucket Offset'); + cy.get('.euiFieldNumber').eq(0).type('6'); +}; + +const vis_name_sub_string = Math.floor(Math.random() * 100); +const saveVisualizationAndVerify = () => { + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').click(); + cy.get('.euiComboBoxOptionsList__rowWrap .euiFilterSelectItem').eq(0).click(); + cy.get( + '.euiPopover__panel .euiFormControlLayoutIcons [data-test-subj="comboBoxToggleListButton"]' + ) + .eq(0) + .click(); + cy.get('.euiPopover__panel input') + .eq(1) + .type(`Test visualization` + vis_name_sub_string); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.wait(delay); + cy.get('.euiHeaderBreadcrumbs a').eq(1).click(); + cy.get('.euiFlexGroup .euiFormControlLayout__childrenWrapper input') + .eq(0) + .type(`Test visualization` + vis_name_sub_string) + .type('{enter}'); + cy.get('.euiBasicTable .euiTableCellContent button').eq(0).click(); +}; +const deleteVisualization = () => { + cy.get('a[href = "#/event_analytics"]').click(); + cy.get('.euiFlexGroup .euiFormControlLayout__childrenWrapper input') + .eq(0) + .type(`Test visualization`) + .type('{enter}'); + cy.get('input[data-test-subj = "checkboxSelectAll"]').click(); + cy.get('.euiButtonContent.euiButtonContent--iconRight.euiButton__content').click(); + cy.get('.euiContextMenuItem .euiContextMenuItem__text').eq(0).click(); + cy.get('input[placeholder = "delete"]').clear().type('delete'); + cy.get('button[data-test-subj = "popoverModal__deleteButton"]').click(); + cy.get('.euiToastHeader').should('exist'); +}; describe('Adding sample data and visualization', () => { it('Adds sample flights data for event analytics', () => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`); @@ -35,13 +93,13 @@ describe('Has working breadcrumbs', () => { it('Redirect to correct page on breadcrumb click', () => { landOnEventExplorer(); cy.wait(delay * 3); - cy.get('.euiBreadcrumb').contains('Explorer').click(); + cy.get('.euiBreadcrumb[href="#/event_analytics/explorer"]').contains('Explorer').click(); cy.wait(delay); cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('exist'); - cy.get('.euiBreadcrumb').contains('Event analytics').click(); + cy.get('.euiBreadcrumb[href="#/event_analytics"]').contains('Event analytics').click(); cy.wait(delay); cy.get('.euiTitle').contains('Event analytics').should('exist'); - cy.get('.euiBreadcrumb').contains('Observability').click(); + cy.get('.euiBreadcrumb[href="observability-dashboards#/"]').contains('Observability').click(); cy.wait(delay); cy.get('.euiTitle').contains('Event analytics').should('exist'); }); @@ -55,11 +113,14 @@ describe('Search a query on event home', () => { cy.get('[data-test-subj="superDatePickerToggleQuickMenuButton"]').click(); cy.get('[data-test-subj="superDatePickerCommonlyUsed_Year_to date"]').click(); cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click(); - cy.window().its('store').invoke('getState').then((state) => { - expect(Object.values(state.queries)[0]['rawQuery'].trim()).equal(TEST_QUERIES[0].query) - expect(Object.values(state.queries)[0]['selectedDateRange'][0]).equal("now/y"); - expect(Object.values(state.queries)[0]['selectedDateRange'][1]).equal("now"); - }); + cy.window() + .its('store') + .invoke('getState') + .then((state) => { + expect(Object.values(state.queries)[0]['rawQuery'].trim()).equal(TEST_QUERIES[0].query); + expect(Object.values(state.queries)[0]['selectedDateRange'][0]).equal('now/y'); + expect(Object.values(state.queries)[0]['selectedDateRange'][1]).equal('now'); + }); cy.wait(delay); cy.url().should('contain', '#/event_analytics/explorer'); @@ -76,16 +137,26 @@ describe('Open flyout for a data row to see details', () => { it('Should be able to open flyout and see data, json and traces', () => { cy.get('[data-test-subj="docTable"] tbody tr button.euiButtonIcon').first().click(); cy.get('.observability-flyout').should('exist'); - cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content').contains('JSON').click(); - cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content').contains('Traces').click(); - cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content').contains('Table').click(); + cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content') + .contains('JSON') + .click(); + cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content') + .contains('Traces') + .click(); + cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content') + .contains('Table') + .click(); }); it('Should be able to see srrounding docs', () => { cy.get('[data-test-subj="docTable"] tbody tr button.euiButtonIcon').first().click(); cy.get('.observability-flyout').should('exist'); - cy.get('.observability-flyout span.euiButton__text').contains('View surrounding events').click(); - cy.get('.observability-flyout #surroundingFyout').contains('View surrounding events').should('exist'); + cy.get('.observability-flyout span.euiButton__text') + .contains('View surrounding events') + .click(); + cy.get('.observability-flyout #surroundingFyout') + .contains('View surrounding events') + .should('exist'); }); }); @@ -252,7 +323,9 @@ describe('Saves a query on explorer page', () => { cy.get('button[id="main-content-vis"]').contains('Visualizations').click(); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); cy.wait(delay * 2); - cy.get('[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]').click(); + cy.get( + '[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]' + ).click(); cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(SAVE_QUERY2); cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); cy.wait(delay * 2); @@ -282,11 +355,15 @@ describe('Saves a query on explorer page', () => { cy.get('button[id="main-content-vis"]').contains('Visualizations').click(); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); cy.wait(delay * 2); - cy.get('[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]').click(); + cy.get( + '[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]' + ).click(); cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(SAVE_QUERY3); cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').type(TESTING_PANEL); cy.get(`input[value="${TESTING_PANEL}"]`).click(); - cy.get('[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]').click(); + cy.get( + '[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]' + ).click(); cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); cy.wait(delay); @@ -305,8 +382,11 @@ describe('Override timestamp for an index', () => { cy.wait(delay); cy.get('[data-attr-field="utc_time"] [data-test-subj="eventFields__default-timestamp-mark"') - .contains('Default Timestamp').should('exist'); - cy.get('[data-attr-field="timestamp"] [data-test-subj="eventFields__default-timestamp-mark"').should('not.exist'); + .contains('Default Timestamp') + .should('exist'); + cy.get( + '[data-attr-field="timestamp"] [data-test-subj="eventFields__default-timestamp-mark"' + ).should('not.exist'); }); }); @@ -369,20 +449,40 @@ describe('Click to view field insights', () => { it('Click a numerical field to view field insights', () => { cy.get('[data-test-subj="field-bytes-showDetails"]').click(); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Top values').should('exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Rare values').should('exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Average overtime').should('exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Maximum overtime').should('exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Minimum overtime').should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Top values') + .should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Rare values') + .should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Average overtime') + .should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Maximum overtime') + .should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Minimum overtime') + .should('exist'); }); it('Click a non-numerical field to view insights', () => { cy.get('[data-test-subj="field-host-showDetails"]').click(); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Top values').should('exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Rare values').should('exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Average overtime').should('not.exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Maximum overtime').should('not.exist'); - cy.get('[data-test-subj="sidebarField__fieldInsights"] button').contains('Minimum overtime').should('not.exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Top values') + .should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Rare values') + .should('exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Average overtime') + .should('not.exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Maximum overtime') + .should('not.exist'); + cy.get('[data-test-subj="sidebarField__fieldInsights"] button') + .contains('Minimum overtime') + .should('not.exist'); }); }); @@ -426,8 +526,8 @@ describe('Live tail stop automatically', () => { cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]') .find('button.euiTab') .should('have.length', initialLength + 1); + }); }); -}); it('Click to switch to another tab', () => { cy.get('[data-test-subj="eventExplorer__addNewTab"]').click(); @@ -469,7 +569,9 @@ describe('Renders noresult chart', () => { }); it('It should render no result when there is no data', () => { - cy.get('[data-test-subj="vizWorkspace__noData"] p').contains('No results found').should('exist'); + cy.get('[data-test-subj="vizWorkspace__noData"] p') + .contains('No results found') + .should('exist'); }); }); @@ -480,7 +582,9 @@ describe('Renders bar charts', () => { it('Renders vertical bar chart', () => { querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); - cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get( + '[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]' + ).click(); cy.wait(delay * 2); cy.get('[data-test-subj="comboBoxOptionsList "] span').contains('Bar').click(); cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]').first().click(); @@ -497,12 +601,16 @@ describe('Renders bar charts', () => { cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Group').click(); cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); cy.wait(delay * 2); - cy.get('g.xaxislayer-above > g.xtick text[data-unformatted|="artifacts.opensearch.org"]').should('exist'); + cy.get( + 'g.xaxislayer-above > g.xtick text[data-unformatted|="artifacts.opensearch.org"]' + ).should('exist'); }); it('Renders horiztontal bar chart', () => { querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); - cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get( + '[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]' + ).click(); cy.wait(delay * 2); cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Bar').click(); cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]').first().click(); @@ -519,7 +627,9 @@ describe('Renders bar charts', () => { cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Group').click(); cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); cy.wait(delay * 2); - cy.get('g.yaxislayer-above > g.ytick text[data-unformatted|="artifacts.opensearch.org"]').should('exist'); + cy.get( + 'g.yaxislayer-above > g.ytick text[data-unformatted|="artifacts.opensearch.org"]' + ).should('exist'); }); }); @@ -530,7 +640,9 @@ describe('Renders line charts', () => { it('Renders line chart with threshold', () => { querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); - cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get( + '[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]' + ).click(); cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Line').click(); cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]').first().click(); cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('host').click(); @@ -544,7 +656,9 @@ describe('Renders line charts', () => { cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); cy.wait(delay * 2); cy.get('g.text > g.textpoint text[data-unformatted|="Max"]').should('exist'); - cy.get('g.xaxislayer-above > g.xtick text[data-unformatted|="artifacts.opensearch.org"]').should('exist'); + cy.get( + 'g.xaxislayer-above > g.xtick text[data-unformatted|="artifacts.opensearch.org"]' + ).should('exist'); }); }); @@ -555,7 +669,9 @@ describe('Renders pie charts', () => { it('Renders pie chart', () => { querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); - cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get( + '[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]' + ).click(); cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Pie').click(); cy.wait(delay); cy.get('g.pielayer').should('exist'); @@ -569,7 +685,9 @@ describe('Renders heatmap chart', () => { it('Renders heatmap chart with different z-axes', () => { querySearch(TEST_QUERIES[4].query, TEST_QUERIES[4].dateRangeDOM); - cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get( + '[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]' + ).click(); cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Heatmap').click(); cy.wait(delay * 2); cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]').click(); @@ -593,13 +711,17 @@ describe('Renders markdown chart', () => { it('Renders markdown chart with test title', () => { querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); - cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get( + '[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]' + ).click(); cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Text').click(); cy.get('[data-test-subj="workspace__viz_markdown"] h2').contains('Text').should('exist'); cy.get('textarea.euiMarkdownEditorTextArea').type('## testing title'); cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); cy.wait(delay * 2); - cy.get('[data-test-subj="workspace__viz_markdown"] h2').contains('testing title').should('exist'); + cy.get('[data-test-subj="workspace__viz_markdown"] h2') + .contains('testing title') + .should('exist'); }); }); @@ -615,4 +737,302 @@ describe('Renders data view', () => { cy.get('[data-test-subj="workspace__dataTableViewSwitch"]').click(); cy.get('[data-test-subj="workspace__dataTable"]').should('not.exist'); }); -}); \ No newline at end of file +}); + +describe('Renders chart and verify Toast message if X-axis and Y-axis values are empty', () => { + beforeEach(() => { + landOnEventVisualizations(); + }); + it('Renders chart, clear X-axis and Y-axis value and click on Apply button, Toast message should display with error message', () => { + querySearch(TEST_QUERIES[4].query, TEST_QUERIES[4].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Bar') + .type('{enter}'); + cy.wait(delay); + cy.get('#configPanel__value_options [data-test-subj="comboBoxClearButton"]') + .eq(0) + .click({ force: true }); + cy.get('#configPanel__value_options [data-test-subj="comboBoxToggleListButton"]').eq(0).click(); + cy.wait(delay); + cy.get('#configPanel__value_options [data-test-subj="comboBoxClearButton"]').click({ + multiple: true, + }); + cy.get('#configPanel__value_options [data-test-subj="comboBoxToggleListButton"]').eq(1).click(); + cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]') + .eq(0) + .should('have.value', ''); + cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]') + .eq(1) + .should('have.value', ''); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); + cy.get('[data-test-subj="euiToastHeader"]') + .contains('Invalid value options configuration selected.') + .should('exist'); + }); + + it('Renders chart, clear X-axis and Y-axis value and try to save visulization, Toast message should display with error message', () => { + querySearch(TEST_QUERIES[4].query, TEST_QUERIES[4].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Bar') + .type('{enter}'); + cy.wait(delay); + cy.get('#configPanel__value_options [data-test-subj="comboBoxClearButton"]') + .eq(0) + .click({ force: true }); + cy.get('#configPanel__value_options [data-test-subj="comboBoxToggleListButton"]').eq(0).click(); + cy.wait(delay); + cy.get('#configPanel__value_options [data-test-subj="comboBoxClearButton"]').click({ + multiple: true, + }); + cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]') + .eq(0) + .should('have.value', ''); + cy.get('#configPanel__value_options [data-test-subj="comboBoxInput"]') + .eq(1) + .should('have.value', ''); + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').click(); + cy.get('.euiComboBoxOptionsList__rowWrap .euiFilterSelectItem').eq(0).click(); + cy.get( + '.euiPopover__panel .euiFormControlLayoutIcons [data-test-subj="comboBoxToggleListButton"]' + ) + .eq(0) + .click(); + cy.get('.euiPopover__panel input').eq(1).type(`Test visulization_`); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.get('[data-test-subj="euiToastHeader"]') + .contains('Invalid value options configuration selected.') + .should('exist'); + }); +}); + +describe('Render Table View', () => { + beforeEach(() => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); + cy.get('[data-test-subj="workspace__dataTableViewSwitch"]').click(); + }); + + it('Switch visualization for table view and verify table data', () => { + cy.get('.ag-header-cell-text').contains('max(AvgTicketPrice)').should('exist'); + cy.get('.ag-header-cell-text').contains('DestCountry').should('exist'); + cy.get('.ag-header-cell-text').contains('DestCityName').should('exist'); + cy.get('.ag-header-cell-text').contains('Carrier').should('exist'); + }); + + it('Switch visualization for table view and change data table density', () => { + cy.get('.euiButtonEmpty__text').contains('Density').click(); + cy.get('.euiButtonIcon.euiButtonIcon--primary.euiButtonIcon--xSmall').eq(1).click(); + cy.get('.euiButtonIcon.euiButtonIcon--primary.euiButtonIcon--xSmall').eq(2).click(); + }); + + it('Switch visualization for table view and show and hide column', () => { + cy.get('.euiButtonEmpty__text').contains('Columns').click(); + cy.get('.euiSwitch__label').contains('DestCountry').click(); + cy.get('.ag-header-cell-text').contains('DestCountry').should('not.exist'); + cy.get('.euiSwitch__label').contains('Carrier').click(); + cy.get('.ag-header-cell-text').contains('Carrier').should('not.exist'); + cy.get('.euiSwitch__label').contains('DestCountry').click(); + cy.get('.ag-header-cell-text').contains('DestCountry').should('exist'); + }); + + it('Switch visualization for table view and see data in full screen', () => { + cy.get('.ag-header-cell-text').contains('max(AvgTicketPrice)').should('exist'); + cy.get('.ag-header-cell-text').contains('DestCountry').should('exist'); + cy.get('.ag-header-cell-text').contains('DestCityName').should('exist'); + cy.get('.ag-header-cell-text').contains('Carrier').should('exist'); + cy.get('.euiButtonEmpty__text').contains('Full screen').click(); + cy.wait(delay); + cy.get('body').type('{esc}'); + cy.wait(delay); + }); + + it('Switch visualization for table view and sort the column data', () => { + cy.get('.ag-header-cell-text').contains('max(AvgTicketPrice)').click(); + cy.get('.ag-cell-value').contains('125.49737').should('exist'); + cy.get('.ag-header-cell-text').contains('max(AvgTicketPrice)').click(); + cy.get('.ag-cell-value').contains('1199.729').should('exist'); + cy.get('.ag-header-cell-text').contains('DestCountry').click(); + cy.get('.ag-cell-value').contains('AE').should('exist'); + }); + + it('Switch visualization for table view and verify pagination link', () => { + cy.get('[aria-label="Next page"]').click(); + cy.get('.ag-cell-value').contains('Vienna').should('exist'); + cy.get('[aria-label="Previous page"]').click(); + cy.get('.ag-cell-value').contains('Dubai').should('exist'); + cy.get('[aria-label="Page 4"]').contains('4').click(); + cy.get('.ag-cell-value').contains('Edmonton').should('exist'); + }); + it('Switch visualization for table view and rows per page data', () => { + cy.get('.euiButtonEmpty__text').eq('6').click(); + cy.get('.euiContextMenuItem__text').eq(1).click(); + }); +}); + +describe('Render Time series chart/Line chart and verify Data configurations UI ', () => { + it('Render line chart and verify Data Configuration Panel', () => { + renderLineChartForDataConfig(); + DataConfigLineChart(); + }); +}); + +describe('Renders Data Configurations section for Pie chart', () => { + beforeEach(() => { + landOnEventVisualizations(); + }); + + it('Renders Dimensions and Metrics under Data Configurations for Pie chart', () => { + renderPieChart(); + renderDataConfig(); + }); + + it('Validate "Add" and "X" buttons', () => { + renderPieChart(); + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Configurations'); + cy.get('.euiButton.euiButton--primary.euiButton--fullWidth').contains('Add').click(); + cy.get('.euiFormRow__fieldWrapper .euiComboBox').eq(3).click(); + cy.get('.euiComboBoxOption__content').eq(2).click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(4).click(); + cy.get('.euiComboBoxOption__content').eq(1).click(); + cy.get('.euiFieldText[placeholder="Custom label"]').eq(1).type('Demo field'); + cy.get('.euiIcon.euiIcon--medium.euiIcon--danger').eq(1).click(); + cy.get('.euiButton.euiButton--primary.euiButton--fullWidth').contains('Add').should('exist'); + }); + + it('Verify drop down values for Aggregation', () => { + renderPieChart(); + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Configurations'); + cy.get('.euiTitle.euiTitle--xxsmall').eq(1).contains('Dimensions').should('exist'); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(0).contains('Aggregation'); + cy.get('[data-test-subj="comboBoxSearchInput"]').eq(0).click(); + aggregationValues.forEach(function (value){ + cy.get('.euiComboBoxOption__content').contains(value); + }); + }); + + it('Collapsible mode for Data Configuration panel', () => { + renderPieChart(); + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Configurations'); + cy.get('.euiResizableButton.euiResizableButton--horizontal').eq(1).click(); + cy.get('[data-test-subj="panel-1-toggle"]').click(); + cy.get('[class*="euiResizableToggleButton-isCollapsed"]').eq(1).should('exist'); +describe('Renders Histogram chart', () => { + beforeEach(() => { + landOnEventVisualizations(); +}); + +it('Renders Histogram chart and save visualization', () => { + renderHistogramChart(); + cy.get('.euiFlexItem.euiFlexItem--flexGrowZero .euiButton__text').eq(2).click(); + cy.wait(delay); + saveVisualizationAndVerify(); + }); + + it('Delete Visualization for Histogram chart from list of saved Visualizations on Event analytics page', () =>{ + deleteVisualization(); + }) + + it('Renders Histogram chart, add value parameters and verify Reset button click is working', () => { + renderHistogramChart(); + cy.get('[data-test-subj="visualizeEditorResetButton"]').click(); + }); +}); +describe('Render Gauge Chart and verify if data gets render', () => { + it('Render gauge chart and verify by default no data gets render', () => { + renderGaugeChart(); + cy.get('.main-svg').contains('BeatsWest').should('not.exist'); + }); + + it('Render gauge chart and verify data gets render after click on update chart', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.main-svg').contains('BeatsWest').should('exist'); + }); +}); + +describe('Render Gauge Chart and work with chart styles', () => { + it('Render gauge chart and change orientation to vertical', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiButton__text').contains('Vertical').click(); + cy.get('.euiButton__text').contains('Preview').click(); + }); + + it('Render gauge chart and change title size then verify the update on chart', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).type('30'); + cy.get('.euiButton__text').contains('Preview').click(); + }); + + it('Render gauge chart and change value size then verify the update on chart', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).type('20'); + cy.get('.euiButton__text').contains('Preview').click(); + }); +}); + +describe('Render Gauge Chart and work with threshold', () => { + it('Render gauge chart and add threshold then verify by default the threshold is not seen', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiButton__text').contains('+ Add threshold').click(); + cy.get('[data-test-subj="nameFieldText"]').type('Gauge Threshold'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(2).type('50'); + cy.get('.euiButton__text').contains('Preview').click(); + cy.get('[data-unformatted="Gauge Threshold"]').should('not.be.visible'); + }); + + it('Render gauge chart and add threshold then verify the threshold label are seen after show threshold button enabled ', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiButton__text').contains('+ Add threshold').click(); + cy.get('[data-test-subj="nameFieldText"]').type('Gauge Threshold'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(2).type('50'); + cy.get('.euiSwitch__label').contains('Show threshold labels').click(); + cy.get('.euiButton__text').contains('Preview').click(); + cy.get('[data-unformatted="Gauge Threshold"]').should('be.visible'); + }); + + it('Render gauge chart and add threshold then verify the threshold marker are seen after show threshold button enabled ', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiButton__text').contains('+ Add threshold').click(); + cy.get('[data-test-subj="nameFieldText"]').type('Gauge Threshold'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(2).type('50'); + cy.get('.euiSwitch__label').contains('Show threshold markers').click(); + cy.get('.euiButton__text').contains('Preview').click(); + cy.get('path[style*="rgb(252, 5, 5)"]').eq(1).should('exist'); + cy.get('.bg-arc').find('path[style*="rgb(252, 5, 5)"]').should('have.length',4); + }); +}); + +describe('Render gauge chart and verify if reset works properly', () => { + it('Render gauge chart with all feild data then click on reset and verify reset works properly', () => { + renderGaugeChart(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('input[placeholder="Title"]').type('Gauge Chart'); + cy.get('textarea[placeholder="Description"]').type('Description For Gauge Chart'); + cy.get('.euiButton__text').contains('Vertical').click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).type('30'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).type('20'); + cy.get('.euiButton__text').contains('+ Add threshold').click(); + cy.get('[data-test-subj="nameFieldText"]').type('Gauge Threshold'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(2).type('50'); + cy.get('.euiSwitch__label').contains('Show threshold labels').click(); + cy.get('.euiSwitch__label').contains('Show threshold markers').click(); + cy.get('.euiButton__text').contains('Preview').click(); + cy.get('.euiButtonEmpty__text').contains('Reset').click(); + cy.get('input[placeholder="Title"]').should('not.have.value','Gauge Chart'); + cy.get('textarea[placeholder="Description"]').should('not.have.value','Description For Gauge Chart') + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).should('have.value',''); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).should('have.value',''); + cy.get('button.euiSwitch__button[aria-checked="false"]').should('exist').should('have.length',3); + }); +}); diff --git a/dashboards-observability/.cypress/integration/notebooks.spec.js b/dashboards-observability/.cypress/integration/2_notebooks.spec.js similarity index 91% rename from dashboards-observability/.cypress/integration/notebooks.spec.js rename to dashboards-observability/.cypress/integration/2_notebooks.spec.js index ca0083249..3ba071215 100644 --- a/dashboards-observability/.cypress/integration/notebooks.spec.js +++ b/dashboards-observability/.cypress/integration/2_notebooks.spec.js @@ -12,6 +12,8 @@ import { SAMPLE_URL, SQL_QUERY_TEXT, PPL_QUERY_TEXT, + NOTEBOOK_TEXT, + OPENSEARCH_URL, } from '../utils/constants'; import { SAMPLE_PANEL } from '../utils/panel_constants'; @@ -63,6 +65,13 @@ describe('Testing notebooks table', () => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/notebooks`); }); + it('Notebooks table empty state', () => { + cy.get('#notebookArea').contains('Notebooks (0)').should('exist'); + cy.get('.euiTextAlign.euiTextAlign--center').contains('No notebooks'); + cy.get('.euiButton__text').eq(2).contains('Create notebook'); + cy.get('.euiButton__text').eq(3).contains('Add samples'); + }); + it('Displays error toast for invalid notebook name', () => { cy.get('.euiButton__text').contains('Create notebook').click(); cy.wait(delay); @@ -125,6 +134,21 @@ describe('Testing notebooks table', () => { .should('exist'); }); + it('Notebooks table columns headers and pagination', () => { + cy.get('.euiTitle.euiTitle--small').contains('Notebooks').should('exist'); + cy.get('.euiTableCellContent__text[title="Name"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Last updated"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Created"]').should('exist'); + cy.get('[data-test-subj="tablePaginationPopoverButton"]').should('exist'); + }); + + it('"Learn more" link under Notebooks header', () => { + cy.get('.euiTitle.euiTitle--small').contains('Notebooks'); + cy.get('.euiTextColor.euiTextColor--subdued').contains(NOTEBOOK_TEXT); + cy.get('a.euiLink.euiLink--primary').contains('Learn more').click(); + cy.get(`a[href="${OPENSEARCH_URL}"]`).should('exist'); + }); + it('Deletes notebooks', () => { cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click(); cy.wait(delay); @@ -231,6 +255,16 @@ describe('Testing paragraphs', () => { cy.get('.euiTitle').contains('Event analytics').should('exist'); }); + it('Paragraph actions layout', () => { + cy.get('button[data-test-subj="notebook-paragraph-actions-button"]').should('exist').click(); + cy.get('.euiContextMenuPanelTitle').contains('Actions'); + cy.get('.euiContextMenuItem__text').eq(0).contains('Add paragraph to top'); + cy.get('.euiContextMenuItem__text').eq(1).contains('Add paragraph to bottom'); + cy.get('.euiContextMenuItem__text').eq(2).contains('Run all paragraphs'); + cy.get('.euiContextMenuItem__text').eq(3).contains('Clear all outputs'); + cy.get('.euiContextMenuItem__text').eq(4).contains('Delete all paragraphs'); + }); + it('Renders markdown', () => { cy.get('.euiTextArea').should('not.exist'); cy.get(`a[href="${SAMPLE_URL}"]`).should('exist'); diff --git a/dashboards-observability/.cypress/integration/panels.spec.js b/dashboards-observability/.cypress/integration/3_panels.spec.js similarity index 94% rename from dashboards-observability/.cypress/integration/panels.spec.js rename to dashboards-observability/.cypress/integration/3_panels.spec.js index 730dd4040..e7b349633 100644 --- a/dashboards-observability/.cypress/integration/panels.spec.js +++ b/dashboards-observability/.cypress/integration/3_panels.spec.js @@ -502,37 +502,7 @@ describe('Testing a panel', () => { }); }); -describe('Add samples and clean up all test data', () => { - it('Add sample data', () => { - moveToPanelHome(); - cy.get('.euiButton__text').contains('Actions').trigger('mouseover').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem__text').contains('Add samples').trigger('mouseover').click(); - cy.wait(delay * 3); - cy.get('.euiModalHeader__title[data-test-subj="confirmModalTitleText"]') - .contains('Add samples') - .should('exist'); - cy.wait(delay); - cy.get('.euiButton__text').contains('Yes').trigger('mouseover').click(); - cy.wait(delay * 5); - cy.route2('POST', '/addSamplePanels').as('removePage'); - cy.wait('@removePage').then(() => { - cy.get('.euiTableCellContent').contains(SAMPLE_PANEL).should('exist'); - }); - cy.wait(delay); - }); - - it('Validate sample data', () => { - moveToPanelHome(); - cy.get('.euiTableCellContent').contains(SAMPLE_PANEL).trigger('mouseover').click(); - cy.wait(delay * 3); - cy.get('h1').contains(SAMPLE_PANEL).should('exist'); - cy.wait(delay); - SAMPLE_VISUALIZATIONS_NAMES.forEach((vizName) => - cy.get('h5').contains(vizName).should('exist') - ); - cy.wait(delay); - }); +describe('Clean up all test data', () => { it('Delete visualizations from event analytics', () => { moveToEventsHome(); @@ -572,3 +542,4 @@ describe('Add samples and clean up all test data', () => { cy.get('.euiTextAlign').contains('No Operational Panels').should('exist'); }); }); + diff --git a/dashboards-observability/.cypress/integration/4_trace_analytics_dashboard.spec.js b/dashboards-observability/.cypress/integration/4_trace_analytics_dashboard.spec.js new file mode 100644 index 000000000..f9bfb5760 --- /dev/null +++ b/dashboards-observability/.cypress/integration/4_trace_analytics_dashboard.spec.js @@ -0,0 +1,294 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +import { testDataSet, delay, setTimeFilter } from '../utils/constants'; + +describe('Dump test data', () => { + it('Indexes test data', () => { + const dumpDataSet = (mapping_url, data_url, index) => { + cy.request({ + method: 'POST', + failOnStatusCode: false, + url: 'api/console/proxy', + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + qs: { + path: `${index}`, + method: 'PUT', + }, + }); + + cy.request(mapping_url).then((response) => { + cy.request({ + method: 'POST', + form: true, + url: 'api/console/proxy', + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + qs: { + path: `${index}/_mapping`, + method: 'POST', + }, + body: response.body, + }); + }); + + cy.request(data_url).then((response) => { + cy.request({ + method: 'POST', + form: true, + url: 'api/console/proxy', + headers: { + 'content-type': 'application/json;charset=UTF-8', + 'osd-xsrf': true, + }, + qs: { + path: `${index}/_bulk`, + method: 'POST', + }, + body: response.body, + }); + }); + }; + + testDataSet.forEach(({ mapping_url, data_url, index }) => + dumpDataSet(mapping_url, data_url, index) + ); + }); +}); + +describe('Testing dashboard table empty state', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/home', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + cy.wait(delay * 3); + }); + + it('Renders empty state', () => { + cy.contains(' (0)').should('exist'); + cy.contains('No matches').should('exist'); + }); +}); + +describe('Testing dashboard table', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/home', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Renders the dashboard table', () => { + cy.contains(' (10)').should('exist'); + cy.contains('client_cancel_order').should('exist'); + cy.contains('166.44').should('exist'); + cy.contains('7.14%').should('exist'); + }); + + it('Has working breadcrumbs', () => { + cy.get('.euiBreadcrumb').contains('Dashboard').click(); + cy.wait(delay); + cy.get('.euiTitle').contains('Dashboard').should('exist'); + cy.get('.euiBreadcrumb').contains('Trace analytics').click(); + cy.wait(delay); + cy.get('.euiTitle').contains('Dashboard').should('exist'); + cy.get('.euiBreadcrumb').contains('Observability').click(); + cy.wait(delay); + cy.get('.euiTitle').contains('Event analytics').should('exist'); + }); + + it('Adds the percentile filters', () => { + cy.contains(' >= 95 percentile').click({ force: true }); + cy.wait(delay); + cy.contains(' >= 95 percentile').click({ force: true }); + cy.wait(delay); + + cy.contains('Latency percentile within trace group: >= 95th').should('exist'); + cy.contains(' (7)').should('exist'); + cy.contains('318.69').should('exist'); + + cy.contains(' < 95 percentile').click({ force: true }); + cy.wait(delay); + cy.contains(' < 95 percentile').click({ force: true }); + cy.wait(delay); + + cy.contains('Latency percentile within trace group: < 95th').should('exist'); + cy.contains(' (8)').should('exist'); + cy.contains('383.05').should('exist'); + }); + + it('Opens latency trend popover', () => { + setTimeFilter(true); + cy.get('.euiButtonIcon[aria-label="Open popover"]').first().click(); + cy.get('text.ytitle[data-unformatted="Hourly latency (ms)"]').should('exist'); + }); + + it('Redirects to traces table with filter', () => { + cy.wait(delay * 5); + cy.get('.euiLink').contains('13').click(); + cy.wait(delay); + + cy.get('h2.euiTitle').contains('Traces').should('exist'); + cy.contains(' (13)').should('exist'); + cy.contains('client_create_order').should('exist'); + + cy.get('.euiSideNavItemButton__label').contains('Trace analytics').click(); + cy.wait(delay); + + cy.contains('client_create_order').should('exist'); + }); +}); + +describe('Testing plots', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/home', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Renders service map', () => { + // plotly scale texts are in attribute "data-unformatted" + cy.get('text.ytitle[data-unformatted="Latency (ms)"]').should('exist'); + cy.get('text[data-unformatted="200"]').should('exist'); + cy.get('.vis-network').should('exist'); + + cy.get('.euiButton__text[title="Error rate"]').click(); + cy.get('text.ytitle[data-unformatted="Error rate"]').should('exist'); + cy.get('text[data-unformatted="10%"]').should('exist'); + + cy.get('.euiButton__text[title="Throughput"]').click(); + cy.get('text.ytitle[data-unformatted="Throughput"]').should('exist'); + cy.get('text[data-unformatted="50"]').should('exist'); + + cy.get('input[type="search"]').eq(1).focus().type('payment{enter}'); + cy.wait(delay); + }); + + it('Renders plots', () => { + cy.get('text.ytitle[data-unformatted="Error rate (%)"]').should('exist'); + cy.get('text.annotation-text[data-unformatted="Now: 14.81%"]').should('exist'); + cy.get('text.ytitle[data-unformatted="Throughput (n)"]').should('exist'); + cy.get('text.annotation-text[data-unformatted="Now: 108"]').should('exist'); + }); +}); + +describe('Latency by trace group table', () =>{ + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/home', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Verify columns in Latency by trace group table along with pagination functionality', () => { + cy.get('span.panel-title').eq(0).should('exist'); + cy.wait(delay); + cy.get('span[title="Trace group name"]').should('exist'); + cy.get('span[title="Latency variance (ms)"]').should('exist'); + cy.get('span[title="Average latency (ms)"]').should('exist'); + cy.get('span[title="24-hour latency trend"]').should('exist'); + cy.get('span[title="Error rate"] .euiToolTipAnchor').should('exist'); + cy.get('span[title="Traces"] .euiToolTipAnchor').should('exist'); + cy.get('[data-test-subj="tablePaginationPopoverButton"]').click(); + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiContextMenu__icon').eq(0).should('exist').click(); + cy.get('[data-test-subj="pagination-button-next"]').should('exist').click(); + cy.get('button[data-test-subj="dashboard-table-trace-group-name-button"]').contains('mysql').should('exist'); + }); + + it('Sorts the Latency by trace group table', () => { + cy.get('span[title*="Trace group name"]').click(); + cy.get('[data-test-subj="dashboard-table-trace-group-name-button"]').eq(0).contains('/**').should('exist'); + cy.wait(delay); + }); + + it('Verify tooltips in Latency by trace group table', () => { + cy.get('.euiIcon.euiIcon--small.euiIcon--subdued.euiIcon-isLoaded.eui-alignTop').eq(0).trigger('mouseover'); + cy.contains('Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.').should('be.visible'); + cy.get('.euiIcon.euiIcon--small.euiIcon--subdued.euiIcon-isLoaded.eui-alignTop').eq(1).trigger('mouseover'); + cy.contains('Range of latencies for traces within a trace group in the selected time range.').should('be.visible'); + cy.get('.euiIcon.euiIcon--small.euiIcon--subdued.euiIcon-isLoaded.eui-alignTop').eq(2).trigger('mouseover'); + cy.contains('Average latency of traces within a trace group in the selected time range.').should('be.visible'); + cy.get('.euiIcon.euiIcon--small.euiIcon--subdued.euiIcon-isLoaded.eui-alignTop').eq(3).trigger('mouseover'); + cy.contains('24 hour time series view of hourly average, hourly percentile, and hourly range of latency for traces within a trace group.').should('be.visible'); + cy.get('.euiIcon.euiIcon--small.euiIcon--subdued.euiIcon-isLoaded.eui-alignTop').eq(4).trigger('mouseover'); + cy.contains('Error rate based on count of trace errors within a trace group in the selected time range.').should('be.visible'); + cy.get('.euiIcon.euiIcon--small.euiIcon--subdued.euiIcon-isLoaded.eui-alignTop').eq(5).trigger('mouseover'); + cy.contains('Count of traces with unique trace identifiers in the selected time range.').should('be.visible'); + }); + + it('Verify Search engine on Trace dashboard', () => { + cy.get('.euiFieldSearch.euiFieldSearch--fullWidth').click().type('client_pay_order{enter}'); + cy.wait(delay); + cy.get('.euiTableCellContent.euiTableCellContent--alignRight.euiTableCellContent--overflowingContent').contains('211.04').should('exist'); + cy.get('button[data-test-subj="dashboard-table-trace-group-name-button"]').click(); + cy.get('.euiBadge.euiBadge--hollow.euiBadge--iconRight.globalFilterItem').click(); + cy.get('.euiIcon.euiIcon--medium.euiContextMenu__arrow').click(); + cy.get('.euiContextMenuPanelTitle').contains('Edit filter').should('exist'); + cy.get('.euiButton.euiButton--primary.euiButton--fill').click(); + cy.get('.euiBadge.euiBadge--hollow.euiBadge--iconRight.globalFilterItem').click(); + cy.get('.euiContextMenuItem__text').eq(1).contains('Exclude results').click(); + cy.get('.euiTextColor.euiTextColor--danger').should('exist'); + cy.get('.euiBadge.euiBadge--hollow.euiBadge--iconRight.globalFilterItem').click(); + cy.get('.euiContextMenuItem__text').eq(1).contains('Include results').click(); + cy.get('.euiBadge.euiBadge--hollow.euiBadge--iconRight.globalFilterItem').click(); + cy.get('.euiContextMenuItem__text').eq(2).contains('Temporarily disable').click(); + cy.get('.euiBadge.euiBadge--iconRight.globalFilterItem.globalFilterItem-isDisabled').should('exist').click(); + cy.get('.euiContextMenuItem__text').eq(2).contains('Re-enable').click(); + cy.get('.euiBadge.euiBadge--hollow.euiBadge--iconRight.globalFilterItem').click(); + cy.get('.euiContextMenuItem__text').eq(3).contains('Delete').click(); + }); +}); + +describe('Testing filters on trace analytics page', () =>{ + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/home', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Verify Change all filters', () =>{ + cy.get('.euiButtonIcon.euiButtonIcon--primary.euiButtonIcon--empty.euiButtonIcon--xSmall').click(); + cy.get('.euiContextMenuPanelTitle').contains('Change all filters').should('exist'); + cy.get('.euiContextMenuItem__text').eq(0).contains('Enable all'); + cy.get('.euiContextMenuItem__text').eq(1).contains('Disable all'); + cy.get('.euiContextMenuItem__text').eq(2).contains('Invert inclusion'); + cy.get('.euiContextMenuItem__text').eq(3).contains('Invert enabled/disabled'); + cy.get('.euiContextMenuItem__text').eq(4).contains('Remove all'); + }) + + it('Verify Add filter section', () => { + cy.get('.euiPopover.euiPopover--anchorDownLeft').contains('+ Add filter').click(); + cy.get('.euiPopoverTitle').contains('Add filter').should('exist'); + cy.wait(delay); + cy.get('.euiComboBox__inputWrap.euiComboBox__inputWrap--noWrap').eq(0).trigger('mouseover').click(); + cy.get('.euiComboBoxOption__content').eq(1).click(); + cy.get('.euiComboBox__inputWrap.euiComboBox__inputWrap--noWrap').eq(1).trigger('mouseover').click(); + cy.get('.euiComboBoxOption__content').eq(2).click(); + cy.get('.euiButton.euiButton--primary.euiButton--fill').contains('Save').click(); + cy.get('.euiBadge__content').should('exist').click(); + cy.get('.euiIcon.euiIcon--medium.euiContextMenu__arrow').click(); + cy.get('[data-test-subj="filter-popover-cancel-button"]').contains('Cancel').click(); + cy.get('.euiIcon.euiIcon--small.euiIcon--inherit.euiBadge__icon').click(); + }) +}); diff --git a/dashboards-observability/.cypress/integration/5_trace_analytics_services.spec.js b/dashboards-observability/.cypress/integration/5_trace_analytics_services.spec.js new file mode 100644 index 000000000..bd2cd4c41 --- /dev/null +++ b/dashboards-observability/.cypress/integration/5_trace_analytics_services.spec.js @@ -0,0 +1,279 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +import { delay, SERVICE_NAME, SERVICE_SPAN_ID, setTimeFilter, verify_traces_spans_data_grid_cols_exists, count_table_row } from '../utils/constants'; + +describe('Testing services table empty state', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/services', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + cy.wait(delay * 3); + }); + + it('Renders empty state', () => { + cy.contains(' (0)').should('exist'); + cy.contains('No matches').should('exist'); + }); +}); + +describe('Testing services table', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/services', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Renders the services table', () => { + cy.contains(' (8)').should('exist'); + cy.contains('analytics-service, frontend-client, recommendation').should('exist'); + cy.contains('186.95').should('exist'); + cy.contains('14.29%').should('exist'); + }); + + it('Searches correctly', () => { + cy.get('input[type="search"]').first().focus().type(`${SERVICE_NAME}{enter}`); + cy.get('.euiButton__text').contains('Refresh').click(); + cy.contains(' (1)').should('exist'); + cy.contains('3.57%').should('exist'); + }); + + it('Verify columns in Services table', () => { + cy.get('.euiFlexItem.euiFlexItem--flexGrow10 .panel-title').contains('Services').should('exist'); + cy.get('.euiTableCellContent__text[title="Name"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Average latency (ms)"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Error rate"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Throughput"]').should('exist'); + cy.get('.euiTableCellContent__text[title="No. of connected services"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Connected services"]').should('exist'); + cy.get('.euiTableCellContent__text[title="Traces"]').should('exist'); + cy.get('[data-test-subj="tablePaginationPopoverButton"]').click(); + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiContextMenu__icon').eq(0).should('exist').click(); + cy.get('[data-test-subj="pagination-button-next"]').should('exist').click(); + cy.get('.euiLink.euiLink--primary').contains('order').should('exist'); + }) + + it('Navigate from Services to Traces', () => { + cy.get('.euiTableCellContent__text[title="Traces"]').should('exist'); + cy.contains('74').should('exist').click(); + cy.get('.euiText.euiText--medium .panel-title').should('exist'); + cy.get('.euiBadge__childButton[data-test-subj="filterBadge"]').should('exist'); + }) +}); + +describe('Testing service view empty state', () => { + beforeEach(() => { + // exception is thrown on loading EuiDataGrid in cypress only, ignore for now + cy.on('uncaught:exception', (err, runnable) => { + if (err.message.includes('ResizeObserver loop')) + return false; + }); + cy.visit(`app/observability-dashboards#/trace_analytics/services/${SERVICE_NAME}`, { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + }); + + it('Renders service view empty state', () => { + cy.contains('frontend-client').should('exist'); + cy.get('.euiText').contains('0').should('exist'); + cy.get('.euiText').contains('-').should('exist'); + }); +}); + +describe('Testing service view', () => { + beforeEach(() => { + // exception is thrown on loading EuiDataGrid in cypress only, ignore for now + cy.on('uncaught:exception', (err, runnable) => { + if (err.message.includes('ResizeObserver loop')) + return false; + }); + cy.visit(`app/observability-dashboards#/trace_analytics/services/${SERVICE_NAME}`, { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(undefined, false); + }); + + it('Renders service view', () => { + cy.get('h2.euiTitle').contains(SERVICE_NAME).should('exist'); + cy.contains('178.6').should('exist'); + cy.contains('3.57%').should('exist'); + cy.get('div.vis-network').should('exist'); + }); + + it('Has working breadcrumbs', () => { + cy.get('.euiBreadcrumb').contains(SERVICE_NAME).click(); + cy.wait(delay); + cy.get('h2.euiTitle').contains(SERVICE_NAME).should('exist'); + cy.get('.euiBreadcrumb').contains('Services').click(); + cy.wait(delay); + cy.get('.euiTitle').contains('Services').should('exist'); + cy.get('.euiBreadcrumb').contains('Trace analytics').click(); + cy.wait(delay); + cy.get('.euiTitle').contains('Dashboard').should('exist'); + cy.get('.euiBreadcrumb').contains('Observability').click(); + cy.wait(delay); + cy.get('.euiTitle').contains('Event analytics').should('exist'); + }); + + it('Renders spans data grid, flyout, filters', () => { + cy.get('.euiLink').contains(SERVICE_SPAN_ID).trigger('mouseover', { force: true }); + cy.get('button[data-datagrid-interactable="true"]').eq(0).click({ force: true }); + cy.wait(delay); + cy.contains('Span detail').should('exist'); + cy.contains('Span attributes').should('exist'); + cy.get('.euiTextColor').contains('Span ID').trigger('mouseover'); + cy.get('.euiButtonIcon[aria-label="span-flyout-filter-icon"').click({ force: true }); + cy.wait(delay); + cy.get('.euiBadge__text').contains('spanId: ').should('exist'); + cy.get('[data-test-subj="euiFlyoutCloseButton"]').click({ force: true }); + cy.contains('Spans (1)').should('exist'); + }); +}); + +describe('Testing Service map', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/services', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Render Service map', () => { + cy.get('.euiText.euiText--medium .panel-title').contains('Service map'); + cy.get('[data-test-subj="latency"]').should('exist'); + cy.get('.ytitle').contains('Latency (ms)'); + cy.get('[data-text = "Error rate"]').click(); + cy.contains('60%'); + cy.get('[data-text = "Throughput"]').click(); + cy.contains('100'); + cy.get('.euiText.euiText--medium').contains('Focus on').should('exist'); + cy.get('[placeholder="Service name"]').focus().type('database{enter}'); + }) +}); + +describe('Testing traces Spans table verify table headers functionality', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/services', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Renders the spans table and verify columns headers', () => { + cy.contains(' (8)').should('exist'); + cy.contains('analytics-service, frontend-client, recommendation').should('exist'); + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + cy.get('.panel-title').contains('Spans').should('exist'); + cy.get('.panel-title-count').contains('5').should('exist'); + verify_traces_spans_data_grid_cols_exists(); + }); + + it('Toggle columns and verify the columns hidden text verify rows', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + cy.get('[data-test-subj = "dataGridColumnSelectorButton"]').click(); + cy.get('.euiSwitch.euiSwitch--compressed.euiSwitch--mini .euiSwitch__button').eq(3).click(); + cy.get('.euiButtonEmpty__text').eq(3).click().should('have.text', '2 columns hidden'); + count_table_row(5); + }); + + it('Show all button Spans table', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + cy.get('[data-test-subj = "dataGridColumnSelectorButton"]').click(); + cy.get('.euiPopoverFooter .euiFlexItem.euiFlexItem--flexGrowZero').eq(0).should('have.text', 'Show all').click(); + cy.get('.euiDataGrid__focusWrap').click().should('exist'); + verify_traces_spans_data_grid_cols_exists(); + }); + + it('Hide all button Spans table', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + cy.get('[data-test-subj = "dataGridColumnSelectorButton"]').click(); + cy.get('.euiPopoverFooter .euiFlexItem.euiFlexItem--flexGrowZero').eq(1).should('have.text', 'Hide all').click(); + cy.get('.euiDataGrid__focusWrap').click().should('exist'); + cy.get('[data-test-subj="dataGridColumnSelectorPopover"]').should('have.text', '10 columns hidden'); + }); + + it('Render Spans table and change data table Density', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + verify_traces_spans_data_grid_cols_exists(); + cy.get('.euiButtonEmpty__text').contains('Density').click(); + cy.get('.euiButtonContent__icon').eq(5).click(); + cy.get('.euiButtonContent__icon').eq(6).click(); + cy.get('.euiButtonContent__icon').eq(7).click(); + }); + + it('Render Spans table and and click on sort', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + verify_traces_spans_data_grid_cols_exists(); + cy.get('[data-test-subj="dataGridColumnSortingButton"]').contains('Sort fields').should('exist').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection"]').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-spanId').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-parentSpanId"]').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-traceId"]').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-traceGroup').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-durationInNanos"]').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-startTime"]').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-endTime').click(); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection-status.code"]').click(); + cy.get('.euiButtonEmpty__text').eq(5).contains('8 fields sorted').should('exist'); + cy.get('[data-test-subj="dataGridColumnSortingPopoverColumnSelection"]').click(); + cy.get('[data-test-subj="dataGridColumnSortingButton"]').should('exist').click(); + }); +}); + + +describe('Testing traces Spans table and verify columns functionality', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/services', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Renders the spans table and click on first span to verify details', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + verify_traces_spans_data_grid_cols_exists(); + cy.get('.euiLink--primary').eq(4).click(); + cy.get('[data-test-subj="spanDetailFlyout"] .euiTitle.euiTitle--medium').contains('Span detail').should('exist'); + cy.get('.euiFlyoutBody .panel-title').contains('Overview').should('exist'); + cy.get('.euiTextColor.euiTextColor--subdued').contains('Span ID').should('exist'); + cy.get('.euiDescriptionList__description .euiFlexItem').eq(0).contains('d03fecfa0f55b77c').should('exist'); + cy.get('.euiFlyoutBody__overflowContent .panel-title').contains('Span attributes').should('exist'); + cy.get('.euiDescriptionList__description .euiFlexItem').eq(0).trigger('mouseover').click(); + cy.get('[aria-label="span-flyout-filter-icon"]').click(); + cy.get('.euiFlyout__closeButton.euiFlyout__closeButton--inside').click(); + cy.get('.euiBadge__content .euiBadge__text').contains('spanId: d03fecfa0f55b77c').should('exist'); + count_table_row(1); + cy.get('[aria-label="remove current filter"]').click(); + count_table_row(5); + }); + + it('Render Spans table and verify Column functionality', () => { + cy.get('.euiLink.euiLink--primary').contains('authentication').should('exist').click(); + verify_traces_spans_data_grid_cols_exists(); + cy.get('.euiDataGridHeaderCell__content').contains('Span ID').click(); + cy.get('.euiListGroupItem__label').contains('Hide column').click(); + cy.get('.euiDataGridHeaderCell__content').contains('Trace ID').click(); + cy.get('.euiListGroupItem__label').contains('Sort A-Z').click(); + cy.get('.euiDataGridHeaderCell__content').contains('Trace group').click(); + cy.get('.euiListGroupItem__label').contains('Move left').click(); + }); +}); diff --git a/dashboards-observability/.cypress/integration/trace_analytics_traces.spec.js b/dashboards-observability/.cypress/integration/6_trace_analytics_traces.spec.js similarity index 70% rename from dashboards-observability/.cypress/integration/trace_analytics_traces.spec.js rename to dashboards-observability/.cypress/integration/6_trace_analytics_traces.spec.js index d8c5735fc..14f71ec10 100644 --- a/dashboards-observability/.cypress/integration/trace_analytics_traces.spec.js +++ b/dashboards-observability/.cypress/integration/6_trace_analytics_traces.spec.js @@ -113,3 +113,43 @@ describe('Testing trace view', () => { cy.contains('Spans (1)').should('exist'); }); }); + +describe('Testing traces table', () => { + beforeEach(() => { + cy.visit('app/observability-dashboards#/trace_analytics/traces', { + onBeforeLoad: (win) => { + win.sessionStorage.clear(); + }, + }); + setTimeFilter(); + }); + + it('Renders the traces table and verify Table Column, Pagination and Rows Data ', () => { + cy.get('.euiTableCellContent__text').contains('Trace ID').should('exist'); + cy.get('.euiTableCellContent__text').contains('Trace group').should('exist'); + cy.get('.euiTableCellContent__text').contains('Latency (ms)').should('exist'); + cy.get('.euiTableCellContent__text').contains('Percentile in trace group').should('exist'); + cy.get('.euiTableCellContent__text').contains('Errors').should('exist'); + cy.get('.euiTableCellContent__text').contains('Last updated').should('exist'); + cy.get('[data-test-subj="pagination-button-next"]').click(); + cy.contains('client_pay_order').should('exist'); + cy.get('[data-test-subj="pagination-button-previous"]').click(); + cy.contains('224.99').should('exist'); + cy.get('.euiButtonEmpty').contains('5').click(); + cy.contains('690d3c7af1a78cf89c43e...').should('exist'); + cy.contains('5be8370207cbb002a165d...').click(); + cy.contains('client_create_order').should('exist'); + cy.get('path[style*="rgb(116, 146, 231)"]').should('exist'); + cy.go('back'); + cy.wait(delay); + cy.get('.euiButtonEmpty__text').contains('Rows per page').click(); + cy.get('.euiContextMenuItem__text').contains('15 rows').click(); + let expected_row_count=15; + cy.get('.euiTable--auto') + .find("tr") + .then((row) => { + let total=row.length-1; + expect(total).to.equal(expected_row_count); + }); + }); +}); diff --git a/dashboards-observability/.cypress/integration/7_app_analytics.spec.js b/dashboards-observability/.cypress/integration/7_app_analytics.spec.js new file mode 100644 index 000000000..377b2d323 --- /dev/null +++ b/dashboards-observability/.cypress/integration/7_app_analytics.spec.js @@ -0,0 +1,596 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +import { + delay, + moveToHomePage, + moveToCreatePage, + moveToApplication, + moveToEditPage, + changeTimeTo24, + expectMessageOnHover, + baseQuery, + nameOne, + nameTwo, + nameThree, + description, + service_one, + service_two, + trace_one, + trace_two, + trace_three, + query_one, + query_two, + availability_default, + visOneName, + visTwoName, + composition, + newName, + TYPING_DELAY, + timeoutDelay +} from '../utils/app_constants'; +import { supressResizeObserverIssue } from '../utils/constants'; + +describe('Creating application', () => { + beforeEach(() => { + moveToCreatePage(); + }); + + it('Suggests correct autocompletion', () => { + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); + cy.get('.aa-List').find('.aa-Item').should('have.length', 1); + cy.get('.aa-Item').contains('source').should('exist'); + cy.focused().type('{enter}'); + cy.get('.aa-List').find('.aa-Item').should('have.length', 1); + cy.get('.aa-Item').contains('=').should('exist'); + cy.focused().type('{enter}'); + cy.focused().type('opensearch'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); + cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_flights').click(); + cy.focused().clear(); + cy.get('.aa-List').find('.aa-Item').should('have.length', 1); + cy.focused().type('{enter}'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source '); + cy.focused().type('{enter}'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = '); + cy.focused().type('opensearch'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); + cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_flights').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights '); + cy.focused().type('{downArrow}'); + cy.focused().type('{enter}'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights, '); + cy.focused().type('opensearch'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); + cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_logs').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights,opensearch_dashboards_sample_data_logs '); + }); + + it('Creates an application and redirects to application', () => { + expectMessageOnHover('createButton', 'Name is required.'); + cy.get('[data-test-subj="nameFormRow"]').type(nameOne); + cy.get('[data-test-subj="descriptionFormRow"]').type('This application is for testing.'); + expectMessageOnHover('createButton', 'Provide at least one log source, service, entity or trace group.'); + cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="servicesEntitiesComboBox"]').click(); + cy.focused().type('{downArrow}'); + cy.focused().type('{enter}'); + cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1'); + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="createButton"]').should('not.be.disabled'); + cy.get('[data-test-subj="createAndSetButton"]').should('be.disabled'); + expectMessageOnHover('createAndSetButton', 'Log source is required to set availability.'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); + cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); + cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click'); + cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); + cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2'); + cy.get('[data-test-subj="createButton"]').should('not.be.disabled'); + cy.get('[data-test-subj="createButton"]').click(); + cy.wait(delay * 3); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne); + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.get('[data-test-subj="addFirstVisualizationText"]').should('exist'); + }); + + it('Redirects to home page on cancel', () => { + cy.get('[data-test-subj="cancelCreateButton"]').contains('Cancel').click(); + cy.get('[data-test-subj="applicationHomePageTitle"]').should('exist'); + }); + + it('Saves current input on reload', () => { + cy.get('[data-test-subj="nameFormRow"]').type(nameOne); + cy.get('[data-test-subj="descriptionFormRow"]').type(description); + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); + cy + .get('[data-test-subj="searchAutocompleteTextArea"]') + .focus() + .type(baseQuery, {delay: TYPING_DELAY}); + cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="servicesEntitiesComboBox"]').scrollIntoView(); + cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click(); + cy.get('.euiFilterSelectItem').contains(service_one).click({ force: true }); + cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1'); + cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); + cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click'); + cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); + cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2'); + cy.reload(); + cy.wait(delay); + cy.get('[data-test-subj="nameFormRow"]').find('.euiFieldText').should('contain.value', nameOne); + cy.get('[data-test-subj="descriptionFormRow"]').find('.euiFieldText').should('contain.value', description); + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', baseQuery); + cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1'); + cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2'); + }); + + it('Shows clear modals before clearing', () => { + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="clearLogSourceButton"]').should('be.disabled'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); + cy.get('[data-test-subj="clearLogSourceButton"]').click(); + cy.get('.euiButton--danger').contains('Clear').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', ''); + cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click(); + cy.get('.euiFilterSelectItem').contains(service_one).trigger('click'); + cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1'); + cy.get('[data-test-subj="clearServicesEntitiesButton"]').click(); + cy.get('.euiButton--danger').contains('Clear all').click(); + cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '0'); + cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); + cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click'); + cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); + cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2'); + cy.get('[data-test-subj="clearTraceGroupsButton"]').click(); + cy.get('.euiButton--danger').contains('Clear all').click(); + cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '0'); + }); + + it('Saves time range for each application', () => { + cy.get('[data-test-subj="nameFormRow"]').type(nameTwo); + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); + cy.get('[data-test-subj="createButton"]').should('not.be.disabled'); + cy.get('[data-test-subj="createButton"]').click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameTwo); + changeTimeTo24('weeks'); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 weeks'); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.wait(delay); + cy.get(`[data-test-subj="${nameOne}ApplicationLink"]`).click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne); + changeTimeTo24('months'); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.get(`[data-test-subj="${nameTwo}ApplicationLink"]`).click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameTwo); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 weeks'); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.get(`[data-test-subj="${nameOne}ApplicationLink"]`).click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + }); +}); + +describe('Setting availability', () => { + it('Redirects to set availability at three entry points', () => { + moveToCreatePage(); + cy.get('[data-test-subj="nameFormRow"]').type(nameThree); + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus(); + cy.focused().type('source = ', { delay: TYPING_DELAY }); + cy.focused().type('{enter}'); + cy.get('[data-test-subj="createAndSetButton"]').click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.get('[data-test-subj="setAvailabilityHomePageLink"]').first().click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree); + cy.get('.euiTab-isSelected[id="app-analytics-log"]').should('exist', { timeout: timeoutDelay }); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', availability_default); + cy.get('[id="explorerPlotComponent"]').should('exist'); + cy.get('.euiTab-isSelected[id="availability-panel"]').should('exist'); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.get(`[data-test-subj="${nameThree}ApplicationLink"]`).click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree); + cy.get('[data-test-subj="app-analytics-configTab"]').click(); + cy.get('[data-test-subj="setAvailabilityConfigLink"]').click(); + cy.get('.euiTab-isSelected[id="app-analytics-log"]').should('exist', { timeout: timeoutDelay }); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', availability_default); + cy.get('[id="explorerPlotComponent"]').should('exist'); + cy.get('.euiTab-isSelected[id="availability-panel"]').should('exist'); + }); +}); + +describe('Viewing application', () => { + beforeEach(() => { + moveToApplication(nameOne); + }); + + it('Has working breadcrumbs', () => { + cy.get('.euiBreadcrumb').contains(nameOne).click(); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.get('[data-test-subj="applicationHomePageTitle"]').should('contain', 'Applications'); + cy.get('.euiBreadcrumb[href="observability-dashboards#/"]').click(); + cy.get('[data-test-subj="eventHomePageTitle"]').should('contain', 'Event analytics'); + }); + + it('Shares time range among tabs', () => { + changeTimeTo24('months'); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + cy.get('[data-test-subj="app-analytics-serviceTab"]').click(); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + cy.get('[data-test-subj="app-analytics-traceTab"]').click(); + supressResizeObserverIssue(); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + cy.get('[data-test-subj="app-analytics-logTab"]').click(); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + }); + + it('Shows latency variance in dashboards table', () => { + changeTimeTo24('months'); + cy.get('[data-test-subj="dashboardTable"]').first().within(($table) => { + cy.get('.plot-container').should('have.length.at.least', 1); + }) + }); + + it('Adds filter when Trace group name is clicked', () => { + cy.get('[data-test-subj="app-analytics-overviewTab"]').click(); + cy.get('[data-test-subj="dashboard-table-trace-group-name-button"]').contains('client_create_order').click(); + cy.get('.euiTableRow').should('have.length', 1, { timeout: timeoutDelay }); + cy.get('[data-test-subj="client_create_orderFilterBadge"]').should('exist'); + cy.get('[data-test-subj="filterBadge"]').click(); + cy.get('[data-test-subj="deleteFilterIcon"]').click(); + cy.get('[data-test-subj="client_create_orderFilterBadge"]').should('not.exist'); + }); + + it('Opens service detail flyout when Service Name is clicked', () => { + cy.get('[data-test-subj="app-analytics-serviceTab"]').click(); + cy.wait(delay); + cy.get('.euiLink').contains('authentication').click(); + supressResizeObserverIssue(); + cy.get('[data-test-subj="serviceDetailFlyoutTitle"]').should('be.visible'); + cy.get('[data-test-subj="serviceDetailFlyout"]').within(($flyout) => { + cy.get('[data-test-subj="Number of connected servicesDescriptionList"]').should('contain', '3'); + cy.get('[data-text="Error rate"]').click(); + cy.get('.ytitle').contains('Error rate').should('exist'); + }); + cy.get('[data-test-subj="dataGridRowCell"] button').contains('718dc32a693c8a17').click(); + cy.get('[data-test-subj="spanDetailFlyout"]').contains('Span detail').should('be.visible'); + cy.get('[data-test-subj="ServiceDescriptionList"]').should('contain', 'authentication'); + cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); + cy.get('[data-test-subj="serviceDetailFlyout"]').should('not.be.visible'); + cy.get('[data-test-subj="spanDetailFlyout"]').should('not.be.visible'); + }); + + it('Opens trace detail flyout when Trace ID is clicked', () => { + cy.get('[data-test-subj="app-analytics-traceTab"]').click(); + supressResizeObserverIssue(); + cy.wait(delay); + cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click(); + cy.get('[data-test-subj="traceDetailFlyoutTitle"]').should('be.visible'); + cy.get('[data-test-subj="traceDetailFlyout"]').within(($flyout) => { + cy.get('[data-test-subj="LatencyDescriptionList"]').should('contain', '224.99'); + }); + cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="traceDetailFlyout"]').should('not.be.visible'); + cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click(); + cy.get('[data-text="Span list"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="dataGridRowCell"] button').contains('d67c5bb617ba9203').click(); + cy.get('[data-test-subj="spanDetailFlyout"]').should('be.visible'); + cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); + cy.get('[data-test-subj="spanDetailFlyout"]').should('not.be.visible'); + }); + + it('Opens span detail flyout when Span ID is clicked', () => { + cy.get('[data-test-subj="app-analytics-traceTab"]').click(); + supressResizeObserverIssue(); + cy.wait(delay); + cy.get('[data-test-subj="dataGridRowCell"]').contains('5ff3516909562c60').click(); + cy.get('[data-test-subj="spanDetailFlyout"]').should('be.visible'); + cy.get('[data-test-subj="spanDetailFlyout"]').within(($flyout) => { + cy.get('[data-test-subj="OperationDescriptionList"]').should('contain', 'HTTP GET'); + }); + cy.get('.euiText').contains('order').click(); + cy.get('[aria-label="span-flyout-filter-icon"]').click(); + cy.focused().blur(); + cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); + cy.get('[data-test-subj="filterBadge"][title="serviceName: order"]').should('exist'); + cy.get('[aria-label="Remove filter"]').click(); + cy.get('[data-test-subj="filterBadge"][title="serviceName: order"]').should('not.exist'); + }); + + it('Shows base query', () => { + cy.get('[data-test-subj="app-analytics-logTab"]').click(); + cy.get('.euiBadge[title="Base Query"]').should('exist'); + cy.get('.euiBadge[title="Base Query"]').trigger('mouseover'); + cy.get('.euiToolTipPopover').contains('source = opensearch_dashboards_sample_data_flights').should('exist'); + }); + + it('Saves visualization #1 to panel', () => { + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.get('[data-test-subj="addVisualizationButton"]').first().click(); + cy.wait(delay); + cy.get('[id="explorerPlotComponent"]').should('exist'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); + cy.get('.aa-List').find('.aa-Item').should('have.length', 11); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(query_one, {delay: TYPING_DELAY}); + changeTimeTo24('months'); + cy.wait(delay * 2); + cy.get('[data-test-subj="main-content-visTab"]').click(); + supressResizeObserverIssue(); + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visOneName); + cy.wait(delay); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="Flights to VeniceVisualizationPanel"]').should('exist'); + cy.get('[id="explorerPlotComponent"]').should('exist'); + cy.get('[class="trace bars"]').should('exist'); + }); + + it('Adds availability level to visualization #1', () => { + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.get('[aria-label="actionMenuButton"]').click(); + cy.get('[data-test-subj="editVizContextMenuItem"]').click(); + supressResizeObserverIssue(); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); + cy.get('.euiTab[id="availability-panel"]').click(); + cy.get('[title="Bar"]').click(); + cy.focused().type('{downArrow}'); + cy.focused().type('{enter}'); + cy.get('[data-test-subj="addAvailabilityButton"]').click(); + cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); + cy.get('[aria-label="Select #54B399 as the color"]').click(); + cy.get('[data-test-subj="nameFieldText"]').click().type('Available'); + cy.get('option').contains('≥').should('exist'); + cy.get('option').contains('≤').should('exist'); + cy.get('option').contains('>').should('exist'); + cy.get('option').contains('<').should('exist'); + cy.get('option').contains('=').should('exist'); + cy.get('option').contains('≠').should('exist'); + cy.get('[data-test-subj="expressionSelect"]').select('>'); + cy.get('[data-test-subj="valueFieldNumber"]').clear().type('0.5'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.get('[id="explorerPlotComponent"]').should('exist'); + cy.get('[class="lines"]').should('exist'); + cy.get('.textpoint').contains('Available').should('exist'); + cy.get('.euiBreadcrumb[href="#/application_analytics"]').click(); + cy.get('[data-test-subj="AvailableAvailabilityBadge"]').should('contain', 'Available'); + cy.get('[data-test-subj="AvailableAvailabilityBadge"][style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('exist'); + }); + + it('Saves visualization #2 to panel with availability level', () => { + changeTimeTo24('months'); + cy.get('[data-test-subj="app-analytics-logTab"]').click(); + cy.get('[id="explorerPlotComponent"]', { timeout: timeoutDelay }).should('exist'); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(query_two, {delay: TYPING_DELAY}); + cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="main-content-visTab"]').click(); + supressResizeObserverIssue(); + cy.get('.euiTab[id="availability-panel"]').click(); + cy.get('[title="Bar"]').click(); + cy.focused().type('{downArrow}'); + cy.focused().type('{enter}'); + cy.wait(delay); + cy.get('[data-test-subj="addAvailabilityButton"]').click(); + cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); + cy.get('[aria-label="Select #9170B8 as the color"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="nameFieldText"]').click().type('Super'); + cy.get('[data-test-subj="expressionSelect"]').select('<'); + cy.get('[data-test-subj="valueFieldNumber"]').clear().type('5.5'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="addAvailabilityButton"]').click(); + cy.get('[data-test-subj="euiColorPickerAnchor"]').first().click(); + cy.get('[aria-label="Select #CA8EAE as the color"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="nameFieldText"]').first().click().type('Cool'); + cy.get('[data-test-subj="expressionSelect"]').first().select('>'); + cy.get('[data-test-subj="valueFieldNumber"]').first().clear().type('0'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visTwoName); + cy.wait(delay); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="app-analytics-panelTab"]').click(); + cy.wait(delay); + cy.get('[id="explorerPlotComponent"]').should('have.length', 2); + moveToHomePage(); + cy.get('[data-test-subj="SuperAvailabilityBadge"][style="background-color: rgb(145, 112, 184); color: rgb(0, 0, 0);"]').should('contain', 'Super'); + }); + + it('Configuration tab shows details', () => { + cy.get('[data-test-subj="app-analytics-configTab"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="configBaseQueryCode"]').should('contain', baseQuery); + cy.get('[aria-label="List of services and entities"]').find('li').should('have.length', 1); + cy.get('[aria-label="List of trace groups"]').find('li').should('have.length', 2); + cy.get('option').should('have.length', 2); + }); + + + it('Changes availability visualization', () => { + cy.get('[data-test-subj="app-analytics-configTab"]').click(); + cy.wait(delay); + cy.get('select').select(visOneName); + cy.wait(delay); + moveToHomePage(); + cy.get('[data-test-subj="AvailableAvailabilityBadge"][style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('contain', 'Available'); + moveToApplication(nameOne); + cy.get('[data-test-subj="app-analytics-configTab"]').click(); + cy.wait(delay); + cy.get('select').find('option:selected').should('have.text', visOneName); + }) +}); + +describe('Separate from other plugins', () => { + it('Hides application visualizations in Event Analytics', () => { + cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics`); + cy.wait(delay * 3); + // When there are saved queries or visualizations there are two buttons + cy.get('body').then(($body) => { + if ($body.find('.euiButton').length == 2) { + cy.get('input.euiFieldSearch').type(visOneName, {delay: TYPING_DELAY}); + cy.wait(delay); + cy.get('.euiTableCellContent__text').contains('No items found').should('exist'); + cy.get('input.euiFieldSearch').clear().type(visTwoName, {delay: TYPING_DELAY}); + cy.wait(delay); + cy.get('.euiTableCellContent__text').contains('No items found').should('exist'); + cy.get('[class="euiFormControlLayoutClearButton"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="tablePaginationPopoverButton"]').click(); + cy.get('.euiContextMenuItem__text').contains('50 rows').click(); + cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="eventHomeAction"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="eventHomeAction__delete"]').click(); + cy.wait(delay); + cy.get('[data-test-subj="popoverModal__deleteButton"]').should('be.disabled'); + cy.get('[data-test-subj="popoverModal__deleteTextInput"]').type('delete'); + cy.get('[data-test-subj="popoverModal__deleteButton"]').should('not.be.disabled'); + cy.get('[data-test-subj="popoverModal__deleteButton"]').click(); + cy.wait(delay); + } + }) + }); + + it('Hides application visualizations in Operational Panels', () => { + cy.visit( + `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/` + ); + cy.get('[data-test-subj="operationalPanelsActionsButton"]', { timeout: timeoutDelay }).click(); + cy.get('[data-test-subj="addSampleContextMenuItem"]', { timeout: timeoutDelay }).click(); + cy.get('[data-test-subj="confirmModalConfirmButton"]', { timeout: timeoutDelay }).click(); + cy.wait(delay * 2); + cy.get('.euiLink').contains('[Logs] Web traffic Panel').first().click(); + cy.wait(delay * 2); + cy.get('[data-test-subj="addVisualizationButton"]').click(); + cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click(); + cy.get('option').contains(visOneName).should('not.exist'); + cy.get('option').contains(visTwoName).should('not.exist'); + }); + + it('Hides application panels in Operational Panels', () => { + cy.visit( + `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/` + ); + cy.get('[data-test-subj="operationalPanelSearchBar"]', { timeout: timeoutDelay }).type(`${nameOne}'s Panel`, {delay: TYPING_DELAY}); + cy.get('.euiTableCellContent__text').contains('No items found').should('exist'); + cy.get('.euiFormControlLayoutClearButton').click(); + cy.get('[data-test-subj="operationalPanelSearchBar"]').type('[Logs] Web traffic Panel', {delay: TYPING_DELAY}); + cy.get('.euiTableRow').first().within(($row) => { + cy.get('.euiCheckbox').click(); + }); + cy.get('[data-test-subj="operationalPanelsActionsButton"]', { timeout: timeoutDelay }).click(); + cy.get('[data-test-subj="deleteContextMenuItem"]', { timeout: timeoutDelay }).click(); + cy.get('[data-test-subj="popoverModal__deleteTextInput"]', { timeout: timeoutDelay }).type('delete'); + cy.get('[data-test-subj="popoverModal__deleteButton"]', { timeout: timeoutDelay }).should('not.be.disabled'); + cy.get('[data-test-subj="popoverModal__deleteButton"]', { timeout: timeoutDelay }).click(); + }); +}); + +describe('Editing application', () => { + beforeEach(() => { + moveToEditPage(); + }); + + it('Redirects to application after saving changes', () => { + cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('be.disabled'); + cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="servicesEntitiesComboBox"]').click(); + cy.get('.euiFilterSelectItem').contains(service_two).click(); + cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '2'); + cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="comboBoxToggleListButton"]').eq(1).click(); + cy.get('.euiFilterSelectItem').contains(trace_three).trigger('click'); + cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '3'); + cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click(); + cy.get('[data-test-subj="createButton"]').click(); + cy.get('[data-test-subj="app-analytics-configTab"]').click(); + cy.get('[data-test-subj="configBaseQueryCode"]').should('contain', baseQuery); + cy.get('[aria-label="List of services and entities"]').find('li').should('have.length', 2); + cy.get('[aria-label="List of trace groups"]').find('li').should('have.length', 3); + cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne); + }); +}); + +describe('Application Analytics home page', () => { + beforeEach(() => { + moveToHomePage(); + }) + + it('Show correct information in table', () => { + cy.get(`[data-test-subj="${nameOne}ApplicationLink"]`).should('exist'); + cy.get('[data-test-subj="appAnalytics__compositionColumn"]').should('contain', composition); + cy.get('[data-test-subj="AvailableAvailabilityBadge"][style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('contain', 'Available') + }); + + it('Renames application', () => { + cy.get('[data-test-subj="appAnalyticsActionsButton"]').click(); + cy.get('[data-test-subj="renameApplicationContextMenuItem"]').should('be.disabled'); + cy.get('[data-test-subj="appAnalyticsActionsButton"]').click(); + cy.get('.euiTableRow').first().within(($row) => { + cy.get('.euiCheckbox').click(); + }); + cy.wait(delay); + cy.get('[data-test-subj="appAnalyticsActionsButton"]').click(); + cy.get('[data-test-subj="renameApplicationContextMenuItem"]').click(); + cy.get('[data-test-subj="customModalFieldText"]').clear().focus().type(newName); + cy.get('[data-test-subj="runModalButton"]').click(); + cy.wait(delay); + cy.get('.euiToast').contains(`Application successfully renamed to "${newName}"`); + cy.get('.euiTableRow').first().within(($row) => { + cy.get('.euiLink').contains(newName).should('exist'); + }); + }); + + it('Deletes application', () => { + cy.get('[data-test-subj="appAnalyticsActionsButton"]').click(); + cy.get('[data-test-subj="deleteApplicationContextMenuItem"]').should('exist'); + cy.get('[data-test-subj="appAnalyticsActionsButton"]').click(); + cy.get('.euiTableRow').first().within(($row) => { + cy.get('.euiCheckbox').click(); + }); + cy.get('.euiTableRow').eq(1).within(($row) => { + cy.get('.euiCheckbox').click(); + }); + cy.get('.euiTableRow').eq(2).within(($row) => { + cy.get('.euiCheckbox').click(); + }); + cy.get('[data-test-subj="appAnalyticsActionsButton"]').click(); + cy.get('[data-test-subj="deleteApplicationContextMenuItem"]').click(); + cy.get('[data-test-subj="popoverModal__deleteTextInput"]').type('delete'); + cy.get('[data-test-subj="popoverModal__deleteButton"').click(); + cy.wait(delay); + cy.get('.euiToast').contains(`Applications successfully deleted!`); + cy.get(`[data-test-subj="${newName}ApplicationLink"]`).should('not.exist'); + }); +}); diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/10_scatter_chart.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/10_scatter_chart.spec.js new file mode 100644 index 000000000..d84e23b00 --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/10_scatter_chart.spec.js @@ -0,0 +1,228 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + delay, + TEST_QUERIES, + querySearch, + landOnEventVisualizations + } from '../../utils/event_constants'; + + const numberOfWindow = 4; + const legendSize = 20; + const pointSize = 30; + const pointSizeUpdated = 35; + const lineWidth = 7; + const lineWidthUpdated = 9; + const fillOpacity = 10; + const fillOpacityUpdated = 50; + const rotateLevel = 45; + const thresholdValue = 50; + + const renderScatterChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[6].query, TEST_QUERIES[6].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').type('scatter').type('{enter}'); + }; + + describe('Render scatter chart and verify default behaviour ', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart and verify by default the data gets render', () => { + cy.get('.xy').should('exist'); + }); + + it('Render scatter chart and verify you see data configuration panel and chart panel', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Dimensions').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Metrics').should('exist'); + cy.get('.euiIEFlexWrapFix').contains('Panel options').click(); + cy.get('.euiIEFlexWrapFix').contains('Legend').click(); + cy.get('.euiIEFlexWrapFix').contains('Chart styles').click(); + cy.get('.euiIEFlexWrapFix').contains('Color theme').click(); + cy.get('.euiIEFlexWrapFix').contains('Thresholds').click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + + it('Render scatter chart and verify the data configuration panel and chart panel are collapsable', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + }); + + describe('Render scatter chart for data configuration panel', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart and verify data config panel', () => { + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(0).should('contain', 'span(timestamp,1d)'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(1).should('contain', 'count()'); + }); + + it('Render scatter chart and verify data config panel no result found if metric is missing', () => { + cy.get('[data-test-subj="comboBoxClearButton"]').eq(1).click(); + cy.get('.euiTextColor.euiTextColor--subdued').contains('No results found').should('exist'); + cy.get('.euiComboBoxOption__content').contains('count()').click(); + cy.get('.main-svg').contains('No results found').should('not.exist'); + }); + }); + + describe('Render scatter chart for panel options', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart and verify the title gets updated according to user input ', () => { + cy.get('input[name="title"]').type("scatter Chart"); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('.gtitle').contains('scatter Chart').should('exist'); + }); + }); + + describe('Render scatter chart for legend', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart and verify legends for Show and Hidden', () => { + cy.get('[data-text="Show"]').should('have.text', 'Show'); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Hidden"]').should('have.text', 'Hidden').click(); + cy.get('[data-text="Hidden"] [data-test-subj="hidden"]').should('not.have.attr', 'checked'); + cy.get('[data-unformatted="max(bytes)"]').should('not.exist'); + }); + + it('Render scatter chart and verify legends for position Right and Bottom', () => { + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Bottom"]').should('have.text', 'Bottom').click(); + cy.get('[data-text="Bottom"] [data-test-subj="h"]').should('not.have.attr', 'checked'); + }); + + it('Render scatter chart and increase Legend Size', () => { + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).click().type(legendSize); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('.legendtext').should('have.css', 'font-size', '20px'); + }); + }); + + describe('Render scatter chart for Chart Styles ', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render ltime serires and verify chart style of Marker Mode', () => { + cy.get('#configPanel__panelOptions .euiFieldText').click().type('scatter chart'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]').click().type('This is the description for scatter chart with chart style of Points'); + cy.get('[data-text="Marker"]').should('have.text', 'Marker').click(); + cy.get('[data-text="Marker"] [data-test-subj="markers"]').should('have.attr', 'checked'); + + }); + + it('Render scatter chart and verify chart style of Marker Mode with larger Point size', () => { + cy.get('#configPanel__panelOptions .euiFieldText').click().type('scatter chart'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]').click().type('This is the description for scatter chart with chart style of Points'); + cy.get('[data-text="Marker"]').should('have.text', 'Marker').click(); + cy.get('[data-text="Marker"] [data-test-subj="markers"]').should('have.attr', 'checked'); + cy.get('input[type="range"]') + .then($el => $el[0].stepUp(pointSize)) + .trigger('change') + cy.get('.euiRangeSlider').should('have.value', pointSizeUpdated) + + }); + + it('Render scatter chart and verify chart style of Lines+Marker Mode', () => { + cy.get('#configPanel__panelOptions .euiFieldText').click().type('scatter chart'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]').click().type('This is the description for scatter chart with chart style of Lines and Marker'); + cy.get('[data-text="Lines + Markers"]').should('have.text', 'Lines + Markers').click(); + cy.get('[data-text="Lines + Markers"] [data-test-subj="lines+markers"]').should('not.have.attr', 'checked'); + + }); + + it('Render scatter chart and verify chart style of Lines+Marker Mode with Line Width, Fill Opacity and Point Size', () => { + cy.get('#configPanel__panelOptions .euiFieldText').click().type('scatter chart'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]').click().type('This is the description for scatter chart with chart style of Lines and Marker'); + cy.get('[data-text="Lines + Markers"]').should('have.text', 'Lines + Markers').click(); + cy.get('[data-text="Lines + Markers"] [data-test-subj="lines+markers"]').should('not.have.attr', 'checked'); + cy.get('input[type="range"]').eq(0) + .then($el => $el[0].stepUp(lineWidth)) + .trigger('change') + cy.get('.euiRangeSlider').eq(0).should('have.value', lineWidthUpdated) + cy.get('input[type="range"]').eq(1) + .then($el => $el[0].stepUp(fillOpacity)) + .trigger('change') + cy.get('.euiRangeSlider').eq(1).should('have.value', fillOpacityUpdated) + cy.get('input[type="range"]').eq(2) + .then($el => $el[0].stepUp(pointSize)) + .trigger('change') + cy.get('.euiRangeSlider').eq(2).should('have.value', pointSizeUpdated) + cy.get('input[type="range"]').eq(3) + .then($el => $el[0].stepUp(rotateLevel)) + .trigger('change') + cy.get('.euiRangeSlider').eq(3).should('have.value', rotateLevel) + }); + }); + + describe('Render scatter chart for color theme', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart and "Add Color theme"', () => { + cy.get('.euiButton__text').contains('+ Add color theme').click(); + cy.wait(delay); + cy.get('[data-test-subj="comboBoxInput"]').eq(5).click(); + cy.get('.euiComboBoxOption__content').contains('count()').click(); + cy.get('path[style*="rgb(252, 5, 5)"]').should('exist'); + + }); + }); + + describe('Render scatter chart and work with Thresholds', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart and add threshold', () => { + cy.get('.euiButton__text').contains('+ Add threshold').click(); + cy.get('[data-test-subj="nameFieldText"]').type('scatter chart Threshold'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).type(thresholdValue); + cy.get('[data-unformatted="scatter chart Threshold"]').should('be.visible'); + cy.get('path[style*="rgb(252, 5, 5)"]').should('exist'); + }); + }); + + describe('Render scatter chart and verify if reset works properly', () => { + beforeEach(() => { + renderScatterChart(); + }); + + it('Render scatter chart with all feild data then click on reset and verify reset works properly', () => { + cy.get('input[placeholder="Title"]').type('scatter chart'); + cy.get('textarea[placeholder="Description"]').type('Description For scatter chart'); + cy.get('[data-text="Hidden"]').should('have.text', 'Hidden').click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).click().type(legendSize); + cy.get('.euiButton__text').contains('+ Add color theme').click(); + cy.wait(delay); + cy.get('[data-test-subj="comboBoxInput"]').eq(5).click(); + cy.get('.euiComboBoxOption__content').contains('count()').click(); + cy.get('.euiButton__text').contains('+ Add threshold').click(); + cy.get('[data-test-subj="nameFieldText"]').type('scatter chart Threshold'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).type(thresholdValue); + cy.get('.euiButtonEmpty__text').contains('Reset').click(); + cy.get('input[placeholder="Title"]').should('not.have.value', 'scatter chart'); + cy.get('textarea[placeholder="Description"]').should('not.have.value', 'Description For scatter chart') + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).should('have.value', ''); + }); + }); + \ No newline at end of file diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/11_horizontalBar_chart.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/11_horizontalBar_chart.spec.js new file mode 100644 index 000000000..a93030962 --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/11_horizontalBar_chart.spec.js @@ -0,0 +1,244 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + delay, + TEST_QUERIES, + querySearch, + landOnEventVisualizations, + } from '../../utils/event_constants'; + + const numberOfWindow = 4; + const labelSize = 20; + const rotateLevel = 45; + const groupWidth = 10; + const groupWidthUpdated = 0.8; + const barWidth = 10; + const barWidthUpdated = 80; + const lineWidth = 7; + const lineWidthUpdated = 8; + const fillOpacity = 10; + const fillOpacityUpdated = 90; + const numberOfColor = 24; + + const renderHorizontalBarChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[4].query, TEST_QUERIES[4].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Horizontal Bar') + .type('{enter}'); + }; + + describe('Render horizontal bar chart and verify default behaviour ', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart and verify by default the data gets render', () => { + cy.get('.xy').should('exist'); + }); + + it('Render horizontal bar chart and verify you see data configuration panel and chart panel', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Dimensions').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Metrics').should('exist'); + cy.get('.euiIEFlexWrapFix').contains('Panel options').click(); + cy.get('.euiIEFlexWrapFix').contains('Legend').click(); + cy.get('.euiIEFlexWrapFix').contains('Chart styles').click(); + cy.get('.euiIEFlexWrapFix').contains('Color theme').click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + + it('Render horizontal bar chart and verify the data configuration panel and chart panel are collapsable', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + }); + + describe('Render horizontal bar chart for data configuration panel', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart and verify data config panel', () => { + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(0).should('contain', 'tags'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(1).should('contain', 'count()'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(2).should('contain', 'avg(bytes)'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(3).should('contain', 'host'); + }); + + it('Render horizontal bar chart and verify data config panel restrict user to select a duplicate field on dimension field', () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(0).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('.euiComboBoxOption__content').should('have.length', 1); + cy.get('.euiComboBoxOption__content').contains('tags'); + }); + + it('Render horizontal bar chart and verify data config panel Restrict user to select a duplicate field on Metrics field', () => { + cy.get('.euiText.euiText--extraSmall').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').should('not.contain', 'tags'); + cy.get('.euiComboBoxOption__content').should('have.length', 2); + }); + + it('Render horizontal bar chart and verify data config panel no result found if metric is missing', () => { + cy.get('.euiText.euiText--extraSmall').eq(0).click(); + cy.get('.euiText.euiText--extraSmall').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(0).click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiTextColor.euiTextColor--subdued').contains('No results found').should('exist'); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').contains('avg(bytes)').click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.main-svg').contains('No results found').should('not.exist'); + }); + }); + + describe('Render horizontal bar chart for panel options', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart and verify the title gets updated according to user input ', () => { + cy.get('input[name="title"]').type('horizontal bar chart'); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('.gtitle').contains('horizontal bar chart').should('exist'); + }); + }); + + describe('Render horizontal bar chart for legend', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart and verify legends for Show and Hidden', () => { + cy.get('[data-text="Show"]').should('have.text', 'Show'); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Hidden"]').should('have.text', 'Hidden').click(); + cy.get('[data-text="Hidden"] [data-test-subj="hidden"]').should('not.have.attr', 'checked'); + cy.get('[data-unformatted="max(bytes)"]').should('not.exist'); + }); + + it('Render horizontal bar chart and verify legends for position Right and Bottom', () => { + cy.get('[data-text="Right"]').should('have.text', 'Right'); + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Bottom"]').should('have.text', 'Bottom').click(); + cy.get('[data-text="Bottom"] [data-test-subj="h"]').should('not.have.attr', 'checked'); + }); + }); + + describe('Render horizontal bar chart for chart style options', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart and increase Label Size ', () => { + cy.get('[data-test-subj="valueFieldNumber"]').click().type(labelSize); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('[data-unformatted="login"]').should('have.css', 'font-size', '20px'); + }); + + it('Render horizontal bar chart and "Rotate bar labels"', () => { + cy.get('input[type="range"]') + .eq(0) + .then(($el) => $el[0].stepUp(rotateLevel)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(0).should('have.value', rotateLevel); + }); + + it('Render horizontal bar chart and change "Group Width"', () => { + cy.get('input[type="range"]') + .eq(1) + .then(($el) => $el[0].stepUp(groupWidth)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(1).should('have.value', groupWidthUpdated); + }); + + it('Render horizontal bar chart and change "Bar Width"', () => { + cy.get('input[type="range"]') + .eq(2) + .then(($el) => $el[0].stepDown(barWidth)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(4).should('have.value', barWidthUpdated); + }); + + it('Render horizontal bar chart and change "Line Width"', () => { + cy.get('input[type="range"]') + .eq(3) + .then(($el) => $el[0].stepUp(lineWidth)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(3).should('have.value', lineWidthUpdated); + }); + + it('Render horizontal bar chart and change "Fill Opacity"', () => { + cy.get('input[type="range"]') + .eq(4) + .then(($el) => $el[0].stepUp(fillOpacity)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(4).should('have.value', fillOpacityUpdated); + }); + }); + + describe('Render horizontal bar chart for color theme', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart and "Add color theme"', () => { + cy.get('.euiButton__text').contains('+ Add color theme').click(); + cy.wait(delay); + cy.get('[data-test-subj="comboBoxInput"]').eq(9).click(); + cy.get('.euiComboBoxOption__content').contains('avg(bytes)').click(); + cy.get('.point').find('path[style*="rgb(252, 5, 5)"]').should('have.length', numberOfColor); + }); + }); + + describe('Render horizontal bar chart and verify if reset works properly', () => { + beforeEach(() => { + renderHorizontalBarChart(); + }); + + it('Render horizontal bar chart with all feild data then click on reset and verify reset works properly', () => { + cy.get('input[placeholder="Title"]').type('horizontal bar chart'); + cy.get('textarea[placeholder="Description"]').type('Description For horizontal bar chart'); + cy.get('.euiButton__text').contains('Hidden').click(); + cy.get('.euiButton__text').contains('Stack').click(); + cy.get('[data-test-subj="valueFieldNumber"]').click().type(labelSize); + cy.get('input[type="range"]') + .eq(0) + .then(($el) => $el[0].stepUp(rotateLevel)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(1) + .then(($el) => $el[0].stepUp(groupWidth)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(2) + .then(($el) => $el[0].stepDown(barWidth)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(3) + .then(($el) => $el[0].stepUp(lineWidth)) + .trigger('change'); + cy.get('.euiButtonEmpty__text').contains('Reset').click(); + cy.get('input[placeholder="Title"]').should('not.have.value', 'horizontal bar chart'); + cy.get('textarea[placeholder="Description"]').should( + 'not.have.value', + 'Description For horizontal bar chart' + ); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Vertical"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Group"] [data-test-subj="group"]').should('have.attr', 'checked'); + cy.get('[data-test-subj="valueFieldNumber"]').should('have.value', ''); + }); + }); diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/12_boxPlot_chart.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/12_boxPlot_chart.spec.js new file mode 100644 index 000000000..d4dae465e --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/12_boxPlot_chart.spec.js @@ -0,0 +1,248 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + delay, + TEST_QUERIES, + querySearch, + landOnEventVisualizations, +} from '../../utils/event_constants'; + +const numberOfWindow = 4; +const labelSize = 20; +const rotateLevel = 45; +const boxSize = 7; +const boxSizeUpdated = 1; +const markerSize = 5; +const markerSizeUpdated = 1; +const jitter = 2; +const jitterUpdated = .1; +const fillOpacity = 10; +const fillOpacityUpdated = 50; +const numberOfColor = 24; + +const renderBoxPlot = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[4].query, TEST_QUERIES[4].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Box plot') + .type('{enter}'); +}; + +describe('Render box plot and verify default behaviour ', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot and verify by default the data gets render', () => { + cy.get('.xy').should('exist'); + }); + + it('Render box plot and verify you see data configuration panel and chart panel', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Dimensions').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Metrics').should('exist'); + cy.get('.euiIEFlexWrapFix').contains('Panel options').click(); + cy.get('.euiIEFlexWrapFix').contains('Legend').click(); + cy.get('.euiIEFlexWrapFix').contains('Chart styles').click(); + cy.get('.euiIEFlexWrapFix').contains('Color Theme').click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + + it('Render box plot and verify the data configuration panel and chart panel are collapsable', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); +}); + +describe('Render box plot for data configuration panel', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot and verify data config panel', () => { + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(0).should('contain', 'tags'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(1).should('contain', 'count()'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(2).should('contain', 'avg(bytes)'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(3).should('contain', 'host'); + }); + + it('Render box plot and verify data config panel restrict user to select a duplicate field on dimension field', () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(0).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('.euiComboBoxOption__content').should('have.length', 1); + cy.get('.euiComboBoxOption__content').contains('tags'); + }); + + it('Render box plot and verify data config panel Restrict user to select a duplicate field on Metrics field', () => { + cy.get('.euiText.euiText--extraSmall').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').should('not.contain', 'tags'); + cy.get('.euiComboBoxOption__content').should('have.length', 2); + }); + + it('Render box plot and verify data config panel no result found if metric is missing', () => { + cy.get('.euiText.euiText--extraSmall').eq(0).click(); + cy.get('.euiText.euiText--extraSmall').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(0).click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiTextColor.euiTextColor--subdued').contains('No results found').should('exist'); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').contains('avg(bytes)').click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.main-svg').contains('No results found').should('not.exist'); + }); +}); + +describe('Render box plot for panel options', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot and verify the title gets updated according to user input ', () => { + cy.get('input[name="title"]').type('box plot'); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('.gtitle').contains('box plot').should('exist'); + }); +}); + +describe('Render box plot for legend', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot and verify legends for Show and Hidden', () => { + cy.get('[data-text="Show"]').should('have.text', 'Show'); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Hidden"]').should('have.text', 'Hidden').click(); + cy.get('[data-text="Hidden"] [data-test-subj="hidden"]').should('not.have.attr', 'checked'); + cy.get('[data-unformatted="max(bytes)"]').should('not.exist'); + }); + + it('Render box plot and verify legends for position Right and Bottom', () => { + cy.get('[data-text="Right"]').should('have.text', 'Right'); + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Bottom"]').should('have.text', 'Bottom').click(); + cy.get('[data-text="Bottom"] [data-test-subj="h"]').should('not.have.attr', 'checked'); + }); +}); + +describe('Render box plot for chart style options', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot and increase Label Size ', () => { + cy.get('[data-test-subj="valueFieldNumber"]').click().type(labelSize); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('[data-unformatted="count()"]').should('have.css', 'font-size', '20px'); + }); + + it('Render box plot and "Rotate box labels"', () => { + cy.get('input[type="range"]') + .eq(0) + .then(($el) => $el[0].stepUp(rotateLevel)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(0).should('have.value', rotateLevel); + }); + + it('Render box plot and change "Box gap"', () => { + cy.get('input[type="range"]') + .eq(1) + .then(($el) => $el[0].stepUp(boxSize)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(1).should('have.value', boxSizeUpdated); + }); + + it('Render box plot and change "Marker size"', () => { + cy.get('input[type="range"]') + .eq(2) + .then(($el) => $el[0].stepDown(markerSize)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(2).should('have.value', markerSizeUpdated); + }); + + it('Render box plot and change "Jitter"', () => { + cy.get('input[type="range"]') + .eq(3) + .then(($el) => $el[0].stepDown(jitter)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(3).should('have.value', jitterUpdated); + }); + + it('Render box plot and change "Fill opacity"', () => { + cy.get('input[type="range"]') + .eq(4) + .then(($el) => $el[0].stepUp(fillOpacity)) + .trigger('change'); + cy.get('.euiRangeSlider').eq(4).should('have.value', fillOpacityUpdated); + }); +}); + +describe('Render box plot for color theme', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot and "Add color theme"', () => { + cy.get('.euiButton__text').contains('+ Add color theme').click(); + cy.wait(delay); + cy.get('[data-test-subj="comboBoxInput"]').eq(9).click(); + cy.get('.euiComboBoxOption__content').contains('avg(bytes)').click(); + cy.get('.points').find('path[style*="rgb(252, 5, 5)"]').should('have.length', numberOfColor); + }); +}); + +describe('Render box plot and verify if reset works properly', () => { + beforeEach(() => { + renderBoxPlot(); + }); + + it('Render box plot with all feild data then click on reset and verify reset works properly', () => { + cy.get('input[placeholder="Title"]').type('box plot'); + cy.get('textarea[placeholder="Description"]').type('Description For box plot'); + cy.get('.euiButton__text').contains('Hidden').click(); + cy.get('.euiButton__text').contains('Horizontal').click(); + cy.get('[data-test-subj="valueFieldNumber"]').click().type(labelSize); + cy.get('input[type="range"]') + .eq(0) + .then(($el) => $el[0].stepUp(rotateLevel)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(1) + .then(($el) => $el[0].stepUp(boxSize)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(2) + .then(($el) => $el[0].stepDown(markerSize)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(3) + .then(($el) => $el[0].stepUp(jitter)) + .trigger('change'); + cy.get('input[type="range"]') + .eq(4) + .then(($el) => $el[0].stepUp(fillOpacity)) + .trigger('change'); + cy.get('.euiButtonEmpty__text').contains('Reset').click(); + cy.get('input[placeholder="Title"]').should('not.have.value', 'box plot'); + cy.get('textarea[placeholder="Description"]').should( + 'not.have.value', + 'Description For box plot' + ); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Vertical"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Overlay"] [data-test-subj="overlay"]').should('have.attr', 'checked'); + cy.get('[data-test-subj="valueFieldNumber"]').should('have.value', ''); + }); +}); diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/13_logsView.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/13_logsView.spec.js new file mode 100644 index 000000000..542e3d776 --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/13_logsView.spec.js @@ -0,0 +1,241 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + delay, + TEST_QUERIES, + querySearch, + landOnEventVisualizations, + saveVisualizationAndVerify, + deleteVisualization, +} from '../../utils/event_constants'; + +const renderLogsView = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[8].query, TEST_QUERIES[8].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Logs view') + .type('{enter}'); +}; + +const renderLogsViewChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[2].query, TEST_QUERIES[2].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Logs view') + .type('{enter}'); +}; + +const fieldName = 'host'; + +describe('Render Logs view and verify default behavior', () => { + beforeEach(() => { + renderLogsView(); + }); + + it('Render Logs view and verify the default data', () => { + cy.get('.logs-view-container').should('exist'); + }); + + it('Render Logs view and verify Data Configuration panel default behavior', () => { + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Columns'); + cy.get('.euiFormLabel.euiFormRow__label').contains('Field'); + cy.get('.euiButton.euiButton--primary.euiButton--fullWidth.euiButton-isDisabled').should( + 'be.disabled' + ); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').should('be.disabled'); + }); + + it('Render Logs view and verify Style section for Logs view', () => { + cy.get('.vis-config-tabs .euiTab__content').contains('Style').should('exist'); + cy.get('.euiAccordion__triggerWrapper').contains('Panel options').should('exist'); + cy.get('#configPanel__panelOptions .euiFormRow__labelWrapper') + .contains('Title') + .should('exist'); + cy.get('#configPanel__panelOptions .euiFormRow__labelWrapper') + .contains('Description') + .should('exist'); + }); + + it('Table view should be enabled for Logs view', () => { + cy.get('.euiSwitch__label').contains('Table view').should('exist'); + cy.get('[data-test-subj="workspace__dataTableViewSwitch"][aria-checked="false"]').click(); + cy.get('.ag-header.ag-pivot-off').should('exist'); + }); + + it('Verify Style section for Logs view', () => { + cy.get('#data-panel').contains('Style').should('exist'); + cy.get('.euiAccordion__button').contains('Panel options').should('exist'); + cy.get('#configPanel__panelOptions').contains('Title').should('exist'); + cy.get('.euiFormHelpText.euiFormRow__text').contains('Name your visualization').should('exist'); + cy.get('#configPanel__panelOptions').contains('Description').should('exist'); + }); + + it('Add and Remove toggle buttons for fields section', () => { + cy.get('#available_fields').contains('Available Fields').should('exist'); + cy.get('[aria-label="Add agent to table"]').should('be.disabled'); + cy.get('#selected_fields').contains('Query fields').should('exist'); + cy.get('[aria-label="Remove clientip from table"]').should('be.disabled'); + }); +}); + +describe('Save and Delete Visualization', () => { + beforeEach(() => { + renderLogsView(); + }); + + it('Render Logs view, Save and Delete Visualization', () => { + saveVisualizationAndVerify(); + deleteVisualization(); + }); +}); + +describe('Render Logs view with no stats section in the query', () => { + beforeEach(() => { + renderLogsViewChart(); + }); + + it('Disabled Table view toogle button', () => { + cy.get('[data-test-subj="workspace__dataTableViewSwitch"]').should('be.disabled'); + }); + + it('Save toast message', () => { + const vis_name_sub_string = Math.floor(Math.random() * 100); + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').click(); + cy.get('.euiComboBoxOptionsList__rowWrap .euiFilterSelectItem').eq(0).click(); + cy.get( + '.euiPopover__panel .euiFormControlLayoutIcons [data-test-subj="comboBoxToggleListButton"]' + ) + .eq(0) + .click(); + cy.get('.euiPopover__panel input') + .eq(1) + .type(`Test visualization` + vis_name_sub_string); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.get('[data-test-subj="euiToastHeader"]') + .contains('There is no query or(and) visualization to save') + .should('exist'); + }); + + it('Verify Logs view details when PPL query does not have stats section ', () => { + cy.get('[data-test-subj="docTable"]').should('exist'); + cy.get('.osdDocTableHeader').contains('Time').should('exist'); + cy.get('.osdDocTableHeader').contains('_source').should('exist'); + }); + + it('Add and Remove toggle buttons for fields section should be enabled', () => { + //Add field + cy.get('[data-test-subj="fieldToggle-agent"]').click(); + cy.get('[data-test-subj="field-agent"]').should('exist'); + //Remove field + cy.get('[data-test-subj="fieldToggle-agent"]').click(); + cy.get('[aria-labelledby="selected_fields"] [data-test-subj="field-agent-showDetails"]').should( + 'not.exist' + ); + }); + + it('Search engine for fields under Visualizations', () => { + cy.get('[data-test-subj="eventExplorer__sidebarSearch"]').should('exist').type(fieldName); + cy.get('[data-test-subj="fieldToggle-host"]').click(); + cy.get('[data-test-subj="fieldList-selected"]').should('exist'); + }); + + it('View surrounding events button enabled', () => { + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + cy.get('.euiButton__text').eq(4).should('not.be.disabled'); + }); +}); + +describe('Event Details overlay', () => { + beforeEach(() => { + renderLogsView(); + }); + + it('Verify Event Details overaly should get opened after clicking on details toggle button', () => { + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + }); + + it('Options in Event Details overlay', () => { + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + cy.get('.euiTabs .euiTab__content').contains('Table'); + cy.get('.table.table-condensed.osdDocViewerTable').should('exist'); + cy.get('.euiTabs .euiTab__content').contains('JSON').click(); + cy.get('.euiCodeBlock__code.json').should('exist'); + cy.get('.euiTabs .euiTab__content').contains('Traces').click(); + cy.get('.euiCallOutHeader__title').contains('No Trace Id found in the event.').should('exist'); + cy.get('.euiLink.euiLink--primary').contains('Trace Analytics').click(); + cy.get('#trace-analytics').contains('Trace Analytics').should('exist'); + cy.get('.euiLink.euiLink--primary').contains('Log Correlation').click(); + cy.get('#log-correlation').contains('Log Correlation').should('exist'); + }); + + it('View surrounding events button disabled', () => { + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + cy.get('.euiButton.euiButton--primary.euiButton-isDisabled.header-button') + .contains('View surrounding events') + .should('be.disabled'); + }); + + it('Event Details overlay resizable and "X" buttons', () => { + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + cy.get('[title="Resize"]').click(); + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + cy.get('[data-test-subj="euiFlyoutCloseButton"]').should('exist').click(); + }); + + it('Table details on Event Details overlay', () => { + cy.get('.euiIcon.euiIcon--medium.euiIcon--inherit.euiButtonIcon__icon') + .eq(2) + .click({ force: true }); + cy.get('#eventsDocFyout').contains('Event Details').should('exist'); + cy.get('[data-test-subj="docTable"]').should('exist'); + }); +}); + +describe('Data Configuration panel when no stats in the query', () => { + beforeEach(() => { + renderLogsViewChart(); + }); + + it('Data Configuration panel default behavior', () => { + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Columns').should('exist'); + cy.get('.euiButton__text').eq(2).contains('Add').should('not.be.disabled'); + cy.get('.euiButton__text').eq(3).contains('Update Chart').should('not.be.disabled'); + }); + + it('Add button in Data Configuration panel', () => { + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Columns').should('exist'); + cy.get('.euiButton__text').eq(2).contains('Add').should('not.be.disabled').click(); + cy.get('.euiFormLabel.euiFormRow__label').contains('Field'); + cy.get('.euiIcon.euiIcon--medium.euiIcon--danger').should('exist'); + cy.get('[data-test-subj="comboBoxToggleListButton"]').eq(0).click(); + cy.get('.euiFlexItem.euiFilterSelectItem__content').eq(1).click(); + cy.get('.euiButton__text').contains('Update Chart').should('not.be.disabled').click(); + cy.get('[data-test-subj="docTable"]').should('exist'); + }); +}); diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/13_stats_chart.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/13_stats_chart.spec.js new file mode 100644 index 000000000..43e071f1e --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/13_stats_chart.spec.js @@ -0,0 +1,211 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + delay, + TEST_QUERIES, + querySearch, + landOnEventVisualizations +} from '../../utils/event_constants'; + +const numberOfWindow = 4; +const metricsPrecisionUpdated = 2; +const metricUnit = 'cm' ; +const titleSize = '25.5px'; +const titleSizeUpdated = '40px'; +const valueSize = '60.8px'; +const valueSizeUpdated = '73.0px'; + +const renderStatsChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[4].query, TEST_QUERIES[4].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').type('Stats').type('{enter}'); +}; + +describe('Render stats chart and verify default behaviour ', () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verify by default the data gets render', () => { + cy.get('.xy').should('exist'); + }); + + it('Render scatter chart and verify you see data configuration panel and chart panel', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Dimensions').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Metrics').should('exist'); + cy.get('.euiIEFlexWrapFix').contains('Panel options').click(); + cy.get('.euiIEFlexWrapFix').contains('Chart styles').click(); + cy.get('.euiIEFlexWrapFix').contains('Thresholds').click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + + it('Render stats chart and verify the data configuration panel and chart panel are collapsable', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); +}); + +describe('Render stats chart for data configuration panel', () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verify data config panel', () => { + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(0).should('contain', 'tags'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(1).should('contain', 'count()'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(2).should('contain', 'avg(bytes)'); + cy.get('.euiComboBoxPill.euiComboBoxPill--plainText').eq(3).should('contain', 'host'); + }); + + it('Render stats chart and verify no result found message if the dimension is removed' , () => { + cy.get('[data-test-subj="comboBoxClearButton"]').eq(0).click(); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); + cy.get('.euiTextColor.euiTextColor--subdued').contains('No results found').should('exist'); + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('.euiComboBoxOption__content').click(); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); + cy.get('.main-svg').contains('No results found').should('not.exist'); + }); + + it('Render stats chart and verify data config panel no result found if metric is missing', () => { + cy.get('.euiText.euiText--extraSmall').eq(0).click(); + cy.get('.euiText.euiText--extraSmall').eq(1).click(); + cy.get('[data-test-subj="comboBoxClearButton"]').eq(1).click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(0).click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.euiTextColor.euiTextColor--subdued').contains('No results found').should('exist'); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').contains('avg(bytes)').click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.main-svg').contains('No results found').should('not.exist'); + }); +}); + +describe('Render stats chart for panel options', () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verify the title gets updated according to user input ', () => { + cy.get('input[name="title"]').type("stats chart"); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('.gtitle').contains('stats chart').should('exist'); + }); +}); + +describe('Render stats chart verfiy functionality for Tooltip mode', () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verfiy the Show and Hidden Tooltip modes', () => { + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(0).should('have.text', 'Show'); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(1).should('have.text', 'Hidden') + .click(); + }); +}); + +describe('Render stats chart verfiy functionality for Tooltip text', () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verfiy the Tootltip text -> All , Dimension , Metric', () => { + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(2).should('have.text', 'All'); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(3).should('have.text', 'Dimension') + .click(); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(4).should('have.text', 'Series') + .click(); + }); +}); + +describe('Render stats chart for Chart Styles ', () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verify the various chart type selected', () => { + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(5).should('have.text', 'Auto'); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(6).should('have.text', 'Horizontal').click(); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(7).should('have.text', 'Text mode').click(); + }); + + it('Render stats chart and verify the various chart orientation selected', () => { + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(8).should('have.text', 'Auto'); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(9).should('have.text', 'Horizontal').click(); + cy.get('.euiButton__text.euiButtonGroupButton__textShift').eq(10).should('have.text', 'Vertical').click(); + }); + + it('Render stats chart and verify Metric unit and Metric Precision on chart ', () => { + cy.get('[data-test-subj="valueFieldText"]').click().type(metricUnit); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).click().type(metricsPrecisionUpdated); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + }); + + it('Render stats chart and verify behaviour for Title size and Value size on chart ', () => { + cy.get('.annotation-text').eq(0).should('have.css', 'font-size', titleSize); + cy.get('.annotation-text').eq(2).should('have.css', 'font-size', titleSize); + cy.get('.annotation-text').eq(4).should('have.css', 'font-size', titleSize); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).click().type(titleSizeUpdated); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + cy.get('.annotation-text').eq(1).should('have.css', 'font-size', valueSize); + cy.get('.annotation-text').eq(3).should('have.css', 'font-size', valueSize); + cy.get('.annotation-text').eq(5).should('have.css', 'font-size', valueSize); + cy.get('[data-test-subj="valueFieldNumber"]').eq(2).click().type(valueSizeUpdated); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + }); +}); + +describe('Render stats chart and verify the Text Mode options' , () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verify text modes ', () => { + cy.get('[data-text="Names"]').should('have.text', 'Names').click(); + cy.get('[data-text="Values"]').should('have.text', 'Values').click(); + cy.get('[data-text="Values + Names"]').should('have.text', 'Values + Names').click(); + cy.wait(delay); + }); +}); + +describe('Render stats chart and verify the +add threshold button option' , () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and verify the +Add Threshold button for color picker' , () => { + cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); + cy.get('.euiColorPickerSwatch.euiColorPicker__swatchSelect').eq(5).click(); + cy.wait(delay); + }); +}); + +describe('Render stats chart and verify the reset button' , () => { + beforeEach(() => { + renderStatsChart(); + }); + + it('Render stats chart and test the Reset button functionality' , () => { + cy.get('[data-test-subj="valueFieldText"]').click().type(metricUnit); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(0).click().type(metricsPrecisionUpdated); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(1).click().type(titleSizeUpdated); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + cy.get('[data-test-subj="valueFieldNumber"]').eq(2).click().type(valueSizeUpdated); + cy.get('.euiSpacer.euiSpacer--s').eq(12).click(); + cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); + cy.get('.euiColorPickerSwatch.euiColorPicker__swatchSelect').eq(5).click(); + cy.get('[data-test-subj="visualizeEditorResetButton"]').click(); + }); +}); \ No newline at end of file diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/7_pie_chart.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/7_pie_chart.spec.js new file mode 100644 index 000000000..b731db10b --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/7_pie_chart.spec.js @@ -0,0 +1,202 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + delay, + TEST_QUERIES, + querySearch, + landOnEventVisualizations, + renderDataConfig, + saveVisualizationAndVerify, + deleteVisualization, + } from '../../utils/event_constants'; + + const renderPieChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[3].query, TEST_QUERIES[3].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Pie').click(); + }; + + const aggregationValues = [ + 'COUNT', + 'SUM', + 'AVERAGE', + 'MAX', + 'MIN', + 'VAR_SAMP', + 'VAR_POP', + 'STDDEV_SAMP', + 'STDDEV_POP', + ]; + + describe.only('Render Pie chart and verify default behavior', () => { + beforeEach(() => { + renderPieChart(); + }); + + it('Render Pie chart and verify the default data', () => { + cy.get('.plot-container.plotly').should('exist'); + }); + + it('Render Pie chart and verify Data Configuration panel default behavior', () => { + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Dimensions').should('exist'); + cy.get('.first-division .euiFormRow__labelWrapper').contains('Aggregation').should('exist'); + cy.get('.first-division .euiFormLabel.euiFormRow__label').contains('Field').should('exist'); + cy.get('.first-division .euiFormLabel.euiFormRow__label') + .contains('Custom label') + .should('exist'); + cy.get('.first-division .euiButton__text').contains('Add').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Metrics').should('exist'); + cy.get('.euiButton__text').contains('Update chart').should('exist'); + }); + + it('Render Pie chart and verify Style section for Pie chart', () => { + cy.get('#data-panel').contains('Style').should('exist'); + cy.get('[aria-controls="configPanel__panelOptions"]').contains('Panel options').should('exist'); + cy.get('[aria-controls="configPanel__legend"]').contains('Legend').should('exist'); + cy.get('.euiForm.visEditorSidebar__form .euiIEFlexWrapFix') + .contains('Tooltip options') + .should('exist'); + cy.get('[aria-controls="configPanel__chartStyles"]').contains('Chart styles').should('exist'); + }); + + it('Options under Legend section', () => { + cy.get('#configPanel__legend').contains('Legend'); + cy.get('.euiTitle.euiTitle--xxsmall').eq(3).contains('Show legend'); + cy.get('[data-text="Show"]').eq(0).contains('Show'); + cy.get('[data-text="Hidden"]').eq(0).contains('Hidden'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Position'); + cy.get('[data-text="Right"]').contains('Right'); + cy.get('[data-text="Bottom"]').contains('Bottom'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Legend size').should('exist'); + }); + + it('Options under Tooltip options section', () => { + cy.get('.euiIEFlexWrapFix').contains('Tooltip options').should('exist'); + cy.get('[data-text="Show"]').eq(1).contains('Show'); + cy.get('[data-text="Hidden"]').eq(1).contains('Hidden'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Tooltip text'); + cy.get('[data-text="All"]').contains('All'); + cy.get('[data-text="Label"]').contains('Label'); + cy.get('[data-text="Value"]').contains('Value'); + cy.get('[data-text="Percent"]').contains('Percent'); + }); + + it('Options under Chart Styles section', () => { + cy.get('.euiIEFlexWrapFix').contains('Chart styles').should('exist'); + cy.get('#configPanel__chartStyles').contains('Mode'); + cy.get('.euiTitle.euiTitle--xxsmall').eq(9).contains('Label size'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Color theme'); + }); + + it('Table view should be enabled for Pie chart', () => { + cy.get('.euiSwitch__label').contains('Table view').should('exist'); + cy.get('[data-test-subj="workspace__dataTableViewSwitch"][aria-checked="false"]').click(); + cy.get('.ag-header.ag-pivot-off').should('exist'); + }); + + it('Render Pie chart and verify legends for Position Right and Bottom', () => { + cy.get('[data-text="Right"]').should('have.text', 'Right'); + cy.get('[data-text="Right"] [data-test-subj="v"]').should('have.attr', 'checked'); + cy.get('[data-text="Bottom"]').should('have.text', 'Bottom').click(); + cy.get('[data-text="Bottom"] [data-test-subj="h"]').should('not.have.attr', 'checked'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click({ force: true, multiple: true }); + }); + + it('Render Pie chart and verify legends for Show and Hidden', () => { + cy.get('[data-text="Show"]').eq(0).should('have.text', 'Show'); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Hidden"]').eq(0).should('have.text', 'Hidden').click(); + cy.get('[data-text="Hidden"] [data-test-subj="hidden"]').should('not.have.attr', 'checked'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click({ force: true, multiple: true }); + }); + }); + + describe('Save and Delete Visualization', () => { + beforeEach(() => { + renderPieChart(); + }); + + it('Render Pie chart, Save and Delete Visualization', () => { + saveVisualizationAndVerify(); + deleteVisualization(); + }); + }); + + describe('Color Theme section', () => { + beforeEach(() => { + renderPieChart(); + }); + + it('Default option in Color Theme', () => { + cy.get('.euiTitle.euiTitle--xxsmall') + .contains('Color Theme') + .scrollIntoView() + .should('be.visible'); + cy.get('.euiSuperSelectControl').contains('Default').should('exist'); + }); + + it('Render pie chart with single color option', () => { + cy.get('.euiTitle.euiTitle--xxsmall') + .contains('Color Theme') + .scrollIntoView() + .should('be.visible'); + cy.get('.euiSuperSelectControl').contains('Default').click(); + cy.get('.euiColorPalettePicker__item').contains('Single Color').click(); + cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); + cy.get('.euiColorPickerSwatch.euiColorPicker__swatchSelect').eq(2).click(); + cy.get('.pielayer').should('exist'); + }); + }); + + describe('Renders Pie chart and Data Configurations section for Pie chart', () => { + beforeEach(() => { + landOnEventVisualizations(); + renderPieChart(); + }); + + it('Renders Dimensions and Metrics under Data Configurations for Pie chart', () => { + renderDataConfig(); + }); + + it('Validate "Add" and "X" buttons', () => { + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Configurations'); + cy.get('.euiText.euiText--extraSmall').eq(0).click(); + cy.get('.euiButton.euiButton--primary.euiButton--fullWidth').contains('Add').click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(2).click(); + cy.get('.euiComboBoxOption__content').eq(0).click(); + cy.get('.euiIcon.euiIcon--medium.euiIcon--danger').eq(1).click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(4).click(); + cy.get('.euiComboBoxOption__content').eq(1).click(); + cy.get('.euiFieldText[placeholder="Custom label"]').eq(1).type('Demo field'); + cy.get('.euiIcon.euiIcon--medium.euiIcon--danger').eq(1).click(); + cy.get('.euiButton.euiButton--primary.euiButton--fullWidth').contains('Add').should('exist'); + }); + + it('Verify drop down values for Aggregation', () => { + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Configurations'); + cy.get('.euiTitle.euiTitle--xxsmall').eq(1).contains('Dimensions').should('exist'); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(0).contains('Aggregation'); + cy.get('.euiText.euiText--extraSmall').eq(0).click(); + cy.get('[data-test-subj="comboBoxSearchInput"]').eq(0).click(); + aggregationValues.forEach(function (value) { + cy.get('.euiComboBoxOption__content').contains(value); + }); + }); + + it('Collapsible mode for Data Configuration panel', () => { + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Configurations'); + cy.get('.euiResizableButton.euiResizableButton--horizontal').eq(1).click(); + cy.get('[data-test-subj="panel-1-toggle"]').click(); + cy.get('[class*="euiResizableToggleButton-isCollapsed"]').eq(1).should('exist'); + cy.get('.euiResizablePanel.euiResizablePanel--middle') + .contains('Data Configurations') + .should('not.be.focused'); + }); + }); + \ No newline at end of file diff --git a/dashboards-observability/.cypress/integration/VisualizationCharts/9_coordinateMap_chart.spec.js b/dashboards-observability/.cypress/integration/VisualizationCharts/9_coordinateMap_chart.spec.js new file mode 100644 index 000000000..175011188 --- /dev/null +++ b/dashboards-observability/.cypress/integration/VisualizationCharts/9_coordinateMap_chart.spec.js @@ -0,0 +1,195 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/// +import { + TEST_QUERIES, + querySearch, + landOnEventVisualizations +} from '../../utils/event_constants'; + +const numberOfWindow = 4; +const labelSize = 20; +const latitudeRangeMin = 40; +const latitudeRangeMax = 70; +const longitudeRangeMin = -130; +const longitudeRangeMax = -55; + +const renderCoordinateMap = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[0].query, TEST_QUERIES[0].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').type('Coordinate Map').type('{enter}'); +}; + +const renderDataForCoordinateMap = () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('.euiComboBoxOption__content').contains('DestLocation').click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').contains('AvgTicketPrice').click(); + cy.get('[data-test-subj="comboBoxInput"]').eq(4).click(); + cy.get('.euiComboBoxOption__content').contains('Dest').click(); + cy.get('.euiButton__text').contains('Update chart').click(); + cy.get('.layer.land').should('exist'); + cy.get('stop[stop-color="rgb(5, 10, 172)"]').should('exist'); +} + +describe('Render coordinate map and verify default behaviour ', () => { + beforeEach(() => { + renderCoordinateMap(); + }); + + it('Render coordinate map and verify by default the data dont gets render', () => { + cy.get('.layer.land').should('not.exist'); + cy.get('.euiTextColor.euiTextColor--subdued').contains('No results found').should('exist'); + }); + + it('Render coordinate map and verify you see data configuration panel and chart panel', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Data Configurations').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Dimensions').should('exist'); + cy.get('.euiTitle.euiTitle--xxsmall').contains('Metrics').should('exist'); + cy.get('.euiIEFlexWrapFix').contains('Panel options').click(); + cy.get('.euiIEFlexWrapFix').contains('Text').click(); + cy.get('.euiIEFlexWrapFix').contains('Chart styles').click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); + + it('Render coordinate map and verify the data configuration panel and chart panel are collapsable', () => { + cy.get('.euiPanel.euiPanel--paddingSmall').should('have.length', numberOfWindow); + cy.get('[aria-label="Press to toggle this panel"]').eq(1).click(); + cy.get('[aria-label="Press to toggle this panel"]').eq(2).click(); + }); +}); + +describe('Render coordinate map for data configuration panel', () => { + beforeEach(() => { + renderCoordinateMap(); + }); + + it('Render coordinate map and verify data config panel', () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(1).contains('Select a field').should('exist'); + cy.get('[data-test-subj="comboBoxInput"]').eq(3).contains('Select a field').should('exist'); + cy.get('[data-test-subj="comboBoxInput"]').eq(4).contains('Select a field').should('exist'); + }); + + it('Render coordinate map and verify data gets render only after selecting the field value in data configuration panel', () => { + renderDataForCoordinateMap(); + }); + + it('Render coordinate map and verify data config dimensions panel "Field" contains only location', () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(1).click(); + cy.get('.euiComboBoxOption__content').contains('DestLocation').should('exist'); + cy.get('.euiComboBoxOption__content').contains('OriginLocation').should('exist'); + }); + + it('Render coordinate map and verify data config metrics panel "Field" contains only value which return either integer or float value', () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(3).click(); + cy.get('.euiComboBoxOption__content').contains('AvgTicketPrice').should('exist'); + cy.get('.euiComboBoxOption__content').contains('DistanceMiles').should('exist'); + cy.get('.euiComboBoxOption__content').should('not.contain', 'DestLocation'); + cy.get('.euiComboBoxOption__content').should('have.length', 6); + }); + + it('Render coordinate map and verify data config metric panel "Plot Label" contains a combination of string value and integer value', () => { + cy.get('[data-test-subj="comboBoxInput"]').eq(4).click(); + cy.get('.euiComboBoxOption__content').contains('AvgTicketPrice').should('exist'); + cy.get('.euiComboBoxOption__content').contains('Dest').should('exist'); + cy.get('.euiComboBoxOption__content').contains('DestLocation').should('exist'); + }); +}); + +describe('Render coordinate map for panel options', () => { + beforeEach(() => { + renderCoordinateMap(); + renderDataForCoordinateMap(); + }); + + it('Render coordinate map and verify the title gets updated according to user input ', () => { + cy.get('input[name="title"]').type("coordinate map"); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('.gtitle').contains('coordinate map').should('exist'); + }); +}); + +describe('Render coordinate map for text', () => { + beforeEach(() => { + renderCoordinateMap(); + renderDataForCoordinateMap(); + }); + + it('Render coordinate map and verify by default the "Show" is enabled for "Show Text"', () => { + cy.get('[data-text="Show"]').should('have.text', 'Show'); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-unformatted="Duluth International Airport"]').should('exist'); + }); + + it('Render coordinate map and change "Show Text" to "Hidden"', () => { + cy.get('[data-text="Hidden"]').should('have.text', 'Hidden').click(); + cy.get('[data-text="Hidden"] [data-test-subj="hidden"]').should('not.have.attr', 'checked'); + cy.get('[data-unformatted="Duluth International Airport"]').should('not.exist'); + }); + + it('Render coordinate map and verify by default the "Top" is enabled for "Position"', () => { + cy.get('[data-text="Top"]').should('have.text', 'Top'); + cy.get('[data-text="Top"] [data-test-subj="top center"]').should('have.attr', 'checked'); + }); + + it('Render coordinate map and change "Position" to "Right", "Bottom" and "Left"', () => { + cy.get('[data-text="Right"]').should('have.text', 'Right').click(); + cy.get('[data-text="Right"] [data-test-subj="middle right"]').should('not.have.attr', 'checked'); + cy.get('[data-text="Bottom"]').should('have.text', 'Bottom').click(); + cy.get('[data-text="Bottom"] [data-test-subj="bottom center"]').should('not.have.attr', 'checked'); + cy.get('[data-text="Left"]').should('have.text', 'Left').click(); + cy.get('[data-text="Left"] [data-test-subj="middle left"]').should('not.have.attr', 'checked'); + }); +}); + +describe('Render coordinate map for chart style options', () => { + beforeEach(() => { + renderCoordinateMap(); + renderDataForCoordinateMap(); + }); + + it('Render coordinate map and change Label Size ', () => { + cy.get('[data-test-subj="valueFieldNumber"]').click().type(labelSize); + cy.get('textarea[name="description"]').should('exist').click(); + cy.get('[data-unformatted="Duluth International Airport"]').should('have.css', 'font-size', '20px'); + cy.get('[data-test-subj="valueFieldNumber"]').should('have.value', labelSize) + }); + + it('Render coordinate map and change "Latitude Range"', () => { + cy.get('input[type="number"]').eq(1).should('have.value', latitudeRangeMin); + cy.get('input[type="number"]').eq(2).should('have.value', latitudeRangeMax); + cy.get('input[type="number"]').eq(1).click().clear().type(30); + }); + + it('Render coordinate map and change "Longitude Range"', () => { + cy.get('input[type="number"]').eq(3).should('have.value', longitudeRangeMin); + cy.get('input[type="number"]').eq(4).should('have.value', longitudeRangeMax); + cy.get('input[type="number"]').eq(4).click().clear().type(40); + }); +}); + +describe('Render coordinate map and verify if reset works properly', () => { + beforeEach(() => { + renderCoordinateMap(); + renderDataForCoordinateMap(); + }); + + it('Render coordinate map with all feild data then click on reset and verify reset works properly', () => { + cy.get('input[placeholder="Title"]').type('coordinate map'); + cy.get('textarea[placeholder="Description"]').type('Description For coordinate map'); + cy.get('.euiButton__text').contains('Hidden').click(); + cy.get('.euiButton__text').contains('Right').click(); + cy.get('[data-test-subj="valueFieldNumber"]').click().type(labelSize); + cy.get('.euiButtonEmpty__text').contains('Reset').click(); + cy.get('input[placeholder="Title"]').should('not.have.value', 'coordinate map'); + cy.get('textarea[placeholder="Description"]').should('not.have.value', 'Description For coordinate map'); + cy.get('[data-text="Show"] [data-test-subj="show"]').should('have.attr', 'checked'); + cy.get('[data-text="Top"] [data-test-subj="top center"]').should('have.attr', 'checked'); + cy.get('[data-test-subj="valueFieldNumber"]').should('have.value', ''); + }); +}); diff --git a/dashboards-observability/.cypress/integration/app_analytics.spec.js b/dashboards-observability/.cypress/integration/app_analytics.spec.js deleted file mode 100644 index 61dcbbef7..000000000 --- a/dashboards-observability/.cypress/integration/app_analytics.spec.js +++ /dev/null @@ -1,625 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/// - -import { - delay, - moveToHomePage, - moveToCreatePage, - moveToApplication, - moveToEditPage, - changeTimeTo24, - expectMessageOnHover, - baseQuery, - nameOne, - nameTwo, - description, - service_one, - service_two, - trace_one, - trace_two, - trace_three, - visOneName, - visTwoName, - composition, - newName, - TYPING_DELAY -} from '../utils/app_constants'; -import { supressResizeObserverIssue } from '../utils/constants'; - -describe('Creating application', () => { - beforeEach(() => { - moveToCreatePage(); - }); - - it('Disables create button if missing fields', () => { - expectMessageOnHover('Name is required.'); - cy.get('[data-test-subj="nameFormRow"]').type(nameOne); - expectMessageOnHover('Provide at least one log source, service, entity or trace group.'); - cy.get('.euiAccordion').contains('Log source').trigger('mouseover').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); - cy.get('.euiButton').contains('Create').should('not.be.disabled'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').clear(); - expectMessageOnHover('Provide at least one log source, service, entity or trace group.'); - cy.get('.euiAccordion').contains('Services & entities').trigger('mouseover').click();; - cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click(); - cy.focused().type('{downArrow}'); - cy.focused().type('{enter}'); - cy.get('.euiBadge').contains('1').should('exist'); - cy.get('.euiButton').contains('Create').should('not.be.disabled'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); - cy.get('.euiAccordion').contains('Trace groups').trigger('mouseover').click(); - cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); - cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click') - cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); - cy.get('.euiBadge').contains('2').should('exist'); - cy.get('.euiButton').contains('Create').should('not.be.disabled'); - }); - - it('Suggests correct autocompletion', () => { - cy.get('.euiAccordion').contains('Log source').trigger('mouseover').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); - cy.get('.aa-List').find('.aa-Item').should('have.length', 1); - cy.get('.aa-Item').contains('source').should('exist'); - cy.focused().type('{enter}'); - cy.get('.aa-List').find('.aa-Item').should('have.length', 1); - cy.get('.aa-Item').contains('=').should('exist'); - cy.focused().type('{enter}'); - cy.focused().type('opensearch'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); - cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_flights').click(); - cy.focused().clear(); - cy.get('.aa-List').find('.aa-Item').should('have.length', 1); - cy.focused().type('{enter}'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source '); - cy.focused().type('{enter}'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = '); - cy.focused().type('opensearch'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); - cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_flights').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights '); - cy.focused().type('{downArrow}'); - cy.focused().type('{enter}'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights, '); - cy.focused().type('opensearch'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); - cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_logs').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights,opensearch_dashboards_sample_data_logs '); - }); - - it('Creates an application and redirects to application', () => { - cy.get('[data-test-subj="nameFormRow"]').type(nameOne); - cy.get('[data-test-subj="descriptionFormRow"]').type('This application is for testing.'); - cy.get('.euiAccordion').contains('Log source').trigger('mouseover').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); - cy.get('.euiAccordion').contains('Services & entities').trigger('mouseover').click(); - cy.get('[data-test-subj="servicesEntitiesComboBox"]').click(); - cy.focused().type('{downArrow}'); - cy.focused().type('{enter}'); - cy.get('.euiBadge').contains('1').should('exist'); - cy.get('.euiAccordion').contains('Trace groups').trigger('mouseover').click(); - cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); - cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click'); - cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); - cy.get('.euiBadge').contains('2').should('exist'); - cy.get('.euiButton').contains('Create').should('not.be.disabled'); - cy.get('.euiButton').contains('Create').click(); - cy.wait(delay*3); - cy.get('.euiTitle').contains(nameOne).should('exist'); - cy.get('.euiTab').contains('Panel').click(); - cy.get('.euiText').contains('Start by adding your first visualization').should('exist'); - }); - - it('Hides application panels in Operational Panels', () => { - cy.visit( - `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/` - ); - cy.wait(delay*4); - if (cy.get('.euiButton').contains('Create panel').length < 2) { - cy.get('input.euiFieldSearch').type(`${nameOne}'s Panel`, {delay: TYPING_DELAY}); - cy.wait(delay); - cy.get('.euiTableCellContent__text').contains('No items found').should('exist'); - cy.get('.euiFormControlLayoutClearButton').click(); - cy.wait(delay); - } - }); - - it('Redirects to home page on cancel', () => { - cy.get('.euiButton').contains('Cancel').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Applications').should('exist'); - }); - - it('Saves current input on reload', () => { - cy.get('[data-test-subj="nameFormRow"]').type(nameOne); - cy.get('[data-test-subj="descriptionFormRow"]').type(description); - cy.get('.euiAccordion').contains('Log source').trigger('mouseover').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); - cy - .get('[data-test-subj="searchAutocompleteTextArea"]') - .focus() - .type(baseQuery, {delay: TYPING_DELAY}); - cy.get('.euiAccordion').contains('Services & entities').trigger('mouseover').click(); - cy.wait(delay); - cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click(); - cy.wait(delay); - cy.get('.euiFilterSelectItem').contains(service_one).trigger('click'); - cy.get('.euiBadge').contains('1').should('exist'); - cy.get('.euiAccordion').contains('Trace groups').trigger('mouseover').click(); - cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); - cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click'); - cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); - cy.get('.euiBadge').contains('2').should('exist'); - cy.reload(); - cy.wait(delay); - cy.get('[data-test-subj="nameFormRow"]').find('.euiFieldText').should('contain.value', nameOne); - cy.get('[data-test-subj="descriptionFormRow"]').find('.euiFieldText').should('contain.value', description); - cy.get('.euiAccordion').contains('Log source').trigger('mouseover').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', baseQuery); - cy.get('.euiBadge').contains('1').should('exist'); - cy.get('.euiBadge').contains('2').should('exist'); - }); - - it('Shows clear modals before clearing', () => { - cy.get('.euiAccordion').contains('Log source').click(); - cy.get('.euiButton-isDisabled').contains('Clear').should('exist'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); - cy.get('.euiButton').contains('Clear').click(); - cy.get('.euiButton--danger').contains('Clear').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', ''); - cy.get('.euiAccordion').contains('Services & entities').trigger('mouseover').click(); - cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click(); - cy.get('.euiFilterSelectItem').contains(service_one).trigger('click'); - cy.get('.euiBadge').contains('1').should('exist'); - cy.get('.euiAccordion-isOpen').within(($service) => { - cy.get('.euiButton').contains('Clear all').click(); - }) - cy.get('.euiButton--danger').contains('Clear all').click(); - cy.get('.euiBadge').contains('1').should('not.exist'); - cy.get('.euiBadge').contains('0').should('exist'); - cy.get('.euiAccordion').contains('Services & entities').trigger('mouseover').click(); - cy.get('.euiAccordion').contains('Trace groups').trigger('mouseover').click(); - cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http'); - cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click'); - cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click'); - cy.get('.euiBadge').contains('2').should('exist'); - cy.get('.euiAccordion-isOpen').within(($trace) => { - cy.get('.euiButton').contains('Clear all').click(); - }) - cy.get('.euiButton--danger').contains('Clear all').click(); - cy.get('.euiBadge').contains('2').should('not.exist'); - cy.get('.euiBadge').contains('0').should('exist'); - }); -}); - -describe('Viewing application', () => { - before(() => { - moveToApplication(nameOne); - }); - - it('Has working breadcrumbs', () => { - cy.get('.euiBreadcrumb').contains('Cypress').click(); - cy.wait(delay); - cy.get('.euiTitle').contains(nameOne).should('exist'); - cy.get('.euiBreadcrumb').contains('Application analytics').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Applications').should('exist'); - cy.get('.euiBreadcrumb').contains('Observability').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Event analytics').should('exist'); - }); - - it('Shares time range among tabs', () => { - moveToApplication(nameOne); - changeTimeTo24('months'); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - cy.get('.euiTab').contains('Services').click(); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - cy.get('.euiTab').contains('Traces & Spans').click(); - supressResizeObserverIssue(); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - cy.get('.euiTab').contains('Log Events').click(); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - cy.get('.euiTab').contains('Panel').click(); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - }); - - it('Shows latency variance in dashboards table', () => { - moveToApplication(nameOne); - changeTimeTo24('months'); - cy.get('.euiBasicTable').first().within(($table) => { - cy.get('.plot-container').should('have.length.at.least', 1); - }) - }); - - it('Saves time range for each application', () => { - moveToCreatePage(); - cy.get('[data-test-subj="nameFormRow"]').type(nameTwo); - cy.get('.euiAccordion').contains('Log source').trigger('mouseover').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY}); - cy.get('.euiButton').contains('Create').should('not.be.disabled'); - cy.get('.euiButton').contains('Create').click(); - cy.wait(delay); - cy.get('.euiTitle').contains(nameTwo).should('exist'); - changeTimeTo24('weeks'); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 weeks'); - cy.get('.euiBreadcrumb').contains('Application analytics').click(); - cy.wait(delay); - cy.get('.euiLink').contains(nameOne).click(); - cy.wait(delay); - cy.get('.euiTitle').contains(nameOne).should('exist'); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - cy.get('.euiBreadcrumb').contains('Application analytics').click(); - cy.wait(delay); - cy.get('.euiLink').contains(nameTwo).click(); - cy.wait(delay); - cy.get('.euiTitle').contains(nameTwo).should('exist'); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 weeks'); - }); - - it('Adds filter when Trace group name is clicked', () => { - moveToApplication(nameOne); - cy.get('.euiTab').contains('Overview').click(); - cy.wait(delay); - cy.get('.euiLink').contains('client_create_order').click(); - cy.get('.euiTableRow').should('have.length', 1); - cy.get('.euiPopover').contains('traceGroup: client_create_order').should('exist'); - cy.get('[aria-label="Remove filter"]').click(); - cy.get('.euiPopover').contains('traceGroup: client_create_order').should('not.exist'); - }); - - it('Opens service detail flyout when Service Name is clicked', () => { - cy.get('.euiTab').contains('Services').click(); - cy.wait(delay); - cy.get('.euiLink').contains('authentication').click(); - supressResizeObserverIssue(); - cy.wait(delay * 3); - cy.get('.euiFlyout').contains('Service detail').should('be.visible'); - cy.get('.euiFlyout').within(($flyout) => { - cy.get('.euiDescriptionList').contains('3.52').should('exist'); - cy.get('[data-text="Error rate"]').click(); - cy.get('.ytitle').contains('Error rate').should('exist'); - }); - cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); - cy.get('.euiFlyout').should('not.be.visible'); - cy.get('.euiLink').contains('authentication').click(); - supressResizeObserverIssue(); - cy.wait(delay * 3); - cy.get('.euiFlyout').contains('Service detail').scrollIntoView().should('be.visible'); - cy.get('[data-test-subj="dataGridRowCell"] button').contains('718dc32a693c8a17').click(); - cy.get('.euiFlyout').contains('Span detail').should('be.visible'); - cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); - cy.get('.euiFlyout').should('not.be.visible'); - }); - - it('Opens trace detail flyout when Trace ID is clicked', () => { - cy.get('.euiTab').contains('Traces & Spans').click(); - supressResizeObserverIssue(); - cy.wait(delay); - cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click(); - cy.get('.euiFlyout').contains('Trace detail').should('be.visible'); - cy.get('.euiFlyout').within(($flyout) => { - cy.get('.euiDescriptionList').contains('224.99').should('exist'); - }); - cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); - cy.wait(delay); - cy.get('.euiFlyout').should('not.be.visible'); - cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click(); - cy.get('[data-text="Span list"]').click(); - cy.wait(delay); - cy.get('[data-test-subj="dataGridRowCell"] button').contains('d67c5bb617ba9203').click(); - cy.get('.euiFlyout').contains('Span detail').should('be.visible'); - cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); - cy.get('.euiFlyout').should('not.be.visible'); - }); - - it('Opens span detail flyout when Span ID is clicked', () => { - cy.get('.euiTab').contains('Traces & Spans').click(); - supressResizeObserverIssue(); - cy.wait(delay); - cy.get('.euiLink').contains('5ff3516909562c60').click(); - cy.get('.euiFlyout').contains('Span detail').should('be.visible'); - cy.get('.euiFlyout').within(($flyout) => { - cy.get('.euiText').contains('HTTP GET').should('exist'); - }); - cy.get('.euiText').contains('order').click(); - cy.get('[aria-label="span-flyout-filter-icon"]').click(); - cy.focused().blur(); - cy.get('[data-test-subj="euiFlyoutCloseButton"]').click(); - cy.get('.euiPopover').contains('serviceName: order').should('exist'); - cy.get('[aria-label="Remove filter"]').click(); - cy.get('.euiPopover').contains('serviceName: order').should('not.exist'); - }); - - it('Shows base query', () => { - cy.get('.euiTab').contains('Log Events').click(); - cy.get('.euiBadge__text').contains('Base Query').should('exist'); - }); - - it('Saves visualization #1 to panel', () => { - cy.get('.euiTab').contains('Panel').click(); - cy.get('.euiButton').contains('Add').click(); - cy.wait(delay); - cy.get('.plot-container').should('exist'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').click(); - cy.get('.aa-List').find('.aa-Item').should('have.length', 11); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type('x', {delay: TYPING_DELAY}); - cy.focused().clear(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type('where DestCityName = "Venice" | stats count() by span( timestamp , 6h )', {delay: TYPING_DELAY}); - changeTimeTo24('months'); - cy.wait(delay * 2); - cy.get('.euiTab').contains('Visualizations').click(); - supressResizeObserverIssue(); - cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); - cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visOneName); - cy.wait(delay); - cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); - cy.wait(delay); - cy.get('.euiTab').contains('Panel').click(); - cy.wait(delay); - cy.get('.js-plotly-plot').should('exist'); - }); - - it('Adds availability level to visualization #1', () => { - cy.get('.euiTab').contains('Panel').click(); - cy.wait(delay); - cy.get('[aria-label="actionMenuButton"]').click(); - cy.get('.euiContextMenuItem').contains('Edit').click(); - supressResizeObserverIssue(); - cy.wait(delay); - cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); - cy.get('.euiBadge').contains('Bar').click(); - cy.focused().type('{downArrow}'); - cy.focused().type('{enter}'); - cy.wait(delay); - cy.get('.euiButton').contains('+ Add availability level').click(); - cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); - cy.get('[aria-label="Select #54B399 as the color"]').click(); - cy.wait(delay); - cy.get('[data-test-subj="nameFieldText"]').click().type('Available'); - cy.get('option').contains('≥').should('exist'); - cy.get('option').contains('≤').should('exist'); - cy.get('option').contains('>').should('exist'); - cy.get('option').contains('<').should('exist'); - cy.get('option').contains('=').should('exist'); - cy.get('option').contains('≠').should('exist'); - cy.get('[data-test-subj="expressionSelect"]').select('>'); - cy.get('[data-test-subj="valueFieldNumber"]').clear().type('0.5'); - cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); - cy.wait(delay); - cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); - cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); - cy.wait(delay); - cy.get('.euiTab').contains('Panel').click(); - cy.wait(delay); - cy.get('.js-plotly-plot').should('exist'); - cy.get('.textpoint').contains('Available').should('exist'); - cy.get('.euiBreadcrumb').contains('Application analytics').click(); - cy.wait(delay); - cy.get('.euiBadge').contains('Available').should('exist'); - cy.get('[style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('exist'); - }); - - it('Saves visualization #2 to panel with availability level', () => { - moveToApplication(nameOne); - changeTimeTo24('months'); - cy.get('.euiTab').contains('Log Events').click(); - cy.wait(delay); - cy.get('.plot-container').should('exist'); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').clear(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type('x', {delay: TYPING_DELAY}); - cy.focused().clear(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type('where DestCityName = "Venice" | stats count() by span( timestamp , 6h )', {delay: TYPING_DELAY}); - cy.get('.euiButton').contains('Refresh').click(); - cy.wait(delay); - cy.get('.euiTab').contains('Visualizations').click(); - supressResizeObserverIssue(); - cy.get('.euiBadge').contains('Bar').click(); - cy.focused().type('{downArrow}'); - cy.focused().type('{enter}'); - cy.wait(delay); - cy.get('.euiButton').contains('+ Add availability level').click(); - cy.get('[data-test-subj="euiColorPickerAnchor"]').click(); - cy.get('[aria-label="Select #9170B8 as the color"]').click(); - cy.wait(delay); - cy.get('[data-test-subj="nameFieldText"]').click().type('Super'); - cy.get('[data-test-subj="expressionSelect"]').select('<'); - cy.get('[data-test-subj="valueFieldNumber"]').clear().type('5.5'); - cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); - cy.wait(delay); - cy.get('.euiButton').contains('+ Add availability level').click(); - cy.get('[data-test-subj="euiColorPickerAnchor"]').first().click(); - cy.get('[aria-label="Select #CA8EAE as the color"]').click(); - cy.wait(delay); - cy.get('[data-test-subj="nameFieldText"]').first().click().type('Cool'); - cy.get('[data-test-subj="expressionSelect"]').first().select('>'); - cy.get('[data-test-subj="valueFieldNumber"]').first().clear().type('0'); - cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); - cy.wait(delay); - cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); - cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visTwoName); - cy.wait(delay); - cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); - cy.wait(delay); - cy.get('.euiTab').contains('Panel').click(); - cy.wait(delay); - cy.get('.js-plotly-plot').should('have.length', 2); - moveToHomePage(); - cy.get('.euiBadge').contains('Super').should('exist'); - cy.get('[style="background-color: rgb(145, 112, 184); color: rgb(0, 0, 0);"]').should('exist'); - }); - - it('Configuration tab shows details', () => { - cy.get('.euiLink').contains(nameOne).click(); - cy.wait(delay); - cy.get('.euiTab').contains('Configuration').click(); - cy.wait(delay); - cy.get('.euiCodeBlock__code').contains(baseQuery).should('exist'); - cy.get('[aria-label="List of services and entities"]').find('li').should('have.length', 1); - cy.get('[aria-label="List of trace groups"]').find('li').should('have.length', 2); - cy.get('option').should('have.length', 2); - }); - - - it('Changes availability visualization', () => { - cy.get('.euiTab').contains('Configuration').click(); - cy.wait(delay); - cy.get('select').select(visOneName); - cy.wait(delay); - moveToHomePage(); - cy.get('.euiBadge').contains('Available').should('exist'); - cy.get('[style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('exist'); - moveToApplication(nameOne); - cy.get('.euiTab').contains('Configuration').click(); - cy.wait(delay); - cy.get('select').find('option:selected').should('have.text', visOneName); - }) - - it('Hides application visualizations in Event Analytics', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics`); - cy.wait(delay*3); - if (cy.get('.euiFieldSearch').length > 1) { - cy.get('input.euiFieldSearch').type(visOneName, {delay: TYPING_DELAY}); - cy.wait(delay); - cy.get('.euiTableCellContent__text').contains('No items found').should('exist'); - cy.get('input.euiFieldSearch').clear().type(visTwoName, {delay: TYPING_DELAY}); - cy.wait(delay); - cy.get('.euiTableCellContent__text').contains('No items found').should('exist'); - cy.get('.euiFormControlLayoutClearButton').click(); - cy.wait(delay); - cy.get('[data-test-subj="tablePaginationPopoverButton"]').click(); - cy.get('.euiContextMenuItem__text').contains('50 rows').click(); - cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click(); - cy.wait(delay); - cy.get('.euiButton__text').contains('Actions').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem__text').contains('Delete').click(); - cy.wait(delay); - - cy.get('button.euiButton--danger').should('be.disabled'); - - cy.get('input.euiFieldText[placeholder="delete"]').type('delete'); - cy.get('button.euiButton--danger').should('not.be.disabled'); - cy.get('.euiButton__text').contains('Delete').click(); - cy.wait(delay); - } - }); - - it('Hides application visualizations in Operational Panels', () => { - cy.visit( - `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/` - ); - cy.wait(delay*3); - cy.get('.euiButton__text').contains('Actions').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem__text').contains('Add samples').click(); - cy.wait(delay); - cy.get('.euiButton__text').contains('Yes').click(); - cy.wait(delay*2); - cy.get('.euiLink').contains('[Logs] Web traffic Panel').first().click(); - cy.wait(delay); - cy.get('.euiButton__text').contains('Add visualization').click(); - cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click(); - cy.get('option').contains(visOneName).should('not.exist'); - cy.get('option').contains(visTwoName).should('not.exist'); - cy.visit( - `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/` - ); - cy.wait(delay*3); - cy.get('input.euiFieldSearch').type('[Logs] Web traffic Panel', {delay: TYPING_DELAY}); - cy.wait(delay); - cy.get('.euiTableRow').first().within(($row) => { - cy.get('.euiCheckbox').click(); - }); - cy.get('.euiButton__text').contains('Actions').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem__text').contains('Delete').click(); - cy.wait(delay); - cy.get('input.euiFieldText[placeholder="delete"]').type('delete'); - cy.get('button.euiButton--danger').should('not.be.disabled'); - cy.get('.euiButton__text').contains('Delete').click(); - cy.wait(delay); - }); -}); - -describe('Editing application', () => { - beforeEach(() => { - moveToEditPage(); - }); - - it('Redirects to application after saving changes', () => { - cy.get('.euiAccordion').contains('Log source').click(); - cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('be.disabled'); - cy.get('.euiAccordion').contains('Trace groups').click(); - cy.get('[data-test-subj="comboBoxToggleListButton"]').filter(':visible').click(); - cy.get('.euiFilterSelectItem').contains(trace_three).trigger('click'); - cy.get('.euiBadge').contains('3').should('exist'); - cy.get('.euiAccordion').contains('Trace groups').click(); - cy.get('.euiAccordion').contains('Services & entities').click(); - cy.get('[data-test-subj="servicesEntitiesComboBox"]').click(); - cy.get('.euiFilterSelectItem').contains(service_two).trigger('click'); - cy.get('.euiBadge').contains('2').should('exist'); - cy.get('.euiButton').contains('Save').click(); - cy.wait(delay); - cy.get('.euiTab').contains('Configuration').click(); - cy.wait(delay); - cy.get('.euiCodeBlock__code').contains(baseQuery).should('exist'); - cy.get('[aria-label="List of services and entities"]').find('li').should('have.length', 2); - cy.get('[aria-label="List of trace groups"]').find('li').should('have.length', 3); - cy.get('.euiTitle').contains(nameOne).should('exist'); - }); -}); - -describe('Application Analytics home page', () => { - beforeEach(() => { - moveToHomePage(); - }) - - it('Show correct information in table', () => { - cy.get('.euiLink').contains(nameOne).should('exist'); - cy.get('[data-test-subj="appAnalytics__compositionColumn"]').contains(composition).should('exist'); - cy.get('.euiBadge').contains('Available').should('exist'); - cy.get('[style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('exist'); - }); - - it('Renames application', () => { - cy.get('.euiPopover').contains('Actions').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem-isDisabled').contains('Rename').should('exist'); - cy.get('.euiTableRow').first().within(($row) => { - cy.get('.euiCheckbox').click(); - }); - cy.wait(delay); - cy.get('.euiPopover').contains('Actions').click(); - cy.get('.euiContextMenuItem').contains('Rename').click(); - cy.get('.euiFieldText').clear().focus().type(newName); - cy.get('.euiButton--fill').contains('Rename').click(); - cy.wait(delay); - cy.get('.euiToast').contains(`Application successfully renamed to "${newName}"`); - cy.get('.euiTableRow').first().within(($row) => { - cy.get('.euiLink').contains(newName).should('exist'); - }); - }); - - it('Deletes application', () => { - cy.get('.euiPopover').contains('Actions').click(); - cy.get('.euiContextMenuItem-isDisabled').contains('Delete').should('exist'); - cy.get('.euiTableRow').eq(0).within(($row) => { - cy.get('.euiCheckbox').click(); - }); - cy.get('.euiTableRow').eq(1).within(($row) => { - cy.get('.euiCheckbox').click(); - }); - cy.wait(delay); - cy.get('.euiPopover').contains('Actions').click(); - cy.wait(delay); - cy.get('.euiContextMenuItem').contains('Delete').click(); - cy.get('.euiButton--fill').contains('Delete').click(); - cy.wait(delay); - cy.get('.euiToast').contains(`Applications successfully deleted!`); - cy.get('.euiLink').contains(newName).should('not.exist'); - }); -}); diff --git a/dashboards-observability/.cypress/integration/trace_analytics_dashboard.spec.js b/dashboards-observability/.cypress/integration/trace_analytics_dashboard.spec.js deleted file mode 100644 index 6e510a8d8..000000000 --- a/dashboards-observability/.cypress/integration/trace_analytics_dashboard.spec.js +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/// - -import { testDataSet, delay, setTimeFilter } from '../utils/constants'; - -describe('Dump test data', () => { - it('Indexes test data', () => { - const dumpDataSet = (mapping_url, data_url, index) => { - cy.request({ - method: 'POST', - failOnStatusCode: false, - url: 'api/console/proxy', - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - }, - qs: { - path: `${index}`, - method: 'PUT', - }, - }); - - cy.request(mapping_url).then((response) => { - cy.request({ - method: 'POST', - form: true, - url: 'api/console/proxy', - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - }, - qs: { - path: `${index}/_mapping`, - method: 'POST', - }, - body: response.body, - }); - }); - - cy.request(data_url).then((response) => { - cy.request({ - method: 'POST', - form: true, - url: 'api/console/proxy', - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - }, - qs: { - path: `${index}/_bulk`, - method: 'POST', - }, - body: response.body, - }); - }); - }; - - testDataSet.forEach(({ mapping_url, data_url, index }) => - dumpDataSet(mapping_url, data_url, index) - ); - }); -}); - -describe('Testing dashboard table empty state', () => { - beforeEach(() => { - cy.visit('app/observability-dashboards#/trace_analytics/home', { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - cy.wait(delay * 3); - }); - - it('Renders empty state', () => { - cy.contains(' (0)').should('exist'); - cy.contains('No matches').should('exist'); - }); -}); - -describe('Testing dashboard table', () => { - beforeEach(() => { - cy.visit('app/observability-dashboards#/trace_analytics/home', { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - setTimeFilter(); - }); - - it('Renders the dashboard table', () => { - cy.contains(' (10)').should('exist'); - cy.contains('client_cancel_order').should('exist'); - cy.contains('166.44').should('exist'); - cy.contains('7.14%').should('exist'); - }); - - it('Has working breadcrumbs', () => { - cy.get('.euiBreadcrumb').contains('Dashboard').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Dashboard').should('exist'); - cy.get('.euiBreadcrumb').contains('Trace analytics').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Dashboard').should('exist'); - cy.get('.euiBreadcrumb').contains('Observability').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Event analytics').should('exist'); - }); - - it('Adds the percentile filters', () => { - cy.contains(' >= 95 percentile').click({ force: true }); - cy.wait(delay); - cy.contains(' >= 95 percentile').click({ force: true }); - cy.wait(delay); - - cy.contains('Latency percentile within trace group: >= 95th').should('exist'); - cy.contains(' (7)').should('exist'); - cy.contains('318.69').should('exist'); - - cy.contains(' < 95 percentile').click({ force: true }); - cy.wait(delay); - cy.contains(' < 95 percentile').click({ force: true }); - cy.wait(delay); - - cy.contains('Latency percentile within trace group: < 95th').should('exist'); - cy.contains(' (8)').should('exist'); - cy.contains('383.05').should('exist'); - }); - - it('Opens latency trend popover', () => { - setTimeFilter(true); - cy.get('.euiButtonIcon[aria-label="Open popover"]').first().click(); - cy.get('text.ytitle[data-unformatted="Hourly latency (ms)"]').should('exist'); - }); - - it('Redirects to traces table with filter', () => { - cy.wait(delay * 5); - cy.get('.euiLink').contains('13').click(); - cy.wait(delay); - - cy.get('h2.euiTitle').contains('Traces').should('exist'); - cy.contains(' (13)').should('exist'); - cy.contains('client_create_order').should('exist'); - - cy.get('.euiSideNavItemButton__label').contains('Trace analytics').click(); - cy.wait(delay); - - cy.contains('client_create_order').should('exist'); - }); -}); - -describe('Testing plots', () => { - beforeEach(() => { - cy.visit('app/observability-dashboards#/trace_analytics/home', { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - setTimeFilter(); - }); - - it('Renders service map', () => { - // plotly scale texts are in attribute "data-unformatted" - cy.get('text.ytitle[data-unformatted="Latency (ms)"]').should('exist'); - cy.get('text[data-unformatted="200"]').should('exist'); - cy.get('.vis-network').should('exist'); - - cy.get('.euiButton__text[title="Error rate"]').click(); - cy.get('text.ytitle[data-unformatted="Error rate"]').should('exist'); - cy.get('text[data-unformatted="10%"]').should('exist'); - - cy.get('.euiButton__text[title="Throughput"]').click(); - cy.get('text.ytitle[data-unformatted="Throughput"]').should('exist'); - cy.get('text[data-unformatted="50"]').should('exist'); - - cy.get('input[type="search"]').eq(1).focus().type('payment{enter}'); - cy.wait(delay); - }); - - it('Renders plots', () => { - cy.get('text.ytitle[data-unformatted="Error rate (%)"]').should('exist'); - cy.get('text.annotation-text[data-unformatted="Now: 14.81%"]').should('exist'); - cy.get('text.ytitle[data-unformatted="Throughput (n)"]').should('exist'); - cy.get('text.annotation-text[data-unformatted="Now: 108"]').should('exist'); - }); -}); diff --git a/dashboards-observability/.cypress/integration/trace_analytics_services.spec.js b/dashboards-observability/.cypress/integration/trace_analytics_services.spec.js deleted file mode 100644 index 6421982a9..000000000 --- a/dashboards-observability/.cypress/integration/trace_analytics_services.spec.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/// - -import { delay, SERVICE_NAME, SERVICE_SPAN_ID, setTimeFilter } from '../utils/constants'; - -describe('Testing services table empty state', () => { - beforeEach(() => { - cy.visit('app/observability-dashboards#/trace_analytics/services', { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - cy.wait(delay * 3); - }); - - it('Renders empty state', () => { - cy.contains(' (0)').should('exist'); - cy.contains('No matches').should('exist'); - }); -}); - -describe('Testing services table', () => { - beforeEach(() => { - cy.visit('app/observability-dashboards#/trace_analytics/services', { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - setTimeFilter(); - }); - - it('Renders the services table', () => { - cy.contains(' (8)').should('exist'); - cy.contains('analytics-service, frontend-client, recommendation').should('exist'); - cy.contains('186.95').should('exist'); - cy.contains('14.29%').should('exist'); - }); - - it('Searches correctly', () => { - cy.get('input[type="search"]').first().focus().type(`${SERVICE_NAME}{enter}`); - cy.get('.euiButton__text').contains('Refresh').click(); - cy.contains(' (1)').should('exist'); - cy.contains('3.57%').should('exist'); - }); -}); - -describe('Testing service view empty state', () => { - beforeEach(() => { - // exception is thrown on loading EuiDataGrid in cypress only, ignore for now - cy.on('uncaught:exception', (err, runnable) => { - if (err.message.includes('ResizeObserver loop')) - return false; - }); - cy.visit(`app/observability-dashboards#/trace_analytics/services/${SERVICE_NAME}`, { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - }); - - it('Renders service view empty state', () => { - cy.contains('frontend-client').should('exist'); - cy.get('.euiText').contains('0').should('exist'); - cy.get('.euiText').contains('-').should('exist'); - }); -}); - -describe('Testing service view', () => { - beforeEach(() => { - // exception is thrown on loading EuiDataGrid in cypress only, ignore for now - cy.on('uncaught:exception', (err, runnable) => { - if (err.message.includes('ResizeObserver loop')) - return false; - }); - cy.visit(`app/observability-dashboards#/trace_analytics/services/${SERVICE_NAME}`, { - onBeforeLoad: (win) => { - win.sessionStorage.clear(); - }, - }); - setTimeFilter(undefined, false); - }); - - it('Renders service view', () => { - cy.get('h2.euiTitle').contains(SERVICE_NAME).should('exist'); - cy.contains('178.6').should('exist'); - cy.contains('3.57%').should('exist'); - cy.get('div.vis-network').should('exist'); - }); - - it('Has working breadcrumbs', () => { - cy.get('.euiBreadcrumb').contains(SERVICE_NAME).click(); - cy.wait(delay); - cy.get('h2.euiTitle').contains(SERVICE_NAME).should('exist'); - cy.get('.euiBreadcrumb').contains('Services').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Services').should('exist'); - cy.get('.euiBreadcrumb').contains('Trace analytics').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Dashboard').should('exist'); - cy.get('.euiBreadcrumb').contains('Observability').click(); - cy.wait(delay); - cy.get('.euiTitle').contains('Event analytics').should('exist'); - }); - - it('Renders spans data grid, flyout, filters', () => { - cy.get('.euiLink').contains(SERVICE_SPAN_ID).trigger('mouseover', { force: true }); - cy.get('button[data-datagrid-interactable="true"]').eq(0).click({ force: true }); - cy.wait(delay); - cy.contains('Span detail').should('exist'); - cy.contains('Span attributes').should('exist'); - cy.get('.euiTextColor').contains('Span ID').trigger('mouseover'); - cy.get('.euiButtonIcon[aria-label="span-flyout-filter-icon"').click({ force: true }); - cy.wait(delay); - - cy.get('.euiBadge__text').contains('spanId: ').should('exist'); - cy.contains('Spans (1)').should('exist'); - }); -}); diff --git a/dashboards-observability/.cypress/utils/app_constants.js b/dashboards-observability/.cypress/utils/app_constants.js index bc3b7e856..f87432409 100644 --- a/dashboards-observability/.cypress/utils/app_constants.js +++ b/dashboards-observability/.cypress/utils/app_constants.js @@ -6,7 +6,7 @@ import { supressResizeObserverIssue } from './constants'; export const delay = 1000; - +export const timeoutDelay = 30000; export const TYPING_DELAY = 500; export const moveToHomePage = () => { @@ -17,30 +17,28 @@ export const moveToHomePage = () => { export const moveToCreatePage = () => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`); - cy.wait(delay * 2); - cy.get('.euiButton__text').contains('Create application').click(); + cy.get('.euiButton[href="#/application_analytics/create"]').eq(0).click(); supressResizeObserverIssue(); - cy.wait(delay); - cy.get('.euiTitle').contains('Create application').should('exist'); + cy.get('[data-test-subj="createPageTitle"]').should('contain', 'Create application'); }; export const moveToApplication = (name) => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`); supressResizeObserverIssue(); cy.wait(delay * 6); - cy.get('.euiLink').contains(name).click(); + cy.get(`[data-test-subj="${name}ApplicationLink"]`).click(); cy.wait(delay); - cy.get('.euiTitle').contains(name).should('exist'); + cy.get('[data-test-subj="applicationTitle"]').should('contain', name); changeTimeTo24('years'); }; export const moveToEditPage = () => { moveToApplication(nameOne); - cy.get('.euiTab').contains('Configuration').click(); - cy.get('.euiButton').contains('Edit').click(); + cy.get('[data-test-subj="app-analytics-configTab"]').click(); + cy.get('[data-test-subj="editApplicationButton"]').click(); supressResizeObserverIssue(); cy.wait(delay); - cy.get('.euiTitle').contains('Edit application'); + cy.get('[data-test-subj="createPageTitle"]').should('contain', 'Edit application'); }; export const changeTimeTo24 = (timeUnit) => { @@ -49,11 +47,11 @@ export const changeTimeTo24 = (timeUnit) => { cy.get('[aria-label="Time unit"]').select(timeUnit); cy.get('.euiButton').contains('Apply').click(); cy.wait(delay); - cy.get('.euiButton').contains('Refresh').click(); + cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').click(); }; -export const expectMessageOnHover = (message) => { - cy.get('.euiToolTipAnchor').contains('Create').click({ force: true }); +export const expectMessageOnHover = (button, message) => { + cy.get(`[data-test-subj="${button}"]`).click({ force: true }); cy.get('.euiToolTipPopover').contains(message).should('exist'); }; @@ -72,22 +70,21 @@ export const deleteAllSavedApplications = () => { cy.get('.euiButton__text').contains('Delete').click(); }; +export const uniqueId = Date.now(); export const baseQuery = 'source = opensearch_dashboards_sample_data_flights'; -export const nameOne = 'Cypress'; -export const nameTwo = 'Pine'; +export const nameOne = `Cypress-${uniqueId}`; +export const nameTwo = `Pine-${uniqueId}`; +export const nameThree = `Cedar-${uniqueId}`; export const description = 'This is my application for cypress testing.'; export const service_one = 'order'; export const service_two = 'payment'; export const trace_one = 'HTTP POST'; export const trace_two = 'HTTP GET'; export const trace_three = 'client_pay_order'; -export const spanQueryOnePartOne = 'where DestCityName '; -export const spanQueryOnePartTwo = '= "Venice" | stats count() by span( timestamp '; -export const spanQueryOnePartThree = ', 6h )'; -export const spanQueryTwoPartOne = 'where OriginCityName '; -export const spanQueryTwoPartTwo = '= "Seoul" | stats count() by span( timestamp '; -export const spanQueryTwoPartThree = ', 6h )'; +export const query_one = 'where DestCityName = "Venice" | stats count() by span( timestamp , 6h )'; +export const query_two = 'where OriginCityName = "Seoul" | stats count() by span( timestamp , 6h )'; +export const availability_default = 'stats count() by span( timestamp, 1h )'; export const visOneName = 'Flights to Venice'; export const visTwoName = 'Flights from Seoul'; export const composition = 'order, payment, HTTP POST, HTTP GET, client_pay_order' -export const newName = 'Monterey Cypress'; \ No newline at end of file +export const newName = `Monterey Cypress-${uniqueId}`; diff --git a/dashboards-observability/.cypress/utils/constants.js b/dashboards-observability/.cypress/utils/constants.js index 75e343086..d67d3988f 100644 --- a/dashboards-observability/.cypress/utils/constants.js +++ b/dashboards-observability/.cypress/utils/constants.js @@ -60,6 +60,8 @@ export const setTimeFilter = (setEndTime = false, refresh = true) => { // notebooks export const TEST_NOTEBOOK = 'Test Notebook'; export const SAMPLE_URL = 'https://github.com/opensearch-project/sql/tree/main/sql-jdbc'; +export const NOTEBOOK_TEXT = 'Use Notebooks to interactively and collaboratively develop rich reports backed by live data. Common use cases for notebooks includes creating postmortem reports, designing run books, building live infrastructure reports, or even documentation.'; +export const OPENSEARCH_URL = 'https://opensearch.org/docs/latest/observability-plugin/notebooks/'; export const MARKDOWN_TEXT = `%md # Heading 1 @@ -100,3 +102,22 @@ export const supressResizeObserverIssue = () => { if (err.message.includes('ResizeObserver loop')) return false; }); }; + +export const verify_traces_spans_data_grid_cols_exists = () => { + cy.get('.euiDataGridHeaderCell__content').contains('Span ID').should('exist'); + cy.get('.euiDataGridHeaderCell__content').contains('Trace ID').should('exist'); + cy.get('.euiDataGridHeaderCell__content').contains('Operation').should('exist'); + cy.get('.euiDataGridHeaderCell__content').contains('Duration').should('exist'); + cy.get('.euiDataGridHeaderCell__content').contains('Start time').should('exist'); + cy.get('.euiDataGridHeaderCell__content').contains('End time').should('exist'); + cy.get('.euiDataGridHeaderCell__content').contains('Errors').should('exist'); +} + +export const count_table_row = (expected_row_count) => { + cy.get('.euiDataGridHeader [role="columnheader"]').then($el => { + let colmun_header_count = Cypress.$($el).length; + let table_grid_cell_count = Cypress.$('[data-test-subj="dataGridRowCell"]').length; + const total_row_count = table_grid_cell_count / colmun_header_count; + expect(total_row_count).to.equal(expected_row_count) + }); +} diff --git a/dashboards-observability/.cypress/utils/event_constants.js b/dashboards-observability/.cypress/utils/event_constants.js index 130d32590..9e0f89697 100644 --- a/dashboards-observability/.cypress/utils/event_constants.js +++ b/dashboards-observability/.cypress/utils/event_constants.js @@ -3,30 +3,53 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { supressResizeObserverIssue } from './constants' +import { supressResizeObserverIssue } from './constants'; export const delay = 1000; -export const YEAR_TO_DATE_DOM_ID = '[data-test-subj="superDatePickerCommonlyUsed_Year_to date"]' +export const YEAR_TO_DATE_DOM_ID = '[data-test-subj="superDatePickerCommonlyUsed_Year_to date"]'; export const TEST_QUERIES = [ { query: 'source = opensearch_dashboards_sample_data_flights', - dateRangeDOM: YEAR_TO_DATE_DOM_ID + dateRangeDOM: YEAR_TO_DATE_DOM_ID, }, { - query: 'source = opensearch_dashboards_sample_data_flights | stats avg(FlightDelayMin) by Carrier', - dateRangeDOM: YEAR_TO_DATE_DOM_ID + query: + 'source = opensearch_dashboards_sample_data_flights | stats avg(FlightDelayMin) by Carrier', + dateRangeDOM: YEAR_TO_DATE_DOM_ID, }, { - query: 'source = opensearch_dashboards_sample_data_logs' + query: 'source = opensearch_dashboards_sample_data_logs', }, { - query: 'source = opensearch_dashboards_sample_data_logs | stats count() by host', - dateRangeDOM: YEAR_TO_DATE_DOM_ID + query: + 'source=opensearch_dashboards_sample_data_flights | stats max(AvgTicketPrice) by DestCountry, DestCityName, Carrier', + dateRangeDOM: YEAR_TO_DATE_DOM_ID, }, { - query: 'source = opensearch_dashboards_sample_data_logs | stats count(), avg(bytes) by host, tags', - dateRangeDOM: YEAR_TO_DATE_DOM_ID + query: + 'source = opensearch_dashboards_sample_data_logs | stats count(), avg(bytes) by host, tags', + dateRangeDOM: YEAR_TO_DATE_DOM_ID, + }, + { + query: + 'source=opensearch_dashboards_sample_data_flights | stats avg(FlightDelayMin) by DestCountry, DestCityName', + dateRangeDOM: YEAR_TO_DATE_DOM_ID, + }, + { + query: + "source = opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count() by span(timestamp,1d)", + dateRangeDOM: YEAR_TO_DATE_DOM_ID, + }, + { + query: + 'source=opensearch_dashboards_sample_data_flights |where FlightDelayMin > 0 | stats sum(FlightDelayMin) as total_delay_min, count() as total_delayed by Carrier |eval avg_delay=total_delay_min / total_delayed | sort - avg_delay', + dateRangeDOM: YEAR_TO_DATE_DOM_ID, + }, + { + query: + 'source = opensearch_dashboards_sample_data_logs | stats count(), max(bytes) by span(timestamp,1d), clientip, host', + dateRangeDOM: YEAR_TO_DATE_DOM_ID, }, ]; @@ -36,6 +59,18 @@ export const SAVE_QUERY2 = 'Mock Flight count by destination'; export const SAVE_QUERY3 = 'Mock Flight count by destination save to panel'; export const SAVE_QUERY4 = 'Mock Flight peek'; +export const aggregationValues = [ + 'COUNT', + 'SUM', + 'AVERAGE', + 'MAX', + 'MIN', + 'VAR_SAMP', + 'VAR_POP', + 'STDDEV_SAMP', + 'STDDEV_POP', +]; + export const querySearch = (query, rangeSelected) => { cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(query); cy.get('[data-test-subj="superDatePickerToggleQuickMenuButton"]').click(); @@ -70,4 +105,146 @@ export const landOnPanels = () => { `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels` ); cy.wait(delay); -}; \ No newline at end of file +}; + +const vis_name_sub_string = Math.floor(Math.random() * 100); +export const saveVisualizationAndVerify = () => { + cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); + cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').click(); + cy.get('.euiComboBoxOptionsList__rowWrap .euiFilterSelectItem').eq(0).click(); + cy.get( + '.euiPopover__panel .euiFormControlLayoutIcons [data-test-subj="comboBoxToggleListButton"]' + ) + .eq(0) + .click(); + cy.get('.euiPopover__panel input') + .eq(1) + .type(`Test visualization` + vis_name_sub_string); + cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click(); + cy.wait(delay); + cy.get('.euiHeaderBreadcrumbs a').eq(1).click(); + cy.get('.euiFlexGroup .euiFormControlLayout__childrenWrapper input') + .eq(0) + .type(`Test visualization` + vis_name_sub_string) + .type('{enter}'); + cy.get('.euiBasicTable .euiTableCellContent button').eq(0).click(); +}; + +export const deleteVisualization = () => { + cy.get('a[href = "#/event_analytics"]').click(); + cy.get('.euiFlexGroup .euiFormControlLayout__childrenWrapper input') + .eq(0) + .type(`Test visualization` + vis_name_sub_string) + .type('{enter}'); + cy.get('input[data-test-subj = "checkboxSelectAll"]').click(); + cy.get('.euiButtonContent.euiButtonContent--iconRight.euiButton__content').click(); + cy.get('.euiContextMenuItem .euiContextMenuItem__text').eq(0).click(); + cy.get('input[placeholder = "delete"]').clear().type('delete'); + cy.get('button[data-test-subj = "popoverModal__deleteButton"]').click(); + cy.get('.euiToastHeader').should('exist'); +}; + +export const renderTreeMapchart = () => { + querySearch(TEST_QUERIES[7].query, TEST_QUERIES[7].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Tree Map') + .type('{enter}'); + cy.get('#configPanel__panelOptions .euiFieldText').click().type('Tree Map'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]') + .click() + .type('This is the description for Tree Map'); + cy.get('.euiIEFlexWrapFix').eq(1).contains('Treemap').should('exist'); + cy.get('#configPanel__treemap_options').contains('Tiling Algorithm').should('exist'); + cy.get('[data-test-subj = "comboBoxInput"]').eq(3).click(); + cy.get('button[name="Slice Dice"]').click(); +}; + +export const renderPieChart = () => { + querySearch(TEST_QUERIES[5].query, TEST_QUERIES[5].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]').click(); + cy.get('[data-test-subj="comboBoxOptionsList "] button span').contains('Pie').click(); + cy.wait(delay); + cy.get('#configPanel__panelOptions .euiFieldText').click().type('Pie chart'); + cy.get('.euiFlexItem .euiFormRow [placeholder="Description"]') + .click() + .type('This is the description for Pie chart'); + cy.get('[aria-controls="configPanel__legend"]').contains('Legend').should('exist'); + cy.get('#configPanel__legend .euiTitle.euiTitle--xxsmall').eq(0).contains('Show Legend'); + cy.get('span[data-text="Show"]').contains('Show').should('exist'); + cy.get('#configPanel__legend .euiTitle.euiTitle--xxsmall').eq(1).contains('Position'); + cy.get('span[data-text="Right"]').contains('Right').should('exist'); + cy.get('#configPanel__legend .euiTitle.euiTitle--xxsmall').eq(2).contains('Legend Size'); + cy.get('[aria-controls="configPanel__chartStyles"]').contains('Chart Styles').should('exist'); + cy.get('#configPanel__chartStyles .euiTitle.euiTitle--xxsmall').eq(0).contains('Mode').click(); + cy.get( + '#configPanel__chartStyles .euiComboBox__inputWrap.euiComboBox__inputWrap--noWrap.euiComboBox__inputWrap-isClearable' + ).click(); + cy.get('.euiComboBoxOption__content').contains('Donut').click(); + cy.get('#configPanel__chartStyles .euiTitle.euiTitle--xxsmall').eq(1).contains('Label Size'); + cy.get('#configPanel__chartStyles input[type="number"]').click().type('10'); + cy.get('#configPanel__chartStyles .euiTitle.euiTitle--xxsmall').eq(2).contains('Color Theme'); + cy.get('.euiSuperSelectControl').click(); + cy.get('.euiColorPalettePicker__item').eq(1).contains('Single Color').click(); + cy.get('.euiFieldText.euiColorPicker__input.euiFieldText--withIcon').click(); + cy.get('[aria-label="Select #D36086 as the color"]').click(); + cy.get('.visEditorSidebar__controls [data-test-subj="visualizeEditorRenderButton"]') + .contains('Preview') + .click(); + cy.get('.plot-container.plotly').should('exist'); +}; + +export const renderDataConfig = () => { + cy.get('.euiResizablePanel.euiResizablePanel--middle').contains('Data Cofigurations'); + cy.get('.euiTitle.euiTitle--xxsmall').eq(1).contains('Dimensions').should('exist'); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(0).contains('Aggregation'); + cy.get('[data-test-subj="comboBoxSearchInput"]').eq(0).click(); + cy.get('.euiComboBoxOption__content').eq(2).click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(1).contains('Field'); + cy.get('[data-test-subj="comboBoxSearchInput"]').eq(1).click(); + cy.get('.euiComboBoxOption__content').eq(1).click(); + cy.get('.euiFieldText[placeholder="Custom label"]').eq(0).type('Average field'); + cy.get('.euiTitle.euiTitle--xxsmall').eq(2).contains('Metrics').should('exist'); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(0).contains('Aggregation'); + cy.get('.euiFormRow__fieldWrapper .euiComboBox').eq(2).click(); + cy.get('.euiComboBoxOption__content').eq(4).click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').eq(4).click(); + cy.get('.euiComboBoxOption__content').eq(0).click(); + cy.get('.euiFieldText[placeholder="Custom label"]').eq(1).type('Min field'); + cy.get('.euiButton__text').contains('Right').click(); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').contains('Update chart').click(); + cy.get('.js-plotly-plot').should('exist'); +}; + +export const renderLineChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[5].query, TEST_QUERIES[5].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Line') + .type('{enter}'); +}; + +export const renderAddParent = () => { + cy.get(' [data-test-subj="addParentButton"] .euiButton__text').contains('+ Add Parent').click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').contains('Parent 1').should('exist'); + cy.get('p.euiComboBoxPlaceholder').eq(0).click({ force: true }); + cy.get('.euiComboBoxOption__content').eq(0).click(); + cy.get(' [data-test-subj="addParentButton"] .euiButton__text').contains('+ Add Parent').click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').contains('Parent 2').should('exist'); + cy.get('p.euiComboBoxPlaceholder').click({ force: true }); + cy.get('.euiComboBoxOption__content').eq(1).click(); + cy.get(' [data-test-subj="addParentButton"] .euiButton__text').contains('+ Add Parent').click(); + cy.get('.first-division .euiFormLabel.euiFormRow__label').contains('Parent 3').should('exist'); + cy.get('p.euiComboBoxPlaceholder').click({ force: true }); + cy.get('.euiComboBoxOption__content').eq(2).click(); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Line') + .type('{enter}'); +}; + +export const renderGaugeChart = () => { + landOnEventVisualizations(); + querySearch(TEST_QUERIES[1].query, TEST_QUERIES[1].dateRangeDOM); + cy.get('[data-test-subj="configPane__vizTypeSelector"] [data-test-subj="comboBoxInput"]') + .type('Gauge') + .type('{enter}'); +}; diff --git a/dashboards-observability/.gitignore b/dashboards-observability/.gitignore index c0fc79791..bf5586d64 100644 --- a/dashboards-observability/.gitignore +++ b/dashboards-observability/.gitignore @@ -4,3 +4,4 @@ build/ coverage/ .cypress/screenshots .cypress/videos +common/query_manager/antlr/output diff --git a/dashboards-observability/common/constants/application_analytics.ts b/dashboards-observability/common/constants/application_analytics.ts index dc24b495b..df675a704 100644 --- a/dashboards-observability/common/constants/application_analytics.ts +++ b/dashboards-observability/common/constants/application_analytics.ts @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -export const TAB_OVERVIEW_ID_TXT_PFX = 'app-analytics-overview-'; -export const TAB_SERVICE_ID_TXT_PFX = 'app-analytics-service-'; -export const TAB_TRACE_ID_TXT_PFX = 'app-analytics-trace-'; -export const TAB_LOG_ID_TXT_PFX = 'app-analytics-log-'; -export const TAB_PANEL_ID_TXT_PFX = 'app-analytics-panel-'; -export const TAB_CONFIG_ID_TXT_PFX = 'app-analytics-config-'; +export const TAB_OVERVIEW_ID = 'app-analytics-overview'; +export const TAB_SERVICE_ID = 'app-analytics-service'; +export const TAB_TRACE_ID = 'app-analytics-trace'; +export const TAB_LOG_ID = 'app-analytics-log'; +export const TAB_PANEL_ID = 'app-analytics-panel'; +export const TAB_CONFIG_ID = 'app-analytics-config'; export const TAB_OVERVIEW_TITLE = 'Overview'; export const TAB_SERVICE_TITLE = 'Services'; export const TAB_TRACE_TITLE = 'Traces & Spans'; diff --git a/dashboards-observability/common/constants/colors.ts b/dashboards-observability/common/constants/colors.ts new file mode 100644 index 000000000..3845e41a0 --- /dev/null +++ b/dashboards-observability/common/constants/colors.ts @@ -0,0 +1,188 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { colorPalette } from '@elastic/eui'; + +export const BLUES_PALETTE = { + name: 'Blues', + label: 'Blues', + colors: [ + 'rgb(5,10,172)', + 'rgb(40,60,190)', + 'rgb(70,100,245)', + 'rgb(90,120,245)', + 'rgb(106,137,247)', + 'rgb(220,220,220)', + ], +}; + +export const REDS_PALETTE = { + name: 'Reds', + label: 'Reds', + colors: ['rgb(220,220,220)', 'rgb(245,195,157)', 'rgb(245,160,105)', 'rgb(178,10,28)'], +}; + +export const GREENS_PALETTE = { + name: 'Greens', + label: 'Greens', + colors: [ + 'rgb(0,68,27)', + 'rgb(0,109,44)', + 'rgb(35,139,69)', + 'rgb(65,171,93)', + 'rgb(116,196,118)', + 'rgb(161,217,155)', + 'rgb(199,233,192)', + 'rgb(229,245,224)', + 'rgb(247,252,245)', + ], +}; + +export const GREYS_PALETTE = { + name: 'Greys', + label: 'Greys', + colors: ['rgb(0,0,0)', 'rgb(255,255,255)'], +}; + +export const BLUE_RED_PALETTE = { + name: 'Bluered', + label: 'Blue-Red', + colors: ['rgb(0,0,255)', 'rgb(255,0,0)'], +}; + +export const RED_BLUE_PALETTE = { + name: 'RdBu', + label: 'Red-Blue', + colors: [ + 'rgb(5,10,172)', + 'rgb(106,137,247)', + 'rgb(190,190,190)', + 'rgb(220,170,132)', + 'rgb(230,145,90)', + 'rgb(178,10,28)', + ], +}; + +export const YELLOW_ORANGE_RED_PALETTE = { + name: 'YlOrRd', + label: 'Yellow-Orange-Red', + colors: [ + 'rgb(128,0,38)', + 'rgb(189,0,38)', + 'rgb(227,26,28)', + 'rgb(252,78,42)', + 'rgb(253,141,60)', + 'rgb(254,178,76)', + 'rgb(254,217,118)', + 'rgb(255,237,160)', + 'rgb(255,255,204)', + ], +}; + +export const YELLOW_GREEN_BLUE_PALETTE = { + name: 'YlGnBu', + label: 'Yellow-Green-Blue', + colors: [ + 'rgb(8,29,88)', + 'rgb(37,52,148)', + 'rgb(34,94,168)', + 'rgb(29,145,192)', + 'rgb(65,182,196)', + 'rgb(127,205,187)', + 'rgb(199,233,180)', + 'rgb(237,248,217)', + 'rgb(255,255,217)', + ], +}; + +export const DEFAULT_PALETTE = 'default'; +export const SINGLE_COLOR_PALETTE = 'singleColor'; +export const MULTI_COLOR_PALETTE = 'multicolor'; + +export const COLOR_PALETTES = [ + { + value: DEFAULT_PALETTE, + title: 'Default', + type: 'text', + }, + { + value: SINGLE_COLOR_PALETTE, + title: 'Single color', + type: 'text', + }, + { + value: MULTI_COLOR_PALETTE, + title: 'Multicolored', + type: 'text', + }, + { + value: BLUES_PALETTE.name, + title: BLUES_PALETTE.label, + palette: colorPalette(BLUES_PALETTE.colors, 20), + type: 'gradient', + }, + { + value: REDS_PALETTE.name, + title: REDS_PALETTE.label, + palette: colorPalette(REDS_PALETTE.colors, 20), + type: 'gradient', + }, + { + value: GREENS_PALETTE.name, + title: GREENS_PALETTE.label, + palette: colorPalette(GREENS_PALETTE.colors, 20), + type: 'gradient', + }, + { + value: GREYS_PALETTE.name, + title: GREYS_PALETTE.label, + palette: colorPalette(GREYS_PALETTE.colors, 20), + type: 'gradient', + }, + { + value: BLUE_RED_PALETTE.name, + title: BLUE_RED_PALETTE.label, + palette: colorPalette(BLUE_RED_PALETTE.colors, 20), + type: 'gradient', + }, + { + value: RED_BLUE_PALETTE.name, + title: RED_BLUE_PALETTE.label, + palette: colorPalette(RED_BLUE_PALETTE.colors, 20, true), + type: 'gradient', + }, + { + value: YELLOW_ORANGE_RED_PALETTE.name, + title: YELLOW_ORANGE_RED_PALETTE.label, + palette: colorPalette(YELLOW_ORANGE_RED_PALETTE.colors, 20), + type: 'gradient', + }, + { + value: YELLOW_GREEN_BLUE_PALETTE.name, + title: YELLOW_GREEN_BLUE_PALETTE.label, + palette: colorPalette(YELLOW_GREEN_BLUE_PALETTE.colors, 20), + type: 'gradient', + }, +]; +export const HEX_CONTRAST_COLOR = 0xffffff; +export const PIE_PALETTES = [ + { + value: DEFAULT_PALETTE, + title: 'Default', + type: 'text', + }, + { + value: SINGLE_COLOR_PALETTE, + title: 'Single Color', + type: 'text', + }, +]; + +export const HEATMAP_PALETTE_COLOR = { name: REDS_PALETTE.label, color: REDS_PALETTE.label }; +export const HEATMAP_SINGLE_COLOR = { name: 'singleColor', color: '#000000' }; +export const OPACITY = 'opacity'; +export const SPECTRUM = 'spectrum'; +export const COLOR_BLACK = 'rgb(0,0,0)'; +export const COLOR_WHITE = 'rgb(255,255,255)'; diff --git a/dashboards-observability/common/constants/data_table.ts b/dashboards-observability/common/constants/data_table.ts new file mode 100644 index 000000000..bbca653a7 --- /dev/null +++ b/dashboards-observability/common/constants/data_table.ts @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const GRID_HEADER_COLUMN_MAX_WIDTH = '150px'; +export const GRID_PAGE_RANGE_DISPLAY = 5; +export const COLUMN_DEFAULT_MIN_WIDTH = 100; +export const GRID_PAGE_SIZES = [10, 50, 100]; +export const ROW_DENSITIES = [ + { icon: 'tableDensityExpanded', height: 55, selected: false }, + { icon: 'tableDensityNormal', height: 45, selected: false }, + { icon: 'tableDensityCompact', height: 35, selected: true }, +]; + +export const HEADER_HEIGHT = 35; diff --git a/dashboards-observability/common/constants/explorer.ts b/dashboards-observability/common/constants/explorer.ts index df666d9d5..b6f022736 100644 --- a/dashboards-observability/common/constants/explorer.ts +++ b/dashboards-observability/common/constants/explorer.ts @@ -3,6 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { htmlIdGenerator } from '@elastic/eui'; +import { VIS_CHART_TYPES } from './shared'; +import { ThresholdUnitType } from '../../public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds'; + export const EVENT_ANALYTICS_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/observability-plugin/event-analytics/'; export const OPEN_TELEMETRY_LOG_CORRELATION_LINK = @@ -11,6 +15,7 @@ export const RAW_QUERY = 'rawQuery'; export const FINAL_QUERY = 'finalQuery'; export const SELECTED_DATE_RANGE = 'selectedDateRange'; export const INDEX = 'index'; +export const SELECTED_PATTERN = 'selectedPattern'; export const SELECTED_TIMESTAMP = 'selectedTimestamp'; export const SELECTED_FIELDS = 'selectedFields'; export const UNSELECTED_FIELDS = 'unselectedFields'; @@ -74,5 +79,203 @@ export const REDUX_EXPL_SLICE_FIELDS = 'fields'; export const REDUX_EXPL_SLICE_QUERY_TABS = 'queryTabs'; export const REDUX_EXPL_SLICE_VISUALIZATION = 'explorerVisualization'; export const REDUX_EXPL_SLICE_COUNT_DISTRIBUTION = 'countDistributionVisualization'; -export const PLOTLY_GAUGE_COLUMN_NUMBER = 5; +export const REDUX_EXPL_SLICE_PATTERNS = 'patterns'; +export const PLOTLY_GAUGE_COLUMN_NUMBER = 4; export const APP_ANALYTICS_TAB_ID_REGEX = /application-analytics-tab.+/; +export const DEFAULT_AVAILABILITY_QUERY = 'stats count() by span( timestamp, 1h )'; +export const PATTERNS_REGEX = /\|\s*patterns\s+\S+\s*\|.*\s*where\s+patterns_field\s*\=\s*'[^a-zA-Z0-9]+'/; +export const PPL_PATTERNS_REGEX = /\|\s*patterns\s+\S+\s*\|\s*where\s+patterns_field\s*\=\s*'[^a-zA-Z0-9]+'/; +export const PATTERNS_EXTRACTOR_REGEX = /patterns\s+(?\S+)/; +export const ADD_BUTTON_TEXT = '+ Add color theme'; +export const NUMBER_INPUT_MIN_LIMIT = 1; + +export const VIZ_CONTAIN_XY_AXIS = [ + VIS_CHART_TYPES.Bar, + VIS_CHART_TYPES.Histogram, + VIS_CHART_TYPES.Line, + VIS_CHART_TYPES.Pie, + VIS_CHART_TYPES.Scatter, + VIS_CHART_TYPES.HorizontalBar, +]; + +// default ppl aggregation method options +export const AGGREGATION_OPTIONS = [ + { + label: 'count', + }, + { + label: 'sum', + }, + { + label: 'avg', + }, + { + label: 'max', + }, + { + label: 'min', + }, + { + label: 'var_samp', + }, + { + label: 'var_pop', + }, + { + label: 'stddev_samp', + }, + { + label: 'stddev_pop', + }, +]; + +// numeric fields type for metrics +export const NUMERICAL_TYPES = [ + 'float', + 'double', + 'bigint', + 'long', + 'octet', + 'short', + 'byte', + 'integer', +]; +// Data table constants +export const GRID_HEADER_COLUMN_MAX_WIDTH = '150px'; +export const GRID_PAGE_RANGE_DISPLAY = 5; +export const COLUMN_DEFAULT_MIN_WIDTH = 100; +export const GRID_PAGE_SIZES = [10, 50, 100]; +export const ROW_DENSITIES = [ + { icon: 'tableDensityExpanded', height: 55, selected: false }, + { icon: 'tableDensityNormal', height: 45, selected: false }, + { icon: 'tableDensityCompact', height: 35, selected: true }, +]; + +export const HEADER_HEIGHT = 35; + +// gauge chart default parameters +export interface DefaultGaugeChartParametersProps { + GaugeTitleSize: number; + DisplayDefaultGauges: number; + OrientationDefault: string; + TickLength: number; + LegendPlacement: string; + ThresholdsMaxLimit: number; +} + +export const DEFAULT_GAUGE_CHART_PARAMETERS: DefaultGaugeChartParametersProps = { + GaugeTitleSize: 14, + DisplayDefaultGauges: 1, + OrientationDefault: 'h', + TickLength: 5, + LegendPlacement: 'center', + ThresholdsMaxLimit: 1, +}; + +// pie chart default parameters +export const PLOTLY_PIE_COLUMN_NUMBER = 2; +export const PIE_XAXIS_GAP = 0.2; +export const PIE_YAXIS_GAP = 0.1; +export interface DefaultPieChartParameterProps { + DefaultMode: string; +} + +export const DEFAULT_PIE_CHART_PARAMETERS: DefaultPieChartParameterProps = { + DefaultMode: 'pie', +}; +export const GROUPBY = 'dimensions'; +export const AGGREGATIONS = 'series'; +export const PARENTFIELDS = 'parentFields'; +export const VALUEFIELD = 'valueField'; +export const CHILDFIELD = 'childField'; +export const TIMESTAMP = 'timestamp'; + +// metrics constants +export const METRICS_GRID_SPACE_BETWEEN_X_AXIS = 0.01; +export const METRICS_GRID_SPACE_BETWEEN_Y_AXIS = 100; +export const METRICS_REDUCE_VALUE_SIZE_PERCENTAGE = 0.08; +export const METRICS_REDUCE_TITLE_SIZE_PERCENTAGE = 0.05; +export const METRICS_REDUCE_SERIES_UNIT_SIZE_PERCENTAGE = 0.2; +export const METRICS_SERIES_UNIT_SUBSTRING_LENGTH = 3; +export const METRICS_AXIS_MARGIN = { + l: 0, + r: 0, + b: 0, + t: 80, +}; + +export const METRICS_ANNOTATION = { + xref: 'paper', + yref: 'paper', + showarrow: false, +}; + +export interface DefaultMetricsChartParametersProps { + DefaultTextMode: string; + DefaultOrientation: string; + DefaultTitleSize: number; + DefaultChartType: string; + TextAlignment: string; + DefaultPrecision: number; + DefaultValueSize: number; + BaseThreshold: ThresholdUnitType; + DefaultTextColor: string; +} + +export const DEFAULT_METRICS_CHART_PARAMETERS: DefaultMetricsChartParametersProps = { + DefaultTextMode: 'auto', + DefaultOrientation: 'auto', + DefaultTitleSize: 30, + DefaultValueSize: 80, + DefaultChartType: 'auto', + TextAlignment: 'auto', + DefaultPrecision: 1, + BaseThreshold: { + thid: htmlIdGenerator('thr')(), + name: 'Base', + color: '#3CA1C7', + value: 0, + isReadOnly: true, + }, + DefaultTextColor: '#FFFFFF', +}; +export interface DefaultBarChartStylesProps { + BarMode: string; + GroupWidth: number; + BarWidth: number; + LabelSize: number; +} + +export const DEFAULT_BAR_CHART_STYLES: DefaultBarChartStylesProps = { + BarMode: 'group', + GroupWidth: 0.7, + BarWidth: 0.97, + LabelSize: 12, +}; + +export const SIMILAR_VIZ_TYPES = [ + VIS_CHART_TYPES.Line, + VIS_CHART_TYPES.Scatter, + VIS_CHART_TYPES.HorizontalBar, + VIS_CHART_TYPES.Bar, +]; + +export enum ConfigChartOptionsEnum { + palettePicker = 'palettePicker', + singleColorPicker = 'singleColorPicker', + colorpicker = 'colorpicker', + treemapColorPicker = 'treemapColorPicker', + input = 'input', + textInput = 'textInput', + slider = 'slider', + switchButton = 'switchButton', + buttons = 'buttons', +} + +export const CUSTOM_LABEL = 'customLabel'; +export const BREAKDOWNS = 'breakdowns'; +export const SPAN = 'span'; +export const AGGREGATION_INFO = 'At least one metric is required to render a chart'; +export const DIMENSION_INFO = 'The timestamp type field can be selected as a first dimension only'; +export const TIME_FIELD = 'time_field'; +export const DISABLED_COLOUR = "#fafbfd"; diff --git a/dashboards-observability/common/constants/shared.ts b/dashboards-observability/common/constants/shared.ts index 19c0fb8fd..5e13e62f1 100644 --- a/dashboards-observability/common/constants/shared.ts +++ b/dashboards-observability/common/constants/shared.ts @@ -2,8 +2,8 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ - import CSS from 'csstype'; +import { IField } from '../../common/types/explorer'; // Client route export const PPL_BASE = '/api/ppl'; @@ -71,57 +71,119 @@ export const pageStyles: CSS.Properties = { maxWidth: '1130px', }; +export enum VIS_CHART_TYPES { + Bar = 'bar', + HorizontalBar = 'horizontal_bar', + Line = 'line', + Pie = 'pie', + HeatMap = 'heatmap', + Text = 'text', +} + export const NUMERICAL_FIELDS = ['short', 'integer', 'long', 'float', 'double']; -export const ENABLED_VIS_TYPES = ['bar', 'horizontal_bar', 'line', 'pie', 'heatmap', 'text']; +export const ENABLED_VIS_TYPES = [ + VIS_CHART_TYPES.Bar, + VIS_CHART_TYPES.HorizontalBar, + VIS_CHART_TYPES.Line, + VIS_CHART_TYPES.Pie, + VIS_CHART_TYPES.HeatMap, + VIS_CHART_TYPES.Text, +]; -//Live tail constants +// Live tail constants export const LIVE_OPTIONS = [ { - label:'5s', + label: '5s', startTime: 'now-5s', delayTime: 5000, }, { - label:'10s', + label: '10s', startTime: 'now-10s', delayTime: 10000, }, { - label:'30s', + label: '30s', startTime: 'now-30s', delayTime: 30000, }, { - label:'1m', + label: '1m', startTime: 'now-1m', delayTime: 60000, }, { - label:'5m', + label: '5m', startTime: 'now-5m', delayTime: 60000 * 5, }, { - label:'15m', + label: '15m', startTime: 'now-15m', delayTime: 60000 * 15, }, { - label:'30m', + label: '30m', startTime: 'now-30m', delayTime: 60000 * 30, }, { - label:'1h', + label: '1h', startTime: 'now-1h', delayTime: 60000 * 60, }, { - label:'2h', + label: '2h', startTime: 'now-2h', delayTime: 60000 * 120, }, ]; -export const LIVE_END_TIME ='now'; \ No newline at end of file +export const LIVE_END_TIME = 'now'; +export interface DefaultChartStylesProps { + DefaultModeLine: string; + Interpolation: string; + LineWidth: number; + FillOpacity: number; + MarkerSize: number; + ShowLegend: string; + LegendPosition: string; + LabelAngle: number; + DefaultSortSectors: string; + DefaultModeScatter: string; +} + +export const DEFAULT_CHART_STYLES: DefaultChartStylesProps = { + DefaultModeLine: 'lines', + Interpolation: 'spline', + LineWidth: 2, + FillOpacity: 40, + MarkerSize: 5, + ShowLegend: 'show', + LegendPosition: 'v', + LabelAngle: 0, + DefaultSortSectors: 'largest_to_smallest', + DefaultModeScatter: 'markers', +}; + +export const FILLOPACITY_DIV_FACTOR = 200; +export const SLIDER_MIN_VALUE = 0; +export const SLIDER_MAX_VALUE = 100; +export const SLIDER_STEP = 1; +export const THRESHOLD_LINE_WIDTH = 3; +export const THRESHOLD_LINE_OPACITY = 0.7; +export const MAX_BUCKET_LENGTH = 16; + +export enum BarOrientation { + horizontal = 'h', + vertical = 'v', +} + +export const PLOT_MARGIN = { + l: 30, + r: 5, + b: 30, + t: 50, + pad: 4, +}; diff --git a/dashboards-observability/common/query_manager/antlr/adaptors/case_insensitive_char_stream.ts b/dashboards-observability/common/query_manager/antlr/adaptors/case_insensitive_char_stream.ts new file mode 100644 index 000000000..6c3414f35 --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/adaptors/case_insensitive_char_stream.ts @@ -0,0 +1,60 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CharStream } from 'antlr4ts'; + +export class CaseInsensitiveCharStream { + private stream: CharStream; + + get index(): number { + return this.stream.index; + } + + get size(): number { + return this.stream.size; + } + + get sourceName(): string { + return 'pplquery'; + } + + constructor(stream: CharStream) { + this.stream = stream; + } + + LA(offset: number): number { + const c: number = this.stream.LA(offset); + if (c <= 0) { + return c; + } + + // case insensitivity support for PPL + return String.fromCodePoint(c).toUpperCase().codePointAt(0)!; + } + + consume(): void { + this.stream.consume(); + } + + mark(): number { + return this.stream.mark(); + } + + release(marker: number): void { + this.stream.release(marker); + } + + seek(index: number): void { + this.stream.seek(index); + } + + getText(interval: any): string { + return this.stream.getText(interval); + } + + toString(): string { + return this.stream.toString(); + } +} diff --git a/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.interp b/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.interp new file mode 100644 index 000000000..68b2f0fd1 --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.interp @@ -0,0 +1,831 @@ +token literal names: +null +'SEARCH' +'FROM' +'WHERE' +'FIELDS' +'RENAME' +'STATS' +'DEDUP' +'SORT' +'EVAL' +'HEAD' +'TOP' +'RARE' +'PARSE' +'KMEANS' +'AD' +'AS' +'BY' +'SOURCE' +'INDEX' +'D' +'DESC' +'SORTBY' +'AUTO' +'STR' +'IP' +'NUM' +'KEEPEMPTY' +'CONSECUTIVE' +'DEDUP_SPLITVALUES' +'PARTITIONS' +'ALLNUM' +'DELIM' +'CENTROIDS' +'ITERATIONS' +'DISTANCE_TYPE' +'NUMBER_OF_TREES' +'SHINGLE_SIZE' +'SAMPLE_SIZE' +'OUTPUT_AFTER' +'TIME_DECAY' +'ANOMALY_RATE' +'TIME_FIELD' +'TIME_ZONE' +'TRAINING_DATA_SIZE' +'ANOMALY_SCORE_THRESHOLD' +'CASE' +'IN' +'NOT' +'OR' +'AND' +'XOR' +'TRUE' +'FALSE' +'REGEXP' +'DATETIME' +'INTERVAL' +'MICROSECOND' +'MILLISECOND' +'SECOND' +'MINUTE' +'HOUR' +'DAY' +'WEEK' +'MONTH' +'QUARTER' +'YEAR' +'SECOND_MICROSECOND' +'MINUTE_MICROSECOND' +'MINUTE_SECOND' +'HOUR_MICROSECOND' +'HOUR_SECOND' +'HOUR_MINUTE' +'DAY_MICROSECOND' +'DAY_SECOND' +'DAY_MINUTE' +'DAY_HOUR' +'YEAR_MONTH' +'DATAMODEL' +'LOOKUP' +'SAVEDSEARCH' +'INT' +'INTEGER' +'DOUBLE' +'LONG' +'FLOAT' +'STRING' +'BOOLEAN' +'|' +',' +'.' +'=' +'>' +'<' +null +null +null +'+' +'-' +'*' +'/' +'%' +'!' +':' +'(' +')' +'[' +']' +'\'' +'"' +'`' +'~' +'&' +'^' +'AVG' +'COUNT' +'DISTINCT_COUNT' +'ESTDC' +'ESTDC_ERROR' +'MAX' +'MEAN' +'MEDIAN' +'MIN' +'MODE' +'RANGE' +'STDEV' +'STDEVP' +'SUM' +'SUMSQ' +'VAR_SAMP' +'VAR_POP' +'STDDEV_SAMP' +'STDDEV_POP' +'PERCENTILE' +'FIRST' +'LAST' +'LIST' +'VALUES' +'EARLIEST' +'EARLIEST_TIME' +'LATEST' +'LATEST_TIME' +'PER_DAY' +'PER_HOUR' +'PER_MINUTE' +'PER_SECOND' +'RATE' +'SPARKLINE' +'C' +'DC' +'ABS' +'CEIL' +'CEILING' +'CONV' +'CRC32' +'E' +'EXP' +'FLOOR' +'LN' +'LOG' +'LOG10' +'LOG2' +'MOD' +'PI' +'POW' +'POWER' +'RAND' +'ROUND' +'SIGN' +'SQRT' +'TRUNCATE' +'ACOS' +'ASIN' +'ATAN' +'ATAN2' +'COS' +'COT' +'DEGREES' +'RADIANS' +'SIN' +'TAN' +'ADDDATE' +'DATE' +'DATE_ADD' +'DATE_SUB' +'DAYOFMONTH' +'DAYOFWEEK' +'DAYOFYEAR' +'DAYNAME' +'FROM_DAYS' +'MONTHNAME' +'SUBDATE' +'TIME' +'TIME_TO_SEC' +'TIMESTAMP' +'DATE_FORMAT' +'TO_DAYS' +'SUBSTR' +'SUBSTRING' +'LTRIM' +'RTRIM' +'TRIM' +'TO' +'LOWER' +'UPPER' +'CONCAT' +'CONCAT_WS' +'LENGTH' +'STRCMP' +'RIGHT' +'LEFT' +'ASCII' +'LOCATE' +'REPLACE' +'CAST' +'LIKE' +'ISNULL' +'ISNOTNULL' +'IFNULL' +'NULLIF' +'IF' +'MATCH' +'MATCH_PHRASE' +'SIMPLE_QUERY_STRING' +'ALLOW_LEADING_WILDCARD' +'ANALYZE_WILDCARD' +'ANALYZER' +'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY' +'BOOST' +'CUTOFF_FREQUENCY' +'DEFAULT_FIELD' +'DEFAULT_OPERATOR' +'ENABLE_POSITION_INCREMENTS' +'FLAGS' +'FUZZY_MAX_EXPANSIONS' +'FUZZY_PREFIX_LENGTH' +'FUZZY_TRANSPOSITIONS' +'FUZZY_REWRITE' +'FUZZINESS' +'LENIENT' +'LOW_FREQ_OPERATOR' +'MAX_DETERMINIZED_STATES' +'MAX_EXPANSIONS' +'MINIMUM_SHOULD_MATCH' +'OPERATOR' +'PHRASE_SLOP' +'PREFIX_LENGTH' +'QUOTE_ANALYZER' +'QUOTE_FIELD_SUFFIX' +'REWRITE' +'SLOP' +'TIE_BREAKER' +'TYPE' +'ZERO_TERMS_QUERY' +'SPAN' +'MS' +'S' +'M' +'H' +'W' +'Q' +'Y' +null +null +null +null +null +null +null +null + +token symbolic names: +null +SEARCH +FROM +WHERE +FIELDS +RENAME +STATS +DEDUP +SORT +EVAL +HEAD +TOP +RARE +PARSE +KMEANS +AD +AS +BY +SOURCE +INDEX +D +DESC +SORTBY +AUTO +STR +IP +NUM +KEEPEMPTY +CONSECUTIVE +DEDUP_SPLITVALUES +PARTITIONS +ALLNUM +DELIM +CENTROIDS +ITERATIONS +DISTANCE_TYPE +NUMBER_OF_TREES +SHINGLE_SIZE +SAMPLE_SIZE +OUTPUT_AFTER +TIME_DECAY +ANOMALY_RATE +TIME_FIELD +TIME_ZONE +TRAINING_DATA_SIZE +ANOMALY_SCORE_THRESHOLD +CASE +IN +NOT +OR +AND +XOR +TRUE +FALSE +REGEXP +DATETIME +INTERVAL +MICROSECOND +MILLISECOND +SECOND +MINUTE +HOUR +DAY +WEEK +MONTH +QUARTER +YEAR +SECOND_MICROSECOND +MINUTE_MICROSECOND +MINUTE_SECOND +HOUR_MICROSECOND +HOUR_SECOND +HOUR_MINUTE +DAY_MICROSECOND +DAY_SECOND +DAY_MINUTE +DAY_HOUR +YEAR_MONTH +DATAMODEL +LOOKUP +SAVEDSEARCH +INT +INTEGER +DOUBLE +LONG +FLOAT +STRING +BOOLEAN +PIPE +COMMA +DOT +EQUAL +GREATER +LESS +NOT_GREATER +NOT_LESS +NOT_EQUAL +PLUS +MINUS +STAR +DIVIDE +MODULE +EXCLAMATION_SYMBOL +COLON +LT_PRTHS +RT_PRTHS +LT_SQR_PRTHS +RT_SQR_PRTHS +SINGLE_QUOTE +DOUBLE_QUOTE +BACKTICK +BIT_NOT_OP +BIT_AND_OP +BIT_XOR_OP +AVG +COUNT +DISTINCT_COUNT +ESTDC +ESTDC_ERROR +MAX +MEAN +MEDIAN +MIN +MODE +RANGE +STDEV +STDEVP +SUM +SUMSQ +VAR_SAMP +VAR_POP +STDDEV_SAMP +STDDEV_POP +PERCENTILE +FIRST +LAST +LIST +VALUES +EARLIEST +EARLIEST_TIME +LATEST +LATEST_TIME +PER_DAY +PER_HOUR +PER_MINUTE +PER_SECOND +RATE +SPARKLINE +C +DC +ABS +CEIL +CEILING +CONV +CRC32 +E +EXP +FLOOR +LN +LOG +LOG10 +LOG2 +MOD +PI +POW +POWER +RAND +ROUND +SIGN +SQRT +TRUNCATE +ACOS +ASIN +ATAN +ATAN2 +COS +COT +DEGREES +RADIANS +SIN +TAN +ADDDATE +DATE +DATE_ADD +DATE_SUB +DAYOFMONTH +DAYOFWEEK +DAYOFYEAR +DAYNAME +FROM_DAYS +MONTHNAME +SUBDATE +TIME +TIME_TO_SEC +TIMESTAMP +DATE_FORMAT +TO_DAYS +SUBSTR +SUBSTRING +LTRIM +RTRIM +TRIM +TO +LOWER +UPPER +CONCAT +CONCAT_WS +LENGTH +STRCMP +RIGHT +LEFT +ASCII +LOCATE +REPLACE +CAST +LIKE +ISNULL +ISNOTNULL +IFNULL +NULLIF +IF +MATCH +MATCH_PHRASE +SIMPLE_QUERY_STRING +ALLOW_LEADING_WILDCARD +ANALYZE_WILDCARD +ANALYZER +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY +BOOST +CUTOFF_FREQUENCY +DEFAULT_FIELD +DEFAULT_OPERATOR +ENABLE_POSITION_INCREMENTS +FLAGS +FUZZY_MAX_EXPANSIONS +FUZZY_PREFIX_LENGTH +FUZZY_TRANSPOSITIONS +FUZZY_REWRITE +FUZZINESS +LENIENT +LOW_FREQ_OPERATOR +MAX_DETERMINIZED_STATES +MAX_EXPANSIONS +MINIMUM_SHOULD_MATCH +OPERATOR +PHRASE_SLOP +PREFIX_LENGTH +QUOTE_ANALYZER +QUOTE_FIELD_SUFFIX +REWRITE +SLOP +TIE_BREAKER +TYPE +ZERO_TERMS_QUERY +SPAN +MS +S +M +H +W +Q +Y +ID +INTEGER_LITERAL +DECIMAL_LITERAL +ID_DATE_SUFFIX +DQUOTA_STRING +SQUOTA_STRING +BQUOTA_STRING +ERROR_RECOGNITION + +rule names: +SEARCH +FROM +WHERE +FIELDS +RENAME +STATS +DEDUP +SORT +EVAL +HEAD +TOP +RARE +PARSE +KMEANS +AD +AS +BY +SOURCE +INDEX +D +DESC +SORTBY +AUTO +STR +IP +NUM +KEEPEMPTY +CONSECUTIVE +DEDUP_SPLITVALUES +PARTITIONS +ALLNUM +DELIM +CENTROIDS +ITERATIONS +DISTANCE_TYPE +NUMBER_OF_TREES +SHINGLE_SIZE +SAMPLE_SIZE +OUTPUT_AFTER +TIME_DECAY +ANOMALY_RATE +TIME_FIELD +TIME_ZONE +TRAINING_DATA_SIZE +ANOMALY_SCORE_THRESHOLD +CASE +IN +NOT +OR +AND +XOR +TRUE +FALSE +REGEXP +DATETIME +INTERVAL +MICROSECOND +MILLISECOND +SECOND +MINUTE +HOUR +DAY +WEEK +MONTH +QUARTER +YEAR +SECOND_MICROSECOND +MINUTE_MICROSECOND +MINUTE_SECOND +HOUR_MICROSECOND +HOUR_SECOND +HOUR_MINUTE +DAY_MICROSECOND +DAY_SECOND +DAY_MINUTE +DAY_HOUR +YEAR_MONTH +DATAMODEL +LOOKUP +SAVEDSEARCH +INT +INTEGER +DOUBLE +LONG +FLOAT +STRING +BOOLEAN +PIPE +COMMA +DOT +EQUAL +GREATER +LESS +NOT_GREATER +NOT_LESS +NOT_EQUAL +PLUS +MINUS +STAR +DIVIDE +MODULE +EXCLAMATION_SYMBOL +COLON +LT_PRTHS +RT_PRTHS +LT_SQR_PRTHS +RT_SQR_PRTHS +SINGLE_QUOTE +DOUBLE_QUOTE +BACKTICK +BIT_NOT_OP +BIT_AND_OP +BIT_XOR_OP +AVG +COUNT +DISTINCT_COUNT +ESTDC +ESTDC_ERROR +MAX +MEAN +MEDIAN +MIN +MODE +RANGE +STDEV +STDEVP +SUM +SUMSQ +VAR_SAMP +VAR_POP +STDDEV_SAMP +STDDEV_POP +PERCENTILE +FIRST +LAST +LIST +VALUES +EARLIEST +EARLIEST_TIME +LATEST +LATEST_TIME +PER_DAY +PER_HOUR +PER_MINUTE +PER_SECOND +RATE +SPARKLINE +C +DC +ABS +CEIL +CEILING +CONV +CRC32 +E +EXP +FLOOR +LN +LOG +LOG10 +LOG2 +MOD +PI +POW +POWER +RAND +ROUND +SIGN +SQRT +TRUNCATE +ACOS +ASIN +ATAN +ATAN2 +COS +COT +DEGREES +RADIANS +SIN +TAN +ADDDATE +DATE +DATE_ADD +DATE_SUB +DAYOFMONTH +DAYOFWEEK +DAYOFYEAR +DAYNAME +FROM_DAYS +MONTHNAME +SUBDATE +TIME +TIME_TO_SEC +TIMESTAMP +DATE_FORMAT +TO_DAYS +SUBSTR +SUBSTRING +LTRIM +RTRIM +TRIM +TO +LOWER +UPPER +CONCAT +CONCAT_WS +LENGTH +STRCMP +RIGHT +LEFT +ASCII +LOCATE +REPLACE +CAST +LIKE +ISNULL +ISNOTNULL +IFNULL +NULLIF +IF +MATCH +MATCH_PHRASE +SIMPLE_QUERY_STRING +ALLOW_LEADING_WILDCARD +ANALYZE_WILDCARD +ANALYZER +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY +BOOST +CUTOFF_FREQUENCY +DEFAULT_FIELD +DEFAULT_OPERATOR +ENABLE_POSITION_INCREMENTS +FLAGS +FUZZY_MAX_EXPANSIONS +FUZZY_PREFIX_LENGTH +FUZZY_TRANSPOSITIONS +FUZZY_REWRITE +FUZZINESS +LENIENT +LOW_FREQ_OPERATOR +MAX_DETERMINIZED_STATES +MAX_EXPANSIONS +MINIMUM_SHOULD_MATCH +OPERATOR +PHRASE_SLOP +PREFIX_LENGTH +QUOTE_ANALYZER +QUOTE_FIELD_SUFFIX +REWRITE +SLOP +TIE_BREAKER +TYPE +ZERO_TERMS_QUERY +SPAN +MS +S +M +H +W +Q +Y +ID +INTEGER_LITERAL +DECIMAL_LITERAL +DATE_SUFFIX +ID_LITERAL +ID_DATE_SUFFIX +DQUOTA_STRING +SQUOTA_STRING +BQUOTA_STRING +DEC_DIGIT +ERROR_RECOGNITION + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN +null +null +WHITESPACE +ERRORCHANNEL + +mode names: +DEFAULT_MODE + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 271, 2671, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 4, 78, 9, 78, 4, 79, 9, 79, 4, 80, 9, 80, 4, 81, 9, 81, 4, 82, 9, 82, 4, 83, 9, 83, 4, 84, 9, 84, 4, 85, 9, 85, 4, 86, 9, 86, 4, 87, 9, 87, 4, 88, 9, 88, 4, 89, 9, 89, 4, 90, 9, 90, 4, 91, 9, 91, 4, 92, 9, 92, 4, 93, 9, 93, 4, 94, 9, 94, 4, 95, 9, 95, 4, 96, 9, 96, 4, 97, 9, 97, 4, 98, 9, 98, 4, 99, 9, 99, 4, 100, 9, 100, 4, 101, 9, 101, 4, 102, 9, 102, 4, 103, 9, 103, 4, 104, 9, 104, 4, 105, 9, 105, 4, 106, 9, 106, 4, 107, 9, 107, 4, 108, 9, 108, 4, 109, 9, 109, 4, 110, 9, 110, 4, 111, 9, 111, 4, 112, 9, 112, 4, 113, 9, 113, 4, 114, 9, 114, 4, 115, 9, 115, 4, 116, 9, 116, 4, 117, 9, 117, 4, 118, 9, 118, 4, 119, 9, 119, 4, 120, 9, 120, 4, 121, 9, 121, 4, 122, 9, 122, 4, 123, 9, 123, 4, 124, 9, 124, 4, 125, 9, 125, 4, 126, 9, 126, 4, 127, 9, 127, 4, 128, 9, 128, 4, 129, 9, 129, 4, 130, 9, 130, 4, 131, 9, 131, 4, 132, 9, 132, 4, 133, 9, 133, 4, 134, 9, 134, 4, 135, 9, 135, 4, 136, 9, 136, 4, 137, 9, 137, 4, 138, 9, 138, 4, 139, 9, 139, 4, 140, 9, 140, 4, 141, 9, 141, 4, 142, 9, 142, 4, 143, 9, 143, 4, 144, 9, 144, 4, 145, 9, 145, 4, 146, 9, 146, 4, 147, 9, 147, 4, 148, 9, 148, 4, 149, 9, 149, 4, 150, 9, 150, 4, 151, 9, 151, 4, 152, 9, 152, 4, 153, 9, 153, 4, 154, 9, 154, 4, 155, 9, 155, 4, 156, 9, 156, 4, 157, 9, 157, 4, 158, 9, 158, 4, 159, 9, 159, 4, 160, 9, 160, 4, 161, 9, 161, 4, 162, 9, 162, 4, 163, 9, 163, 4, 164, 9, 164, 4, 165, 9, 165, 4, 166, 9, 166, 4, 167, 9, 167, 4, 168, 9, 168, 4, 169, 9, 169, 4, 170, 9, 170, 4, 171, 9, 171, 4, 172, 9, 172, 4, 173, 9, 173, 4, 174, 9, 174, 4, 175, 9, 175, 4, 176, 9, 176, 4, 177, 9, 177, 4, 178, 9, 178, 4, 179, 9, 179, 4, 180, 9, 180, 4, 181, 9, 181, 4, 182, 9, 182, 4, 183, 9, 183, 4, 184, 9, 184, 4, 185, 9, 185, 4, 186, 9, 186, 4, 187, 9, 187, 4, 188, 9, 188, 4, 189, 9, 189, 4, 190, 9, 190, 4, 191, 9, 191, 4, 192, 9, 192, 4, 193, 9, 193, 4, 194, 9, 194, 4, 195, 9, 195, 4, 196, 9, 196, 4, 197, 9, 197, 4, 198, 9, 198, 4, 199, 9, 199, 4, 200, 9, 200, 4, 201, 9, 201, 4, 202, 9, 202, 4, 203, 9, 203, 4, 204, 9, 204, 4, 205, 9, 205, 4, 206, 9, 206, 4, 207, 9, 207, 4, 208, 9, 208, 4, 209, 9, 209, 4, 210, 9, 210, 4, 211, 9, 211, 4, 212, 9, 212, 4, 213, 9, 213, 4, 214, 9, 214, 4, 215, 9, 215, 4, 216, 9, 216, 4, 217, 9, 217, 4, 218, 9, 218, 4, 219, 9, 219, 4, 220, 9, 220, 4, 221, 9, 221, 4, 222, 9, 222, 4, 223, 9, 223, 4, 224, 9, 224, 4, 225, 9, 225, 4, 226, 9, 226, 4, 227, 9, 227, 4, 228, 9, 228, 4, 229, 9, 229, 4, 230, 9, 230, 4, 231, 9, 231, 4, 232, 9, 232, 4, 233, 9, 233, 4, 234, 9, 234, 4, 235, 9, 235, 4, 236, 9, 236, 4, 237, 9, 237, 4, 238, 9, 238, 4, 239, 9, 239, 4, 240, 9, 240, 4, 241, 9, 241, 4, 242, 9, 242, 4, 243, 9, 243, 4, 244, 9, 244, 4, 245, 9, 245, 4, 246, 9, 246, 4, 247, 9, 247, 4, 248, 9, 248, 4, 249, 9, 249, 4, 250, 9, 250, 4, 251, 9, 251, 4, 252, 9, 252, 4, 253, 9, 253, 4, 254, 9, 254, 4, 255, 9, 255, 4, 256, 9, 256, 4, 257, 9, 257, 4, 258, 9, 258, 4, 259, 9, 259, 4, 260, 9, 260, 4, 261, 9, 261, 4, 262, 9, 262, 4, 263, 9, 263, 4, 264, 9, 264, 4, 265, 9, 265, 4, 266, 9, 266, 4, 267, 9, 267, 4, 268, 9, 268, 4, 269, 9, 269, 4, 270, 9, 270, 4, 271, 9, 271, 4, 272, 9, 272, 4, 273, 9, 273, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 79, 3, 79, 3, 79, 3, 79, 3, 79, 3, 79, 3, 79, 3, 79, 3, 79, 3, 79, 3, 80, 3, 80, 3, 80, 3, 80, 3, 80, 3, 80, 3, 80, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 82, 3, 82, 3, 82, 3, 82, 3, 83, 3, 83, 3, 83, 3, 83, 3, 83, 3, 83, 3, 83, 3, 83, 3, 84, 3, 84, 3, 84, 3, 84, 3, 84, 3, 84, 3, 84, 3, 85, 3, 85, 3, 85, 3, 85, 3, 85, 3, 86, 3, 86, 3, 86, 3, 86, 3, 86, 3, 86, 3, 87, 3, 87, 3, 87, 3, 87, 3, 87, 3, 87, 3, 87, 3, 88, 3, 88, 3, 88, 3, 88, 3, 88, 3, 88, 3, 88, 3, 88, 3, 89, 3, 89, 3, 90, 3, 90, 3, 91, 3, 91, 3, 92, 3, 92, 3, 93, 3, 93, 3, 94, 3, 94, 3, 95, 3, 95, 3, 95, 3, 96, 3, 96, 3, 96, 3, 97, 3, 97, 3, 97, 3, 98, 3, 98, 3, 99, 3, 99, 3, 100, 3, 100, 3, 101, 3, 101, 3, 102, 3, 102, 3, 103, 3, 103, 3, 104, 3, 104, 3, 105, 3, 105, 3, 106, 3, 106, 3, 107, 3, 107, 3, 108, 3, 108, 3, 109, 3, 109, 3, 110, 3, 110, 3, 111, 3, 111, 3, 112, 3, 112, 3, 113, 3, 113, 3, 114, 3, 114, 3, 115, 3, 115, 3, 115, 3, 115, 3, 116, 3, 116, 3, 116, 3, 116, 3, 116, 3, 116, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 117, 3, 118, 3, 118, 3, 118, 3, 118, 3, 118, 3, 118, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 119, 3, 120, 3, 120, 3, 120, 3, 120, 3, 121, 3, 121, 3, 121, 3, 121, 3, 121, 3, 122, 3, 122, 3, 122, 3, 122, 3, 122, 3, 122, 3, 122, 3, 123, 3, 123, 3, 123, 3, 123, 3, 124, 3, 124, 3, 124, 3, 124, 3, 124, 3, 125, 3, 125, 3, 125, 3, 125, 3, 125, 3, 125, 3, 126, 3, 126, 3, 126, 3, 126, 3, 126, 3, 126, 3, 127, 3, 127, 3, 127, 3, 127, 3, 127, 3, 127, 3, 127, 3, 128, 3, 128, 3, 128, 3, 128, 3, 129, 3, 129, 3, 129, 3, 129, 3, 129, 3, 129, 3, 130, 3, 130, 3, 130, 3, 130, 3, 130, 3, 130, 3, 130, 3, 130, 3, 130, 3, 131, 3, 131, 3, 131, 3, 131, 3, 131, 3, 131, 3, 131, 3, 131, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 132, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 133, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 134, 3, 135, 3, 135, 3, 135, 3, 135, 3, 135, 3, 135, 3, 136, 3, 136, 3, 136, 3, 136, 3, 136, 3, 137, 3, 137, 3, 137, 3, 137, 3, 137, 3, 138, 3, 138, 3, 138, 3, 138, 3, 138, 3, 138, 3, 138, 3, 139, 3, 139, 3, 139, 3, 139, 3, 139, 3, 139, 3, 139, 3, 139, 3, 139, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 140, 3, 141, 3, 141, 3, 141, 3, 141, 3, 141, 3, 141, 3, 141, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 142, 3, 143, 3, 143, 3, 143, 3, 143, 3, 143, 3, 143, 3, 143, 3, 143, 3, 144, 3, 144, 3, 144, 3, 144, 3, 144, 3, 144, 3, 144, 3, 144, 3, 144, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 145, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 146, 3, 147, 3, 147, 3, 147, 3, 147, 3, 147, 3, 148, 3, 148, 3, 148, 3, 148, 3, 148, 3, 148, 3, 148, 3, 148, 3, 148, 3, 148, 3, 149, 3, 149, 3, 150, 3, 150, 3, 150, 3, 151, 3, 151, 3, 151, 3, 151, 3, 152, 3, 152, 3, 152, 3, 152, 3, 152, 3, 153, 3, 153, 3, 153, 3, 153, 3, 153, 3, 153, 3, 153, 3, 153, 3, 154, 3, 154, 3, 154, 3, 154, 3, 154, 3, 155, 3, 155, 3, 155, 3, 155, 3, 155, 3, 155, 3, 156, 3, 156, 3, 157, 3, 157, 3, 157, 3, 157, 3, 158, 3, 158, 3, 158, 3, 158, 3, 158, 3, 158, 3, 159, 3, 159, 3, 159, 3, 160, 3, 160, 3, 160, 3, 160, 3, 161, 3, 161, 3, 161, 3, 161, 3, 161, 3, 161, 3, 162, 3, 162, 3, 162, 3, 162, 3, 162, 3, 163, 3, 163, 3, 163, 3, 163, 3, 164, 3, 164, 3, 164, 3, 165, 3, 165, 3, 165, 3, 165, 3, 166, 3, 166, 3, 166, 3, 166, 3, 166, 3, 166, 3, 167, 3, 167, 3, 167, 3, 167, 3, 167, 3, 168, 3, 168, 3, 168, 3, 168, 3, 168, 3, 168, 3, 169, 3, 169, 3, 169, 3, 169, 3, 169, 3, 170, 3, 170, 3, 170, 3, 170, 3, 170, 3, 171, 3, 171, 3, 171, 3, 171, 3, 171, 3, 171, 3, 171, 3, 171, 3, 171, 3, 172, 3, 172, 3, 172, 3, 172, 3, 172, 3, 173, 3, 173, 3, 173, 3, 173, 3, 173, 3, 174, 3, 174, 3, 174, 3, 174, 3, 174, 3, 175, 3, 175, 3, 175, 3, 175, 3, 175, 3, 175, 3, 176, 3, 176, 3, 176, 3, 176, 3, 177, 3, 177, 3, 177, 3, 177, 3, 178, 3, 178, 3, 178, 3, 178, 3, 178, 3, 178, 3, 178, 3, 178, 3, 179, 3, 179, 3, 179, 3, 179, 3, 179, 3, 179, 3, 179, 3, 179, 3, 180, 3, 180, 3, 180, 3, 180, 3, 181, 3, 181, 3, 181, 3, 181, 3, 182, 3, 182, 3, 182, 3, 182, 3, 182, 3, 182, 3, 182, 3, 182, 3, 183, 3, 183, 3, 183, 3, 183, 3, 183, 3, 184, 3, 184, 3, 184, 3, 184, 3, 184, 3, 184, 3, 184, 3, 184, 3, 184, 3, 185, 3, 185, 3, 185, 3, 185, 3, 185, 3, 185, 3, 185, 3, 185, 3, 185, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 186, 3, 187, 3, 187, 3, 187, 3, 187, 3, 187, 3, 187, 3, 187, 3, 187, 3, 187, 3, 187, 3, 188, 3, 188, 3, 188, 3, 188, 3, 188, 3, 188, 3, 188, 3, 188, 3, 188, 3, 188, 3, 189, 3, 189, 3, 189, 3, 189, 3, 189, 3, 189, 3, 189, 3, 189, 3, 190, 3, 190, 3, 190, 3, 190, 3, 190, 3, 190, 3, 190, 3, 190, 3, 190, 3, 190, 3, 191, 3, 191, 3, 191, 3, 191, 3, 191, 3, 191, 3, 191, 3, 191, 3, 191, 3, 191, 3, 192, 3, 192, 3, 192, 3, 192, 3, 192, 3, 192, 3, 192, 3, 192, 3, 193, 3, 193, 3, 193, 3, 193, 3, 193, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 194, 3, 195, 3, 195, 3, 195, 3, 195, 3, 195, 3, 195, 3, 195, 3, 195, 3, 195, 3, 195, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 196, 3, 197, 3, 197, 3, 197, 3, 197, 3, 197, 3, 197, 3, 197, 3, 197, 3, 198, 3, 198, 3, 198, 3, 198, 3, 198, 3, 198, 3, 198, 3, 199, 3, 199, 3, 199, 3, 199, 3, 199, 3, 199, 3, 199, 3, 199, 3, 199, 3, 199, 3, 200, 3, 200, 3, 200, 3, 200, 3, 200, 3, 200, 3, 201, 3, 201, 3, 201, 3, 201, 3, 201, 3, 201, 3, 202, 3, 202, 3, 202, 3, 202, 3, 202, 3, 203, 3, 203, 3, 203, 3, 204, 3, 204, 3, 204, 3, 204, 3, 204, 3, 204, 3, 205, 3, 205, 3, 205, 3, 205, 3, 205, 3, 205, 3, 206, 3, 206, 3, 206, 3, 206, 3, 206, 3, 206, 3, 206, 3, 207, 3, 207, 3, 207, 3, 207, 3, 207, 3, 207, 3, 207, 3, 207, 3, 207, 3, 207, 3, 208, 3, 208, 3, 208, 3, 208, 3, 208, 3, 208, 3, 208, 3, 209, 3, 209, 3, 209, 3, 209, 3, 209, 3, 209, 3, 209, 3, 210, 3, 210, 3, 210, 3, 210, 3, 210, 3, 210, 3, 211, 3, 211, 3, 211, 3, 211, 3, 211, 3, 212, 3, 212, 3, 212, 3, 212, 3, 212, 3, 212, 3, 213, 3, 213, 3, 213, 3, 213, 3, 213, 3, 213, 3, 213, 3, 214, 3, 214, 3, 214, 3, 214, 3, 214, 3, 214, 3, 214, 3, 214, 3, 215, 3, 215, 3, 215, 3, 215, 3, 215, 3, 216, 3, 216, 3, 216, 3, 216, 3, 216, 3, 217, 3, 217, 3, 217, 3, 217, 3, 217, 3, 217, 3, 217, 3, 218, 3, 218, 3, 218, 3, 218, 3, 218, 3, 218, 3, 218, 3, 218, 3, 218, 3, 218, 3, 219, 3, 219, 3, 219, 3, 219, 3, 219, 3, 219, 3, 219, 3, 220, 3, 220, 3, 220, 3, 220, 3, 220, 3, 220, 3, 220, 3, 221, 3, 221, 3, 221, 3, 222, 3, 222, 3, 222, 3, 222, 3, 222, 3, 222, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 223, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 224, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 225, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 226, 3, 227, 3, 227, 3, 227, 3, 227, 3, 227, 3, 227, 3, 227, 3, 227, 3, 227, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 228, 3, 229, 3, 229, 3, 229, 3, 229, 3, 229, 3, 229, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 230, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 231, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 232, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 233, 3, 234, 3, 234, 3, 234, 3, 234, 3, 234, 3, 234, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 235, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 236, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 237, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 238, 3, 239, 3, 239, 3, 239, 3, 239, 3, 239, 3, 239, 3, 239, 3, 239, 3, 239, 3, 239, 3, 240, 3, 240, 3, 240, 3, 240, 3, 240, 3, 240, 3, 240, 3, 240, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 241, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 242, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 243, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 244, 3, 245, 3, 245, 3, 245, 3, 245, 3, 245, 3, 245, 3, 245, 3, 245, 3, 245, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 246, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 247, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 248, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 249, 3, 250, 3, 250, 3, 250, 3, 250, 3, 250, 3, 250, 3, 250, 3, 250, 3, 251, 3, 251, 3, 251, 3, 251, 3, 251, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 252, 3, 253, 3, 253, 3, 253, 3, 253, 3, 253, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 254, 3, 255, 3, 255, 3, 255, 3, 255, 3, 255, 3, 256, 3, 256, 3, 256, 3, 257, 3, 257, 3, 258, 3, 258, 3, 259, 3, 259, 3, 260, 3, 260, 3, 261, 3, 261, 3, 262, 3, 262, 3, 263, 3, 263, 3, 264, 6, 264, 2585, 10, 264, 13, 264, 14, 264, 2586, 3, 265, 6, 265, 2590, 10, 265, 13, 265, 14, 265, 2591, 5, 265, 2594, 10, 265, 3, 265, 3, 265, 6, 265, 2598, 10, 265, 13, 265, 14, 265, 2599, 3, 266, 3, 266, 6, 266, 2604, 10, 266, 13, 266, 14, 266, 2605, 7, 266, 2608, 10, 266, 12, 266, 14, 266, 2611, 11, 266, 3, 267, 6, 267, 2614, 10, 267, 13, 267, 14, 267, 2615, 3, 267, 7, 267, 2619, 10, 267, 12, 267, 14, 267, 2622, 11, 267, 3, 268, 3, 268, 3, 268, 3, 269, 3, 269, 3, 269, 3, 269, 3, 269, 3, 269, 7, 269, 2633, 10, 269, 12, 269, 14, 269, 2636, 11, 269, 3, 269, 3, 269, 3, 270, 3, 270, 3, 270, 3, 270, 3, 270, 3, 270, 7, 270, 2646, 10, 270, 12, 270, 14, 270, 2649, 11, 270, 3, 270, 3, 270, 3, 271, 3, 271, 3, 271, 3, 271, 3, 271, 3, 271, 7, 271, 2659, 10, 271, 12, 271, 14, 271, 2662, 11, 271, 3, 271, 3, 271, 3, 272, 3, 272, 3, 273, 3, 273, 3, 273, 3, 273, 3, 2615, 2, 274, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 45, 89, 46, 91, 47, 93, 48, 95, 49, 97, 50, 99, 51, 101, 52, 103, 53, 105, 54, 107, 55, 109, 56, 111, 57, 113, 58, 115, 59, 117, 60, 119, 61, 121, 62, 123, 63, 125, 64, 127, 65, 129, 66, 131, 67, 133, 68, 135, 69, 137, 70, 139, 71, 141, 72, 143, 73, 145, 74, 147, 75, 149, 76, 151, 77, 153, 78, 155, 79, 157, 80, 159, 81, 161, 82, 163, 83, 165, 84, 167, 85, 169, 86, 171, 87, 173, 88, 175, 89, 177, 90, 179, 91, 181, 92, 183, 93, 185, 94, 187, 95, 189, 96, 191, 97, 193, 98, 195, 99, 197, 100, 199, 101, 201, 102, 203, 103, 205, 104, 207, 105, 209, 106, 211, 107, 213, 108, 215, 109, 217, 110, 219, 111, 221, 112, 223, 113, 225, 114, 227, 115, 229, 116, 231, 117, 233, 118, 235, 119, 237, 120, 239, 121, 241, 122, 243, 123, 245, 124, 247, 125, 249, 126, 251, 127, 253, 128, 255, 129, 257, 130, 259, 131, 261, 132, 263, 133, 265, 134, 267, 135, 269, 136, 271, 137, 273, 138, 275, 139, 277, 140, 279, 141, 281, 142, 283, 143, 285, 144, 287, 145, 289, 146, 291, 147, 293, 148, 295, 149, 297, 150, 299, 151, 301, 152, 303, 153, 305, 154, 307, 155, 309, 156, 311, 157, 313, 158, 315, 159, 317, 160, 319, 161, 321, 162, 323, 163, 325, 164, 327, 165, 329, 166, 331, 167, 333, 168, 335, 169, 337, 170, 339, 171, 341, 172, 343, 173, 345, 174, 347, 175, 349, 176, 351, 177, 353, 178, 355, 179, 357, 180, 359, 181, 361, 182, 363, 183, 365, 184, 367, 185, 369, 186, 371, 187, 373, 188, 375, 189, 377, 190, 379, 191, 381, 192, 383, 193, 385, 194, 387, 195, 389, 196, 391, 197, 393, 198, 395, 199, 397, 200, 399, 201, 401, 202, 403, 203, 405, 204, 407, 205, 409, 206, 411, 207, 413, 208, 415, 209, 417, 210, 419, 211, 421, 212, 423, 213, 425, 214, 427, 215, 429, 216, 431, 217, 433, 218, 435, 219, 437, 220, 439, 221, 441, 222, 443, 223, 445, 224, 447, 225, 449, 226, 451, 227, 453, 228, 455, 229, 457, 230, 459, 231, 461, 232, 463, 233, 465, 234, 467, 235, 469, 236, 471, 237, 473, 238, 475, 239, 477, 240, 479, 241, 481, 242, 483, 243, 485, 244, 487, 245, 489, 246, 491, 247, 493, 248, 495, 249, 497, 250, 499, 251, 501, 252, 503, 253, 505, 254, 507, 255, 509, 256, 511, 257, 513, 258, 515, 259, 517, 260, 519, 261, 521, 262, 523, 263, 525, 264, 527, 265, 529, 266, 531, 2, 533, 2, 535, 267, 537, 268, 539, 269, 541, 270, 543, 2, 545, 271, 3, 2, 10, 3, 2, 47, 48, 4, 2, 44, 44, 50, 59, 4, 2, 44, 44, 66, 92, 7, 2, 44, 44, 47, 47, 50, 59, 67, 92, 97, 97, 4, 2, 36, 36, 94, 94, 4, 2, 41, 41, 94, 94, 4, 2, 94, 94, 98, 98, 3, 2, 50, 59, 2, 2684, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 95, 3, 2, 2, 2, 2, 97, 3, 2, 2, 2, 2, 99, 3, 2, 2, 2, 2, 101, 3, 2, 2, 2, 2, 103, 3, 2, 2, 2, 2, 105, 3, 2, 2, 2, 2, 107, 3, 2, 2, 2, 2, 109, 3, 2, 2, 2, 2, 111, 3, 2, 2, 2, 2, 113, 3, 2, 2, 2, 2, 115, 3, 2, 2, 2, 2, 117, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2, 2, 121, 3, 2, 2, 2, 2, 123, 3, 2, 2, 2, 2, 125, 3, 2, 2, 2, 2, 127, 3, 2, 2, 2, 2, 129, 3, 2, 2, 2, 2, 131, 3, 2, 2, 2, 2, 133, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 2, 141, 3, 2, 2, 2, 2, 143, 3, 2, 2, 2, 2, 145, 3, 2, 2, 2, 2, 147, 3, 2, 2, 2, 2, 149, 3, 2, 2, 2, 2, 151, 3, 2, 2, 2, 2, 153, 3, 2, 2, 2, 2, 155, 3, 2, 2, 2, 2, 157, 3, 2, 2, 2, 2, 159, 3, 2, 2, 2, 2, 161, 3, 2, 2, 2, 2, 163, 3, 2, 2, 2, 2, 165, 3, 2, 2, 2, 2, 167, 3, 2, 2, 2, 2, 169, 3, 2, 2, 2, 2, 171, 3, 2, 2, 2, 2, 173, 3, 2, 2, 2, 2, 175, 3, 2, 2, 2, 2, 177, 3, 2, 2, 2, 2, 179, 3, 2, 2, 2, 2, 181, 3, 2, 2, 2, 2, 183, 3, 2, 2, 2, 2, 185, 3, 2, 2, 2, 2, 187, 3, 2, 2, 2, 2, 189, 3, 2, 2, 2, 2, 191, 3, 2, 2, 2, 2, 193, 3, 2, 2, 2, 2, 195, 3, 2, 2, 2, 2, 197, 3, 2, 2, 2, 2, 199, 3, 2, 2, 2, 2, 201, 3, 2, 2, 2, 2, 203, 3, 2, 2, 2, 2, 205, 3, 2, 2, 2, 2, 207, 3, 2, 2, 2, 2, 209, 3, 2, 2, 2, 2, 211, 3, 2, 2, 2, 2, 213, 3, 2, 2, 2, 2, 215, 3, 2, 2, 2, 2, 217, 3, 2, 2, 2, 2, 219, 3, 2, 2, 2, 2, 221, 3, 2, 2, 2, 2, 223, 3, 2, 2, 2, 2, 225, 3, 2, 2, 2, 2, 227, 3, 2, 2, 2, 2, 229, 3, 2, 2, 2, 2, 231, 3, 2, 2, 2, 2, 233, 3, 2, 2, 2, 2, 235, 3, 2, 2, 2, 2, 237, 3, 2, 2, 2, 2, 239, 3, 2, 2, 2, 2, 241, 3, 2, 2, 2, 2, 243, 3, 2, 2, 2, 2, 245, 3, 2, 2, 2, 2, 247, 3, 2, 2, 2, 2, 249, 3, 2, 2, 2, 2, 251, 3, 2, 2, 2, 2, 253, 3, 2, 2, 2, 2, 255, 3, 2, 2, 2, 2, 257, 3, 2, 2, 2, 2, 259, 3, 2, 2, 2, 2, 261, 3, 2, 2, 2, 2, 263, 3, 2, 2, 2, 2, 265, 3, 2, 2, 2, 2, 267, 3, 2, 2, 2, 2, 269, 3, 2, 2, 2, 2, 271, 3, 2, 2, 2, 2, 273, 3, 2, 2, 2, 2, 275, 3, 2, 2, 2, 2, 277, 3, 2, 2, 2, 2, 279, 3, 2, 2, 2, 2, 281, 3, 2, 2, 2, 2, 283, 3, 2, 2, 2, 2, 285, 3, 2, 2, 2, 2, 287, 3, 2, 2, 2, 2, 289, 3, 2, 2, 2, 2, 291, 3, 2, 2, 2, 2, 293, 3, 2, 2, 2, 2, 295, 3, 2, 2, 2, 2, 297, 3, 2, 2, 2, 2, 299, 3, 2, 2, 2, 2, 301, 3, 2, 2, 2, 2, 303, 3, 2, 2, 2, 2, 305, 3, 2, 2, 2, 2, 307, 3, 2, 2, 2, 2, 309, 3, 2, 2, 2, 2, 311, 3, 2, 2, 2, 2, 313, 3, 2, 2, 2, 2, 315, 3, 2, 2, 2, 2, 317, 3, 2, 2, 2, 2, 319, 3, 2, 2, 2, 2, 321, 3, 2, 2, 2, 2, 323, 3, 2, 2, 2, 2, 325, 3, 2, 2, 2, 2, 327, 3, 2, 2, 2, 2, 329, 3, 2, 2, 2, 2, 331, 3, 2, 2, 2, 2, 333, 3, 2, 2, 2, 2, 335, 3, 2, 2, 2, 2, 337, 3, 2, 2, 2, 2, 339, 3, 2, 2, 2, 2, 341, 3, 2, 2, 2, 2, 343, 3, 2, 2, 2, 2, 345, 3, 2, 2, 2, 2, 347, 3, 2, 2, 2, 2, 349, 3, 2, 2, 2, 2, 351, 3, 2, 2, 2, 2, 353, 3, 2, 2, 2, 2, 355, 3, 2, 2, 2, 2, 357, 3, 2, 2, 2, 2, 359, 3, 2, 2, 2, 2, 361, 3, 2, 2, 2, 2, 363, 3, 2, 2, 2, 2, 365, 3, 2, 2, 2, 2, 367, 3, 2, 2, 2, 2, 369, 3, 2, 2, 2, 2, 371, 3, 2, 2, 2, 2, 373, 3, 2, 2, 2, 2, 375, 3, 2, 2, 2, 2, 377, 3, 2, 2, 2, 2, 379, 3, 2, 2, 2, 2, 381, 3, 2, 2, 2, 2, 383, 3, 2, 2, 2, 2, 385, 3, 2, 2, 2, 2, 387, 3, 2, 2, 2, 2, 389, 3, 2, 2, 2, 2, 391, 3, 2, 2, 2, 2, 393, 3, 2, 2, 2, 2, 395, 3, 2, 2, 2, 2, 397, 3, 2, 2, 2, 2, 399, 3, 2, 2, 2, 2, 401, 3, 2, 2, 2, 2, 403, 3, 2, 2, 2, 2, 405, 3, 2, 2, 2, 2, 407, 3, 2, 2, 2, 2, 409, 3, 2, 2, 2, 2, 411, 3, 2, 2, 2, 2, 413, 3, 2, 2, 2, 2, 415, 3, 2, 2, 2, 2, 417, 3, 2, 2, 2, 2, 419, 3, 2, 2, 2, 2, 421, 3, 2, 2, 2, 2, 423, 3, 2, 2, 2, 2, 425, 3, 2, 2, 2, 2, 427, 3, 2, 2, 2, 2, 429, 3, 2, 2, 2, 2, 431, 3, 2, 2, 2, 2, 433, 3, 2, 2, 2, 2, 435, 3, 2, 2, 2, 2, 437, 3, 2, 2, 2, 2, 439, 3, 2, 2, 2, 2, 441, 3, 2, 2, 2, 2, 443, 3, 2, 2, 2, 2, 445, 3, 2, 2, 2, 2, 447, 3, 2, 2, 2, 2, 449, 3, 2, 2, 2, 2, 451, 3, 2, 2, 2, 2, 453, 3, 2, 2, 2, 2, 455, 3, 2, 2, 2, 2, 457, 3, 2, 2, 2, 2, 459, 3, 2, 2, 2, 2, 461, 3, 2, 2, 2, 2, 463, 3, 2, 2, 2, 2, 465, 3, 2, 2, 2, 2, 467, 3, 2, 2, 2, 2, 469, 3, 2, 2, 2, 2, 471, 3, 2, 2, 2, 2, 473, 3, 2, 2, 2, 2, 475, 3, 2, 2, 2, 2, 477, 3, 2, 2, 2, 2, 479, 3, 2, 2, 2, 2, 481, 3, 2, 2, 2, 2, 483, 3, 2, 2, 2, 2, 485, 3, 2, 2, 2, 2, 487, 3, 2, 2, 2, 2, 489, 3, 2, 2, 2, 2, 491, 3, 2, 2, 2, 2, 493, 3, 2, 2, 2, 2, 495, 3, 2, 2, 2, 2, 497, 3, 2, 2, 2, 2, 499, 3, 2, 2, 2, 2, 501, 3, 2, 2, 2, 2, 503, 3, 2, 2, 2, 2, 505, 3, 2, 2, 2, 2, 507, 3, 2, 2, 2, 2, 509, 3, 2, 2, 2, 2, 511, 3, 2, 2, 2, 2, 513, 3, 2, 2, 2, 2, 515, 3, 2, 2, 2, 2, 517, 3, 2, 2, 2, 2, 519, 3, 2, 2, 2, 2, 521, 3, 2, 2, 2, 2, 523, 3, 2, 2, 2, 2, 525, 3, 2, 2, 2, 2, 527, 3, 2, 2, 2, 2, 529, 3, 2, 2, 2, 2, 535, 3, 2, 2, 2, 2, 537, 3, 2, 2, 2, 2, 539, 3, 2, 2, 2, 2, 541, 3, 2, 2, 2, 2, 545, 3, 2, 2, 2, 3, 547, 3, 2, 2, 2, 5, 554, 3, 2, 2, 2, 7, 559, 3, 2, 2, 2, 9, 565, 3, 2, 2, 2, 11, 572, 3, 2, 2, 2, 13, 579, 3, 2, 2, 2, 15, 585, 3, 2, 2, 2, 17, 591, 3, 2, 2, 2, 19, 596, 3, 2, 2, 2, 21, 601, 3, 2, 2, 2, 23, 606, 3, 2, 2, 2, 25, 610, 3, 2, 2, 2, 27, 615, 3, 2, 2, 2, 29, 621, 3, 2, 2, 2, 31, 628, 3, 2, 2, 2, 33, 631, 3, 2, 2, 2, 35, 634, 3, 2, 2, 2, 37, 637, 3, 2, 2, 2, 39, 644, 3, 2, 2, 2, 41, 650, 3, 2, 2, 2, 43, 652, 3, 2, 2, 2, 45, 657, 3, 2, 2, 2, 47, 664, 3, 2, 2, 2, 49, 669, 3, 2, 2, 2, 51, 673, 3, 2, 2, 2, 53, 676, 3, 2, 2, 2, 55, 680, 3, 2, 2, 2, 57, 690, 3, 2, 2, 2, 59, 702, 3, 2, 2, 2, 61, 720, 3, 2, 2, 2, 63, 731, 3, 2, 2, 2, 65, 738, 3, 2, 2, 2, 67, 744, 3, 2, 2, 2, 69, 754, 3, 2, 2, 2, 71, 765, 3, 2, 2, 2, 73, 779, 3, 2, 2, 2, 75, 795, 3, 2, 2, 2, 77, 808, 3, 2, 2, 2, 79, 820, 3, 2, 2, 2, 81, 833, 3, 2, 2, 2, 83, 844, 3, 2, 2, 2, 85, 857, 3, 2, 2, 2, 87, 868, 3, 2, 2, 2, 89, 878, 3, 2, 2, 2, 91, 897, 3, 2, 2, 2, 93, 921, 3, 2, 2, 2, 95, 926, 3, 2, 2, 2, 97, 929, 3, 2, 2, 2, 99, 933, 3, 2, 2, 2, 101, 936, 3, 2, 2, 2, 103, 940, 3, 2, 2, 2, 105, 944, 3, 2, 2, 2, 107, 949, 3, 2, 2, 2, 109, 955, 3, 2, 2, 2, 111, 962, 3, 2, 2, 2, 113, 971, 3, 2, 2, 2, 115, 980, 3, 2, 2, 2, 117, 992, 3, 2, 2, 2, 119, 1004, 3, 2, 2, 2, 121, 1011, 3, 2, 2, 2, 123, 1018, 3, 2, 2, 2, 125, 1023, 3, 2, 2, 2, 127, 1027, 3, 2, 2, 2, 129, 1032, 3, 2, 2, 2, 131, 1038, 3, 2, 2, 2, 133, 1046, 3, 2, 2, 2, 135, 1051, 3, 2, 2, 2, 137, 1070, 3, 2, 2, 2, 139, 1089, 3, 2, 2, 2, 141, 1103, 3, 2, 2, 2, 143, 1120, 3, 2, 2, 2, 145, 1132, 3, 2, 2, 2, 147, 1144, 3, 2, 2, 2, 149, 1160, 3, 2, 2, 2, 151, 1171, 3, 2, 2, 2, 153, 1182, 3, 2, 2, 2, 155, 1191, 3, 2, 2, 2, 157, 1202, 3, 2, 2, 2, 159, 1212, 3, 2, 2, 2, 161, 1219, 3, 2, 2, 2, 163, 1231, 3, 2, 2, 2, 165, 1235, 3, 2, 2, 2, 167, 1243, 3, 2, 2, 2, 169, 1250, 3, 2, 2, 2, 171, 1255, 3, 2, 2, 2, 173, 1261, 3, 2, 2, 2, 175, 1268, 3, 2, 2, 2, 177, 1276, 3, 2, 2, 2, 179, 1278, 3, 2, 2, 2, 181, 1280, 3, 2, 2, 2, 183, 1282, 3, 2, 2, 2, 185, 1284, 3, 2, 2, 2, 187, 1286, 3, 2, 2, 2, 189, 1288, 3, 2, 2, 2, 191, 1291, 3, 2, 2, 2, 193, 1294, 3, 2, 2, 2, 195, 1297, 3, 2, 2, 2, 197, 1299, 3, 2, 2, 2, 199, 1301, 3, 2, 2, 2, 201, 1303, 3, 2, 2, 2, 203, 1305, 3, 2, 2, 2, 205, 1307, 3, 2, 2, 2, 207, 1309, 3, 2, 2, 2, 209, 1311, 3, 2, 2, 2, 211, 1313, 3, 2, 2, 2, 213, 1315, 3, 2, 2, 2, 215, 1317, 3, 2, 2, 2, 217, 1319, 3, 2, 2, 2, 219, 1321, 3, 2, 2, 2, 221, 1323, 3, 2, 2, 2, 223, 1325, 3, 2, 2, 2, 225, 1327, 3, 2, 2, 2, 227, 1329, 3, 2, 2, 2, 229, 1331, 3, 2, 2, 2, 231, 1335, 3, 2, 2, 2, 233, 1341, 3, 2, 2, 2, 235, 1356, 3, 2, 2, 2, 237, 1362, 3, 2, 2, 2, 239, 1374, 3, 2, 2, 2, 241, 1378, 3, 2, 2, 2, 243, 1383, 3, 2, 2, 2, 245, 1390, 3, 2, 2, 2, 247, 1394, 3, 2, 2, 2, 249, 1399, 3, 2, 2, 2, 251, 1405, 3, 2, 2, 2, 253, 1411, 3, 2, 2, 2, 255, 1418, 3, 2, 2, 2, 257, 1422, 3, 2, 2, 2, 259, 1428, 3, 2, 2, 2, 261, 1437, 3, 2, 2, 2, 263, 1445, 3, 2, 2, 2, 265, 1457, 3, 2, 2, 2, 267, 1468, 3, 2, 2, 2, 269, 1479, 3, 2, 2, 2, 271, 1485, 3, 2, 2, 2, 273, 1490, 3, 2, 2, 2, 275, 1495, 3, 2, 2, 2, 277, 1502, 3, 2, 2, 2, 279, 1511, 3, 2, 2, 2, 281, 1525, 3, 2, 2, 2, 283, 1532, 3, 2, 2, 2, 285, 1544, 3, 2, 2, 2, 287, 1552, 3, 2, 2, 2, 289, 1561, 3, 2, 2, 2, 291, 1572, 3, 2, 2, 2, 293, 1583, 3, 2, 2, 2, 295, 1588, 3, 2, 2, 2, 297, 1598, 3, 2, 2, 2, 299, 1600, 3, 2, 2, 2, 301, 1603, 3, 2, 2, 2, 303, 1607, 3, 2, 2, 2, 305, 1612, 3, 2, 2, 2, 307, 1620, 3, 2, 2, 2, 309, 1625, 3, 2, 2, 2, 311, 1631, 3, 2, 2, 2, 313, 1633, 3, 2, 2, 2, 315, 1637, 3, 2, 2, 2, 317, 1643, 3, 2, 2, 2, 319, 1646, 3, 2, 2, 2, 321, 1650, 3, 2, 2, 2, 323, 1656, 3, 2, 2, 2, 325, 1661, 3, 2, 2, 2, 327, 1665, 3, 2, 2, 2, 329, 1668, 3, 2, 2, 2, 331, 1672, 3, 2, 2, 2, 333, 1678, 3, 2, 2, 2, 335, 1683, 3, 2, 2, 2, 337, 1689, 3, 2, 2, 2, 339, 1694, 3, 2, 2, 2, 341, 1699, 3, 2, 2, 2, 343, 1708, 3, 2, 2, 2, 345, 1713, 3, 2, 2, 2, 347, 1718, 3, 2, 2, 2, 349, 1723, 3, 2, 2, 2, 351, 1729, 3, 2, 2, 2, 353, 1733, 3, 2, 2, 2, 355, 1737, 3, 2, 2, 2, 357, 1745, 3, 2, 2, 2, 359, 1753, 3, 2, 2, 2, 361, 1757, 3, 2, 2, 2, 363, 1761, 3, 2, 2, 2, 365, 1769, 3, 2, 2, 2, 367, 1774, 3, 2, 2, 2, 369, 1783, 3, 2, 2, 2, 371, 1792, 3, 2, 2, 2, 373, 1803, 3, 2, 2, 2, 375, 1813, 3, 2, 2, 2, 377, 1823, 3, 2, 2, 2, 379, 1831, 3, 2, 2, 2, 381, 1841, 3, 2, 2, 2, 383, 1851, 3, 2, 2, 2, 385, 1859, 3, 2, 2, 2, 387, 1864, 3, 2, 2, 2, 389, 1876, 3, 2, 2, 2, 391, 1886, 3, 2, 2, 2, 393, 1898, 3, 2, 2, 2, 395, 1906, 3, 2, 2, 2, 397, 1913, 3, 2, 2, 2, 399, 1923, 3, 2, 2, 2, 401, 1929, 3, 2, 2, 2, 403, 1935, 3, 2, 2, 2, 405, 1940, 3, 2, 2, 2, 407, 1943, 3, 2, 2, 2, 409, 1949, 3, 2, 2, 2, 411, 1955, 3, 2, 2, 2, 413, 1962, 3, 2, 2, 2, 415, 1972, 3, 2, 2, 2, 417, 1979, 3, 2, 2, 2, 419, 1986, 3, 2, 2, 2, 421, 1992, 3, 2, 2, 2, 423, 1997, 3, 2, 2, 2, 425, 2003, 3, 2, 2, 2, 427, 2010, 3, 2, 2, 2, 429, 2018, 3, 2, 2, 2, 431, 2023, 3, 2, 2, 2, 433, 2028, 3, 2, 2, 2, 435, 2035, 3, 2, 2, 2, 437, 2045, 3, 2, 2, 2, 439, 2052, 3, 2, 2, 2, 441, 2059, 3, 2, 2, 2, 443, 2062, 3, 2, 2, 2, 445, 2068, 3, 2, 2, 2, 447, 2081, 3, 2, 2, 2, 449, 2101, 3, 2, 2, 2, 451, 2124, 3, 2, 2, 2, 453, 2141, 3, 2, 2, 2, 455, 2150, 3, 2, 2, 2, 457, 2186, 3, 2, 2, 2, 459, 2192, 3, 2, 2, 2, 461, 2209, 3, 2, 2, 2, 463, 2223, 3, 2, 2, 2, 465, 2240, 3, 2, 2, 2, 467, 2267, 3, 2, 2, 2, 469, 2273, 3, 2, 2, 2, 471, 2294, 3, 2, 2, 2, 473, 2314, 3, 2, 2, 2, 475, 2335, 3, 2, 2, 2, 477, 2349, 3, 2, 2, 2, 479, 2359, 3, 2, 2, 2, 481, 2367, 3, 2, 2, 2, 483, 2385, 3, 2, 2, 2, 485, 2409, 3, 2, 2, 2, 487, 2424, 3, 2, 2, 2, 489, 2445, 3, 2, 2, 2, 491, 2454, 3, 2, 2, 2, 493, 2466, 3, 2, 2, 2, 495, 2480, 3, 2, 2, 2, 497, 2495, 3, 2, 2, 2, 499, 2514, 3, 2, 2, 2, 501, 2522, 3, 2, 2, 2, 503, 2527, 3, 2, 2, 2, 505, 2539, 3, 2, 2, 2, 507, 2544, 3, 2, 2, 2, 509, 2561, 3, 2, 2, 2, 511, 2566, 3, 2, 2, 2, 513, 2569, 3, 2, 2, 2, 515, 2571, 3, 2, 2, 2, 517, 2573, 3, 2, 2, 2, 519, 2575, 3, 2, 2, 2, 521, 2577, 3, 2, 2, 2, 523, 2579, 3, 2, 2, 2, 525, 2581, 3, 2, 2, 2, 527, 2584, 3, 2, 2, 2, 529, 2593, 3, 2, 2, 2, 531, 2609, 3, 2, 2, 2, 533, 2613, 3, 2, 2, 2, 535, 2623, 3, 2, 2, 2, 537, 2626, 3, 2, 2, 2, 539, 2639, 3, 2, 2, 2, 541, 2652, 3, 2, 2, 2, 543, 2665, 3, 2, 2, 2, 545, 2667, 3, 2, 2, 2, 547, 548, 7, 85, 2, 2, 548, 549, 7, 71, 2, 2, 549, 550, 7, 67, 2, 2, 550, 551, 7, 84, 2, 2, 551, 552, 7, 69, 2, 2, 552, 553, 7, 74, 2, 2, 553, 4, 3, 2, 2, 2, 554, 555, 7, 72, 2, 2, 555, 556, 7, 84, 2, 2, 556, 557, 7, 81, 2, 2, 557, 558, 7, 79, 2, 2, 558, 6, 3, 2, 2, 2, 559, 560, 7, 89, 2, 2, 560, 561, 7, 74, 2, 2, 561, 562, 7, 71, 2, 2, 562, 563, 7, 84, 2, 2, 563, 564, 7, 71, 2, 2, 564, 8, 3, 2, 2, 2, 565, 566, 7, 72, 2, 2, 566, 567, 7, 75, 2, 2, 567, 568, 7, 71, 2, 2, 568, 569, 7, 78, 2, 2, 569, 570, 7, 70, 2, 2, 570, 571, 7, 85, 2, 2, 571, 10, 3, 2, 2, 2, 572, 573, 7, 84, 2, 2, 573, 574, 7, 71, 2, 2, 574, 575, 7, 80, 2, 2, 575, 576, 7, 67, 2, 2, 576, 577, 7, 79, 2, 2, 577, 578, 7, 71, 2, 2, 578, 12, 3, 2, 2, 2, 579, 580, 7, 85, 2, 2, 580, 581, 7, 86, 2, 2, 581, 582, 7, 67, 2, 2, 582, 583, 7, 86, 2, 2, 583, 584, 7, 85, 2, 2, 584, 14, 3, 2, 2, 2, 585, 586, 7, 70, 2, 2, 586, 587, 7, 71, 2, 2, 587, 588, 7, 70, 2, 2, 588, 589, 7, 87, 2, 2, 589, 590, 7, 82, 2, 2, 590, 16, 3, 2, 2, 2, 591, 592, 7, 85, 2, 2, 592, 593, 7, 81, 2, 2, 593, 594, 7, 84, 2, 2, 594, 595, 7, 86, 2, 2, 595, 18, 3, 2, 2, 2, 596, 597, 7, 71, 2, 2, 597, 598, 7, 88, 2, 2, 598, 599, 7, 67, 2, 2, 599, 600, 7, 78, 2, 2, 600, 20, 3, 2, 2, 2, 601, 602, 7, 74, 2, 2, 602, 603, 7, 71, 2, 2, 603, 604, 7, 67, 2, 2, 604, 605, 7, 70, 2, 2, 605, 22, 3, 2, 2, 2, 606, 607, 7, 86, 2, 2, 607, 608, 7, 81, 2, 2, 608, 609, 7, 82, 2, 2, 609, 24, 3, 2, 2, 2, 610, 611, 7, 84, 2, 2, 611, 612, 7, 67, 2, 2, 612, 613, 7, 84, 2, 2, 613, 614, 7, 71, 2, 2, 614, 26, 3, 2, 2, 2, 615, 616, 7, 82, 2, 2, 616, 617, 7, 67, 2, 2, 617, 618, 7, 84, 2, 2, 618, 619, 7, 85, 2, 2, 619, 620, 7, 71, 2, 2, 620, 28, 3, 2, 2, 2, 621, 622, 7, 77, 2, 2, 622, 623, 7, 79, 2, 2, 623, 624, 7, 71, 2, 2, 624, 625, 7, 67, 2, 2, 625, 626, 7, 80, 2, 2, 626, 627, 7, 85, 2, 2, 627, 30, 3, 2, 2, 2, 628, 629, 7, 67, 2, 2, 629, 630, 7, 70, 2, 2, 630, 32, 3, 2, 2, 2, 631, 632, 7, 67, 2, 2, 632, 633, 7, 85, 2, 2, 633, 34, 3, 2, 2, 2, 634, 635, 7, 68, 2, 2, 635, 636, 7, 91, 2, 2, 636, 36, 3, 2, 2, 2, 637, 638, 7, 85, 2, 2, 638, 639, 7, 81, 2, 2, 639, 640, 7, 87, 2, 2, 640, 641, 7, 84, 2, 2, 641, 642, 7, 69, 2, 2, 642, 643, 7, 71, 2, 2, 643, 38, 3, 2, 2, 2, 644, 645, 7, 75, 2, 2, 645, 646, 7, 80, 2, 2, 646, 647, 7, 70, 2, 2, 647, 648, 7, 71, 2, 2, 648, 649, 7, 90, 2, 2, 649, 40, 3, 2, 2, 2, 650, 651, 7, 70, 2, 2, 651, 42, 3, 2, 2, 2, 652, 653, 7, 70, 2, 2, 653, 654, 7, 71, 2, 2, 654, 655, 7, 85, 2, 2, 655, 656, 7, 69, 2, 2, 656, 44, 3, 2, 2, 2, 657, 658, 7, 85, 2, 2, 658, 659, 7, 81, 2, 2, 659, 660, 7, 84, 2, 2, 660, 661, 7, 86, 2, 2, 661, 662, 7, 68, 2, 2, 662, 663, 7, 91, 2, 2, 663, 46, 3, 2, 2, 2, 664, 665, 7, 67, 2, 2, 665, 666, 7, 87, 2, 2, 666, 667, 7, 86, 2, 2, 667, 668, 7, 81, 2, 2, 668, 48, 3, 2, 2, 2, 669, 670, 7, 85, 2, 2, 670, 671, 7, 86, 2, 2, 671, 672, 7, 84, 2, 2, 672, 50, 3, 2, 2, 2, 673, 674, 7, 75, 2, 2, 674, 675, 7, 82, 2, 2, 675, 52, 3, 2, 2, 2, 676, 677, 7, 80, 2, 2, 677, 678, 7, 87, 2, 2, 678, 679, 7, 79, 2, 2, 679, 54, 3, 2, 2, 2, 680, 681, 7, 77, 2, 2, 681, 682, 7, 71, 2, 2, 682, 683, 7, 71, 2, 2, 683, 684, 7, 82, 2, 2, 684, 685, 7, 71, 2, 2, 685, 686, 7, 79, 2, 2, 686, 687, 7, 82, 2, 2, 687, 688, 7, 86, 2, 2, 688, 689, 7, 91, 2, 2, 689, 56, 3, 2, 2, 2, 690, 691, 7, 69, 2, 2, 691, 692, 7, 81, 2, 2, 692, 693, 7, 80, 2, 2, 693, 694, 7, 85, 2, 2, 694, 695, 7, 71, 2, 2, 695, 696, 7, 69, 2, 2, 696, 697, 7, 87, 2, 2, 697, 698, 7, 86, 2, 2, 698, 699, 7, 75, 2, 2, 699, 700, 7, 88, 2, 2, 700, 701, 7, 71, 2, 2, 701, 58, 3, 2, 2, 2, 702, 703, 7, 70, 2, 2, 703, 704, 7, 71, 2, 2, 704, 705, 7, 70, 2, 2, 705, 706, 7, 87, 2, 2, 706, 707, 7, 82, 2, 2, 707, 708, 7, 97, 2, 2, 708, 709, 7, 85, 2, 2, 709, 710, 7, 82, 2, 2, 710, 711, 7, 78, 2, 2, 711, 712, 7, 75, 2, 2, 712, 713, 7, 86, 2, 2, 713, 714, 7, 88, 2, 2, 714, 715, 7, 67, 2, 2, 715, 716, 7, 78, 2, 2, 716, 717, 7, 87, 2, 2, 717, 718, 7, 71, 2, 2, 718, 719, 7, 85, 2, 2, 719, 60, 3, 2, 2, 2, 720, 721, 7, 82, 2, 2, 721, 722, 7, 67, 2, 2, 722, 723, 7, 84, 2, 2, 723, 724, 7, 86, 2, 2, 724, 725, 7, 75, 2, 2, 725, 726, 7, 86, 2, 2, 726, 727, 7, 75, 2, 2, 727, 728, 7, 81, 2, 2, 728, 729, 7, 80, 2, 2, 729, 730, 7, 85, 2, 2, 730, 62, 3, 2, 2, 2, 731, 732, 7, 67, 2, 2, 732, 733, 7, 78, 2, 2, 733, 734, 7, 78, 2, 2, 734, 735, 7, 80, 2, 2, 735, 736, 7, 87, 2, 2, 736, 737, 7, 79, 2, 2, 737, 64, 3, 2, 2, 2, 738, 739, 7, 70, 2, 2, 739, 740, 7, 71, 2, 2, 740, 741, 7, 78, 2, 2, 741, 742, 7, 75, 2, 2, 742, 743, 7, 79, 2, 2, 743, 66, 3, 2, 2, 2, 744, 745, 7, 69, 2, 2, 745, 746, 7, 71, 2, 2, 746, 747, 7, 80, 2, 2, 747, 748, 7, 86, 2, 2, 748, 749, 7, 84, 2, 2, 749, 750, 7, 81, 2, 2, 750, 751, 7, 75, 2, 2, 751, 752, 7, 70, 2, 2, 752, 753, 7, 85, 2, 2, 753, 68, 3, 2, 2, 2, 754, 755, 7, 75, 2, 2, 755, 756, 7, 86, 2, 2, 756, 757, 7, 71, 2, 2, 757, 758, 7, 84, 2, 2, 758, 759, 7, 67, 2, 2, 759, 760, 7, 86, 2, 2, 760, 761, 7, 75, 2, 2, 761, 762, 7, 81, 2, 2, 762, 763, 7, 80, 2, 2, 763, 764, 7, 85, 2, 2, 764, 70, 3, 2, 2, 2, 765, 766, 7, 70, 2, 2, 766, 767, 7, 75, 2, 2, 767, 768, 7, 85, 2, 2, 768, 769, 7, 86, 2, 2, 769, 770, 7, 67, 2, 2, 770, 771, 7, 80, 2, 2, 771, 772, 7, 69, 2, 2, 772, 773, 7, 71, 2, 2, 773, 774, 7, 97, 2, 2, 774, 775, 7, 86, 2, 2, 775, 776, 7, 91, 2, 2, 776, 777, 7, 82, 2, 2, 777, 778, 7, 71, 2, 2, 778, 72, 3, 2, 2, 2, 779, 780, 7, 80, 2, 2, 780, 781, 7, 87, 2, 2, 781, 782, 7, 79, 2, 2, 782, 783, 7, 68, 2, 2, 783, 784, 7, 71, 2, 2, 784, 785, 7, 84, 2, 2, 785, 786, 7, 97, 2, 2, 786, 787, 7, 81, 2, 2, 787, 788, 7, 72, 2, 2, 788, 789, 7, 97, 2, 2, 789, 790, 7, 86, 2, 2, 790, 791, 7, 84, 2, 2, 791, 792, 7, 71, 2, 2, 792, 793, 7, 71, 2, 2, 793, 794, 7, 85, 2, 2, 794, 74, 3, 2, 2, 2, 795, 796, 7, 85, 2, 2, 796, 797, 7, 74, 2, 2, 797, 798, 7, 75, 2, 2, 798, 799, 7, 80, 2, 2, 799, 800, 7, 73, 2, 2, 800, 801, 7, 78, 2, 2, 801, 802, 7, 71, 2, 2, 802, 803, 7, 97, 2, 2, 803, 804, 7, 85, 2, 2, 804, 805, 7, 75, 2, 2, 805, 806, 7, 92, 2, 2, 806, 807, 7, 71, 2, 2, 807, 76, 3, 2, 2, 2, 808, 809, 7, 85, 2, 2, 809, 810, 7, 67, 2, 2, 810, 811, 7, 79, 2, 2, 811, 812, 7, 82, 2, 2, 812, 813, 7, 78, 2, 2, 813, 814, 7, 71, 2, 2, 814, 815, 7, 97, 2, 2, 815, 816, 7, 85, 2, 2, 816, 817, 7, 75, 2, 2, 817, 818, 7, 92, 2, 2, 818, 819, 7, 71, 2, 2, 819, 78, 3, 2, 2, 2, 820, 821, 7, 81, 2, 2, 821, 822, 7, 87, 2, 2, 822, 823, 7, 86, 2, 2, 823, 824, 7, 82, 2, 2, 824, 825, 7, 87, 2, 2, 825, 826, 7, 86, 2, 2, 826, 827, 7, 97, 2, 2, 827, 828, 7, 67, 2, 2, 828, 829, 7, 72, 2, 2, 829, 830, 7, 86, 2, 2, 830, 831, 7, 71, 2, 2, 831, 832, 7, 84, 2, 2, 832, 80, 3, 2, 2, 2, 833, 834, 7, 86, 2, 2, 834, 835, 7, 75, 2, 2, 835, 836, 7, 79, 2, 2, 836, 837, 7, 71, 2, 2, 837, 838, 7, 97, 2, 2, 838, 839, 7, 70, 2, 2, 839, 840, 7, 71, 2, 2, 840, 841, 7, 69, 2, 2, 841, 842, 7, 67, 2, 2, 842, 843, 7, 91, 2, 2, 843, 82, 3, 2, 2, 2, 844, 845, 7, 67, 2, 2, 845, 846, 7, 80, 2, 2, 846, 847, 7, 81, 2, 2, 847, 848, 7, 79, 2, 2, 848, 849, 7, 67, 2, 2, 849, 850, 7, 78, 2, 2, 850, 851, 7, 91, 2, 2, 851, 852, 7, 97, 2, 2, 852, 853, 7, 84, 2, 2, 853, 854, 7, 67, 2, 2, 854, 855, 7, 86, 2, 2, 855, 856, 7, 71, 2, 2, 856, 84, 3, 2, 2, 2, 857, 858, 7, 86, 2, 2, 858, 859, 7, 75, 2, 2, 859, 860, 7, 79, 2, 2, 860, 861, 7, 71, 2, 2, 861, 862, 7, 97, 2, 2, 862, 863, 7, 72, 2, 2, 863, 864, 7, 75, 2, 2, 864, 865, 7, 71, 2, 2, 865, 866, 7, 78, 2, 2, 866, 867, 7, 70, 2, 2, 867, 86, 3, 2, 2, 2, 868, 869, 7, 86, 2, 2, 869, 870, 7, 75, 2, 2, 870, 871, 7, 79, 2, 2, 871, 872, 7, 71, 2, 2, 872, 873, 7, 97, 2, 2, 873, 874, 7, 92, 2, 2, 874, 875, 7, 81, 2, 2, 875, 876, 7, 80, 2, 2, 876, 877, 7, 71, 2, 2, 877, 88, 3, 2, 2, 2, 878, 879, 7, 86, 2, 2, 879, 880, 7, 84, 2, 2, 880, 881, 7, 67, 2, 2, 881, 882, 7, 75, 2, 2, 882, 883, 7, 80, 2, 2, 883, 884, 7, 75, 2, 2, 884, 885, 7, 80, 2, 2, 885, 886, 7, 73, 2, 2, 886, 887, 7, 97, 2, 2, 887, 888, 7, 70, 2, 2, 888, 889, 7, 67, 2, 2, 889, 890, 7, 86, 2, 2, 890, 891, 7, 67, 2, 2, 891, 892, 7, 97, 2, 2, 892, 893, 7, 85, 2, 2, 893, 894, 7, 75, 2, 2, 894, 895, 7, 92, 2, 2, 895, 896, 7, 71, 2, 2, 896, 90, 3, 2, 2, 2, 897, 898, 7, 67, 2, 2, 898, 899, 7, 80, 2, 2, 899, 900, 7, 81, 2, 2, 900, 901, 7, 79, 2, 2, 901, 902, 7, 67, 2, 2, 902, 903, 7, 78, 2, 2, 903, 904, 7, 91, 2, 2, 904, 905, 7, 97, 2, 2, 905, 906, 7, 85, 2, 2, 906, 907, 7, 69, 2, 2, 907, 908, 7, 81, 2, 2, 908, 909, 7, 84, 2, 2, 909, 910, 7, 71, 2, 2, 910, 911, 7, 97, 2, 2, 911, 912, 7, 86, 2, 2, 912, 913, 7, 74, 2, 2, 913, 914, 7, 84, 2, 2, 914, 915, 7, 71, 2, 2, 915, 916, 7, 85, 2, 2, 916, 917, 7, 74, 2, 2, 917, 918, 7, 81, 2, 2, 918, 919, 7, 78, 2, 2, 919, 920, 7, 70, 2, 2, 920, 92, 3, 2, 2, 2, 921, 922, 7, 69, 2, 2, 922, 923, 7, 67, 2, 2, 923, 924, 7, 85, 2, 2, 924, 925, 7, 71, 2, 2, 925, 94, 3, 2, 2, 2, 926, 927, 7, 75, 2, 2, 927, 928, 7, 80, 2, 2, 928, 96, 3, 2, 2, 2, 929, 930, 7, 80, 2, 2, 930, 931, 7, 81, 2, 2, 931, 932, 7, 86, 2, 2, 932, 98, 3, 2, 2, 2, 933, 934, 7, 81, 2, 2, 934, 935, 7, 84, 2, 2, 935, 100, 3, 2, 2, 2, 936, 937, 7, 67, 2, 2, 937, 938, 7, 80, 2, 2, 938, 939, 7, 70, 2, 2, 939, 102, 3, 2, 2, 2, 940, 941, 7, 90, 2, 2, 941, 942, 7, 81, 2, 2, 942, 943, 7, 84, 2, 2, 943, 104, 3, 2, 2, 2, 944, 945, 7, 86, 2, 2, 945, 946, 7, 84, 2, 2, 946, 947, 7, 87, 2, 2, 947, 948, 7, 71, 2, 2, 948, 106, 3, 2, 2, 2, 949, 950, 7, 72, 2, 2, 950, 951, 7, 67, 2, 2, 951, 952, 7, 78, 2, 2, 952, 953, 7, 85, 2, 2, 953, 954, 7, 71, 2, 2, 954, 108, 3, 2, 2, 2, 955, 956, 7, 84, 2, 2, 956, 957, 7, 71, 2, 2, 957, 958, 7, 73, 2, 2, 958, 959, 7, 71, 2, 2, 959, 960, 7, 90, 2, 2, 960, 961, 7, 82, 2, 2, 961, 110, 3, 2, 2, 2, 962, 963, 7, 70, 2, 2, 963, 964, 7, 67, 2, 2, 964, 965, 7, 86, 2, 2, 965, 966, 7, 71, 2, 2, 966, 967, 7, 86, 2, 2, 967, 968, 7, 75, 2, 2, 968, 969, 7, 79, 2, 2, 969, 970, 7, 71, 2, 2, 970, 112, 3, 2, 2, 2, 971, 972, 7, 75, 2, 2, 972, 973, 7, 80, 2, 2, 973, 974, 7, 86, 2, 2, 974, 975, 7, 71, 2, 2, 975, 976, 7, 84, 2, 2, 976, 977, 7, 88, 2, 2, 977, 978, 7, 67, 2, 2, 978, 979, 7, 78, 2, 2, 979, 114, 3, 2, 2, 2, 980, 981, 7, 79, 2, 2, 981, 982, 7, 75, 2, 2, 982, 983, 7, 69, 2, 2, 983, 984, 7, 84, 2, 2, 984, 985, 7, 81, 2, 2, 985, 986, 7, 85, 2, 2, 986, 987, 7, 71, 2, 2, 987, 988, 7, 69, 2, 2, 988, 989, 7, 81, 2, 2, 989, 990, 7, 80, 2, 2, 990, 991, 7, 70, 2, 2, 991, 116, 3, 2, 2, 2, 992, 993, 7, 79, 2, 2, 993, 994, 7, 75, 2, 2, 994, 995, 7, 78, 2, 2, 995, 996, 7, 78, 2, 2, 996, 997, 7, 75, 2, 2, 997, 998, 7, 85, 2, 2, 998, 999, 7, 71, 2, 2, 999, 1000, 7, 69, 2, 2, 1000, 1001, 7, 81, 2, 2, 1001, 1002, 7, 80, 2, 2, 1002, 1003, 7, 70, 2, 2, 1003, 118, 3, 2, 2, 2, 1004, 1005, 7, 85, 2, 2, 1005, 1006, 7, 71, 2, 2, 1006, 1007, 7, 69, 2, 2, 1007, 1008, 7, 81, 2, 2, 1008, 1009, 7, 80, 2, 2, 1009, 1010, 7, 70, 2, 2, 1010, 120, 3, 2, 2, 2, 1011, 1012, 7, 79, 2, 2, 1012, 1013, 7, 75, 2, 2, 1013, 1014, 7, 80, 2, 2, 1014, 1015, 7, 87, 2, 2, 1015, 1016, 7, 86, 2, 2, 1016, 1017, 7, 71, 2, 2, 1017, 122, 3, 2, 2, 2, 1018, 1019, 7, 74, 2, 2, 1019, 1020, 7, 81, 2, 2, 1020, 1021, 7, 87, 2, 2, 1021, 1022, 7, 84, 2, 2, 1022, 124, 3, 2, 2, 2, 1023, 1024, 7, 70, 2, 2, 1024, 1025, 7, 67, 2, 2, 1025, 1026, 7, 91, 2, 2, 1026, 126, 3, 2, 2, 2, 1027, 1028, 7, 89, 2, 2, 1028, 1029, 7, 71, 2, 2, 1029, 1030, 7, 71, 2, 2, 1030, 1031, 7, 77, 2, 2, 1031, 128, 3, 2, 2, 2, 1032, 1033, 7, 79, 2, 2, 1033, 1034, 7, 81, 2, 2, 1034, 1035, 7, 80, 2, 2, 1035, 1036, 7, 86, 2, 2, 1036, 1037, 7, 74, 2, 2, 1037, 130, 3, 2, 2, 2, 1038, 1039, 7, 83, 2, 2, 1039, 1040, 7, 87, 2, 2, 1040, 1041, 7, 67, 2, 2, 1041, 1042, 7, 84, 2, 2, 1042, 1043, 7, 86, 2, 2, 1043, 1044, 7, 71, 2, 2, 1044, 1045, 7, 84, 2, 2, 1045, 132, 3, 2, 2, 2, 1046, 1047, 7, 91, 2, 2, 1047, 1048, 7, 71, 2, 2, 1048, 1049, 7, 67, 2, 2, 1049, 1050, 7, 84, 2, 2, 1050, 134, 3, 2, 2, 2, 1051, 1052, 7, 85, 2, 2, 1052, 1053, 7, 71, 2, 2, 1053, 1054, 7, 69, 2, 2, 1054, 1055, 7, 81, 2, 2, 1055, 1056, 7, 80, 2, 2, 1056, 1057, 7, 70, 2, 2, 1057, 1058, 7, 97, 2, 2, 1058, 1059, 7, 79, 2, 2, 1059, 1060, 7, 75, 2, 2, 1060, 1061, 7, 69, 2, 2, 1061, 1062, 7, 84, 2, 2, 1062, 1063, 7, 81, 2, 2, 1063, 1064, 7, 85, 2, 2, 1064, 1065, 7, 71, 2, 2, 1065, 1066, 7, 69, 2, 2, 1066, 1067, 7, 81, 2, 2, 1067, 1068, 7, 80, 2, 2, 1068, 1069, 7, 70, 2, 2, 1069, 136, 3, 2, 2, 2, 1070, 1071, 7, 79, 2, 2, 1071, 1072, 7, 75, 2, 2, 1072, 1073, 7, 80, 2, 2, 1073, 1074, 7, 87, 2, 2, 1074, 1075, 7, 86, 2, 2, 1075, 1076, 7, 71, 2, 2, 1076, 1077, 7, 97, 2, 2, 1077, 1078, 7, 79, 2, 2, 1078, 1079, 7, 75, 2, 2, 1079, 1080, 7, 69, 2, 2, 1080, 1081, 7, 84, 2, 2, 1081, 1082, 7, 81, 2, 2, 1082, 1083, 7, 85, 2, 2, 1083, 1084, 7, 71, 2, 2, 1084, 1085, 7, 69, 2, 2, 1085, 1086, 7, 81, 2, 2, 1086, 1087, 7, 80, 2, 2, 1087, 1088, 7, 70, 2, 2, 1088, 138, 3, 2, 2, 2, 1089, 1090, 7, 79, 2, 2, 1090, 1091, 7, 75, 2, 2, 1091, 1092, 7, 80, 2, 2, 1092, 1093, 7, 87, 2, 2, 1093, 1094, 7, 86, 2, 2, 1094, 1095, 7, 71, 2, 2, 1095, 1096, 7, 97, 2, 2, 1096, 1097, 7, 85, 2, 2, 1097, 1098, 7, 71, 2, 2, 1098, 1099, 7, 69, 2, 2, 1099, 1100, 7, 81, 2, 2, 1100, 1101, 7, 80, 2, 2, 1101, 1102, 7, 70, 2, 2, 1102, 140, 3, 2, 2, 2, 1103, 1104, 7, 74, 2, 2, 1104, 1105, 7, 81, 2, 2, 1105, 1106, 7, 87, 2, 2, 1106, 1107, 7, 84, 2, 2, 1107, 1108, 7, 97, 2, 2, 1108, 1109, 7, 79, 2, 2, 1109, 1110, 7, 75, 2, 2, 1110, 1111, 7, 69, 2, 2, 1111, 1112, 7, 84, 2, 2, 1112, 1113, 7, 81, 2, 2, 1113, 1114, 7, 85, 2, 2, 1114, 1115, 7, 71, 2, 2, 1115, 1116, 7, 69, 2, 2, 1116, 1117, 7, 81, 2, 2, 1117, 1118, 7, 80, 2, 2, 1118, 1119, 7, 70, 2, 2, 1119, 142, 3, 2, 2, 2, 1120, 1121, 7, 74, 2, 2, 1121, 1122, 7, 81, 2, 2, 1122, 1123, 7, 87, 2, 2, 1123, 1124, 7, 84, 2, 2, 1124, 1125, 7, 97, 2, 2, 1125, 1126, 7, 85, 2, 2, 1126, 1127, 7, 71, 2, 2, 1127, 1128, 7, 69, 2, 2, 1128, 1129, 7, 81, 2, 2, 1129, 1130, 7, 80, 2, 2, 1130, 1131, 7, 70, 2, 2, 1131, 144, 3, 2, 2, 2, 1132, 1133, 7, 74, 2, 2, 1133, 1134, 7, 81, 2, 2, 1134, 1135, 7, 87, 2, 2, 1135, 1136, 7, 84, 2, 2, 1136, 1137, 7, 97, 2, 2, 1137, 1138, 7, 79, 2, 2, 1138, 1139, 7, 75, 2, 2, 1139, 1140, 7, 80, 2, 2, 1140, 1141, 7, 87, 2, 2, 1141, 1142, 7, 86, 2, 2, 1142, 1143, 7, 71, 2, 2, 1143, 146, 3, 2, 2, 2, 1144, 1145, 7, 70, 2, 2, 1145, 1146, 7, 67, 2, 2, 1146, 1147, 7, 91, 2, 2, 1147, 1148, 7, 97, 2, 2, 1148, 1149, 7, 79, 2, 2, 1149, 1150, 7, 75, 2, 2, 1150, 1151, 7, 69, 2, 2, 1151, 1152, 7, 84, 2, 2, 1152, 1153, 7, 81, 2, 2, 1153, 1154, 7, 85, 2, 2, 1154, 1155, 7, 71, 2, 2, 1155, 1156, 7, 69, 2, 2, 1156, 1157, 7, 81, 2, 2, 1157, 1158, 7, 80, 2, 2, 1158, 1159, 7, 70, 2, 2, 1159, 148, 3, 2, 2, 2, 1160, 1161, 7, 70, 2, 2, 1161, 1162, 7, 67, 2, 2, 1162, 1163, 7, 91, 2, 2, 1163, 1164, 7, 97, 2, 2, 1164, 1165, 7, 85, 2, 2, 1165, 1166, 7, 71, 2, 2, 1166, 1167, 7, 69, 2, 2, 1167, 1168, 7, 81, 2, 2, 1168, 1169, 7, 80, 2, 2, 1169, 1170, 7, 70, 2, 2, 1170, 150, 3, 2, 2, 2, 1171, 1172, 7, 70, 2, 2, 1172, 1173, 7, 67, 2, 2, 1173, 1174, 7, 91, 2, 2, 1174, 1175, 7, 97, 2, 2, 1175, 1176, 7, 79, 2, 2, 1176, 1177, 7, 75, 2, 2, 1177, 1178, 7, 80, 2, 2, 1178, 1179, 7, 87, 2, 2, 1179, 1180, 7, 86, 2, 2, 1180, 1181, 7, 71, 2, 2, 1181, 152, 3, 2, 2, 2, 1182, 1183, 7, 70, 2, 2, 1183, 1184, 7, 67, 2, 2, 1184, 1185, 7, 91, 2, 2, 1185, 1186, 7, 97, 2, 2, 1186, 1187, 7, 74, 2, 2, 1187, 1188, 7, 81, 2, 2, 1188, 1189, 7, 87, 2, 2, 1189, 1190, 7, 84, 2, 2, 1190, 154, 3, 2, 2, 2, 1191, 1192, 7, 91, 2, 2, 1192, 1193, 7, 71, 2, 2, 1193, 1194, 7, 67, 2, 2, 1194, 1195, 7, 84, 2, 2, 1195, 1196, 7, 97, 2, 2, 1196, 1197, 7, 79, 2, 2, 1197, 1198, 7, 81, 2, 2, 1198, 1199, 7, 80, 2, 2, 1199, 1200, 7, 86, 2, 2, 1200, 1201, 7, 74, 2, 2, 1201, 156, 3, 2, 2, 2, 1202, 1203, 7, 70, 2, 2, 1203, 1204, 7, 67, 2, 2, 1204, 1205, 7, 86, 2, 2, 1205, 1206, 7, 67, 2, 2, 1206, 1207, 7, 79, 2, 2, 1207, 1208, 7, 81, 2, 2, 1208, 1209, 7, 70, 2, 2, 1209, 1210, 7, 71, 2, 2, 1210, 1211, 7, 78, 2, 2, 1211, 158, 3, 2, 2, 2, 1212, 1213, 7, 78, 2, 2, 1213, 1214, 7, 81, 2, 2, 1214, 1215, 7, 81, 2, 2, 1215, 1216, 7, 77, 2, 2, 1216, 1217, 7, 87, 2, 2, 1217, 1218, 7, 82, 2, 2, 1218, 160, 3, 2, 2, 2, 1219, 1220, 7, 85, 2, 2, 1220, 1221, 7, 67, 2, 2, 1221, 1222, 7, 88, 2, 2, 1222, 1223, 7, 71, 2, 2, 1223, 1224, 7, 70, 2, 2, 1224, 1225, 7, 85, 2, 2, 1225, 1226, 7, 71, 2, 2, 1226, 1227, 7, 67, 2, 2, 1227, 1228, 7, 84, 2, 2, 1228, 1229, 7, 69, 2, 2, 1229, 1230, 7, 74, 2, 2, 1230, 162, 3, 2, 2, 2, 1231, 1232, 7, 75, 2, 2, 1232, 1233, 7, 80, 2, 2, 1233, 1234, 7, 86, 2, 2, 1234, 164, 3, 2, 2, 2, 1235, 1236, 7, 75, 2, 2, 1236, 1237, 7, 80, 2, 2, 1237, 1238, 7, 86, 2, 2, 1238, 1239, 7, 71, 2, 2, 1239, 1240, 7, 73, 2, 2, 1240, 1241, 7, 71, 2, 2, 1241, 1242, 7, 84, 2, 2, 1242, 166, 3, 2, 2, 2, 1243, 1244, 7, 70, 2, 2, 1244, 1245, 7, 81, 2, 2, 1245, 1246, 7, 87, 2, 2, 1246, 1247, 7, 68, 2, 2, 1247, 1248, 7, 78, 2, 2, 1248, 1249, 7, 71, 2, 2, 1249, 168, 3, 2, 2, 2, 1250, 1251, 7, 78, 2, 2, 1251, 1252, 7, 81, 2, 2, 1252, 1253, 7, 80, 2, 2, 1253, 1254, 7, 73, 2, 2, 1254, 170, 3, 2, 2, 2, 1255, 1256, 7, 72, 2, 2, 1256, 1257, 7, 78, 2, 2, 1257, 1258, 7, 81, 2, 2, 1258, 1259, 7, 67, 2, 2, 1259, 1260, 7, 86, 2, 2, 1260, 172, 3, 2, 2, 2, 1261, 1262, 7, 85, 2, 2, 1262, 1263, 7, 86, 2, 2, 1263, 1264, 7, 84, 2, 2, 1264, 1265, 7, 75, 2, 2, 1265, 1266, 7, 80, 2, 2, 1266, 1267, 7, 73, 2, 2, 1267, 174, 3, 2, 2, 2, 1268, 1269, 7, 68, 2, 2, 1269, 1270, 7, 81, 2, 2, 1270, 1271, 7, 81, 2, 2, 1271, 1272, 7, 78, 2, 2, 1272, 1273, 7, 71, 2, 2, 1273, 1274, 7, 67, 2, 2, 1274, 1275, 7, 80, 2, 2, 1275, 176, 3, 2, 2, 2, 1276, 1277, 7, 126, 2, 2, 1277, 178, 3, 2, 2, 2, 1278, 1279, 7, 46, 2, 2, 1279, 180, 3, 2, 2, 2, 1280, 1281, 7, 48, 2, 2, 1281, 182, 3, 2, 2, 2, 1282, 1283, 7, 63, 2, 2, 1283, 184, 3, 2, 2, 2, 1284, 1285, 7, 64, 2, 2, 1285, 186, 3, 2, 2, 2, 1286, 1287, 7, 62, 2, 2, 1287, 188, 3, 2, 2, 2, 1288, 1289, 7, 62, 2, 2, 1289, 1290, 7, 63, 2, 2, 1290, 190, 3, 2, 2, 2, 1291, 1292, 7, 64, 2, 2, 1292, 1293, 7, 63, 2, 2, 1293, 192, 3, 2, 2, 2, 1294, 1295, 7, 35, 2, 2, 1295, 1296, 7, 63, 2, 2, 1296, 194, 3, 2, 2, 2, 1297, 1298, 7, 45, 2, 2, 1298, 196, 3, 2, 2, 2, 1299, 1300, 7, 47, 2, 2, 1300, 198, 3, 2, 2, 2, 1301, 1302, 7, 44, 2, 2, 1302, 200, 3, 2, 2, 2, 1303, 1304, 7, 49, 2, 2, 1304, 202, 3, 2, 2, 2, 1305, 1306, 7, 39, 2, 2, 1306, 204, 3, 2, 2, 2, 1307, 1308, 7, 35, 2, 2, 1308, 206, 3, 2, 2, 2, 1309, 1310, 7, 60, 2, 2, 1310, 208, 3, 2, 2, 2, 1311, 1312, 7, 42, 2, 2, 1312, 210, 3, 2, 2, 2, 1313, 1314, 7, 43, 2, 2, 1314, 212, 3, 2, 2, 2, 1315, 1316, 7, 93, 2, 2, 1316, 214, 3, 2, 2, 2, 1317, 1318, 7, 95, 2, 2, 1318, 216, 3, 2, 2, 2, 1319, 1320, 7, 41, 2, 2, 1320, 218, 3, 2, 2, 2, 1321, 1322, 7, 36, 2, 2, 1322, 220, 3, 2, 2, 2, 1323, 1324, 7, 98, 2, 2, 1324, 222, 3, 2, 2, 2, 1325, 1326, 7, 128, 2, 2, 1326, 224, 3, 2, 2, 2, 1327, 1328, 7, 40, 2, 2, 1328, 226, 3, 2, 2, 2, 1329, 1330, 7, 96, 2, 2, 1330, 228, 3, 2, 2, 2, 1331, 1332, 7, 67, 2, 2, 1332, 1333, 7, 88, 2, 2, 1333, 1334, 7, 73, 2, 2, 1334, 230, 3, 2, 2, 2, 1335, 1336, 7, 69, 2, 2, 1336, 1337, 7, 81, 2, 2, 1337, 1338, 7, 87, 2, 2, 1338, 1339, 7, 80, 2, 2, 1339, 1340, 7, 86, 2, 2, 1340, 232, 3, 2, 2, 2, 1341, 1342, 7, 70, 2, 2, 1342, 1343, 7, 75, 2, 2, 1343, 1344, 7, 85, 2, 2, 1344, 1345, 7, 86, 2, 2, 1345, 1346, 7, 75, 2, 2, 1346, 1347, 7, 80, 2, 2, 1347, 1348, 7, 69, 2, 2, 1348, 1349, 7, 86, 2, 2, 1349, 1350, 7, 97, 2, 2, 1350, 1351, 7, 69, 2, 2, 1351, 1352, 7, 81, 2, 2, 1352, 1353, 7, 87, 2, 2, 1353, 1354, 7, 80, 2, 2, 1354, 1355, 7, 86, 2, 2, 1355, 234, 3, 2, 2, 2, 1356, 1357, 7, 71, 2, 2, 1357, 1358, 7, 85, 2, 2, 1358, 1359, 7, 86, 2, 2, 1359, 1360, 7, 70, 2, 2, 1360, 1361, 7, 69, 2, 2, 1361, 236, 3, 2, 2, 2, 1362, 1363, 7, 71, 2, 2, 1363, 1364, 7, 85, 2, 2, 1364, 1365, 7, 86, 2, 2, 1365, 1366, 7, 70, 2, 2, 1366, 1367, 7, 69, 2, 2, 1367, 1368, 7, 97, 2, 2, 1368, 1369, 7, 71, 2, 2, 1369, 1370, 7, 84, 2, 2, 1370, 1371, 7, 84, 2, 2, 1371, 1372, 7, 81, 2, 2, 1372, 1373, 7, 84, 2, 2, 1373, 238, 3, 2, 2, 2, 1374, 1375, 7, 79, 2, 2, 1375, 1376, 7, 67, 2, 2, 1376, 1377, 7, 90, 2, 2, 1377, 240, 3, 2, 2, 2, 1378, 1379, 7, 79, 2, 2, 1379, 1380, 7, 71, 2, 2, 1380, 1381, 7, 67, 2, 2, 1381, 1382, 7, 80, 2, 2, 1382, 242, 3, 2, 2, 2, 1383, 1384, 7, 79, 2, 2, 1384, 1385, 7, 71, 2, 2, 1385, 1386, 7, 70, 2, 2, 1386, 1387, 7, 75, 2, 2, 1387, 1388, 7, 67, 2, 2, 1388, 1389, 7, 80, 2, 2, 1389, 244, 3, 2, 2, 2, 1390, 1391, 7, 79, 2, 2, 1391, 1392, 7, 75, 2, 2, 1392, 1393, 7, 80, 2, 2, 1393, 246, 3, 2, 2, 2, 1394, 1395, 7, 79, 2, 2, 1395, 1396, 7, 81, 2, 2, 1396, 1397, 7, 70, 2, 2, 1397, 1398, 7, 71, 2, 2, 1398, 248, 3, 2, 2, 2, 1399, 1400, 7, 84, 2, 2, 1400, 1401, 7, 67, 2, 2, 1401, 1402, 7, 80, 2, 2, 1402, 1403, 7, 73, 2, 2, 1403, 1404, 7, 71, 2, 2, 1404, 250, 3, 2, 2, 2, 1405, 1406, 7, 85, 2, 2, 1406, 1407, 7, 86, 2, 2, 1407, 1408, 7, 70, 2, 2, 1408, 1409, 7, 71, 2, 2, 1409, 1410, 7, 88, 2, 2, 1410, 252, 3, 2, 2, 2, 1411, 1412, 7, 85, 2, 2, 1412, 1413, 7, 86, 2, 2, 1413, 1414, 7, 70, 2, 2, 1414, 1415, 7, 71, 2, 2, 1415, 1416, 7, 88, 2, 2, 1416, 1417, 7, 82, 2, 2, 1417, 254, 3, 2, 2, 2, 1418, 1419, 7, 85, 2, 2, 1419, 1420, 7, 87, 2, 2, 1420, 1421, 7, 79, 2, 2, 1421, 256, 3, 2, 2, 2, 1422, 1423, 7, 85, 2, 2, 1423, 1424, 7, 87, 2, 2, 1424, 1425, 7, 79, 2, 2, 1425, 1426, 7, 85, 2, 2, 1426, 1427, 7, 83, 2, 2, 1427, 258, 3, 2, 2, 2, 1428, 1429, 7, 88, 2, 2, 1429, 1430, 7, 67, 2, 2, 1430, 1431, 7, 84, 2, 2, 1431, 1432, 7, 97, 2, 2, 1432, 1433, 7, 85, 2, 2, 1433, 1434, 7, 67, 2, 2, 1434, 1435, 7, 79, 2, 2, 1435, 1436, 7, 82, 2, 2, 1436, 260, 3, 2, 2, 2, 1437, 1438, 7, 88, 2, 2, 1438, 1439, 7, 67, 2, 2, 1439, 1440, 7, 84, 2, 2, 1440, 1441, 7, 97, 2, 2, 1441, 1442, 7, 82, 2, 2, 1442, 1443, 7, 81, 2, 2, 1443, 1444, 7, 82, 2, 2, 1444, 262, 3, 2, 2, 2, 1445, 1446, 7, 85, 2, 2, 1446, 1447, 7, 86, 2, 2, 1447, 1448, 7, 70, 2, 2, 1448, 1449, 7, 70, 2, 2, 1449, 1450, 7, 71, 2, 2, 1450, 1451, 7, 88, 2, 2, 1451, 1452, 7, 97, 2, 2, 1452, 1453, 7, 85, 2, 2, 1453, 1454, 7, 67, 2, 2, 1454, 1455, 7, 79, 2, 2, 1455, 1456, 7, 82, 2, 2, 1456, 264, 3, 2, 2, 2, 1457, 1458, 7, 85, 2, 2, 1458, 1459, 7, 86, 2, 2, 1459, 1460, 7, 70, 2, 2, 1460, 1461, 7, 70, 2, 2, 1461, 1462, 7, 71, 2, 2, 1462, 1463, 7, 88, 2, 2, 1463, 1464, 7, 97, 2, 2, 1464, 1465, 7, 82, 2, 2, 1465, 1466, 7, 81, 2, 2, 1466, 1467, 7, 82, 2, 2, 1467, 266, 3, 2, 2, 2, 1468, 1469, 7, 82, 2, 2, 1469, 1470, 7, 71, 2, 2, 1470, 1471, 7, 84, 2, 2, 1471, 1472, 7, 69, 2, 2, 1472, 1473, 7, 71, 2, 2, 1473, 1474, 7, 80, 2, 2, 1474, 1475, 7, 86, 2, 2, 1475, 1476, 7, 75, 2, 2, 1476, 1477, 7, 78, 2, 2, 1477, 1478, 7, 71, 2, 2, 1478, 268, 3, 2, 2, 2, 1479, 1480, 7, 72, 2, 2, 1480, 1481, 7, 75, 2, 2, 1481, 1482, 7, 84, 2, 2, 1482, 1483, 7, 85, 2, 2, 1483, 1484, 7, 86, 2, 2, 1484, 270, 3, 2, 2, 2, 1485, 1486, 7, 78, 2, 2, 1486, 1487, 7, 67, 2, 2, 1487, 1488, 7, 85, 2, 2, 1488, 1489, 7, 86, 2, 2, 1489, 272, 3, 2, 2, 2, 1490, 1491, 7, 78, 2, 2, 1491, 1492, 7, 75, 2, 2, 1492, 1493, 7, 85, 2, 2, 1493, 1494, 7, 86, 2, 2, 1494, 274, 3, 2, 2, 2, 1495, 1496, 7, 88, 2, 2, 1496, 1497, 7, 67, 2, 2, 1497, 1498, 7, 78, 2, 2, 1498, 1499, 7, 87, 2, 2, 1499, 1500, 7, 71, 2, 2, 1500, 1501, 7, 85, 2, 2, 1501, 276, 3, 2, 2, 2, 1502, 1503, 7, 71, 2, 2, 1503, 1504, 7, 67, 2, 2, 1504, 1505, 7, 84, 2, 2, 1505, 1506, 7, 78, 2, 2, 1506, 1507, 7, 75, 2, 2, 1507, 1508, 7, 71, 2, 2, 1508, 1509, 7, 85, 2, 2, 1509, 1510, 7, 86, 2, 2, 1510, 278, 3, 2, 2, 2, 1511, 1512, 7, 71, 2, 2, 1512, 1513, 7, 67, 2, 2, 1513, 1514, 7, 84, 2, 2, 1514, 1515, 7, 78, 2, 2, 1515, 1516, 7, 75, 2, 2, 1516, 1517, 7, 71, 2, 2, 1517, 1518, 7, 85, 2, 2, 1518, 1519, 7, 86, 2, 2, 1519, 1520, 7, 97, 2, 2, 1520, 1521, 7, 86, 2, 2, 1521, 1522, 7, 75, 2, 2, 1522, 1523, 7, 79, 2, 2, 1523, 1524, 7, 71, 2, 2, 1524, 280, 3, 2, 2, 2, 1525, 1526, 7, 78, 2, 2, 1526, 1527, 7, 67, 2, 2, 1527, 1528, 7, 86, 2, 2, 1528, 1529, 7, 71, 2, 2, 1529, 1530, 7, 85, 2, 2, 1530, 1531, 7, 86, 2, 2, 1531, 282, 3, 2, 2, 2, 1532, 1533, 7, 78, 2, 2, 1533, 1534, 7, 67, 2, 2, 1534, 1535, 7, 86, 2, 2, 1535, 1536, 7, 71, 2, 2, 1536, 1537, 7, 85, 2, 2, 1537, 1538, 7, 86, 2, 2, 1538, 1539, 7, 97, 2, 2, 1539, 1540, 7, 86, 2, 2, 1540, 1541, 7, 75, 2, 2, 1541, 1542, 7, 79, 2, 2, 1542, 1543, 7, 71, 2, 2, 1543, 284, 3, 2, 2, 2, 1544, 1545, 7, 82, 2, 2, 1545, 1546, 7, 71, 2, 2, 1546, 1547, 7, 84, 2, 2, 1547, 1548, 7, 97, 2, 2, 1548, 1549, 7, 70, 2, 2, 1549, 1550, 7, 67, 2, 2, 1550, 1551, 7, 91, 2, 2, 1551, 286, 3, 2, 2, 2, 1552, 1553, 7, 82, 2, 2, 1553, 1554, 7, 71, 2, 2, 1554, 1555, 7, 84, 2, 2, 1555, 1556, 7, 97, 2, 2, 1556, 1557, 7, 74, 2, 2, 1557, 1558, 7, 81, 2, 2, 1558, 1559, 7, 87, 2, 2, 1559, 1560, 7, 84, 2, 2, 1560, 288, 3, 2, 2, 2, 1561, 1562, 7, 82, 2, 2, 1562, 1563, 7, 71, 2, 2, 1563, 1564, 7, 84, 2, 2, 1564, 1565, 7, 97, 2, 2, 1565, 1566, 7, 79, 2, 2, 1566, 1567, 7, 75, 2, 2, 1567, 1568, 7, 80, 2, 2, 1568, 1569, 7, 87, 2, 2, 1569, 1570, 7, 86, 2, 2, 1570, 1571, 7, 71, 2, 2, 1571, 290, 3, 2, 2, 2, 1572, 1573, 7, 82, 2, 2, 1573, 1574, 7, 71, 2, 2, 1574, 1575, 7, 84, 2, 2, 1575, 1576, 7, 97, 2, 2, 1576, 1577, 7, 85, 2, 2, 1577, 1578, 7, 71, 2, 2, 1578, 1579, 7, 69, 2, 2, 1579, 1580, 7, 81, 2, 2, 1580, 1581, 7, 80, 2, 2, 1581, 1582, 7, 70, 2, 2, 1582, 292, 3, 2, 2, 2, 1583, 1584, 7, 84, 2, 2, 1584, 1585, 7, 67, 2, 2, 1585, 1586, 7, 86, 2, 2, 1586, 1587, 7, 71, 2, 2, 1587, 294, 3, 2, 2, 2, 1588, 1589, 7, 85, 2, 2, 1589, 1590, 7, 82, 2, 2, 1590, 1591, 7, 67, 2, 2, 1591, 1592, 7, 84, 2, 2, 1592, 1593, 7, 77, 2, 2, 1593, 1594, 7, 78, 2, 2, 1594, 1595, 7, 75, 2, 2, 1595, 1596, 7, 80, 2, 2, 1596, 1597, 7, 71, 2, 2, 1597, 296, 3, 2, 2, 2, 1598, 1599, 7, 69, 2, 2, 1599, 298, 3, 2, 2, 2, 1600, 1601, 7, 70, 2, 2, 1601, 1602, 7, 69, 2, 2, 1602, 300, 3, 2, 2, 2, 1603, 1604, 7, 67, 2, 2, 1604, 1605, 7, 68, 2, 2, 1605, 1606, 7, 85, 2, 2, 1606, 302, 3, 2, 2, 2, 1607, 1608, 7, 69, 2, 2, 1608, 1609, 7, 71, 2, 2, 1609, 1610, 7, 75, 2, 2, 1610, 1611, 7, 78, 2, 2, 1611, 304, 3, 2, 2, 2, 1612, 1613, 7, 69, 2, 2, 1613, 1614, 7, 71, 2, 2, 1614, 1615, 7, 75, 2, 2, 1615, 1616, 7, 78, 2, 2, 1616, 1617, 7, 75, 2, 2, 1617, 1618, 7, 80, 2, 2, 1618, 1619, 7, 73, 2, 2, 1619, 306, 3, 2, 2, 2, 1620, 1621, 7, 69, 2, 2, 1621, 1622, 7, 81, 2, 2, 1622, 1623, 7, 80, 2, 2, 1623, 1624, 7, 88, 2, 2, 1624, 308, 3, 2, 2, 2, 1625, 1626, 7, 69, 2, 2, 1626, 1627, 7, 84, 2, 2, 1627, 1628, 7, 69, 2, 2, 1628, 1629, 7, 53, 2, 2, 1629, 1630, 7, 52, 2, 2, 1630, 310, 3, 2, 2, 2, 1631, 1632, 7, 71, 2, 2, 1632, 312, 3, 2, 2, 2, 1633, 1634, 7, 71, 2, 2, 1634, 1635, 7, 90, 2, 2, 1635, 1636, 7, 82, 2, 2, 1636, 314, 3, 2, 2, 2, 1637, 1638, 7, 72, 2, 2, 1638, 1639, 7, 78, 2, 2, 1639, 1640, 7, 81, 2, 2, 1640, 1641, 7, 81, 2, 2, 1641, 1642, 7, 84, 2, 2, 1642, 316, 3, 2, 2, 2, 1643, 1644, 7, 78, 2, 2, 1644, 1645, 7, 80, 2, 2, 1645, 318, 3, 2, 2, 2, 1646, 1647, 7, 78, 2, 2, 1647, 1648, 7, 81, 2, 2, 1648, 1649, 7, 73, 2, 2, 1649, 320, 3, 2, 2, 2, 1650, 1651, 7, 78, 2, 2, 1651, 1652, 7, 81, 2, 2, 1652, 1653, 7, 73, 2, 2, 1653, 1654, 7, 51, 2, 2, 1654, 1655, 7, 50, 2, 2, 1655, 322, 3, 2, 2, 2, 1656, 1657, 7, 78, 2, 2, 1657, 1658, 7, 81, 2, 2, 1658, 1659, 7, 73, 2, 2, 1659, 1660, 7, 52, 2, 2, 1660, 324, 3, 2, 2, 2, 1661, 1662, 7, 79, 2, 2, 1662, 1663, 7, 81, 2, 2, 1663, 1664, 7, 70, 2, 2, 1664, 326, 3, 2, 2, 2, 1665, 1666, 7, 82, 2, 2, 1666, 1667, 7, 75, 2, 2, 1667, 328, 3, 2, 2, 2, 1668, 1669, 7, 82, 2, 2, 1669, 1670, 7, 81, 2, 2, 1670, 1671, 7, 89, 2, 2, 1671, 330, 3, 2, 2, 2, 1672, 1673, 7, 82, 2, 2, 1673, 1674, 7, 81, 2, 2, 1674, 1675, 7, 89, 2, 2, 1675, 1676, 7, 71, 2, 2, 1676, 1677, 7, 84, 2, 2, 1677, 332, 3, 2, 2, 2, 1678, 1679, 7, 84, 2, 2, 1679, 1680, 7, 67, 2, 2, 1680, 1681, 7, 80, 2, 2, 1681, 1682, 7, 70, 2, 2, 1682, 334, 3, 2, 2, 2, 1683, 1684, 7, 84, 2, 2, 1684, 1685, 7, 81, 2, 2, 1685, 1686, 7, 87, 2, 2, 1686, 1687, 7, 80, 2, 2, 1687, 1688, 7, 70, 2, 2, 1688, 336, 3, 2, 2, 2, 1689, 1690, 7, 85, 2, 2, 1690, 1691, 7, 75, 2, 2, 1691, 1692, 7, 73, 2, 2, 1692, 1693, 7, 80, 2, 2, 1693, 338, 3, 2, 2, 2, 1694, 1695, 7, 85, 2, 2, 1695, 1696, 7, 83, 2, 2, 1696, 1697, 7, 84, 2, 2, 1697, 1698, 7, 86, 2, 2, 1698, 340, 3, 2, 2, 2, 1699, 1700, 7, 86, 2, 2, 1700, 1701, 7, 84, 2, 2, 1701, 1702, 7, 87, 2, 2, 1702, 1703, 7, 80, 2, 2, 1703, 1704, 7, 69, 2, 2, 1704, 1705, 7, 67, 2, 2, 1705, 1706, 7, 86, 2, 2, 1706, 1707, 7, 71, 2, 2, 1707, 342, 3, 2, 2, 2, 1708, 1709, 7, 67, 2, 2, 1709, 1710, 7, 69, 2, 2, 1710, 1711, 7, 81, 2, 2, 1711, 1712, 7, 85, 2, 2, 1712, 344, 3, 2, 2, 2, 1713, 1714, 7, 67, 2, 2, 1714, 1715, 7, 85, 2, 2, 1715, 1716, 7, 75, 2, 2, 1716, 1717, 7, 80, 2, 2, 1717, 346, 3, 2, 2, 2, 1718, 1719, 7, 67, 2, 2, 1719, 1720, 7, 86, 2, 2, 1720, 1721, 7, 67, 2, 2, 1721, 1722, 7, 80, 2, 2, 1722, 348, 3, 2, 2, 2, 1723, 1724, 7, 67, 2, 2, 1724, 1725, 7, 86, 2, 2, 1725, 1726, 7, 67, 2, 2, 1726, 1727, 7, 80, 2, 2, 1727, 1728, 7, 52, 2, 2, 1728, 350, 3, 2, 2, 2, 1729, 1730, 7, 69, 2, 2, 1730, 1731, 7, 81, 2, 2, 1731, 1732, 7, 85, 2, 2, 1732, 352, 3, 2, 2, 2, 1733, 1734, 7, 69, 2, 2, 1734, 1735, 7, 81, 2, 2, 1735, 1736, 7, 86, 2, 2, 1736, 354, 3, 2, 2, 2, 1737, 1738, 7, 70, 2, 2, 1738, 1739, 7, 71, 2, 2, 1739, 1740, 7, 73, 2, 2, 1740, 1741, 7, 84, 2, 2, 1741, 1742, 7, 71, 2, 2, 1742, 1743, 7, 71, 2, 2, 1743, 1744, 7, 85, 2, 2, 1744, 356, 3, 2, 2, 2, 1745, 1746, 7, 84, 2, 2, 1746, 1747, 7, 67, 2, 2, 1747, 1748, 7, 70, 2, 2, 1748, 1749, 7, 75, 2, 2, 1749, 1750, 7, 67, 2, 2, 1750, 1751, 7, 80, 2, 2, 1751, 1752, 7, 85, 2, 2, 1752, 358, 3, 2, 2, 2, 1753, 1754, 7, 85, 2, 2, 1754, 1755, 7, 75, 2, 2, 1755, 1756, 7, 80, 2, 2, 1756, 360, 3, 2, 2, 2, 1757, 1758, 7, 86, 2, 2, 1758, 1759, 7, 67, 2, 2, 1759, 1760, 7, 80, 2, 2, 1760, 362, 3, 2, 2, 2, 1761, 1762, 7, 67, 2, 2, 1762, 1763, 7, 70, 2, 2, 1763, 1764, 7, 70, 2, 2, 1764, 1765, 7, 70, 2, 2, 1765, 1766, 7, 67, 2, 2, 1766, 1767, 7, 86, 2, 2, 1767, 1768, 7, 71, 2, 2, 1768, 364, 3, 2, 2, 2, 1769, 1770, 7, 70, 2, 2, 1770, 1771, 7, 67, 2, 2, 1771, 1772, 7, 86, 2, 2, 1772, 1773, 7, 71, 2, 2, 1773, 366, 3, 2, 2, 2, 1774, 1775, 7, 70, 2, 2, 1775, 1776, 7, 67, 2, 2, 1776, 1777, 7, 86, 2, 2, 1777, 1778, 7, 71, 2, 2, 1778, 1779, 7, 97, 2, 2, 1779, 1780, 7, 67, 2, 2, 1780, 1781, 7, 70, 2, 2, 1781, 1782, 7, 70, 2, 2, 1782, 368, 3, 2, 2, 2, 1783, 1784, 7, 70, 2, 2, 1784, 1785, 7, 67, 2, 2, 1785, 1786, 7, 86, 2, 2, 1786, 1787, 7, 71, 2, 2, 1787, 1788, 7, 97, 2, 2, 1788, 1789, 7, 85, 2, 2, 1789, 1790, 7, 87, 2, 2, 1790, 1791, 7, 68, 2, 2, 1791, 370, 3, 2, 2, 2, 1792, 1793, 7, 70, 2, 2, 1793, 1794, 7, 67, 2, 2, 1794, 1795, 7, 91, 2, 2, 1795, 1796, 7, 81, 2, 2, 1796, 1797, 7, 72, 2, 2, 1797, 1798, 7, 79, 2, 2, 1798, 1799, 7, 81, 2, 2, 1799, 1800, 7, 80, 2, 2, 1800, 1801, 7, 86, 2, 2, 1801, 1802, 7, 74, 2, 2, 1802, 372, 3, 2, 2, 2, 1803, 1804, 7, 70, 2, 2, 1804, 1805, 7, 67, 2, 2, 1805, 1806, 7, 91, 2, 2, 1806, 1807, 7, 81, 2, 2, 1807, 1808, 7, 72, 2, 2, 1808, 1809, 7, 89, 2, 2, 1809, 1810, 7, 71, 2, 2, 1810, 1811, 7, 71, 2, 2, 1811, 1812, 7, 77, 2, 2, 1812, 374, 3, 2, 2, 2, 1813, 1814, 7, 70, 2, 2, 1814, 1815, 7, 67, 2, 2, 1815, 1816, 7, 91, 2, 2, 1816, 1817, 7, 81, 2, 2, 1817, 1818, 7, 72, 2, 2, 1818, 1819, 7, 91, 2, 2, 1819, 1820, 7, 71, 2, 2, 1820, 1821, 7, 67, 2, 2, 1821, 1822, 7, 84, 2, 2, 1822, 376, 3, 2, 2, 2, 1823, 1824, 7, 70, 2, 2, 1824, 1825, 7, 67, 2, 2, 1825, 1826, 7, 91, 2, 2, 1826, 1827, 7, 80, 2, 2, 1827, 1828, 7, 67, 2, 2, 1828, 1829, 7, 79, 2, 2, 1829, 1830, 7, 71, 2, 2, 1830, 378, 3, 2, 2, 2, 1831, 1832, 7, 72, 2, 2, 1832, 1833, 7, 84, 2, 2, 1833, 1834, 7, 81, 2, 2, 1834, 1835, 7, 79, 2, 2, 1835, 1836, 7, 97, 2, 2, 1836, 1837, 7, 70, 2, 2, 1837, 1838, 7, 67, 2, 2, 1838, 1839, 7, 91, 2, 2, 1839, 1840, 7, 85, 2, 2, 1840, 380, 3, 2, 2, 2, 1841, 1842, 7, 79, 2, 2, 1842, 1843, 7, 81, 2, 2, 1843, 1844, 7, 80, 2, 2, 1844, 1845, 7, 86, 2, 2, 1845, 1846, 7, 74, 2, 2, 1846, 1847, 7, 80, 2, 2, 1847, 1848, 7, 67, 2, 2, 1848, 1849, 7, 79, 2, 2, 1849, 1850, 7, 71, 2, 2, 1850, 382, 3, 2, 2, 2, 1851, 1852, 7, 85, 2, 2, 1852, 1853, 7, 87, 2, 2, 1853, 1854, 7, 68, 2, 2, 1854, 1855, 7, 70, 2, 2, 1855, 1856, 7, 67, 2, 2, 1856, 1857, 7, 86, 2, 2, 1857, 1858, 7, 71, 2, 2, 1858, 384, 3, 2, 2, 2, 1859, 1860, 7, 86, 2, 2, 1860, 1861, 7, 75, 2, 2, 1861, 1862, 7, 79, 2, 2, 1862, 1863, 7, 71, 2, 2, 1863, 386, 3, 2, 2, 2, 1864, 1865, 7, 86, 2, 2, 1865, 1866, 7, 75, 2, 2, 1866, 1867, 7, 79, 2, 2, 1867, 1868, 7, 71, 2, 2, 1868, 1869, 7, 97, 2, 2, 1869, 1870, 7, 86, 2, 2, 1870, 1871, 7, 81, 2, 2, 1871, 1872, 7, 97, 2, 2, 1872, 1873, 7, 85, 2, 2, 1873, 1874, 7, 71, 2, 2, 1874, 1875, 7, 69, 2, 2, 1875, 388, 3, 2, 2, 2, 1876, 1877, 7, 86, 2, 2, 1877, 1878, 7, 75, 2, 2, 1878, 1879, 7, 79, 2, 2, 1879, 1880, 7, 71, 2, 2, 1880, 1881, 7, 85, 2, 2, 1881, 1882, 7, 86, 2, 2, 1882, 1883, 7, 67, 2, 2, 1883, 1884, 7, 79, 2, 2, 1884, 1885, 7, 82, 2, 2, 1885, 390, 3, 2, 2, 2, 1886, 1887, 7, 70, 2, 2, 1887, 1888, 7, 67, 2, 2, 1888, 1889, 7, 86, 2, 2, 1889, 1890, 7, 71, 2, 2, 1890, 1891, 7, 97, 2, 2, 1891, 1892, 7, 72, 2, 2, 1892, 1893, 7, 81, 2, 2, 1893, 1894, 7, 84, 2, 2, 1894, 1895, 7, 79, 2, 2, 1895, 1896, 7, 67, 2, 2, 1896, 1897, 7, 86, 2, 2, 1897, 392, 3, 2, 2, 2, 1898, 1899, 7, 86, 2, 2, 1899, 1900, 7, 81, 2, 2, 1900, 1901, 7, 97, 2, 2, 1901, 1902, 7, 70, 2, 2, 1902, 1903, 7, 67, 2, 2, 1903, 1904, 7, 91, 2, 2, 1904, 1905, 7, 85, 2, 2, 1905, 394, 3, 2, 2, 2, 1906, 1907, 7, 85, 2, 2, 1907, 1908, 7, 87, 2, 2, 1908, 1909, 7, 68, 2, 2, 1909, 1910, 7, 85, 2, 2, 1910, 1911, 7, 86, 2, 2, 1911, 1912, 7, 84, 2, 2, 1912, 396, 3, 2, 2, 2, 1913, 1914, 7, 85, 2, 2, 1914, 1915, 7, 87, 2, 2, 1915, 1916, 7, 68, 2, 2, 1916, 1917, 7, 85, 2, 2, 1917, 1918, 7, 86, 2, 2, 1918, 1919, 7, 84, 2, 2, 1919, 1920, 7, 75, 2, 2, 1920, 1921, 7, 80, 2, 2, 1921, 1922, 7, 73, 2, 2, 1922, 398, 3, 2, 2, 2, 1923, 1924, 7, 78, 2, 2, 1924, 1925, 7, 86, 2, 2, 1925, 1926, 7, 84, 2, 2, 1926, 1927, 7, 75, 2, 2, 1927, 1928, 7, 79, 2, 2, 1928, 400, 3, 2, 2, 2, 1929, 1930, 7, 84, 2, 2, 1930, 1931, 7, 86, 2, 2, 1931, 1932, 7, 84, 2, 2, 1932, 1933, 7, 75, 2, 2, 1933, 1934, 7, 79, 2, 2, 1934, 402, 3, 2, 2, 2, 1935, 1936, 7, 86, 2, 2, 1936, 1937, 7, 84, 2, 2, 1937, 1938, 7, 75, 2, 2, 1938, 1939, 7, 79, 2, 2, 1939, 404, 3, 2, 2, 2, 1940, 1941, 7, 86, 2, 2, 1941, 1942, 7, 81, 2, 2, 1942, 406, 3, 2, 2, 2, 1943, 1944, 7, 78, 2, 2, 1944, 1945, 7, 81, 2, 2, 1945, 1946, 7, 89, 2, 2, 1946, 1947, 7, 71, 2, 2, 1947, 1948, 7, 84, 2, 2, 1948, 408, 3, 2, 2, 2, 1949, 1950, 7, 87, 2, 2, 1950, 1951, 7, 82, 2, 2, 1951, 1952, 7, 82, 2, 2, 1952, 1953, 7, 71, 2, 2, 1953, 1954, 7, 84, 2, 2, 1954, 410, 3, 2, 2, 2, 1955, 1956, 7, 69, 2, 2, 1956, 1957, 7, 81, 2, 2, 1957, 1958, 7, 80, 2, 2, 1958, 1959, 7, 69, 2, 2, 1959, 1960, 7, 67, 2, 2, 1960, 1961, 7, 86, 2, 2, 1961, 412, 3, 2, 2, 2, 1962, 1963, 7, 69, 2, 2, 1963, 1964, 7, 81, 2, 2, 1964, 1965, 7, 80, 2, 2, 1965, 1966, 7, 69, 2, 2, 1966, 1967, 7, 67, 2, 2, 1967, 1968, 7, 86, 2, 2, 1968, 1969, 7, 97, 2, 2, 1969, 1970, 7, 89, 2, 2, 1970, 1971, 7, 85, 2, 2, 1971, 414, 3, 2, 2, 2, 1972, 1973, 7, 78, 2, 2, 1973, 1974, 7, 71, 2, 2, 1974, 1975, 7, 80, 2, 2, 1975, 1976, 7, 73, 2, 2, 1976, 1977, 7, 86, 2, 2, 1977, 1978, 7, 74, 2, 2, 1978, 416, 3, 2, 2, 2, 1979, 1980, 7, 85, 2, 2, 1980, 1981, 7, 86, 2, 2, 1981, 1982, 7, 84, 2, 2, 1982, 1983, 7, 69, 2, 2, 1983, 1984, 7, 79, 2, 2, 1984, 1985, 7, 82, 2, 2, 1985, 418, 3, 2, 2, 2, 1986, 1987, 7, 84, 2, 2, 1987, 1988, 7, 75, 2, 2, 1988, 1989, 7, 73, 2, 2, 1989, 1990, 7, 74, 2, 2, 1990, 1991, 7, 86, 2, 2, 1991, 420, 3, 2, 2, 2, 1992, 1993, 7, 78, 2, 2, 1993, 1994, 7, 71, 2, 2, 1994, 1995, 7, 72, 2, 2, 1995, 1996, 7, 86, 2, 2, 1996, 422, 3, 2, 2, 2, 1997, 1998, 7, 67, 2, 2, 1998, 1999, 7, 85, 2, 2, 1999, 2000, 7, 69, 2, 2, 2000, 2001, 7, 75, 2, 2, 2001, 2002, 7, 75, 2, 2, 2002, 424, 3, 2, 2, 2, 2003, 2004, 7, 78, 2, 2, 2004, 2005, 7, 81, 2, 2, 2005, 2006, 7, 69, 2, 2, 2006, 2007, 7, 67, 2, 2, 2007, 2008, 7, 86, 2, 2, 2008, 2009, 7, 71, 2, 2, 2009, 426, 3, 2, 2, 2, 2010, 2011, 7, 84, 2, 2, 2011, 2012, 7, 71, 2, 2, 2012, 2013, 7, 82, 2, 2, 2013, 2014, 7, 78, 2, 2, 2014, 2015, 7, 67, 2, 2, 2015, 2016, 7, 69, 2, 2, 2016, 2017, 7, 71, 2, 2, 2017, 428, 3, 2, 2, 2, 2018, 2019, 7, 69, 2, 2, 2019, 2020, 7, 67, 2, 2, 2020, 2021, 7, 85, 2, 2, 2021, 2022, 7, 86, 2, 2, 2022, 430, 3, 2, 2, 2, 2023, 2024, 7, 78, 2, 2, 2024, 2025, 7, 75, 2, 2, 2025, 2026, 7, 77, 2, 2, 2026, 2027, 7, 71, 2, 2, 2027, 432, 3, 2, 2, 2, 2028, 2029, 7, 75, 2, 2, 2029, 2030, 7, 85, 2, 2, 2030, 2031, 7, 80, 2, 2, 2031, 2032, 7, 87, 2, 2, 2032, 2033, 7, 78, 2, 2, 2033, 2034, 7, 78, 2, 2, 2034, 434, 3, 2, 2, 2, 2035, 2036, 7, 75, 2, 2, 2036, 2037, 7, 85, 2, 2, 2037, 2038, 7, 80, 2, 2, 2038, 2039, 7, 81, 2, 2, 2039, 2040, 7, 86, 2, 2, 2040, 2041, 7, 80, 2, 2, 2041, 2042, 7, 87, 2, 2, 2042, 2043, 7, 78, 2, 2, 2043, 2044, 7, 78, 2, 2, 2044, 436, 3, 2, 2, 2, 2045, 2046, 7, 75, 2, 2, 2046, 2047, 7, 72, 2, 2, 2047, 2048, 7, 80, 2, 2, 2048, 2049, 7, 87, 2, 2, 2049, 2050, 7, 78, 2, 2, 2050, 2051, 7, 78, 2, 2, 2051, 438, 3, 2, 2, 2, 2052, 2053, 7, 80, 2, 2, 2053, 2054, 7, 87, 2, 2, 2054, 2055, 7, 78, 2, 2, 2055, 2056, 7, 78, 2, 2, 2056, 2057, 7, 75, 2, 2, 2057, 2058, 7, 72, 2, 2, 2058, 440, 3, 2, 2, 2, 2059, 2060, 7, 75, 2, 2, 2060, 2061, 7, 72, 2, 2, 2061, 442, 3, 2, 2, 2, 2062, 2063, 7, 79, 2, 2, 2063, 2064, 7, 67, 2, 2, 2064, 2065, 7, 86, 2, 2, 2065, 2066, 7, 69, 2, 2, 2066, 2067, 7, 74, 2, 2, 2067, 444, 3, 2, 2, 2, 2068, 2069, 7, 79, 2, 2, 2069, 2070, 7, 67, 2, 2, 2070, 2071, 7, 86, 2, 2, 2071, 2072, 7, 69, 2, 2, 2072, 2073, 7, 74, 2, 2, 2073, 2074, 7, 97, 2, 2, 2074, 2075, 7, 82, 2, 2, 2075, 2076, 7, 74, 2, 2, 2076, 2077, 7, 84, 2, 2, 2077, 2078, 7, 67, 2, 2, 2078, 2079, 7, 85, 2, 2, 2079, 2080, 7, 71, 2, 2, 2080, 446, 3, 2, 2, 2, 2081, 2082, 7, 85, 2, 2, 2082, 2083, 7, 75, 2, 2, 2083, 2084, 7, 79, 2, 2, 2084, 2085, 7, 82, 2, 2, 2085, 2086, 7, 78, 2, 2, 2086, 2087, 7, 71, 2, 2, 2087, 2088, 7, 97, 2, 2, 2088, 2089, 7, 83, 2, 2, 2089, 2090, 7, 87, 2, 2, 2090, 2091, 7, 71, 2, 2, 2091, 2092, 7, 84, 2, 2, 2092, 2093, 7, 91, 2, 2, 2093, 2094, 7, 97, 2, 2, 2094, 2095, 7, 85, 2, 2, 2095, 2096, 7, 86, 2, 2, 2096, 2097, 7, 84, 2, 2, 2097, 2098, 7, 75, 2, 2, 2098, 2099, 7, 80, 2, 2, 2099, 2100, 7, 73, 2, 2, 2100, 448, 3, 2, 2, 2, 2101, 2102, 7, 67, 2, 2, 2102, 2103, 7, 78, 2, 2, 2103, 2104, 7, 78, 2, 2, 2104, 2105, 7, 81, 2, 2, 2105, 2106, 7, 89, 2, 2, 2106, 2107, 7, 97, 2, 2, 2107, 2108, 7, 78, 2, 2, 2108, 2109, 7, 71, 2, 2, 2109, 2110, 7, 67, 2, 2, 2110, 2111, 7, 70, 2, 2, 2111, 2112, 7, 75, 2, 2, 2112, 2113, 7, 80, 2, 2, 2113, 2114, 7, 73, 2, 2, 2114, 2115, 7, 97, 2, 2, 2115, 2116, 7, 89, 2, 2, 2116, 2117, 7, 75, 2, 2, 2117, 2118, 7, 78, 2, 2, 2118, 2119, 7, 70, 2, 2, 2119, 2120, 7, 69, 2, 2, 2120, 2121, 7, 67, 2, 2, 2121, 2122, 7, 84, 2, 2, 2122, 2123, 7, 70, 2, 2, 2123, 450, 3, 2, 2, 2, 2124, 2125, 7, 67, 2, 2, 2125, 2126, 7, 80, 2, 2, 2126, 2127, 7, 67, 2, 2, 2127, 2128, 7, 78, 2, 2, 2128, 2129, 7, 91, 2, 2, 2129, 2130, 7, 92, 2, 2, 2130, 2131, 7, 71, 2, 2, 2131, 2132, 7, 97, 2, 2, 2132, 2133, 7, 89, 2, 2, 2133, 2134, 7, 75, 2, 2, 2134, 2135, 7, 78, 2, 2, 2135, 2136, 7, 70, 2, 2, 2136, 2137, 7, 69, 2, 2, 2137, 2138, 7, 67, 2, 2, 2138, 2139, 7, 84, 2, 2, 2139, 2140, 7, 70, 2, 2, 2140, 452, 3, 2, 2, 2, 2141, 2142, 7, 67, 2, 2, 2142, 2143, 7, 80, 2, 2, 2143, 2144, 7, 67, 2, 2, 2144, 2145, 7, 78, 2, 2, 2145, 2146, 7, 91, 2, 2, 2146, 2147, 7, 92, 2, 2, 2147, 2148, 7, 71, 2, 2, 2148, 2149, 7, 84, 2, 2, 2149, 454, 3, 2, 2, 2, 2150, 2151, 7, 67, 2, 2, 2151, 2152, 7, 87, 2, 2, 2152, 2153, 7, 86, 2, 2, 2153, 2154, 7, 81, 2, 2, 2154, 2155, 7, 97, 2, 2, 2155, 2156, 7, 73, 2, 2, 2156, 2157, 7, 71, 2, 2, 2157, 2158, 7, 80, 2, 2, 2158, 2159, 7, 71, 2, 2, 2159, 2160, 7, 84, 2, 2, 2160, 2161, 7, 67, 2, 2, 2161, 2162, 7, 86, 2, 2, 2162, 2163, 7, 71, 2, 2, 2163, 2164, 7, 97, 2, 2, 2164, 2165, 7, 85, 2, 2, 2165, 2166, 7, 91, 2, 2, 2166, 2167, 7, 80, 2, 2, 2167, 2168, 7, 81, 2, 2, 2168, 2169, 7, 80, 2, 2, 2169, 2170, 7, 91, 2, 2, 2170, 2171, 7, 79, 2, 2, 2171, 2172, 7, 85, 2, 2, 2172, 2173, 7, 97, 2, 2, 2173, 2174, 7, 82, 2, 2, 2174, 2175, 7, 74, 2, 2, 2175, 2176, 7, 84, 2, 2, 2176, 2177, 7, 67, 2, 2, 2177, 2178, 7, 85, 2, 2, 2178, 2179, 7, 71, 2, 2, 2179, 2180, 7, 97, 2, 2, 2180, 2181, 7, 83, 2, 2, 2181, 2182, 7, 87, 2, 2, 2182, 2183, 7, 71, 2, 2, 2183, 2184, 7, 84, 2, 2, 2184, 2185, 7, 91, 2, 2, 2185, 456, 3, 2, 2, 2, 2186, 2187, 7, 68, 2, 2, 2187, 2188, 7, 81, 2, 2, 2188, 2189, 7, 81, 2, 2, 2189, 2190, 7, 85, 2, 2, 2190, 2191, 7, 86, 2, 2, 2191, 458, 3, 2, 2, 2, 2192, 2193, 7, 69, 2, 2, 2193, 2194, 7, 87, 2, 2, 2194, 2195, 7, 86, 2, 2, 2195, 2196, 7, 81, 2, 2, 2196, 2197, 7, 72, 2, 2, 2197, 2198, 7, 72, 2, 2, 2198, 2199, 7, 97, 2, 2, 2199, 2200, 7, 72, 2, 2, 2200, 2201, 7, 84, 2, 2, 2201, 2202, 7, 71, 2, 2, 2202, 2203, 7, 83, 2, 2, 2203, 2204, 7, 87, 2, 2, 2204, 2205, 7, 71, 2, 2, 2205, 2206, 7, 80, 2, 2, 2206, 2207, 7, 69, 2, 2, 2207, 2208, 7, 91, 2, 2, 2208, 460, 3, 2, 2, 2, 2209, 2210, 7, 70, 2, 2, 2210, 2211, 7, 71, 2, 2, 2211, 2212, 7, 72, 2, 2, 2212, 2213, 7, 67, 2, 2, 2213, 2214, 7, 87, 2, 2, 2214, 2215, 7, 78, 2, 2, 2215, 2216, 7, 86, 2, 2, 2216, 2217, 7, 97, 2, 2, 2217, 2218, 7, 72, 2, 2, 2218, 2219, 7, 75, 2, 2, 2219, 2220, 7, 71, 2, 2, 2220, 2221, 7, 78, 2, 2, 2221, 2222, 7, 70, 2, 2, 2222, 462, 3, 2, 2, 2, 2223, 2224, 7, 70, 2, 2, 2224, 2225, 7, 71, 2, 2, 2225, 2226, 7, 72, 2, 2, 2226, 2227, 7, 67, 2, 2, 2227, 2228, 7, 87, 2, 2, 2228, 2229, 7, 78, 2, 2, 2229, 2230, 7, 86, 2, 2, 2230, 2231, 7, 97, 2, 2, 2231, 2232, 7, 81, 2, 2, 2232, 2233, 7, 82, 2, 2, 2233, 2234, 7, 71, 2, 2, 2234, 2235, 7, 84, 2, 2, 2235, 2236, 7, 67, 2, 2, 2236, 2237, 7, 86, 2, 2, 2237, 2238, 7, 81, 2, 2, 2238, 2239, 7, 84, 2, 2, 2239, 464, 3, 2, 2, 2, 2240, 2241, 7, 71, 2, 2, 2241, 2242, 7, 80, 2, 2, 2242, 2243, 7, 67, 2, 2, 2243, 2244, 7, 68, 2, 2, 2244, 2245, 7, 78, 2, 2, 2245, 2246, 7, 71, 2, 2, 2246, 2247, 7, 97, 2, 2, 2247, 2248, 7, 82, 2, 2, 2248, 2249, 7, 81, 2, 2, 2249, 2250, 7, 85, 2, 2, 2250, 2251, 7, 75, 2, 2, 2251, 2252, 7, 86, 2, 2, 2252, 2253, 7, 75, 2, 2, 2253, 2254, 7, 81, 2, 2, 2254, 2255, 7, 80, 2, 2, 2255, 2256, 7, 97, 2, 2, 2256, 2257, 7, 75, 2, 2, 2257, 2258, 7, 80, 2, 2, 2258, 2259, 7, 69, 2, 2, 2259, 2260, 7, 84, 2, 2, 2260, 2261, 7, 71, 2, 2, 2261, 2262, 7, 79, 2, 2, 2262, 2263, 7, 71, 2, 2, 2263, 2264, 7, 80, 2, 2, 2264, 2265, 7, 86, 2, 2, 2265, 2266, 7, 85, 2, 2, 2266, 466, 3, 2, 2, 2, 2267, 2268, 7, 72, 2, 2, 2268, 2269, 7, 78, 2, 2, 2269, 2270, 7, 67, 2, 2, 2270, 2271, 7, 73, 2, 2, 2271, 2272, 7, 85, 2, 2, 2272, 468, 3, 2, 2, 2, 2273, 2274, 7, 72, 2, 2, 2274, 2275, 7, 87, 2, 2, 2275, 2276, 7, 92, 2, 2, 2276, 2277, 7, 92, 2, 2, 2277, 2278, 7, 91, 2, 2, 2278, 2279, 7, 97, 2, 2, 2279, 2280, 7, 79, 2, 2, 2280, 2281, 7, 67, 2, 2, 2281, 2282, 7, 90, 2, 2, 2282, 2283, 7, 97, 2, 2, 2283, 2284, 7, 71, 2, 2, 2284, 2285, 7, 90, 2, 2, 2285, 2286, 7, 82, 2, 2, 2286, 2287, 7, 67, 2, 2, 2287, 2288, 7, 80, 2, 2, 2288, 2289, 7, 85, 2, 2, 2289, 2290, 7, 75, 2, 2, 2290, 2291, 7, 81, 2, 2, 2291, 2292, 7, 80, 2, 2, 2292, 2293, 7, 85, 2, 2, 2293, 470, 3, 2, 2, 2, 2294, 2295, 7, 72, 2, 2, 2295, 2296, 7, 87, 2, 2, 2296, 2297, 7, 92, 2, 2, 2297, 2298, 7, 92, 2, 2, 2298, 2299, 7, 91, 2, 2, 2299, 2300, 7, 97, 2, 2, 2300, 2301, 7, 82, 2, 2, 2301, 2302, 7, 84, 2, 2, 2302, 2303, 7, 71, 2, 2, 2303, 2304, 7, 72, 2, 2, 2304, 2305, 7, 75, 2, 2, 2305, 2306, 7, 90, 2, 2, 2306, 2307, 7, 97, 2, 2, 2307, 2308, 7, 78, 2, 2, 2308, 2309, 7, 71, 2, 2, 2309, 2310, 7, 80, 2, 2, 2310, 2311, 7, 73, 2, 2, 2311, 2312, 7, 86, 2, 2, 2312, 2313, 7, 74, 2, 2, 2313, 472, 3, 2, 2, 2, 2314, 2315, 7, 72, 2, 2, 2315, 2316, 7, 87, 2, 2, 2316, 2317, 7, 92, 2, 2, 2317, 2318, 7, 92, 2, 2, 2318, 2319, 7, 91, 2, 2, 2319, 2320, 7, 97, 2, 2, 2320, 2321, 7, 86, 2, 2, 2321, 2322, 7, 84, 2, 2, 2322, 2323, 7, 67, 2, 2, 2323, 2324, 7, 80, 2, 2, 2324, 2325, 7, 85, 2, 2, 2325, 2326, 7, 82, 2, 2, 2326, 2327, 7, 81, 2, 2, 2327, 2328, 7, 85, 2, 2, 2328, 2329, 7, 75, 2, 2, 2329, 2330, 7, 86, 2, 2, 2330, 2331, 7, 75, 2, 2, 2331, 2332, 7, 81, 2, 2, 2332, 2333, 7, 80, 2, 2, 2333, 2334, 7, 85, 2, 2, 2334, 474, 3, 2, 2, 2, 2335, 2336, 7, 72, 2, 2, 2336, 2337, 7, 87, 2, 2, 2337, 2338, 7, 92, 2, 2, 2338, 2339, 7, 92, 2, 2, 2339, 2340, 7, 91, 2, 2, 2340, 2341, 7, 97, 2, 2, 2341, 2342, 7, 84, 2, 2, 2342, 2343, 7, 71, 2, 2, 2343, 2344, 7, 89, 2, 2, 2344, 2345, 7, 84, 2, 2, 2345, 2346, 7, 75, 2, 2, 2346, 2347, 7, 86, 2, 2, 2347, 2348, 7, 71, 2, 2, 2348, 476, 3, 2, 2, 2, 2349, 2350, 7, 72, 2, 2, 2350, 2351, 7, 87, 2, 2, 2351, 2352, 7, 92, 2, 2, 2352, 2353, 7, 92, 2, 2, 2353, 2354, 7, 75, 2, 2, 2354, 2355, 7, 80, 2, 2, 2355, 2356, 7, 71, 2, 2, 2356, 2357, 7, 85, 2, 2, 2357, 2358, 7, 85, 2, 2, 2358, 478, 3, 2, 2, 2, 2359, 2360, 7, 78, 2, 2, 2360, 2361, 7, 71, 2, 2, 2361, 2362, 7, 80, 2, 2, 2362, 2363, 7, 75, 2, 2, 2363, 2364, 7, 71, 2, 2, 2364, 2365, 7, 80, 2, 2, 2365, 2366, 7, 86, 2, 2, 2366, 480, 3, 2, 2, 2, 2367, 2368, 7, 78, 2, 2, 2368, 2369, 7, 81, 2, 2, 2369, 2370, 7, 89, 2, 2, 2370, 2371, 7, 97, 2, 2, 2371, 2372, 7, 72, 2, 2, 2372, 2373, 7, 84, 2, 2, 2373, 2374, 7, 71, 2, 2, 2374, 2375, 7, 83, 2, 2, 2375, 2376, 7, 97, 2, 2, 2376, 2377, 7, 81, 2, 2, 2377, 2378, 7, 82, 2, 2, 2378, 2379, 7, 71, 2, 2, 2379, 2380, 7, 84, 2, 2, 2380, 2381, 7, 67, 2, 2, 2381, 2382, 7, 86, 2, 2, 2382, 2383, 7, 81, 2, 2, 2383, 2384, 7, 84, 2, 2, 2384, 482, 3, 2, 2, 2, 2385, 2386, 7, 79, 2, 2, 2386, 2387, 7, 67, 2, 2, 2387, 2388, 7, 90, 2, 2, 2388, 2389, 7, 97, 2, 2, 2389, 2390, 7, 70, 2, 2, 2390, 2391, 7, 71, 2, 2, 2391, 2392, 7, 86, 2, 2, 2392, 2393, 7, 71, 2, 2, 2393, 2394, 7, 84, 2, 2, 2394, 2395, 7, 79, 2, 2, 2395, 2396, 7, 75, 2, 2, 2396, 2397, 7, 80, 2, 2, 2397, 2398, 7, 75, 2, 2, 2398, 2399, 7, 92, 2, 2, 2399, 2400, 7, 71, 2, 2, 2400, 2401, 7, 70, 2, 2, 2401, 2402, 7, 97, 2, 2, 2402, 2403, 7, 85, 2, 2, 2403, 2404, 7, 86, 2, 2, 2404, 2405, 7, 67, 2, 2, 2405, 2406, 7, 86, 2, 2, 2406, 2407, 7, 71, 2, 2, 2407, 2408, 7, 85, 2, 2, 2408, 484, 3, 2, 2, 2, 2409, 2410, 7, 79, 2, 2, 2410, 2411, 7, 67, 2, 2, 2411, 2412, 7, 90, 2, 2, 2412, 2413, 7, 97, 2, 2, 2413, 2414, 7, 71, 2, 2, 2414, 2415, 7, 90, 2, 2, 2415, 2416, 7, 82, 2, 2, 2416, 2417, 7, 67, 2, 2, 2417, 2418, 7, 80, 2, 2, 2418, 2419, 7, 85, 2, 2, 2419, 2420, 7, 75, 2, 2, 2420, 2421, 7, 81, 2, 2, 2421, 2422, 7, 80, 2, 2, 2422, 2423, 7, 85, 2, 2, 2423, 486, 3, 2, 2, 2, 2424, 2425, 7, 79, 2, 2, 2425, 2426, 7, 75, 2, 2, 2426, 2427, 7, 80, 2, 2, 2427, 2428, 7, 75, 2, 2, 2428, 2429, 7, 79, 2, 2, 2429, 2430, 7, 87, 2, 2, 2430, 2431, 7, 79, 2, 2, 2431, 2432, 7, 97, 2, 2, 2432, 2433, 7, 85, 2, 2, 2433, 2434, 7, 74, 2, 2, 2434, 2435, 7, 81, 2, 2, 2435, 2436, 7, 87, 2, 2, 2436, 2437, 7, 78, 2, 2, 2437, 2438, 7, 70, 2, 2, 2438, 2439, 7, 97, 2, 2, 2439, 2440, 7, 79, 2, 2, 2440, 2441, 7, 67, 2, 2, 2441, 2442, 7, 86, 2, 2, 2442, 2443, 7, 69, 2, 2, 2443, 2444, 7, 74, 2, 2, 2444, 488, 3, 2, 2, 2, 2445, 2446, 7, 81, 2, 2, 2446, 2447, 7, 82, 2, 2, 2447, 2448, 7, 71, 2, 2, 2448, 2449, 7, 84, 2, 2, 2449, 2450, 7, 67, 2, 2, 2450, 2451, 7, 86, 2, 2, 2451, 2452, 7, 81, 2, 2, 2452, 2453, 7, 84, 2, 2, 2453, 490, 3, 2, 2, 2, 2454, 2455, 7, 82, 2, 2, 2455, 2456, 7, 74, 2, 2, 2456, 2457, 7, 84, 2, 2, 2457, 2458, 7, 67, 2, 2, 2458, 2459, 7, 85, 2, 2, 2459, 2460, 7, 71, 2, 2, 2460, 2461, 7, 97, 2, 2, 2461, 2462, 7, 85, 2, 2, 2462, 2463, 7, 78, 2, 2, 2463, 2464, 7, 81, 2, 2, 2464, 2465, 7, 82, 2, 2, 2465, 492, 3, 2, 2, 2, 2466, 2467, 7, 82, 2, 2, 2467, 2468, 7, 84, 2, 2, 2468, 2469, 7, 71, 2, 2, 2469, 2470, 7, 72, 2, 2, 2470, 2471, 7, 75, 2, 2, 2471, 2472, 7, 90, 2, 2, 2472, 2473, 7, 97, 2, 2, 2473, 2474, 7, 78, 2, 2, 2474, 2475, 7, 71, 2, 2, 2475, 2476, 7, 80, 2, 2, 2476, 2477, 7, 73, 2, 2, 2477, 2478, 7, 86, 2, 2, 2478, 2479, 7, 74, 2, 2, 2479, 494, 3, 2, 2, 2, 2480, 2481, 7, 83, 2, 2, 2481, 2482, 7, 87, 2, 2, 2482, 2483, 7, 81, 2, 2, 2483, 2484, 7, 86, 2, 2, 2484, 2485, 7, 71, 2, 2, 2485, 2486, 7, 97, 2, 2, 2486, 2487, 7, 67, 2, 2, 2487, 2488, 7, 80, 2, 2, 2488, 2489, 7, 67, 2, 2, 2489, 2490, 7, 78, 2, 2, 2490, 2491, 7, 91, 2, 2, 2491, 2492, 7, 92, 2, 2, 2492, 2493, 7, 71, 2, 2, 2493, 2494, 7, 84, 2, 2, 2494, 496, 3, 2, 2, 2, 2495, 2496, 7, 83, 2, 2, 2496, 2497, 7, 87, 2, 2, 2497, 2498, 7, 81, 2, 2, 2498, 2499, 7, 86, 2, 2, 2499, 2500, 7, 71, 2, 2, 2500, 2501, 7, 97, 2, 2, 2501, 2502, 7, 72, 2, 2, 2502, 2503, 7, 75, 2, 2, 2503, 2504, 7, 71, 2, 2, 2504, 2505, 7, 78, 2, 2, 2505, 2506, 7, 70, 2, 2, 2506, 2507, 7, 97, 2, 2, 2507, 2508, 7, 85, 2, 2, 2508, 2509, 7, 87, 2, 2, 2509, 2510, 7, 72, 2, 2, 2510, 2511, 7, 72, 2, 2, 2511, 2512, 7, 75, 2, 2, 2512, 2513, 7, 90, 2, 2, 2513, 498, 3, 2, 2, 2, 2514, 2515, 7, 84, 2, 2, 2515, 2516, 7, 71, 2, 2, 2516, 2517, 7, 89, 2, 2, 2517, 2518, 7, 84, 2, 2, 2518, 2519, 7, 75, 2, 2, 2519, 2520, 7, 86, 2, 2, 2520, 2521, 7, 71, 2, 2, 2521, 500, 3, 2, 2, 2, 2522, 2523, 7, 85, 2, 2, 2523, 2524, 7, 78, 2, 2, 2524, 2525, 7, 81, 2, 2, 2525, 2526, 7, 82, 2, 2, 2526, 502, 3, 2, 2, 2, 2527, 2528, 7, 86, 2, 2, 2528, 2529, 7, 75, 2, 2, 2529, 2530, 7, 71, 2, 2, 2530, 2531, 7, 97, 2, 2, 2531, 2532, 7, 68, 2, 2, 2532, 2533, 7, 84, 2, 2, 2533, 2534, 7, 71, 2, 2, 2534, 2535, 7, 67, 2, 2, 2535, 2536, 7, 77, 2, 2, 2536, 2537, 7, 71, 2, 2, 2537, 2538, 7, 84, 2, 2, 2538, 504, 3, 2, 2, 2, 2539, 2540, 7, 86, 2, 2, 2540, 2541, 7, 91, 2, 2, 2541, 2542, 7, 82, 2, 2, 2542, 2543, 7, 71, 2, 2, 2543, 506, 3, 2, 2, 2, 2544, 2545, 7, 92, 2, 2, 2545, 2546, 7, 71, 2, 2, 2546, 2547, 7, 84, 2, 2, 2547, 2548, 7, 81, 2, 2, 2548, 2549, 7, 97, 2, 2, 2549, 2550, 7, 86, 2, 2, 2550, 2551, 7, 71, 2, 2, 2551, 2552, 7, 84, 2, 2, 2552, 2553, 7, 79, 2, 2, 2553, 2554, 7, 85, 2, 2, 2554, 2555, 7, 97, 2, 2, 2555, 2556, 7, 83, 2, 2, 2556, 2557, 7, 87, 2, 2, 2557, 2558, 7, 71, 2, 2, 2558, 2559, 7, 84, 2, 2, 2559, 2560, 7, 91, 2, 2, 2560, 508, 3, 2, 2, 2, 2561, 2562, 7, 85, 2, 2, 2562, 2563, 7, 82, 2, 2, 2563, 2564, 7, 67, 2, 2, 2564, 2565, 7, 80, 2, 2, 2565, 510, 3, 2, 2, 2, 2566, 2567, 7, 79, 2, 2, 2567, 2568, 7, 85, 2, 2, 2568, 512, 3, 2, 2, 2, 2569, 2570, 7, 85, 2, 2, 2570, 514, 3, 2, 2, 2, 2571, 2572, 7, 79, 2, 2, 2572, 516, 3, 2, 2, 2, 2573, 2574, 7, 74, 2, 2, 2574, 518, 3, 2, 2, 2, 2575, 2576, 7, 89, 2, 2, 2576, 520, 3, 2, 2, 2, 2577, 2578, 7, 83, 2, 2, 2578, 522, 3, 2, 2, 2, 2579, 2580, 7, 91, 2, 2, 2580, 524, 3, 2, 2, 2, 2581, 2582, 5, 533, 267, 2, 2582, 526, 3, 2, 2, 2, 2583, 2585, 5, 543, 272, 2, 2584, 2583, 3, 2, 2, 2, 2585, 2586, 3, 2, 2, 2, 2586, 2584, 3, 2, 2, 2, 2586, 2587, 3, 2, 2, 2, 2587, 528, 3, 2, 2, 2, 2588, 2590, 5, 543, 272, 2, 2589, 2588, 3, 2, 2, 2, 2590, 2591, 3, 2, 2, 2, 2591, 2589, 3, 2, 2, 2, 2591, 2592, 3, 2, 2, 2, 2592, 2594, 3, 2, 2, 2, 2593, 2589, 3, 2, 2, 2, 2593, 2594, 3, 2, 2, 2, 2594, 2595, 3, 2, 2, 2, 2595, 2597, 7, 48, 2, 2, 2596, 2598, 5, 543, 272, 2, 2597, 2596, 3, 2, 2, 2, 2598, 2599, 3, 2, 2, 2, 2599, 2597, 3, 2, 2, 2, 2599, 2600, 3, 2, 2, 2, 2600, 530, 3, 2, 2, 2, 2601, 2603, 9, 2, 2, 2, 2602, 2604, 9, 3, 2, 2, 2603, 2602, 3, 2, 2, 2, 2604, 2605, 3, 2, 2, 2, 2605, 2603, 3, 2, 2, 2, 2605, 2606, 3, 2, 2, 2, 2606, 2608, 3, 2, 2, 2, 2607, 2601, 3, 2, 2, 2, 2608, 2611, 3, 2, 2, 2, 2609, 2607, 3, 2, 2, 2, 2609, 2610, 3, 2, 2, 2, 2610, 532, 3, 2, 2, 2, 2611, 2609, 3, 2, 2, 2, 2612, 2614, 9, 4, 2, 2, 2613, 2612, 3, 2, 2, 2, 2614, 2615, 3, 2, 2, 2, 2615, 2616, 3, 2, 2, 2, 2615, 2613, 3, 2, 2, 2, 2616, 2620, 3, 2, 2, 2, 2617, 2619, 9, 5, 2, 2, 2618, 2617, 3, 2, 2, 2, 2619, 2622, 3, 2, 2, 2, 2620, 2618, 3, 2, 2, 2, 2620, 2621, 3, 2, 2, 2, 2621, 534, 3, 2, 2, 2, 2622, 2620, 3, 2, 2, 2, 2623, 2624, 5, 533, 267, 2, 2624, 2625, 5, 531, 266, 2, 2625, 536, 3, 2, 2, 2, 2626, 2634, 7, 36, 2, 2, 2627, 2628, 7, 94, 2, 2, 2628, 2633, 11, 2, 2, 2, 2629, 2630, 7, 36, 2, 2, 2630, 2633, 7, 36, 2, 2, 2631, 2633, 10, 6, 2, 2, 2632, 2627, 3, 2, 2, 2, 2632, 2629, 3, 2, 2, 2, 2632, 2631, 3, 2, 2, 2, 2633, 2636, 3, 2, 2, 2, 2634, 2632, 3, 2, 2, 2, 2634, 2635, 3, 2, 2, 2, 2635, 2637, 3, 2, 2, 2, 2636, 2634, 3, 2, 2, 2, 2637, 2638, 7, 36, 2, 2, 2638, 538, 3, 2, 2, 2, 2639, 2647, 7, 41, 2, 2, 2640, 2641, 7, 94, 2, 2, 2641, 2646, 11, 2, 2, 2, 2642, 2643, 7, 41, 2, 2, 2643, 2646, 7, 41, 2, 2, 2644, 2646, 10, 7, 2, 2, 2645, 2640, 3, 2, 2, 2, 2645, 2642, 3, 2, 2, 2, 2645, 2644, 3, 2, 2, 2, 2646, 2649, 3, 2, 2, 2, 2647, 2645, 3, 2, 2, 2, 2647, 2648, 3, 2, 2, 2, 2648, 2650, 3, 2, 2, 2, 2649, 2647, 3, 2, 2, 2, 2650, 2651, 7, 41, 2, 2, 2651, 540, 3, 2, 2, 2, 2652, 2660, 7, 98, 2, 2, 2653, 2654, 7, 94, 2, 2, 2654, 2659, 11, 2, 2, 2, 2655, 2656, 7, 98, 2, 2, 2656, 2659, 7, 98, 2, 2, 2657, 2659, 10, 8, 2, 2, 2658, 2653, 3, 2, 2, 2, 2658, 2655, 3, 2, 2, 2, 2658, 2657, 3, 2, 2, 2, 2659, 2662, 3, 2, 2, 2, 2660, 2658, 3, 2, 2, 2, 2660, 2661, 3, 2, 2, 2, 2661, 2663, 3, 2, 2, 2, 2662, 2660, 3, 2, 2, 2, 2663, 2664, 7, 98, 2, 2, 2664, 542, 3, 2, 2, 2, 2665, 2666, 9, 9, 2, 2, 2666, 544, 3, 2, 2, 2, 2667, 2668, 11, 2, 2, 2, 2668, 2669, 3, 2, 2, 2, 2669, 2670, 8, 273, 2, 2, 2670, 546, 3, 2, 2, 2, 17, 2, 2586, 2591, 2593, 2599, 2605, 2609, 2615, 2620, 2632, 2634, 2645, 2647, 2658, 2660, 3, 2, 5, 2] \ No newline at end of file diff --git a/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.java b/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.java new file mode 100644 index 000000000..b7cc88a4e --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.java @@ -0,0 +1,1277 @@ +// Generated from /Users/menwe/amazon/OpenSearch-Dashboards/plugins/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLLexer.g4 by ANTLR 4.9.2 +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class OpenSearchPPLLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.9.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + SEARCH=1, FROM=2, WHERE=3, FIELDS=4, RENAME=5, STATS=6, DEDUP=7, SORT=8, + EVAL=9, HEAD=10, TOP=11, RARE=12, PARSE=13, KMEANS=14, AD=15, AS=16, BY=17, + SOURCE=18, INDEX=19, D=20, DESC=21, SORTBY=22, AUTO=23, STR=24, IP=25, + NUM=26, KEEPEMPTY=27, CONSECUTIVE=28, DEDUP_SPLITVALUES=29, PARTITIONS=30, + ALLNUM=31, DELIM=32, CENTROIDS=33, ITERATIONS=34, DISTANCE_TYPE=35, NUMBER_OF_TREES=36, + SHINGLE_SIZE=37, SAMPLE_SIZE=38, OUTPUT_AFTER=39, TIME_DECAY=40, ANOMALY_RATE=41, + TIME_FIELD=42, TIME_ZONE=43, TRAINING_DATA_SIZE=44, ANOMALY_SCORE_THRESHOLD=45, + CASE=46, IN=47, NOT=48, OR=49, AND=50, XOR=51, TRUE=52, FALSE=53, REGEXP=54, + DATETIME=55, INTERVAL=56, MICROSECOND=57, MILLISECOND=58, SECOND=59, MINUTE=60, + HOUR=61, DAY=62, WEEK=63, MONTH=64, QUARTER=65, YEAR=66, SECOND_MICROSECOND=67, + MINUTE_MICROSECOND=68, MINUTE_SECOND=69, HOUR_MICROSECOND=70, HOUR_SECOND=71, + HOUR_MINUTE=72, DAY_MICROSECOND=73, DAY_SECOND=74, DAY_MINUTE=75, DAY_HOUR=76, + YEAR_MONTH=77, DATAMODEL=78, LOOKUP=79, SAVEDSEARCH=80, INT=81, INTEGER=82, + DOUBLE=83, LONG=84, FLOAT=85, STRING=86, BOOLEAN=87, PIPE=88, COMMA=89, + DOT=90, EQUAL=91, GREATER=92, LESS=93, NOT_GREATER=94, NOT_LESS=95, NOT_EQUAL=96, + PLUS=97, MINUS=98, STAR=99, DIVIDE=100, MODULE=101, EXCLAMATION_SYMBOL=102, + COLON=103, LT_PRTHS=104, RT_PRTHS=105, LT_SQR_PRTHS=106, RT_SQR_PRTHS=107, + SINGLE_QUOTE=108, DOUBLE_QUOTE=109, BACKTICK=110, BIT_NOT_OP=111, BIT_AND_OP=112, + BIT_XOR_OP=113, AVG=114, COUNT=115, DISTINCT_COUNT=116, ESTDC=117, ESTDC_ERROR=118, + MAX=119, MEAN=120, MEDIAN=121, MIN=122, MODE=123, RANGE=124, STDEV=125, + STDEVP=126, SUM=127, SUMSQ=128, VAR_SAMP=129, VAR_POP=130, STDDEV_SAMP=131, + STDDEV_POP=132, PERCENTILE=133, FIRST=134, LAST=135, LIST=136, VALUES=137, + EARLIEST=138, EARLIEST_TIME=139, LATEST=140, LATEST_TIME=141, PER_DAY=142, + PER_HOUR=143, PER_MINUTE=144, PER_SECOND=145, RATE=146, SPARKLINE=147, + C=148, DC=149, ABS=150, CEIL=151, CEILING=152, CONV=153, CRC32=154, E=155, + EXP=156, FLOOR=157, LN=158, LOG=159, LOG10=160, LOG2=161, MOD=162, PI=163, + POW=164, POWER=165, RAND=166, ROUND=167, SIGN=168, SQRT=169, TRUNCATE=170, + ACOS=171, ASIN=172, ATAN=173, ATAN2=174, COS=175, COT=176, DEGREES=177, + RADIANS=178, SIN=179, TAN=180, ADDDATE=181, DATE=182, DATE_ADD=183, DATE_SUB=184, + DAYOFMONTH=185, DAYOFWEEK=186, DAYOFYEAR=187, DAYNAME=188, FROM_DAYS=189, + MONTHNAME=190, SUBDATE=191, TIME=192, TIME_TO_SEC=193, TIMESTAMP=194, + DATE_FORMAT=195, TO_DAYS=196, SUBSTR=197, SUBSTRING=198, LTRIM=199, RTRIM=200, + TRIM=201, TO=202, LOWER=203, UPPER=204, CONCAT=205, CONCAT_WS=206, LENGTH=207, + STRCMP=208, RIGHT=209, LEFT=210, ASCII=211, LOCATE=212, REPLACE=213, CAST=214, + LIKE=215, ISNULL=216, ISNOTNULL=217, IFNULL=218, NULLIF=219, IF=220, MATCH=221, + MATCH_PHRASE=222, SIMPLE_QUERY_STRING=223, ALLOW_LEADING_WILDCARD=224, + ANALYZE_WILDCARD=225, ANALYZER=226, AUTO_GENERATE_SYNONYMS_PHRASE_QUERY=227, + BOOST=228, CUTOFF_FREQUENCY=229, DEFAULT_FIELD=230, DEFAULT_OPERATOR=231, + ENABLE_POSITION_INCREMENTS=232, FLAGS=233, FUZZY_MAX_EXPANSIONS=234, FUZZY_PREFIX_LENGTH=235, + FUZZY_TRANSPOSITIONS=236, FUZZY_REWRITE=237, FUZZINESS=238, LENIENT=239, + LOW_FREQ_OPERATOR=240, MAX_DETERMINIZED_STATES=241, MAX_EXPANSIONS=242, + MINIMUM_SHOULD_MATCH=243, OPERATOR=244, PHRASE_SLOP=245, PREFIX_LENGTH=246, + QUOTE_ANALYZER=247, QUOTE_FIELD_SUFFIX=248, REWRITE=249, SLOP=250, TIE_BREAKER=251, + TYPE=252, ZERO_TERMS_QUERY=253, SPAN=254, MS=255, S=256, M=257, H=258, + W=259, Q=260, Y=261, ID=262, INTEGER_LITERAL=263, DECIMAL_LITERAL=264, + ID_DATE_SUFFIX=265, DQUOTA_STRING=266, SQUOTA_STRING=267, BQUOTA_STRING=268, + ERROR_RECOGNITION=269; + public static final int + WHITESPACE=2, ERRORCHANNEL=3; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "WHITESPACE", "ERRORCHANNEL" + }; + + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "SEARCH", "FROM", "WHERE", "FIELDS", "RENAME", "STATS", "DEDUP", "SORT", + "EVAL", "HEAD", "TOP", "RARE", "PARSE", "KMEANS", "AD", "AS", "BY", "SOURCE", + "INDEX", "D", "DESC", "SORTBY", "AUTO", "STR", "IP", "NUM", "KEEPEMPTY", + "CONSECUTIVE", "DEDUP_SPLITVALUES", "PARTITIONS", "ALLNUM", "DELIM", + "CENTROIDS", "ITERATIONS", "DISTANCE_TYPE", "NUMBER_OF_TREES", "SHINGLE_SIZE", + "SAMPLE_SIZE", "OUTPUT_AFTER", "TIME_DECAY", "ANOMALY_RATE", "TIME_FIELD", + "TIME_ZONE", "TRAINING_DATA_SIZE", "ANOMALY_SCORE_THRESHOLD", "CASE", + "IN", "NOT", "OR", "AND", "XOR", "TRUE", "FALSE", "REGEXP", "DATETIME", + "INTERVAL", "MICROSECOND", "MILLISECOND", "SECOND", "MINUTE", "HOUR", + "DAY", "WEEK", "MONTH", "QUARTER", "YEAR", "SECOND_MICROSECOND", "MINUTE_MICROSECOND", + "MINUTE_SECOND", "HOUR_MICROSECOND", "HOUR_SECOND", "HOUR_MINUTE", "DAY_MICROSECOND", + "DAY_SECOND", "DAY_MINUTE", "DAY_HOUR", "YEAR_MONTH", "DATAMODEL", "LOOKUP", + "SAVEDSEARCH", "INT", "INTEGER", "DOUBLE", "LONG", "FLOAT", "STRING", + "BOOLEAN", "PIPE", "COMMA", "DOT", "EQUAL", "GREATER", "LESS", "NOT_GREATER", + "NOT_LESS", "NOT_EQUAL", "PLUS", "MINUS", "STAR", "DIVIDE", "MODULE", + "EXCLAMATION_SYMBOL", "COLON", "LT_PRTHS", "RT_PRTHS", "LT_SQR_PRTHS", + "RT_SQR_PRTHS", "SINGLE_QUOTE", "DOUBLE_QUOTE", "BACKTICK", "BIT_NOT_OP", + "BIT_AND_OP", "BIT_XOR_OP", "AVG", "COUNT", "DISTINCT_COUNT", "ESTDC", + "ESTDC_ERROR", "MAX", "MEAN", "MEDIAN", "MIN", "MODE", "RANGE", "STDEV", + "STDEVP", "SUM", "SUMSQ", "VAR_SAMP", "VAR_POP", "STDDEV_SAMP", "STDDEV_POP", + "PERCENTILE", "FIRST", "LAST", "LIST", "VALUES", "EARLIEST", "EARLIEST_TIME", + "LATEST", "LATEST_TIME", "PER_DAY", "PER_HOUR", "PER_MINUTE", "PER_SECOND", + "RATE", "SPARKLINE", "C", "DC", "ABS", "CEIL", "CEILING", "CONV", "CRC32", + "E", "EXP", "FLOOR", "LN", "LOG", "LOG10", "LOG2", "MOD", "PI", "POW", + "POWER", "RAND", "ROUND", "SIGN", "SQRT", "TRUNCATE", "ACOS", "ASIN", + "ATAN", "ATAN2", "COS", "COT", "DEGREES", "RADIANS", "SIN", "TAN", "ADDDATE", + "DATE", "DATE_ADD", "DATE_SUB", "DAYOFMONTH", "DAYOFWEEK", "DAYOFYEAR", + "DAYNAME", "FROM_DAYS", "MONTHNAME", "SUBDATE", "TIME", "TIME_TO_SEC", + "TIMESTAMP", "DATE_FORMAT", "TO_DAYS", "SUBSTR", "SUBSTRING", "LTRIM", + "RTRIM", "TRIM", "TO", "LOWER", "UPPER", "CONCAT", "CONCAT_WS", "LENGTH", + "STRCMP", "RIGHT", "LEFT", "ASCII", "LOCATE", "REPLACE", "CAST", "LIKE", + "ISNULL", "ISNOTNULL", "IFNULL", "NULLIF", "IF", "MATCH", "MATCH_PHRASE", + "SIMPLE_QUERY_STRING", "ALLOW_LEADING_WILDCARD", "ANALYZE_WILDCARD", + "ANALYZER", "AUTO_GENERATE_SYNONYMS_PHRASE_QUERY", "BOOST", "CUTOFF_FREQUENCY", + "DEFAULT_FIELD", "DEFAULT_OPERATOR", "ENABLE_POSITION_INCREMENTS", "FLAGS", + "FUZZY_MAX_EXPANSIONS", "FUZZY_PREFIX_LENGTH", "FUZZY_TRANSPOSITIONS", + "FUZZY_REWRITE", "FUZZINESS", "LENIENT", "LOW_FREQ_OPERATOR", "MAX_DETERMINIZED_STATES", + "MAX_EXPANSIONS", "MINIMUM_SHOULD_MATCH", "OPERATOR", "PHRASE_SLOP", + "PREFIX_LENGTH", "QUOTE_ANALYZER", "QUOTE_FIELD_SUFFIX", "REWRITE", "SLOP", + "TIE_BREAKER", "TYPE", "ZERO_TERMS_QUERY", "SPAN", "MS", "S", "M", "H", + "W", "Q", "Y", "ID", "INTEGER_LITERAL", "DECIMAL_LITERAL", "DATE_SUFFIX", + "ID_LITERAL", "ID_DATE_SUFFIX", "DQUOTA_STRING", "SQUOTA_STRING", "BQUOTA_STRING", + "DEC_DIGIT", "ERROR_RECOGNITION" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "'SEARCH'", "'FROM'", "'WHERE'", "'FIELDS'", "'RENAME'", "'STATS'", + "'DEDUP'", "'SORT'", "'EVAL'", "'HEAD'", "'TOP'", "'RARE'", "'PARSE'", + "'KMEANS'", "'AD'", "'AS'", "'BY'", "'SOURCE'", "'INDEX'", "'D'", "'DESC'", + "'SORTBY'", "'AUTO'", "'STR'", "'IP'", "'NUM'", "'KEEPEMPTY'", "'CONSECUTIVE'", + "'DEDUP_SPLITVALUES'", "'PARTITIONS'", "'ALLNUM'", "'DELIM'", "'CENTROIDS'", + "'ITERATIONS'", "'DISTANCE_TYPE'", "'NUMBER_OF_TREES'", "'SHINGLE_SIZE'", + "'SAMPLE_SIZE'", "'OUTPUT_AFTER'", "'TIME_DECAY'", "'ANOMALY_RATE'", + "'TIME_FIELD'", "'TIME_ZONE'", "'TRAINING_DATA_SIZE'", "'ANOMALY_SCORE_THRESHOLD'", + "'CASE'", "'IN'", "'NOT'", "'OR'", "'AND'", "'XOR'", "'TRUE'", "'FALSE'", + "'REGEXP'", "'DATETIME'", "'INTERVAL'", "'MICROSECOND'", "'MILLISECOND'", + "'SECOND'", "'MINUTE'", "'HOUR'", "'DAY'", "'WEEK'", "'MONTH'", "'QUARTER'", + "'YEAR'", "'SECOND_MICROSECOND'", "'MINUTE_MICROSECOND'", "'MINUTE_SECOND'", + "'HOUR_MICROSECOND'", "'HOUR_SECOND'", "'HOUR_MINUTE'", "'DAY_MICROSECOND'", + "'DAY_SECOND'", "'DAY_MINUTE'", "'DAY_HOUR'", "'YEAR_MONTH'", "'DATAMODEL'", + "'LOOKUP'", "'SAVEDSEARCH'", "'INT'", "'INTEGER'", "'DOUBLE'", "'LONG'", + "'FLOAT'", "'STRING'", "'BOOLEAN'", "'|'", "','", "'.'", "'='", "'>'", + "'<'", null, null, null, "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "':'", + "'('", "')'", "'['", "']'", "'''", "'\"'", "'`'", "'~'", "'&'", "'^'", + "'AVG'", "'COUNT'", "'DISTINCT_COUNT'", "'ESTDC'", "'ESTDC_ERROR'", "'MAX'", + "'MEAN'", "'MEDIAN'", "'MIN'", "'MODE'", "'RANGE'", "'STDEV'", "'STDEVP'", + "'SUM'", "'SUMSQ'", "'VAR_SAMP'", "'VAR_POP'", "'STDDEV_SAMP'", "'STDDEV_POP'", + "'PERCENTILE'", "'FIRST'", "'LAST'", "'LIST'", "'VALUES'", "'EARLIEST'", + "'EARLIEST_TIME'", "'LATEST'", "'LATEST_TIME'", "'PER_DAY'", "'PER_HOUR'", + "'PER_MINUTE'", "'PER_SECOND'", "'RATE'", "'SPARKLINE'", "'C'", "'DC'", + "'ABS'", "'CEIL'", "'CEILING'", "'CONV'", "'CRC32'", "'E'", "'EXP'", + "'FLOOR'", "'LN'", "'LOG'", "'LOG10'", "'LOG2'", "'MOD'", "'PI'", "'POW'", + "'POWER'", "'RAND'", "'ROUND'", "'SIGN'", "'SQRT'", "'TRUNCATE'", "'ACOS'", + "'ASIN'", "'ATAN'", "'ATAN2'", "'COS'", "'COT'", "'DEGREES'", "'RADIANS'", + "'SIN'", "'TAN'", "'ADDDATE'", "'DATE'", "'DATE_ADD'", "'DATE_SUB'", + "'DAYOFMONTH'", "'DAYOFWEEK'", "'DAYOFYEAR'", "'DAYNAME'", "'FROM_DAYS'", + "'MONTHNAME'", "'SUBDATE'", "'TIME'", "'TIME_TO_SEC'", "'TIMESTAMP'", + "'DATE_FORMAT'", "'TO_DAYS'", "'SUBSTR'", "'SUBSTRING'", "'LTRIM'", "'RTRIM'", + "'TRIM'", "'TO'", "'LOWER'", "'UPPER'", "'CONCAT'", "'CONCAT_WS'", "'LENGTH'", + "'STRCMP'", "'RIGHT'", "'LEFT'", "'ASCII'", "'LOCATE'", "'REPLACE'", + "'CAST'", "'LIKE'", "'ISNULL'", "'ISNOTNULL'", "'IFNULL'", "'NULLIF'", + "'IF'", "'MATCH'", "'MATCH_PHRASE'", "'SIMPLE_QUERY_STRING'", "'ALLOW_LEADING_WILDCARD'", + "'ANALYZE_WILDCARD'", "'ANALYZER'", "'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'", + "'BOOST'", "'CUTOFF_FREQUENCY'", "'DEFAULT_FIELD'", "'DEFAULT_OPERATOR'", + "'ENABLE_POSITION_INCREMENTS'", "'FLAGS'", "'FUZZY_MAX_EXPANSIONS'", + "'FUZZY_PREFIX_LENGTH'", "'FUZZY_TRANSPOSITIONS'", "'FUZZY_REWRITE'", + "'FUZZINESS'", "'LENIENT'", "'LOW_FREQ_OPERATOR'", "'MAX_DETERMINIZED_STATES'", + "'MAX_EXPANSIONS'", "'MINIMUM_SHOULD_MATCH'", "'OPERATOR'", "'PHRASE_SLOP'", + "'PREFIX_LENGTH'", "'QUOTE_ANALYZER'", "'QUOTE_FIELD_SUFFIX'", "'REWRITE'", + "'SLOP'", "'TIE_BREAKER'", "'TYPE'", "'ZERO_TERMS_QUERY'", "'SPAN'", + "'MS'", "'S'", "'M'", "'H'", "'W'", "'Q'", "'Y'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "SEARCH", "FROM", "WHERE", "FIELDS", "RENAME", "STATS", "DEDUP", + "SORT", "EVAL", "HEAD", "TOP", "RARE", "PARSE", "KMEANS", "AD", "AS", + "BY", "SOURCE", "INDEX", "D", "DESC", "SORTBY", "AUTO", "STR", "IP", + "NUM", "KEEPEMPTY", "CONSECUTIVE", "DEDUP_SPLITVALUES", "PARTITIONS", + "ALLNUM", "DELIM", "CENTROIDS", "ITERATIONS", "DISTANCE_TYPE", "NUMBER_OF_TREES", + "SHINGLE_SIZE", "SAMPLE_SIZE", "OUTPUT_AFTER", "TIME_DECAY", "ANOMALY_RATE", + "TIME_FIELD", "TIME_ZONE", "TRAINING_DATA_SIZE", "ANOMALY_SCORE_THRESHOLD", + "CASE", "IN", "NOT", "OR", "AND", "XOR", "TRUE", "FALSE", "REGEXP", "DATETIME", + "INTERVAL", "MICROSECOND", "MILLISECOND", "SECOND", "MINUTE", "HOUR", + "DAY", "WEEK", "MONTH", "QUARTER", "YEAR", "SECOND_MICROSECOND", "MINUTE_MICROSECOND", + "MINUTE_SECOND", "HOUR_MICROSECOND", "HOUR_SECOND", "HOUR_MINUTE", "DAY_MICROSECOND", + "DAY_SECOND", "DAY_MINUTE", "DAY_HOUR", "YEAR_MONTH", "DATAMODEL", "LOOKUP", + "SAVEDSEARCH", "INT", "INTEGER", "DOUBLE", "LONG", "FLOAT", "STRING", + "BOOLEAN", "PIPE", "COMMA", "DOT", "EQUAL", "GREATER", "LESS", "NOT_GREATER", + "NOT_LESS", "NOT_EQUAL", "PLUS", "MINUS", "STAR", "DIVIDE", "MODULE", + "EXCLAMATION_SYMBOL", "COLON", "LT_PRTHS", "RT_PRTHS", "LT_SQR_PRTHS", + "RT_SQR_PRTHS", "SINGLE_QUOTE", "DOUBLE_QUOTE", "BACKTICK", "BIT_NOT_OP", + "BIT_AND_OP", "BIT_XOR_OP", "AVG", "COUNT", "DISTINCT_COUNT", "ESTDC", + "ESTDC_ERROR", "MAX", "MEAN", "MEDIAN", "MIN", "MODE", "RANGE", "STDEV", + "STDEVP", "SUM", "SUMSQ", "VAR_SAMP", "VAR_POP", "STDDEV_SAMP", "STDDEV_POP", + "PERCENTILE", "FIRST", "LAST", "LIST", "VALUES", "EARLIEST", "EARLIEST_TIME", + "LATEST", "LATEST_TIME", "PER_DAY", "PER_HOUR", "PER_MINUTE", "PER_SECOND", + "RATE", "SPARKLINE", "C", "DC", "ABS", "CEIL", "CEILING", "CONV", "CRC32", + "E", "EXP", "FLOOR", "LN", "LOG", "LOG10", "LOG2", "MOD", "PI", "POW", + "POWER", "RAND", "ROUND", "SIGN", "SQRT", "TRUNCATE", "ACOS", "ASIN", + "ATAN", "ATAN2", "COS", "COT", "DEGREES", "RADIANS", "SIN", "TAN", "ADDDATE", + "DATE", "DATE_ADD", "DATE_SUB", "DAYOFMONTH", "DAYOFWEEK", "DAYOFYEAR", + "DAYNAME", "FROM_DAYS", "MONTHNAME", "SUBDATE", "TIME", "TIME_TO_SEC", + "TIMESTAMP", "DATE_FORMAT", "TO_DAYS", "SUBSTR", "SUBSTRING", "LTRIM", + "RTRIM", "TRIM", "TO", "LOWER", "UPPER", "CONCAT", "CONCAT_WS", "LENGTH", + "STRCMP", "RIGHT", "LEFT", "ASCII", "LOCATE", "REPLACE", "CAST", "LIKE", + "ISNULL", "ISNOTNULL", "IFNULL", "NULLIF", "IF", "MATCH", "MATCH_PHRASE", + "SIMPLE_QUERY_STRING", "ALLOW_LEADING_WILDCARD", "ANALYZE_WILDCARD", + "ANALYZER", "AUTO_GENERATE_SYNONYMS_PHRASE_QUERY", "BOOST", "CUTOFF_FREQUENCY", + "DEFAULT_FIELD", "DEFAULT_OPERATOR", "ENABLE_POSITION_INCREMENTS", "FLAGS", + "FUZZY_MAX_EXPANSIONS", "FUZZY_PREFIX_LENGTH", "FUZZY_TRANSPOSITIONS", + "FUZZY_REWRITE", "FUZZINESS", "LENIENT", "LOW_FREQ_OPERATOR", "MAX_DETERMINIZED_STATES", + "MAX_EXPANSIONS", "MINIMUM_SHOULD_MATCH", "OPERATOR", "PHRASE_SLOP", + "PREFIX_LENGTH", "QUOTE_ANALYZER", "QUOTE_FIELD_SUFFIX", "REWRITE", "SLOP", + "TIE_BREAKER", "TYPE", "ZERO_TERMS_QUERY", "SPAN", "MS", "S", "M", "H", + "W", "Q", "Y", "ID", "INTEGER_LITERAL", "DECIMAL_LITERAL", "ID_DATE_SUFFIX", + "DQUOTA_STRING", "SQUOTA_STRING", "BQUOTA_STRING", "ERROR_RECOGNITION" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public OpenSearchPPLLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "OpenSearchPPLLexer.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + private static final int _serializedATNSegments = 2; + private static final String _serializedATNSegment0 = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\u010f\u0a6f\b\1\4"+ + "\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n"+ + "\4\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ + "\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+ + "\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t"+ + " \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t"+ + "+\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64"+ + "\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t"+ + "=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4"+ + "I\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\t"+ + "T\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_"+ + "\4`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\4k"+ + "\tk\4l\tl\4m\tm\4n\tn\4o\to\4p\tp\4q\tq\4r\tr\4s\ts\4t\tt\4u\tu\4v\tv"+ + "\4w\tw\4x\tx\4y\ty\4z\tz\4{\t{\4|\t|\4}\t}\4~\t~\4\177\t\177\4\u0080\t"+ + "\u0080\4\u0081\t\u0081\4\u0082\t\u0082\4\u0083\t\u0083\4\u0084\t\u0084"+ + "\4\u0085\t\u0085\4\u0086\t\u0086\4\u0087\t\u0087\4\u0088\t\u0088\4\u0089"+ + "\t\u0089\4\u008a\t\u008a\4\u008b\t\u008b\4\u008c\t\u008c\4\u008d\t\u008d"+ + "\4\u008e\t\u008e\4\u008f\t\u008f\4\u0090\t\u0090\4\u0091\t\u0091\4\u0092"+ + "\t\u0092\4\u0093\t\u0093\4\u0094\t\u0094\4\u0095\t\u0095\4\u0096\t\u0096"+ + "\4\u0097\t\u0097\4\u0098\t\u0098\4\u0099\t\u0099\4\u009a\t\u009a\4\u009b"+ + "\t\u009b\4\u009c\t\u009c\4\u009d\t\u009d\4\u009e\t\u009e\4\u009f\t\u009f"+ + "\4\u00a0\t\u00a0\4\u00a1\t\u00a1\4\u00a2\t\u00a2\4\u00a3\t\u00a3\4\u00a4"+ + "\t\u00a4\4\u00a5\t\u00a5\4\u00a6\t\u00a6\4\u00a7\t\u00a7\4\u00a8\t\u00a8"+ + "\4\u00a9\t\u00a9\4\u00aa\t\u00aa\4\u00ab\t\u00ab\4\u00ac\t\u00ac\4\u00ad"+ + "\t\u00ad\4\u00ae\t\u00ae\4\u00af\t\u00af\4\u00b0\t\u00b0\4\u00b1\t\u00b1"+ + "\4\u00b2\t\u00b2\4\u00b3\t\u00b3\4\u00b4\t\u00b4\4\u00b5\t\u00b5\4\u00b6"+ + "\t\u00b6\4\u00b7\t\u00b7\4\u00b8\t\u00b8\4\u00b9\t\u00b9\4\u00ba\t\u00ba"+ + "\4\u00bb\t\u00bb\4\u00bc\t\u00bc\4\u00bd\t\u00bd\4\u00be\t\u00be\4\u00bf"+ + "\t\u00bf\4\u00c0\t\u00c0\4\u00c1\t\u00c1\4\u00c2\t\u00c2\4\u00c3\t\u00c3"+ + "\4\u00c4\t\u00c4\4\u00c5\t\u00c5\4\u00c6\t\u00c6\4\u00c7\t\u00c7\4\u00c8"+ + "\t\u00c8\4\u00c9\t\u00c9\4\u00ca\t\u00ca\4\u00cb\t\u00cb\4\u00cc\t\u00cc"+ + "\4\u00cd\t\u00cd\4\u00ce\t\u00ce\4\u00cf\t\u00cf\4\u00d0\t\u00d0\4\u00d1"+ + "\t\u00d1\4\u00d2\t\u00d2\4\u00d3\t\u00d3\4\u00d4\t\u00d4\4\u00d5\t\u00d5"+ + "\4\u00d6\t\u00d6\4\u00d7\t\u00d7\4\u00d8\t\u00d8\4\u00d9\t\u00d9\4\u00da"+ + "\t\u00da\4\u00db\t\u00db\4\u00dc\t\u00dc\4\u00dd\t\u00dd\4\u00de\t\u00de"+ + "\4\u00df\t\u00df\4\u00e0\t\u00e0\4\u00e1\t\u00e1\4\u00e2\t\u00e2\4\u00e3"+ + "\t\u00e3\4\u00e4\t\u00e4\4\u00e5\t\u00e5\4\u00e6\t\u00e6\4\u00e7\t\u00e7"+ + "\4\u00e8\t\u00e8\4\u00e9\t\u00e9\4\u00ea\t\u00ea\4\u00eb\t\u00eb\4\u00ec"+ + "\t\u00ec\4\u00ed\t\u00ed\4\u00ee\t\u00ee\4\u00ef\t\u00ef\4\u00f0\t\u00f0"+ + "\4\u00f1\t\u00f1\4\u00f2\t\u00f2\4\u00f3\t\u00f3\4\u00f4\t\u00f4\4\u00f5"+ + "\t\u00f5\4\u00f6\t\u00f6\4\u00f7\t\u00f7\4\u00f8\t\u00f8\4\u00f9\t\u00f9"+ + "\4\u00fa\t\u00fa\4\u00fb\t\u00fb\4\u00fc\t\u00fc\4\u00fd\t\u00fd\4\u00fe"+ + "\t\u00fe\4\u00ff\t\u00ff\4\u0100\t\u0100\4\u0101\t\u0101\4\u0102\t\u0102"+ + "\4\u0103\t\u0103\4\u0104\t\u0104\4\u0105\t\u0105\4\u0106\t\u0106\4\u0107"+ + "\t\u0107\4\u0108\t\u0108\4\u0109\t\u0109\4\u010a\t\u010a\4\u010b\t\u010b"+ + "\4\u010c\t\u010c\4\u010d\t\u010d\4\u010e\t\u010e\4\u010f\t\u010f\4\u0110"+ + "\t\u0110\4\u0111\t\u0111\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3"+ + "\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6"+ + "\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3"+ + "\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3"+ + "\f\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3"+ + "\17\3\17\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3"+ + "\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3"+ + "\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3"+ + "\30\3\30\3\30\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3"+ + "\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3"+ + "\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\36\3"+ + "\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\37\3\37\3"+ + "\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \3 \3 \3!\3"+ + "!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3#\3#\3#\3#\3"+ + "#\3#\3#\3#\3#\3#\3$\3$\3$\3$\3$\3$\3$\3$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3"+ + "%\3%\3%\3%\3%\3%\3%\3%\3%\3%\3%\3%\3%\3&\3&\3&\3&\3&\3&\3&\3&\3&\3&\3"+ + "&\3&\3&\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3"+ + "(\3(\3(\3(\3(\3(\3(\3(\3(\3)\3)\3)\3)\3)\3)\3)\3)\3)\3)\3)\3*\3*\3*\3"+ + "*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+\3+\3+\3+\3+\3,\3,\3"+ + ",\3,\3,\3,\3,\3,\3,\3,\3-\3-\3-\3-\3-\3-\3-\3-\3-\3-\3-\3-\3-\3-\3-\3"+ + "-\3-\3-\3-\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3"+ + ".\3.\3.\3.\3.\3/\3/\3/\3/\3/\3\60\3\60\3\60\3\61\3\61\3\61\3\61\3\62\3"+ + "\62\3\62\3\63\3\63\3\63\3\63\3\64\3\64\3\64\3\64\3\65\3\65\3\65\3\65\3"+ + "\65\3\66\3\66\3\66\3\66\3\66\3\66\3\67\3\67\3\67\3\67\3\67\3\67\3\67\3"+ + "8\38\38\38\38\38\38\38\38\39\39\39\39\39\39\39\39\39\3:\3:\3:\3:\3:\3"+ + ":\3:\3:\3:\3:\3:\3:\3;\3;\3;\3;\3;\3;\3;\3;\3;\3;\3;\3;\3<\3<\3<\3<\3"+ + "<\3<\3<\3=\3=\3=\3=\3=\3=\3=\3>\3>\3>\3>\3>\3?\3?\3?\3?\3@\3@\3@\3@\3"+ + "@\3A\3A\3A\3A\3A\3A\3B\3B\3B\3B\3B\3B\3B\3B\3C\3C\3C\3C\3C\3D\3D\3D\3"+ + "D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3D\3E\3E\3E\3E\3E\3E\3E\3"+ + "E\3E\3E\3E\3E\3E\3E\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3"+ + "F\3F\3F\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3G\3H\3H\3H\3"+ + "H\3H\3H\3H\3H\3H\3H\3H\3H\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3J\3J\3"+ + "J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3K\3K\3K\3K\3K\3K\3K\3K\3K\3"+ + "K\3K\3L\3L\3L\3L\3L\3L\3L\3L\3L\3L\3L\3M\3M\3M\3M\3M\3M\3M\3M\3M\3N\3"+ + "N\3N\3N\3N\3N\3N\3N\3N\3N\3N\3O\3O\3O\3O\3O\3O\3O\3O\3O\3O\3P\3P\3P\3"+ + "P\3P\3P\3P\3Q\3Q\3Q\3Q\3Q\3Q\3Q\3Q\3Q\3Q\3Q\3Q\3R\3R\3R\3R\3S\3S\3S\3"+ + "S\3S\3S\3S\3S\3T\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3V\3V\3V\3V\3V\3V\3"+ + "W\3W\3W\3W\3W\3W\3W\3X\3X\3X\3X\3X\3X\3X\3X\3Y\3Y\3Z\3Z\3[\3[\3\\\3\\"+ + "\3]\3]\3^\3^\3_\3_\3_\3`\3`\3`\3a\3a\3a\3b\3b\3c\3c\3d\3d\3e\3e\3f\3f"+ + "\3g\3g\3h\3h\3i\3i\3j\3j\3k\3k\3l\3l\3m\3m\3n\3n\3o\3o\3p\3p\3q\3q\3r"+ + "\3r\3s\3s\3s\3s\3t\3t\3t\3t\3t\3t\3u\3u\3u\3u\3u\3u\3u\3u\3u\3u\3u\3u"+ + "\3u\3u\3u\3v\3v\3v\3v\3v\3v\3w\3w\3w\3w\3w\3w\3w\3w\3w\3w\3w\3w\3x\3x"+ + "\3x\3x\3y\3y\3y\3y\3y\3z\3z\3z\3z\3z\3z\3z\3{\3{\3{\3{\3|\3|\3|\3|\3|"+ + "\3}\3}\3}\3}\3}\3}\3~\3~\3~\3~\3~\3~\3\177\3\177\3\177\3\177\3\177\3\177"+ + "\3\177\3\u0080\3\u0080\3\u0080\3\u0080\3\u0081\3\u0081\3\u0081\3\u0081"+ + "\3\u0081\3\u0081\3\u0082\3\u0082\3\u0082\3\u0082\3\u0082\3\u0082\3\u0082"+ + "\3\u0082\3\u0082\3\u0083\3\u0083\3\u0083\3\u0083\3\u0083\3\u0083\3\u0083"+ + "\3\u0083\3\u0084\3\u0084\3\u0084\3\u0084\3\u0084\3\u0084\3\u0084\3\u0084"+ + "\3\u0084\3\u0084\3\u0084\3\u0084\3\u0085\3\u0085\3\u0085\3\u0085\3\u0085"+ + "\3\u0085\3\u0085\3\u0085\3\u0085\3\u0085\3\u0085\3\u0086\3\u0086\3\u0086"+ + "\3\u0086\3\u0086\3\u0086\3\u0086\3\u0086\3\u0086\3\u0086\3\u0086\3\u0087"+ + "\3\u0087\3\u0087\3\u0087\3\u0087\3\u0087\3\u0088\3\u0088\3\u0088\3\u0088"+ + "\3\u0088\3\u0089\3\u0089\3\u0089\3\u0089\3\u0089\3\u008a\3\u008a\3\u008a"+ + "\3\u008a\3\u008a\3\u008a\3\u008a\3\u008b\3\u008b\3\u008b\3\u008b\3\u008b"+ + "\3\u008b\3\u008b\3\u008b\3\u008b\3\u008c\3\u008c\3\u008c\3\u008c\3\u008c"+ + "\3\u008c\3\u008c\3\u008c\3\u008c\3\u008c\3\u008c\3\u008c\3\u008c\3\u008c"+ + "\3\u008d\3\u008d\3\u008d\3\u008d\3\u008d\3\u008d\3\u008d\3\u008e\3\u008e"+ + "\3\u008e\3\u008e\3\u008e\3\u008e\3\u008e\3\u008e\3\u008e\3\u008e\3\u008e"+ + "\3\u008e\3\u008f\3\u008f\3\u008f\3\u008f\3\u008f\3\u008f\3\u008f\3\u008f"+ + "\3\u0090\3\u0090\3\u0090\3\u0090\3\u0090\3\u0090\3\u0090\3\u0090\3\u0090"+ + "\3\u0091\3\u0091\3\u0091\3\u0091\3\u0091\3\u0091\3\u0091\3\u0091\3\u0091"+ + "\3\u0091\3\u0091\3\u0092\3\u0092\3\u0092\3\u0092\3\u0092\3\u0092\3\u0092"+ + "\3\u0092\3\u0092\3\u0092\3\u0092\3\u0093\3\u0093\3\u0093\3\u0093\3\u0093"+ + "\3\u0094\3\u0094\3\u0094\3\u0094\3\u0094\3\u0094\3\u0094\3\u0094\3\u0094"+ + "\3\u0094\3\u0095\3\u0095\3\u0096\3\u0096\3\u0096\3\u0097\3\u0097\3\u0097"+ + "\3\u0097\3\u0098\3\u0098\3\u0098\3\u0098\3\u0098\3\u0099\3\u0099\3\u0099"+ + "\3\u0099\3\u0099\3\u0099\3\u0099\3\u0099\3\u009a\3\u009a\3\u009a\3\u009a"+ + "\3\u009a\3\u009b\3\u009b\3\u009b\3\u009b\3\u009b\3\u009b\3\u009c\3\u009c"+ + "\3\u009d\3\u009d\3\u009d\3\u009d\3\u009e\3\u009e\3\u009e\3\u009e\3\u009e"+ + "\3\u009e\3\u009f\3\u009f\3\u009f\3\u00a0\3\u00a0\3\u00a0\3\u00a0\3\u00a1"+ + "\3\u00a1\3\u00a1\3\u00a1\3\u00a1\3\u00a1\3\u00a2\3\u00a2\3\u00a2\3\u00a2"+ + "\3\u00a2\3\u00a3\3\u00a3\3\u00a3\3\u00a3\3\u00a4\3\u00a4\3\u00a4\3\u00a5"+ + "\3\u00a5\3\u00a5\3\u00a5\3\u00a6\3\u00a6\3\u00a6\3\u00a6\3\u00a6\3\u00a6"+ + "\3\u00a7\3\u00a7\3\u00a7\3\u00a7\3\u00a7\3\u00a8\3\u00a8\3\u00a8\3\u00a8"+ + "\3\u00a8\3\u00a8\3\u00a9\3\u00a9\3\u00a9\3\u00a9\3\u00a9\3\u00aa\3\u00aa"+ + "\3\u00aa\3\u00aa\3\u00aa\3\u00ab\3\u00ab\3\u00ab\3\u00ab\3\u00ab\3\u00ab"+ + "\3\u00ab\3\u00ab\3\u00ab\3\u00ac\3\u00ac\3\u00ac\3\u00ac\3\u00ac\3\u00ad"+ + "\3\u00ad\3\u00ad\3\u00ad\3\u00ad\3\u00ae\3\u00ae\3\u00ae\3\u00ae\3\u00ae"+ + "\3\u00af\3\u00af\3\u00af\3\u00af\3\u00af\3\u00af\3\u00b0\3\u00b0\3\u00b0"+ + "\3\u00b0\3\u00b1\3\u00b1\3\u00b1\3\u00b1\3\u00b2\3\u00b2\3\u00b2\3\u00b2"+ + "\3\u00b2\3\u00b2\3\u00b2\3\u00b2\3\u00b3\3\u00b3\3\u00b3\3\u00b3\3\u00b3"+ + "\3\u00b3\3\u00b3\3\u00b3\3\u00b4\3\u00b4\3\u00b4\3\u00b4\3\u00b5\3\u00b5"+ + "\3\u00b5\3\u00b5\3\u00b6\3\u00b6\3\u00b6\3\u00b6\3\u00b6\3\u00b6\3\u00b6"+ + "\3\u00b6\3\u00b7\3\u00b7\3\u00b7\3\u00b7\3\u00b7\3\u00b8\3\u00b8\3\u00b8"+ + "\3\u00b8\3\u00b8\3\u00b8\3\u00b8\3\u00b8\3\u00b8\3\u00b9\3\u00b9\3\u00b9"+ + "\3\u00b9\3\u00b9\3\u00b9\3\u00b9\3\u00b9\3\u00b9\3\u00ba\3\u00ba\3\u00ba"+ + "\3\u00ba\3\u00ba\3\u00ba\3\u00ba\3\u00ba\3\u00ba\3\u00ba\3\u00ba\3\u00bb"+ + "\3\u00bb\3\u00bb\3\u00bb\3\u00bb\3\u00bb\3\u00bb\3\u00bb\3\u00bb\3\u00bb"+ + "\3\u00bc\3\u00bc\3\u00bc\3\u00bc\3\u00bc\3\u00bc\3\u00bc\3\u00bc\3\u00bc"+ + "\3\u00bc\3\u00bd\3\u00bd\3\u00bd\3\u00bd\3\u00bd\3\u00bd\3\u00bd\3\u00bd"+ + "\3\u00be\3\u00be\3\u00be\3\u00be\3\u00be\3\u00be\3\u00be\3\u00be\3\u00be"+ + "\3\u00be\3\u00bf\3\u00bf\3\u00bf\3\u00bf\3\u00bf\3\u00bf\3\u00bf\3\u00bf"+ + "\3\u00bf\3\u00bf\3\u00c0\3\u00c0\3\u00c0\3\u00c0\3\u00c0\3\u00c0\3\u00c0"+ + "\3\u00c0\3\u00c1\3\u00c1\3\u00c1\3\u00c1\3\u00c1\3\u00c2\3\u00c2\3\u00c2"+ + "\3\u00c2\3\u00c2\3\u00c2\3\u00c2\3\u00c2\3\u00c2\3\u00c2\3\u00c2\3\u00c2"+ + "\3\u00c3\3\u00c3\3\u00c3\3\u00c3\3\u00c3\3\u00c3\3\u00c3\3\u00c3\3\u00c3"+ + "\3\u00c3\3\u00c4\3\u00c4\3\u00c4\3\u00c4\3\u00c4\3\u00c4\3\u00c4\3\u00c4"+ + "\3\u00c4\3\u00c4\3\u00c4\3\u00c4\3\u00c5\3\u00c5\3\u00c5\3\u00c5\3\u00c5"+ + "\3\u00c5\3\u00c5\3\u00c5\3\u00c6\3\u00c6\3\u00c6\3\u00c6\3\u00c6\3\u00c6"+ + "\3\u00c6\3\u00c7\3\u00c7\3\u00c7\3\u00c7\3\u00c7\3\u00c7\3\u00c7\3\u00c7"+ + "\3\u00c7\3\u00c7\3\u00c8\3\u00c8\3\u00c8\3\u00c8\3\u00c8\3\u00c8\3\u00c9"+ + "\3\u00c9\3\u00c9\3\u00c9\3\u00c9\3\u00c9\3\u00ca\3\u00ca\3\u00ca\3\u00ca"+ + "\3\u00ca\3\u00cb\3\u00cb\3\u00cb\3\u00cc\3\u00cc\3\u00cc\3\u00cc\3\u00cc"+ + "\3\u00cc\3\u00cd\3\u00cd\3\u00cd\3\u00cd\3\u00cd\3\u00cd\3\u00ce\3\u00ce"+ + "\3\u00ce\3\u00ce\3\u00ce\3\u00ce\3\u00ce\3\u00cf\3\u00cf\3\u00cf\3\u00cf"+ + "\3\u00cf\3\u00cf\3\u00cf\3\u00cf\3\u00cf\3\u00cf\3\u00d0\3\u00d0\3\u00d0"+ + "\3\u00d0\3\u00d0\3\u00d0\3\u00d0\3\u00d1\3\u00d1\3\u00d1\3\u00d1\3\u00d1"+ + "\3\u00d1\3\u00d1\3\u00d2\3\u00d2\3\u00d2\3\u00d2\3\u00d2\3\u00d2\3\u00d3"+ + "\3\u00d3\3\u00d3\3\u00d3\3\u00d3\3\u00d4\3\u00d4\3\u00d4\3\u00d4\3\u00d4"+ + "\3\u00d4\3\u00d5\3\u00d5\3\u00d5\3\u00d5\3\u00d5\3\u00d5\3\u00d5\3\u00d6"+ + "\3\u00d6\3\u00d6\3\u00d6\3\u00d6\3\u00d6\3\u00d6\3\u00d6\3\u00d7\3\u00d7"+ + "\3\u00d7\3\u00d7\3\u00d7\3\u00d8\3\u00d8\3\u00d8\3\u00d8\3\u00d8\3\u00d9"+ + "\3\u00d9\3\u00d9\3\u00d9\3\u00d9\3\u00d9\3\u00d9\3\u00da\3\u00da\3\u00da"+ + "\3\u00da\3\u00da\3\u00da\3\u00da\3\u00da\3\u00da\3\u00da\3\u00db\3\u00db"+ + "\3\u00db\3\u00db\3\u00db\3\u00db\3\u00db\3\u00dc\3\u00dc\3\u00dc\3\u00dc"+ + "\3\u00dc\3\u00dc\3\u00dc\3\u00dd\3\u00dd\3\u00dd\3\u00de\3\u00de\3\u00de"+ + "\3\u00de\3\u00de\3\u00de\3\u00df\3\u00df\3\u00df\3\u00df\3\u00df\3\u00df"+ + "\3\u00df\3\u00df\3\u00df\3\u00df\3\u00df\3\u00df\3\u00df\3\u00e0\3\u00e0"+ + "\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0"+ + "\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0\3\u00e0"+ + "\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1"+ + "\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1"+ + "\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e1\3\u00e2\3\u00e2\3\u00e2\3\u00e2"+ + "\3\u00e2\3\u00e2\3\u00e2\3\u00e2\3\u00e2\3\u00e2\3\u00e2\3\u00e2\3\u00e2"+ + "\3\u00e2\3\u00e2\3\u00e2\3\u00e2\3\u00e3\3\u00e3\3\u00e3\3\u00e3\3\u00e3"+ + "\3\u00e3\3\u00e3\3\u00e3\3\u00e3\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4"+ + "\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4"+ + "\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4"+ + "\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e4"+ + "\3\u00e4\3\u00e4\3\u00e4\3\u00e4\3\u00e5\3\u00e5\3\u00e5\3\u00e5\3\u00e5"+ + "\3\u00e5\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6"+ + "\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6\3\u00e6"+ + "\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e7"+ + "\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e7\3\u00e8\3\u00e8\3\u00e8\3\u00e8"+ + "\3\u00e8\3\u00e8\3\u00e8\3\u00e8\3\u00e8\3\u00e8\3\u00e8\3\u00e8\3\u00e8"+ + "\3\u00e8\3\u00e8\3\u00e8\3\u00e8\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9"+ + "\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9"+ + "\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00e9"+ + "\3\u00e9\3\u00e9\3\u00e9\3\u00e9\3\u00ea\3\u00ea\3\u00ea\3\u00ea\3\u00ea"+ + "\3\u00ea\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb"+ + "\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00eb"+ + "\3\u00eb\3\u00eb\3\u00eb\3\u00eb\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec"+ + "\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec"+ + "\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ec\3\u00ed\3\u00ed\3\u00ed"+ + "\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed"+ + "\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed\3\u00ed"+ + "\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ee"+ + "\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ee\3\u00ef\3\u00ef\3\u00ef\3\u00ef"+ + "\3\u00ef\3\u00ef\3\u00ef\3\u00ef\3\u00ef\3\u00ef\3\u00f0\3\u00f0\3\u00f0"+ + "\3\u00f0\3\u00f0\3\u00f0\3\u00f0\3\u00f0\3\u00f1\3\u00f1\3\u00f1\3\u00f1"+ + "\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f1"+ + "\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f1\3\u00f2\3\u00f2\3\u00f2\3\u00f2"+ + "\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2"+ + "\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2\3\u00f2"+ + "\3\u00f2\3\u00f2\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3"+ + "\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f3\3\u00f4"+ + "\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4"+ + "\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4\3\u00f4"+ + "\3\u00f4\3\u00f4\3\u00f5\3\u00f5\3\u00f5\3\u00f5\3\u00f5\3\u00f5\3\u00f5"+ + "\3\u00f5\3\u00f5\3\u00f6\3\u00f6\3\u00f6\3\u00f6\3\u00f6\3\u00f6\3\u00f6"+ + "\3\u00f6\3\u00f6\3\u00f6\3\u00f6\3\u00f6\3\u00f7\3\u00f7\3\u00f7\3\u00f7"+ + "\3\u00f7\3\u00f7\3\u00f7\3\u00f7\3\u00f7\3\u00f7\3\u00f7\3\u00f7\3\u00f7"+ + "\3\u00f7\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8"+ + "\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f8\3\u00f9\3\u00f9"+ + "\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9"+ + "\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00f9\3\u00fa"+ + "\3\u00fa\3\u00fa\3\u00fa\3\u00fa\3\u00fa\3\u00fa\3\u00fa\3\u00fb\3\u00fb"+ + "\3\u00fb\3\u00fb\3\u00fb\3\u00fc\3\u00fc\3\u00fc\3\u00fc\3\u00fc\3\u00fc"+ + "\3\u00fc\3\u00fc\3\u00fc\3\u00fc\3\u00fc\3\u00fc\3\u00fd\3\u00fd\3\u00fd"+ + "\3\u00fd\3\u00fd\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe"+ + "\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe\3\u00fe"+ + "\3\u00fe\3\u00ff\3\u00ff\3\u00ff\3\u00ff\3\u00ff\3\u0100\3\u0100\3\u0100"+ + "\3\u0101\3\u0101\3\u0102\3\u0102\3\u0103\3\u0103\3\u0104\3\u0104\3\u0105"+ + "\3\u0105\3\u0106\3\u0106\3\u0107\3\u0107\3\u0108\6\u0108\u0a19\n\u0108"+ + "\r\u0108\16\u0108\u0a1a\3\u0109\6\u0109\u0a1e\n\u0109\r\u0109\16\u0109"+ + "\u0a1f\5\u0109\u0a22\n\u0109\3\u0109\3\u0109\6\u0109\u0a26\n\u0109\r\u0109"+ + "\16\u0109\u0a27\3\u010a\3\u010a\6\u010a\u0a2c\n\u010a\r\u010a\16\u010a"+ + "\u0a2d\7\u010a\u0a30\n\u010a\f\u010a\16\u010a\u0a33\13\u010a\3\u010b\6"+ + "\u010b\u0a36\n\u010b\r\u010b\16\u010b\u0a37\3\u010b\7\u010b\u0a3b\n\u010b"+ + "\f\u010b\16\u010b\u0a3e\13\u010b\3\u010c\3\u010c\3\u010c\3\u010d\3\u010d"+ + "\3\u010d\3\u010d\3\u010d\3\u010d\7\u010d\u0a49\n\u010d\f\u010d\16\u010d"+ + "\u0a4c\13\u010d\3\u010d\3\u010d\3\u010e\3\u010e\3\u010e\3\u010e\3\u010e"+ + "\3\u010e\7\u010e\u0a56\n\u010e\f\u010e\16\u010e\u0a59\13\u010e\3\u010e"+ + "\3\u010e\3\u010f\3\u010f\3\u010f\3\u010f\3\u010f\3\u010f\7\u010f\u0a63"+ + "\n\u010f\f\u010f\16\u010f\u0a66\13\u010f\3\u010f\3\u010f\3\u0110\3\u0110"+ + "\3\u0111\3\u0111\3\u0111\3\u0111\3\u0a37\2\u0112\3\3\5\4\7\5\t\6\13\7"+ + "\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25"+ + ")\26+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O"+ + ")Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65i\66k\67m8o9q:s;u{?}@\177A\u0081"+ + "B\u0083C\u0085D\u0087E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095"+ + "L\u0097M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9"+ + "V\u00abW\u00adX\u00afY\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd"+ + "`\u00bfa\u00c1b\u00c3c\u00c5d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1"+ + "j\u00d3k\u00d5l\u00d7m\u00d9n\u00dbo\u00ddp\u00dfq\u00e1r\u00e3s\u00e5"+ + "t\u00e7u\u00e9v\u00ebw\u00edx\u00efy\u00f1z\u00f3{\u00f5|\u00f7}\u00f9"+ + "~\u00fb\177\u00fd\u0080\u00ff\u0081\u0101\u0082\u0103\u0083\u0105\u0084"+ + "\u0107\u0085\u0109\u0086\u010b\u0087\u010d\u0088\u010f\u0089\u0111\u008a"+ + "\u0113\u008b\u0115\u008c\u0117\u008d\u0119\u008e\u011b\u008f\u011d\u0090"+ + "\u011f\u0091\u0121\u0092\u0123\u0093\u0125\u0094\u0127\u0095\u0129\u0096"+ + "\u012b\u0097\u012d\u0098\u012f\u0099\u0131\u009a\u0133\u009b\u0135\u009c"+ + "\u0137\u009d\u0139\u009e\u013b\u009f\u013d\u00a0\u013f\u00a1\u0141\u00a2"+ + "\u0143\u00a3\u0145\u00a4\u0147\u00a5\u0149\u00a6\u014b\u00a7\u014d\u00a8"+ + "\u014f\u00a9\u0151\u00aa\u0153\u00ab\u0155\u00ac\u0157\u00ad\u0159\u00ae"+ + "\u015b\u00af\u015d\u00b0\u015f\u00b1\u0161\u00b2\u0163\u00b3\u0165\u00b4"+ + "\u0167\u00b5\u0169\u00b6\u016b\u00b7\u016d\u00b8\u016f\u00b9\u0171\u00ba"+ + "\u0173\u00bb\u0175\u00bc\u0177\u00bd\u0179\u00be\u017b\u00bf\u017d\u00c0"+ + "\u017f\u00c1\u0181\u00c2\u0183\u00c3\u0185\u00c4\u0187\u00c5\u0189\u00c6"+ + "\u018b\u00c7\u018d\u00c8\u018f\u00c9\u0191\u00ca\u0193\u00cb\u0195\u00cc"+ + "\u0197\u00cd\u0199\u00ce\u019b\u00cf\u019d\u00d0\u019f\u00d1\u01a1\u00d2"+ + "\u01a3\u00d3\u01a5\u00d4\u01a7\u00d5\u01a9\u00d6\u01ab\u00d7\u01ad\u00d8"+ + "\u01af\u00d9\u01b1\u00da\u01b3\u00db\u01b5\u00dc\u01b7\u00dd\u01b9\u00de"+ + "\u01bb\u00df\u01bd\u00e0\u01bf\u00e1\u01c1\u00e2\u01c3\u00e3\u01c5\u00e4"+ + "\u01c7\u00e5\u01c9\u00e6\u01cb\u00e7\u01cd\u00e8\u01cf\u00e9\u01d1\u00ea"+ + "\u01d3\u00eb\u01d5\u00ec\u01d7\u00ed\u01d9\u00ee\u01db\u00ef\u01dd\u00f0"+ + "\u01df\u00f1\u01e1\u00f2\u01e3\u00f3\u01e5\u00f4\u01e7\u00f5\u01e9\u00f6"+ + "\u01eb\u00f7\u01ed\u00f8\u01ef\u00f9\u01f1\u00fa\u01f3\u00fb\u01f5\u00fc"+ + "\u01f7\u00fd\u01f9\u00fe\u01fb\u00ff\u01fd\u0100\u01ff\u0101\u0201\u0102"+ + "\u0203\u0103\u0205\u0104\u0207\u0105\u0209\u0106\u020b\u0107\u020d\u0108"+ + "\u020f\u0109\u0211\u010a\u0213\2\u0215\2\u0217\u010b\u0219\u010c\u021b"+ + "\u010d\u021d\u010e\u021f\2\u0221\u010f\3\2\n\3\2/\60\4\2,,\62;\4\2,,B"+ + "\\\7\2,,//\62;C\\aa\4\2$$^^\4\2))^^\4\2^^bb\3\2\62;\2\u0a7c\2\3\3\2\2"+ + "\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3"+ + "\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2"+ + "\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2"+ + "\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2"+ + "\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3"+ + "\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2"+ + "\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2"+ + "W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3"+ + "\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2"+ + "\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2"+ + "}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2"+ + "\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f"+ + "\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2"+ + "\2\2\u0099\3\2\2\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1"+ + "\3\2\2\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9\3\2\2"+ + "\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b3"+ + "\3\2\2\2\2\u00b5\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb\3\2\2"+ + "\2\2\u00bd\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2\2\2\u00c5"+ + "\3\2\2\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd\3\2\2"+ + "\2\2\u00cf\3\2\2\2\2\u00d1\3\2\2\2\2\u00d3\3\2\2\2\2\u00d5\3\2\2\2\2\u00d7"+ + "\3\2\2\2\2\u00d9\3\2\2\2\2\u00db\3\2\2\2\2\u00dd\3\2\2\2\2\u00df\3\2\2"+ + "\2\2\u00e1\3\2\2\2\2\u00e3\3\2\2\2\2\u00e5\3\2\2\2\2\u00e7\3\2\2\2\2\u00e9"+ + "\3\2\2\2\2\u00eb\3\2\2\2\2\u00ed\3\2\2\2\2\u00ef\3\2\2\2\2\u00f1\3\2\2"+ + "\2\2\u00f3\3\2\2\2\2\u00f5\3\2\2\2\2\u00f7\3\2\2\2\2\u00f9\3\2\2\2\2\u00fb"+ + "\3\2\2\2\2\u00fd\3\2\2\2\2\u00ff\3\2\2\2\2\u0101\3\2\2\2\2\u0103\3\2\2"+ + "\2\2\u0105\3\2\2\2\2\u0107\3\2\2\2\2\u0109\3\2\2\2\2\u010b\3\2\2\2\2\u010d"+ + "\3\2\2\2\2\u010f\3\2\2\2\2\u0111\3\2\2\2\2\u0113\3\2\2\2\2\u0115\3\2\2"+ + "\2\2\u0117\3\2\2\2\2\u0119\3\2\2\2\2\u011b\3\2\2\2\2\u011d\3\2\2\2\2\u011f"+ + "\3\2\2\2\2\u0121\3\2\2\2\2\u0123\3\2\2\2\2\u0125\3\2\2\2\2\u0127\3\2\2"+ + "\2\2\u0129\3\2\2\2\2\u012b\3\2\2\2\2\u012d\3\2\2\2\2\u012f\3\2\2\2\2\u0131"+ + "\3\2\2\2\2\u0133\3\2\2\2\2\u0135\3\2\2\2\2\u0137\3\2\2\2\2\u0139\3\2\2"+ + "\2\2\u013b\3\2\2\2\2\u013d\3\2\2\2\2\u013f\3\2\2\2\2\u0141\3\2\2\2\2\u0143"+ + "\3\2\2\2\2\u0145\3\2\2\2\2\u0147\3\2\2\2\2\u0149\3\2\2\2\2\u014b\3\2\2"+ + "\2\2\u014d\3\2\2\2\2\u014f\3\2\2\2\2\u0151\3\2\2\2\2\u0153\3\2\2\2\2\u0155"+ + "\3\2\2\2\2\u0157\3\2\2\2\2\u0159\3\2\2\2\2\u015b\3\2\2\2\2\u015d\3\2\2"+ + "\2\2\u015f\3\2\2\2\2\u0161\3\2\2\2\2\u0163\3\2\2\2\2\u0165\3\2\2\2\2\u0167"+ + "\3\2\2\2\2\u0169\3\2\2\2\2\u016b\3\2\2\2\2\u016d\3\2\2\2\2\u016f\3\2\2"+ + "\2\2\u0171\3\2\2\2\2\u0173\3\2\2\2\2\u0175\3\2\2\2\2\u0177\3\2\2\2\2\u0179"+ + "\3\2\2\2\2\u017b\3\2\2\2\2\u017d\3\2\2\2\2\u017f\3\2\2\2\2\u0181\3\2\2"+ + "\2\2\u0183\3\2\2\2\2\u0185\3\2\2\2\2\u0187\3\2\2\2\2\u0189\3\2\2\2\2\u018b"+ + "\3\2\2\2\2\u018d\3\2\2\2\2\u018f\3\2\2\2\2\u0191\3\2\2\2\2\u0193\3\2\2"+ + "\2\2\u0195\3\2\2\2\2\u0197\3\2\2\2\2\u0199\3\2\2\2\2\u019b\3\2\2\2\2\u019d"+ + "\3\2\2\2\2\u019f\3\2\2\2\2\u01a1\3\2\2\2\2\u01a3\3\2\2\2\2\u01a5\3\2\2"+ + "\2\2\u01a7\3\2\2\2\2\u01a9\3\2\2\2\2\u01ab\3\2\2\2\2\u01ad\3\2\2\2\2\u01af"+ + "\3\2\2\2\2\u01b1\3\2\2\2\2\u01b3\3\2\2\2\2\u01b5\3\2\2\2\2\u01b7\3\2\2"+ + "\2\2\u01b9\3\2\2\2\2\u01bb\3\2\2\2\2\u01bd\3\2\2\2\2\u01bf\3\2\2\2\2\u01c1"+ + "\3\2\2\2\2\u01c3\3\2\2\2\2\u01c5\3\2\2\2\2\u01c7\3\2\2\2\2\u01c9\3\2\2"+ + "\2\2\u01cb\3\2\2\2\2\u01cd\3\2\2\2\2\u01cf\3\2\2\2\2\u01d1\3\2\2\2\2\u01d3"+ + "\3\2\2\2\2\u01d5\3\2\2\2\2\u01d7\3\2\2\2\2\u01d9\3\2\2\2\2\u01db\3\2\2"+ + "\2\2\u01dd\3\2\2\2\2\u01df\3\2\2\2\2\u01e1\3\2\2\2\2\u01e3\3\2\2\2\2\u01e5"+ + "\3\2\2\2\2\u01e7\3\2\2\2\2\u01e9\3\2\2\2\2\u01eb\3\2\2\2\2\u01ed\3\2\2"+ + "\2\2\u01ef\3\2\2\2\2\u01f1\3\2\2\2\2\u01f3\3\2\2\2\2\u01f5\3\2\2\2\2\u01f7"+ + "\3\2\2\2\2\u01f9\3\2\2\2\2\u01fb\3\2\2\2\2\u01fd\3\2\2\2\2\u01ff\3\2\2"+ + "\2\2\u0201\3\2\2\2\2\u0203\3\2\2\2\2\u0205\3\2\2\2\2\u0207\3\2\2\2\2\u0209"+ + "\3\2\2\2\2\u020b\3\2\2\2\2\u020d\3\2\2\2\2\u020f\3\2\2\2\2\u0211\3\2\2"+ + "\2\2\u0217\3\2\2\2\2\u0219\3\2\2\2\2\u021b\3\2\2\2\2\u021d\3\2\2\2\2\u0221"+ + "\3\2\2\2\3\u0223\3\2\2\2\5\u022a\3\2\2\2\7\u022f\3\2\2\2\t\u0235\3\2\2"+ + "\2\13\u023c\3\2\2\2\r\u0243\3\2\2\2\17\u0249\3\2\2\2\21\u024f\3\2\2\2"+ + "\23\u0254\3\2\2\2\25\u0259\3\2\2\2\27\u025e\3\2\2\2\31\u0262\3\2\2\2\33"+ + "\u0267\3\2\2\2\35\u026d\3\2\2\2\37\u0274\3\2\2\2!\u0277\3\2\2\2#\u027a"+ + "\3\2\2\2%\u027d\3\2\2\2\'\u0284\3\2\2\2)\u028a\3\2\2\2+\u028c\3\2\2\2"+ + "-\u0291\3\2\2\2/\u0298\3\2\2\2\61\u029d\3\2\2\2\63\u02a1\3\2\2\2\65\u02a4"+ + "\3\2\2\2\67\u02a8\3\2\2\29\u02b2\3\2\2\2;\u02be\3\2\2\2=\u02d0\3\2\2\2"+ + "?\u02db\3\2\2\2A\u02e2\3\2\2\2C\u02e8\3\2\2\2E\u02f2\3\2\2\2G\u02fd\3"+ + "\2\2\2I\u030b\3\2\2\2K\u031b\3\2\2\2M\u0328\3\2\2\2O\u0334\3\2\2\2Q\u0341"+ + "\3\2\2\2S\u034c\3\2\2\2U\u0359\3\2\2\2W\u0364\3\2\2\2Y\u036e\3\2\2\2["+ + "\u0381\3\2\2\2]\u0399\3\2\2\2_\u039e\3\2\2\2a\u03a1\3\2\2\2c\u03a5\3\2"+ + "\2\2e\u03a8\3\2\2\2g\u03ac\3\2\2\2i\u03b0\3\2\2\2k\u03b5\3\2\2\2m\u03bb"+ + "\3\2\2\2o\u03c2\3\2\2\2q\u03cb\3\2\2\2s\u03d4\3\2\2\2u\u03e0\3\2\2\2w"+ + "\u03ec\3\2\2\2y\u03f3\3\2\2\2{\u03fa\3\2\2\2}\u03ff\3\2\2\2\177\u0403"+ + "\3\2\2\2\u0081\u0408\3\2\2\2\u0083\u040e\3\2\2\2\u0085\u0416\3\2\2\2\u0087"+ + "\u041b\3\2\2\2\u0089\u042e\3\2\2\2\u008b\u0441\3\2\2\2\u008d\u044f\3\2"+ + "\2\2\u008f\u0460\3\2\2\2\u0091\u046c\3\2\2\2\u0093\u0478\3\2\2\2\u0095"+ + "\u0488\3\2\2\2\u0097\u0493\3\2\2\2\u0099\u049e\3\2\2\2\u009b\u04a7\3\2"+ + "\2\2\u009d\u04b2\3\2\2\2\u009f\u04bc\3\2\2\2\u00a1\u04c3\3\2\2\2\u00a3"+ + "\u04cf\3\2\2\2\u00a5\u04d3\3\2\2\2\u00a7\u04db\3\2\2\2\u00a9\u04e2\3\2"+ + "\2\2\u00ab\u04e7\3\2\2\2\u00ad\u04ed\3\2\2\2\u00af\u04f4\3\2\2\2\u00b1"+ + "\u04fc\3\2\2\2\u00b3\u04fe\3\2\2\2\u00b5\u0500\3\2\2\2\u00b7\u0502\3\2"+ + "\2\2\u00b9\u0504\3\2\2\2\u00bb\u0506\3\2\2\2\u00bd\u0508\3\2\2\2\u00bf"+ + "\u050b\3\2\2\2\u00c1\u050e\3\2\2\2\u00c3\u0511\3\2\2\2\u00c5\u0513\3\2"+ + "\2\2\u00c7\u0515\3\2\2\2\u00c9\u0517\3\2\2\2\u00cb\u0519\3\2\2\2\u00cd"+ + "\u051b\3\2\2\2\u00cf\u051d\3\2\2\2\u00d1\u051f\3\2\2\2\u00d3\u0521\3\2"+ + "\2\2\u00d5\u0523\3\2\2\2\u00d7\u0525\3\2\2\2\u00d9\u0527\3\2\2\2\u00db"+ + "\u0529\3\2\2\2\u00dd\u052b\3\2\2\2\u00df\u052d\3\2\2\2\u00e1\u052f\3\2"+ + "\2\2\u00e3\u0531\3\2\2\2\u00e5\u0533\3\2\2\2\u00e7\u0537\3\2\2\2\u00e9"+ + "\u053d\3\2\2\2\u00eb\u054c\3\2\2\2\u00ed\u0552\3\2\2\2\u00ef\u055e\3\2"+ + "\2\2\u00f1\u0562\3\2\2\2\u00f3\u0567\3\2\2\2\u00f5\u056e\3\2\2\2\u00f7"+ + "\u0572\3\2\2\2\u00f9\u0577\3\2\2\2\u00fb\u057d\3\2\2\2\u00fd\u0583\3\2"+ + "\2\2\u00ff\u058a\3\2\2\2\u0101\u058e\3\2\2\2\u0103\u0594\3\2\2\2\u0105"+ + "\u059d\3\2\2\2\u0107\u05a5\3\2\2\2\u0109\u05b1\3\2\2\2\u010b\u05bc\3\2"+ + "\2\2\u010d\u05c7\3\2\2\2\u010f\u05cd\3\2\2\2\u0111\u05d2\3\2\2\2\u0113"+ + "\u05d7\3\2\2\2\u0115\u05de\3\2\2\2\u0117\u05e7\3\2\2\2\u0119\u05f5\3\2"+ + "\2\2\u011b\u05fc\3\2\2\2\u011d\u0608\3\2\2\2\u011f\u0610\3\2\2\2\u0121"+ + "\u0619\3\2\2\2\u0123\u0624\3\2\2\2\u0125\u062f\3\2\2\2\u0127\u0634\3\2"+ + "\2\2\u0129\u063e\3\2\2\2\u012b\u0640\3\2\2\2\u012d\u0643\3\2\2\2\u012f"+ + "\u0647\3\2\2\2\u0131\u064c\3\2\2\2\u0133\u0654\3\2\2\2\u0135\u0659\3\2"+ + "\2\2\u0137\u065f\3\2\2\2\u0139\u0661\3\2\2\2\u013b\u0665\3\2\2\2\u013d"+ + "\u066b\3\2\2\2\u013f\u066e\3\2\2\2\u0141\u0672\3\2\2\2\u0143\u0678\3\2"+ + "\2\2\u0145\u067d\3\2\2\2\u0147\u0681\3\2\2\2\u0149\u0684\3\2\2\2\u014b"+ + "\u0688\3\2\2\2\u014d\u068e\3\2\2\2\u014f\u0693\3\2\2\2\u0151\u0699\3\2"+ + "\2\2\u0153\u069e\3\2\2\2\u0155\u06a3\3\2\2\2\u0157\u06ac\3\2\2\2\u0159"+ + "\u06b1\3\2\2\2\u015b\u06b6\3\2\2\2\u015d\u06bb\3\2\2\2\u015f\u06c1\3\2"+ + "\2\2\u0161\u06c5\3\2\2\2\u0163\u06c9\3\2\2\2\u0165\u06d1\3\2\2\2\u0167"+ + "\u06d9\3\2\2\2\u0169\u06dd\3\2\2\2\u016b\u06e1\3\2\2\2\u016d\u06e9\3\2"+ + "\2\2\u016f\u06ee\3\2\2\2\u0171\u06f7\3\2\2\2\u0173\u0700\3\2\2\2\u0175"+ + "\u070b\3\2\2\2\u0177\u0715\3\2\2\2\u0179\u071f\3\2\2\2\u017b\u0727\3\2"+ + "\2\2\u017d\u0731\3\2\2\2\u017f\u073b\3\2\2\2\u0181\u0743\3\2\2\2\u0183"+ + "\u0748\3\2\2\2\u0185\u0754\3\2\2\2\u0187\u075e\3\2\2\2\u0189\u076a\3\2"+ + "\2\2\u018b\u0772\3\2\2\2\u018d\u0779\3\2\2\2\u018f\u0783\3\2\2\2\u0191"+ + "\u0789\3\2\2\2\u0193\u078f\3\2\2\2\u0195\u0794\3\2\2\2\u0197\u0797\3\2"+ + "\2\2\u0199\u079d\3\2\2\2\u019b\u07a3\3\2\2\2\u019d\u07aa\3\2\2\2\u019f"+ + "\u07b4\3\2\2\2\u01a1\u07bb\3\2\2\2\u01a3\u07c2\3\2\2\2\u01a5\u07c8\3\2"+ + "\2\2\u01a7\u07cd\3\2\2\2\u01a9\u07d3\3\2\2\2\u01ab\u07da\3\2\2\2\u01ad"+ + "\u07e2\3\2\2\2\u01af\u07e7\3\2\2\2\u01b1\u07ec\3\2\2\2\u01b3\u07f3\3\2"+ + "\2\2\u01b5\u07fd\3\2\2\2\u01b7\u0804\3\2\2\2\u01b9\u080b\3\2\2\2\u01bb"+ + "\u080e\3\2\2\2\u01bd\u0814\3\2\2\2\u01bf\u0821\3\2\2\2\u01c1\u0835\3\2"+ + "\2\2\u01c3\u084c\3\2\2\2\u01c5\u085d\3\2\2\2\u01c7\u0866\3\2\2\2\u01c9"+ + "\u088a\3\2\2\2\u01cb\u0890\3\2\2\2\u01cd\u08a1\3\2\2\2\u01cf\u08af\3\2"+ + "\2\2\u01d1\u08c0\3\2\2\2\u01d3\u08db\3\2\2\2\u01d5\u08e1\3\2\2\2\u01d7"+ + "\u08f6\3\2\2\2\u01d9\u090a\3\2\2\2\u01db\u091f\3\2\2\2\u01dd\u092d\3\2"+ + "\2\2\u01df\u0937\3\2\2\2\u01e1\u093f\3\2\2\2\u01e3\u0951\3\2\2\2\u01e5"+ + "\u0969\3\2\2\2\u01e7\u0978\3\2\2\2\u01e9\u098d\3\2\2\2\u01eb\u0996\3\2"+ + "\2\2\u01ed\u09a2\3\2\2\2\u01ef\u09b0\3\2\2\2\u01f1\u09bf\3\2\2\2\u01f3"+ + "\u09d2\3\2\2\2\u01f5\u09da\3\2\2\2\u01f7\u09df\3\2\2\2\u01f9\u09eb\3\2"+ + "\2\2\u01fb\u09f0\3\2\2\2\u01fd\u0a01\3\2\2\2\u01ff\u0a06\3\2\2\2\u0201"+ + "\u0a09\3\2\2\2\u0203\u0a0b\3\2\2\2\u0205\u0a0d\3\2\2\2\u0207\u0a0f\3\2"+ + "\2\2\u0209\u0a11\3\2\2\2\u020b\u0a13\3\2\2\2\u020d\u0a15\3\2\2\2\u020f"+ + "\u0a18\3\2\2\2\u0211\u0a21\3\2\2\2\u0213\u0a31\3\2\2\2\u0215\u0a35\3\2"+ + "\2\2\u0217\u0a3f\3\2\2\2\u0219\u0a42\3\2\2\2\u021b\u0a4f\3\2\2\2\u021d"+ + "\u0a5c\3\2\2\2\u021f\u0a69\3\2\2\2\u0221\u0a6b\3\2\2\2\u0223\u0224\7U"+ + "\2\2\u0224\u0225\7G\2\2\u0225\u0226\7C\2\2\u0226\u0227\7T\2\2\u0227\u0228"+ + "\7E\2\2\u0228\u0229\7J\2\2\u0229\4\3\2\2\2\u022a\u022b\7H\2\2\u022b\u022c"+ + "\7T\2\2\u022c\u022d\7Q\2\2\u022d\u022e\7O\2\2\u022e\6\3\2\2\2\u022f\u0230"+ + "\7Y\2\2\u0230\u0231\7J\2\2\u0231\u0232\7G\2\2\u0232\u0233\7T\2\2\u0233"+ + "\u0234\7G\2\2\u0234\b\3\2\2\2\u0235\u0236\7H\2\2\u0236\u0237\7K\2\2\u0237"+ + "\u0238\7G\2\2\u0238\u0239\7N\2\2\u0239\u023a\7F\2\2\u023a\u023b\7U\2\2"+ + "\u023b\n\3\2\2\2\u023c\u023d\7T\2\2\u023d\u023e\7G\2\2\u023e\u023f\7P"+ + "\2\2\u023f\u0240\7C\2\2\u0240\u0241\7O\2\2\u0241\u0242\7G\2\2\u0242\f"+ + "\3\2\2\2\u0243\u0244\7U\2\2\u0244\u0245\7V\2\2\u0245\u0246\7C\2\2\u0246"+ + "\u0247\7V\2\2\u0247\u0248\7U\2\2\u0248\16\3\2\2\2\u0249\u024a\7F\2\2\u024a"+ + "\u024b\7G\2\2\u024b\u024c\7F\2\2\u024c\u024d\7W\2\2\u024d\u024e\7R\2\2"+ + "\u024e\20\3\2\2\2\u024f\u0250\7U\2\2\u0250\u0251\7Q\2\2\u0251\u0252\7"+ + "T\2\2\u0252\u0253\7V\2\2\u0253\22\3\2\2\2\u0254\u0255\7G\2\2\u0255\u0256"+ + "\7X\2\2\u0256\u0257\7C\2\2\u0257\u0258\7N\2\2\u0258\24\3\2\2\2\u0259\u025a"+ + "\7J\2\2\u025a\u025b\7G\2\2\u025b\u025c\7C\2\2\u025c\u025d\7F\2\2\u025d"+ + "\26\3\2\2\2\u025e\u025f\7V\2\2\u025f\u0260\7Q\2\2\u0260\u0261\7R\2\2\u0261"+ + "\30\3\2\2\2\u0262\u0263\7T\2\2\u0263\u0264\7C\2\2\u0264\u0265\7T\2\2\u0265"+ + "\u0266\7G\2\2\u0266\32\3\2\2\2\u0267\u0268\7R\2\2\u0268\u0269\7C\2\2\u0269"+ + "\u026a\7T\2\2\u026a\u026b\7U\2\2\u026b\u026c\7G\2\2\u026c\34\3\2\2\2\u026d"+ + "\u026e\7M\2\2\u026e\u026f\7O\2\2\u026f\u0270\7G\2\2\u0270\u0271\7C\2\2"+ + "\u0271\u0272\7P\2\2\u0272\u0273\7U\2\2\u0273\36\3\2\2\2\u0274\u0275\7"+ + "C\2\2\u0275\u0276\7F\2\2\u0276 \3\2\2\2\u0277\u0278\7C\2\2\u0278\u0279"+ + "\7U\2\2\u0279\"\3\2\2\2\u027a\u027b\7D\2\2\u027b\u027c\7[\2\2\u027c$\3"+ + "\2\2\2\u027d\u027e\7U\2\2\u027e\u027f\7Q\2\2\u027f\u0280\7W\2\2\u0280"+ + "\u0281\7T\2\2\u0281\u0282\7E\2\2\u0282\u0283\7G\2\2\u0283&\3\2\2\2\u0284"+ + "\u0285\7K\2\2\u0285\u0286\7P\2\2\u0286\u0287\7F\2\2\u0287\u0288\7G\2\2"+ + "\u0288\u0289\7Z\2\2\u0289(\3\2\2\2\u028a\u028b\7F\2\2\u028b*\3\2\2\2\u028c"+ + "\u028d\7F\2\2\u028d\u028e\7G\2\2\u028e\u028f\7U\2\2\u028f\u0290\7E\2\2"+ + "\u0290,\3\2\2\2\u0291\u0292\7U\2\2\u0292\u0293\7Q\2\2\u0293\u0294\7T\2"+ + "\2\u0294\u0295\7V\2\2\u0295\u0296\7D\2\2\u0296\u0297\7[\2\2\u0297.\3\2"+ + "\2\2\u0298\u0299\7C\2\2\u0299\u029a\7W\2\2\u029a\u029b\7V\2\2\u029b\u029c"+ + "\7Q\2\2\u029c\60\3\2\2\2\u029d\u029e\7U\2\2\u029e\u029f\7V\2\2\u029f\u02a0"+ + "\7T\2\2\u02a0\62\3\2\2\2\u02a1\u02a2\7K\2\2\u02a2\u02a3\7R\2\2\u02a3\64"+ + "\3\2\2\2\u02a4\u02a5\7P\2\2\u02a5\u02a6\7W\2\2\u02a6\u02a7\7O\2\2\u02a7"+ + "\66\3\2\2\2\u02a8\u02a9\7M\2\2\u02a9\u02aa\7G\2\2\u02aa\u02ab\7G\2\2\u02ab"+ + "\u02ac\7R\2\2\u02ac\u02ad\7G\2\2\u02ad\u02ae\7O\2\2\u02ae\u02af\7R\2\2"+ + "\u02af\u02b0\7V\2\2\u02b0\u02b1\7[\2\2\u02b18\3\2\2\2\u02b2\u02b3\7E\2"+ + "\2\u02b3\u02b4\7Q\2\2\u02b4\u02b5\7P\2\2\u02b5\u02b6\7U\2\2\u02b6\u02b7"+ + "\7G\2\2\u02b7\u02b8\7E\2\2\u02b8\u02b9\7W\2\2\u02b9\u02ba\7V\2\2\u02ba"+ + "\u02bb\7K\2\2\u02bb\u02bc\7X\2\2\u02bc\u02bd\7G\2\2\u02bd:\3\2\2\2\u02be"+ + "\u02bf\7F\2\2\u02bf\u02c0\7G\2\2\u02c0\u02c1\7F\2\2\u02c1\u02c2\7W\2\2"+ + "\u02c2\u02c3\7R\2\2\u02c3\u02c4\7a\2\2\u02c4\u02c5\7U\2\2\u02c5\u02c6"+ + "\7R\2\2\u02c6\u02c7\7N\2\2\u02c7\u02c8\7K\2\2\u02c8\u02c9\7V\2\2\u02c9"+ + "\u02ca\7X\2\2\u02ca\u02cb\7C\2\2\u02cb\u02cc\7N\2\2\u02cc\u02cd\7W\2\2"+ + "\u02cd\u02ce\7G\2\2\u02ce\u02cf\7U\2\2\u02cf<\3\2\2\2\u02d0\u02d1\7R\2"+ + "\2\u02d1\u02d2\7C\2\2\u02d2\u02d3\7T\2\2\u02d3\u02d4\7V\2\2\u02d4\u02d5"+ + "\7K\2\2\u02d5\u02d6\7V\2\2\u02d6\u02d7\7K\2\2\u02d7\u02d8\7Q\2\2\u02d8"+ + "\u02d9\7P\2\2\u02d9\u02da\7U\2\2\u02da>\3\2\2\2\u02db\u02dc\7C\2\2\u02dc"+ + "\u02dd\7N\2\2\u02dd\u02de\7N\2\2\u02de\u02df\7P\2\2\u02df\u02e0\7W\2\2"+ + "\u02e0\u02e1\7O\2\2\u02e1@\3\2\2\2\u02e2\u02e3\7F\2\2\u02e3\u02e4\7G\2"+ + "\2\u02e4\u02e5\7N\2\2\u02e5\u02e6\7K\2\2\u02e6\u02e7\7O\2\2\u02e7B\3\2"+ + "\2\2\u02e8\u02e9\7E\2\2\u02e9\u02ea\7G\2\2\u02ea\u02eb\7P\2\2\u02eb\u02ec"+ + "\7V\2\2\u02ec\u02ed\7T\2\2\u02ed\u02ee\7Q\2\2\u02ee\u02ef\7K\2\2\u02ef"+ + "\u02f0\7F\2\2\u02f0\u02f1\7U\2\2\u02f1D\3\2\2\2\u02f2\u02f3\7K\2\2\u02f3"+ + "\u02f4\7V\2\2\u02f4\u02f5\7G\2\2\u02f5\u02f6\7T\2\2\u02f6\u02f7\7C\2\2"+ + "\u02f7\u02f8\7V\2\2\u02f8\u02f9\7K\2\2\u02f9\u02fa\7Q\2\2\u02fa\u02fb"+ + "\7P\2\2\u02fb\u02fc\7U\2\2\u02fcF\3\2\2\2\u02fd\u02fe\7F\2\2\u02fe\u02ff"+ + "\7K\2\2\u02ff\u0300\7U\2\2\u0300\u0301\7V\2\2\u0301\u0302\7C\2\2\u0302"+ + "\u0303\7P\2\2\u0303\u0304\7E\2\2\u0304\u0305\7G\2\2\u0305\u0306\7a\2\2"+ + "\u0306\u0307\7V\2\2\u0307\u0308\7[\2\2\u0308\u0309\7R\2\2\u0309\u030a"+ + "\7G\2\2\u030aH\3\2\2\2\u030b\u030c\7P\2\2\u030c\u030d\7W\2\2\u030d\u030e"+ + "\7O\2\2\u030e\u030f\7D\2\2\u030f\u0310\7G\2\2\u0310\u0311\7T\2\2\u0311"+ + "\u0312\7a\2\2\u0312\u0313\7Q\2\2\u0313\u0314\7H\2\2\u0314\u0315\7a\2\2"+ + "\u0315\u0316\7V\2\2\u0316\u0317\7T\2\2\u0317\u0318\7G\2\2\u0318\u0319"+ + "\7G\2\2\u0319\u031a\7U\2\2\u031aJ\3\2\2\2\u031b\u031c\7U\2\2\u031c\u031d"+ + "\7J\2\2\u031d\u031e\7K\2\2\u031e\u031f\7P\2\2\u031f\u0320\7I\2\2\u0320"+ + "\u0321\7N\2\2\u0321\u0322\7G\2\2\u0322\u0323\7a\2\2\u0323\u0324\7U\2\2"+ + "\u0324\u0325\7K\2\2\u0325\u0326\7\\\2\2\u0326\u0327\7G\2\2\u0327L\3\2"+ + "\2\2\u0328\u0329\7U\2\2\u0329\u032a\7C\2\2\u032a\u032b\7O\2\2\u032b\u032c"+ + "\7R\2\2\u032c\u032d\7N\2\2\u032d\u032e\7G\2\2\u032e\u032f\7a\2\2\u032f"+ + "\u0330\7U\2\2\u0330\u0331\7K\2\2\u0331\u0332\7\\\2\2\u0332\u0333\7G\2"+ + "\2\u0333N\3\2\2\2\u0334\u0335\7Q\2\2\u0335\u0336\7W\2\2\u0336\u0337\7"+ + "V\2\2\u0337\u0338\7R\2\2\u0338\u0339\7W\2\2\u0339\u033a\7V\2\2\u033a\u033b"+ + "\7a\2\2\u033b\u033c\7C\2\2\u033c\u033d\7H\2\2\u033d\u033e\7V\2\2\u033e"+ + "\u033f\7G\2\2\u033f\u0340\7T\2\2\u0340P\3\2\2\2\u0341\u0342\7V\2\2\u0342"+ + "\u0343\7K\2\2\u0343\u0344\7O\2\2\u0344\u0345\7G\2\2\u0345\u0346\7a\2\2"+ + "\u0346\u0347\7F\2\2\u0347\u0348\7G\2\2\u0348\u0349\7E\2\2\u0349\u034a"+ + "\7C\2\2\u034a\u034b\7[\2\2\u034bR\3\2\2\2\u034c\u034d\7C\2\2\u034d\u034e"+ + "\7P\2\2\u034e\u034f\7Q\2\2\u034f\u0350\7O\2\2\u0350\u0351\7C\2\2\u0351"+ + "\u0352\7N\2\2\u0352\u0353\7[\2\2\u0353\u0354\7a\2\2\u0354\u0355\7T\2\2"+ + "\u0355\u0356\7C\2\2\u0356\u0357\7V\2\2\u0357\u0358\7G\2\2\u0358T\3\2\2"+ + "\2\u0359\u035a\7V\2\2\u035a\u035b\7K\2\2\u035b\u035c\7O\2\2\u035c\u035d"+ + "\7G\2\2\u035d\u035e\7a\2\2\u035e\u035f\7H\2\2\u035f\u0360\7K\2\2\u0360"+ + "\u0361\7G\2\2\u0361\u0362\7N\2\2\u0362\u0363\7F\2\2\u0363V\3\2\2\2\u0364"+ + "\u0365\7V\2\2\u0365\u0366\7K\2\2\u0366\u0367\7O\2\2\u0367\u0368\7G\2\2"+ + "\u0368\u0369\7a\2\2\u0369\u036a\7\\\2\2\u036a\u036b\7Q\2\2\u036b\u036c"+ + "\7P\2\2\u036c\u036d\7G\2\2\u036dX\3\2\2\2\u036e\u036f\7V\2\2\u036f\u0370"+ + "\7T\2\2\u0370\u0371\7C\2\2\u0371\u0372\7K\2\2\u0372\u0373\7P\2\2\u0373"+ + "\u0374\7K\2\2\u0374\u0375\7P\2\2\u0375\u0376\7I\2\2\u0376\u0377\7a\2\2"+ + "\u0377\u0378\7F\2\2\u0378\u0379\7C\2\2\u0379\u037a\7V\2\2\u037a\u037b"+ + "\7C\2\2\u037b\u037c\7a\2\2\u037c\u037d\7U\2\2\u037d\u037e\7K\2\2\u037e"+ + "\u037f\7\\\2\2\u037f\u0380\7G\2\2\u0380Z\3\2\2\2\u0381\u0382\7C\2\2\u0382"+ + "\u0383\7P\2\2\u0383\u0384\7Q\2\2\u0384\u0385\7O\2\2\u0385\u0386\7C\2\2"+ + "\u0386\u0387\7N\2\2\u0387\u0388\7[\2\2\u0388\u0389\7a\2\2\u0389\u038a"+ + "\7U\2\2\u038a\u038b\7E\2\2\u038b\u038c\7Q\2\2\u038c\u038d\7T\2\2\u038d"+ + "\u038e\7G\2\2\u038e\u038f\7a\2\2\u038f\u0390\7V\2\2\u0390\u0391\7J\2\2"+ + "\u0391\u0392\7T\2\2\u0392\u0393\7G\2\2\u0393\u0394\7U\2\2\u0394\u0395"+ + "\7J\2\2\u0395\u0396\7Q\2\2\u0396\u0397\7N\2\2\u0397\u0398\7F\2\2\u0398"+ + "\\\3\2\2\2\u0399\u039a\7E\2\2\u039a\u039b\7C\2\2\u039b\u039c\7U\2\2\u039c"+ + "\u039d\7G\2\2\u039d^\3\2\2\2\u039e\u039f\7K\2\2\u039f\u03a0\7P\2\2\u03a0"+ + "`\3\2\2\2\u03a1\u03a2\7P\2\2\u03a2\u03a3\7Q\2\2\u03a3\u03a4\7V\2\2\u03a4"+ + "b\3\2\2\2\u03a5\u03a6\7Q\2\2\u03a6\u03a7\7T\2\2\u03a7d\3\2\2\2\u03a8\u03a9"+ + "\7C\2\2\u03a9\u03aa\7P\2\2\u03aa\u03ab\7F\2\2\u03abf\3\2\2\2\u03ac\u03ad"+ + "\7Z\2\2\u03ad\u03ae\7Q\2\2\u03ae\u03af\7T\2\2\u03afh\3\2\2\2\u03b0\u03b1"+ + "\7V\2\2\u03b1\u03b2\7T\2\2\u03b2\u03b3\7W\2\2\u03b3\u03b4\7G\2\2\u03b4"+ + "j\3\2\2\2\u03b5\u03b6\7H\2\2\u03b6\u03b7\7C\2\2\u03b7\u03b8\7N\2\2\u03b8"+ + "\u03b9\7U\2\2\u03b9\u03ba\7G\2\2\u03bal\3\2\2\2\u03bb\u03bc\7T\2\2\u03bc"+ + "\u03bd\7G\2\2\u03bd\u03be\7I\2\2\u03be\u03bf\7G\2\2\u03bf\u03c0\7Z\2\2"+ + "\u03c0\u03c1\7R\2\2\u03c1n\3\2\2\2\u03c2\u03c3\7F\2\2\u03c3\u03c4\7C\2"+ + "\2\u03c4\u03c5\7V\2\2\u03c5\u03c6\7G\2\2\u03c6\u03c7\7V\2\2\u03c7\u03c8"+ + "\7K\2\2\u03c8\u03c9\7O\2\2\u03c9\u03ca\7G\2\2\u03cap\3\2\2\2\u03cb\u03cc"+ + "\7K\2\2\u03cc\u03cd\7P\2\2\u03cd\u03ce\7V\2\2\u03ce\u03cf\7G\2\2\u03cf"+ + "\u03d0\7T\2\2\u03d0\u03d1\7X\2\2\u03d1\u03d2\7C\2\2\u03d2\u03d3\7N\2\2"+ + "\u03d3r\3\2\2\2\u03d4\u03d5\7O\2\2\u03d5\u03d6\7K\2\2\u03d6\u03d7\7E\2"+ + "\2\u03d7\u03d8\7T\2\2\u03d8\u03d9\7Q\2\2\u03d9\u03da\7U\2\2\u03da\u03db"+ + "\7G\2\2\u03db\u03dc\7E\2\2\u03dc\u03dd\7Q\2\2\u03dd\u03de\7P\2\2\u03de"+ + "\u03df\7F\2\2\u03dft\3\2\2\2\u03e0\u03e1\7O\2\2\u03e1\u03e2\7K\2\2\u03e2"+ + "\u03e3\7N\2\2\u03e3\u03e4\7N\2\2\u03e4\u03e5\7K\2\2\u03e5\u03e6\7U\2\2"+ + "\u03e6\u03e7\7G\2\2\u03e7\u03e8\7E\2\2\u03e8\u03e9\7Q\2\2\u03e9\u03ea"+ + "\7P\2\2\u03ea\u03eb\7F\2\2\u03ebv\3\2\2\2\u03ec\u03ed\7U\2\2\u03ed\u03ee"+ + "\7G\2\2\u03ee\u03ef\7E\2\2\u03ef\u03f0\7Q\2\2\u03f0\u03f1\7P\2\2\u03f1"+ + "\u03f2\7F\2\2\u03f2x\3\2\2\2\u03f3\u03f4\7O\2\2\u03f4\u03f5\7K\2\2\u03f5"+ + "\u03f6\7P\2\2\u03f6\u03f7\7W\2\2\u03f7\u03f8\7V\2\2\u03f8\u03f9\7G\2\2"+ + "\u03f9z\3\2\2\2\u03fa\u03fb\7J\2\2\u03fb\u03fc\7Q\2\2\u03fc\u03fd\7W\2"+ + "\2\u03fd\u03fe\7T\2\2\u03fe|\3\2\2\2\u03ff\u0400\7F\2\2\u0400\u0401\7"+ + "C\2\2\u0401\u0402\7[\2\2\u0402~\3\2\2\2\u0403\u0404\7Y\2\2\u0404\u0405"+ + "\7G\2\2\u0405\u0406\7G\2\2\u0406\u0407\7M\2\2\u0407\u0080\3\2\2\2\u0408"+ + "\u0409\7O\2\2\u0409\u040a\7Q\2\2\u040a\u040b\7P\2\2\u040b\u040c\7V\2\2"+ + "\u040c\u040d\7J\2\2\u040d\u0082\3\2\2\2\u040e\u040f\7S\2\2\u040f\u0410"+ + "\7W\2\2\u0410\u0411\7C\2\2\u0411\u0412\7T\2\2\u0412\u0413\7V\2\2\u0413"+ + "\u0414\7G\2\2\u0414\u0415\7T\2\2\u0415\u0084\3\2\2\2\u0416\u0417\7[\2"+ + "\2\u0417\u0418\7G\2\2\u0418\u0419\7C\2\2\u0419\u041a\7T\2\2\u041a\u0086"+ + "\3\2\2\2\u041b\u041c\7U\2\2\u041c\u041d\7G\2\2\u041d\u041e\7E\2\2\u041e"+ + "\u041f\7Q\2\2\u041f\u0420\7P\2\2\u0420\u0421\7F\2\2\u0421\u0422\7a\2\2"+ + "\u0422\u0423\7O\2\2\u0423\u0424\7K\2\2\u0424\u0425\7E\2\2\u0425\u0426"+ + "\7T\2\2\u0426\u0427\7Q\2\2\u0427\u0428\7U\2\2\u0428\u0429\7G\2\2\u0429"+ + "\u042a\7E\2\2\u042a\u042b\7Q\2\2\u042b\u042c\7P\2\2\u042c\u042d\7F\2\2"+ + "\u042d\u0088\3\2\2\2\u042e\u042f\7O\2\2\u042f\u0430\7K\2\2\u0430\u0431"+ + "\7P\2\2\u0431\u0432\7W\2\2\u0432\u0433\7V\2\2\u0433\u0434\7G\2\2\u0434"+ + "\u0435\7a\2\2\u0435\u0436\7O\2\2\u0436\u0437\7K\2\2\u0437\u0438\7E\2\2"+ + "\u0438\u0439\7T\2\2\u0439\u043a\7Q\2\2\u043a\u043b\7U\2\2\u043b\u043c"+ + "\7G\2\2\u043c\u043d\7E\2\2\u043d\u043e\7Q\2\2\u043e\u043f\7P\2\2\u043f"+ + "\u0440\7F\2\2\u0440\u008a\3\2\2\2\u0441\u0442\7O\2\2\u0442\u0443\7K\2"+ + "\2\u0443\u0444\7P\2\2\u0444\u0445\7W\2\2\u0445\u0446\7V\2\2\u0446\u0447"+ + "\7G\2\2\u0447\u0448\7a\2\2\u0448\u0449\7U\2\2\u0449\u044a\7G\2\2\u044a"+ + "\u044b\7E\2\2\u044b\u044c\7Q\2\2\u044c\u044d\7P\2\2\u044d\u044e\7F\2\2"+ + "\u044e\u008c\3\2\2\2\u044f\u0450\7J\2\2\u0450\u0451\7Q\2\2\u0451\u0452"+ + "\7W\2\2\u0452\u0453\7T\2\2\u0453\u0454\7a\2\2\u0454\u0455\7O\2\2\u0455"+ + "\u0456\7K\2\2\u0456\u0457\7E\2\2\u0457\u0458\7T\2\2\u0458\u0459\7Q\2\2"+ + "\u0459\u045a\7U\2\2\u045a\u045b\7G\2\2\u045b\u045c\7E\2\2\u045c\u045d"+ + "\7Q\2\2\u045d\u045e\7P\2\2\u045e\u045f\7F\2\2\u045f\u008e\3\2\2\2\u0460"+ + "\u0461\7J\2\2\u0461\u0462\7Q\2\2\u0462\u0463\7W\2\2\u0463\u0464\7T\2\2"+ + "\u0464\u0465\7a\2\2\u0465\u0466\7U\2\2\u0466\u0467\7G\2\2\u0467\u0468"+ + "\7E\2\2\u0468\u0469\7Q\2\2\u0469\u046a\7P\2\2\u046a\u046b\7F\2\2\u046b"+ + "\u0090\3\2\2\2\u046c\u046d\7J\2\2\u046d\u046e\7Q\2\2\u046e\u046f\7W\2"+ + "\2\u046f\u0470\7T\2\2\u0470\u0471\7a\2\2\u0471\u0472\7O\2\2\u0472\u0473"+ + "\7K\2\2\u0473\u0474\7P\2\2\u0474\u0475\7W\2\2\u0475\u0476\7V\2\2\u0476"+ + "\u0477\7G\2\2\u0477\u0092\3\2\2\2\u0478\u0479\7F\2\2\u0479\u047a\7C\2"+ + "\2\u047a\u047b\7[\2\2\u047b\u047c\7a\2\2\u047c\u047d\7O\2\2\u047d\u047e"+ + "\7K\2\2\u047e\u047f\7E\2\2\u047f\u0480\7T\2\2\u0480\u0481\7Q\2\2\u0481"+ + "\u0482\7U\2\2\u0482\u0483\7G\2\2\u0483\u0484\7E\2\2\u0484\u0485\7Q\2\2"+ + "\u0485\u0486\7P\2\2\u0486\u0487\7F\2\2\u0487\u0094\3\2\2\2\u0488\u0489"+ + "\7F\2\2\u0489\u048a\7C\2\2\u048a\u048b\7[\2\2\u048b\u048c\7a\2\2\u048c"+ + "\u048d\7U\2\2\u048d\u048e\7G\2\2\u048e\u048f\7E\2\2\u048f\u0490\7Q\2\2"+ + "\u0490\u0491\7P\2\2\u0491\u0492\7F\2\2\u0492\u0096\3\2\2\2\u0493\u0494"+ + "\7F\2\2\u0494\u0495\7C\2\2\u0495\u0496\7[\2\2\u0496\u0497\7a\2\2\u0497"+ + "\u0498\7O\2\2\u0498\u0499\7K\2\2\u0499\u049a\7P\2\2\u049a\u049b\7W\2\2"+ + "\u049b\u049c\7V\2\2\u049c\u049d\7G\2\2\u049d\u0098\3\2\2\2\u049e\u049f"+ + "\7F\2\2\u049f\u04a0\7C\2\2\u04a0\u04a1\7[\2\2\u04a1\u04a2\7a\2\2\u04a2"+ + "\u04a3\7J\2\2\u04a3\u04a4\7Q\2\2\u04a4\u04a5\7W\2\2\u04a5\u04a6\7T\2\2"+ + "\u04a6\u009a\3\2\2\2\u04a7\u04a8\7[\2\2\u04a8\u04a9\7G\2\2\u04a9\u04aa"+ + "\7C\2\2\u04aa\u04ab\7T\2\2\u04ab\u04ac\7a\2\2\u04ac\u04ad\7O\2\2\u04ad"+ + "\u04ae\7Q\2\2\u04ae\u04af\7P\2\2\u04af\u04b0\7V\2\2\u04b0\u04b1\7J\2\2"+ + "\u04b1\u009c\3\2\2\2\u04b2\u04b3\7F\2\2\u04b3\u04b4\7C\2\2\u04b4\u04b5"+ + "\7V\2\2\u04b5\u04b6\7C\2\2\u04b6\u04b7\7O\2\2\u04b7\u04b8\7Q\2\2\u04b8"+ + "\u04b9\7F\2\2\u04b9\u04ba\7G\2\2\u04ba\u04bb\7N\2\2\u04bb\u009e\3\2\2"+ + "\2\u04bc\u04bd\7N\2\2\u04bd\u04be\7Q\2\2\u04be\u04bf\7Q\2\2\u04bf\u04c0"+ + "\7M\2\2\u04c0\u04c1\7W\2\2\u04c1\u04c2\7R\2\2\u04c2\u00a0\3\2\2\2\u04c3"+ + "\u04c4\7U\2\2\u04c4\u04c5\7C\2\2\u04c5\u04c6\7X\2\2\u04c6\u04c7\7G\2\2"+ + "\u04c7\u04c8\7F\2\2\u04c8\u04c9\7U\2\2\u04c9\u04ca\7G\2\2\u04ca\u04cb"+ + "\7C\2\2\u04cb\u04cc\7T\2\2\u04cc\u04cd\7E\2\2\u04cd\u04ce\7J\2\2\u04ce"+ + "\u00a2\3\2\2\2\u04cf\u04d0\7K\2\2\u04d0\u04d1\7P\2\2\u04d1\u04d2\7V\2"+ + "\2\u04d2\u00a4\3\2\2\2\u04d3\u04d4\7K\2\2\u04d4\u04d5\7P\2\2\u04d5\u04d6"+ + "\7V\2\2\u04d6\u04d7\7G\2\2\u04d7\u04d8\7I\2\2\u04d8\u04d9\7G\2\2\u04d9"+ + "\u04da\7T\2\2\u04da\u00a6\3\2\2\2\u04db\u04dc\7F\2\2\u04dc\u04dd\7Q\2"+ + "\2\u04dd\u04de\7W\2\2\u04de\u04df\7D\2\2\u04df\u04e0\7N\2\2\u04e0\u04e1"+ + "\7G\2\2\u04e1\u00a8\3\2\2\2\u04e2\u04e3\7N\2\2\u04e3\u04e4\7Q\2\2\u04e4"+ + "\u04e5\7P\2\2\u04e5\u04e6\7I\2\2\u04e6\u00aa\3\2\2\2\u04e7\u04e8\7H\2"+ + "\2\u04e8\u04e9\7N\2\2\u04e9\u04ea\7Q\2\2\u04ea\u04eb\7C\2\2\u04eb\u04ec"+ + "\7V\2\2\u04ec\u00ac\3\2\2\2\u04ed\u04ee\7U\2\2\u04ee\u04ef\7V\2\2\u04ef"+ + "\u04f0\7T\2\2\u04f0\u04f1\7K\2\2\u04f1\u04f2\7P\2\2\u04f2\u04f3\7I\2\2"+ + "\u04f3\u00ae\3\2\2\2\u04f4\u04f5\7D\2\2\u04f5\u04f6\7Q\2\2\u04f6\u04f7"+ + "\7Q\2\2\u04f7\u04f8\7N\2\2\u04f8\u04f9\7G\2\2\u04f9\u04fa\7C\2\2\u04fa"+ + "\u04fb\7P\2\2\u04fb\u00b0\3\2\2\2\u04fc\u04fd\7~\2\2\u04fd\u00b2\3\2\2"+ + "\2\u04fe\u04ff\7.\2\2\u04ff\u00b4\3\2\2\2\u0500\u0501\7\60\2\2\u0501\u00b6"+ + "\3\2\2\2\u0502\u0503\7?\2\2\u0503\u00b8\3\2\2\2\u0504\u0505\7@\2\2\u0505"+ + "\u00ba\3\2\2\2\u0506\u0507\7>\2\2\u0507\u00bc\3\2\2\2\u0508\u0509\7>\2"+ + "\2\u0509\u050a\7?\2\2\u050a\u00be\3\2\2\2\u050b\u050c\7@\2\2\u050c\u050d"+ + "\7?\2\2\u050d\u00c0\3\2\2\2\u050e\u050f\7#\2\2\u050f\u0510\7?\2\2\u0510"+ + "\u00c2\3\2\2\2\u0511\u0512\7-\2\2\u0512\u00c4\3\2\2\2\u0513\u0514\7/\2"+ + "\2\u0514\u00c6\3\2\2\2\u0515\u0516\7,\2\2\u0516\u00c8\3\2\2\2\u0517\u0518"+ + "\7\61\2\2\u0518\u00ca\3\2\2\2\u0519\u051a\7\'\2\2\u051a\u00cc\3\2\2\2"+ + "\u051b\u051c\7#\2\2\u051c\u00ce\3\2\2\2\u051d\u051e\7<\2\2\u051e\u00d0"+ + "\3\2\2\2\u051f\u0520\7*\2\2\u0520\u00d2\3\2\2\2\u0521\u0522\7+\2\2\u0522"+ + "\u00d4\3\2\2\2\u0523\u0524\7]\2\2\u0524\u00d6\3\2\2\2\u0525\u0526\7_\2"+ + "\2\u0526\u00d8\3\2\2\2\u0527\u0528\7)\2\2\u0528\u00da\3\2\2\2\u0529\u052a"+ + "\7$\2\2\u052a\u00dc\3\2\2\2\u052b\u052c\7b\2\2\u052c\u00de\3\2\2\2\u052d"+ + "\u052e\7\u0080\2\2\u052e\u00e0\3\2\2\2\u052f\u0530\7(\2\2\u0530\u00e2"+ + "\3\2\2\2\u0531\u0532\7`\2\2\u0532\u00e4\3\2\2\2\u0533\u0534\7C\2\2\u0534"+ + "\u0535\7X\2\2\u0535\u0536\7I\2\2\u0536\u00e6\3\2\2\2\u0537\u0538\7E\2"+ + "\2\u0538\u0539\7Q\2\2\u0539\u053a\7W\2\2\u053a\u053b\7P\2\2\u053b\u053c"+ + "\7V\2\2\u053c\u00e8\3\2\2\2\u053d\u053e\7F\2\2\u053e\u053f\7K\2\2\u053f"+ + "\u0540\7U\2\2\u0540\u0541\7V\2\2\u0541\u0542\7K\2\2\u0542\u0543\7P\2\2"+ + "\u0543\u0544\7E\2\2\u0544\u0545\7V\2\2\u0545\u0546\7a\2\2\u0546\u0547"+ + "\7E\2\2\u0547\u0548\7Q\2\2\u0548\u0549\7W\2\2\u0549\u054a\7P\2\2\u054a"+ + "\u054b\7V\2\2\u054b\u00ea\3\2\2\2\u054c\u054d\7G\2\2\u054d\u054e\7U\2"+ + "\2\u054e\u054f\7V\2\2\u054f\u0550\7F\2\2\u0550\u0551\7E\2\2\u0551\u00ec"+ + "\3\2\2\2\u0552\u0553\7G\2\2\u0553\u0554\7U\2\2\u0554\u0555\7V\2\2\u0555"+ + "\u0556\7F\2\2\u0556\u0557\7E\2\2\u0557\u0558\7a\2\2\u0558\u0559\7G\2\2"+ + "\u0559\u055a\7T\2\2\u055a\u055b\7T\2\2\u055b\u055c\7Q\2\2\u055c\u055d"+ + "\7T\2\2\u055d\u00ee\3\2\2\2\u055e\u055f\7O\2\2\u055f\u0560\7C\2\2\u0560"+ + "\u0561\7Z\2\2\u0561\u00f0\3\2\2\2\u0562\u0563\7O\2\2\u0563\u0564\7G\2"+ + "\2\u0564\u0565\7C\2\2\u0565\u0566\7P\2\2\u0566\u00f2\3\2\2\2\u0567\u0568"+ + "\7O\2\2\u0568\u0569\7G\2\2\u0569\u056a\7F\2\2\u056a\u056b\7K\2\2\u056b"+ + "\u056c\7C\2\2\u056c\u056d\7P\2\2\u056d\u00f4\3\2\2\2\u056e\u056f\7O\2"+ + "\2\u056f\u0570\7K\2\2\u0570\u0571\7P\2\2\u0571\u00f6\3\2\2\2\u0572\u0573"+ + "\7O\2\2\u0573\u0574\7Q\2\2\u0574\u0575\7F\2\2\u0575\u0576\7G\2\2\u0576"+ + "\u00f8\3\2\2\2\u0577\u0578\7T\2\2\u0578\u0579\7C\2\2\u0579\u057a\7P\2"+ + "\2\u057a\u057b\7I\2\2\u057b\u057c\7G\2\2\u057c\u00fa\3\2\2\2\u057d\u057e"+ + "\7U\2\2\u057e\u057f\7V\2\2\u057f\u0580\7F\2\2\u0580\u0581\7G\2\2\u0581"+ + "\u0582\7X\2\2\u0582\u00fc\3\2\2\2\u0583\u0584\7U\2\2\u0584\u0585\7V\2"+ + "\2\u0585\u0586\7F\2\2\u0586\u0587\7G\2\2\u0587\u0588\7X\2\2\u0588\u0589"+ + "\7R\2\2\u0589\u00fe\3\2\2\2\u058a\u058b\7U\2\2\u058b\u058c\7W\2\2\u058c"+ + "\u058d\7O\2\2\u058d\u0100\3\2\2\2\u058e\u058f\7U\2\2\u058f\u0590\7W\2"+ + "\2\u0590\u0591\7O\2\2\u0591\u0592\7U\2\2\u0592\u0593\7S\2\2\u0593\u0102"+ + "\3\2\2\2\u0594\u0595\7X\2\2\u0595\u0596\7C\2\2\u0596\u0597\7T\2\2\u0597"+ + "\u0598\7a\2\2\u0598\u0599\7U\2\2\u0599\u059a\7C\2\2\u059a\u059b\7O\2\2"+ + "\u059b\u059c\7R\2\2\u059c\u0104\3\2\2\2\u059d\u059e\7X\2\2\u059e\u059f"+ + "\7C\2\2\u059f\u05a0\7T\2\2\u05a0\u05a1\7a\2\2\u05a1\u05a2\7R\2\2\u05a2"+ + "\u05a3\7Q\2\2\u05a3\u05a4\7R\2\2\u05a4\u0106\3\2\2\2\u05a5\u05a6\7U\2"+ + "\2\u05a6\u05a7\7V\2\2\u05a7\u05a8\7F\2\2\u05a8\u05a9\7F\2\2\u05a9\u05aa"+ + "\7G\2\2\u05aa\u05ab\7X\2\2\u05ab\u05ac\7a\2\2\u05ac\u05ad\7U\2\2\u05ad"+ + "\u05ae\7C\2\2\u05ae\u05af\7O\2\2\u05af\u05b0\7R\2\2\u05b0\u0108\3\2\2"+ + "\2\u05b1\u05b2\7U\2\2\u05b2\u05b3\7V\2\2\u05b3\u05b4\7F\2\2\u05b4\u05b5"+ + "\7F\2\2\u05b5\u05b6\7G\2\2\u05b6\u05b7\7X\2\2\u05b7\u05b8\7a\2\2\u05b8"+ + "\u05b9\7R\2\2\u05b9\u05ba\7Q\2\2\u05ba\u05bb\7R\2\2\u05bb\u010a\3\2\2"+ + "\2\u05bc\u05bd\7R\2\2\u05bd\u05be\7G\2\2\u05be\u05bf\7T\2\2\u05bf\u05c0"+ + "\7E\2\2\u05c0\u05c1\7G\2\2\u05c1\u05c2\7P\2\2\u05c2\u05c3\7V\2\2\u05c3"+ + "\u05c4\7K\2\2\u05c4\u05c5\7N\2\2\u05c5\u05c6\7G\2\2\u05c6\u010c\3\2\2"+ + "\2\u05c7\u05c8\7H\2\2\u05c8\u05c9\7K\2\2\u05c9\u05ca\7T\2\2\u05ca\u05cb"+ + "\7U\2\2\u05cb\u05cc\7V\2\2\u05cc\u010e\3\2\2\2\u05cd\u05ce\7N\2\2\u05ce"+ + "\u05cf\7C\2\2\u05cf\u05d0\7U\2\2\u05d0\u05d1\7V\2\2\u05d1\u0110\3\2\2"+ + "\2\u05d2\u05d3\7N\2\2\u05d3\u05d4\7K\2\2\u05d4\u05d5\7U\2\2\u05d5\u05d6"+ + "\7V\2\2\u05d6\u0112\3\2\2\2\u05d7\u05d8\7X\2\2\u05d8\u05d9\7C\2\2\u05d9"+ + "\u05da\7N\2\2\u05da\u05db\7W\2\2\u05db\u05dc\7G\2\2\u05dc\u05dd\7U\2\2"+ + "\u05dd\u0114\3\2\2\2\u05de\u05df\7G\2\2\u05df\u05e0\7C\2\2\u05e0\u05e1"+ + "\7T\2\2\u05e1\u05e2\7N\2\2\u05e2\u05e3\7K\2\2\u05e3\u05e4\7G\2\2\u05e4"+ + "\u05e5\7U\2\2\u05e5\u05e6\7V\2\2\u05e6\u0116\3\2\2\2\u05e7\u05e8\7G\2"+ + "\2\u05e8\u05e9\7C\2\2\u05e9\u05ea\7T\2\2\u05ea\u05eb\7N\2\2\u05eb\u05ec"+ + "\7K\2\2\u05ec\u05ed\7G\2\2\u05ed\u05ee\7U\2\2\u05ee\u05ef\7V\2\2\u05ef"+ + "\u05f0\7a\2\2\u05f0\u05f1\7V\2\2\u05f1\u05f2\7K\2\2\u05f2\u05f3\7O\2\2"+ + "\u05f3\u05f4\7G\2\2\u05f4\u0118\3\2\2\2\u05f5\u05f6\7N\2\2\u05f6\u05f7"+ + "\7C\2\2\u05f7\u05f8\7V\2\2\u05f8\u05f9\7G\2\2\u05f9\u05fa\7U\2\2\u05fa"+ + "\u05fb\7V\2\2\u05fb\u011a\3\2\2\2\u05fc\u05fd\7N\2\2\u05fd\u05fe\7C\2"+ + "\2\u05fe\u05ff\7V\2\2\u05ff\u0600\7G\2\2\u0600\u0601\7U\2\2\u0601\u0602"+ + "\7V\2\2\u0602\u0603\7a\2\2\u0603\u0604\7V\2\2\u0604\u0605\7K\2\2\u0605"+ + "\u0606\7O\2\2\u0606\u0607\7G\2\2\u0607\u011c\3\2\2\2\u0608\u0609\7R\2"+ + "\2\u0609\u060a\7G\2\2\u060a\u060b\7T\2\2\u060b\u060c\7a\2\2\u060c\u060d"+ + "\7F\2\2\u060d\u060e\7C\2\2\u060e\u060f\7[\2\2\u060f\u011e\3\2\2\2\u0610"+ + "\u0611\7R\2\2\u0611\u0612\7G\2\2\u0612\u0613\7T\2\2\u0613\u0614\7a\2\2"+ + "\u0614\u0615\7J\2\2\u0615\u0616\7Q\2\2\u0616\u0617\7W\2\2\u0617\u0618"+ + "\7T\2\2\u0618\u0120\3\2\2\2\u0619\u061a\7R\2\2\u061a\u061b\7G\2\2\u061b"+ + "\u061c\7T\2\2\u061c\u061d\7a\2\2\u061d\u061e\7O\2\2\u061e\u061f\7K\2\2"+ + "\u061f\u0620\7P\2\2\u0620\u0621\7W\2\2\u0621\u0622\7V\2\2\u0622\u0623"+ + "\7G\2\2\u0623\u0122\3\2\2\2\u0624\u0625\7R\2\2\u0625\u0626\7G\2\2\u0626"+ + "\u0627\7T\2\2\u0627\u0628\7a\2\2\u0628\u0629\7U\2\2\u0629\u062a\7G\2\2"+ + "\u062a\u062b\7E\2\2\u062b\u062c\7Q\2\2\u062c\u062d\7P\2\2\u062d\u062e"+ + "\7F\2\2\u062e\u0124\3\2\2\2\u062f\u0630\7T\2\2\u0630\u0631\7C\2\2\u0631"+ + "\u0632\7V\2\2\u0632\u0633\7G\2\2\u0633\u0126\3\2\2\2\u0634\u0635\7U\2"+ + "\2\u0635\u0636\7R\2\2\u0636\u0637\7C\2\2\u0637\u0638\7T\2\2\u0638\u0639"+ + "\7M\2\2\u0639\u063a\7N\2\2\u063a\u063b\7K\2\2\u063b\u063c\7P\2\2\u063c"+ + "\u063d\7G\2\2\u063d\u0128\3\2\2\2\u063e\u063f\7E\2\2\u063f\u012a\3\2\2"+ + "\2\u0640\u0641\7F\2\2\u0641\u0642\7E\2\2\u0642\u012c\3\2\2\2\u0643\u0644"+ + "\7C\2\2\u0644\u0645\7D\2\2\u0645\u0646\7U\2\2\u0646\u012e\3\2\2\2\u0647"+ + "\u0648\7E\2\2\u0648\u0649\7G\2\2\u0649\u064a\7K\2\2\u064a\u064b\7N\2\2"+ + "\u064b\u0130\3\2\2\2\u064c\u064d\7E\2\2\u064d\u064e\7G\2\2\u064e\u064f"+ + "\7K\2\2\u064f\u0650\7N\2\2\u0650\u0651\7K\2\2\u0651\u0652\7P\2\2\u0652"+ + "\u0653\7I\2\2\u0653\u0132\3\2\2\2\u0654\u0655\7E\2\2\u0655\u0656\7Q\2"+ + "\2\u0656\u0657\7P\2\2\u0657\u0658\7X\2\2\u0658\u0134\3\2\2\2\u0659\u065a"+ + "\7E\2\2\u065a\u065b\7T\2\2\u065b\u065c\7E\2\2\u065c\u065d\7\65\2\2\u065d"+ + "\u065e\7\64\2\2\u065e\u0136\3\2\2\2\u065f\u0660\7G\2\2\u0660\u0138\3\2"+ + "\2\2\u0661\u0662\7G\2\2\u0662\u0663\7Z\2\2\u0663\u0664\7R\2\2\u0664\u013a"+ + "\3\2\2\2\u0665\u0666\7H\2\2\u0666\u0667\7N\2\2\u0667\u0668\7Q\2\2\u0668"+ + "\u0669\7Q\2\2\u0669\u066a\7T\2\2\u066a\u013c\3\2\2\2\u066b\u066c\7N\2"+ + "\2\u066c\u066d\7P\2\2\u066d\u013e\3\2\2\2\u066e\u066f\7N\2\2\u066f\u0670"+ + "\7Q\2\2\u0670\u0671\7I\2\2\u0671\u0140\3\2\2\2\u0672\u0673\7N\2\2\u0673"+ + "\u0674\7Q\2\2\u0674\u0675\7I\2\2\u0675\u0676\7\63\2\2\u0676\u0677\7\62"+ + "\2\2\u0677\u0142\3\2\2\2\u0678\u0679\7N\2\2\u0679\u067a\7Q\2\2\u067a\u067b"+ + "\7I\2\2\u067b\u067c\7\64\2\2\u067c\u0144\3\2\2\2\u067d\u067e\7O\2\2\u067e"+ + "\u067f\7Q\2\2\u067f\u0680\7F\2\2\u0680\u0146\3\2\2\2\u0681\u0682\7R\2"+ + "\2\u0682\u0683\7K\2\2\u0683\u0148\3\2\2\2\u0684\u0685\7R\2\2\u0685\u0686"+ + "\7Q\2\2\u0686\u0687\7Y\2\2\u0687\u014a\3\2\2\2\u0688\u0689\7R\2\2\u0689"+ + "\u068a\7Q\2\2\u068a\u068b\7Y\2\2\u068b\u068c\7G\2\2\u068c\u068d\7T\2\2"+ + "\u068d\u014c\3\2\2\2\u068e\u068f\7T\2\2\u068f\u0690\7C\2\2\u0690\u0691"+ + "\7P\2\2\u0691\u0692\7F\2\2\u0692\u014e\3\2\2\2\u0693\u0694\7T\2\2\u0694"+ + "\u0695\7Q\2\2\u0695\u0696\7W\2\2\u0696\u0697\7P\2\2\u0697\u0698\7F\2\2"+ + "\u0698\u0150\3\2\2\2\u0699\u069a\7U\2\2\u069a\u069b\7K\2\2\u069b\u069c"+ + "\7I\2\2\u069c\u069d\7P\2\2\u069d\u0152\3\2\2\2\u069e\u069f\7U\2\2\u069f"+ + "\u06a0\7S\2\2\u06a0\u06a1\7T\2\2\u06a1\u06a2\7V\2\2\u06a2\u0154\3\2\2"+ + "\2\u06a3\u06a4\7V\2\2\u06a4\u06a5\7T\2\2\u06a5\u06a6\7W\2\2\u06a6\u06a7"+ + "\7P\2\2\u06a7\u06a8\7E\2\2\u06a8\u06a9\7C\2\2\u06a9\u06aa\7V\2\2\u06aa"+ + "\u06ab\7G\2\2\u06ab\u0156\3\2\2\2\u06ac\u06ad\7C\2\2\u06ad\u06ae\7E\2"+ + "\2\u06ae\u06af\7Q\2\2\u06af\u06b0\7U\2\2\u06b0\u0158\3\2\2\2\u06b1\u06b2"+ + "\7C\2\2\u06b2\u06b3\7U\2\2\u06b3\u06b4\7K\2\2\u06b4\u06b5\7P\2\2\u06b5"+ + "\u015a\3\2\2\2\u06b6\u06b7\7C\2\2\u06b7\u06b8\7V\2\2\u06b8\u06b9\7C\2"+ + "\2\u06b9\u06ba\7P\2\2\u06ba\u015c\3\2\2\2\u06bb\u06bc\7C\2\2\u06bc\u06bd"+ + "\7V\2\2\u06bd\u06be\7C\2\2\u06be\u06bf\7P\2\2\u06bf\u06c0\7\64\2\2\u06c0"+ + "\u015e\3\2\2\2\u06c1\u06c2\7E\2\2\u06c2\u06c3\7Q\2\2\u06c3\u06c4\7U\2"+ + "\2\u06c4\u0160\3\2\2\2\u06c5\u06c6\7E\2\2\u06c6\u06c7\7Q\2\2\u06c7\u06c8"+ + "\7V\2\2\u06c8\u0162\3\2\2\2\u06c9\u06ca\7F\2\2\u06ca\u06cb\7G\2\2\u06cb"+ + "\u06cc\7I\2\2\u06cc\u06cd\7T\2\2\u06cd\u06ce\7G\2\2\u06ce\u06cf\7G\2\2"+ + "\u06cf\u06d0\7U\2\2\u06d0\u0164\3\2\2\2\u06d1\u06d2\7T\2\2\u06d2\u06d3"+ + "\7C\2\2\u06d3\u06d4\7F\2\2\u06d4\u06d5\7K\2\2\u06d5\u06d6\7C\2\2\u06d6"+ + "\u06d7\7P\2\2\u06d7\u06d8\7U\2\2\u06d8\u0166\3\2\2\2\u06d9\u06da\7U\2"+ + "\2\u06da\u06db\7K\2\2\u06db\u06dc\7P\2\2\u06dc\u0168\3\2\2\2\u06dd\u06de"+ + "\7V\2\2\u06de\u06df\7C\2\2\u06df\u06e0\7P\2\2\u06e0\u016a\3\2\2\2\u06e1"+ + "\u06e2\7C\2\2\u06e2\u06e3\7F\2\2\u06e3\u06e4\7F\2\2\u06e4\u06e5\7F\2\2"+ + "\u06e5\u06e6\7C\2\2\u06e6\u06e7\7V\2\2\u06e7\u06e8\7G\2\2\u06e8\u016c"+ + "\3\2\2\2\u06e9\u06ea\7F\2\2\u06ea\u06eb\7C\2\2\u06eb\u06ec\7V\2\2\u06ec"+ + "\u06ed\7G\2\2\u06ed\u016e\3\2\2\2\u06ee\u06ef\7F\2\2\u06ef\u06f0\7C\2"+ + "\2\u06f0\u06f1\7V\2\2\u06f1\u06f2\7G\2\2\u06f2\u06f3\7a\2\2\u06f3\u06f4"+ + "\7C\2\2\u06f4\u06f5\7F\2\2\u06f5\u06f6\7F\2\2\u06f6\u0170\3\2\2\2\u06f7"+ + "\u06f8\7F\2\2\u06f8\u06f9\7C\2\2\u06f9\u06fa\7V\2\2\u06fa\u06fb\7G\2\2"+ + "\u06fb\u06fc\7a\2\2\u06fc\u06fd\7U\2\2\u06fd\u06fe\7W\2\2\u06fe\u06ff"+ + "\7D\2\2\u06ff\u0172\3\2\2\2\u0700\u0701\7F\2\2\u0701\u0702\7C\2\2\u0702"+ + "\u0703\7[\2\2\u0703\u0704\7Q\2\2\u0704\u0705\7H\2\2\u0705\u0706\7O\2\2"+ + "\u0706\u0707\7Q\2\2\u0707\u0708\7P\2\2\u0708\u0709\7V\2\2\u0709\u070a"+ + "\7J\2\2\u070a\u0174\3\2\2\2\u070b\u070c\7F\2\2\u070c\u070d\7C\2\2\u070d"+ + "\u070e\7[\2\2\u070e\u070f\7Q\2\2\u070f\u0710\7H\2\2\u0710\u0711\7Y\2\2"+ + "\u0711\u0712\7G\2\2\u0712\u0713\7G\2\2\u0713\u0714\7M\2\2\u0714\u0176"+ + "\3\2\2\2\u0715\u0716\7F\2\2\u0716\u0717\7C\2\2\u0717\u0718\7[\2\2\u0718"+ + "\u0719\7Q\2\2\u0719\u071a\7H\2\2\u071a\u071b\7[\2\2\u071b\u071c\7G\2\2"+ + "\u071c\u071d\7C\2\2\u071d\u071e\7T\2\2\u071e\u0178\3\2\2\2\u071f\u0720"+ + "\7F\2\2\u0720\u0721\7C\2\2\u0721\u0722\7[\2\2\u0722\u0723\7P\2\2\u0723"+ + "\u0724\7C\2\2\u0724\u0725\7O\2\2\u0725\u0726\7G\2\2\u0726\u017a\3\2\2"+ + "\2\u0727\u0728\7H\2\2\u0728\u0729\7T\2\2\u0729\u072a\7Q\2\2\u072a\u072b"+ + "\7O\2\2\u072b\u072c\7a\2\2\u072c\u072d\7F\2\2\u072d\u072e\7C\2\2\u072e"+ + "\u072f\7[\2\2\u072f\u0730\7U\2\2\u0730\u017c\3\2\2\2\u0731\u0732\7O\2"+ + "\2\u0732\u0733\7Q\2\2\u0733\u0734\7P\2\2\u0734\u0735\7V\2\2\u0735\u0736"+ + "\7J\2\2\u0736\u0737\7P\2\2\u0737\u0738\7C\2\2\u0738\u0739\7O\2\2\u0739"+ + "\u073a\7G\2\2\u073a\u017e\3\2\2\2\u073b\u073c\7U\2\2\u073c\u073d\7W\2"+ + "\2\u073d\u073e\7D\2\2\u073e\u073f\7F\2\2\u073f\u0740\7C\2\2\u0740\u0741"+ + "\7V\2\2\u0741\u0742\7G\2\2\u0742\u0180\3\2\2\2\u0743\u0744\7V\2\2\u0744"+ + "\u0745\7K\2\2\u0745\u0746\7O\2\2\u0746\u0747\7G\2\2\u0747\u0182\3\2\2"+ + "\2\u0748\u0749\7V\2\2\u0749\u074a\7K\2\2\u074a\u074b\7O\2\2\u074b\u074c"+ + "\7G\2\2\u074c\u074d\7a\2\2\u074d\u074e\7V\2\2\u074e\u074f\7Q\2\2\u074f"+ + "\u0750\7a\2\2\u0750\u0751\7U\2\2\u0751\u0752\7G\2\2\u0752\u0753\7E\2\2"+ + "\u0753\u0184\3\2\2\2\u0754\u0755\7V\2\2\u0755\u0756\7K\2\2\u0756\u0757"+ + "\7O\2\2\u0757\u0758\7G\2\2\u0758\u0759\7U\2\2\u0759\u075a\7V\2\2\u075a"+ + "\u075b\7C\2\2\u075b\u075c\7O\2\2\u075c\u075d\7R\2\2\u075d\u0186\3\2\2"+ + "\2\u075e\u075f\7F\2\2\u075f\u0760\7C\2\2\u0760\u0761\7V\2\2\u0761\u0762"+ + "\7G\2\2\u0762\u0763\7a\2\2\u0763\u0764\7H\2\2\u0764\u0765\7Q\2\2\u0765"+ + "\u0766\7T\2\2\u0766\u0767\7O\2\2\u0767\u0768\7C\2\2\u0768\u0769\7V\2\2"+ + "\u0769\u0188\3\2\2\2\u076a\u076b\7V\2\2\u076b\u076c\7Q\2\2\u076c\u076d"+ + "\7a\2\2\u076d\u076e\7F\2\2\u076e\u076f\7C\2\2\u076f\u0770\7[\2\2\u0770"+ + "\u0771\7U\2\2\u0771\u018a\3\2\2\2\u0772\u0773\7U\2\2\u0773\u0774\7W\2"+ + "\2\u0774\u0775\7D\2\2\u0775\u0776\7U\2\2\u0776\u0777\7V\2\2\u0777\u0778"+ + "\7T\2\2\u0778\u018c\3\2\2\2\u0779\u077a\7U\2\2\u077a\u077b\7W\2\2\u077b"+ + "\u077c\7D\2\2\u077c\u077d\7U\2\2\u077d\u077e\7V\2\2\u077e\u077f\7T\2\2"+ + "\u077f\u0780\7K\2\2\u0780\u0781\7P\2\2\u0781\u0782\7I\2\2\u0782\u018e"+ + "\3\2\2\2\u0783\u0784\7N\2\2\u0784\u0785\7V\2\2\u0785\u0786\7T\2\2\u0786"+ + "\u0787\7K\2\2\u0787\u0788\7O\2\2\u0788\u0190\3\2\2\2\u0789\u078a\7T\2"+ + "\2\u078a\u078b\7V\2\2\u078b\u078c\7T\2\2\u078c\u078d\7K\2\2\u078d\u078e"+ + "\7O\2\2\u078e\u0192\3\2\2\2\u078f\u0790\7V\2\2\u0790\u0791\7T\2\2\u0791"+ + "\u0792\7K\2\2\u0792\u0793\7O\2\2\u0793\u0194\3\2\2\2\u0794\u0795\7V\2"+ + "\2\u0795\u0796\7Q\2\2\u0796\u0196\3\2\2\2\u0797\u0798\7N\2\2\u0798\u0799"+ + "\7Q\2\2\u0799\u079a\7Y\2\2\u079a\u079b\7G\2\2\u079b\u079c\7T\2\2\u079c"+ + "\u0198\3\2\2\2\u079d\u079e\7W\2\2\u079e\u079f\7R\2\2\u079f\u07a0\7R\2"+ + "\2\u07a0\u07a1\7G\2\2\u07a1\u07a2\7T\2\2\u07a2\u019a\3\2\2\2\u07a3\u07a4"+ + "\7E\2\2\u07a4\u07a5\7Q\2\2\u07a5\u07a6\7P\2\2\u07a6\u07a7\7E\2\2\u07a7"+ + "\u07a8\7C\2\2\u07a8\u07a9\7V\2\2\u07a9\u019c\3\2\2\2\u07aa\u07ab\7E\2"+ + "\2\u07ab\u07ac\7Q\2\2\u07ac\u07ad\7P\2\2\u07ad\u07ae\7E\2\2\u07ae\u07af"+ + "\7C\2\2\u07af\u07b0\7V\2\2\u07b0\u07b1\7a\2\2\u07b1\u07b2\7Y\2\2\u07b2"+ + "\u07b3\7U\2\2\u07b3\u019e\3\2\2\2\u07b4\u07b5\7N\2\2\u07b5\u07b6\7G\2"+ + "\2\u07b6\u07b7\7P\2\2\u07b7\u07b8\7I\2\2\u07b8\u07b9\7V\2\2\u07b9\u07ba"+ + "\7J\2\2\u07ba\u01a0\3\2\2\2\u07bb\u07bc\7U\2\2\u07bc\u07bd\7V\2\2\u07bd"+ + "\u07be\7T\2\2\u07be\u07bf\7E\2\2\u07bf\u07c0\7O\2\2\u07c0\u07c1\7R\2\2"+ + "\u07c1\u01a2\3\2\2\2\u07c2\u07c3\7T\2\2\u07c3\u07c4\7K\2\2\u07c4\u07c5"+ + "\7I\2\2\u07c5\u07c6\7J\2\2\u07c6\u07c7\7V\2\2\u07c7\u01a4\3\2\2\2\u07c8"+ + "\u07c9\7N\2\2\u07c9\u07ca\7G\2\2\u07ca\u07cb\7H\2\2\u07cb\u07cc\7V\2\2"+ + "\u07cc\u01a6\3\2\2\2\u07cd\u07ce\7C\2\2\u07ce\u07cf\7U\2\2\u07cf\u07d0"+ + "\7E\2\2\u07d0\u07d1\7K\2\2\u07d1\u07d2\7K\2\2\u07d2\u01a8\3\2\2\2\u07d3"+ + "\u07d4\7N\2\2\u07d4\u07d5\7Q\2\2\u07d5\u07d6\7E\2\2\u07d6\u07d7\7C\2\2"+ + "\u07d7\u07d8\7V\2\2\u07d8\u07d9\7G\2\2\u07d9\u01aa\3\2\2\2\u07da\u07db"+ + "\7T\2\2\u07db\u07dc\7G\2\2\u07dc\u07dd\7R\2\2\u07dd\u07de\7N\2\2\u07de"+ + "\u07df\7C\2\2\u07df\u07e0\7E\2\2\u07e0\u07e1\7G\2\2\u07e1\u01ac\3\2\2"+ + "\2\u07e2\u07e3\7E\2\2\u07e3\u07e4\7C\2\2\u07e4\u07e5\7U\2\2\u07e5\u07e6"+ + "\7V\2\2\u07e6\u01ae\3\2\2\2\u07e7\u07e8\7N\2\2\u07e8\u07e9\7K\2\2\u07e9"+ + "\u07ea\7M\2\2\u07ea\u07eb\7G\2\2\u07eb\u01b0\3\2\2\2\u07ec\u07ed\7K\2"+ + "\2\u07ed\u07ee\7U\2\2\u07ee\u07ef\7P\2\2\u07ef\u07f0\7W\2\2\u07f0\u07f1"+ + "\7N\2\2\u07f1\u07f2\7N\2\2\u07f2\u01b2\3\2\2\2\u07f3\u07f4\7K\2\2\u07f4"+ + "\u07f5\7U\2\2\u07f5\u07f6\7P\2\2\u07f6\u07f7\7Q\2\2\u07f7\u07f8\7V\2\2"+ + "\u07f8\u07f9\7P\2\2\u07f9\u07fa\7W\2\2\u07fa\u07fb\7N\2\2\u07fb\u07fc"+ + "\7N\2\2\u07fc\u01b4\3\2\2\2\u07fd\u07fe\7K\2\2\u07fe\u07ff\7H\2\2\u07ff"+ + "\u0800\7P\2\2\u0800\u0801\7W\2\2\u0801\u0802\7N\2\2\u0802\u0803\7N\2\2"+ + "\u0803\u01b6\3\2\2\2\u0804\u0805\7P\2\2\u0805\u0806\7W\2\2\u0806\u0807"+ + "\7N\2\2\u0807\u0808\7N\2\2\u0808\u0809\7K\2\2\u0809\u080a\7H\2\2\u080a"+ + "\u01b8\3\2\2\2\u080b\u080c\7K\2\2\u080c\u080d\7H\2\2\u080d\u01ba\3\2\2"+ + "\2\u080e\u080f\7O\2\2\u080f\u0810\7C\2\2\u0810\u0811\7V\2\2\u0811\u0812"+ + "\7E\2\2\u0812\u0813\7J\2\2\u0813\u01bc\3\2\2\2\u0814\u0815\7O\2\2\u0815"+ + "\u0816\7C\2\2\u0816\u0817\7V\2\2\u0817\u0818\7E\2\2\u0818\u0819\7J\2\2"+ + "\u0819\u081a\7a\2\2\u081a\u081b\7R\2\2\u081b\u081c\7J\2\2\u081c\u081d"+ + "\7T\2\2\u081d\u081e\7C\2\2\u081e\u081f\7U\2\2\u081f\u0820\7G\2\2\u0820"+ + "\u01be\3\2\2\2\u0821\u0822\7U\2\2\u0822\u0823\7K\2\2\u0823\u0824\7O\2"+ + "\2\u0824\u0825\7R\2\2\u0825\u0826\7N\2\2\u0826\u0827\7G\2\2\u0827\u0828"+ + "\7a\2\2\u0828\u0829\7S\2\2\u0829\u082a\7W\2\2\u082a\u082b\7G\2\2\u082b"+ + "\u082c\7T\2\2\u082c\u082d\7[\2\2\u082d\u082e\7a\2\2\u082e\u082f\7U\2\2"+ + "\u082f\u0830\7V\2\2\u0830\u0831\7T\2\2\u0831\u0832\7K\2\2\u0832\u0833"+ + "\7P\2\2\u0833\u0834\7I\2\2\u0834\u01c0\3\2\2\2\u0835\u0836\7C\2\2\u0836"+ + "\u0837\7N\2\2\u0837\u0838\7N\2\2\u0838\u0839\7Q\2\2\u0839\u083a\7Y\2\2"+ + "\u083a\u083b\7a\2\2\u083b\u083c\7N\2\2\u083c\u083d\7G\2\2\u083d\u083e"+ + "\7C\2\2\u083e\u083f\7F\2\2\u083f\u0840\7K\2\2\u0840\u0841\7P\2\2\u0841"+ + "\u0842\7I\2\2\u0842\u0843\7a\2\2\u0843\u0844\7Y\2\2\u0844\u0845\7K\2\2"+ + "\u0845\u0846\7N\2\2\u0846\u0847\7F\2\2\u0847\u0848\7E\2\2\u0848\u0849"+ + "\7C\2\2\u0849\u084a\7T\2\2\u084a\u084b\7F\2\2\u084b\u01c2\3\2\2\2\u084c"+ + "\u084d\7C\2\2\u084d\u084e\7P\2\2\u084e\u084f\7C\2\2\u084f\u0850\7N\2\2"+ + "\u0850\u0851\7[\2\2\u0851\u0852\7\\\2\2\u0852\u0853\7G\2\2\u0853\u0854"+ + "\7a\2\2\u0854\u0855\7Y\2\2\u0855\u0856\7K\2\2\u0856\u0857\7N\2\2\u0857"+ + "\u0858\7F\2\2\u0858\u0859\7E\2\2\u0859\u085a\7C\2\2\u085a\u085b\7T\2\2"+ + "\u085b\u085c\7F\2\2\u085c\u01c4\3\2\2\2\u085d\u085e\7C\2\2\u085e\u085f"+ + "\7P\2\2\u085f\u0860\7C\2\2\u0860\u0861\7N\2\2\u0861\u0862\7[\2\2\u0862"+ + "\u0863\7\\\2\2\u0863\u0864\7G\2\2\u0864\u0865\7T\2\2\u0865\u01c6\3\2\2"+ + "\2\u0866\u0867\7C\2\2\u0867\u0868\7W\2\2\u0868\u0869\7V\2\2\u0869\u086a"+ + "\7Q\2\2\u086a\u086b\7a\2\2\u086b\u086c\7I\2\2\u086c\u086d\7G\2\2\u086d"+ + "\u086e\7P\2\2\u086e\u086f\7G\2\2\u086f\u0870\7T\2\2\u0870\u0871\7C\2\2"+ + "\u0871\u0872\7V\2\2\u0872\u0873\7G\2\2\u0873\u0874\7a\2\2\u0874\u0875"+ + "\7U\2\2\u0875\u0876\7[\2\2\u0876\u0877\7P\2\2\u0877\u0878\7Q\2\2\u0878"+ + "\u0879\7P\2\2\u0879\u087a\7[\2\2\u087a\u087b\7O\2\2\u087b\u087c\7U\2\2"+ + "\u087c\u087d\7a\2\2\u087d\u087e\7R\2\2\u087e\u087f\7J\2\2\u087f\u0880"+ + "\7T\2\2\u0880\u0881\7C\2\2\u0881\u0882\7U\2\2\u0882\u0883\7G\2\2\u0883"+ + "\u0884\7a\2\2\u0884\u0885\7S\2\2\u0885\u0886\7W\2\2\u0886\u0887\7G\2\2"+ + "\u0887\u0888\7T\2\2\u0888\u0889\7[\2\2\u0889\u01c8\3\2\2\2\u088a\u088b"+ + "\7D\2\2\u088b\u088c\7Q\2\2\u088c\u088d\7Q\2\2\u088d\u088e\7U\2\2\u088e"+ + "\u088f\7V\2\2\u088f\u01ca\3\2\2\2\u0890\u0891\7E\2\2\u0891\u0892\7W\2"+ + "\2\u0892\u0893\7V\2\2\u0893\u0894\7Q\2\2\u0894\u0895\7H\2\2\u0895\u0896"+ + "\7H\2\2\u0896\u0897\7a\2\2\u0897\u0898\7H\2\2\u0898\u0899\7T\2\2\u0899"+ + "\u089a\7G\2\2\u089a\u089b\7S\2\2\u089b\u089c\7W\2\2\u089c\u089d\7G\2\2"+ + "\u089d\u089e\7P\2\2\u089e\u089f\7E\2\2\u089f\u08a0\7[\2\2\u08a0\u01cc"+ + "\3\2\2\2\u08a1\u08a2\7F\2\2\u08a2\u08a3\7G\2\2\u08a3\u08a4\7H\2\2\u08a4"+ + "\u08a5\7C\2\2\u08a5\u08a6\7W\2\2\u08a6\u08a7\7N\2\2\u08a7\u08a8\7V\2\2"+ + "\u08a8\u08a9\7a\2\2\u08a9\u08aa\7H\2\2\u08aa\u08ab\7K\2\2\u08ab\u08ac"+ + "\7G\2\2\u08ac\u08ad\7N\2\2\u08ad\u08ae\7F\2\2\u08ae\u01ce\3\2\2\2\u08af"+ + "\u08b0\7F\2\2\u08b0\u08b1\7G\2\2\u08b1\u08b2\7H\2\2\u08b2\u08b3\7C\2\2"+ + "\u08b3\u08b4\7W\2\2\u08b4\u08b5\7N\2\2\u08b5\u08b6\7V\2\2\u08b6\u08b7"+ + "\7a\2\2\u08b7\u08b8\7Q\2\2\u08b8\u08b9\7R\2\2\u08b9\u08ba\7G\2\2\u08ba"+ + "\u08bb\7T\2\2\u08bb\u08bc\7C\2\2\u08bc\u08bd\7V\2\2\u08bd\u08be\7Q\2\2"+ + "\u08be\u08bf\7T\2\2\u08bf\u01d0\3\2\2\2\u08c0\u08c1\7G\2\2\u08c1\u08c2"+ + "\7P\2\2\u08c2\u08c3\7C\2\2\u08c3\u08c4\7D\2\2\u08c4\u08c5\7N\2\2\u08c5"+ + "\u08c6\7G\2\2\u08c6\u08c7\7a\2\2\u08c7\u08c8\7R\2\2\u08c8\u08c9\7Q\2\2"+ + "\u08c9\u08ca\7U\2\2\u08ca\u08cb\7K\2\2\u08cb\u08cc\7V\2\2\u08cc\u08cd"+ + "\7K\2\2\u08cd\u08ce\7Q\2\2\u08ce\u08cf\7P\2\2\u08cf\u08d0\7a\2\2\u08d0"+ + "\u08d1\7K\2\2\u08d1\u08d2\7P\2\2\u08d2\u08d3\7E\2\2\u08d3\u08d4\7T\2\2"+ + "\u08d4\u08d5\7G\2\2\u08d5\u08d6\7O\2\2\u08d6\u08d7\7G\2\2\u08d7\u08d8"+ + "\7P\2\2\u08d8\u08d9\7V\2\2\u08d9\u08da\7U\2\2\u08da\u01d2\3\2\2\2\u08db"+ + "\u08dc\7H\2\2\u08dc\u08dd\7N\2\2\u08dd\u08de\7C\2\2\u08de\u08df\7I\2\2"+ + "\u08df\u08e0\7U\2\2\u08e0\u01d4\3\2\2\2\u08e1\u08e2\7H\2\2\u08e2\u08e3"+ + "\7W\2\2\u08e3\u08e4\7\\\2\2\u08e4\u08e5\7\\\2\2\u08e5\u08e6\7[\2\2\u08e6"+ + "\u08e7\7a\2\2\u08e7\u08e8\7O\2\2\u08e8\u08e9\7C\2\2\u08e9\u08ea\7Z\2\2"+ + "\u08ea\u08eb\7a\2\2\u08eb\u08ec\7G\2\2\u08ec\u08ed\7Z\2\2\u08ed\u08ee"+ + "\7R\2\2\u08ee\u08ef\7C\2\2\u08ef\u08f0\7P\2\2\u08f0\u08f1\7U\2\2\u08f1"+ + "\u08f2\7K\2\2\u08f2\u08f3\7Q\2\2\u08f3\u08f4\7P\2\2\u08f4\u08f5\7U\2\2"+ + "\u08f5\u01d6\3\2\2\2\u08f6\u08f7\7H\2\2\u08f7\u08f8\7W\2\2\u08f8\u08f9"+ + "\7\\\2\2\u08f9\u08fa\7\\\2\2\u08fa\u08fb\7[\2\2\u08fb\u08fc\7a\2\2\u08fc"+ + "\u08fd\7R\2\2\u08fd\u08fe\7T\2\2\u08fe\u08ff\7G\2\2\u08ff\u0900\7H\2\2"+ + "\u0900\u0901\7K\2\2\u0901\u0902\7Z\2\2\u0902\u0903\7a\2\2\u0903\u0904"+ + "\7N\2\2\u0904\u0905\7G\2\2\u0905\u0906\7P\2\2\u0906\u0907\7I\2\2\u0907"+ + "\u0908\7V\2\2\u0908\u0909\7J\2\2\u0909\u01d8\3\2\2\2\u090a\u090b\7H\2"+ + "\2\u090b\u090c\7W\2\2\u090c\u090d\7\\\2\2\u090d\u090e\7\\\2\2\u090e\u090f"+ + "\7[\2\2\u090f\u0910\7a\2\2\u0910\u0911\7V\2\2\u0911\u0912\7T\2\2\u0912"+ + "\u0913\7C\2\2\u0913\u0914\7P\2\2\u0914\u0915\7U\2\2\u0915\u0916\7R\2\2"+ + "\u0916\u0917\7Q\2\2\u0917\u0918\7U\2\2\u0918\u0919\7K\2\2\u0919\u091a"+ + "\7V\2\2\u091a\u091b\7K\2\2\u091b\u091c\7Q\2\2\u091c\u091d\7P\2\2\u091d"+ + "\u091e\7U\2\2\u091e\u01da\3\2\2\2\u091f\u0920\7H\2\2\u0920\u0921\7W\2"+ + "\2\u0921\u0922\7\\\2\2\u0922\u0923\7\\\2\2\u0923\u0924\7[\2\2\u0924\u0925"+ + "\7a\2\2\u0925\u0926\7T\2\2\u0926\u0927\7G\2\2\u0927\u0928\7Y\2\2\u0928"+ + "\u0929\7T\2\2\u0929\u092a\7K\2\2\u092a\u092b\7V\2\2\u092b\u092c\7G\2\2"+ + "\u092c\u01dc\3\2\2\2\u092d\u092e\7H\2\2\u092e\u092f\7W\2\2\u092f\u0930"+ + "\7\\\2\2\u0930\u0931\7\\\2\2\u0931\u0932\7K\2\2\u0932\u0933\7P\2\2\u0933"+ + "\u0934\7G\2\2\u0934\u0935\7U\2\2\u0935\u0936\7U\2\2\u0936\u01de\3\2\2"+ + "\2\u0937\u0938\7N\2\2\u0938\u0939\7G\2\2\u0939\u093a\7P\2\2\u093a\u093b"+ + "\7K\2\2\u093b\u093c\7G\2\2\u093c\u093d\7P\2\2\u093d\u093e\7V\2\2\u093e"+ + "\u01e0\3\2\2\2\u093f\u0940\7N\2\2\u0940\u0941\7Q\2\2\u0941\u0942\7Y\2"+ + "\2\u0942\u0943\7a\2\2\u0943\u0944\7H\2\2\u0944\u0945\7T\2\2\u0945\u0946"+ + "\7G\2\2\u0946\u0947\7S\2\2\u0947\u0948\7a\2\2\u0948\u0949\7Q\2\2\u0949"+ + "\u094a\7R\2\2\u094a\u094b\7G\2\2\u094b\u094c\7T\2\2\u094c\u094d\7C\2\2"+ + "\u094d\u094e\7V\2\2\u094e\u094f\7Q\2\2\u094f\u0950\7T\2\2\u0950\u01e2"+ + "\3\2\2\2\u0951\u0952\7O\2\2\u0952\u0953\7C\2\2\u0953\u0954\7Z\2\2\u0954"+ + "\u0955\7a\2\2\u0955\u0956\7F\2\2\u0956\u0957\7G\2\2\u0957\u0958\7V\2\2"+ + "\u0958\u0959\7G\2\2\u0959\u095a\7T\2\2\u095a\u095b\7O\2\2\u095b\u095c"+ + "\7K\2\2\u095c\u095d\7P\2\2\u095d\u095e\7K\2\2\u095e\u095f\7\\\2\2\u095f"+ + "\u0960\7G\2\2\u0960\u0961\7F\2\2\u0961\u0962\7a\2\2\u0962\u0963\7U\2\2"+ + "\u0963\u0964\7V\2\2\u0964\u0965\7C\2\2\u0965\u0966\7V\2\2\u0966\u0967"+ + "\7G\2\2\u0967\u0968\7U\2\2\u0968\u01e4\3\2\2\2\u0969\u096a\7O\2\2\u096a"+ + "\u096b\7C\2\2\u096b\u096c\7Z\2\2\u096c\u096d\7a\2\2\u096d\u096e\7G\2\2"+ + "\u096e\u096f\7Z\2\2\u096f\u0970\7R\2\2\u0970\u0971\7C\2\2\u0971\u0972"+ + "\7P\2\2\u0972\u0973\7U\2\2\u0973\u0974\7K\2\2\u0974\u0975\7Q\2\2\u0975"+ + "\u0976\7P\2\2\u0976\u0977\7U\2\2\u0977\u01e6\3\2\2\2\u0978\u0979\7O\2"+ + "\2\u0979\u097a\7K\2\2\u097a\u097b\7P\2\2\u097b\u097c\7K\2\2\u097c\u097d"+ + "\7O\2\2\u097d\u097e\7W\2\2\u097e\u097f\7O\2\2\u097f\u0980\7a\2\2\u0980"+ + "\u0981\7U\2\2\u0981\u0982\7J\2\2\u0982\u0983\7Q\2\2\u0983\u0984\7W\2\2"+ + "\u0984\u0985\7N\2\2\u0985\u0986\7F\2\2\u0986\u0987\7a\2\2\u0987\u0988"+ + "\7O\2\2\u0988\u0989\7C\2\2\u0989\u098a\7V\2\2\u098a\u098b\7E\2\2\u098b"+ + "\u098c\7J\2\2\u098c\u01e8\3\2\2\2\u098d\u098e\7Q\2\2\u098e\u098f\7R\2"+ + "\2\u098f\u0990\7G\2\2\u0990\u0991\7T\2\2\u0991\u0992\7C\2\2\u0992\u0993"+ + "\7V\2\2\u0993\u0994\7Q\2\2\u0994\u0995\7T\2\2\u0995\u01ea\3\2\2\2\u0996"+ + "\u0997\7R\2\2\u0997\u0998\7J\2\2\u0998\u0999\7T\2\2\u0999\u099a\7C\2\2"+ + "\u099a\u099b\7U\2\2\u099b\u099c\7G\2\2\u099c\u099d\7a\2\2\u099d\u099e"+ + "\7U\2\2\u099e\u099f\7N\2\2\u099f\u09a0\7Q\2\2\u09a0\u09a1\7R\2\2\u09a1"+ + "\u01ec\3\2\2\2\u09a2\u09a3\7R\2\2\u09a3\u09a4\7T\2\2\u09a4\u09a5\7G\2"+ + "\2\u09a5\u09a6\7H\2\2\u09a6\u09a7\7K\2\2\u09a7\u09a8\7Z\2\2\u09a8\u09a9"+ + "\7a\2\2\u09a9\u09aa\7N\2\2\u09aa\u09ab\7G\2\2\u09ab\u09ac\7P\2\2\u09ac"+ + "\u09ad\7I\2\2\u09ad\u09ae\7V\2\2\u09ae\u09af\7J\2\2\u09af\u01ee\3\2\2"+ + "\2\u09b0\u09b1\7S\2\2\u09b1\u09b2\7W\2\2\u09b2\u09b3\7Q\2\2\u09b3\u09b4"+ + "\7V\2\2\u09b4\u09b5\7G\2\2\u09b5\u09b6\7a\2\2\u09b6\u09b7\7C\2\2\u09b7"+ + "\u09b8\7P\2\2\u09b8\u09b9\7C\2\2\u09b9\u09ba\7N\2\2\u09ba\u09bb\7[\2\2"+ + "\u09bb\u09bc\7\\\2\2\u09bc\u09bd\7G\2\2\u09bd\u09be\7T\2\2\u09be\u01f0"+ + "\3\2\2\2\u09bf\u09c0\7S\2\2\u09c0\u09c1\7W\2\2\u09c1\u09c2\7Q\2\2\u09c2"+ + "\u09c3\7V\2\2\u09c3\u09c4\7G\2\2\u09c4\u09c5\7a\2\2\u09c5\u09c6\7H\2\2"+ + "\u09c6\u09c7\7K\2\2\u09c7\u09c8\7G\2\2\u09c8\u09c9\7N\2\2\u09c9\u09ca"+ + "\7F\2\2\u09ca\u09cb\7a\2\2\u09cb\u09cc\7U\2\2\u09cc\u09cd\7W\2\2\u09cd"+ + "\u09ce\7H\2\2\u09ce\u09cf\7H\2\2\u09cf\u09d0\7K\2\2\u09d0\u09d1\7Z\2\2"+ + "\u09d1\u01f2\3\2\2\2\u09d2\u09d3\7T\2\2\u09d3\u09d4\7G\2\2\u09d4\u09d5"+ + "\7Y\2\2\u09d5\u09d6\7T\2\2\u09d6\u09d7\7K\2\2\u09d7\u09d8\7V\2\2\u09d8"+ + "\u09d9\7G\2\2\u09d9\u01f4\3\2\2\2\u09da\u09db\7U\2\2\u09db\u09dc\7N\2"+ + "\2\u09dc\u09dd\7Q\2\2\u09dd\u09de\7R\2\2\u09de\u01f6\3\2\2\2\u09df\u09e0"+ + "\7V\2\2\u09e0\u09e1\7K\2\2\u09e1\u09e2\7G\2\2\u09e2\u09e3\7a\2\2\u09e3"+ + "\u09e4\7D\2\2\u09e4\u09e5\7T\2\2\u09e5\u09e6\7G\2\2\u09e6\u09e7\7C\2\2"+ + "\u09e7\u09e8\7M\2\2\u09e8\u09e9\7G\2\2\u09e9\u09ea\7T\2\2\u09ea\u01f8"+ + "\3\2\2\2\u09eb\u09ec\7V\2\2\u09ec\u09ed\7[\2\2\u09ed\u09ee\7R\2\2\u09ee"+ + "\u09ef\7G\2\2\u09ef\u01fa\3\2\2\2\u09f0\u09f1\7\\\2\2\u09f1\u09f2\7G\2"+ + "\2\u09f2\u09f3\7T\2\2\u09f3\u09f4\7Q\2\2\u09f4\u09f5\7a\2\2\u09f5\u09f6"+ + "\7V\2\2\u09f6\u09f7\7G\2\2\u09f7\u09f8\7T\2\2\u09f8\u09f9\7O\2\2\u09f9"+ + "\u09fa\7U\2\2\u09fa\u09fb\7a\2\2\u09fb\u09fc\7S\2\2\u09fc\u09fd\7W\2\2"+ + "\u09fd\u09fe\7G\2\2\u09fe\u09ff\7T\2\2\u09ff\u0a00\7[\2\2\u0a00\u01fc"+ + "\3\2\2\2\u0a01\u0a02\7U\2\2\u0a02\u0a03\7R\2\2\u0a03\u0a04\7C\2\2\u0a04"+ + "\u0a05\7P\2\2\u0a05\u01fe\3\2\2\2\u0a06\u0a07\7O\2\2\u0a07\u0a08\7U\2"+ + "\2\u0a08\u0200\3\2\2\2\u0a09\u0a0a\7U\2\2\u0a0a\u0202\3\2\2\2\u0a0b\u0a0c"+ + "\7O\2\2\u0a0c\u0204\3\2\2\2\u0a0d\u0a0e\7J\2\2\u0a0e\u0206\3\2\2\2\u0a0f"+ + "\u0a10\7Y\2\2\u0a10\u0208\3\2\2\2\u0a11\u0a12\7S\2\2\u0a12\u020a\3\2\2"+ + "\2\u0a13\u0a14\7[\2\2\u0a14\u020c\3\2\2\2\u0a15\u0a16\5\u0215\u010b\2"+ + "\u0a16\u020e\3\2\2\2\u0a17\u0a19\5\u021f\u0110\2\u0a18\u0a17\3\2\2\2\u0a19"+ + "\u0a1a\3\2\2\2\u0a1a\u0a18\3\2\2\2\u0a1a\u0a1b\3\2\2\2\u0a1b\u0210\3\2"+ + "\2\2\u0a1c\u0a1e\5\u021f\u0110\2\u0a1d\u0a1c\3\2\2\2\u0a1e\u0a1f\3\2\2"+ + "\2\u0a1f\u0a1d\3\2\2\2\u0a1f\u0a20\3\2\2\2\u0a20\u0a22\3\2\2\2\u0a21\u0a1d"+ + "\3\2\2\2\u0a21\u0a22\3\2\2\2\u0a22\u0a23\3\2\2\2\u0a23\u0a25\7\60\2\2"+ + "\u0a24\u0a26\5\u021f\u0110\2\u0a25\u0a24\3\2\2\2\u0a26\u0a27\3\2\2\2\u0a27"+ + "\u0a25\3\2\2\2\u0a27\u0a28\3\2\2\2\u0a28\u0212\3\2\2\2\u0a29\u0a2b\t\2"+ + "\2\2\u0a2a\u0a2c\t\3\2\2\u0a2b\u0a2a\3\2\2\2\u0a2c\u0a2d\3\2\2\2\u0a2d"+ + "\u0a2b\3\2\2\2\u0a2d\u0a2e\3\2\2\2\u0a2e\u0a30\3\2\2\2\u0a2f\u0a29\3\2"+ + "\2\2\u0a30\u0a33\3\2\2\2\u0a31\u0a2f\3\2\2\2\u0a31\u0a32\3\2\2\2\u0a32"+ + "\u0214\3\2\2\2\u0a33\u0a31\3\2\2\2\u0a34\u0a36\t\4\2\2\u0a35\u0a34\3\2"+ + "\2\2\u0a36\u0a37\3\2\2\2\u0a37\u0a38\3\2\2\2\u0a37\u0a35\3\2\2\2\u0a38"+ + "\u0a3c\3\2\2\2\u0a39\u0a3b\t\5\2\2\u0a3a\u0a39\3\2\2\2\u0a3b\u0a3e\3\2"+ + "\2\2\u0a3c\u0a3a\3\2\2\2\u0a3c\u0a3d\3\2\2\2\u0a3d\u0216\3\2\2\2\u0a3e"+ + "\u0a3c\3\2\2\2\u0a3f\u0a40\5\u0215\u010b\2\u0a40\u0a41\5\u0213\u010a\2"+ + "\u0a41\u0218\3\2\2\2\u0a42\u0a4a\7$\2\2\u0a43\u0a44\7^\2\2\u0a44\u0a49"+ + "\13\2\2\2\u0a45\u0a46\7$\2\2\u0a46\u0a49\7$\2\2\u0a47\u0a49\n\6\2\2\u0a48"+ + "\u0a43\3\2\2\2\u0a48\u0a45\3\2\2\2\u0a48\u0a47\3\2\2\2\u0a49\u0a4c\3\2"+ + "\2\2\u0a4a\u0a48\3\2\2\2\u0a4a\u0a4b\3\2\2\2\u0a4b\u0a4d\3\2\2\2\u0a4c"+ + "\u0a4a\3\2\2\2\u0a4d\u0a4e\7$\2\2\u0a4e\u021a\3\2\2\2\u0a4f\u0a57\7)\2"+ + "\2\u0a50"; + private static final String _serializedATNSegment1 = + "\u0a51\7^\2\2\u0a51\u0a56\13\2\2\2\u0a52\u0a53\7)\2\2\u0a53\u0a56\7)\2"+ + "\2\u0a54\u0a56\n\7\2\2\u0a55\u0a50\3\2\2\2\u0a55\u0a52\3\2\2\2\u0a55\u0a54"+ + "\3\2\2\2\u0a56\u0a59\3\2\2\2\u0a57\u0a55\3\2\2\2\u0a57\u0a58\3\2\2\2\u0a58"+ + "\u0a5a\3\2\2\2\u0a59\u0a57\3\2\2\2\u0a5a\u0a5b\7)\2\2\u0a5b\u021c\3\2"+ + "\2\2\u0a5c\u0a64\7b\2\2\u0a5d\u0a5e\7^\2\2\u0a5e\u0a63\13\2\2\2\u0a5f"+ + "\u0a60\7b\2\2\u0a60\u0a63\7b\2\2\u0a61\u0a63\n\b\2\2\u0a62\u0a5d\3\2\2"+ + "\2\u0a62\u0a5f\3\2\2\2\u0a62\u0a61\3\2\2\2\u0a63\u0a66\3\2\2\2\u0a64\u0a62"+ + "\3\2\2\2\u0a64\u0a65\3\2\2\2\u0a65\u0a67\3\2\2\2\u0a66\u0a64\3\2\2\2\u0a67"+ + "\u0a68\7b\2\2\u0a68\u021e\3\2\2\2\u0a69\u0a6a\t\t\2\2\u0a6a\u0220\3\2"+ + "\2\2\u0a6b\u0a6c\13\2\2\2\u0a6c\u0a6d\3\2\2\2\u0a6d\u0a6e\b\u0111\2\2"+ + "\u0a6e\u0222\3\2\2\2\21\2\u0a1a\u0a1f\u0a21\u0a27\u0a2d\u0a31\u0a37\u0a3c"+ + "\u0a48\u0a4a\u0a55\u0a57\u0a62\u0a64\3\2\5\2"; + public static final String _serializedATN = Utils.join( + new String[] { + _serializedATNSegment0, + _serializedATNSegment1 + }, + "" + ); + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} \ No newline at end of file diff --git a/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.tokens b/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.tokens new file mode 100644 index 000000000..e7b58d1ef --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/grammar/.antlr/OpenSearchPPLLexer.tokens @@ -0,0 +1,527 @@ +SEARCH=1 +FROM=2 +WHERE=3 +FIELDS=4 +RENAME=5 +STATS=6 +DEDUP=7 +SORT=8 +EVAL=9 +HEAD=10 +TOP=11 +RARE=12 +PARSE=13 +KMEANS=14 +AD=15 +AS=16 +BY=17 +SOURCE=18 +INDEX=19 +D=20 +DESC=21 +SORTBY=22 +AUTO=23 +STR=24 +IP=25 +NUM=26 +KEEPEMPTY=27 +CONSECUTIVE=28 +DEDUP_SPLITVALUES=29 +PARTITIONS=30 +ALLNUM=31 +DELIM=32 +CENTROIDS=33 +ITERATIONS=34 +DISTANCE_TYPE=35 +NUMBER_OF_TREES=36 +SHINGLE_SIZE=37 +SAMPLE_SIZE=38 +OUTPUT_AFTER=39 +TIME_DECAY=40 +ANOMALY_RATE=41 +TIME_FIELD=42 +TIME_ZONE=43 +TRAINING_DATA_SIZE=44 +ANOMALY_SCORE_THRESHOLD=45 +CASE=46 +IN=47 +NOT=48 +OR=49 +AND=50 +XOR=51 +TRUE=52 +FALSE=53 +REGEXP=54 +DATETIME=55 +INTERVAL=56 +MICROSECOND=57 +MILLISECOND=58 +SECOND=59 +MINUTE=60 +HOUR=61 +DAY=62 +WEEK=63 +MONTH=64 +QUARTER=65 +YEAR=66 +SECOND_MICROSECOND=67 +MINUTE_MICROSECOND=68 +MINUTE_SECOND=69 +HOUR_MICROSECOND=70 +HOUR_SECOND=71 +HOUR_MINUTE=72 +DAY_MICROSECOND=73 +DAY_SECOND=74 +DAY_MINUTE=75 +DAY_HOUR=76 +YEAR_MONTH=77 +DATAMODEL=78 +LOOKUP=79 +SAVEDSEARCH=80 +INT=81 +INTEGER=82 +DOUBLE=83 +LONG=84 +FLOAT=85 +STRING=86 +BOOLEAN=87 +PIPE=88 +COMMA=89 +DOT=90 +EQUAL=91 +GREATER=92 +LESS=93 +NOT_GREATER=94 +NOT_LESS=95 +NOT_EQUAL=96 +PLUS=97 +MINUS=98 +STAR=99 +DIVIDE=100 +MODULE=101 +EXCLAMATION_SYMBOL=102 +COLON=103 +LT_PRTHS=104 +RT_PRTHS=105 +LT_SQR_PRTHS=106 +RT_SQR_PRTHS=107 +SINGLE_QUOTE=108 +DOUBLE_QUOTE=109 +BACKTICK=110 +BIT_NOT_OP=111 +BIT_AND_OP=112 +BIT_XOR_OP=113 +AVG=114 +COUNT=115 +DISTINCT_COUNT=116 +ESTDC=117 +ESTDC_ERROR=118 +MAX=119 +MEAN=120 +MEDIAN=121 +MIN=122 +MODE=123 +RANGE=124 +STDEV=125 +STDEVP=126 +SUM=127 +SUMSQ=128 +VAR_SAMP=129 +VAR_POP=130 +STDDEV_SAMP=131 +STDDEV_POP=132 +PERCENTILE=133 +FIRST=134 +LAST=135 +LIST=136 +VALUES=137 +EARLIEST=138 +EARLIEST_TIME=139 +LATEST=140 +LATEST_TIME=141 +PER_DAY=142 +PER_HOUR=143 +PER_MINUTE=144 +PER_SECOND=145 +RATE=146 +SPARKLINE=147 +C=148 +DC=149 +ABS=150 +CEIL=151 +CEILING=152 +CONV=153 +CRC32=154 +E=155 +EXP=156 +FLOOR=157 +LN=158 +LOG=159 +LOG10=160 +LOG2=161 +MOD=162 +PI=163 +POW=164 +POWER=165 +RAND=166 +ROUND=167 +SIGN=168 +SQRT=169 +TRUNCATE=170 +ACOS=171 +ASIN=172 +ATAN=173 +ATAN2=174 +COS=175 +COT=176 +DEGREES=177 +RADIANS=178 +SIN=179 +TAN=180 +ADDDATE=181 +DATE=182 +DATE_ADD=183 +DATE_SUB=184 +DAYOFMONTH=185 +DAYOFWEEK=186 +DAYOFYEAR=187 +DAYNAME=188 +FROM_DAYS=189 +MONTHNAME=190 +SUBDATE=191 +TIME=192 +TIME_TO_SEC=193 +TIMESTAMP=194 +DATE_FORMAT=195 +TO_DAYS=196 +SUBSTR=197 +SUBSTRING=198 +LTRIM=199 +RTRIM=200 +TRIM=201 +TO=202 +LOWER=203 +UPPER=204 +CONCAT=205 +CONCAT_WS=206 +LENGTH=207 +STRCMP=208 +RIGHT=209 +LEFT=210 +ASCII=211 +LOCATE=212 +REPLACE=213 +CAST=214 +LIKE=215 +ISNULL=216 +ISNOTNULL=217 +IFNULL=218 +NULLIF=219 +IF=220 +MATCH=221 +MATCH_PHRASE=222 +SIMPLE_QUERY_STRING=223 +ALLOW_LEADING_WILDCARD=224 +ANALYZE_WILDCARD=225 +ANALYZER=226 +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY=227 +BOOST=228 +CUTOFF_FREQUENCY=229 +DEFAULT_FIELD=230 +DEFAULT_OPERATOR=231 +ENABLE_POSITION_INCREMENTS=232 +FLAGS=233 +FUZZY_MAX_EXPANSIONS=234 +FUZZY_PREFIX_LENGTH=235 +FUZZY_TRANSPOSITIONS=236 +FUZZY_REWRITE=237 +FUZZINESS=238 +LENIENT=239 +LOW_FREQ_OPERATOR=240 +MAX_DETERMINIZED_STATES=241 +MAX_EXPANSIONS=242 +MINIMUM_SHOULD_MATCH=243 +OPERATOR=244 +PHRASE_SLOP=245 +PREFIX_LENGTH=246 +QUOTE_ANALYZER=247 +QUOTE_FIELD_SUFFIX=248 +REWRITE=249 +SLOP=250 +TIE_BREAKER=251 +TYPE=252 +ZERO_TERMS_QUERY=253 +SPAN=254 +MS=255 +S=256 +M=257 +H=258 +W=259 +Q=260 +Y=261 +ID=262 +INTEGER_LITERAL=263 +DECIMAL_LITERAL=264 +ID_DATE_SUFFIX=265 +DQUOTA_STRING=266 +SQUOTA_STRING=267 +BQUOTA_STRING=268 +ERROR_RECOGNITION=269 +'SEARCH'=1 +'FROM'=2 +'WHERE'=3 +'FIELDS'=4 +'RENAME'=5 +'STATS'=6 +'DEDUP'=7 +'SORT'=8 +'EVAL'=9 +'HEAD'=10 +'TOP'=11 +'RARE'=12 +'PARSE'=13 +'KMEANS'=14 +'AD'=15 +'AS'=16 +'BY'=17 +'SOURCE'=18 +'INDEX'=19 +'D'=20 +'DESC'=21 +'SORTBY'=22 +'AUTO'=23 +'STR'=24 +'IP'=25 +'NUM'=26 +'KEEPEMPTY'=27 +'CONSECUTIVE'=28 +'DEDUP_SPLITVALUES'=29 +'PARTITIONS'=30 +'ALLNUM'=31 +'DELIM'=32 +'CENTROIDS'=33 +'ITERATIONS'=34 +'DISTANCE_TYPE'=35 +'NUMBER_OF_TREES'=36 +'SHINGLE_SIZE'=37 +'SAMPLE_SIZE'=38 +'OUTPUT_AFTER'=39 +'TIME_DECAY'=40 +'ANOMALY_RATE'=41 +'TIME_FIELD'=42 +'TIME_ZONE'=43 +'TRAINING_DATA_SIZE'=44 +'ANOMALY_SCORE_THRESHOLD'=45 +'CASE'=46 +'IN'=47 +'NOT'=48 +'OR'=49 +'AND'=50 +'XOR'=51 +'TRUE'=52 +'FALSE'=53 +'REGEXP'=54 +'DATETIME'=55 +'INTERVAL'=56 +'MICROSECOND'=57 +'MILLISECOND'=58 +'SECOND'=59 +'MINUTE'=60 +'HOUR'=61 +'DAY'=62 +'WEEK'=63 +'MONTH'=64 +'QUARTER'=65 +'YEAR'=66 +'SECOND_MICROSECOND'=67 +'MINUTE_MICROSECOND'=68 +'MINUTE_SECOND'=69 +'HOUR_MICROSECOND'=70 +'HOUR_SECOND'=71 +'HOUR_MINUTE'=72 +'DAY_MICROSECOND'=73 +'DAY_SECOND'=74 +'DAY_MINUTE'=75 +'DAY_HOUR'=76 +'YEAR_MONTH'=77 +'DATAMODEL'=78 +'LOOKUP'=79 +'SAVEDSEARCH'=80 +'INT'=81 +'INTEGER'=82 +'DOUBLE'=83 +'LONG'=84 +'FLOAT'=85 +'STRING'=86 +'BOOLEAN'=87 +'|'=88 +','=89 +'.'=90 +'='=91 +'>'=92 +'<'=93 +'+'=97 +'-'=98 +'*'=99 +'/'=100 +'%'=101 +'!'=102 +':'=103 +'('=104 +')'=105 +'['=106 +']'=107 +'\''=108 +'"'=109 +'`'=110 +'~'=111 +'&'=112 +'^'=113 +'AVG'=114 +'COUNT'=115 +'DISTINCT_COUNT'=116 +'ESTDC'=117 +'ESTDC_ERROR'=118 +'MAX'=119 +'MEAN'=120 +'MEDIAN'=121 +'MIN'=122 +'MODE'=123 +'RANGE'=124 +'STDEV'=125 +'STDEVP'=126 +'SUM'=127 +'SUMSQ'=128 +'VAR_SAMP'=129 +'VAR_POP'=130 +'STDDEV_SAMP'=131 +'STDDEV_POP'=132 +'PERCENTILE'=133 +'FIRST'=134 +'LAST'=135 +'LIST'=136 +'VALUES'=137 +'EARLIEST'=138 +'EARLIEST_TIME'=139 +'LATEST'=140 +'LATEST_TIME'=141 +'PER_DAY'=142 +'PER_HOUR'=143 +'PER_MINUTE'=144 +'PER_SECOND'=145 +'RATE'=146 +'SPARKLINE'=147 +'C'=148 +'DC'=149 +'ABS'=150 +'CEIL'=151 +'CEILING'=152 +'CONV'=153 +'CRC32'=154 +'E'=155 +'EXP'=156 +'FLOOR'=157 +'LN'=158 +'LOG'=159 +'LOG10'=160 +'LOG2'=161 +'MOD'=162 +'PI'=163 +'POW'=164 +'POWER'=165 +'RAND'=166 +'ROUND'=167 +'SIGN'=168 +'SQRT'=169 +'TRUNCATE'=170 +'ACOS'=171 +'ASIN'=172 +'ATAN'=173 +'ATAN2'=174 +'COS'=175 +'COT'=176 +'DEGREES'=177 +'RADIANS'=178 +'SIN'=179 +'TAN'=180 +'ADDDATE'=181 +'DATE'=182 +'DATE_ADD'=183 +'DATE_SUB'=184 +'DAYOFMONTH'=185 +'DAYOFWEEK'=186 +'DAYOFYEAR'=187 +'DAYNAME'=188 +'FROM_DAYS'=189 +'MONTHNAME'=190 +'SUBDATE'=191 +'TIME'=192 +'TIME_TO_SEC'=193 +'TIMESTAMP'=194 +'DATE_FORMAT'=195 +'TO_DAYS'=196 +'SUBSTR'=197 +'SUBSTRING'=198 +'LTRIM'=199 +'RTRIM'=200 +'TRIM'=201 +'TO'=202 +'LOWER'=203 +'UPPER'=204 +'CONCAT'=205 +'CONCAT_WS'=206 +'LENGTH'=207 +'STRCMP'=208 +'RIGHT'=209 +'LEFT'=210 +'ASCII'=211 +'LOCATE'=212 +'REPLACE'=213 +'CAST'=214 +'LIKE'=215 +'ISNULL'=216 +'ISNOTNULL'=217 +'IFNULL'=218 +'NULLIF'=219 +'IF'=220 +'MATCH'=221 +'MATCH_PHRASE'=222 +'SIMPLE_QUERY_STRING'=223 +'ALLOW_LEADING_WILDCARD'=224 +'ANALYZE_WILDCARD'=225 +'ANALYZER'=226 +'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'=227 +'BOOST'=228 +'CUTOFF_FREQUENCY'=229 +'DEFAULT_FIELD'=230 +'DEFAULT_OPERATOR'=231 +'ENABLE_POSITION_INCREMENTS'=232 +'FLAGS'=233 +'FUZZY_MAX_EXPANSIONS'=234 +'FUZZY_PREFIX_LENGTH'=235 +'FUZZY_TRANSPOSITIONS'=236 +'FUZZY_REWRITE'=237 +'FUZZINESS'=238 +'LENIENT'=239 +'LOW_FREQ_OPERATOR'=240 +'MAX_DETERMINIZED_STATES'=241 +'MAX_EXPANSIONS'=242 +'MINIMUM_SHOULD_MATCH'=243 +'OPERATOR'=244 +'PHRASE_SLOP'=245 +'PREFIX_LENGTH'=246 +'QUOTE_ANALYZER'=247 +'QUOTE_FIELD_SUFFIX'=248 +'REWRITE'=249 +'SLOP'=250 +'TIE_BREAKER'=251 +'TYPE'=252 +'ZERO_TERMS_QUERY'=253 +'SPAN'=254 +'MS'=255 +'S'=256 +'M'=257 +'H'=258 +'W'=259 +'Q'=260 +'Y'=261 diff --git a/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLLexer.g4 b/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLLexer.g4 new file mode 100644 index 000000000..c30967a77 --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLLexer.g4 @@ -0,0 +1,333 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + + +lexer grammar OpenSearchPPLLexer; + +channels { WHITESPACE, ERRORCHANNEL } + + +// COMMAND KEYWORDS +SEARCH: 'SEARCH'; +FROM: 'FROM'; +WHERE: 'WHERE'; +FIELDS: 'FIELDS'; +RENAME: 'RENAME'; +STATS: 'STATS'; +DEDUP: 'DEDUP'; +SORT: 'SORT'; +EVAL: 'EVAL'; +HEAD: 'HEAD'; +TOP: 'TOP'; +RARE: 'RARE'; +PARSE: 'PARSE'; +KMEANS: 'KMEANS'; +AD: 'AD'; + +// COMMAND ASSIST KEYWORDS +AS: 'AS'; +BY: 'BY'; +SOURCE: 'SOURCE'; +INDEX: 'INDEX'; +D: 'D'; +DESC: 'DESC'; + +// CLAUSE KEYWORDS +SORTBY: 'SORTBY'; + +// FIELD KEYWORDS +AUTO: 'AUTO'; +STR: 'STR'; +IP: 'IP'; +NUM: 'NUM'; + +// ARGUMENT KEYWORDS +KEEPEMPTY: 'KEEPEMPTY'; +CONSECUTIVE: 'CONSECUTIVE'; +DEDUP_SPLITVALUES: 'DEDUP_SPLITVALUES'; +PARTITIONS: 'PARTITIONS'; +ALLNUM: 'ALLNUM'; +DELIM: 'DELIM'; +CENTROIDS: 'CENTROIDS'; +ITERATIONS: 'ITERATIONS'; +DISTANCE_TYPE: 'DISTANCE_TYPE'; +NUMBER_OF_TREES: 'NUMBER_OF_TREES'; +SHINGLE_SIZE: 'SHINGLE_SIZE'; +SAMPLE_SIZE: 'SAMPLE_SIZE'; +OUTPUT_AFTER: 'OUTPUT_AFTER'; +TIME_DECAY: 'TIME_DECAY'; +ANOMALY_RATE: 'ANOMALY_RATE'; +TIME_FIELD: 'TIME_FIELD'; +TIME_ZONE: 'TIME_ZONE'; +TRAINING_DATA_SIZE: 'TRAINING_DATA_SIZE'; +ANOMALY_SCORE_THRESHOLD: 'ANOMALY_SCORE_THRESHOLD'; + +// COMPARISON FUNCTION KEYWORDS +CASE: 'CASE'; +IN: 'IN'; + +// LOGICAL KEYWORDS +NOT: 'NOT'; +OR: 'OR'; +AND: 'AND'; +XOR: 'XOR'; +TRUE: 'TRUE'; +FALSE: 'FALSE'; +REGEXP: 'REGEXP'; + +// DATETIME, INTERVAL AND UNIT KEYWORDS +DATETIME: 'DATETIME'; +INTERVAL: 'INTERVAL'; +MICROSECOND: 'MICROSECOND'; +MILLISECOND: 'MILLISECOND'; +SECOND: 'SECOND'; +MINUTE: 'MINUTE'; +HOUR: 'HOUR'; +DAY: 'DAY'; +WEEK: 'WEEK'; +MONTH: 'MONTH'; +QUARTER: 'QUARTER'; +YEAR: 'YEAR'; +SECOND_MICROSECOND: 'SECOND_MICROSECOND'; +MINUTE_MICROSECOND: 'MINUTE_MICROSECOND'; +MINUTE_SECOND: 'MINUTE_SECOND'; +HOUR_MICROSECOND: 'HOUR_MICROSECOND'; +HOUR_SECOND: 'HOUR_SECOND'; +HOUR_MINUTE: 'HOUR_MINUTE'; +DAY_MICROSECOND: 'DAY_MICROSECOND'; +DAY_SECOND: 'DAY_SECOND'; +DAY_MINUTE: 'DAY_MINUTE'; +DAY_HOUR: 'DAY_HOUR'; +YEAR_MONTH: 'YEAR_MONTH'; + +// DATASET TYPES +DATAMODEL: 'DATAMODEL'; +LOOKUP: 'LOOKUP'; +SAVEDSEARCH: 'SAVEDSEARCH'; + +// CONVERTED DATA TYPES +INT: 'INT'; +INTEGER: 'INTEGER'; +DOUBLE: 'DOUBLE'; +LONG: 'LONG'; +FLOAT: 'FLOAT'; +STRING: 'STRING'; +BOOLEAN: 'BOOLEAN'; + +// SPECIAL CHARACTERS AND OPERATORS +PIPE: '|'; +COMMA: ','; +DOT: '.'; +EQUAL: '='; +GREATER: '>'; +LESS: '<'; +NOT_GREATER: '<' '='; +NOT_LESS: '>' '='; +NOT_EQUAL: '!' '='; +PLUS: '+'; +MINUS: '-'; +STAR: '*'; +DIVIDE: '/'; +MODULE: '%'; +EXCLAMATION_SYMBOL: '!'; +COLON: ':'; +LT_PRTHS: '('; +RT_PRTHS: ')'; +LT_SQR_PRTHS: '['; +RT_SQR_PRTHS: ']'; +SINGLE_QUOTE: '\''; +DOUBLE_QUOTE: '"'; +BACKTICK: '`'; + +// Operators. Bit + +BIT_NOT_OP: '~'; +BIT_AND_OP: '&'; +BIT_XOR_OP: '^'; + +// AGGREGATIONS +AVG: 'AVG'; +COUNT: 'COUNT'; +DISTINCT_COUNT: 'DISTINCT_COUNT'; +ESTDC: 'ESTDC'; +ESTDC_ERROR: 'ESTDC_ERROR'; +MAX: 'MAX'; +MEAN: 'MEAN'; +MEDIAN: 'MEDIAN'; +MIN: 'MIN'; +MODE: 'MODE'; +RANGE: 'RANGE'; +STDEV: 'STDEV'; +STDEVP: 'STDEVP'; +SUM: 'SUM'; +SUMSQ: 'SUMSQ'; +VAR_SAMP: 'VAR_SAMP'; +VAR_POP: 'VAR_POP'; +STDDEV_SAMP: 'STDDEV_SAMP'; +STDDEV_POP: 'STDDEV_POP'; +PERCENTILE: 'PERCENTILE'; +FIRST: 'FIRST'; +LAST: 'LAST'; +LIST: 'LIST'; +VALUES: 'VALUES'; +EARLIEST: 'EARLIEST'; +EARLIEST_TIME: 'EARLIEST_TIME'; +LATEST: 'LATEST'; +LATEST_TIME: 'LATEST_TIME'; +PER_DAY: 'PER_DAY'; +PER_HOUR: 'PER_HOUR'; +PER_MINUTE: 'PER_MINUTE'; +PER_SECOND: 'PER_SECOND'; +RATE: 'RATE'; +SPARKLINE: 'SPARKLINE'; +C: 'C'; +DC: 'DC'; + +// BASIC FUNCTIONS +ABS: 'ABS'; +CEIL: 'CEIL'; +CEILING: 'CEILING'; +CONV: 'CONV'; +CRC32: 'CRC32'; +E: 'E'; +EXP: 'EXP'; +FLOOR: 'FLOOR'; +LN: 'LN'; +LOG: 'LOG'; +LOG10: 'LOG10'; +LOG2: 'LOG2'; +MOD: 'MOD'; +PI: 'PI'; +POW: 'POW'; +POWER: 'POWER'; +RAND: 'RAND'; +ROUND: 'ROUND'; +SIGN: 'SIGN'; +SQRT: 'SQRT'; +TRUNCATE: 'TRUNCATE'; + +// TRIGONOMETRIC FUNCTIONS +ACOS: 'ACOS'; +ASIN: 'ASIN'; +ATAN: 'ATAN'; +ATAN2: 'ATAN2'; +COS: 'COS'; +COT: 'COT'; +DEGREES: 'DEGREES'; +RADIANS: 'RADIANS'; +SIN: 'SIN'; +TAN: 'TAN'; + +// DATE AND TIME FUNCTIONS +ADDDATE: 'ADDDATE'; +DATE: 'DATE'; +DATE_ADD: 'DATE_ADD'; +DATE_SUB: 'DATE_SUB'; +DAYOFMONTH: 'DAYOFMONTH'; +DAYOFWEEK: 'DAYOFWEEK'; +DAYOFYEAR: 'DAYOFYEAR'; +DAYNAME: 'DAYNAME'; +FROM_DAYS: 'FROM_DAYS'; +MONTHNAME: 'MONTHNAME'; +SUBDATE: 'SUBDATE'; +TIME: 'TIME'; +TIME_TO_SEC: 'TIME_TO_SEC'; +TIMESTAMP: 'TIMESTAMP'; +DATE_FORMAT: 'DATE_FORMAT'; +TO_DAYS: 'TO_DAYS'; + +// TEXT FUNCTIONS +SUBSTR: 'SUBSTR'; +SUBSTRING: 'SUBSTRING'; +LTRIM: 'LTRIM'; +RTRIM: 'RTRIM'; +TRIM: 'TRIM'; +TO: 'TO'; +LOWER: 'LOWER'; +UPPER: 'UPPER'; +CONCAT: 'CONCAT'; +CONCAT_WS: 'CONCAT_WS'; +LENGTH: 'LENGTH'; +STRCMP: 'STRCMP'; +RIGHT: 'RIGHT'; +LEFT: 'LEFT'; +ASCII: 'ASCII'; +LOCATE: 'LOCATE'; +REPLACE: 'REPLACE'; +CAST: 'CAST'; + +// BOOL FUNCTIONS +LIKE: 'LIKE'; +ISNULL: 'ISNULL'; +ISNOTNULL: 'ISNOTNULL'; + +// FLOWCONTROL FUNCTIONS +IFNULL: 'IFNULL'; +NULLIF: 'NULLIF'; +IF: 'IF'; + +// RELEVANCE FUNCTIONS AND PARAMETERS +MATCH: 'MATCH'; +MATCH_PHRASE: 'MATCH_PHRASE'; +SIMPLE_QUERY_STRING: 'SIMPLE_QUERY_STRING'; + +ALLOW_LEADING_WILDCARD: 'ALLOW_LEADING_WILDCARD'; +ANALYZE_WILDCARD: 'ANALYZE_WILDCARD'; +ANALYZER: 'ANALYZER'; +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY:'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'; +BOOST: 'BOOST'; +CUTOFF_FREQUENCY: 'CUTOFF_FREQUENCY'; +DEFAULT_FIELD: 'DEFAULT_FIELD'; +DEFAULT_OPERATOR: 'DEFAULT_OPERATOR'; +ENABLE_POSITION_INCREMENTS: 'ENABLE_POSITION_INCREMENTS'; +FLAGS: 'FLAGS'; +FUZZY_MAX_EXPANSIONS: 'FUZZY_MAX_EXPANSIONS'; +FUZZY_PREFIX_LENGTH: 'FUZZY_PREFIX_LENGTH'; +FUZZY_TRANSPOSITIONS: 'FUZZY_TRANSPOSITIONS'; +FUZZY_REWRITE: 'FUZZY_REWRITE'; +FUZZINESS: 'FUZZINESS'; +LENIENT: 'LENIENT'; +LOW_FREQ_OPERATOR: 'LOW_FREQ_OPERATOR'; +MAX_DETERMINIZED_STATES: 'MAX_DETERMINIZED_STATES'; +MAX_EXPANSIONS: 'MAX_EXPANSIONS'; +MINIMUM_SHOULD_MATCH: 'MINIMUM_SHOULD_MATCH'; +OPERATOR: 'OPERATOR'; +PHRASE_SLOP: 'PHRASE_SLOP'; +PREFIX_LENGTH: 'PREFIX_LENGTH'; +QUOTE_ANALYZER: 'QUOTE_ANALYZER'; +QUOTE_FIELD_SUFFIX: 'QUOTE_FIELD_SUFFIX'; +REWRITE: 'REWRITE'; +SLOP: 'SLOP'; +TIE_BREAKER: 'TIE_BREAKER'; +TYPE: 'TYPE'; +ZERO_TERMS_QUERY: 'ZERO_TERMS_QUERY'; + +// SPAN KEYWORDS +SPAN: 'SPAN'; +MS: 'MS'; +S: 'S'; +M: 'M'; +H: 'H'; +W: 'W'; +Q: 'Q'; +Y: 'Y'; + + +// LITERALS AND VALUES +//STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; +ID: ID_LITERAL; +INTEGER_LITERAL: DEC_DIGIT+; +DECIMAL_LITERAL: (DEC_DIGIT+)? '.' DEC_DIGIT+; + +fragment DATE_SUFFIX: ([\-.][*0-9]+)*; +fragment ID_LITERAL: [@*A-Z]+?[*A-Z_\-0-9]*; +ID_DATE_SUFFIX: ID_LITERAL DATE_SUFFIX; +DQUOTA_STRING: '"' ( '\\'. | '""' | ~('"'| '\\') )* '"'; +SQUOTA_STRING: '\'' ('\\'. | '\'\'' | ~('\'' | '\\'))* '\''; +BQUOTA_STRING: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`'; +fragment DEC_DIGIT: [0-9]; + + +ERROR_RECOGNITION: . -> channel(ERRORCHANNEL); \ No newline at end of file diff --git a/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLParser.g4 b/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLParser.g4 new file mode 100644 index 000000000..de96295f9 --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/grammar/OpenSearchPPLParser.g4 @@ -0,0 +1,475 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + + + +parser grammar OpenSearchPPLParser; +options { tokenVocab=OpenSearchPPLLexer; } + +root + : pplStatement? EOF + ; + +/** statement */ +pplStatement + : searchCommand (PIPE commands)* + ; + +/** commands */ +commands + : whereCommand | fieldsCommand | renameCommand | statsCommand | dedupCommand | sortCommand | evalCommand | headCommand + | topCommand | rareCommand | parseCommand | kmeansCommand | adCommand; + +searchCommand + : (SEARCH)? fromClause #searchFrom + | (SEARCH)? fromClause logicalExpression #searchFromFilter + | (SEARCH)? logicalExpression fromClause #searchFilterFrom + ; + +whereCommand + : WHERE logicalExpression + ; + +fieldsCommand + : FIELDS (PLUS | MINUS)? fieldList + ; + +renameCommand + : RENAME renameClasue (COMMA renameClasue)* + ; + +statsCommand + : STATS + (PARTITIONS EQUAL partitions=integerLiteral)? + (ALLNUM EQUAL allnum=booleanLiteral)? + (DELIM EQUAL delim=stringLiteral)? + statsAggTerm (COMMA statsAggTerm)* + (statsByClause)? + (DEDUP_SPLITVALUES EQUAL dedupsplit=booleanLiteral)? + ; + +dedupCommand + : DEDUP + (number=integerLiteral)? + fieldList + (KEEPEMPTY EQUAL keepempty=booleanLiteral)? + (CONSECUTIVE EQUAL consecutive=booleanLiteral)? + ; + +sortCommand + : SORT sortbyClause + ; + +evalCommand + : EVAL evalClause (COMMA evalClause)* + ; + +headCommand + : HEAD + (number=integerLiteral)? + (FROM from=integerLiteral)? + ; + +topCommand + : TOP + (number=integerLiteral)? + fieldList + (byClause)? + ; + +rareCommand + : RARE + fieldList + (byClause)? + ; + +parseCommand + : PARSE expression pattern + ; + +kmeansCommand + : KMEANS (kmeansParameter)* + ; + +kmeansParameter + : (CENTROIDS EQUAL centroids=integerLiteral) + | (ITERATIONS EQUAL iterations=integerLiteral) + | (DISTANCE_TYPE EQUAL distance_type=stringLiteral) + ; + +adCommand + : AD (adParameter)* + ; + +adParameter + : (NUMBER_OF_TREES EQUAL number_of_trees=integerLiteral) + | (SHINGLE_SIZE EQUAL shingle_size=integerLiteral) + | (SAMPLE_SIZE EQUAL sample_size=integerLiteral) + | (OUTPUT_AFTER EQUAL output_after=integerLiteral) + | (TIME_DECAY EQUAL time_decay=decimalLiteral) + | (ANOMALY_RATE EQUAL anomaly_rate=decimalLiteral) + | (TIME_FIELD EQUAL time_field=stringLiteral) + | (DATE_FORMAT EQUAL date_format=stringLiteral) + | (TIME_ZONE EQUAL time_zone=stringLiteral) + | (TRAINING_DATA_SIZE EQUAL training_data_size=integerLiteral) + | (ANOMALY_SCORE_THRESHOLD EQUAL anomaly_score_threshold=decimalLiteral) + ; + +/** clauses */ +fromClause + : SOURCE EQUAL tableSource (COMMA tableSource)* + | INDEX EQUAL tableSource (COMMA tableSource)* + ; + +renameClasue + : orignalField=wcFieldExpression AS renamedField=wcFieldExpression + ; + +byClause + : BY fieldList + ; + +statsByClause + : BY fieldList + | BY bySpanClause + | BY bySpanClause COMMA fieldList + ; + +bySpanClause + : spanClause (AS alias=qualifiedName)? + ; + +spanClause + : SPAN LT_PRTHS fieldExpression COMMA value=literalValue (unit=timespanUnit)? RT_PRTHS + ; + +sortbyClause + : sortField (COMMA sortField)* + ; + +evalClause + : fieldExpression EQUAL expression + ; + +/** aggregation terms */ +statsAggTerm + : statsFunction (AS alias=wcFieldExpression)? + ; + +/** aggregation functions */ +statsFunction + : statsFunctionName LT_PRTHS valueExpression RT_PRTHS #statsFunctionCall + | COUNT LT_PRTHS RT_PRTHS #countAllFunctionCall + | (DISTINCT_COUNT | DC) LT_PRTHS valueExpression RT_PRTHS #distinctCountFunctionCall + | percentileAggFunction #percentileAggFunctionCall + ; + +statsFunctionName + : AVG | COUNT | SUM | MIN | MAX | VAR_SAMP | VAR_POP | STDDEV_SAMP | STDDEV_POP + ; + +percentileAggFunction + : PERCENTILE LESS value=integerLiteral GREATER LT_PRTHS aggField=fieldExpression RT_PRTHS + ; + +/** expressions */ +expression + : logicalExpression + | comparisonExpression + | valueExpression + ; + +logicalExpression + : comparisonExpression #comparsion + | NOT logicalExpression #logicalNot + | left=logicalExpression OR right=logicalExpression #logicalOr + | left=logicalExpression (AND)? right=logicalExpression #logicalAnd + | left=logicalExpression XOR right=logicalExpression #logicalXor + | booleanExpression #booleanExpr + | relevanceExpression #relevanceExpr + ; + +comparisonExpression + : left=valueExpression comparisonOperator right=valueExpression #compareExpr + | valueExpression IN valueList #inExpr + ; + +valueExpression + : left=valueExpression binaryOperator right=valueExpression #binaryArithmetic + | LT_PRTHS left=valueExpression binaryOperator + right=valueExpression RT_PRTHS #parentheticBinaryArithmetic + | primaryExpression #valueExpressionDefault + ; + +primaryExpression + : evalFunctionCall + | dataTypeFunctionCall + | fieldExpression + | literalValue + ; + +booleanExpression + : booleanFunctionCall + ; + +relevanceExpression + : singleFieldRelevanceFunction | multiFieldRelevanceFunction + ; + +// Field is a single column +singleFieldRelevanceFunction + : singleFieldRelevanceFunctionName LT_PRTHS + field=relevanceField COMMA query=relevanceQuery + (COMMA relevanceArg)* RT_PRTHS + ; + +// Field is a list of columns +multiFieldRelevanceFunction + : multiFieldRelevanceFunctionName LT_PRTHS + LT_SQR_PRTHS field=relevanceFieldAndWeight (COMMA field=relevanceFieldAndWeight)* RT_SQR_PRTHS + COMMA query=relevanceQuery (COMMA relevanceArg)* RT_PRTHS + ; + +/** tables */ +tableSource + : qualifiedName + | ID_DATE_SUFFIX + ; + +/** fields */ +fieldList + : fieldExpression (COMMA fieldExpression)* + ; + +wcFieldList + : wcFieldExpression (COMMA wcFieldExpression)* + ; + +sortField + : (PLUS | MINUS)? sortFieldExpression + ; + +sortFieldExpression + : fieldExpression + | AUTO LT_PRTHS fieldExpression RT_PRTHS + | STR LT_PRTHS fieldExpression RT_PRTHS + | IP LT_PRTHS fieldExpression RT_PRTHS + | NUM LT_PRTHS fieldExpression RT_PRTHS + ; + +fieldExpression + : qualifiedName + ; + +wcFieldExpression + : wcQualifiedName + ; + +/** functions */ +evalFunctionCall + : evalFunctionName LT_PRTHS functionArgs RT_PRTHS + ; + +/** cast function */ +dataTypeFunctionCall + : CAST LT_PRTHS expression AS convertedDataType RT_PRTHS + ; + +/** boolean functions */ +booleanFunctionCall + : conditionFunctionBase LT_PRTHS functionArgs RT_PRTHS + ; + +convertedDataType + : typeName=DATE + | typeName=TIME + | typeName=TIMESTAMP + | typeName=INT + | typeName=INTEGER + | typeName=DOUBLE + | typeName=LONG + | typeName=FLOAT + | typeName=STRING + | typeName=BOOLEAN + ; + +evalFunctionName + : mathematicalFunctionBase + | dateAndTimeFunctionBase + | textFunctionBase + | conditionFunctionBase + ; + +functionArgs + : (functionArg (COMMA functionArg)*)? + ; + +functionArg + : valueExpression + ; + +relevanceArg + : relevanceArgName EQUAL relevanceArgValue + ; + +relevanceArgName + : ALLOW_LEADING_WILDCARD | ANALYZER | ANALYZE_WILDCARD | AUTO_GENERATE_SYNONYMS_PHRASE_QUERY + | BOOST | CUTOFF_FREQUENCY | DEFAULT_FIELD | DEFAULT_OPERATOR | ENABLE_POSITION_INCREMENTS + | FIELDS | FLAGS | FUZZINESS | FUZZY_MAX_EXPANSIONS | FUZZY_PREFIX_LENGTH | FUZZY_REWRITE + | FUZZY_TRANSPOSITIONS | LENIENT | LOW_FREQ_OPERATOR | MAX_DETERMINIZED_STATES + | MAX_EXPANSIONS | MINIMUM_SHOULD_MATCH | OPERATOR | PHRASE_SLOP | PREFIX_LENGTH + | QUOTE_ANALYZER | QUOTE_FIELD_SUFFIX | REWRITE | SLOP | TIE_BREAKER | TIME_ZONE | TYPE + | ZERO_TERMS_QUERY + ; + +relevanceFieldAndWeight + : field=relevanceField + | field=relevanceField weight=relevanceFieldWeight + | field=relevanceField BIT_XOR_OP weight=relevanceFieldWeight + ; + +relevanceFieldWeight + : integerLiteral + | decimalLiteral + ; + +relevanceField + : qualifiedName + | stringLiteral + ; + +relevanceQuery + : relevanceArgValue + ; + +relevanceArgValue + : qualifiedName + | literalValue + ; + +mathematicalFunctionBase + : ABS | CEIL | CEILING | CONV | CRC32 | E | EXP | FLOOR | LN | LOG | LOG10 | LOG2 | MOD | PI |POW | POWER + | RAND | ROUND | SIGN | SQRT | TRUNCATE + | trigonometricFunctionName + ; + +trigonometricFunctionName + : ACOS | ASIN | ATAN | ATAN2 | COS | COT | DEGREES | RADIANS | SIN | TAN + ; + +dateAndTimeFunctionBase + : ADDDATE | DATE | DATE_ADD | DATE_SUB | DAY | DAYNAME | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR | FROM_DAYS + | HOUR | MICROSECOND | MINUTE | MONTH | MONTHNAME | QUARTER | SECOND | SUBDATE | TIME | TIME_TO_SEC + | TIMESTAMP | TO_DAYS | YEAR | WEEK | DATE_FORMAT + ; + +/** condition function return boolean value */ +conditionFunctionBase + : LIKE + | IF | ISNULL | ISNOTNULL | IFNULL | NULLIF + ; + +textFunctionBase + : SUBSTR | SUBSTRING | TRIM | LTRIM | RTRIM | LOWER | UPPER | CONCAT | CONCAT_WS | LENGTH | STRCMP + | RIGHT | LEFT | ASCII | LOCATE | REPLACE + ; + +/** operators */ +comparisonOperator + : EQUAL | NOT_EQUAL | LESS | NOT_LESS | GREATER | NOT_GREATER | REGEXP + ; + +binaryOperator + : PLUS | MINUS | STAR | DIVIDE | MODULE + ; + + +singleFieldRelevanceFunctionName + : MATCH + | MATCH_PHRASE + ; + +multiFieldRelevanceFunctionName + : SIMPLE_QUERY_STRING + ; + +/** literals and values*/ +literalValue + : intervalLiteral + | stringLiteral + | integerLiteral + | decimalLiteral + | booleanLiteral + ; + +intervalLiteral + : INTERVAL valueExpression intervalUnit + ; + +stringLiteral + : DQUOTA_STRING | SQUOTA_STRING + ; + +integerLiteral + : (PLUS | MINUS)? INTEGER_LITERAL + ; + +decimalLiteral + : (PLUS | MINUS)? DECIMAL_LITERAL + ; + +booleanLiteral + : TRUE | FALSE + ; + +pattern + : stringLiteral + ; + +intervalUnit + : MICROSECOND | SECOND | MINUTE | HOUR | DAY | WEEK | MONTH | QUARTER | YEAR | SECOND_MICROSECOND + | MINUTE_MICROSECOND | MINUTE_SECOND | HOUR_MICROSECOND | HOUR_SECOND | HOUR_MINUTE | DAY_MICROSECOND + | DAY_SECOND | DAY_MINUTE | DAY_HOUR | YEAR_MONTH + ; + +timespanUnit + : MS | S | M | H | D | W | Q | Y + | MILLISECOND | SECOND | MINUTE | HOUR | DAY | WEEK | MONTH | QUARTER | YEAR + ; + + +valueList + : LT_PRTHS literalValue (COMMA literalValue)* RT_PRTHS + ; + +qualifiedName + : ident (DOT ident)* #identsAsQualifiedName + ; + +wcQualifiedName + : wildcard (DOT wildcard)* #identsAsWildcardQualifiedName + ; + +ident + : (DOT)? ID + | BACKTICK ident BACKTICK + | BQUOTA_STRING + | keywordsCanBeId + ; + +wildcard + : ident (MODULE ident)* (MODULE)? + | SINGLE_QUOTE wildcard SINGLE_QUOTE + | DOUBLE_QUOTE wildcard DOUBLE_QUOTE + | BACKTICK wildcard BACKTICK + ; + +keywordsCanBeId + : D // OD SQL and ODBC special + | statsFunctionName + | TIMESTAMP | DATE | TIME + | FIRST | LAST + | timespanUnit | SPAN + ; \ No newline at end of file diff --git a/dashboards-observability/common/query_manager/antlr/ppl_syntax_parser.ts b/dashboards-observability/common/query_manager/antlr/ppl_syntax_parser.ts new file mode 100644 index 000000000..6f62bce1c --- /dev/null +++ b/dashboards-observability/common/query_manager/antlr/ppl_syntax_parser.ts @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CharStreams, CommonTokenStream } from 'antlr4ts'; +import { CaseInsensitiveCharStream } from './adaptors/case_insensitive_char_stream'; +import { OpenSearchPPLLexer } from './output/OpenSearchPPLLexer'; +import { OpenSearchPPLParser } from './output/OpenSearchPPLParser'; + +/** + * PPL Syntax Parser. + */ +export class PPLSyntaxParser { + /** + * Analyze the query syntax. + */ + + parse(query: string) { + return this.createParser(this.createLexer(query)); + } + + createLexer(query: string) { + return new OpenSearchPPLLexer(new CaseInsensitiveCharStream(CharStreams.fromString(query))); + } + + createParser(lexer: OpenSearchPPLLexer) { + return new OpenSearchPPLParser(new CommonTokenStream(lexer)); + } +} diff --git a/dashboards-observability/common/query_manager/ast/builder/query_builder.ts b/dashboards-observability/common/query_manager/ast/builder/query_builder.ts new file mode 100644 index 000000000..a6b6494c0 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/builder/query_builder.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface QueryBuilder { + build: () => T; +} diff --git a/dashboards-observability/common/query_manager/ast/builder/stats_ast_builder.ts b/dashboards-observability/common/query_manager/ast/builder/stats_ast_builder.ts new file mode 100644 index 000000000..6a396654a --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/builder/stats_ast_builder.ts @@ -0,0 +1,232 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isFunction, isEqual } from 'lodash'; +import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'; +import { + RootContext, + PplStatementContext, + CommandsContext, + StatsCommandContext, + BooleanLiteralContext, + BySpanClauseContext, + FieldExpressionContext, + FieldListContext, + IntegerLiteralContext, + LiteralValueContext, + QualifiedNameContext, + SpanClauseContext, + StatsAggTermContext, + StatsByClauseContext, + StatsFunctionContext, + StatsFunctionNameContext, + StringLiteralContext, + TimespanUnitContext, + ValueExpressionContext, + WcFieldExpressionContext, +} from '../../antlr/output/OpenSearchPPLParser'; +import { OpenSearchPPLParserVisitor } from '../../antlr/output/OpenSearchPPLParserVisitor'; +import { PPLNode } from '../node'; +import { Aggregations } from '../tree/aggragations'; +import { + AggregateFunction, + AggregateTerm, + GroupBy, + Field, + Span, + SpanExpression, +} from '../expression'; + +type VisitResult = PPLNode | Array | string; + +export class StatsAstBuilder + extends AbstractParseTreeVisitor + implements OpenSearchPPLParserVisitor { + protected defaultResult(): PPLNode { + return new PPLNode('default', [] as Array); + } + + visitRoot(ctx: RootContext) { + if (!ctx.pplStatement()) return this.defaultResult(); + return this.visitPplStatement(ctx.pplStatement()!); + } + + visitPplStatement(ctx: PplStatementContext): PPLNode { + let statsTree: VisitResult = this.defaultResult(); + ctx.commands().map((pplCommandContext) => { + if ( + isFunction(this.visitChildren(pplCommandContext).getName) && + isEqual(this.visitChildren(pplCommandContext).getName(), 'stats_command') + ) + statsTree = this.visitChildren(pplCommandContext); + }); + return statsTree; + } + + visitCommands(ctx: CommandsContext) { + if (ctx.statsCommand()) { + return this.visitStatsCommand(ctx.statsCommand()!); + } + return this.defaultResult(); + } + + /** + * Stats command + */ + visitStatsCommand(ctx: StatsCommandContext): PPLNode { + return new Aggregations( + 'stats_command', + [] as Array, + ctx.PARTITIONS() && ctx.integerLiteral() + ? { + keyword: ctx.PARTITIONS()?.text, + sign: '=', + value: ctx.integerLiteral()?.text, + } + : {}, // visit partitions partial + ctx.ALLNUM() && ctx.booleanLiteral() + ? { + keyword: ctx.ALLNUM()?.text, + sign: '=', + value: this.visitBooleanLiteral(ctx.booleanLiteral()[0]), + } + : {}, // visit allnum partial + ctx.DELIM() && ctx.stringLiteral() + ? { + keyword: ctx.DELIM()?.text, + sign: '=', + value: this.visitStringLiteral(ctx.stringLiteral()!), + } + : '', // visit delim partial + ctx.statsAggTerm().map((aggTermAlternative) => this.visitStatsAggTerm(aggTermAlternative)), // visit statsAggTerm + ctx.statsByClause() ? this.visitStatsByClause(ctx.statsByClause()!) : ({} as GroupBy), // visit group list + ctx.DEDUP_SPLITVALUES() && ctx.booleanLiteral() + ? { + keyword: ctx.DEDUP_SPLITVALUES()?.text, + sign: '=', + value: this.visitBooleanLiteral(ctx.booleanLiteral()[1]), + } + : '', // visit dedup split value + { + start: ctx.start.startIndex, + end: ctx.stop?.stopIndex, + } // stats start/end indices in query for later query concatenation + ); + } + + visitIntegerLiteral(ctx: IntegerLiteralContext): string { + return ctx.text; + } + + visitBooleanLiteral(ctx: BooleanLiteralContext): string { + return ctx.text; + } + + visitStringLiteral(ctx: StringLiteralContext): string { + return ctx.text; + } + + visitStatsAggTerm(ctx: StatsAggTermContext): PPLNode { + return new AggregateTerm( + 'stats_agg_term', + [] as Array, + this.visitStatsFunction(ctx.statsFunction()), + ctx.wcFieldExpression() ? this.visitWcFieldExpression(ctx.wcFieldExpression()!) : '' + ); + } + + visitWcFieldExpression(ctx: WcFieldExpressionContext): string { + // return only text from here to all its chilren for now + return ctx.wcQualifiedName().text; + } + + visitStatsByClause(ctx: StatsByClauseContext): PPLNode { + return new GroupBy( + 'stats_by_clause', + [] as Array, + ctx.fieldList() ? this.visitFieldList(ctx.fieldList()!) : [], + ctx.bySpanClause() ? this.visitBySpanClause(ctx.bySpanClause()!) : this.defaultResult() + ); + } + + visitBySpanClause(ctx: BySpanClauseContext): PPLNode { + return new Span( + 'span_clause', + [] as Array, + this.visitSpanClause(ctx.spanClause()), + ctx.qualifiedName() ? this.visitQualifiedName(ctx.qualifiedName()!) : '' + ); + } + + visitSpanClause(ctx: SpanClauseContext): PPLNode { + return new SpanExpression( + 'span_expression', + [] as Array, + this.visitFieldExpression(ctx.fieldExpression()), + this.visitLiteralValue(ctx.literalValue()), + ctx.timespanUnit() ? this.visitTimespanUnit(ctx.timespanUnit()!) : '' + ); + } + + visitLiteralValue(ctx: LiteralValueContext): string { + return ctx.text; + } + + visitTimespanUnit(ctx: TimespanUnitContext): string { + return ctx.text; + } + + visitStatsFunction(ctx: StatsFunctionContext): PPLNode { + let funcName = ''; + let valueExpr = ''; + + if (typeof ctx.valueExpression === 'function') { + valueExpr = this.visitValueExpression(ctx.valueExpression()); + if (typeof ctx.statsFunctionName === 'function') { + funcName = this.visitStatsFunctionName(ctx.statsFunctionName()); + } else { + funcName = ctx.DISTINCT_COUNT() ? ctx.DISTINCT_COUNT().text : ctx.DC().text; + } + } else if (typeof ctx.percentileAggFunction === 'function') { + // for now just return plain text + } else { + funcName = ctx.COUNT().text; + } + + return new AggregateFunction( + 'stats_function', + [] as Array, + funcName, + valueExpr, + typeof ctx.percentileAggFunction === 'function' ? ctx.text : '' + ); + } + + visitValueExpression(ctx: ValueExpressionContext): string { + return ctx.text; + } + + visitStatsFunctionName(ctx: StatsFunctionNameContext): string { + return ctx.text; + } + + visitFieldList(ctx: FieldListContext): Array { + return ctx.fieldExpression().map((fieldExprAlternative) => { + return new Field( + 'field_expression', + [] as Array, + this.visitFieldExpression(fieldExprAlternative) + ); + }); + } + + visitFieldExpression(ctx: FieldExpressionContext): string { + return this.visitQualifiedName(ctx.qualifiedName()); + } + + visitQualifiedName(ctx: QualifiedNameContext): string { + return ctx.text; + } +} diff --git a/dashboards-observability/common/query_manager/ast/builder/stats_builder.ts b/dashboards-observability/common/query_manager/ast/builder/stats_builder.ts new file mode 100644 index 000000000..064ac8c5d --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/builder/stats_builder.ts @@ -0,0 +1,136 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { QueryBuilder } from './query_builder'; +import { Aggregations } from '../tree/aggragations'; +import { PPLNode } from '../node'; +import { + AggregateFunction, + AggregateTerm, + Field, + GroupBy, + Span, + SpanExpression, +} from '../expression'; +import { + ExpressionChunk, + SpanChunk, + StatsAggregationChunk, + StatsAggregationFunctionChunk, + GroupByChunk, + GroupField, + StatsChunk, + SpanExpressionChunk, +} from '../types'; +import { CUSTOM_LABEL } from '../../../../common/constants/explorer'; + +export class StatsBuilder implements QueryBuilder { + constructor(private statsChunk: StatsChunk) {} + + build(): Aggregations { + // return a new stats subtree + return new Aggregations( + 'stats_command', + [] as PPLNode[], + !isEmpty(this.statsChunk.partitions) ? this.buildParttions(this.statsChunk.partitions) : '', + !isEmpty(this.statsChunk.all_num) ? this.buildAllNum(this.statsChunk.all_num) : '', + !isEmpty(this.statsChunk.delim) ? this.buildDelim(this.statsChunk.delim) : '', + !isEmpty(this.statsChunk.aggregations) + ? this.buildAggList(this.statsChunk.aggregations) + : ([] as PPLNode[]), + !isEmpty(this.statsChunk.groupby) + ? this.buildGroupList(this.statsChunk.groupby) + : new GroupBy('stats_by_clause', [] as PPLNode[], [], null), + !isEmpty(this.statsChunk.dedup_split_value) + ? this.buildDedupSplitValue(this.statsChunk.dedup_split_value) + : '' + ); + } + + /** + * Flags + */ + buildParttions(partitions: ExpressionChunk) { + return `${partitions.keyword} ${partitions.sign} ${partitions.value}`; + } + + buildAllNum(allNum: ExpressionChunk) { + return `${allNum.keyword} ${allNum.sign} ${allNum.value}`; + } + + buildDelim(delim: ExpressionChunk) { + return `${delim.keyword} ${delim.sign} ${delim.value}`; + } + + buildDedupSplitValue(dedupSplitvalue: ExpressionChunk) { + return `${dedupSplitvalue.keyword} ${dedupSplitvalue.sign} ${dedupSplitvalue.value}`; + } + + /** + * Aggregations + */ + buildAggList(aggregations: StatsAggregationChunk[]) { + return aggregations.map((aggregation) => { + return this.buildAggTerm(aggregation); + }); + } + + buildAggTerm(aggTerm: StatsAggregationChunk) { + return new AggregateTerm( + 'stats_agg_term', + [] as PPLNode[], + this.buildAggregateFunction(aggTerm.function), + aggTerm.function_alias + ); + } + + buildAggregateFunction(aggFunction: StatsAggregationFunctionChunk) { + return new AggregateFunction( + 'stats_function', + [] as PPLNode[], + aggFunction.name, + aggFunction.value_expression, + aggFunction.percentile_agg_function + ); + } + + /** + * Groups + */ + buildGroupList(groupby: GroupByChunk) { + return new GroupBy( + 'stats_by_clause', + [] as PPLNode[], + this.buildFieldList(groupby.group_fields), + groupby.span ? this.buildSpan(groupby.span) : null + ); + } + + buildFieldList(group_fields: GroupField[]) { + return group_fields.map((gf: GroupField) => { + return new Field('field_expression', [] as PPLNode[], gf.name); + }); + } + + buildSpan(span: SpanChunk) { + return new Span( + 'span_clause', + [] as PPLNode[], + this.buildeSpanExpression(span.span_expression), + span[CUSTOM_LABEL] + ); + } + + buildeSpanExpression(spanExpression: SpanExpressionChunk) { + return new SpanExpression( + 'span_expression', + [] as PPLNode[], + spanExpression.field, + spanExpression.literal_value, + spanExpression.time_unit + ); + } +} diff --git a/dashboards-observability/common/query_manager/ast/expression/AggregateFunction.ts b/dashboards-observability/common/query_manager/ast/expression/AggregateFunction.ts new file mode 100644 index 000000000..06c05cec6 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/AggregateFunction.ts @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLNode } from '../node'; + +export class AggregateFunction extends PPLNode { + constructor( + name: string, + children: Array, + private statsFunctionName: string, + private valueExpression: string, + private percentileAggFunction: string + ) { + super(name, children); + } + + getTokens() { + return { + name: this.statsFunctionName, + value_expression: this.valueExpression, + percentile_agg_function: this.percentileAggFunction, + }; + } + + toString(): string { + if (this.statsFunctionName && this.valueExpression) { + return `${this.statsFunctionName}(${this.valueExpression})`; + } else if (this.statsFunctionName) { + return `${this.statsFunctionName}()`; + } else if (this.percentileAggFunction) { + return `${this.percentileAggFunction}`; + } + return ''; + } +} diff --git a/dashboards-observability/common/query_manager/ast/expression/AggregateTerm.ts b/dashboards-observability/common/query_manager/ast/expression/AggregateTerm.ts new file mode 100644 index 000000000..9864bbfcd --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/AggregateTerm.ts @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { CUSTOM_LABEL } from '../../../../common/constants/explorer'; +import { PPLNode } from '../node'; +export class AggregateTerm extends PPLNode { + constructor( + name: string, + children: PPLNode[], + private statsFunction: PPLNode, + private customLabel: string + ) { + super(name, children); + } + + getTokens() { + return { + function: this.statsFunction.getTokens(), + [CUSTOM_LABEL]: this[CUSTOM_LABEL], + }; + } + + toString(): string { + if (this[CUSTOM_LABEL]) { + return `${this.statsFunction.toString()}${ + this[CUSTOM_LABEL] ? ` as ${this[CUSTOM_LABEL]}` : '' + }`; + } + return `${this.statsFunction.toString()}`; + } +} diff --git a/dashboards-observability/common/query_manager/ast/expression/field.ts b/dashboards-observability/common/query_manager/ast/expression/field.ts new file mode 100644 index 000000000..3bc35ce70 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/field.ts @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLNode } from '../node'; + +export class Field extends PPLNode { + constructor(name: string, children: Array, private fieldExpression: string) { + super(name, children); + } + + getTokens() { + return { name: this.fieldExpression ?? '' }; + } + + toString(): string { + return this.fieldExpression ?? ''; + } +} diff --git a/dashboards-observability/common/query_manager/ast/expression/group_by.ts b/dashboards-observability/common/query_manager/ast/expression/group_by.ts new file mode 100644 index 000000000..ce6d8ffef --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/group_by.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLNode } from '../node'; +import { Field } from './field'; + +export class GroupBy extends PPLNode { + constructor( + name: string, + children: Array, + private fields: Array, + private span: PPLNode | null + ) { + super(name, children); + } + + getTokens() { + return { + group_fields: this.fields.map((field) => field.getTokens()), + span: this.span?.getTokens(), + }; + } + + toString(): string { + return `by ${this.span ? `${this.span.toString()}${this.fields.length > 0 ? ', ' : ''}` : ''}${this.fields + .map((field) => field.toString()) + .join(', ')}`; + } +} diff --git a/dashboards-observability/common/query_manager/ast/expression/index.ts b/dashboards-observability/common/query_manager/ast/expression/index.ts new file mode 100644 index 000000000..222ca12ca --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/index.ts @@ -0,0 +1,6 @@ +export { AggregateFunction } from './AggregateFunction'; +export { AggregateTerm } from './AggregateTerm'; +export { GroupBy } from './group_by'; +export { Span } from './span'; +export { SpanExpression } from './spanExpression'; +export { Field } from './field'; diff --git a/dashboards-observability/common/query_manager/ast/expression/span.ts b/dashboards-observability/common/query_manager/ast/expression/span.ts new file mode 100644 index 000000000..278ca18eb --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/span.ts @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLNode } from '../node'; + +export class Span extends PPLNode { + constructor( + name: string, + children: PPLNode[], + private spanExpression: PPLNode, + private customLabel: string + ) { + super(name, children); + } + + getTokens() { + return { + span_expression: this.spanExpression.getTokens(), + customLabel: this.customLabel, + }; + } + + toString(): string { + return `${this.spanExpression.toString()}${this.customLabel ? ` as ${this.customLabel}` : ''}`; + } +} diff --git a/dashboards-observability/common/query_manager/ast/expression/spanExpression.ts b/dashboards-observability/common/query_manager/ast/expression/spanExpression.ts new file mode 100644 index 000000000..c3f8d15ed --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/expression/spanExpression.ts @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLNode } from '../node'; + +export class SpanExpression extends PPLNode { + constructor( + name: string, + children: Array, + private fieldExpression: string, + private literalValue: string, + private timeUnit: string + ) { + super(name, children); + } + + getTokens() { + return { + field: this.fieldExpression, + literal_value: this.literalValue, + time_unit: this.timeUnit, + }; + } + + toString(): string { + return `span(${this.fieldExpression}, ${this.literalValue}${this.timeUnit})`; + } +} diff --git a/dashboards-observability/common/query_manager/ast/index.ts b/dashboards-observability/common/query_manager/ast/index.ts new file mode 100644 index 000000000..eb0dbf6a7 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { PPLNode } from './node'; diff --git a/dashboards-observability/common/query_manager/ast/node.ts b/dashboards-observability/common/query_manager/ast/node.ts new file mode 100644 index 000000000..c28877369 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/node.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +interface PPLNodeProps { + getName: () => string; + getChildren: () => Array; + toString: () => string; + getTokens: () => any; +} + +export class PPLNode implements PPLNodeProps { + constructor(private name: string, private children: Array) {} + + getChildren(): Array { + return this.children; + } + + getName(): string { + return this.name; + } + + toString(): string { + return ''; + } + + getTokens(): any { + return null; + } +} diff --git a/dashboards-observability/common/query_manager/ast/tree/aggragations.ts b/dashboards-observability/common/query_manager/ast/tree/aggragations.ts new file mode 100644 index 000000000..39281a0a7 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/tree/aggragations.ts @@ -0,0 +1,58 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { PPLNode } from '../node'; +import { GroupBy } from '../expression/group_by'; + +export class Aggregations extends PPLNode { + constructor( + name: string, + children: Array, + private partitions: String, + private allNum: string, + private delim: string, + private aggExprList: Array, + private groupExprList: GroupBy, + private dedupSplitValue: string, + private indices?: { start: number; end: number } + ) { + super(name, children); + } + + getStartEndIndicesOfOriginQuery(): { start: number; end: number } { + if (this.indices === undefined) { + return { + start: -1, + end: -1, + }; + } + return { + start: this.indices.start, + end: this.indices.end, + }; + } + + getTokens() { + return { + partitions: this.partitions, + all_num: this.allNum, + delim: this.delim, + aggregations: this.aggExprList.map((aggTerm) => aggTerm.getTokens()), + groupby: !isEmpty(this.groupExprList) ? this.groupExprList.getTokens() : '', + dedup_split_value: this.dedupSplitValue, + }; + } + + toString() { + return `stats ${!isEmpty(this.partitions) ? `${this.partitions} ` : ''}${ + !isEmpty(this.allNum) ? `${this.allNum} ` : '' + }${!isEmpty(this.delim) ? `${this.delim} ` : ''}${this.aggExprList + .map((aggTerm) => aggTerm.toString()) + .join(', ')}${!isEmpty(this.groupExprList) ? ` ${this.groupExprList.toString()}` : ''}${ + !isEmpty(this.dedupSplitValue) ? ` ${this.dedupSplitValue}` : '' + }`; + } +} diff --git a/dashboards-observability/common/query_manager/ast/types/index.ts b/dashboards-observability/common/query_manager/ast/types/index.ts new file mode 100644 index 000000000..3256b0992 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/types/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { + ExpressionChunk, + SpanChunk, + StatsAggregationChunk, + StatsAggregationFunctionChunk, + GroupByChunk, + GroupField, + StatsChunk, + SpanExpressionChunk, + AggregationConfigurations, + PreviouslyParsedStaleStats +} from './stats'; diff --git a/dashboards-observability/common/query_manager/ast/types/stats.ts b/dashboards-observability/common/query_manager/ast/types/stats.ts new file mode 100644 index 000000000..13a77eb11 --- /dev/null +++ b/dashboards-observability/common/query_manager/ast/types/stats.ts @@ -0,0 +1,74 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * stats chunck types + */ +export interface StatsAggregationChunk { + function: StatsAggregationFunctionChunk; + function_alias: string; +} + +export interface StatsAggregationFunctionChunk { + name: string; + value_expression: string; + percentile_agg_function: string; +} + +export interface GroupField { + name: string; +} + +export interface SpanChunk { + customLabel: string; + span_expression: SpanExpressionChunk; +} + +export interface SpanExpressionChunk { + type: string; + field: string; + time_unit: string; + literal_value: string; +} + +export interface GroupByChunk { + group_fields: GroupField[]; + span: SpanChunk | null; +} + +export interface statsChunk { + aggregations: StatsAggregationChunk[]; + groupby: GroupByChunk; + partitions: ExpressionChunk; + all_num: ExpressionChunk; + delim: ExpressionChunk; + dedup_split_value: ExpressionChunk; +} + +export interface ExpressionChunk { + keyword: string; + sign: string; + value: string | number; +} + +export interface DataConfigSeries { + customLabel: string; + label: string; + name: string; + aggregation: string; +} + +export interface AggregationConfigurations { + series: DataConfigSeries[]; + dimensions: GroupField[]; + span: SpanChunk; +} + +export interface PreviouslyParsedStaleStats { + partitions: ExpressionChunk; + all_num: ExpressionChunk; + delim: ExpressionChunk; + dedup_split_value: ExpressionChunk; +} diff --git a/dashboards-observability/common/query_manager/index.ts b/dashboards-observability/common/query_manager/index.ts new file mode 100644 index 000000000..72b5cd2f6 --- /dev/null +++ b/dashboards-observability/common/query_manager/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { QueryManager } from './ppl_query_manager'; diff --git a/dashboards-observability/common/query_manager/ppl_query_manager.ts b/dashboards-observability/common/query_manager/ppl_query_manager.ts new file mode 100644 index 000000000..513485cf5 --- /dev/null +++ b/dashboards-observability/common/query_manager/ppl_query_manager.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLQueryBuilder } from './query_builder/ppl_query_builder'; +import { PPLQueryParser } from './query_parser/ppl_query_parser'; + +export class QueryManager { + queryBuilder(): PPLQueryBuilder { + return new PPLQueryBuilder(); + } + + queryParser(): PPLQueryParser { + return new PPLQueryParser(); + } +} diff --git a/dashboards-observability/common/query_manager/query_builder/index.ts b/dashboards-observability/common/query_manager/query_builder/index.ts new file mode 100644 index 000000000..24e0492f5 --- /dev/null +++ b/dashboards-observability/common/query_manager/query_builder/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { PPLQueryBuilder } from './ppl_query_builder'; diff --git a/dashboards-observability/common/query_manager/query_builder/ppl_query_builder.ts b/dashboards-observability/common/query_manager/query_builder/ppl_query_builder.ts new file mode 100644 index 000000000..50ea50b41 --- /dev/null +++ b/dashboards-observability/common/query_manager/query_builder/ppl_query_builder.ts @@ -0,0 +1,39 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLSyntaxParser } from '../antlr/ppl_syntax_parser'; +import { StatsBuilder } from '../ast/builder/stats_builder'; +import { StatsAstBuilder } from '../ast/builder/stats_ast_builder'; + +export class PPLQueryBuilder { + parser: PPLSyntaxParser | null = null; + + build(query: string, pplTokens: any) { + this.parser = new PPLSyntaxParser().parse(query); + return this.buildStats(query, pplTokens); + } + + buildStats(query: string, statsTokens: any) { + const statsTree = new StatsAstBuilder().visitRoot(this.parser!.root()); + const newStatsAstTree = new StatsBuilder(statsTokens).build(); + if (typeof statsTree.getStartEndIndicesOfOriginQuery !== 'function') { + return query + ' | ' + newStatsAstTree.toString(); + } + + const indices = statsTree.getStartEndIndicesOfOriginQuery(); + + if (indices.start !== -1 && indices.end !== -1) { + return ( + query.substring(0, indices.start) + + newStatsAstTree.toString() + + query.substring(indices.end + 1, query.length) + ); + } else if (indices && newStatsAstTree) { + return query + ' | ' + newStatsAstTree.toString(); + } + + return ''; + } +} diff --git a/dashboards-observability/common/query_manager/query_parser/index.ts b/dashboards-observability/common/query_manager/query_parser/index.ts new file mode 100644 index 000000000..c4afe0e5d --- /dev/null +++ b/dashboards-observability/common/query_manager/query_parser/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { PPLQueryParser } from './ppl_query_parser'; diff --git a/dashboards-observability/common/query_manager/query_parser/ppl_query_parser.ts b/dashboards-observability/common/query_manager/query_parser/ppl_query_parser.ts new file mode 100644 index 000000000..9a39276e0 --- /dev/null +++ b/dashboards-observability/common/query_manager/query_parser/ppl_query_parser.ts @@ -0,0 +1,25 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLSyntaxParser } from '../antlr/ppl_syntax_parser'; +import { OpenSearchPPLParser } from '../antlr/output/OpenSearchPPLParser'; +import { StatsAstBuilder } from '../ast/builder/stats_ast_builder'; + +export class PPLQueryParser { + parser: OpenSearchPPLParser | null = null; + visitor: any = null; + rawQuery: string = ''; + + parse(pplQuery: string) { + this.rawQuery = pplQuery; + this.parser = new PPLSyntaxParser().parse(this.rawQuery); + return this; + } + + getStats() { + this.visitor = new StatsAstBuilder(); + return this.visitor.visitRoot(this.parser!.root()).getTokens(); + } +} diff --git a/dashboards-observability/common/query_manager/utils/index.ts b/dashboards-observability/common/query_manager/utils/index.ts new file mode 100644 index 000000000..e61e8333c --- /dev/null +++ b/dashboards-observability/common/query_manager/utils/index.ts @@ -0,0 +1,43 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { CUSTOM_LABEL } from '../../../common/constants/explorer'; +import { AggregationConfigurations, PreviouslyParsedStaleStats } from '../ast/types'; + +export const composeAggregations = ( + aggConfig: AggregationConfigurations, + staleStats: PreviouslyParsedStaleStats +) => { + return { + aggregations: aggConfig.series.map((metric) => ({ + function_alias: metric[CUSTOM_LABEL], + function: { + name: metric.aggregation, + value_expression: metric.name, + percentile_agg_function: '', + }, + })), + groupby: { + group_fields: aggConfig?.dimensions.map((dimension) => ({ name: dimension.name })), + ...(aggConfig.span && + JSON.stringify(aggConfig?.span) !== '{}' && { span: composeSpan(aggConfig.span) }), + }, + partitions: staleStats?.partitions ?? {}, + all_num: staleStats?.all_num ?? {}, + delim: staleStats?.delim ?? {}, + dedup_split_value: staleStats?.dedup_split_value ?? {}, + }; +}; + +const composeSpan = (spanConfig) => { + return { + [CUSTOM_LABEL]: spanConfig[CUSTOM_LABEL] ?? '', + span_expression: { + type: spanConfig.time_field[0]?.type ?? 'timestamp', + field: spanConfig.time_field[0]?.name ?? 'timestamp', + time_unit: spanConfig.unit[0]?.value ?? 'd', + literal_value: spanConfig.interval ?? 1, + }, + }; +}; diff --git a/dashboards-observability/common/types/app_analytics.ts b/dashboards-observability/common/types/application_analytics.ts similarity index 57% rename from dashboards-observability/common/types/app_analytics.ts rename to dashboards-observability/common/types/application_analytics.ts index c73bbb0b0..11f42c236 100644 --- a/dashboards-observability/common/types/app_analytics.ts +++ b/dashboards-observability/common/types/application_analytics.ts @@ -7,17 +7,20 @@ export interface OptionType { label: string; } -export interface ApplicationListType { - name: string; +export interface ApplicationType { id: string; - panelId: string; - composition: string[]; dateCreated: string; dateModified: string; - availability: { name: string; color: string; mainVisId: string }; + name: string; + description: string; + baseQuery: string; + servicesEntities: string[]; + traceGroups: string[]; + panelId: string; + availability: { name: string; color: string; availabilityVisId: string }; } -export interface ApplicationType { +export interface ApplicationRequestType { name: string; description: string; baseQuery: string; @@ -26,3 +29,9 @@ export interface ApplicationType { panelId: string; availabilityVisId: string; } + +export interface AvailabilityType { + name: string; + color: string; + availabilityVisId: string; +} diff --git a/dashboards-observability/common/types/explorer.ts b/dashboards-observability/common/types/explorer.ts index fcf9017d2..8fa042f2e 100644 --- a/dashboards-observability/common/types/explorer.ts +++ b/dashboards-observability/common/types/explorer.ts @@ -5,6 +5,8 @@ import { History } from 'history'; import Plotly from 'plotly.js-dist'; +import { QueryManager } from 'common/query_manager'; +import { VIS_CHART_TYPES } from '../../common/constants/shared'; import { RAW_QUERY, SELECTED_FIELDS, @@ -15,13 +17,23 @@ import { FINAL_QUERY, SELECTED_TIMESTAMP, SELECTED_DATE_RANGE, + GROUPBY, + AGGREGATIONS, + CUSTOM_LABEL, + BREAKDOWNS, } from '../constants/explorer'; -import { CoreStart, HttpStart, NotificationsStart } from '../../../../src/core/public'; +import { + CoreStart, + CoreSetup, + HttpSetup, + HttpStart, + NotificationsStart, +} from '../../../../src/core/public'; import SavedObjects from '../../public/services/saved_objects/event_analytics/saved_objects'; import TimestampUtils from '../../public/services/timestamp/timestamp'; import PPLService from '../../public/services/requests/ppl'; import DSLService from '../../public/services/requests/dsl'; - +import { SavedObjectsStart } from '../../../../src/core/public/saved_objects'; export interface IQueryTab { id: string; name: React.ReactNode | string; @@ -31,6 +43,20 @@ export interface IQueryTab { export interface IField { name: string; type: string; + label?: string; +} + +export interface TimeUnit { + name: string; + label: string; + value: string; +} + +export interface ExplorerFields { + availableFields: IField[]; + queriedFields: IField[]; + selectedFields: IField[]; + unselectedFields: IField[]; } export interface ITabQueryResults { @@ -82,6 +108,7 @@ export interface ILogExplorerProps { ) => void; savedObjectId: string; getExistingEmptyTab: (params: EmptyTabParams) => string; + queryManager: QueryManager; } export interface IExplorerProps { @@ -110,6 +137,9 @@ export interface IExplorerProps { setStartTime?: any; setEndTime?: any; appBaseQuery?: string; + callback?: any; + callbackInApp?: any; + queryManager: QueryManager; } export interface SavedQuery { @@ -117,8 +147,8 @@ export interface SavedQuery { name: string; query: string; selected_date_range: { start: string; end: string; text: string }; - selected_fields: { text: string; tokens: [{ name: string; type: string }] }; - selected_timestamp: { name: string; type: string }; + selected_fields: { text: string; tokens: IField[] }; + selected_timestamp: IField; } export interface SavedVisualization { @@ -127,7 +157,7 @@ export interface SavedVisualization { query: string; selected_date_range: { start: string; end: string; text: string }; selected_fields: { text: string; tokens: [] }; - selected_timestamp: { name: string; type: string }; + selected_timestamp: IField; type: string; application_id?: string; } @@ -148,6 +178,31 @@ export interface SavedVizRes { tenant: string; } +export interface ExplorerDataType { + jsonData: object[]; + jsonDataAll: object[]; +} + +export interface Query { + finalQuery: string; + index: string; + isLoaded: boolean; + objectType: string; + rawQuery: string; + savedObjectId: string; + selectedDateRange: string[]; + selectedTimestamp: string; + tabCreatedType: string; +} + +export interface ExplorerData { + explorerData?: ExplorerDataType; + explorerFields?: IExplorerFields; + query?: Query; + http?: HttpSetup; + pplService?: PPLService; +} + export interface IVisualizationContainerPropsData { appData?: { fromApp: boolean }; rawVizData?: any; @@ -158,6 +213,7 @@ export interface IVisualizationContainerPropsData { xaxis: IField[]; yaxis: IField[]; }; + explorer?: ExplorerData; } export interface IVisualizationContainerPropsVis { @@ -184,9 +240,11 @@ export interface IConfigPanelOptions { export interface IConfigPanelOptionSection { name: string; component: null; - mapTo: 'mode'; + mapTo: string; props?: any; isSingleSelection?: boolean; + defaultState?: boolean | string; + eleType?: string; } export interface IVisualizationTypeDefination { @@ -194,13 +252,13 @@ export interface IVisualizationTypeDefination { type: string; id: string; label: string; - fullLabel: string; + fulllabel: string; category: string; icon: React.ReactNode; - editorConfig: { + editorconfig: { panelTabs: IConfigPanelTab; }; - visConfig: { + visconfig: { layout: Partial; config: Partial; }; @@ -225,3 +283,92 @@ export interface LiveTailProps { isLiveTailPopoverOpen: boolean; dataTestSubj: string; } + +export interface ConfigListEntry { + label: string; + aggregation: string; + [CUSTOM_LABEL]: string; + name: string; + side: string; + type: string; + alias?: string; +} + +export interface HistogramConfigList { + bucketSize: string; + bucketOffset: string; +} + +export interface DimensionSpan { + time_field: IField[]; + interval: number; + unit: TimeUnit[]; +} + +export interface ConfigList { + [GROUPBY]?: ConfigListEntry[] | HistogramConfigList[]; + [AGGREGATIONS]?: ConfigListEntry[]; + [BREAKDOWNS]?: ConfigListEntry[] | HistogramConfigList[]; + span?: DimensionSpan; +} + +export interface Breadcrumbs { + text: string; + href: string; +} + +export interface EventAnalyticsProps { + chrome: CoreSetup; + parentBreadcrumbs: Breadcrumbs[]; + pplService: any; + dslService: any; + savedObjects: SavedObjectsStart; + timestampUtils: TimestampUtils; + http: HttpStart; + notifications: NotificationsStart; + queryManager: QueryManager; +} + +export interface DataConfigPanelProps { + fieldOptionList: IField[]; + visualizations: IVisualizationContainerProps; + queryManager?: QueryManager; +} +export interface GetTooltipHoverInfoType { + tooltipMode: string; + tooltipText: string; +} + +export interface PatternTableData { + count: number; + pattern: string; + sampleLog: string; +} + +export interface SelectedConfigItem { + index: number; + name: string; +} + +export interface ParentUnitType { + name: string; + label: string; + type: string; +} + +export interface TreemapParentsProps { + selectedAxis: ParentUnitType[]; + setSelectedParentItem: (item: { isClicked: boolean; index: number }) => void; + handleUpdateParentFields: (arr: ParentUnitType[]) => void; +} + +export interface DataConfigPanelFieldProps { + list: ConfigListEntry[]; + dimensionSpan: DimensionSpan; + sectionName: string; + visType: VIS_CHART_TYPES; + addButtonText: string; + handleServiceAdd: (name: string) => void; + handleServiceRemove: (index: number, name: string) => void; + handleServiceEdit: (arrIndex: number, sectionName: string, isTimeStamp: boolean) => void; +} diff --git a/dashboards-observability/opensearch_dashboards.json b/dashboards-observability/opensearch_dashboards.json index cb800a492..0d145f1a9 100644 --- a/dashboards-observability/opensearch_dashboards.json +++ b/dashboards-observability/opensearch_dashboards.json @@ -1,7 +1,7 @@ { "id": "observabilityDashboards", - "version": "2.0.0.0-rc1", - "opensearchDashboardsVersion": "2.0.0", + "version": "3.0.0.0", + "opensearchDashboardsVersion": "3.0.0", "server": true, "ui": true, "requiredPlugins": [ diff --git a/dashboards-observability/package.json b/dashboards-observability/package.json index f67b52e56..173f4b567 100644 --- a/dashboards-observability/package.json +++ b/dashboards-observability/package.json @@ -1,6 +1,6 @@ { "name": "observability-dashboards", - "version": "2.0.0.0-rc1", + "version": "3.0.0.0", "main": "index.ts", "license": "Apache-2.0", "scripts": { @@ -9,7 +9,8 @@ "test": "../../node_modules/.bin/jest --config ./test/jest.config.js", "cypress:run": "TZ=America/Los_Angeles cypress run", "cypress:open": "TZ=America/Los_Angeles cypress open", - "plugin_helpers": "node ../../scripts/plugin_helpers" + "plugin_helpers": "node ../../scripts/plugin_helpers", + "postinstall": "antlr4ts -visitor ./common/query_manager/antlr/grammar/OpenSearchPPLLexer.g4 -Xexact-output-dir -o ./common/query_manager/antlr/output && antlr4ts -visitor ./common/query_manager/antlr/grammar/OpenSearchPPLParser.g4 -Xexact-output-dir -o ./common/query_manager/antlr/output" }, "dependencies": { "@algolia/autocomplete-core": "^1.4.1", @@ -17,8 +18,14 @@ "@nteract/outputs": "^3.0.11", "@nteract/presentational-components": "^3.4.3", "@reduxjs/toolkit": "^1.6.1", + "ag-grid-community": "^27.3.0", + "ag-grid-react": "^27.3.0", + "antlr4": "4.8.0", + "antlr4ts": "^0.5.0-alpha.4", "plotly.js-dist": "^2.2.0", + "postinstall": "^0.7.4", "react-graph-vis": "^1.0.5", + "react-paginate": "^8.1.3", "react-plotly.js": "^2.5.1" }, "devDependencies": { @@ -26,6 +33,7 @@ "@types/enzyme-adapter-react-16": "^1.0.6", "@types/react-plotly.js": "^2.5.0", "@types/react-test-renderer": "^16.9.1", + "antlr4ts-cli": "^0.5.0-alpha.4", "cypress": "^5.0.0", "eslint": "^6.8.0", "jest-dom": "^4.0.0", diff --git a/dashboards-observability/public/.DS_Store b/dashboards-observability/public/.DS_Store new file mode 100644 index 000000000..dbd07c1a1 Binary files /dev/null and b/dashboards-observability/public/.DS_Store differ diff --git a/dashboards-observability/public/components/app.tsx b/dashboards-observability/public/components/app.tsx index b4d164331..307a0edcf 100644 --- a/dashboards-observability/public/components/app.tsx +++ b/dashboards-observability/public/components/app.tsx @@ -7,6 +7,7 @@ import { I18nProvider } from '@osd/i18n/react'; import React from 'react'; import { Provider } from 'react-redux'; import { HashRouter, Route, Switch } from 'react-router-dom'; +import { QueryManager } from 'common/query_manager'; import { CoreStart } from '../../../../src/core/public'; import { observabilityID, observabilityTitle } from '../../common/constants/shared'; import store from '../framework/redux/store'; @@ -24,6 +25,7 @@ interface ObservabilityAppDeps { dslService: any; savedObjects: any; timestampUtils: any; + queryManager: QueryManager; } // for cypress to test redux store @@ -38,6 +40,7 @@ export const App = ({ dslService, savedObjects, timestampUtils, + queryManager, }: ObservabilityAppDeps) => { const { chrome, http, notifications } = CoreStartProp; const parentBreadcrumb = { @@ -130,6 +133,7 @@ export const App = ({ timestampUtils={timestampUtils} http={http} notifications={notifications} + queryManager={queryManager} {...props} /> ); diff --git a/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap b/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap index c93d4518e..fd2d3f4e4 100644 --- a/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap +++ b/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap @@ -27,6 +27,7 @@ Object { >

Create application @@ -156,6 +157,7 @@ Object {
+
+ + + +
@@ -1243,6 +1280,7 @@ Object { >

Create application @@ -1372,6 +1410,7 @@ Object {
+
+ + + +
@@ -2399,6 +2473,7 @@ Object { >

Create application @@ -2528,6 +2603,7 @@ Object {
+
+ + + +
@@ -3529,6 +3640,7 @@ Object { >

Create application @@ -3658,6 +3770,7 @@ Object {
+
+ + + +
@@ -4718,6 +4866,7 @@ Object { >

Create application @@ -4847,6 +4996,7 @@ Object {
+
+ + + +
@@ -5848,6 +6033,7 @@ Object { >

Create application @@ -5977,6 +6163,7 @@ Object {
+
+ + + +
@@ -7035,6 +7257,7 @@ Object { >

Create application @@ -7164,6 +7387,7 @@ Object {
+
+ + + +
@@ -8102,6 +8361,7 @@ Object { >

Create application @@ -8231,6 +8491,7 @@ Object {
+
+ + + +
@@ -9226,6 +9522,7 @@ Object { >

Create application @@ -9355,6 +9652,7 @@ Object {
+
+ + + +
@@ -10323,6 +10655,7 @@ Object { >

Create application @@ -10452,6 +10785,7 @@ Object {
+
+ + + +
@@ -11479,6 +11847,7 @@ Object { >

Create application @@ -11608,6 +11977,7 @@ Object {
+
+ + + +
@@ -12609,6 +13014,7 @@ Object { >

Create application @@ -12738,6 +13144,7 @@ Object {
+
+ + + +
@@ -13798,6 +14240,7 @@ Object { >

Create application @@ -13927,6 +14370,7 @@ Object {
+
+ + + +
@@ -14928,6 +15407,7 @@ Object { >

Create application @@ -15057,6 +15537,7 @@ Object {
+
+ + + +
@@ -16120,6 +16636,7 @@ Object { >

Create application @@ -16249,6 +16766,7 @@ Object {
+
+ + + +
@@ -17332,6 +17885,7 @@ Object { >

Create application @@ -17461,6 +18015,7 @@ Object {
+
+ + + +
diff --git a/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap b/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap index c43359919..18c3c8847 100644 --- a/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap +++ b/dashboards-observability/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap @@ -68,8 +68,10 @@ exports[`Log Config component renders empty log config 1`] = ` } + data-test-subj="logSourceAccordion" extraAction={

} + titleSize="s" + iconType="minusInCircle" + iconColor="#DDDDDD" + body={ +

+ Try expanding your time range or modifying your query. Learn more from our{' '} + + PPL documentation + + +

+ } + /> + ); + + const getRowProps = (item: PatternTableData) => { + const { pattern } = item; + return { + 'data-test-subj': `row-${pattern}`, + className: 'customRowClass', + onClick: () => { + onPatternSelection(pattern); + setSelectedPattern(pattern); + }, + isSelected: pattern === selectedPattern, + }; + }; + + return ( + + ); +} diff --git a/dashboards-observability/public/components/event_analytics/explorer/no_results.tsx b/dashboards-observability/public/components/event_analytics/explorer/no_results.tsx index 802099729..91cc8ab62 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/no_results.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/no_results.tsx @@ -38,8 +38,7 @@ export const NoResults = () => {

diff --git a/dashboards-observability/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap b/dashboards-observability/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap index 30d744eb9..f2c5f5cb9 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap +++ b/dashboards-observability/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap @@ -21,7 +21,7 @@ exports[`Field component Renders a sidebar field 1`] = ` anchorPosition="rightUp" button={ @@ -67,7 +67,7 @@ exports[`Field component Renders a sidebar field 1`] = ` } isActive={false} onClick={[Function]} - size="s" + size="m" /> } closePopover={[Function]} @@ -85,7 +85,7 @@ exports[`Field component Renders a sidebar field 1`] = ` className="euiPopover__anchor" > @@ -131,10 +131,10 @@ exports[`Field component Renders a sidebar field 1`] = ` } isActive={false} onClick={[Function]} - size="s" + size="m" >
-
- - - - - - - - - - -
-
-
- - - -
- -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    + + + -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="s" + -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - + + + + +
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip_count - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" + -
    +
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip_count - - } - isActive={false} - onClick={[Function]} - size="s" +
      -
      - -
      - - - - - + + + + + + + + + + + + + + + + double_per_ip_bytes + + + +
      + + + + + + + + + + +
      +
      + +
      +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + host + + } + isActive={false} + onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    - - - - - -
    - - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + host + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - per_ip_bytes - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + ip_count + + } + isActive={false} + onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - per_ip_bytes - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - + + + + + + + + + + + + + + + + ip_count + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + per_ip_bytes + + } + isActive={false} + onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    - - - - - -
    - - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + per_ip_bytes + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - resp_code - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + resp_code + + } + isActive={false} + onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - resp_code - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - + + + + + + + + + + + + + + + + resp_code + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + sum_bytes + + } + isActive={false} + onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    - - - - - -
    - - + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • + - - - -
  • + + + + +
    + + + + Selected Fields + + + } + id="fieldSelector__selectedFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" + > +
    - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - sum_bytes - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" + -
    - - - - - - - - - - -
    -
    - + + + + + + + + Selected Fields + + + + +
    +
    + +
    +
    +
    - - -
  • - - -

    - - Selected Fields - -

    -
    + + + +
    -
      -
      - -

      - + Available Fields - -

      -
      + + + } + id="fieldSelector__availableFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" + >
      - - -
      -
      -
        -
      • - +
        - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - agent - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" + -
        +
        - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - agent - - } - isActive={false} - onClick={[Function]} - size="s" +
          -
          - -
          - - - - - - + + + + + + + + + + + + + + + + agent + + + +
          + + + + + + + + + + +
          +
          + +
          +
        + + +
      • +
      • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + bytes + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
        +
        - - - - -
        -
        - -
    - - - - -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + bytes + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - bytes - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + clientip + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - bytes - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + + + + + + + + + clientip + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + event + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + event + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - clientip - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + extension + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - clientip - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + + + + + + + + extension + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + geo + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + geo + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - event - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + host + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - event - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + + + + + + + + + host + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + index + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + index + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - extension - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - extension - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    - - -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - geo - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - geo - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - index - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - index - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - machine - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - machine - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - memory - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - memory - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - message - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - message - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - phpmemory - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - phpmemory - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - referer - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - referer - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - request - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - request - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + ip + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - -
    -
    - - -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + ip + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - response - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + machine + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - response - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + + + + + + + + + machine + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + memory + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + memory + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - tags - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + message + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - tags - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + + + + + + + + + message + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + phpmemory + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - Default Timestamp - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + phpmemory + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - timestamp - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - Default Timestamp - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + referer + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - timestamp - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - Default Timestamp - - - - - - - + + + + + + + + + + + + + + + + referer + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + request + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + request + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - url - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + response + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - url - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - - - - + + + + + + + + + + + + + + + + response + + + +
    + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + tags + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - - - -
    -
    -
  • -
  • - - - - - - Override - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - + + + + + + + + + + + + + + + + tags + + + +
    + + + + + + + + + + +
    + + + + +
    +
    +
  • +
  • - utc_time - - } - isActive={false} - onClick={[Function]} - size="s" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - Override - - - - - - + + + + + Default Timestamp + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + timestamp + + } + isActive={false} onClick={[Function]} + size="m" /> - - - - } - fieldIcon={ - - } - fieldName={ - - utc_time - - } - isActive={false} - onClick={[Function]} - size="s" - > -
    - -
    - - - + + + + + + + + + + + + + + + + timestamp + + + +
    + + + + + Default Timestamp + + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + url + + } + isActive={false} onClick={[Function]} - size="s" + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - - - - + + + + + + + + + + + + + + + + url + + + +
    + + + + + + + + + + +
    +
    + +
    + +
    +
    +
  • +
  • + + + + + + Override + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + utc_time + + } + isActive={false} onClick={[Function]} + size="m" + /> + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    - - - - -
    -
    - + +
    + + + + + + + + + + + + + + +
    + + + + +
    +
    +
  • + - - - - + + + + diff --git a/dashboards-observability/public/components/event_analytics/explorer/sidebar/field.tsx b/dashboards-observability/public/components/event_analytics/explorer/sidebar/field.tsx index efeacf5c1..0a75102ba 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/sidebar/field.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/sidebar/field.tsx @@ -10,11 +10,8 @@ import { EuiPopover, EuiButtonIcon, EuiToolTip, - EuiButton, EuiMark, EuiLoadingSpinner, - EuiPopoverTitle, - EuiPanel, EuiFlexGroup, EuiFlexItem, EuiTitle, @@ -25,12 +22,15 @@ import { IField } from '../../../../../common/types/explorer'; import { FieldInsights } from './field_insights'; interface IFieldProps { + query: string; field: IField; + selectedPattern: string; + isOverridingPattern: boolean; + handleOverridePattern: (pattern: IField) => void; selectedTimestamp: string; isOverridingTimestamp: boolean; - handleOverrideTimestamp: (timestamp: { name: string; type: string }) => void; + handleOverrideTimestamp: (timestamp: IField) => void; selected: boolean; - showToggleButton: boolean; showTimestampOverrideButton: boolean; isFieldToggleButtonDisabled: boolean; onToggleField: (field: IField) => void; @@ -40,6 +40,9 @@ export const Field = (props: IFieldProps) => { const { query, field, + selectedPattern, + isOverridingPattern, + handleOverridePattern, selectedTimestamp, isOverridingTimestamp, handleOverrideTimestamp, @@ -64,13 +67,38 @@ export const Field = (props: IFieldProps) => { setIsFieldDetailsOpen((staleState) => !staleState); }; - const toggleField = (field: IField) => { - onToggleField(field); + const toggleField = (tField: IField) => { + onToggleField(tField); }; const getFieldActionDOM = () => { return ( <> + + <> + {isEqual(field.type, 'string') ? ( + isEqual(selectedPattern, field.name) ? ( + + Default Pattern + + ) : isOverridingPattern ? ( + + ) : ( + handleOverridePattern(field)} + data-test-subj="eventExplorer__overrideDefaultPattern" + > + Override + + ) + ) : null} + + <> {showTimestampOverrideButton && isEqual(field.type, 'timestamp') ? ( @@ -150,8 +178,8 @@ export const Field = (props: IFieldProps) => { panelClassName="dscSidebarItem__fieldPopoverPanel" button={ } diff --git a/dashboards-observability/public/components/event_analytics/explorer/sidebar/field_insights.tsx b/dashboards-observability/public/components/event_analytics/explorer/sidebar/field_insights.tsx index 6a682cc5c..b9414ba70 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/sidebar/field_insights.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/sidebar/field_insights.tsx @@ -48,8 +48,8 @@ export const FieldInsights = ({ field, query }: any) => { format: 'viz', }, ]; - const numericalTypes = ['short', 'integer', 'long', 'float', 'double']; - const isNumericalField = indexOf(numericalTypes, field.type) > 0; + const NUMERICAL_TYPES = ['short', 'integer', 'long', 'float', 'double']; + const isNumericalField = indexOf(NUMERICAL_TYPES, field.type) > 0; const [curReport, setCurReport] = useState({ ...generalReports[0] }); const [reportContent, setReportContent] = useState({}); @@ -137,7 +137,7 @@ export const FieldInsights = ({ field, query }: any) => { ); })} - {indexOf(numericalTypes, field.type) > 0 && + {indexOf(NUMERICAL_TYPES, field.type) > 0 && numericalOnlyReports.map((report) => { return ( diff --git a/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.scss b/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.scss index 8ef4cc875..a5ab8d061 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.scss +++ b/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.scss @@ -37,25 +37,11 @@ background-color: lightOrDarkTheme(tint($euiColorPrimary, 90%), $euiColorLightShade); } -.dscFieldChooser { - padding-left: $euiSize; -} - .dscFieldChooser__toggle { color: $euiColorMediumShade; margin-left: $euiSizeS !important; } -.dscSidebarItem { - &:hover, - &:focus-within, - &[class*='-isActive'] { - .dscSidebarItem__action { - opacity: 1; - } - } -} - /** * 1. Only visually hide the action, so that it's still accessible to screen readers. * 2. When tabbed to, this element needs to be visible for keyboard accessibility. @@ -110,3 +96,47 @@ .override_timestamp_loading { vertical-align: middle; } + +.explorerFieldSelector { + padding: $euiSizeS; +} + +#vis__mainContent { + .explorer__insights { + min-height: 0; + display: grid; + grid-template-columns: 50% 50%; + height: 100%; + .explorerFieldSelector, .explorer__vizDataConfig { + padding: $euiSizeS; + overflow: auto; + + &__fieldGroups { + @include euiYScrollWithShadows; + + overflow-y: auto; + margin-right: -$euiSizeS; + padding-right: $euiSizeS; + margin-top: $euiSizeS; + } + + &__fieldGroup { + margin-top: $euiSizeS; + + &:first-child { + margin-top: 0; + } + } + } + .explorerFieldSelector { + @include euiYScrollWithShadows; + .sidebar-list { + height: 100%; + } + } + } +} + +.ws__configPanel--right{ + overflow-y: unset; +} diff --git a/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.tsx b/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.tsx index 9a49ca926..794ce5328 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/sidebar/sidebar.tsx @@ -7,20 +7,22 @@ import './sidebar.scss'; import React, { useState } from 'react'; import { isEmpty } from 'lodash'; -import { EuiTitle, EuiSpacer, EuiButtonIcon, EuiFieldSearch } from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; -import { cssNumber } from 'jquery'; +import { EuiTitle, EuiSpacer, EuiFieldSearch, EuiAccordion } from '@elastic/eui'; +import { I18nProvider } from '@osd/i18n/react'; import { Field } from './field'; import { IExplorerFields, IField } from '../../../../../common/types/explorer'; interface ISidebarProps { + query: string; explorerFields: IExplorerFields; explorerData: any; + selectedPattern: string; + isOverridingPattern: boolean; selectedTimestamp: string; isOverridingTimestamp: boolean; isFieldToggleButtonDisabled: boolean; - handleOverrideTimestamp: (timestamp: { name: string; type: string }) => void; + handleOverridePattern: (pattern: IField) => void; + handleOverrideTimestamp: (timestamp: IField) => void; handleAddField: (field: IField) => void; handleRemoveField: (field: IField) => void; } @@ -30,9 +32,12 @@ export const Sidebar = (props: ISidebarProps) => { query, explorerFields, explorerData, + selectedPattern, + isOverridingPattern, selectedTimestamp, isOverridingTimestamp, isFieldToggleButtonDisabled, + handleOverridePattern, handleOverrideTimestamp, handleAddField, handleRemoveField, @@ -44,7 +49,6 @@ export const Sidebar = (props: ISidebarProps) => { return (
    -
    { !isEmpty(explorerFields.availableFields)) && ( <> {explorerFields?.queriedFields && explorerFields.queriedFields?.length > 0 && ( - <> - -

    - -

    -
    - + + Query fields + + } + paddingSize="xs" + >
      {explorerFields.queriedFields && @@ -89,6 +93,10 @@ export const Sidebar = (props: ISidebarProps) => { { ); })}
    - +
    )} - -

    - -

    -
    - -
      - {explorerData && - !isEmpty(explorerData.jsonData) && - explorerFields.selectedFields && - explorerFields.selectedFields.map((field) => { - return ( -
    • - -
    • - ); - })} -
    -
    - -

    - -

    -
    -
    - setShowFields(!showFields)} - aria-label={ - showFields - ? i18n.translate( - 'discover.fieldChooser.filter.indexAndFieldsSectionHideAriaLabel', - { - defaultMessage: 'Hide fields', - } - ) - : i18n.translate( - 'discover.fieldChooser.filter.indexAndFieldsSectionShowAriaLabel', - { - defaultMessage: 'Show fields', - } - ) - } - /> -
    -
    -
      + + Selected Fields + + } + paddingSize="xs" > - {explorerFields.availableFields && - explorerFields.availableFields - .filter((field) => searchTerm === '' || field.name.indexOf(searchTerm) !== -1) - .map((field) => { +
        + {explorerData && + !isEmpty(explorerData.jsonData) && + explorerFields.selectedFields && + explorerFields.selectedFields.map((field) => { return (
      • {
      • ); })} -
      +
    + + + + Available Fields + + } + paddingSize="xs" + > +
      + {explorerFields.availableFields && + explorerFields.availableFields + .filter((field) => searchTerm === '' || field.name.indexOf(searchTerm) !== -1) + .map((field) => { + return ( +
    • + +
    • + ); + })} +
    +
    )}
    diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/app.scss b/dashboards-observability/public/components/event_analytics/explorer/visualizations/app.scss index 2f01e1b8e..8f4e129e9 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/app.scss +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/app.scss @@ -3,45 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -.lnsAppWrapper { - display: flex; - flex-direction: column; - flex-grow: 1; +.dataConfigContainer { + height: 1242px; + overflow: auto; } -.lnsApp { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - display: flex; - flex-direction: column; +.explorerViz__commonPanel { + display: grid; + grid-template-rows: auto 1fr; + grid-area: workspace; + background-color: #FFF; height: 100%; - overflow: hidden; -} - -.lnsApp__header { - border-bottom: $euiBorderThin; -} - -.lnsApp__frame { - position: relative; - display: flex; - flex-direction: column; - flex-grow: 1; -} - -.lensChartIcon__subdued { - fill: $euiTextSubduedColor; - - // Not great, but the easiest way to fix the gray fill when stuck in a button with a fill - // Like when selected in a button group - .euiButton--fill & { - fill: currentColor; - } -} - -.lensChartIcon__accent { - fill: $euiColorVis0; } diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap index 69eda470d..df4ce5655 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap @@ -2,6 +2,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] = ` -
    - -
    - -
    - - -
    - +
    + + +
    +
    +
    + + + + + + + Vertical bar + + + + + + + + + + + + +
    + +
    +
    + +
    + +
    + + + +
    +
    +
    +
    + + +
    + +
    +
    + , + "id": "data-panel", + "name": "Style", + } + } + tabs={ + Array [ + Object { + "content": , + "id": "data-panel", + "name": "Style", + }, + Object { + "content": , + "id": "style-panel", + "name": "Layout", + }, + Object { + "content": , + "id": "availability-panel", + "name": "Availability", + }, + ] + } + > +
    + +
    + + + + + + + + + +
    +
    +
    + - -
    -
    -
    - +
    + +
    + +
    +
    - - - + +
    - - - Bar - - - - - - - - - - - - -
    - -
    -
    - + + + + + + + + Panel options + + +
    +
    + +
    +
    + +
    + +
    +
    + + + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    + +
    + Name your visualization. +
    +
    +
    +
    +
    + +
    +
    + + + +
    +
    + + +