diff --git a/bin/start-frontend-https b/bin/start-frontend-https deleted file mode 100755 index 771b2940c67a5..0000000000000 --- a/bin/start-frontend-https +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -e - -# pass first argument to WEBPACK_HOT_RELOAD_HOST -[ $# -ge 1 ] && export WEBPACK_HOT_RELOAD_HOST=$1 - -pnpm install -pnpm start-https diff --git a/bin/start-https b/bin/start-https deleted file mode 100755 index 5ebaa291f6dca..0000000000000 --- a/bin/start-https +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -e - -trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT - -export IS_BEHIND_PROXY=1 -export DISABLE_SECURE_SSL_REDIRECT=1 -./bin/start-worker & -./bin/start-backend & -./bin/start-frontend-https & - -wait diff --git a/ee/clickhouse/materialized_columns/columns.py b/ee/clickhouse/materialized_columns/columns.py index 135f27b392190..3dc21ccde59f6 100644 --- a/ee/clickhouse/materialized_columns/columns.py +++ b/ee/clickhouse/materialized_columns/columns.py @@ -44,7 +44,6 @@ def get_materialized_columns( WHERE database = %(database)s AND table = %(table)s AND comment LIKE '%%column_materializer::%%' - AND comment not LIKE '%%column_materializer::elements_chain::%%' """, {"database": CLICKHOUSE_DATABASE, "table": table}, ) diff --git a/frontend/__snapshots__/scenes-app-errortracking--group-page--dark.png b/frontend/__snapshots__/scenes-app-errortracking--group-page--dark.png index 14648057b8da0..7d78d779f063e 100644 Binary files a/frontend/__snapshots__/scenes-app-errortracking--group-page--dark.png and b/frontend/__snapshots__/scenes-app-errortracking--group-page--dark.png differ diff --git a/frontend/__snapshots__/scenes-app-errortracking--group-page--light.png b/frontend/__snapshots__/scenes-app-errortracking--group-page--light.png index 8ef16bb7ccb83..904f485ef38ed 100644 Binary files a/frontend/__snapshots__/scenes-app-errortracking--group-page--light.png and b/frontend/__snapshots__/scenes-app-errortracking--group-page--light.png differ diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--dark.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--dark.png index 4d2ff3308afa8..207875a3704f8 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--dark.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--dark.png differ diff --git a/frontend/public/transformations/semver-flattener.png b/frontend/public/transformations/semver-flattener.png new file mode 100644 index 0000000000000..fe9f1eb7acc57 Binary files /dev/null and b/frontend/public/transformations/semver-flattener.png differ diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index a099b5b044dd6..6b0c6061310a4 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -1630,8 +1630,8 @@ const api = { }, hogFunctions: { - async list(): Promise> { - return await new ApiRequest().hogFunctions().get() + async list(params?: { filters?: any }): Promise> { + return await new ApiRequest().hogFunctions().withQueryString(params).get() }, async get(id: HogFunctionType['id']): Promise { return await new ApiRequest().hogFunction(id).get() diff --git a/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts b/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts index 73c95b095ff80..1291b68844af2 100644 --- a/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts +++ b/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts @@ -21,7 +21,7 @@ export const addToDashboardModalLogic = kea([ key(keyForInsightLogicProps('new')), path((key) => ['lib', 'components', 'AddToDashboard', 'saveToDashboardModalLogic', key]), connect((props: InsightLogicProps) => ({ - values: [insightLogic(props), ['queryBasedInsight', 'legacyInsight']], + values: [insightLogic(props), ['queryBasedInsight']], actions: [ insightLogic(props), ['updateInsight', 'updateInsightSuccess', 'updateInsightFailure'], @@ -101,7 +101,9 @@ export const addToDashboardModalLogic = kea([ // TODO be able to update not by patching `dashboards` against insight // either patch dashboard_tiles on the insight or add a dashboard_tiles API actions.updateInsight( - { ...values.legacyInsight, dashboards: [...(values.legacyInsight.dashboards || []), dashboardId] }, + { + dashboards: [...(values.queryBasedInsight.dashboards || []), dashboardId], + }, () => { actions.reportSavedInsightToDashboard() dashboardsModel.actions.tileAddedToDashboard(dashboardId) @@ -117,9 +119,8 @@ export const addToDashboardModalLogic = kea([ removeFromDashboard: async ({ dashboardId }): Promise => { actions.updateInsight( { - ...values.legacyInsight, - dashboards: (values.legacyInsight.dashboards || []).filter((d) => d !== dashboardId), - dashboard_tiles: (values.legacyInsight.dashboard_tiles || []).filter( + dashboards: (values.queryBasedInsight.dashboards || []).filter((d) => d !== dashboardId), + dashboard_tiles: (values.queryBasedInsight.dashboard_tiles || []).filter( (dt) => dt.dashboard_id !== dashboardId ), }, diff --git a/frontend/src/lib/components/Cards/TextCard/TextCard.stories.tsx b/frontend/src/lib/components/Cards/TextCard/TextCard.stories.tsx index 426f978577e43..ec3dd435687aa 100644 --- a/frontend/src/lib/components/Cards/TextCard/TextCard.stories.tsx +++ b/frontend/src/lib/components/Cards/TextCard/TextCard.stories.tsx @@ -27,8 +27,6 @@ const makeTextTile = (body: string, color: InsightColor | null = null): Dashboar layouts: {}, color, - last_refresh: null, - next_allowed_client_refresh: null, } } diff --git a/frontend/src/models/dashboardsModel.tsx b/frontend/src/models/dashboardsModel.tsx index 96155776d941a..cf6b9b92c472c 100644 --- a/frontend/src/models/dashboardsModel.tsx +++ b/frontend/src/models/dashboardsModel.tsx @@ -31,26 +31,10 @@ export const dashboardsModel = kea([ // can provide extra dashboard ids if not all listeners will choose to respond to this action // not providing a dashboard id is a signal that only listeners in the item.dashboards array should respond // specifying `number` not `Pick because kea typegen couldn't figure out the import in `savedInsightsLogic` - // if an update is made against an insight it will hold last_refresh, color, and filters_hash in dashboard context - updateDashboardInsight: ( - insight: InsightModel, - extraDashboardIds?: number[], - updateTileOnDashboards?: [number] - ) => ({ + // if an update is made against an insight it will hold color in dashboard context + updateDashboardInsight: (insight: InsightModel, extraDashboardIds?: number[]) => ({ insight, extraDashboardIds, - updateTileOnDashboards, - }), - // a side effect on this action exists in dashboardLogic so that individual refresh statuses can be bubbled up - // to dashboard items in dashboards - updateDashboardRefreshStatus: ( - shortId: string | undefined | null, - refreshing: boolean | null, - last_refresh: string | null - ) => ({ - shortId, - refreshing, - last_refresh, }), pinDashboard: (id: number, source: DashboardEventSource) => ({ id, source }), unpinDashboard: (id: number, source: DashboardEventSource) => ({ id, source }), diff --git a/frontend/src/queries/nodes/HogQLX/render.tsx b/frontend/src/queries/nodes/HogQLX/render.tsx index 7e4e53a59e530..cf559762e7b9b 100644 --- a/frontend/src/queries/nodes/HogQLX/render.tsx +++ b/frontend/src/queries/nodes/HogQLX/render.tsx @@ -1,3 +1,4 @@ +import { Link } from '@posthog/lemon-ui' import { JSONViewer } from 'lib/components/JSONViewer' import { Sparkline } from 'lib/components/Sparkline' @@ -37,6 +38,29 @@ export function renderHogQLX(value: any): JSX.Element { ) + } else if (tag === 'a') { + const { href, source, target } = rest + return ( + + + {source ? renderHogQLX(source) : href} + + + ) + } else if (tag === 'strong') { + const { source } = rest + return ( + + {renderHogQLX(source)} + + ) + } else if (tag === 'em') { + const { source } = rest + return ( + + {renderHogQLX(source)} + + ) } return
Unknown tag: {String(tag)}
} diff --git a/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.test.ts b/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.test.ts index 9cb7ce95e339c..4922cc0b66a7b 100644 --- a/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.test.ts +++ b/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.test.ts @@ -409,6 +409,112 @@ describe('filtersToQueryNode', () => { } expect(result).toEqual(query) }) + + it('converts multiple breakdowns', () => { + const filters: Partial = { + insight: InsightType.TRENDS, + breakdowns: [ + { + type: 'event', + property: '$pathname', + normalize_url: true, + }, + { + type: 'group', + property: '$num', + group_type_index: 0, + histogram_bin_count: 10, + }, + ], + } + + const result = filtersToQueryNode(filters) + + const query: TrendsQuery = { + kind: NodeKind.TrendsQuery, + breakdownFilter: { + breakdowns: [ + { + type: 'event', + property: '$pathname', + normalize_url: true, + }, + { + type: 'group', + property: '$num', + group_type_index: 0, + histogram_bin_count: 10, + }, + ], + }, + series: [], + } + expect(result).toEqual(query) + }) + + it('converts legacy funnel breakdowns', () => { + const filters: Partial = { + insight: InsightType.TRENDS, + breakdowns: [ + { + type: 'event', + property: '$current_url', + }, + { + property: '$pathname', + } as any, + ], + } + + const result = filtersToQueryNode(filters) + + const query: TrendsQuery = { + kind: NodeKind.TrendsQuery, + breakdownFilter: { + breakdowns: [ + { + type: 'event', + property: '$current_url', + }, + { + type: 'event', + property: '$pathname', + }, + ], + }, + series: [], + } + expect(result).toEqual(query) + }) + + it('does not add breakdown_type for multiple breakdowns', () => { + const filters: Partial = { + insight: InsightType.TRENDS, + breakdowns: [ + { + type: 'person', + property: '$browser', + }, + ], + } + + const result = filtersToQueryNode(filters) + + const query: TrendsQuery = { + kind: NodeKind.TrendsQuery, + breakdownFilter: { + breakdowns: [ + { + type: 'person', + property: '$browser', + }, + ], + breakdown_type: undefined, + }, + series: [], + } + expect(result).toEqual(query) + }) }) describe('funnels filter', () => { diff --git a/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.ts b/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.ts index ea838920cc452..90c0c007c06b8 100644 --- a/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.ts +++ b/frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.ts @@ -296,22 +296,34 @@ export const filtersToQueryNode = (filters: Partial): InsightQueryNo // breakdown if (isInsightQueryWithBreakdown(query)) { - /* handle multi-breakdowns */ // not undefined or null if (filters.breakdowns != null) { - if (filters.breakdowns.length === 1) { - filters.breakdown_type = filters.breakdowns[0].type - filters.breakdown = filters.breakdowns[0].property as string - } else { - captureException( - 'Could not convert multi-breakdown property `breakdowns` - found more than one breakdown' - ) + /* handle multi-breakdowns for funnels */ + if (isFunnelsFilter(filters)) { + if (filters.breakdowns.length === 1) { + filters.breakdown_type = filters.breakdowns[0].type || 'event' + filters.breakdown = filters.breakdowns[0].property as string + } else { + captureException( + 'Could not convert multi-breakdown property `breakdowns` - found more than one breakdown' + ) + } } - } - /* handle missing breakdown_type */ - // check for undefined and null values - if (filters.breakdown != null && filters.breakdown_type == null) { + /* handle multi-breakdowns for trends */ + if (isTrendsFilter(filters)) { + filters.breakdowns = filters.breakdowns.map((b) => ({ + ...b, + // Compatibility with legacy funnel breakdowns when someone switches a view from funnels to trends + type: b.type || filters.breakdown_type || 'event', + })) + } + } else if ( + /* handle missing breakdown_type */ + // check for undefined and null values + filters.breakdown != null && + filters.breakdown_type == null + ) { filters.breakdown_type = 'event' } diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 1b30aa0bcc48b..457413fac79ed 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -7669,6 +7669,7 @@ "type": "integer" }, "end_time": { + "description": "When did the query execution task finish (whether successfully or not).", "format": "date-time", "type": "string" }, @@ -7697,6 +7698,11 @@ }, "type": "array" }, + "pickup_time": { + "description": "When was the query execution task picked up by a worker.", + "format": "date-time", + "type": "string" + }, "query_async": { "const": true, "default": true, @@ -7708,6 +7714,7 @@ }, "results": {}, "start_time": { + "description": "When was query execution task enqueued.", "format": "date-time", "type": "string" }, diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 924bc2bc0ee7e..e24bebda2ba5c 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -1079,9 +1079,11 @@ export type QueryStatus = { /** @default null */ error_message: string | null results?: any - /** @format date-time */ + /** When was the query execution task picked up by a worker. @format date-time */ + pickup_time?: string + /** When was query execution task enqueued. @format date-time */ start_time?: string - /** @format date-time */ + /** When did the query execution task finish (whether successfully or not). @format date-time */ end_time?: string /** @format date-time */ expiration_time?: string diff --git a/frontend/src/scenes/actions/Action.stories.tsx b/frontend/src/scenes/actions/Action.stories.tsx index 9f1e4d9f2bf26..f3586f06350a7 100644 --- a/frontend/src/scenes/actions/Action.stories.tsx +++ b/frontend/src/scenes/actions/Action.stories.tsx @@ -75,7 +75,6 @@ const meta: Meta = { get: { '/api/projects/:team_id/actions/': toPaginatedResponse([MOCK_ACTION]), '/api/projects/:team_id/actions/1/': MOCK_ACTION, - '/api/projects/:team_id/actions/1/plugin_configs': toPaginatedResponse([]), }, }), ], diff --git a/frontend/src/scenes/actions/Action.tsx b/frontend/src/scenes/actions/Action.tsx index 5ff2bdc067eb0..a76ac93078850 100644 --- a/frontend/src/scenes/actions/Action.tsx +++ b/frontend/src/scenes/actions/Action.tsx @@ -11,6 +11,7 @@ import { NodeKind } from '~/queries/schema' import { ActionType } from '~/types' import { ActionEdit } from './ActionEdit' +import { ActionHogFunctions } from './ActionHogFunctions' export const scene: SceneExport = { logic: actionLogic, @@ -44,6 +45,7 @@ export function Action({ id }: { id?: ActionType['id'] } = {}): JSX.Element { return ( <> + {id && ( <> {isComplete ? ( diff --git a/frontend/src/scenes/actions/ActionEdit.tsx b/frontend/src/scenes/actions/ActionEdit.tsx index e254cd34be4b0..eeb4512f8a627 100644 --- a/frontend/src/scenes/actions/ActionEdit.tsx +++ b/frontend/src/scenes/actions/ActionEdit.tsx @@ -1,11 +1,12 @@ import { IconInfo, IconPlus, IconWarning } from '@posthog/icons' -import { LemonCheckbox, LemonTextArea } from '@posthog/lemon-ui' +import { LemonBanner, LemonCheckbox, LemonTextArea } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { Form } from 'kea-forms' import { router } from 'kea-router' import { EditableField } from 'lib/components/EditableField/EditableField' import { ObjectTags } from 'lib/components/ObjectTags/ObjectTags' import { PageHeader } from 'lib/components/PageHeader' +import { useFeatureFlag } from 'lib/hooks/useFeatureFlag' import { IconPlayCircle } from 'lib/lemon-ui/icons' import { LemonButton } from 'lib/lemon-ui/LemonButton' import { LemonField } from 'lib/lemon-ui/LemonField' @@ -33,6 +34,8 @@ export function ActionEdit({ action: loadedAction, id }: ActionEditLogicProps): const slackEnabled = currentTeam?.slack_incoming_webhook + const hogFunctionsEnabled = useFeatureFlag('HOG_FUNCTIONS') + const deleteButton = (): JSX.Element => ( -
-

Webhook delivery

- - {({ value, onChange }) => ( -
- - Post to webhook when this action is triggered. - {action.bytecode_error ? ( - - ) : null} - - } - /> - - {slackEnabled ? 'Configure' : 'Enable'} webhooks in project settings. - -
+ {!hogFunctionsEnabled || action.post_to_slack ? ( +
+

Webhook delivery

+ + {hogFunctionsEnabled && ( + + The Webhook integration has been replaced with our new Pipeline Destinations + allowing for much greater customization and visibility into their execution. + )} - - {action.post_to_slack && ( - <> - {!action.bytecode_error && action.post_to_slack && ( - <> - - {({ value, onChange }) => ( + + + {({ value, onChange }) => ( +
+ - Slack message format - - - - See documentation on how to format webhook messages. - - + Post to webhook when this action is triggered. + {action.bytecode_error ? ( + + ) : null} - )} - - + } + /> + + {slackEnabled ? 'Configure' : 'Enable'} webhooks in project settings. + +
)} - - )} -
+
+ {action.post_to_slack && ( + <> + {!action.bytecode_error && action.post_to_slack && ( + <> + + {({ value, onChange }) => ( + <> + Slack message format + + + + See documentation on how to format webhook messages. + + + + )} + + + )} + + )} +
+ ) : undefined} ) diff --git a/frontend/src/scenes/actions/ActionHogFunctions.tsx b/frontend/src/scenes/actions/ActionHogFunctions.tsx new file mode 100644 index 0000000000000..781669d066d1b --- /dev/null +++ b/frontend/src/scenes/actions/ActionHogFunctions.tsx @@ -0,0 +1,59 @@ +import { LemonButton } from '@posthog/lemon-ui' +import { useValues } from 'kea' +import { useFeatureFlag } from 'lib/hooks/useFeatureFlag' +import { actionLogic } from 'scenes/actions/actionLogic' +import { DestinationsTable } from 'scenes/pipeline/destinations/Destinations' +import { PipelineBackend } from 'scenes/pipeline/types' +import { urls } from 'scenes/urls' + +import { PipelineStage } from '~/types' + +export function ActionHogFunctions(): JSX.Element | null { + const { action } = useValues(actionLogic) + + const hogFunctionsEnabled = useFeatureFlag('HOG_FUNCTIONS') + + if (!action || !hogFunctionsEnabled) { + return null + } + + return ( +
+
+

Connected destinations

+ + + New destination + +
+

Actions can be used a filters for destinations such as Slack or Webhook delivery

+ + +
+ ) +} diff --git a/frontend/src/scenes/actions/actionLogic.ts b/frontend/src/scenes/actions/actionLogic.ts index c640029bca9c5..0273bae1af70a 100644 --- a/frontend/src/scenes/actions/actionLogic.ts +++ b/frontend/src/scenes/actions/actionLogic.ts @@ -5,7 +5,7 @@ import { DataManagementTab } from 'scenes/data-management/DataManagementScene' import { Scene } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { ActionType, Breadcrumb, PluginConfigWithPluginInfoNew } from '~/types' +import { ActionType, Breadcrumb, HogFunctionType } from '~/types' import { actionEditLogic } from './actionEditLogic' import type { actionLogicType } from './actionLogicType' @@ -35,11 +35,11 @@ export const actionLogic = kea([ }, }, ], - matchingPluginConfigs: [ - null as PluginConfigWithPluginInfoNew[] | null, + matchingHogFunctions: [ + null as HogFunctionType[] | null, { - loadMatchingPluginConfigs: async () => { - const res = await api.actions.listMatchingPluginConfigs(props.id!) + loadMatchingHogFunctions: async () => { + const res = await api.hogFunctions.list({ filters: { actions: [{ id: `${props.id}` }] } }) return res.results }, diff --git a/frontend/src/scenes/batch_exports/BatchExportEditForm.tsx b/frontend/src/scenes/batch_exports/BatchExportEditForm.tsx index 12906569aea9f..3ecec1e636dcf 100644 --- a/frontend/src/scenes/batch_exports/BatchExportEditForm.tsx +++ b/frontend/src/scenes/batch_exports/BatchExportEditForm.tsx @@ -107,16 +107,6 @@ export function BatchExportGeneralEditFields({ )} - {featureFlags[FEATURE_FLAGS.PERSON_BATCH_EXPORTS] && ( - - - - )}
- + - + @@ -388,11 +378,11 @@ export function BatchExportsEditFields({ ) : batchExportConfigForm.destination === 'Postgres' ? ( <> - + - + @@ -453,11 +443,11 @@ export function BatchExportsEditFields({ ) : batchExportConfigForm.destination === 'Redshift' ? ( <> - + - + diff --git a/frontend/src/scenes/dashboard/dashboardLogic.test.ts b/frontend/src/scenes/dashboard/dashboardLogic.test.ts index d8c37d8f7b205..4533c1b69dbcf 100644 --- a/frontend/src/scenes/dashboard/dashboardLogic.test.ts +++ b/frontend/src/scenes/dashboard/dashboardLogic.test.ts @@ -40,7 +40,12 @@ export function insightOnDashboard( if (!tile.insight) { throw new Error('tile has no insight') } - return { ...tile.insight, dashboards: dashboardsRelation, filters: { ...tile.insight.filters, ...insight.filters } } + return { + ...tile.insight, + dashboards: dashboardsRelation, + dashboard_tiles: dashboardsRelation.map((dashboardId) => ({ id: insight.id!, dashboard_id: dashboardId })), + filters: { ...tile.insight.filters, ...insight.filters }, + } } const TEXT_TILE: DashboardTile = { @@ -48,7 +53,6 @@ const TEXT_TILE: DashboardTile = { text: { body: 'I AM A TEXT', last_modified_at: '2021-01-01T00:00:00Z' }, layouts: {}, color: InsightColor.Blue, - last_refresh: '2021-01-01T00:00:00Z', } let tileId = 0 @@ -57,7 +61,6 @@ export const tileFromInsight = (insight: InsightModel, id: number = tileId++): D layouts: {}, color: null, insight: insight, - last_refresh: insight.last_refresh, }) export const dashboardResult = ( @@ -590,22 +593,17 @@ describe('dashboardLogic', () => { it('can respond to external update of an insight on the dashboard', async () => { const copiedInsight = insight800() - dashboardsModel.actions.updateDashboardInsight( - { - ...copiedInsight, - filters: { ...copiedInsight.filters, date_from: '-1d', interval: 'hour' }, - last_refresh: '2012-04-01T00:00:00Z', - }, - [], - [9] - ) + dashboardsModel.actions.updateDashboardInsight({ + ...copiedInsight, + filters: { ...copiedInsight.filters, date_from: '-1d', interval: 'hour' }, + last_refresh: '2012-04-01T00:00:00Z', + }) await expectLogic(logic).toFinishAllListeners() expect(logic.values.dashboard?.tiles).toHaveLength(2) expect(logic.values.insightTiles[0].insight!.filters.date_from).toEqual('-1d') expect(logic.values.insightTiles[0].insight!.filters.interval).toEqual('hour') expect(logic.values.textTiles[0].text!.body).toEqual('I AM A TEXT') - expect(logic.values.insightTiles[0].last_refresh).toEqual('2012-04-01T00:00:00Z') }) it('can respond to external insight rename', async () => { diff --git a/frontend/src/scenes/dashboard/dashboardLogic.tsx b/frontend/src/scenes/dashboard/dashboardLogic.tsx index bb6e815dc0a8c..3ef98a5315506 100644 --- a/frontend/src/scenes/dashboard/dashboardLogic.tsx +++ b/frontend/src/scenes/dashboard/dashboardLogic.tsx @@ -409,11 +409,10 @@ export const dashboardLogic = kea([ } return state }, - [dashboardsModel.actionTypes.updateDashboardInsight]: ( - state, - { insight, extraDashboardIds, updateTileOnDashboards } - ) => { - const targetDashboards = (insight.dashboards || []).concat(extraDashboardIds || []) + [dashboardsModel.actionTypes.updateDashboardInsight]: (state, { insight, extraDashboardIds }) => { + const targetDashboards = (insight.dashboard_tiles || []) + .map((tile) => tile.dashboard_id) + .concat(extraDashboardIds || []) if (!targetDashboards.includes(props.id)) { // this update is not for this dashboard return state @@ -427,11 +426,10 @@ export const dashboardLogic = kea([ const newTiles = state.tiles.slice() if (tileIndex >= 0) { - if (insight.dashboards?.includes(props.id) && updateTileOnDashboards?.includes(props.id)) { + if (insight.dashboards?.includes(props.id)) { newTiles[tileIndex] = { ...newTiles[tileIndex], insight: insight, - last_refresh: insight.last_refresh, } } else if (!insight.dashboards?.includes(props.id)) { newTiles.splice(tileIndex, 1) @@ -452,27 +450,6 @@ export const dashboardLogic = kea([ [dashboardsModel.actionTypes.updateDashboardSuccess]: (state, { dashboard }) => { return state && dashboard && state.id === dashboard.id ? dashboard : state }, - [dashboardsModel.actionTypes.updateDashboardRefreshStatus]: ( - state, - { shortId, refreshing, last_refresh } - ) => { - // If not a dashboard item, don't do anything. - if (!shortId) { - return state - } - return { - ...state, - items: state?.tiles.map((t) => - !t.insight || t.insight.short_id === shortId - ? { - ...t, - ...(refreshing != null ? { refreshing } : {}), - ...(last_refresh != null ? { last_refresh } : {}), - } - : t - ), - } as DashboardType - }, [insightsModel.actionTypes.renameInsightSuccess]: (state, { item }): DashboardType | null => { const tileIndex = state?.tiles.findIndex((t) => !!t.insight && t.insight.short_id === item.short_id) const tiles = state?.tiles.slice(0) @@ -686,7 +663,9 @@ export const dashboardLogic = kea([ return [] } - const validDates = insightTiles.map((i) => dayjs(i.last_refresh)).filter((date) => date.isValid()) + const validDates = insightTiles + .map((i) => dayjs(i.insight?.last_refresh)) + .filter((date) => date.isValid()) return sortDayJsDates(validDates) }, ], @@ -701,16 +680,6 @@ export const dashboardLogic = kea([ return sortedDates[sortedDates.length - 1] }, ], - oldestRefreshed: [ - (s) => [s.sortedDates], - (sortedDates): Dayjs | null => { - if (!sortedDates.length) { - return null - } - - return sortedDates[0] - }, - ], sortedClientRefreshAllowed: [ (s) => [s.insightTiles], (insightTiles): Dayjs[] => { @@ -914,7 +883,9 @@ export const dashboardLogic = kea([ } }, [dashboardsModel.actionTypes.updateDashboardInsight]: ({ insight, extraDashboardIds }) => { - const targetDashboards = (insight.dashboards || []).concat(extraDashboardIds || []) + const targetDashboards = (insight.dashboard_tiles || []) + .map((tile) => tile.dashboard_id) + .concat(extraDashboardIds || []) if (!targetDashboards.includes(props.id)) { // this update is not for this dashboard return @@ -1000,7 +971,7 @@ export const dashboardLogic = kea([ uuid(), 'force_async' ) - dashboardsModel.actions.updateDashboardInsight(refreshedInsight, [], props.id ? [props.id] : undefined) + dashboardsModel.actions.updateDashboardInsight(refreshedInsight) // Start polling for results tile.insight = refreshedInsight actions.refreshAllDashboardItems({ tiles: [tile], action: 'refresh' }) @@ -1063,11 +1034,7 @@ export const dashboardLogic = kea([ 'async', methodOptions ) - dashboardsModel.actions.updateDashboardInsight( - polledInsight, - [], - props.id ? [props.id] : undefined - ) + dashboardsModel.actions.updateDashboardInsight(polledInsight) actions.setRefreshStatus(insight.short_id) } } catch (e: any) { @@ -1165,7 +1132,7 @@ export const dashboardLogic = kea([ const dashboard = values.dashboard const { action, dashboardQueryId, startTime, responseBytes } = values.dashboardLoadTimerData - const lastRefresh = sortDates(dashboard.tiles.map((tile) => tile.last_refresh)) + const lastRefresh = sortDates(dashboard.tiles.map((tile) => tile.insight?.last_refresh || null)) const initialLoad = action === 'initial_load' const allLoaded = false // TODO: Check this diff --git a/frontend/src/scenes/data-warehouse/external/forms/PostgresSchemaForm.tsx b/frontend/src/scenes/data-warehouse/external/forms/SchemaForm.tsx similarity index 93% rename from frontend/src/scenes/data-warehouse/external/forms/PostgresSchemaForm.tsx rename to frontend/src/scenes/data-warehouse/external/forms/SchemaForm.tsx index 98125b15466d3..fd23f4a2674fc 100644 --- a/frontend/src/scenes/data-warehouse/external/forms/PostgresSchemaForm.tsx +++ b/frontend/src/scenes/data-warehouse/external/forms/SchemaForm.tsx @@ -4,7 +4,7 @@ import { useActions, useValues } from 'kea' import { sourceWizardLogic } from '../../new/sourceWizardLogic' import { SyncMethodForm } from './SyncMethodForm' -export default function PostgresSchemaForm(): JSX.Element { +export default function SchemaForm(): JSX.Element { const { toggleSchemaShouldSync, openSyncMethodModal } = useActions(sourceWizardLogic) const { databaseSchema } = useValues(sourceWizardLogic) @@ -26,6 +26,11 @@ export default function PostgresSchemaForm(): JSX.Element { onChange={(checked) => { toggleSchemaShouldSync(schema, checked) }} + disabledReason={ + schema.sync_type === null + ? 'Please set up a sync method first' + : undefined + } /> ) }, diff --git a/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx b/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx index 81c44222314dd..4f402724ff9b3 100644 --- a/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx +++ b/frontend/src/scenes/data-warehouse/new/NewSourceWizard.tsx @@ -7,7 +7,7 @@ import { SceneExport } from 'scenes/sceneTypes' import { ManualLinkSourceType, SourceConfig } from '~/types' import { DataWarehouseInitialBillingLimitNotice } from '../DataWarehouseInitialBillingLimitNotice' -import PostgresSchemaForm from '../external/forms/PostgresSchemaForm' +import SchemaForm from '../external/forms/SchemaForm' import SourceForm from '../external/forms/SourceForm' import { SyncProgressStep } from '../external/forms/SyncProgressStep' import { DatawarehouseTableForm } from '../new/DataWarehouseTableForm' @@ -241,7 +241,7 @@ function SecondStep(): JSX.Element { function ThirdStep(): JSX.Element { return ( - + ) } diff --git a/frontend/src/scenes/error-tracking/ErrorTrackingActions.tsx b/frontend/src/scenes/error-tracking/ErrorTrackingActions.tsx deleted file mode 100644 index 5ad2db9f54524..0000000000000 --- a/frontend/src/scenes/error-tracking/ErrorTrackingActions.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { LemonButton, LemonSelect } from '@posthog/lemon-ui' -import { useActions, useValues } from 'kea' -import { DateFilter } from 'lib/components/DateFilter/DateFilter' - -import { errorTrackingDataLogic } from './errorTrackingDataLogic' -import { errorTrackingLogic } from './errorTrackingLogic' -import { errorTrackingSceneLogic } from './errorTrackingSceneLogic' - -export const ErrorTrackingActions = ({ showOrder = true }: { showOrder?: boolean }): JSX.Element => { - const { dateRange } = useValues(errorTrackingLogic) - const { setDateRange } = useActions(errorTrackingLogic) - const { order, selectedRows } = useValues(errorTrackingSceneLogic) - const { setOrder, setSelectedRows } = useActions(errorTrackingSceneLogic) - const { mergeGroups } = useActions(errorTrackingDataLogic) - - return selectedRows.length === 0 ? ( -
-
- Date range: - { - setDateRange({ date_from: changedDateFrom, date_to: changedDateTo }) - }} - size="small" - /> -
- {showOrder && ( -
- Sort by: - -
- )} -
- ) : ( -
- setSelectedRows([])}> - Unselect all - - {selectedRows.length > 1 && ( - { - mergeGroups(selectedRows) - setSelectedRows([]) - }} - > - Merge - - )} -
- ) -} diff --git a/frontend/src/scenes/error-tracking/ErrorTrackingFilters.tsx b/frontend/src/scenes/error-tracking/ErrorTrackingFilters.tsx index 37d5007133f28..2ea376d39cea6 100644 --- a/frontend/src/scenes/error-tracking/ErrorTrackingFilters.tsx +++ b/frontend/src/scenes/error-tracking/ErrorTrackingFilters.tsx @@ -1,4 +1,6 @@ +import { LemonSelect } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' +import { DateFilter } from 'lib/components/DateFilter/DateFilter' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' import UniversalFilters from 'lib/components/UniversalFilters/UniversalFilters' import { universalFiltersLogic } from 'lib/components/UniversalFilters/universalFiltersLogic' @@ -7,8 +9,9 @@ import { useEffect, useState } from 'react' import { TestAccountFilter } from 'scenes/insights/filters/TestAccountFilter' import { errorTrackingLogic } from './errorTrackingLogic' +import { errorTrackingSceneLogic } from './errorTrackingSceneLogic' -export const ErrorTrackingFilters = (): JSX.Element => { +export const FilterGroup = (): JSX.Element => { const { filterGroup, filterTestAccounts } = useValues(errorTrackingLogic) const { setFilterGroup, setFilterTestAccounts } = useActions(errorTrackingLogic) @@ -66,3 +69,64 @@ const RecordingsUniversalFilterGroup = (): JSX.Element => { ) } + +export const Options = ({ showOrder = true }: { showOrder?: boolean }): JSX.Element => { + const { dateRange } = useValues(errorTrackingLogic) + const { setDateRange } = useActions(errorTrackingLogic) + const { order } = useValues(errorTrackingSceneLogic) + const { setOrder } = useActions(errorTrackingSceneLogic) + + return ( +
+
+ Date range: + { + setDateRange({ date_from: changedDateFrom, date_to: changedDateTo }) + }} + size="small" + /> +
+ {showOrder && ( +
+ Sort by: + +
+ )} +
+ ) +} + +export default { + FilterGroup, + Options, +} diff --git a/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx b/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx index 6009b8f03961e..917668336ece8 100644 --- a/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx +++ b/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx @@ -4,8 +4,7 @@ import { LemonDivider, LemonTabs } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { SceneExport } from 'scenes/sceneTypes' -import { ErrorTrackingActions } from './ErrorTrackingActions' -import { ErrorTrackingFilters } from './ErrorTrackingFilters' +import ErrorTrackingFilters from './ErrorTrackingFilters' import { ErrorGroupTab, errorTrackingGroupSceneLogic } from './errorTrackingGroupSceneLogic' import { BreakdownsTab } from './groups/BreakdownsTab' import { OverviewTab } from './groups/OverviewTab' @@ -23,10 +22,10 @@ export function ErrorTrackingGroupScene(): JSX.Element { const { setErrorGroupTab } = useActions(errorTrackingGroupSceneLogic) return ( -
- - - + <> + + + -
+ ) } diff --git a/frontend/src/scenes/error-tracking/ErrorTrackingScene.tsx b/frontend/src/scenes/error-tracking/ErrorTrackingScene.tsx index d1e794ea7ff67..de779b65fba99 100644 --- a/frontend/src/scenes/error-tracking/ErrorTrackingScene.tsx +++ b/frontend/src/scenes/error-tracking/ErrorTrackingScene.tsx @@ -14,9 +14,8 @@ import { ErrorTrackingGroup } from '~/queries/schema' import { QueryContext, QueryContextColumnComponent, QueryContextColumnTitleComponent } from '~/queries/types' import { InsightLogicProps } from '~/types' -import { ErrorTrackingActions } from './ErrorTrackingActions' -import { errorTrackingDataLogic } from './errorTrackingDataLogic' -import { ErrorTrackingFilters } from './ErrorTrackingFilters' +import { errorTrackingDataNodeLogic } from './errorTrackingDataNodeLogic' +import ErrorTrackingFilters from './ErrorTrackingFilters' import { errorTrackingLogic } from './errorTrackingLogic' import { errorTrackingSceneLogic } from './errorTrackingSceneLogic' @@ -26,7 +25,7 @@ export const scene: SceneExport = { } export function ErrorTrackingScene(): JSX.Element { - const { query } = useValues(errorTrackingSceneLogic) + const { query, selectedRows } = useValues(errorTrackingSceneLogic) const insightProps: InsightLogicProps = { dashboardItemId: 'new-ErrorTrackingQuery', @@ -48,17 +47,41 @@ export function ErrorTrackingScene(): JSX.Element { } return ( - -
- - - - -
+ + + + {selectedRows.length === 0 ? : } + ) } +const ErrorTrackingActions = (): JSX.Element => { + const { selectedRows } = useValues(errorTrackingSceneLogic) + const { setSelectedRows } = useActions(errorTrackingSceneLogic) + const { mergeGroups } = useActions(errorTrackingDataNodeLogic) + + return ( +
+ setSelectedRows([])}> + Unselect all + + {selectedRows.length > 1 && ( + { + mergeGroups(selectedRows) + setSelectedRows([]) + }} + > + Merge + + )} +
+ ) +} + const CustomVolumeColumnHeader: QueryContextColumnTitleComponent = ({ columnName }) => { const { sparklineSelectedPeriod, sparklineOptions: options } = useValues(errorTrackingLogic) const { setSparklineSelectedPeriod } = useActions(errorTrackingLogic) @@ -121,7 +144,7 @@ const CustomGroupTitleColumn: QueryContextColumnComponent = (props) => { } const AssigneeColumn: QueryContextColumnComponent = (props) => { - const { assignGroup } = useActions(errorTrackingDataLogic) + const { assignGroup } = useActions(errorTrackingDataNodeLogic) const record = props.record as ErrorTrackingGroup diff --git a/frontend/src/scenes/error-tracking/__mocks__/error_tracking_query.ts b/frontend/src/scenes/error-tracking/__mocks__/error_tracking_query.ts index 1247854bf8251..b69d479cf1acb 100644 --- a/frontend/src/scenes/error-tracking/__mocks__/error_tracking_query.ts +++ b/frontend/src/scenes/error-tracking/__mocks__/error_tracking_query.ts @@ -147,7 +147,7 @@ const errorTrackingGroupQueryResponse = { person: { created_at: '2024-04-05T21:14:16.048000Z', distinct_id: 'BTQiT390vxwlLeDSwZAZpXC7r7bkNc3TQuhobit0oj7', - properties: JSON.stringify({ email: 'test@example.com' }), + properties: { email: 'test@example.com' }, uuid: 'person_uuid', }, })), diff --git a/frontend/src/scenes/error-tracking/errorTrackingDataLogic.tsx b/frontend/src/scenes/error-tracking/errorTrackingDataNodeLogic.tsx similarity index 86% rename from frontend/src/scenes/error-tracking/errorTrackingDataLogic.tsx rename to frontend/src/scenes/error-tracking/errorTrackingDataNodeLogic.tsx index 540590d01ffe8..586b5bcf64e39 100644 --- a/frontend/src/scenes/error-tracking/errorTrackingDataLogic.tsx +++ b/frontend/src/scenes/error-tracking/errorTrackingDataNodeLogic.tsx @@ -4,19 +4,19 @@ import api from 'lib/api' import { dataNodeLogic, DataNodeLogicProps } from '~/queries/nodes/DataNode/dataNodeLogic' import { ErrorTrackingGroup } from '~/queries/schema' -import type { errorTrackingDataLogicType } from './errorTrackingDataLogicType' +import type { errorTrackingDataNodeLogicType } from './errorTrackingDataNodeLogicType' import { mergeGroups } from './utils' -export interface ErrorTrackingDataLogicProps { +export interface ErrorTrackingDataNodeLogicProps { query: DataNodeLogicProps['query'] key: DataNodeLogicProps['key'] } -export const errorTrackingDataLogic = kea([ - path(['scenes', 'error-tracking', 'errorTrackingDataLogic']), - props({} as ErrorTrackingDataLogicProps), +export const errorTrackingDataNodeLogic = kea([ + path(['scenes', 'error-tracking', 'errorTrackingDataNodeLogic']), + props({} as ErrorTrackingDataNodeLogicProps), - connect(({ key, query }: ErrorTrackingDataLogicProps) => ({ + connect(({ key, query }: ErrorTrackingDataNodeLogicProps) => ({ values: [dataNodeLogic({ key, query }), ['response']], actions: [dataNodeLogic({ key, query }), ['setResponse']], })), diff --git a/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts b/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts index 8289707d37d1e..f070c24177e69 100644 --- a/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts +++ b/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts @@ -29,7 +29,7 @@ export type ErrorTrackingGroupEvent = { distinct_id: string uuid?: string created_at?: string - properties?: string + properties?: Record } } diff --git a/frontend/src/scenes/error-tracking/groups/OverviewTab.tsx b/frontend/src/scenes/error-tracking/groups/OverviewTab.tsx index a640f17ee14c8..62d04251edc55 100644 --- a/frontend/src/scenes/error-tracking/groups/OverviewTab.tsx +++ b/frontend/src/scenes/error-tracking/groups/OverviewTab.tsx @@ -71,13 +71,13 @@ const ListItemException = ({ }) .filter((property) => !!property.value) - const person = { ...event.person, properties: event.person.properties ? JSON.parse(event.person.properties) : {} } + // const person = { ...event.person, properties: event.person.properties ? JSON.parse(event.person.properties) : {} } return (
- +
diff --git a/frontend/src/scenes/insights/InsightNav/insightNavLogic.test.ts b/frontend/src/scenes/insights/InsightNav/insightNavLogic.test.ts index 04203684479ba..cefd6499bf052 100644 --- a/frontend/src/scenes/insights/InsightNav/insightNavLogic.test.ts +++ b/frontend/src/scenes/insights/InsightNav/insightNavLogic.test.ts @@ -5,7 +5,7 @@ import { insightNavLogic } from 'scenes/insights/InsightNav/insightNavLogic' import { useMocks } from '~/mocks/jest' import { nodeKindToDefaultQuery } from '~/queries/nodes/InsightQuery/defaults' -import { InsightVizNode, Node, NodeKind, TrendsQuery } from '~/queries/schema' +import { FunnelsQuery, InsightVizNode, Node, NodeKind, TrendsQuery } from '~/queries/schema' import { initKeaTests } from '~/test/init' import { FunnelVizType, InsightLogicProps, InsightShortId, InsightType, StepOrderValue } from '~/types' @@ -286,6 +286,144 @@ describe('insightNavLogic', () => { } as Node), ]) }) + + it('gets rid of multiple breakdowns when switching from trends to funnels', async () => { + trendsQuery.source = { + ...trendsQuery.source, + breakdownFilter: { + breakdowns: [ + { property: 'num', type: 'person', histogram_bin_count: 10 }, + { property: '$device_type', type: 'event' }, + ], + }, + } as TrendsQuery + + await expectLogic(logic, () => { + builtInsightDataLogic.actions.setQuery(trendsQuery) + }) + + await expectLogic(builtInsightDataLogic, () => { + logic.actions.setActiveView(InsightType.FUNNELS) + }).toDispatchActions([ + builtInsightDataLogic.actionCreators.setQuery({ + kind: 'InsightVizNode', + source: { + kind: 'FunnelsQuery', + series: [{ kind: 'EventsNode', name: '$pageview', event: '$pageview' }], + funnelsFilter: { funnelVizType: 'steps' }, + filterTestAccounts: true, + interval: 'hour', + breakdownFilter: { + breakdowns: undefined, + breakdown: 'num', + breakdown_type: 'person', + breakdown_histogram_bin_count: 10, + breakdown_group_type_index: undefined, + breakdown_normalize_url: undefined, + }, + }, + } as Node), + ]) + }) + + it('keeps multiple breakdowns when switching from funnels to trends', async () => { + funnelsQuery.source = { + ...funnelsQuery.source, + breakdownFilter: { + breakdowns: [ + { property: 'num', type: 'person' }, + { property: '$device_type', type: 'event' }, + ], + }, + } as FunnelsQuery + + await expectLogic(logic, () => { + builtInsightDataLogic.actions.setQuery(funnelsQuery) + }) + + await expectLogic(builtInsightDataLogic, () => { + logic.actions.setActiveView(InsightType.TRENDS) + }).toDispatchActions([ + builtInsightDataLogic.actionCreators.setQuery({ + kind: 'InsightVizNode', + source: { + kind: 'TrendsQuery', + series: [ + { kind: 'EventsNode', name: '$pageview', event: '$pageview', math: 'total' }, + { kind: 'EventsNode', name: '$pageleave', event: '$pageleave', math: 'total' }, + ], + trendsFilter: {}, + filterTestAccounts: true, + breakdownFilter: { + breakdowns: [ + { property: 'num', type: 'person' }, + { property: '$device_type', type: 'event' }, + ], + }, + }, + } as Node), + ]) + }) + + it('keeps breakdowns when switching between trends and funnels', async () => { + trendsQuery.source = { + ...trendsQuery.source, + breakdownFilter: { + breakdowns: [ + { property: '$pathname', type: 'group', normalize_url: true, group_type_index: 0 }, + { property: '$device_type', type: 'event' }, + ], + }, + } as TrendsQuery + + await expectLogic(logic, () => { + builtInsightDataLogic.actions.setQuery(trendsQuery) + }) + + await expectLogic(builtInsightDataLogic, () => { + logic.actions.setActiveView(InsightType.FUNNELS) + }).toDispatchActions([ + builtInsightDataLogic.actionCreators.setQuery({ + kind: 'InsightVizNode', + source: { + kind: 'FunnelsQuery', + series: [{ kind: 'EventsNode', name: '$pageview', event: '$pageview' }], + funnelsFilter: { funnelVizType: 'steps' }, + filterTestAccounts: true, + interval: 'hour', + breakdownFilter: { + breakdowns: undefined, + breakdown: '$pathname', + breakdown_type: 'group', + breakdown_group_type_index: 0, + breakdown_normalize_url: true, + }, + }, + } as Node), + ]) + + await expectLogic(builtInsightDataLogic, () => { + logic.actions.setActiveView(InsightType.TRENDS) + }).toDispatchActions([ + builtInsightDataLogic.actionCreators.setQuery({ + kind: 'InsightVizNode', + source: { + kind: 'TrendsQuery', + series: [{ kind: 'EventsNode', name: '$pageview', event: '$pageview', math: 'total' }], + trendsFilter: { showValuesOnSeries: true }, + filterTestAccounts: true, + interval: 'hour', + breakdownFilter: { + breakdowns: undefined, + breakdown: '$pathname', + breakdown_type: 'group', + breakdown_group_type_index: 0, + breakdown_normalize_url: true, + }, + }, + } as Node), + ]) + }) }) }) }) diff --git a/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx b/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx index d3df8da9f7c8c..c4ac869a1ec34 100644 --- a/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx +++ b/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx @@ -36,6 +36,7 @@ import { getDisplay, getShowPercentStackView, getShowValuesOnSeries, + isFunnelsQuery, isHogQuery, isInsightQueryWithBreakdown, isInsightQueryWithSeries, @@ -375,6 +376,27 @@ const mergeCachedProperties = (query: InsightQueryNode, cache: QueryPropertyCach // breakdown filter if (isInsightQueryWithBreakdown(mergedQuery) && cache.breakdownFilter) { mergedQuery.breakdownFilter = cache.breakdownFilter + + // If we've changed the query kind, convert multiple breakdowns to a single breakdown + if (isTrendsQuery(cache) && isFunnelsQuery(query)) { + if (cache.breakdownFilter.breakdowns?.length) { + const firstBreakdown = cache.breakdownFilter?.breakdowns?.[0] + mergedQuery.breakdownFilter = { + ...cache.breakdownFilter, + breakdowns: undefined, + breakdown: firstBreakdown?.property, + breakdown_type: firstBreakdown?.type, + breakdown_histogram_bin_count: firstBreakdown?.histogram_bin_count, + breakdown_group_type_index: firstBreakdown?.group_type_index, + breakdown_normalize_url: firstBreakdown?.normalize_url, + } + } else { + mergedQuery.breakdownFilter = { + ...cache.breakdownFilter, + breakdowns: undefined, + } + } + } } // funnel paths filter diff --git a/frontend/src/scenes/insights/insightLogic.test.ts b/frontend/src/scenes/insights/insightLogic.test.ts index c94ea390e505f..1c8595b2d264c 100644 --- a/frontend/src/scenes/insights/insightLogic.test.ts +++ b/frontend/src/scenes/insights/insightLogic.test.ts @@ -9,7 +9,6 @@ import { savedInsightsLogic } from 'scenes/saved-insights/savedInsightsLogic' import { teamLogic } from 'scenes/teamLogic' import { urls } from 'scenes/urls' -import { resumeKeaLoadersErrors, silenceKeaLoadersErrors } from '~/initKea' import { useMocks } from '~/mocks/jest' import { dashboardsModel } from '~/models/dashboardsModel' import { insightsModel } from '~/models/insightsModel' @@ -528,7 +527,7 @@ describe('insightLogic', () => { logic.actions.saveInsight() await expectLogic(logic).toDispatchActions([savedInsightsLogic.actionTypes.addInsight]) - logic.actions.updateInsight({ filters: { insight: InsightType.FUNNELS } }) + logic.actions.updateInsight({ name: 'my new name' }) await expectLogic(logic).toDispatchActions([savedInsightsLogic.actionTypes.setInsight]) }) @@ -552,6 +551,9 @@ describe('insightLogic', () => { savedInsightsLogic.mount() logic = insightLogic({ dashboardItemId: Insight43, + cachedInsight: { + id: 3, + }, }) logic.mount() @@ -591,42 +593,6 @@ describe('insightLogic', () => { }) }) - describe('emptyFilters', () => { - let theEmptyFiltersLogic: ReturnType - beforeEach(() => { - const insight = { - result: ['result from api'], - } - theEmptyFiltersLogic = insightLogic({ - dashboardItemId: undefined, - cachedInsight: insight, - }) - theEmptyFiltersLogic.mount() - silenceKeaLoadersErrors() - }) - afterEach(resumeKeaLoadersErrors) - - it('does not call the api on update when empty filters and no query', async () => { - await expectLogic(theEmptyFiltersLogic, () => { - theEmptyFiltersLogic.actions.updateInsight({ - name: 'name', - filters: {}, - query: undefined, - }) - }).toNotHaveDispatchedActions(['updateInsightSuccess']) - }) - - it('does call the api on update when empty filters but query is present', async () => { - await expectLogic(theEmptyFiltersLogic, () => { - theEmptyFiltersLogic.actions.updateInsight({ - name: 'name', - filters: {}, - query: { kind: NodeKind.DataTableNode } as DataTableNode, - }) - }).toDispatchActions(['updateInsightSuccess']) - }) - }) - describe('reacts to external changes', () => { beforeEach(async () => { logic = insightLogic({ diff --git a/frontend/src/scenes/insights/insightLogic.ts b/frontend/src/scenes/insights/insightLogic.ts index 036b501f42f91..457e10f261c3c 100644 --- a/frontend/src/scenes/insights/insightLogic.ts +++ b/frontend/src/scenes/insights/insightLogic.ts @@ -39,16 +39,10 @@ import { import { teamLogic } from '../teamLogic' import type { insightLogicType } from './insightLogicType' import { getInsightId } from './utils' +import { insightsApi } from './utils/api' export const UNSAVED_INSIGHT_MIN_REFRESH_INTERVAL_MINUTES = 3 -function emptyFilters(filters: Partial | undefined): boolean { - return ( - !filters || - (Object.keys(filters).length < 2 && JSON.stringify(cleanFilters(filters)) === JSON.stringify(cleanFilters({}))) - ) -} - export const createEmptyInsight = ( insightId: InsightShortId | `new-${string}` | 'new', filterTestAccounts: boolean @@ -102,8 +96,8 @@ export const insightLogic = kea([ loadInsight: (shortId: InsightShortId) => ({ shortId, }), - updateInsight: (insight: Partial, callback?: (insight: Partial) => void) => ({ - insight, + updateInsight: (insightUpdate: Partial, callback?: () => void) => ({ + insightUpdate, callback, }), setInsightMetadata: (metadata: Partial) => ({ metadata }), @@ -126,35 +120,23 @@ export const insightLogic = kea([ } throw new Error(`Insight "${shortId}" not found`) }, - updateInsight: async ({ insight, callback }, breakpoint) => { - if (!Object.entries(insight).length) { + updateInsight: async ({ insightUpdate, callback }, breakpoint) => { + if (!Object.entries(insightUpdate).length) { return values.legacyInsight } - if ('filters' in insight && !insight.query && emptyFilters(insight.filters)) { - const error = new Error('Will not override empty filters in updateInsight.') - captureException(error, { - extra: { - filters: JSON.stringify(insight.filters), - insight: JSON.stringify(insight), - valuesInsight: JSON.stringify(values.legacyInsight), - }, - }) - throw error - } - - const response = await api.update( - `api/projects/${teamLogic.values.currentTeamId}/insights/${values.legacyInsight.id}`, - insight - ) + const response = await insightsApi.update(values.queryBasedInsight.id, insightUpdate, { + writeAsQuery: values.queryBasedInsightSaving, + readAsQuery: false, + }) breakpoint() const updatedInsight: InsightModel = { ...response, result: response.result || values.legacyInsight.result, } - callback?.(updatedInsight) + callback?.() - const removedDashboards = (values.legacyInsight.dashboards || []).filter( + const removedDashboards = (values.queryBasedInsight.dashboards || []).filter( (d) => !updatedInsight.dashboards?.includes(d) ) dashboardsModel.actions.updateDashboardInsight(updatedInsight, removedDashboards) diff --git a/frontend/src/scenes/insights/views/InsightsTable/InsightsTable.tsx b/frontend/src/scenes/insights/views/InsightsTable/InsightsTable.tsx index 7217c0074f27b..730ad17b66cda 100644 --- a/frontend/src/scenes/insights/views/InsightsTable/InsightsTable.tsx +++ b/frontend/src/scenes/insights/views/InsightsTable/InsightsTable.tsx @@ -167,9 +167,7 @@ export function InsightsTable({ }, }) } - } - - if (breakdownFilter?.breakdowns) { + } else if (breakdownFilter?.breakdowns) { breakdownFilter.breakdowns.forEach((breakdown, index) => { const formatItemBreakdownLabel = (item: IndexedTrendResult): string => formatBreakdownLabel( diff --git a/frontend/src/scenes/persons/PersonDisplay.tsx b/frontend/src/scenes/persons/PersonDisplay.tsx index 5271d7c7899c7..30faf9300ac64 100644 --- a/frontend/src/scenes/persons/PersonDisplay.tsx +++ b/frontend/src/scenes/persons/PersonDisplay.tsx @@ -8,8 +8,6 @@ import { ProfilePicture, ProfilePictureProps } from 'lib/lemon-ui/ProfilePicture import { useMemo, useState } from 'react' import { useNotebookNode } from 'scenes/notebooks/Nodes/NotebookNodeContext' -import { NotebookNodeType } from '~/types' - import { asDisplay, asLink } from './person-utils' import { PersonPreview } from './PersonPreview' @@ -83,19 +81,6 @@ export function PersonDisplay({ router.actions.push(href) } else { setVisible(true) - - if (notebookNode && person) { - notebookNode.actions.updateAttributes({ - children: [ - { - type: NotebookNodeType.Person, - attrs: { - id: person.distinct_id || person.distinct_ids?.[0], - }, - }, - ], - }) - } } } : undefined @@ -107,7 +92,7 @@ export function PersonDisplay({ { - if (!noPopover) { + if (!noPopover && !notebookNode) { e.preventDefault() return } diff --git a/frontend/src/scenes/pipeline/destinations/Destinations.tsx b/frontend/src/scenes/pipeline/destinations/Destinations.tsx index 0dc46d76e3d2c..6d2ea2b019c72 100644 --- a/frontend/src/scenes/pipeline/destinations/Destinations.tsx +++ b/frontend/src/scenes/pipeline/destinations/Destinations.tsx @@ -54,7 +54,7 @@ export function Destinations(): JSX.Element { ) } -export function DestinationsTable(props: PipelineDestinationsLogicProps): JSX.Element { +export function DestinationsTable({ ...props }: PipelineDestinationsLogicProps): JSX.Element { const { loading, filteredDestinations, filters, destinations } = useValues(pipelineDestinationsLogic(props)) const { setFilters, resetFilters } = useActions(pipelineDestinationsLogic(props)) @@ -63,36 +63,42 @@ export function DestinationsTable(props: PipelineDestinationsLogicProps): JSX.El return ( <>
- setFilters({ search: e })} - /> + {!props.forceFilters?.search && ( + setFilters({ search: e })} + /> + )}
- setFilters({ onlyActive: e ?? undefined })} - /> - setFilters({ kind: e ?? undefined })} - /> + {typeof props.forceFilters?.onlyActive !== 'boolean' && ( + setFilters({ onlyActive: e ?? undefined })} + /> + )} + {!props.forceFilters?.kind && ( + setFilters({ kind: e ?? undefined })} + /> + )}
@@ -216,7 +222,7 @@ export function DestinationsTable(props: PipelineDestinationsLogicProps): JSX.El } const DestinationMoreOverlay = ({ destination }: { destination: Destination }): JSX.Element => { - const { canConfigurePlugins, canEnableNewDestinations } = useValues(pipelineAccessLogic) + const { canConfigurePlugins, canEnableDestination } = useValues(pipelineAccessLogic) const { toggleNode, deleteNode } = useActions(pipelineDestinationsLogic) return ( @@ -227,7 +233,7 @@ const DestinationMoreOverlay = ({ destination }: { destination: Destination }): onClick: () => toggleNode(destination, !destination.enabled), disabledReason: !canConfigurePlugins ? 'You do not have permission to toggle destinations.' - : !canEnableNewDestinations && !destination.enabled + : !canEnableDestination(destination) && !destination.enabled ? 'Data pipelines add-on is required for enabling new destinations' : undefined, }, diff --git a/frontend/src/scenes/pipeline/destinations/NewDestinations.tsx b/frontend/src/scenes/pipeline/destinations/NewDestinations.tsx index ad91ad46e5c95..c862242200a5c 100644 --- a/frontend/src/scenes/pipeline/destinations/NewDestinations.tsx +++ b/frontend/src/scenes/pipeline/destinations/NewDestinations.tsx @@ -17,7 +17,7 @@ export function DestinationOptionsTable(): JSX.Element { const hogFunctionsEnabled = !!useFeatureFlag('HOG_FUNCTIONS') const { loading, filteredDestinations, filters } = useValues(newDestinationsLogic) const { setFilters, openFeedbackDialog } = useActions(newDestinationsLogic) - const { canEnableNewDestinations } = useValues(pipelineAccessLogic) + const { canEnableDestination } = useValues(pipelineAccessLogic) return (
@@ -71,7 +71,7 @@ export function DestinationOptionsTable(): JSX.Element { render: function RenderName(_, target) { return ( {target.name} @@ -98,7 +98,7 @@ export function DestinationOptionsTable(): JSX.Element { width: 100, align: 'right', render: function RenderActions(_, target) { - return canEnableNewDestinations || target.status === 'free' ? ( + return canEnableDestination(target) ? ( } export type PipelineDestinationsLogicProps = { defaultFilters?: DestinationFilters + forceFilters?: DestinationFilters syncFiltersWithUrl?: boolean } @@ -55,7 +57,7 @@ export const pipelineDestinationsLogic = kea([ userLogic, ['user', 'hasAvailableFeature'], pipelineAccessLogic, - ['canEnableNewDestinations'], + ['canEnableDestination'], ], }), actions({ @@ -73,13 +75,16 @@ export const pipelineDestinationsLogic = kea([ }), reducers(({ props }) => ({ filters: [ - props.defaultFilters as DestinationFilters, + { ...(props.defaultFilters || {}), ...(props.forceFilters || {}) } as DestinationFilters, { setFilters: (state, { filters }) => ({ ...state, ...filters, + ...(props.forceFilters || {}), + }), + resetFilters: () => ({ + ...(props.forceFilters || {}), }), - resetFilters: () => ({}), }, ], })), @@ -188,7 +193,11 @@ export const pipelineDestinationsLogic = kea([ { loadHogFunctions: async () => { // TODO: Support pagination? - return (await api.hogFunctions.list()).results + return ( + await api.hogFunctions.list({ + filters: values.filters?.filters, + }) + ).results }, deleteNodeHogFunction: async ({ destination }) => { @@ -286,7 +295,7 @@ export const pipelineDestinationsLogic = kea([ }), listeners(({ values, actions }) => ({ toggleNode: ({ destination, enabled }) => { - if (enabled && !values.canEnableNewDestinations) { + if (enabled && !values.canEnableDestination(destination)) { lemonToast.error('Data pipelines add-on is required for enabling new destinations.') return } diff --git a/frontend/src/scenes/pipeline/hogfunctions/HogFunctionConfiguration.tsx b/frontend/src/scenes/pipeline/hogfunctions/HogFunctionConfiguration.tsx index f9f4e71e48926..15674256224b8 100644 --- a/frontend/src/scenes/pipeline/hogfunctions/HogFunctionConfiguration.tsx +++ b/frontend/src/scenes/pipeline/hogfunctions/HogFunctionConfiguration.tsx @@ -170,7 +170,6 @@ export function HogFunctionConfiguration({ templateId, id }: { templateId?: stri {({ value, onChange }) => ( onChange(val)} /> @@ -306,12 +305,12 @@ export function HogFunctionConfiguration({ templateId, id }: { templateId?: stri <> {sparkline.count > EVENT_THRESHOLD_ALERT_LEVEL ? ( - Warning: This destionation would have triggered{' '} + Warning: This destination would have triggered{' '} {sparkline.count ?? 0} time{sparkline.count !== 1 ? 's' : ''} {' '} in the last 7 days. Consider the impact of this function on your - infrastructure. + destination. ) : (

diff --git a/frontend/src/scenes/pipeline/hogfunctions/HogFunctionIcon.tsx b/frontend/src/scenes/pipeline/hogfunctions/HogFunctionIcon.tsx index f99ee30ef52bb..49b0e094862bb 100644 --- a/frontend/src/scenes/pipeline/hogfunctions/HogFunctionIcon.tsx +++ b/frontend/src/scenes/pipeline/hogfunctions/HogFunctionIcon.tsx @@ -2,6 +2,7 @@ import { LemonButton, LemonFileInput, LemonInput, LemonSkeleton, lemonToast, Pop import clsx from 'clsx' import { useActions, useValues } from 'kea' import { IconUploadFile } from 'lib/lemon-ui/icons' +import { useState } from 'react' import { hogFunctionIconLogic, HogFunctionIconLogicProps } from './hogFunctionIconLogic' @@ -47,15 +48,7 @@ export function HogFunctionIconEditable({ const { setShowPopover, setSearchTerm } = useActions(hogFunctionIconLogic(props)) const content = ( - setShowPopover(!showPopover)} - > - {possibleIconsLoading ? : null} + setShowPopover(!showPopover)}> ) @@ -105,18 +98,14 @@ export function HogFunctionIconEditable({ {possibleIcons?.map((icon) => ( { const nonTempUrl = icon.url.replace('&temp=true', '') props.onChange?.(nonTempUrl) setShowPopover(false) }} > - + )) ?? (possibleIconsLoading ? ( @@ -142,15 +131,31 @@ export function HogFunctionIcon({ src?: string size?: 'small' | 'medium' | 'large' }): JSX.Element { + const [loaded, setLoaded] = useState(false) + return ( - {src ? : 🦔} + {src ? ( + <> + setLoaded(true)} + /> + {!loaded && } + + ) : ( + 🦔 + )} ) } diff --git a/frontend/src/scenes/pipeline/hogfunctions/hogFunctionIconLogic.ts b/frontend/src/scenes/pipeline/hogfunctions/hogFunctionIconLogic.ts index 2f92423b57a00..28c3076c3cbed 100644 --- a/frontend/src/scenes/pipeline/hogfunctions/hogFunctionIconLogic.ts +++ b/frontend/src/scenes/pipeline/hogfunctions/hogFunctionIconLogic.ts @@ -1,4 +1,4 @@ -import { actions, kea, key, listeners, path, props, propsChanged, reducers } from 'kea' +import { actions, kea, key, listeners, path, props, reducers } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' @@ -8,7 +8,6 @@ import type { hogFunctionIconLogicType } from './hogFunctionIconLogicType' export interface HogFunctionIconLogicProps { logicKey: string - search: string src?: string onChange?: (src: string) => void } @@ -41,12 +40,12 @@ export const hogFunctionIconLogic = kea([ ], }), - loaders(({ props, values }) => ({ + loaders(({ values }) => ({ possibleIcons: [ null as HogFunctionIconResponse[] | null, { loadPossibleIcons: async (_, breakpoint) => { - const search = values.searchTerm ?? props.search + const search = values.searchTerm if (!search) { return [] @@ -63,18 +62,7 @@ export const hogFunctionIconLogic = kea([ ], })), - listeners(({ actions, values, props }) => ({ - loadPossibleIconsSuccess: async () => { - const autoChange = props.onChange && (!props.src || props.src.includes('temp=true')) - if (!autoChange) { - return - } - const firstValue = values.possibleIcons?.[0] - if (firstValue) { - props.onChange?.(firstValue.url) - } - }, - + listeners(({ actions }) => ({ setShowPopover: ({ show }) => { if (show) { actions.loadPossibleIcons() @@ -85,13 +73,4 @@ export const hogFunctionIconLogic = kea([ actions.loadPossibleIcons() }, })), - - propsChanged(({ props, actions }, oldProps) => { - if (!props.onChange) { - return - } - if (!props.src || (props.search !== oldProps.search && props.src.includes('temp=true'))) { - actions.loadPossibleIcons() - } - }), ]) diff --git a/frontend/src/scenes/pipeline/pipelineAccessLogic.tsx b/frontend/src/scenes/pipeline/pipelineAccessLogic.tsx index d738434e8aed4..5a997a8a33bac 100644 --- a/frontend/src/scenes/pipeline/pipelineAccessLogic.tsx +++ b/frontend/src/scenes/pipeline/pipelineAccessLogic.tsx @@ -5,6 +5,7 @@ import { userLogic } from 'scenes/userLogic' import { AvailableFeature } from '~/types' import type { pipelineAccessLogicType } from './pipelineAccessLogicType' +import { Destination, NewDestinationItemType, PipelineBackend } from './types' export const pipelineAccessLogic = kea([ path(['scenes', 'pipeline', 'pipelineAccessLogic']), @@ -22,5 +23,18 @@ export const pipelineAccessLogic = kea([ user?.is_impersonated || (canConfigurePlugins(user?.organization) && hasAvailableFeature(AvailableFeature.DATA_PIPELINES)), ], + + canEnableDestination: [ + (s) => [s.canEnableNewDestinations], + (canEnableNewDestinations): ((destination: Destination | NewDestinationItemType) => boolean) => { + return (destination: Destination | NewDestinationItemType) => { + return destination.backend === PipelineBackend.HogFunction + ? ('hog_function' in destination + ? destination.hog_function.template?.status === 'free' + : destination.status === 'free') || canEnableNewDestinations + : canEnableNewDestinations + } + }, + ], }), ]) diff --git a/frontend/src/scenes/pipeline/pipelineBatchExportConfigurationLogic.tsx b/frontend/src/scenes/pipeline/pipelineBatchExportConfigurationLogic.tsx index e66534326f964..f596d8c158d42 100644 --- a/frontend/src/scenes/pipeline/pipelineBatchExportConfigurationLogic.tsx +++ b/frontend/src/scenes/pipeline/pipelineBatchExportConfigurationLogic.tsx @@ -332,14 +332,14 @@ export const pipelineBatchExportConfigurationLogic = kea [p.id], (id): boolean => !id], requiredFields: [ - (s) => [s.service], - (service): string[] => { + (s) => [s.service, s.isNew], + (service, isNew): string[] => { const generalRequiredFields = ['interval', 'name', 'model'] if (service === 'Postgres') { return [ ...generalRequiredFields, - 'user', - 'password', + ...(isNew ? ['user'] : []), + ...(isNew ? ['password'] : []), 'host', 'port', 'database', @@ -349,8 +349,8 @@ export const pipelineBatchExportConfigurationLogic = kea } > - {plugin.url ? ( + {plugin.url && plugin.plugin_type !== 'inline' ? ( diff --git a/frontend/src/scenes/plugins/plugin/PluginImage.tsx b/frontend/src/scenes/plugins/plugin/PluginImage.tsx index 610a9d64a46b7..dc6fc298377bd 100644 --- a/frontend/src/scenes/plugins/plugin/PluginImage.tsx +++ b/frontend/src/scenes/plugins/plugin/PluginImage.tsx @@ -1,10 +1,15 @@ import { IconTerminal } from '@posthog/icons' import { parseGithubRepoURL } from 'lib/utils' import imgPluginDefault from 'public/plugin-default.svg' +import IconTransformationSemverFlattener from 'public/transformations/semver-flattener.png' import { useEffect, useState } from 'react' import { PluginType } from '~/types' +const pluginImageOverrides: Record = { + 'inline://semver-flattener': IconTransformationSemverFlattener, +} + export type PluginImageSize = 'small' | 'medium' | 'large' export function PluginImage({ @@ -23,7 +28,10 @@ export function PluginImage({ }[size] useEffect(() => { - if (icon) { + const imageOverride = pluginImageOverrides[url ?? ''] + if (imageOverride) { + setState((state) => ({ ...state, image: imageOverride })) + } else if (icon) { setState((state) => ({ ...state, image: icon })) } else if (url?.includes('github.com')) { const { user, repo, path } = parseGithubRepoURL(url) diff --git a/frontend/src/scenes/session-recordings/player/rrweb/canvas/canvas-plugin.ts b/frontend/src/scenes/session-recordings/player/rrweb/canvas/canvas-plugin.ts index 6b6d58a1e2f4b..b11d928f51c22 100644 --- a/frontend/src/scenes/session-recordings/player/rrweb/canvas/canvas-plugin.ts +++ b/frontend/src/scenes/session-recordings/player/rrweb/canvas/canvas-plugin.ts @@ -165,7 +165,7 @@ export const CanvasReplayerPlugin = (events: eventWithTime[]): ReplayPlugin => { }, // ensures transparency is possible 'image/webp', - 0.5 + 0.4 ) } } diff --git a/frontend/src/scenes/settings/project/WebhookIntegration.tsx b/frontend/src/scenes/settings/project/WebhookIntegration.tsx index 6a01dd2e113ce..a14ee599902b0 100644 --- a/frontend/src/scenes/settings/project/WebhookIntegration.tsx +++ b/frontend/src/scenes/settings/project/WebhookIntegration.tsx @@ -5,6 +5,9 @@ import { FEATURE_FLAGS } from 'lib/constants' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { useEffect, useState } from 'react' import { teamLogic } from 'scenes/teamLogic' +import { urls } from 'scenes/urls' + +import { PipelineTab } from '~/types' import { webhookIntegrationLogic } from './webhookIntegrationLogic' @@ -22,6 +25,8 @@ export function WebhookIntegration(): JSX.Element { } }, [currentTeam]) + const hogFunctionsEnabled = featureFlags[FEATURE_FLAGS.HOG_FUNCTIONS] + const webhooks_disallowed = featureFlags[FEATURE_FLAGS.WEBHOOKS_DENYLIST] if (webhooks_disallowed) { return ( @@ -36,6 +41,18 @@ export function WebhookIntegration(): JSX.Element { ) } + if (hogFunctionsEnabled && !currentTeam?.slack_incoming_webhook) { + return ( + <> +

+ The Webhook integration has been replaced with our new{' '} + Pipeline Destinations allowing you to + create multiple, highly customizable webhook triggers based off of Actions or Events. +

+ + ) + } + return (

diff --git a/frontend/src/scenes/web-analytics/WebDashboard.tsx b/frontend/src/scenes/web-analytics/WebDashboard.tsx index d2bd1958c810c..1ad977cfa7193 100644 --- a/frontend/src/scenes/web-analytics/WebDashboard.tsx +++ b/frontend/src/scenes/web-analytics/WebDashboard.tsx @@ -40,12 +40,10 @@ const Filters = (): JSX.Element => { return (

diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 48b61d2556218..620ea900d7b25 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -1658,7 +1658,7 @@ export interface Tileable { color: InsightColor | null } -export interface DashboardTile extends Tileable, Cacheable { +export interface DashboardTile extends Tileable { id: number insight?: InsightModel text?: TextModel diff --git a/hogql_parser/HogQLParser.cpp b/hogql_parser/HogQLParser.cpp index 987d4a53df495..00d7c0e7b68de 100644 --- a/hogql_parser/HogQLParser.cpp +++ b/hogql_parser/HogQLParser.cpp @@ -114,7 +114,7 @@ void hogqlparserParserInitialize() { } ); static const int32_t serializedATNSegment[] = { - 4,1,159,1307,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6, + 4,1,159,1311,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6, 2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14, 7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21, 7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7,26,2,27,7,27,2,28, @@ -201,407 +201,409 @@ void hogqlparserParserInitialize() { 12,61,1067,9,61,1,61,3,61,1070,8,61,1,61,1,61,1,61,1,61,1,61,5,61,1077, 8,61,10,61,12,61,1080,9,61,1,61,3,61,1083,8,61,3,61,1085,8,61,1,61,1, 61,1,61,1,62,1,62,1,62,5,62,1093,8,62,10,62,12,62,1096,9,62,1,62,1,62, - 1,62,1,62,1,62,1,62,5,62,1104,8,62,10,62,12,62,1107,9,62,1,62,1,62,3, - 62,1111,8,62,1,62,1,62,1,62,1,62,1,62,3,62,1118,8,62,1,63,1,63,1,63,1, - 63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,3,63,1131,8,63,1,64,1,64,1,64,5, - 64,1136,8,64,10,64,12,64,1139,9,64,1,64,3,64,1142,8,64,1,65,1,65,1,65, - 1,65,1,65,1,65,1,65,1,65,1,65,1,65,3,65,1154,8,65,1,66,1,66,1,66,1,66, - 3,66,1160,8,66,1,66,3,66,1163,8,66,1,67,1,67,1,67,5,67,1168,8,67,10,67, - 12,67,1171,9,67,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,3,68,1182, - 8,68,1,68,1,68,1,68,1,68,3,68,1188,8,68,5,68,1190,8,68,10,68,12,68,1193, - 9,68,1,69,1,69,1,69,3,69,1198,8,69,1,69,1,69,1,70,1,70,1,70,3,70,1205, - 8,70,1,70,1,70,1,71,1,71,1,71,5,71,1212,8,71,10,71,12,71,1215,9,71,1, - 71,3,71,1218,8,71,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1,73,3,73,1228,8, - 73,3,73,1230,8,73,1,74,3,74,1233,8,74,1,74,1,74,1,74,1,74,1,74,1,74,3, - 74,1241,8,74,1,75,1,75,1,75,3,75,1246,8,75,1,76,1,76,1,77,1,77,1,78,1, - 78,1,79,1,79,3,79,1256,8,79,1,80,1,80,1,80,3,80,1261,8,80,1,81,1,81,1, - 81,1,81,1,82,1,82,1,82,1,82,1,83,1,83,3,83,1273,8,83,1,84,1,84,5,84,1277, - 8,84,10,84,12,84,1280,9,84,1,84,1,84,1,85,1,85,1,85,1,85,1,85,3,85,1289, - 8,85,1,86,1,86,5,86,1293,8,86,10,86,12,86,1296,9,86,1,86,1,86,1,87,1, - 87,1,87,1,87,1,87,3,87,1305,8,87,1,87,0,3,78,116,136,88,0,2,4,6,8,10, - 12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56, - 58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102, - 104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138, - 140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174, - 0,16,2,0,18,18,74,74,2,0,44,44,51,51,3,0,1,1,4,4,8,8,4,0,1,1,3,4,8,8, - 80,80,2,0,51,51,73,73,2,0,1,1,4,4,2,0,7,7,22,23,2,0,30,30,49,49,2,0,71, - 71,76,76,3,0,10,10,50,50,90,90,2,0,41,41,53,53,1,0,107,108,2,0,118,118, - 139,139,7,0,21,21,38,38,55,56,70,70,78,78,97,97,103,103,16,0,1,13,15, - 20,22,28,30,30,32,37,39,42,44,51,53,54,58,58,60,69,71,77,79,83,85,92, - 94,96,98,99,101,102,4,0,20,20,30,30,39,39,48,48,1474,0,179,1,0,0,0,2, - 186,1,0,0,0,4,188,1,0,0,0,6,190,1,0,0,0,8,197,1,0,0,0,10,220,1,0,0,0, - 12,222,1,0,0,0,14,229,1,0,0,0,16,236,1,0,0,0,18,249,1,0,0,0,20,261,1, - 0,0,0,22,270,1,0,0,0,24,278,1,0,0,0,26,300,1,0,0,0,28,315,1,0,0,0,30, - 324,1,0,0,0,32,329,1,0,0,0,34,333,1,0,0,0,36,335,1,0,0,0,38,344,1,0,0, - 0,40,348,1,0,0,0,42,362,1,0,0,0,44,366,1,0,0,0,46,381,1,0,0,0,48,384, - 1,0,0,0,50,433,1,0,0,0,52,436,1,0,0,0,54,442,1,0,0,0,56,446,1,0,0,0,58, - 452,1,0,0,0,60,470,1,0,0,0,62,473,1,0,0,0,64,476,1,0,0,0,66,486,1,0,0, - 0,68,489,1,0,0,0,70,493,1,0,0,0,72,526,1,0,0,0,74,528,1,0,0,0,76,531, - 1,0,0,0,78,546,1,0,0,0,80,608,1,0,0,0,82,613,1,0,0,0,84,624,1,0,0,0,86, - 626,1,0,0,0,88,632,1,0,0,0,90,640,1,0,0,0,92,658,1,0,0,0,94,660,1,0,0, - 0,96,668,1,0,0,0,98,673,1,0,0,0,100,681,1,0,0,0,102,685,1,0,0,0,104,689, - 1,0,0,0,106,698,1,0,0,0,108,712,1,0,0,0,110,714,1,0,0,0,112,773,1,0,0, - 0,114,775,1,0,0,0,116,935,1,0,0,0,118,1044,1,0,0,0,120,1057,1,0,0,0,122, - 1084,1,0,0,0,124,1117,1,0,0,0,126,1130,1,0,0,0,128,1132,1,0,0,0,130,1153, - 1,0,0,0,132,1162,1,0,0,0,134,1164,1,0,0,0,136,1181,1,0,0,0,138,1194,1, - 0,0,0,140,1204,1,0,0,0,142,1208,1,0,0,0,144,1219,1,0,0,0,146,1229,1,0, - 0,0,148,1232,1,0,0,0,150,1245,1,0,0,0,152,1247,1,0,0,0,154,1249,1,0,0, - 0,156,1251,1,0,0,0,158,1255,1,0,0,0,160,1260,1,0,0,0,162,1262,1,0,0,0, - 164,1266,1,0,0,0,166,1272,1,0,0,0,168,1274,1,0,0,0,170,1288,1,0,0,0,172, - 1290,1,0,0,0,174,1304,1,0,0,0,176,178,3,2,1,0,177,176,1,0,0,0,178,181, - 1,0,0,0,179,177,1,0,0,0,179,180,1,0,0,0,180,182,1,0,0,0,181,179,1,0,0, - 0,182,183,5,0,0,1,183,1,1,0,0,0,184,187,3,6,3,0,185,187,3,10,5,0,186, - 184,1,0,0,0,186,185,1,0,0,0,187,3,1,0,0,0,188,189,3,116,58,0,189,5,1, - 0,0,0,190,191,5,52,0,0,191,195,3,160,80,0,192,193,5,115,0,0,193,194,5, - 122,0,0,194,196,3,4,2,0,195,192,1,0,0,0,195,196,1,0,0,0,196,7,1,0,0,0, - 197,202,3,160,80,0,198,199,5,116,0,0,199,201,3,160,80,0,200,198,1,0,0, - 0,201,204,1,0,0,0,202,200,1,0,0,0,202,203,1,0,0,0,203,206,1,0,0,0,204, - 202,1,0,0,0,205,207,5,116,0,0,206,205,1,0,0,0,206,207,1,0,0,0,207,9,1, - 0,0,0,208,221,3,12,6,0,209,221,3,14,7,0,210,221,3,18,9,0,211,221,3,20, - 10,0,212,221,3,22,11,0,213,221,3,26,13,0,214,221,3,24,12,0,215,221,3, - 28,14,0,216,221,3,30,15,0,217,221,3,36,18,0,218,221,3,32,16,0,219,221, - 3,34,17,0,220,208,1,0,0,0,220,209,1,0,0,0,220,210,1,0,0,0,220,211,1,0, - 0,0,220,212,1,0,0,0,220,213,1,0,0,0,220,214,1,0,0,0,220,215,1,0,0,0,220, - 216,1,0,0,0,220,217,1,0,0,0,220,218,1,0,0,0,220,219,1,0,0,0,221,11,1, - 0,0,0,222,224,5,72,0,0,223,225,3,4,2,0,224,223,1,0,0,0,224,225,1,0,0, - 0,225,227,1,0,0,0,226,228,5,150,0,0,227,226,1,0,0,0,227,228,1,0,0,0,228, - 13,1,0,0,0,229,231,5,84,0,0,230,232,3,4,2,0,231,230,1,0,0,0,231,232,1, - 0,0,0,232,234,1,0,0,0,233,235,5,150,0,0,234,233,1,0,0,0,234,235,1,0,0, - 0,235,15,1,0,0,0,236,245,5,14,0,0,237,238,5,130,0,0,238,241,3,160,80, - 0,239,240,5,115,0,0,240,242,3,160,80,0,241,239,1,0,0,0,241,242,1,0,0, - 0,242,243,1,0,0,0,243,244,5,149,0,0,244,246,1,0,0,0,245,237,1,0,0,0,245, - 246,1,0,0,0,246,247,1,0,0,0,247,248,3,36,18,0,248,17,1,0,0,0,249,250, - 5,93,0,0,250,254,3,36,18,0,251,253,3,16,8,0,252,251,1,0,0,0,253,256,1, - 0,0,0,254,252,1,0,0,0,254,255,1,0,0,0,255,259,1,0,0,0,256,254,1,0,0,0, - 257,258,5,29,0,0,258,260,3,36,18,0,259,257,1,0,0,0,259,260,1,0,0,0,260, - 19,1,0,0,0,261,262,5,40,0,0,262,263,5,130,0,0,263,264,3,4,2,0,264,265, - 5,149,0,0,265,268,3,10,5,0,266,267,5,25,0,0,267,269,3,10,5,0,268,266, - 1,0,0,0,268,269,1,0,0,0,269,21,1,0,0,0,270,271,5,100,0,0,271,272,5,130, - 0,0,272,273,3,4,2,0,273,274,5,149,0,0,274,276,3,10,5,0,275,277,5,150, - 0,0,276,275,1,0,0,0,276,277,1,0,0,0,277,23,1,0,0,0,278,279,5,33,0,0,279, - 283,5,130,0,0,280,284,3,6,3,0,281,284,3,30,15,0,282,284,3,4,2,0,283,280, - 1,0,0,0,283,281,1,0,0,0,283,282,1,0,0,0,283,284,1,0,0,0,284,285,1,0,0, - 0,285,287,5,150,0,0,286,288,3,4,2,0,287,286,1,0,0,0,287,288,1,0,0,0,288, - 289,1,0,0,0,289,293,5,150,0,0,290,294,3,6,3,0,291,294,3,30,15,0,292,294, - 3,4,2,0,293,290,1,0,0,0,293,291,1,0,0,0,293,292,1,0,0,0,293,294,1,0,0, - 0,294,295,1,0,0,0,295,296,5,149,0,0,296,298,3,10,5,0,297,299,5,150,0, - 0,298,297,1,0,0,0,298,299,1,0,0,0,299,25,1,0,0,0,300,301,5,33,0,0,301, - 302,5,130,0,0,302,303,5,52,0,0,303,306,3,160,80,0,304,305,5,116,0,0,305, - 307,3,160,80,0,306,304,1,0,0,0,306,307,1,0,0,0,307,308,1,0,0,0,308,309, - 5,42,0,0,309,310,3,4,2,0,310,311,5,149,0,0,311,313,3,10,5,0,312,314,5, - 150,0,0,313,312,1,0,0,0,313,314,1,0,0,0,314,27,1,0,0,0,315,316,5,31,0, - 0,316,317,3,160,80,0,317,319,5,130,0,0,318,320,3,8,4,0,319,318,1,0,0, - 0,319,320,1,0,0,0,320,321,1,0,0,0,321,322,5,149,0,0,322,323,3,36,18,0, - 323,29,1,0,0,0,324,325,3,4,2,0,325,326,5,115,0,0,326,327,5,122,0,0,327, - 328,3,4,2,0,328,31,1,0,0,0,329,331,3,4,2,0,330,332,5,150,0,0,331,330, - 1,0,0,0,331,332,1,0,0,0,332,33,1,0,0,0,333,334,5,150,0,0,334,35,1,0,0, - 0,335,339,5,128,0,0,336,338,3,2,1,0,337,336,1,0,0,0,338,341,1,0,0,0,339, - 337,1,0,0,0,339,340,1,0,0,0,340,342,1,0,0,0,341,339,1,0,0,0,342,343,5, - 147,0,0,343,37,1,0,0,0,344,345,3,4,2,0,345,346,5,115,0,0,346,347,3,4, - 2,0,347,39,1,0,0,0,348,353,3,38,19,0,349,350,5,116,0,0,350,352,3,38,19, - 0,351,349,1,0,0,0,352,355,1,0,0,0,353,351,1,0,0,0,353,354,1,0,0,0,354, - 357,1,0,0,0,355,353,1,0,0,0,356,358,5,116,0,0,357,356,1,0,0,0,357,358, - 1,0,0,0,358,41,1,0,0,0,359,363,3,44,22,0,360,363,3,48,24,0,361,363,3, - 124,62,0,362,359,1,0,0,0,362,360,1,0,0,0,362,361,1,0,0,0,363,364,1,0, - 0,0,364,365,5,0,0,1,365,43,1,0,0,0,366,372,3,46,23,0,367,368,5,95,0,0, - 368,369,5,1,0,0,369,371,3,46,23,0,370,367,1,0,0,0,371,374,1,0,0,0,372, - 370,1,0,0,0,372,373,1,0,0,0,373,45,1,0,0,0,374,372,1,0,0,0,375,382,3, - 48,24,0,376,377,5,130,0,0,377,378,3,44,22,0,378,379,5,149,0,0,379,382, - 1,0,0,0,380,382,3,164,82,0,381,375,1,0,0,0,381,376,1,0,0,0,381,380,1, - 0,0,0,382,47,1,0,0,0,383,385,3,50,25,0,384,383,1,0,0,0,384,385,1,0,0, - 0,385,386,1,0,0,0,386,388,5,79,0,0,387,389,5,24,0,0,388,387,1,0,0,0,388, - 389,1,0,0,0,389,391,1,0,0,0,390,392,3,52,26,0,391,390,1,0,0,0,391,392, - 1,0,0,0,392,393,1,0,0,0,393,395,3,114,57,0,394,396,3,54,27,0,395,394, - 1,0,0,0,395,396,1,0,0,0,396,398,1,0,0,0,397,399,3,56,28,0,398,397,1,0, - 0,0,398,399,1,0,0,0,399,401,1,0,0,0,400,402,3,60,30,0,401,400,1,0,0,0, - 401,402,1,0,0,0,402,404,1,0,0,0,403,405,3,62,31,0,404,403,1,0,0,0,404, - 405,1,0,0,0,405,407,1,0,0,0,406,408,3,64,32,0,407,406,1,0,0,0,407,408, - 1,0,0,0,408,411,1,0,0,0,409,410,5,102,0,0,410,412,7,0,0,0,411,409,1,0, - 0,0,411,412,1,0,0,0,412,415,1,0,0,0,413,414,5,102,0,0,414,416,5,89,0, - 0,415,413,1,0,0,0,415,416,1,0,0,0,416,418,1,0,0,0,417,419,3,66,33,0,418, - 417,1,0,0,0,418,419,1,0,0,0,419,421,1,0,0,0,420,422,3,58,29,0,421,420, - 1,0,0,0,421,422,1,0,0,0,422,424,1,0,0,0,423,425,3,68,34,0,424,423,1,0, - 0,0,424,425,1,0,0,0,425,428,1,0,0,0,426,429,3,72,36,0,427,429,3,74,37, - 0,428,426,1,0,0,0,428,427,1,0,0,0,428,429,1,0,0,0,429,431,1,0,0,0,430, - 432,3,76,38,0,431,430,1,0,0,0,431,432,1,0,0,0,432,49,1,0,0,0,433,434, - 5,102,0,0,434,435,3,128,64,0,435,51,1,0,0,0,436,437,5,88,0,0,437,440, - 5,108,0,0,438,439,5,102,0,0,439,441,5,85,0,0,440,438,1,0,0,0,440,441, - 1,0,0,0,441,53,1,0,0,0,442,443,5,34,0,0,443,444,3,78,39,0,444,55,1,0, - 0,0,445,447,7,1,0,0,446,445,1,0,0,0,446,447,1,0,0,0,447,448,1,0,0,0,448, - 449,5,5,0,0,449,450,5,47,0,0,450,451,3,114,57,0,451,57,1,0,0,0,452,453, - 5,101,0,0,453,454,3,160,80,0,454,455,5,6,0,0,455,456,5,130,0,0,456,457, - 3,98,49,0,457,467,5,149,0,0,458,459,5,116,0,0,459,460,3,160,80,0,460, - 461,5,6,0,0,461,462,5,130,0,0,462,463,3,98,49,0,463,464,5,149,0,0,464, - 466,1,0,0,0,465,458,1,0,0,0,466,469,1,0,0,0,467,465,1,0,0,0,467,468,1, - 0,0,0,468,59,1,0,0,0,469,467,1,0,0,0,470,471,5,69,0,0,471,472,3,116,58, - 0,472,61,1,0,0,0,473,474,5,99,0,0,474,475,3,116,58,0,475,63,1,0,0,0,476, - 477,5,36,0,0,477,484,5,11,0,0,478,479,7,0,0,0,479,480,5,130,0,0,480,481, - 3,114,57,0,481,482,5,149,0,0,482,485,1,0,0,0,483,485,3,114,57,0,484,478, - 1,0,0,0,484,483,1,0,0,0,485,65,1,0,0,0,486,487,5,37,0,0,487,488,3,116, - 58,0,488,67,1,0,0,0,489,490,5,64,0,0,490,491,5,11,0,0,491,492,3,88,44, - 0,492,69,1,0,0,0,493,494,5,64,0,0,494,495,5,11,0,0,495,496,3,114,57,0, - 496,71,1,0,0,0,497,498,5,54,0,0,498,501,3,116,58,0,499,500,5,116,0,0, - 500,502,3,116,58,0,501,499,1,0,0,0,501,502,1,0,0,0,502,507,1,0,0,0,503, - 504,5,102,0,0,504,508,5,85,0,0,505,506,5,11,0,0,506,508,3,114,57,0,507, - 503,1,0,0,0,507,505,1,0,0,0,507,508,1,0,0,0,508,527,1,0,0,0,509,510,5, - 54,0,0,510,513,3,116,58,0,511,512,5,102,0,0,512,514,5,85,0,0,513,511, - 1,0,0,0,513,514,1,0,0,0,514,515,1,0,0,0,515,516,5,61,0,0,516,517,3,116, - 58,0,517,527,1,0,0,0,518,519,5,54,0,0,519,520,3,116,58,0,520,521,5,61, - 0,0,521,524,3,116,58,0,522,523,5,11,0,0,523,525,3,114,57,0,524,522,1, - 0,0,0,524,525,1,0,0,0,525,527,1,0,0,0,526,497,1,0,0,0,526,509,1,0,0,0, - 526,518,1,0,0,0,527,73,1,0,0,0,528,529,5,61,0,0,529,530,3,116,58,0,530, - 75,1,0,0,0,531,532,5,81,0,0,532,533,3,94,47,0,533,77,1,0,0,0,534,535, - 6,39,-1,0,535,537,3,136,68,0,536,538,5,28,0,0,537,536,1,0,0,0,537,538, - 1,0,0,0,538,540,1,0,0,0,539,541,3,86,43,0,540,539,1,0,0,0,540,541,1,0, - 0,0,541,547,1,0,0,0,542,543,5,130,0,0,543,544,3,78,39,0,544,545,5,149, - 0,0,545,547,1,0,0,0,546,534,1,0,0,0,546,542,1,0,0,0,547,562,1,0,0,0,548, - 549,10,3,0,0,549,550,3,82,41,0,550,551,3,78,39,4,551,561,1,0,0,0,552, - 554,10,4,0,0,553,555,3,80,40,0,554,553,1,0,0,0,554,555,1,0,0,0,555,556, - 1,0,0,0,556,557,5,47,0,0,557,558,3,78,39,0,558,559,3,84,42,0,559,561, - 1,0,0,0,560,548,1,0,0,0,560,552,1,0,0,0,561,564,1,0,0,0,562,560,1,0,0, - 0,562,563,1,0,0,0,563,79,1,0,0,0,564,562,1,0,0,0,565,567,7,2,0,0,566, - 565,1,0,0,0,566,567,1,0,0,0,567,568,1,0,0,0,568,575,5,44,0,0,569,571, - 5,44,0,0,570,572,7,2,0,0,571,570,1,0,0,0,571,572,1,0,0,0,572,575,1,0, - 0,0,573,575,7,2,0,0,574,566,1,0,0,0,574,569,1,0,0,0,574,573,1,0,0,0,575, - 609,1,0,0,0,576,578,7,3,0,0,577,576,1,0,0,0,577,578,1,0,0,0,578,579,1, - 0,0,0,579,581,7,4,0,0,580,582,5,65,0,0,581,580,1,0,0,0,581,582,1,0,0, - 0,582,591,1,0,0,0,583,585,7,4,0,0,584,586,5,65,0,0,585,584,1,0,0,0,585, - 586,1,0,0,0,586,588,1,0,0,0,587,589,7,3,0,0,588,587,1,0,0,0,588,589,1, - 0,0,0,589,591,1,0,0,0,590,577,1,0,0,0,590,583,1,0,0,0,591,609,1,0,0,0, - 592,594,7,5,0,0,593,592,1,0,0,0,593,594,1,0,0,0,594,595,1,0,0,0,595,597, - 5,35,0,0,596,598,5,65,0,0,597,596,1,0,0,0,597,598,1,0,0,0,598,607,1,0, - 0,0,599,601,5,35,0,0,600,602,5,65,0,0,601,600,1,0,0,0,601,602,1,0,0,0, - 602,604,1,0,0,0,603,605,7,5,0,0,604,603,1,0,0,0,604,605,1,0,0,0,605,607, - 1,0,0,0,606,593,1,0,0,0,606,599,1,0,0,0,607,609,1,0,0,0,608,574,1,0,0, - 0,608,590,1,0,0,0,608,606,1,0,0,0,609,81,1,0,0,0,610,611,5,17,0,0,611, - 614,5,47,0,0,612,614,5,116,0,0,613,610,1,0,0,0,613,612,1,0,0,0,614,83, - 1,0,0,0,615,616,5,62,0,0,616,625,3,114,57,0,617,618,5,96,0,0,618,619, - 5,130,0,0,619,620,3,114,57,0,620,621,5,149,0,0,621,625,1,0,0,0,622,623, - 5,96,0,0,623,625,3,114,57,0,624,615,1,0,0,0,624,617,1,0,0,0,624,622,1, - 0,0,0,625,85,1,0,0,0,626,627,5,77,0,0,627,630,3,92,46,0,628,629,5,61, - 0,0,629,631,3,92,46,0,630,628,1,0,0,0,630,631,1,0,0,0,631,87,1,0,0,0, - 632,637,3,90,45,0,633,634,5,116,0,0,634,636,3,90,45,0,635,633,1,0,0,0, - 636,639,1,0,0,0,637,635,1,0,0,0,637,638,1,0,0,0,638,89,1,0,0,0,639,637, - 1,0,0,0,640,642,3,116,58,0,641,643,7,6,0,0,642,641,1,0,0,0,642,643,1, - 0,0,0,643,646,1,0,0,0,644,645,5,60,0,0,645,647,7,7,0,0,646,644,1,0,0, - 0,646,647,1,0,0,0,647,650,1,0,0,0,648,649,5,16,0,0,649,651,5,110,0,0, - 650,648,1,0,0,0,650,651,1,0,0,0,651,91,1,0,0,0,652,659,3,164,82,0,653, - 656,3,148,74,0,654,655,5,151,0,0,655,657,3,148,74,0,656,654,1,0,0,0,656, - 657,1,0,0,0,657,659,1,0,0,0,658,652,1,0,0,0,658,653,1,0,0,0,659,93,1, - 0,0,0,660,665,3,96,48,0,661,662,5,116,0,0,662,664,3,96,48,0,663,661,1, - 0,0,0,664,667,1,0,0,0,665,663,1,0,0,0,665,666,1,0,0,0,666,95,1,0,0,0, - 667,665,1,0,0,0,668,669,3,160,80,0,669,670,5,122,0,0,670,671,3,150,75, - 0,671,97,1,0,0,0,672,674,3,100,50,0,673,672,1,0,0,0,673,674,1,0,0,0,674, - 676,1,0,0,0,675,677,3,102,51,0,676,675,1,0,0,0,676,677,1,0,0,0,677,679, - 1,0,0,0,678,680,3,104,52,0,679,678,1,0,0,0,679,680,1,0,0,0,680,99,1,0, - 0,0,681,682,5,67,0,0,682,683,5,11,0,0,683,684,3,114,57,0,684,101,1,0, - 0,0,685,686,5,64,0,0,686,687,5,11,0,0,687,688,3,88,44,0,688,103,1,0,0, - 0,689,690,7,8,0,0,690,691,3,106,53,0,691,105,1,0,0,0,692,699,3,108,54, - 0,693,694,5,9,0,0,694,695,3,108,54,0,695,696,5,2,0,0,696,697,3,108,54, - 0,697,699,1,0,0,0,698,692,1,0,0,0,698,693,1,0,0,0,699,107,1,0,0,0,700, - 701,5,19,0,0,701,713,5,75,0,0,702,703,5,94,0,0,703,713,5,68,0,0,704,705, - 5,94,0,0,705,713,5,32,0,0,706,707,3,148,74,0,707,708,5,68,0,0,708,713, - 1,0,0,0,709,710,3,148,74,0,710,711,5,32,0,0,711,713,1,0,0,0,712,700,1, - 0,0,0,712,702,1,0,0,0,712,704,1,0,0,0,712,706,1,0,0,0,712,709,1,0,0,0, - 713,109,1,0,0,0,714,715,3,116,58,0,715,716,5,0,0,1,716,111,1,0,0,0,717, - 774,3,160,80,0,718,719,3,160,80,0,719,720,5,130,0,0,720,721,3,160,80, - 0,721,728,3,112,56,0,722,723,5,116,0,0,723,724,3,160,80,0,724,725,3,112, - 56,0,725,727,1,0,0,0,726,722,1,0,0,0,727,730,1,0,0,0,728,726,1,0,0,0, - 728,729,1,0,0,0,729,732,1,0,0,0,730,728,1,0,0,0,731,733,5,116,0,0,732, - 731,1,0,0,0,732,733,1,0,0,0,733,734,1,0,0,0,734,735,5,149,0,0,735,774, - 1,0,0,0,736,737,3,160,80,0,737,738,5,130,0,0,738,743,3,162,81,0,739,740, - 5,116,0,0,740,742,3,162,81,0,741,739,1,0,0,0,742,745,1,0,0,0,743,741, - 1,0,0,0,743,744,1,0,0,0,744,747,1,0,0,0,745,743,1,0,0,0,746,748,5,116, - 0,0,747,746,1,0,0,0,747,748,1,0,0,0,748,749,1,0,0,0,749,750,5,149,0,0, - 750,774,1,0,0,0,751,752,3,160,80,0,752,753,5,130,0,0,753,758,3,112,56, - 0,754,755,5,116,0,0,755,757,3,112,56,0,756,754,1,0,0,0,757,760,1,0,0, - 0,758,756,1,0,0,0,758,759,1,0,0,0,759,762,1,0,0,0,760,758,1,0,0,0,761, - 763,5,116,0,0,762,761,1,0,0,0,762,763,1,0,0,0,763,764,1,0,0,0,764,765, - 5,149,0,0,765,774,1,0,0,0,766,767,3,160,80,0,767,769,5,130,0,0,768,770, - 3,114,57,0,769,768,1,0,0,0,769,770,1,0,0,0,770,771,1,0,0,0,771,772,5, - 149,0,0,772,774,1,0,0,0,773,717,1,0,0,0,773,718,1,0,0,0,773,736,1,0,0, - 0,773,751,1,0,0,0,773,766,1,0,0,0,774,113,1,0,0,0,775,780,3,116,58,0, - 776,777,5,116,0,0,777,779,3,116,58,0,778,776,1,0,0,0,779,782,1,0,0,0, - 780,778,1,0,0,0,780,781,1,0,0,0,781,784,1,0,0,0,782,780,1,0,0,0,783,785, - 5,116,0,0,784,783,1,0,0,0,784,785,1,0,0,0,785,115,1,0,0,0,786,787,6,58, - -1,0,787,789,5,12,0,0,788,790,3,116,58,0,789,788,1,0,0,0,789,790,1,0, - 0,0,790,796,1,0,0,0,791,792,5,98,0,0,792,793,3,116,58,0,793,794,5,83, - 0,0,794,795,3,116,58,0,795,797,1,0,0,0,796,791,1,0,0,0,797,798,1,0,0, - 0,798,796,1,0,0,0,798,799,1,0,0,0,799,802,1,0,0,0,800,801,5,25,0,0,801, - 803,3,116,58,0,802,800,1,0,0,0,802,803,1,0,0,0,803,804,1,0,0,0,804,805, - 5,26,0,0,805,936,1,0,0,0,806,807,5,13,0,0,807,808,5,130,0,0,808,809,3, - 116,58,0,809,810,5,6,0,0,810,811,3,112,56,0,811,812,5,149,0,0,812,936, - 1,0,0,0,813,814,5,20,0,0,814,936,5,110,0,0,815,816,5,45,0,0,816,817,3, - 116,58,0,817,818,3,152,76,0,818,936,1,0,0,0,819,820,5,82,0,0,820,821, - 5,130,0,0,821,822,3,116,58,0,822,823,5,34,0,0,823,826,3,116,58,0,824, - 825,5,33,0,0,825,827,3,116,58,0,826,824,1,0,0,0,826,827,1,0,0,0,827,828, - 1,0,0,0,828,829,5,149,0,0,829,936,1,0,0,0,830,831,5,86,0,0,831,936,5, - 110,0,0,832,833,5,91,0,0,833,834,5,130,0,0,834,835,7,9,0,0,835,836,3, - 166,83,0,836,837,5,34,0,0,837,838,3,116,58,0,838,839,5,149,0,0,839,936, - 1,0,0,0,840,841,3,160,80,0,841,843,5,130,0,0,842,844,3,114,57,0,843,842, - 1,0,0,0,843,844,1,0,0,0,844,845,1,0,0,0,845,846,5,149,0,0,846,855,1,0, - 0,0,847,849,5,130,0,0,848,850,5,24,0,0,849,848,1,0,0,0,849,850,1,0,0, - 0,850,852,1,0,0,0,851,853,3,118,59,0,852,851,1,0,0,0,852,853,1,0,0,0, - 853,854,1,0,0,0,854,856,5,149,0,0,855,847,1,0,0,0,855,856,1,0,0,0,856, - 857,1,0,0,0,857,858,5,66,0,0,858,859,5,130,0,0,859,860,3,98,49,0,860, - 861,5,149,0,0,861,936,1,0,0,0,862,863,3,160,80,0,863,865,5,130,0,0,864, - 866,3,114,57,0,865,864,1,0,0,0,865,866,1,0,0,0,866,867,1,0,0,0,867,868, - 5,149,0,0,868,877,1,0,0,0,869,871,5,130,0,0,870,872,5,24,0,0,871,870, - 1,0,0,0,871,872,1,0,0,0,872,874,1,0,0,0,873,875,3,118,59,0,874,873,1, - 0,0,0,874,875,1,0,0,0,875,876,1,0,0,0,876,878,5,149,0,0,877,869,1,0,0, - 0,877,878,1,0,0,0,878,879,1,0,0,0,879,880,5,66,0,0,880,881,3,160,80,0, - 881,936,1,0,0,0,882,888,3,160,80,0,883,885,5,130,0,0,884,886,3,114,57, - 0,885,884,1,0,0,0,885,886,1,0,0,0,886,887,1,0,0,0,887,889,5,149,0,0,888, - 883,1,0,0,0,888,889,1,0,0,0,889,890,1,0,0,0,890,892,5,130,0,0,891,893, - 5,24,0,0,892,891,1,0,0,0,892,893,1,0,0,0,893,895,1,0,0,0,894,896,3,118, - 59,0,895,894,1,0,0,0,895,896,1,0,0,0,896,897,1,0,0,0,897,898,5,149,0, - 0,898,936,1,0,0,0,899,936,3,124,62,0,900,936,3,168,84,0,901,936,3,150, - 75,0,902,903,5,118,0,0,903,936,3,116,58,19,904,905,5,58,0,0,905,936,3, - 116,58,13,906,907,3,140,70,0,907,908,5,120,0,0,908,910,1,0,0,0,909,906, - 1,0,0,0,909,910,1,0,0,0,910,911,1,0,0,0,911,936,5,112,0,0,912,913,5,130, - 0,0,913,914,3,44,22,0,914,915,5,149,0,0,915,936,1,0,0,0,916,917,5,130, - 0,0,917,918,3,116,58,0,918,919,5,149,0,0,919,936,1,0,0,0,920,921,5,130, - 0,0,921,922,3,114,57,0,922,923,5,149,0,0,923,936,1,0,0,0,924,926,5,129, - 0,0,925,927,3,114,57,0,926,925,1,0,0,0,926,927,1,0,0,0,927,928,1,0,0, - 0,928,936,5,148,0,0,929,931,5,128,0,0,930,932,3,40,20,0,931,930,1,0,0, - 0,931,932,1,0,0,0,932,933,1,0,0,0,933,936,5,147,0,0,934,936,3,132,66, - 0,935,786,1,0,0,0,935,806,1,0,0,0,935,813,1,0,0,0,935,815,1,0,0,0,935, - 819,1,0,0,0,935,830,1,0,0,0,935,832,1,0,0,0,935,840,1,0,0,0,935,862,1, - 0,0,0,935,882,1,0,0,0,935,899,1,0,0,0,935,900,1,0,0,0,935,901,1,0,0,0, - 935,902,1,0,0,0,935,904,1,0,0,0,935,909,1,0,0,0,935,912,1,0,0,0,935,916, - 1,0,0,0,935,920,1,0,0,0,935,924,1,0,0,0,935,929,1,0,0,0,935,934,1,0,0, - 0,936,1041,1,0,0,0,937,941,10,18,0,0,938,942,5,112,0,0,939,942,5,151, - 0,0,940,942,5,138,0,0,941,938,1,0,0,0,941,939,1,0,0,0,941,940,1,0,0,0, - 942,943,1,0,0,0,943,1040,3,116,58,19,944,948,10,17,0,0,945,949,5,139, - 0,0,946,949,5,118,0,0,947,949,5,117,0,0,948,945,1,0,0,0,948,946,1,0,0, - 0,948,947,1,0,0,0,949,950,1,0,0,0,950,1040,3,116,58,18,951,976,10,16, - 0,0,952,977,5,121,0,0,953,977,5,122,0,0,954,977,5,133,0,0,955,977,5,131, - 0,0,956,977,5,132,0,0,957,977,5,123,0,0,958,977,5,124,0,0,959,961,5,58, - 0,0,960,959,1,0,0,0,960,961,1,0,0,0,961,962,1,0,0,0,962,964,5,42,0,0, - 963,965,5,15,0,0,964,963,1,0,0,0,964,965,1,0,0,0,965,977,1,0,0,0,966, - 968,5,58,0,0,967,966,1,0,0,0,967,968,1,0,0,0,968,969,1,0,0,0,969,977, - 7,10,0,0,970,977,5,145,0,0,971,977,5,146,0,0,972,977,5,135,0,0,973,977, - 5,126,0,0,974,977,5,127,0,0,975,977,5,134,0,0,976,952,1,0,0,0,976,953, - 1,0,0,0,976,954,1,0,0,0,976,955,1,0,0,0,976,956,1,0,0,0,976,957,1,0,0, - 0,976,958,1,0,0,0,976,960,1,0,0,0,976,967,1,0,0,0,976,970,1,0,0,0,976, - 971,1,0,0,0,976,972,1,0,0,0,976,973,1,0,0,0,976,974,1,0,0,0,976,975,1, - 0,0,0,977,978,1,0,0,0,978,1040,3,116,58,17,979,980,10,14,0,0,980,981, - 5,137,0,0,981,1040,3,116,58,15,982,983,10,12,0,0,983,984,5,2,0,0,984, - 1040,3,116,58,13,985,986,10,11,0,0,986,987,5,63,0,0,987,1040,3,116,58, - 12,988,990,10,10,0,0,989,991,5,58,0,0,990,989,1,0,0,0,990,991,1,0,0,0, - 991,992,1,0,0,0,992,993,5,9,0,0,993,994,3,116,58,0,994,995,5,2,0,0,995, - 996,3,116,58,11,996,1040,1,0,0,0,997,998,10,9,0,0,998,999,5,140,0,0,999, - 1000,3,116,58,0,1000,1001,5,115,0,0,1001,1002,3,116,58,9,1002,1040,1, - 0,0,0,1003,1004,10,25,0,0,1004,1005,5,129,0,0,1005,1006,3,116,58,0,1006, - 1007,5,148,0,0,1007,1040,1,0,0,0,1008,1009,10,24,0,0,1009,1010,5,120, - 0,0,1010,1040,5,108,0,0,1011,1012,10,23,0,0,1012,1013,5,120,0,0,1013, - 1040,3,160,80,0,1014,1015,10,22,0,0,1015,1016,5,136,0,0,1016,1017,5,129, - 0,0,1017,1018,3,116,58,0,1018,1019,5,148,0,0,1019,1040,1,0,0,0,1020,1021, - 10,21,0,0,1021,1022,5,136,0,0,1022,1040,5,108,0,0,1023,1024,10,20,0,0, - 1024,1025,5,136,0,0,1025,1040,3,160,80,0,1026,1027,10,15,0,0,1027,1029, - 5,46,0,0,1028,1030,5,58,0,0,1029,1028,1,0,0,0,1029,1030,1,0,0,0,1030, - 1031,1,0,0,0,1031,1040,5,59,0,0,1032,1037,10,8,0,0,1033,1034,5,6,0,0, - 1034,1038,3,160,80,0,1035,1036,5,6,0,0,1036,1038,5,110,0,0,1037,1033, - 1,0,0,0,1037,1035,1,0,0,0,1038,1040,1,0,0,0,1039,937,1,0,0,0,1039,944, - 1,0,0,0,1039,951,1,0,0,0,1039,979,1,0,0,0,1039,982,1,0,0,0,1039,985,1, - 0,0,0,1039,988,1,0,0,0,1039,997,1,0,0,0,1039,1003,1,0,0,0,1039,1008,1, - 0,0,0,1039,1011,1,0,0,0,1039,1014,1,0,0,0,1039,1020,1,0,0,0,1039,1023, - 1,0,0,0,1039,1026,1,0,0,0,1039,1032,1,0,0,0,1040,1043,1,0,0,0,1041,1039, - 1,0,0,0,1041,1042,1,0,0,0,1042,117,1,0,0,0,1043,1041,1,0,0,0,1044,1049, - 3,120,60,0,1045,1046,5,116,0,0,1046,1048,3,120,60,0,1047,1045,1,0,0,0, - 1048,1051,1,0,0,0,1049,1047,1,0,0,0,1049,1050,1,0,0,0,1050,1053,1,0,0, - 0,1051,1049,1,0,0,0,1052,1054,5,116,0,0,1053,1052,1,0,0,0,1053,1054,1, - 0,0,0,1054,119,1,0,0,0,1055,1058,3,122,61,0,1056,1058,3,116,58,0,1057, - 1055,1,0,0,0,1057,1056,1,0,0,0,1058,121,1,0,0,0,1059,1060,5,130,0,0,1060, - 1065,3,160,80,0,1061,1062,5,116,0,0,1062,1064,3,160,80,0,1063,1061,1, - 0,0,0,1064,1067,1,0,0,0,1065,1063,1,0,0,0,1065,1066,1,0,0,0,1066,1069, - 1,0,0,0,1067,1065,1,0,0,0,1068,1070,5,116,0,0,1069,1068,1,0,0,0,1069, - 1070,1,0,0,0,1070,1071,1,0,0,0,1071,1072,5,149,0,0,1072,1085,1,0,0,0, - 1073,1078,3,160,80,0,1074,1075,5,116,0,0,1075,1077,3,160,80,0,1076,1074, - 1,0,0,0,1077,1080,1,0,0,0,1078,1076,1,0,0,0,1078,1079,1,0,0,0,1079,1082, - 1,0,0,0,1080,1078,1,0,0,0,1081,1083,5,116,0,0,1082,1081,1,0,0,0,1082, - 1083,1,0,0,0,1083,1085,1,0,0,0,1084,1059,1,0,0,0,1084,1073,1,0,0,0,1085, - 1086,1,0,0,0,1086,1087,5,111,0,0,1087,1088,3,116,58,0,1088,123,1,0,0, - 0,1089,1090,5,132,0,0,1090,1094,3,160,80,0,1091,1093,3,126,63,0,1092, - 1091,1,0,0,0,1093,1096,1,0,0,0,1094,1092,1,0,0,0,1094,1095,1,0,0,0,1095, - 1097,1,0,0,0,1096,1094,1,0,0,0,1097,1098,5,151,0,0,1098,1099,5,124,0, - 0,1099,1118,1,0,0,0,1100,1101,5,132,0,0,1101,1105,3,160,80,0,1102,1104, - 3,126,63,0,1103,1102,1,0,0,0,1104,1107,1,0,0,0,1105,1103,1,0,0,0,1105, - 1106,1,0,0,0,1106,1108,1,0,0,0,1107,1105,1,0,0,0,1108,1110,5,124,0,0, - 1109,1111,3,124,62,0,1110,1109,1,0,0,0,1110,1111,1,0,0,0,1111,1112,1, - 0,0,0,1112,1113,5,132,0,0,1113,1114,5,151,0,0,1114,1115,3,160,80,0,1115, - 1116,5,124,0,0,1116,1118,1,0,0,0,1117,1089,1,0,0,0,1117,1100,1,0,0,0, - 1118,125,1,0,0,0,1119,1120,3,160,80,0,1120,1121,5,122,0,0,1121,1122,3, - 166,83,0,1122,1131,1,0,0,0,1123,1124,3,160,80,0,1124,1125,5,122,0,0,1125, - 1126,5,128,0,0,1126,1127,3,116,58,0,1127,1128,5,147,0,0,1128,1131,1,0, - 0,0,1129,1131,3,160,80,0,1130,1119,1,0,0,0,1130,1123,1,0,0,0,1130,1129, - 1,0,0,0,1131,127,1,0,0,0,1132,1137,3,130,65,0,1133,1134,5,116,0,0,1134, - 1136,3,130,65,0,1135,1133,1,0,0,0,1136,1139,1,0,0,0,1137,1135,1,0,0,0, - 1137,1138,1,0,0,0,1138,1141,1,0,0,0,1139,1137,1,0,0,0,1140,1142,5,116, - 0,0,1141,1140,1,0,0,0,1141,1142,1,0,0,0,1142,129,1,0,0,0,1143,1144,3, - 160,80,0,1144,1145,5,6,0,0,1145,1146,5,130,0,0,1146,1147,3,44,22,0,1147, - 1148,5,149,0,0,1148,1154,1,0,0,0,1149,1150,3,116,58,0,1150,1151,5,6,0, - 0,1151,1152,3,160,80,0,1152,1154,1,0,0,0,1153,1143,1,0,0,0,1153,1149, - 1,0,0,0,1154,131,1,0,0,0,1155,1163,3,164,82,0,1156,1157,3,140,70,0,1157, - 1158,5,120,0,0,1158,1160,1,0,0,0,1159,1156,1,0,0,0,1159,1160,1,0,0,0, - 1160,1161,1,0,0,0,1161,1163,3,134,67,0,1162,1155,1,0,0,0,1162,1159,1, - 0,0,0,1163,133,1,0,0,0,1164,1169,3,160,80,0,1165,1166,5,120,0,0,1166, - 1168,3,160,80,0,1167,1165,1,0,0,0,1168,1171,1,0,0,0,1169,1167,1,0,0,0, - 1169,1170,1,0,0,0,1170,135,1,0,0,0,1171,1169,1,0,0,0,1172,1173,6,68,-1, - 0,1173,1182,3,140,70,0,1174,1182,3,138,69,0,1175,1176,5,130,0,0,1176, - 1177,3,44,22,0,1177,1178,5,149,0,0,1178,1182,1,0,0,0,1179,1182,3,124, - 62,0,1180,1182,3,164,82,0,1181,1172,1,0,0,0,1181,1174,1,0,0,0,1181,1175, - 1,0,0,0,1181,1179,1,0,0,0,1181,1180,1,0,0,0,1182,1191,1,0,0,0,1183,1187, - 10,3,0,0,1184,1188,3,158,79,0,1185,1186,5,6,0,0,1186,1188,3,160,80,0, - 1187,1184,1,0,0,0,1187,1185,1,0,0,0,1188,1190,1,0,0,0,1189,1183,1,0,0, - 0,1190,1193,1,0,0,0,1191,1189,1,0,0,0,1191,1192,1,0,0,0,1192,137,1,0, - 0,0,1193,1191,1,0,0,0,1194,1195,3,160,80,0,1195,1197,5,130,0,0,1196,1198, - 3,142,71,0,1197,1196,1,0,0,0,1197,1198,1,0,0,0,1198,1199,1,0,0,0,1199, - 1200,5,149,0,0,1200,139,1,0,0,0,1201,1202,3,144,72,0,1202,1203,5,120, - 0,0,1203,1205,1,0,0,0,1204,1201,1,0,0,0,1204,1205,1,0,0,0,1205,1206,1, - 0,0,0,1206,1207,3,160,80,0,1207,141,1,0,0,0,1208,1213,3,116,58,0,1209, - 1210,5,116,0,0,1210,1212,3,116,58,0,1211,1209,1,0,0,0,1212,1215,1,0,0, - 0,1213,1211,1,0,0,0,1213,1214,1,0,0,0,1214,1217,1,0,0,0,1215,1213,1,0, - 0,0,1216,1218,5,116,0,0,1217,1216,1,0,0,0,1217,1218,1,0,0,0,1218,143, - 1,0,0,0,1219,1220,3,160,80,0,1220,145,1,0,0,0,1221,1230,5,106,0,0,1222, - 1223,5,120,0,0,1223,1230,7,11,0,0,1224,1225,5,108,0,0,1225,1227,5,120, - 0,0,1226,1228,7,11,0,0,1227,1226,1,0,0,0,1227,1228,1,0,0,0,1228,1230, - 1,0,0,0,1229,1221,1,0,0,0,1229,1222,1,0,0,0,1229,1224,1,0,0,0,1230,147, - 1,0,0,0,1231,1233,7,12,0,0,1232,1231,1,0,0,0,1232,1233,1,0,0,0,1233,1240, - 1,0,0,0,1234,1241,3,146,73,0,1235,1241,5,107,0,0,1236,1241,5,108,0,0, - 1237,1241,5,109,0,0,1238,1241,5,43,0,0,1239,1241,5,57,0,0,1240,1234,1, - 0,0,0,1240,1235,1,0,0,0,1240,1236,1,0,0,0,1240,1237,1,0,0,0,1240,1238, - 1,0,0,0,1240,1239,1,0,0,0,1241,149,1,0,0,0,1242,1246,3,148,74,0,1243, - 1246,5,110,0,0,1244,1246,5,59,0,0,1245,1242,1,0,0,0,1245,1243,1,0,0,0, - 1245,1244,1,0,0,0,1246,151,1,0,0,0,1247,1248,7,13,0,0,1248,153,1,0,0, - 0,1249,1250,7,14,0,0,1250,155,1,0,0,0,1251,1252,7,15,0,0,1252,157,1,0, - 0,0,1253,1256,5,105,0,0,1254,1256,3,156,78,0,1255,1253,1,0,0,0,1255,1254, - 1,0,0,0,1256,159,1,0,0,0,1257,1261,5,105,0,0,1258,1261,3,152,76,0,1259, - 1261,3,154,77,0,1260,1257,1,0,0,0,1260,1258,1,0,0,0,1260,1259,1,0,0,0, - 1261,161,1,0,0,0,1262,1263,3,166,83,0,1263,1264,5,122,0,0,1264,1265,3, - 148,74,0,1265,163,1,0,0,0,1266,1267,5,128,0,0,1267,1268,3,160,80,0,1268, - 1269,5,147,0,0,1269,165,1,0,0,0,1270,1273,5,110,0,0,1271,1273,3,168,84, - 0,1272,1270,1,0,0,0,1272,1271,1,0,0,0,1273,167,1,0,0,0,1274,1278,5,142, - 0,0,1275,1277,3,170,85,0,1276,1275,1,0,0,0,1277,1280,1,0,0,0,1278,1276, - 1,0,0,0,1278,1279,1,0,0,0,1279,1281,1,0,0,0,1280,1278,1,0,0,0,1281,1282, - 5,144,0,0,1282,169,1,0,0,0,1283,1284,5,157,0,0,1284,1285,3,116,58,0,1285, - 1286,5,147,0,0,1286,1289,1,0,0,0,1287,1289,5,156,0,0,1288,1283,1,0,0, - 0,1288,1287,1,0,0,0,1289,171,1,0,0,0,1290,1294,5,143,0,0,1291,1293,3, - 174,87,0,1292,1291,1,0,0,0,1293,1296,1,0,0,0,1294,1292,1,0,0,0,1294,1295, - 1,0,0,0,1295,1297,1,0,0,0,1296,1294,1,0,0,0,1297,1298,5,0,0,1,1298,173, - 1,0,0,0,1299,1300,5,159,0,0,1300,1301,3,116,58,0,1301,1302,5,147,0,0, - 1302,1305,1,0,0,0,1303,1305,5,158,0,0,1304,1299,1,0,0,0,1304,1303,1,0, - 0,0,1305,175,1,0,0,0,168,179,186,195,202,206,220,224,227,231,234,241, - 245,254,259,268,276,283,287,293,298,306,313,319,331,339,353,357,362,372, - 381,384,388,391,395,398,401,404,407,411,415,418,421,424,428,431,440,446, - 467,484,501,507,513,524,526,537,540,546,554,560,562,566,571,574,577,581, - 585,588,590,593,597,601,604,606,608,613,624,630,637,642,646,650,656,658, - 665,673,676,679,698,712,728,732,743,747,758,762,769,773,780,784,789,798, - 802,826,843,849,852,855,865,871,874,877,885,888,892,895,909,926,931,935, - 941,948,960,964,967,976,990,1029,1037,1039,1041,1049,1053,1057,1065,1069, - 1078,1082,1084,1094,1105,1110,1117,1130,1137,1141,1153,1159,1162,1169, - 1181,1187,1191,1197,1204,1213,1217,1227,1229,1232,1240,1245,1255,1260, - 1272,1278,1288,1294,1304 + 1,62,1,62,1,62,1,62,5,62,1104,8,62,10,62,12,62,1107,9,62,1,62,1,62,1, + 62,1,62,1,62,1,62,3,62,1115,8,62,1,62,1,62,1,62,1,62,1,62,3,62,1122,8, + 62,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,3,63,1135,8, + 63,1,64,1,64,1,64,5,64,1140,8,64,10,64,12,64,1143,9,64,1,64,3,64,1146, + 8,64,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,3,65,1158,8,65, + 1,66,1,66,1,66,1,66,3,66,1164,8,66,1,66,3,66,1167,8,66,1,67,1,67,1,67, + 5,67,1172,8,67,10,67,12,67,1175,9,67,1,68,1,68,1,68,1,68,1,68,1,68,1, + 68,1,68,1,68,3,68,1186,8,68,1,68,1,68,1,68,1,68,3,68,1192,8,68,5,68,1194, + 8,68,10,68,12,68,1197,9,68,1,69,1,69,1,69,3,69,1202,8,69,1,69,1,69,1, + 70,1,70,1,70,3,70,1209,8,70,1,70,1,70,1,71,1,71,1,71,5,71,1216,8,71,10, + 71,12,71,1219,9,71,1,71,3,71,1222,8,71,1,72,1,72,1,73,1,73,1,73,1,73, + 1,73,1,73,3,73,1232,8,73,3,73,1234,8,73,1,74,3,74,1237,8,74,1,74,1,74, + 1,74,1,74,1,74,1,74,3,74,1245,8,74,1,75,1,75,1,75,3,75,1250,8,75,1,76, + 1,76,1,77,1,77,1,78,1,78,1,79,1,79,3,79,1260,8,79,1,80,1,80,1,80,3,80, + 1265,8,80,1,81,1,81,1,81,1,81,1,82,1,82,1,82,1,82,1,83,1,83,3,83,1277, + 8,83,1,84,1,84,5,84,1281,8,84,10,84,12,84,1284,9,84,1,84,1,84,1,85,1, + 85,1,85,1,85,1,85,3,85,1293,8,85,1,86,1,86,5,86,1297,8,86,10,86,12,86, + 1300,9,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87,3,87,1309,8,87,1,87,0,3, + 78,116,136,88,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38, + 40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84, + 86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122, + 124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158, + 160,162,164,166,168,170,172,174,0,16,2,0,18,18,74,74,2,0,44,44,51,51, + 3,0,1,1,4,4,8,8,4,0,1,1,3,4,8,8,80,80,2,0,51,51,73,73,2,0,1,1,4,4,2,0, + 7,7,22,23,2,0,30,30,49,49,2,0,71,71,76,76,3,0,10,10,50,50,90,90,2,0,41, + 41,53,53,1,0,107,108,2,0,118,118,139,139,7,0,21,21,38,38,55,56,70,70, + 78,78,97,97,103,103,16,0,1,13,15,20,22,28,30,30,32,37,39,42,44,51,53, + 54,58,58,60,69,71,77,79,83,85,92,94,96,98,99,101,102,4,0,20,20,30,30, + 39,39,48,48,1479,0,179,1,0,0,0,2,186,1,0,0,0,4,188,1,0,0,0,6,190,1,0, + 0,0,8,197,1,0,0,0,10,220,1,0,0,0,12,222,1,0,0,0,14,229,1,0,0,0,16,236, + 1,0,0,0,18,249,1,0,0,0,20,261,1,0,0,0,22,270,1,0,0,0,24,278,1,0,0,0,26, + 300,1,0,0,0,28,315,1,0,0,0,30,324,1,0,0,0,32,329,1,0,0,0,34,333,1,0,0, + 0,36,335,1,0,0,0,38,344,1,0,0,0,40,348,1,0,0,0,42,362,1,0,0,0,44,366, + 1,0,0,0,46,381,1,0,0,0,48,384,1,0,0,0,50,433,1,0,0,0,52,436,1,0,0,0,54, + 442,1,0,0,0,56,446,1,0,0,0,58,452,1,0,0,0,60,470,1,0,0,0,62,473,1,0,0, + 0,64,476,1,0,0,0,66,486,1,0,0,0,68,489,1,0,0,0,70,493,1,0,0,0,72,526, + 1,0,0,0,74,528,1,0,0,0,76,531,1,0,0,0,78,546,1,0,0,0,80,608,1,0,0,0,82, + 613,1,0,0,0,84,624,1,0,0,0,86,626,1,0,0,0,88,632,1,0,0,0,90,640,1,0,0, + 0,92,658,1,0,0,0,94,660,1,0,0,0,96,668,1,0,0,0,98,673,1,0,0,0,100,681, + 1,0,0,0,102,685,1,0,0,0,104,689,1,0,0,0,106,698,1,0,0,0,108,712,1,0,0, + 0,110,714,1,0,0,0,112,773,1,0,0,0,114,775,1,0,0,0,116,935,1,0,0,0,118, + 1044,1,0,0,0,120,1057,1,0,0,0,122,1084,1,0,0,0,124,1121,1,0,0,0,126,1134, + 1,0,0,0,128,1136,1,0,0,0,130,1157,1,0,0,0,132,1166,1,0,0,0,134,1168,1, + 0,0,0,136,1185,1,0,0,0,138,1198,1,0,0,0,140,1208,1,0,0,0,142,1212,1,0, + 0,0,144,1223,1,0,0,0,146,1233,1,0,0,0,148,1236,1,0,0,0,150,1249,1,0,0, + 0,152,1251,1,0,0,0,154,1253,1,0,0,0,156,1255,1,0,0,0,158,1259,1,0,0,0, + 160,1264,1,0,0,0,162,1266,1,0,0,0,164,1270,1,0,0,0,166,1276,1,0,0,0,168, + 1278,1,0,0,0,170,1292,1,0,0,0,172,1294,1,0,0,0,174,1308,1,0,0,0,176,178, + 3,2,1,0,177,176,1,0,0,0,178,181,1,0,0,0,179,177,1,0,0,0,179,180,1,0,0, + 0,180,182,1,0,0,0,181,179,1,0,0,0,182,183,5,0,0,1,183,1,1,0,0,0,184,187, + 3,6,3,0,185,187,3,10,5,0,186,184,1,0,0,0,186,185,1,0,0,0,187,3,1,0,0, + 0,188,189,3,116,58,0,189,5,1,0,0,0,190,191,5,52,0,0,191,195,3,160,80, + 0,192,193,5,115,0,0,193,194,5,122,0,0,194,196,3,4,2,0,195,192,1,0,0,0, + 195,196,1,0,0,0,196,7,1,0,0,0,197,202,3,160,80,0,198,199,5,116,0,0,199, + 201,3,160,80,0,200,198,1,0,0,0,201,204,1,0,0,0,202,200,1,0,0,0,202,203, + 1,0,0,0,203,206,1,0,0,0,204,202,1,0,0,0,205,207,5,116,0,0,206,205,1,0, + 0,0,206,207,1,0,0,0,207,9,1,0,0,0,208,221,3,12,6,0,209,221,3,14,7,0,210, + 221,3,18,9,0,211,221,3,20,10,0,212,221,3,22,11,0,213,221,3,26,13,0,214, + 221,3,24,12,0,215,221,3,28,14,0,216,221,3,30,15,0,217,221,3,36,18,0,218, + 221,3,32,16,0,219,221,3,34,17,0,220,208,1,0,0,0,220,209,1,0,0,0,220,210, + 1,0,0,0,220,211,1,0,0,0,220,212,1,0,0,0,220,213,1,0,0,0,220,214,1,0,0, + 0,220,215,1,0,0,0,220,216,1,0,0,0,220,217,1,0,0,0,220,218,1,0,0,0,220, + 219,1,0,0,0,221,11,1,0,0,0,222,224,5,72,0,0,223,225,3,4,2,0,224,223,1, + 0,0,0,224,225,1,0,0,0,225,227,1,0,0,0,226,228,5,150,0,0,227,226,1,0,0, + 0,227,228,1,0,0,0,228,13,1,0,0,0,229,231,5,84,0,0,230,232,3,4,2,0,231, + 230,1,0,0,0,231,232,1,0,0,0,232,234,1,0,0,0,233,235,5,150,0,0,234,233, + 1,0,0,0,234,235,1,0,0,0,235,15,1,0,0,0,236,245,5,14,0,0,237,238,5,130, + 0,0,238,241,3,160,80,0,239,240,5,115,0,0,240,242,3,160,80,0,241,239,1, + 0,0,0,241,242,1,0,0,0,242,243,1,0,0,0,243,244,5,149,0,0,244,246,1,0,0, + 0,245,237,1,0,0,0,245,246,1,0,0,0,246,247,1,0,0,0,247,248,3,36,18,0,248, + 17,1,0,0,0,249,250,5,93,0,0,250,254,3,36,18,0,251,253,3,16,8,0,252,251, + 1,0,0,0,253,256,1,0,0,0,254,252,1,0,0,0,254,255,1,0,0,0,255,259,1,0,0, + 0,256,254,1,0,0,0,257,258,5,29,0,0,258,260,3,36,18,0,259,257,1,0,0,0, + 259,260,1,0,0,0,260,19,1,0,0,0,261,262,5,40,0,0,262,263,5,130,0,0,263, + 264,3,4,2,0,264,265,5,149,0,0,265,268,3,10,5,0,266,267,5,25,0,0,267,269, + 3,10,5,0,268,266,1,0,0,0,268,269,1,0,0,0,269,21,1,0,0,0,270,271,5,100, + 0,0,271,272,5,130,0,0,272,273,3,4,2,0,273,274,5,149,0,0,274,276,3,10, + 5,0,275,277,5,150,0,0,276,275,1,0,0,0,276,277,1,0,0,0,277,23,1,0,0,0, + 278,279,5,33,0,0,279,283,5,130,0,0,280,284,3,6,3,0,281,284,3,30,15,0, + 282,284,3,4,2,0,283,280,1,0,0,0,283,281,1,0,0,0,283,282,1,0,0,0,283,284, + 1,0,0,0,284,285,1,0,0,0,285,287,5,150,0,0,286,288,3,4,2,0,287,286,1,0, + 0,0,287,288,1,0,0,0,288,289,1,0,0,0,289,293,5,150,0,0,290,294,3,6,3,0, + 291,294,3,30,15,0,292,294,3,4,2,0,293,290,1,0,0,0,293,291,1,0,0,0,293, + 292,1,0,0,0,293,294,1,0,0,0,294,295,1,0,0,0,295,296,5,149,0,0,296,298, + 3,10,5,0,297,299,5,150,0,0,298,297,1,0,0,0,298,299,1,0,0,0,299,25,1,0, + 0,0,300,301,5,33,0,0,301,302,5,130,0,0,302,303,5,52,0,0,303,306,3,160, + 80,0,304,305,5,116,0,0,305,307,3,160,80,0,306,304,1,0,0,0,306,307,1,0, + 0,0,307,308,1,0,0,0,308,309,5,42,0,0,309,310,3,4,2,0,310,311,5,149,0, + 0,311,313,3,10,5,0,312,314,5,150,0,0,313,312,1,0,0,0,313,314,1,0,0,0, + 314,27,1,0,0,0,315,316,5,31,0,0,316,317,3,160,80,0,317,319,5,130,0,0, + 318,320,3,8,4,0,319,318,1,0,0,0,319,320,1,0,0,0,320,321,1,0,0,0,321,322, + 5,149,0,0,322,323,3,36,18,0,323,29,1,0,0,0,324,325,3,4,2,0,325,326,5, + 115,0,0,326,327,5,122,0,0,327,328,3,4,2,0,328,31,1,0,0,0,329,331,3,4, + 2,0,330,332,5,150,0,0,331,330,1,0,0,0,331,332,1,0,0,0,332,33,1,0,0,0, + 333,334,5,150,0,0,334,35,1,0,0,0,335,339,5,128,0,0,336,338,3,2,1,0,337, + 336,1,0,0,0,338,341,1,0,0,0,339,337,1,0,0,0,339,340,1,0,0,0,340,342,1, + 0,0,0,341,339,1,0,0,0,342,343,5,147,0,0,343,37,1,0,0,0,344,345,3,4,2, + 0,345,346,5,115,0,0,346,347,3,4,2,0,347,39,1,0,0,0,348,353,3,38,19,0, + 349,350,5,116,0,0,350,352,3,38,19,0,351,349,1,0,0,0,352,355,1,0,0,0,353, + 351,1,0,0,0,353,354,1,0,0,0,354,357,1,0,0,0,355,353,1,0,0,0,356,358,5, + 116,0,0,357,356,1,0,0,0,357,358,1,0,0,0,358,41,1,0,0,0,359,363,3,44,22, + 0,360,363,3,48,24,0,361,363,3,124,62,0,362,359,1,0,0,0,362,360,1,0,0, + 0,362,361,1,0,0,0,363,364,1,0,0,0,364,365,5,0,0,1,365,43,1,0,0,0,366, + 372,3,46,23,0,367,368,5,95,0,0,368,369,5,1,0,0,369,371,3,46,23,0,370, + 367,1,0,0,0,371,374,1,0,0,0,372,370,1,0,0,0,372,373,1,0,0,0,373,45,1, + 0,0,0,374,372,1,0,0,0,375,382,3,48,24,0,376,377,5,130,0,0,377,378,3,44, + 22,0,378,379,5,149,0,0,379,382,1,0,0,0,380,382,3,164,82,0,381,375,1,0, + 0,0,381,376,1,0,0,0,381,380,1,0,0,0,382,47,1,0,0,0,383,385,3,50,25,0, + 384,383,1,0,0,0,384,385,1,0,0,0,385,386,1,0,0,0,386,388,5,79,0,0,387, + 389,5,24,0,0,388,387,1,0,0,0,388,389,1,0,0,0,389,391,1,0,0,0,390,392, + 3,52,26,0,391,390,1,0,0,0,391,392,1,0,0,0,392,393,1,0,0,0,393,395,3,114, + 57,0,394,396,3,54,27,0,395,394,1,0,0,0,395,396,1,0,0,0,396,398,1,0,0, + 0,397,399,3,56,28,0,398,397,1,0,0,0,398,399,1,0,0,0,399,401,1,0,0,0,400, + 402,3,60,30,0,401,400,1,0,0,0,401,402,1,0,0,0,402,404,1,0,0,0,403,405, + 3,62,31,0,404,403,1,0,0,0,404,405,1,0,0,0,405,407,1,0,0,0,406,408,3,64, + 32,0,407,406,1,0,0,0,407,408,1,0,0,0,408,411,1,0,0,0,409,410,5,102,0, + 0,410,412,7,0,0,0,411,409,1,0,0,0,411,412,1,0,0,0,412,415,1,0,0,0,413, + 414,5,102,0,0,414,416,5,89,0,0,415,413,1,0,0,0,415,416,1,0,0,0,416,418, + 1,0,0,0,417,419,3,66,33,0,418,417,1,0,0,0,418,419,1,0,0,0,419,421,1,0, + 0,0,420,422,3,58,29,0,421,420,1,0,0,0,421,422,1,0,0,0,422,424,1,0,0,0, + 423,425,3,68,34,0,424,423,1,0,0,0,424,425,1,0,0,0,425,428,1,0,0,0,426, + 429,3,72,36,0,427,429,3,74,37,0,428,426,1,0,0,0,428,427,1,0,0,0,428,429, + 1,0,0,0,429,431,1,0,0,0,430,432,3,76,38,0,431,430,1,0,0,0,431,432,1,0, + 0,0,432,49,1,0,0,0,433,434,5,102,0,0,434,435,3,128,64,0,435,51,1,0,0, + 0,436,437,5,88,0,0,437,440,5,108,0,0,438,439,5,102,0,0,439,441,5,85,0, + 0,440,438,1,0,0,0,440,441,1,0,0,0,441,53,1,0,0,0,442,443,5,34,0,0,443, + 444,3,78,39,0,444,55,1,0,0,0,445,447,7,1,0,0,446,445,1,0,0,0,446,447, + 1,0,0,0,447,448,1,0,0,0,448,449,5,5,0,0,449,450,5,47,0,0,450,451,3,114, + 57,0,451,57,1,0,0,0,452,453,5,101,0,0,453,454,3,160,80,0,454,455,5,6, + 0,0,455,456,5,130,0,0,456,457,3,98,49,0,457,467,5,149,0,0,458,459,5,116, + 0,0,459,460,3,160,80,0,460,461,5,6,0,0,461,462,5,130,0,0,462,463,3,98, + 49,0,463,464,5,149,0,0,464,466,1,0,0,0,465,458,1,0,0,0,466,469,1,0,0, + 0,467,465,1,0,0,0,467,468,1,0,0,0,468,59,1,0,0,0,469,467,1,0,0,0,470, + 471,5,69,0,0,471,472,3,116,58,0,472,61,1,0,0,0,473,474,5,99,0,0,474,475, + 3,116,58,0,475,63,1,0,0,0,476,477,5,36,0,0,477,484,5,11,0,0,478,479,7, + 0,0,0,479,480,5,130,0,0,480,481,3,114,57,0,481,482,5,149,0,0,482,485, + 1,0,0,0,483,485,3,114,57,0,484,478,1,0,0,0,484,483,1,0,0,0,485,65,1,0, + 0,0,486,487,5,37,0,0,487,488,3,116,58,0,488,67,1,0,0,0,489,490,5,64,0, + 0,490,491,5,11,0,0,491,492,3,88,44,0,492,69,1,0,0,0,493,494,5,64,0,0, + 494,495,5,11,0,0,495,496,3,114,57,0,496,71,1,0,0,0,497,498,5,54,0,0,498, + 501,3,116,58,0,499,500,5,116,0,0,500,502,3,116,58,0,501,499,1,0,0,0,501, + 502,1,0,0,0,502,507,1,0,0,0,503,504,5,102,0,0,504,508,5,85,0,0,505,506, + 5,11,0,0,506,508,3,114,57,0,507,503,1,0,0,0,507,505,1,0,0,0,507,508,1, + 0,0,0,508,527,1,0,0,0,509,510,5,54,0,0,510,513,3,116,58,0,511,512,5,102, + 0,0,512,514,5,85,0,0,513,511,1,0,0,0,513,514,1,0,0,0,514,515,1,0,0,0, + 515,516,5,61,0,0,516,517,3,116,58,0,517,527,1,0,0,0,518,519,5,54,0,0, + 519,520,3,116,58,0,520,521,5,61,0,0,521,524,3,116,58,0,522,523,5,11,0, + 0,523,525,3,114,57,0,524,522,1,0,0,0,524,525,1,0,0,0,525,527,1,0,0,0, + 526,497,1,0,0,0,526,509,1,0,0,0,526,518,1,0,0,0,527,73,1,0,0,0,528,529, + 5,61,0,0,529,530,3,116,58,0,530,75,1,0,0,0,531,532,5,81,0,0,532,533,3, + 94,47,0,533,77,1,0,0,0,534,535,6,39,-1,0,535,537,3,136,68,0,536,538,5, + 28,0,0,537,536,1,0,0,0,537,538,1,0,0,0,538,540,1,0,0,0,539,541,3,86,43, + 0,540,539,1,0,0,0,540,541,1,0,0,0,541,547,1,0,0,0,542,543,5,130,0,0,543, + 544,3,78,39,0,544,545,5,149,0,0,545,547,1,0,0,0,546,534,1,0,0,0,546,542, + 1,0,0,0,547,562,1,0,0,0,548,549,10,3,0,0,549,550,3,82,41,0,550,551,3, + 78,39,4,551,561,1,0,0,0,552,554,10,4,0,0,553,555,3,80,40,0,554,553,1, + 0,0,0,554,555,1,0,0,0,555,556,1,0,0,0,556,557,5,47,0,0,557,558,3,78,39, + 0,558,559,3,84,42,0,559,561,1,0,0,0,560,548,1,0,0,0,560,552,1,0,0,0,561, + 564,1,0,0,0,562,560,1,0,0,0,562,563,1,0,0,0,563,79,1,0,0,0,564,562,1, + 0,0,0,565,567,7,2,0,0,566,565,1,0,0,0,566,567,1,0,0,0,567,568,1,0,0,0, + 568,575,5,44,0,0,569,571,5,44,0,0,570,572,7,2,0,0,571,570,1,0,0,0,571, + 572,1,0,0,0,572,575,1,0,0,0,573,575,7,2,0,0,574,566,1,0,0,0,574,569,1, + 0,0,0,574,573,1,0,0,0,575,609,1,0,0,0,576,578,7,3,0,0,577,576,1,0,0,0, + 577,578,1,0,0,0,578,579,1,0,0,0,579,581,7,4,0,0,580,582,5,65,0,0,581, + 580,1,0,0,0,581,582,1,0,0,0,582,591,1,0,0,0,583,585,7,4,0,0,584,586,5, + 65,0,0,585,584,1,0,0,0,585,586,1,0,0,0,586,588,1,0,0,0,587,589,7,3,0, + 0,588,587,1,0,0,0,588,589,1,0,0,0,589,591,1,0,0,0,590,577,1,0,0,0,590, + 583,1,0,0,0,591,609,1,0,0,0,592,594,7,5,0,0,593,592,1,0,0,0,593,594,1, + 0,0,0,594,595,1,0,0,0,595,597,5,35,0,0,596,598,5,65,0,0,597,596,1,0,0, + 0,597,598,1,0,0,0,598,607,1,0,0,0,599,601,5,35,0,0,600,602,5,65,0,0,601, + 600,1,0,0,0,601,602,1,0,0,0,602,604,1,0,0,0,603,605,7,5,0,0,604,603,1, + 0,0,0,604,605,1,0,0,0,605,607,1,0,0,0,606,593,1,0,0,0,606,599,1,0,0,0, + 607,609,1,0,0,0,608,574,1,0,0,0,608,590,1,0,0,0,608,606,1,0,0,0,609,81, + 1,0,0,0,610,611,5,17,0,0,611,614,5,47,0,0,612,614,5,116,0,0,613,610,1, + 0,0,0,613,612,1,0,0,0,614,83,1,0,0,0,615,616,5,62,0,0,616,625,3,114,57, + 0,617,618,5,96,0,0,618,619,5,130,0,0,619,620,3,114,57,0,620,621,5,149, + 0,0,621,625,1,0,0,0,622,623,5,96,0,0,623,625,3,114,57,0,624,615,1,0,0, + 0,624,617,1,0,0,0,624,622,1,0,0,0,625,85,1,0,0,0,626,627,5,77,0,0,627, + 630,3,92,46,0,628,629,5,61,0,0,629,631,3,92,46,0,630,628,1,0,0,0,630, + 631,1,0,0,0,631,87,1,0,0,0,632,637,3,90,45,0,633,634,5,116,0,0,634,636, + 3,90,45,0,635,633,1,0,0,0,636,639,1,0,0,0,637,635,1,0,0,0,637,638,1,0, + 0,0,638,89,1,0,0,0,639,637,1,0,0,0,640,642,3,116,58,0,641,643,7,6,0,0, + 642,641,1,0,0,0,642,643,1,0,0,0,643,646,1,0,0,0,644,645,5,60,0,0,645, + 647,7,7,0,0,646,644,1,0,0,0,646,647,1,0,0,0,647,650,1,0,0,0,648,649,5, + 16,0,0,649,651,5,110,0,0,650,648,1,0,0,0,650,651,1,0,0,0,651,91,1,0,0, + 0,652,659,3,164,82,0,653,656,3,148,74,0,654,655,5,151,0,0,655,657,3,148, + 74,0,656,654,1,0,0,0,656,657,1,0,0,0,657,659,1,0,0,0,658,652,1,0,0,0, + 658,653,1,0,0,0,659,93,1,0,0,0,660,665,3,96,48,0,661,662,5,116,0,0,662, + 664,3,96,48,0,663,661,1,0,0,0,664,667,1,0,0,0,665,663,1,0,0,0,665,666, + 1,0,0,0,666,95,1,0,0,0,667,665,1,0,0,0,668,669,3,160,80,0,669,670,5,122, + 0,0,670,671,3,150,75,0,671,97,1,0,0,0,672,674,3,100,50,0,673,672,1,0, + 0,0,673,674,1,0,0,0,674,676,1,0,0,0,675,677,3,102,51,0,676,675,1,0,0, + 0,676,677,1,0,0,0,677,679,1,0,0,0,678,680,3,104,52,0,679,678,1,0,0,0, + 679,680,1,0,0,0,680,99,1,0,0,0,681,682,5,67,0,0,682,683,5,11,0,0,683, + 684,3,114,57,0,684,101,1,0,0,0,685,686,5,64,0,0,686,687,5,11,0,0,687, + 688,3,88,44,0,688,103,1,0,0,0,689,690,7,8,0,0,690,691,3,106,53,0,691, + 105,1,0,0,0,692,699,3,108,54,0,693,694,5,9,0,0,694,695,3,108,54,0,695, + 696,5,2,0,0,696,697,3,108,54,0,697,699,1,0,0,0,698,692,1,0,0,0,698,693, + 1,0,0,0,699,107,1,0,0,0,700,701,5,19,0,0,701,713,5,75,0,0,702,703,5,94, + 0,0,703,713,5,68,0,0,704,705,5,94,0,0,705,713,5,32,0,0,706,707,3,148, + 74,0,707,708,5,68,0,0,708,713,1,0,0,0,709,710,3,148,74,0,710,711,5,32, + 0,0,711,713,1,0,0,0,712,700,1,0,0,0,712,702,1,0,0,0,712,704,1,0,0,0,712, + 706,1,0,0,0,712,709,1,0,0,0,713,109,1,0,0,0,714,715,3,116,58,0,715,716, + 5,0,0,1,716,111,1,0,0,0,717,774,3,160,80,0,718,719,3,160,80,0,719,720, + 5,130,0,0,720,721,3,160,80,0,721,728,3,112,56,0,722,723,5,116,0,0,723, + 724,3,160,80,0,724,725,3,112,56,0,725,727,1,0,0,0,726,722,1,0,0,0,727, + 730,1,0,0,0,728,726,1,0,0,0,728,729,1,0,0,0,729,732,1,0,0,0,730,728,1, + 0,0,0,731,733,5,116,0,0,732,731,1,0,0,0,732,733,1,0,0,0,733,734,1,0,0, + 0,734,735,5,149,0,0,735,774,1,0,0,0,736,737,3,160,80,0,737,738,5,130, + 0,0,738,743,3,162,81,0,739,740,5,116,0,0,740,742,3,162,81,0,741,739,1, + 0,0,0,742,745,1,0,0,0,743,741,1,0,0,0,743,744,1,0,0,0,744,747,1,0,0,0, + 745,743,1,0,0,0,746,748,5,116,0,0,747,746,1,0,0,0,747,748,1,0,0,0,748, + 749,1,0,0,0,749,750,5,149,0,0,750,774,1,0,0,0,751,752,3,160,80,0,752, + 753,5,130,0,0,753,758,3,112,56,0,754,755,5,116,0,0,755,757,3,112,56,0, + 756,754,1,0,0,0,757,760,1,0,0,0,758,756,1,0,0,0,758,759,1,0,0,0,759,762, + 1,0,0,0,760,758,1,0,0,0,761,763,5,116,0,0,762,761,1,0,0,0,762,763,1,0, + 0,0,763,764,1,0,0,0,764,765,5,149,0,0,765,774,1,0,0,0,766,767,3,160,80, + 0,767,769,5,130,0,0,768,770,3,114,57,0,769,768,1,0,0,0,769,770,1,0,0, + 0,770,771,1,0,0,0,771,772,5,149,0,0,772,774,1,0,0,0,773,717,1,0,0,0,773, + 718,1,0,0,0,773,736,1,0,0,0,773,751,1,0,0,0,773,766,1,0,0,0,774,113,1, + 0,0,0,775,780,3,116,58,0,776,777,5,116,0,0,777,779,3,116,58,0,778,776, + 1,0,0,0,779,782,1,0,0,0,780,778,1,0,0,0,780,781,1,0,0,0,781,784,1,0,0, + 0,782,780,1,0,0,0,783,785,5,116,0,0,784,783,1,0,0,0,784,785,1,0,0,0,785, + 115,1,0,0,0,786,787,6,58,-1,0,787,789,5,12,0,0,788,790,3,116,58,0,789, + 788,1,0,0,0,789,790,1,0,0,0,790,796,1,0,0,0,791,792,5,98,0,0,792,793, + 3,116,58,0,793,794,5,83,0,0,794,795,3,116,58,0,795,797,1,0,0,0,796,791, + 1,0,0,0,797,798,1,0,0,0,798,796,1,0,0,0,798,799,1,0,0,0,799,802,1,0,0, + 0,800,801,5,25,0,0,801,803,3,116,58,0,802,800,1,0,0,0,802,803,1,0,0,0, + 803,804,1,0,0,0,804,805,5,26,0,0,805,936,1,0,0,0,806,807,5,13,0,0,807, + 808,5,130,0,0,808,809,3,116,58,0,809,810,5,6,0,0,810,811,3,112,56,0,811, + 812,5,149,0,0,812,936,1,0,0,0,813,814,5,20,0,0,814,936,5,110,0,0,815, + 816,5,45,0,0,816,817,3,116,58,0,817,818,3,152,76,0,818,936,1,0,0,0,819, + 820,5,82,0,0,820,821,5,130,0,0,821,822,3,116,58,0,822,823,5,34,0,0,823, + 826,3,116,58,0,824,825,5,33,0,0,825,827,3,116,58,0,826,824,1,0,0,0,826, + 827,1,0,0,0,827,828,1,0,0,0,828,829,5,149,0,0,829,936,1,0,0,0,830,831, + 5,86,0,0,831,936,5,110,0,0,832,833,5,91,0,0,833,834,5,130,0,0,834,835, + 7,9,0,0,835,836,3,166,83,0,836,837,5,34,0,0,837,838,3,116,58,0,838,839, + 5,149,0,0,839,936,1,0,0,0,840,841,3,160,80,0,841,843,5,130,0,0,842,844, + 3,114,57,0,843,842,1,0,0,0,843,844,1,0,0,0,844,845,1,0,0,0,845,846,5, + 149,0,0,846,855,1,0,0,0,847,849,5,130,0,0,848,850,5,24,0,0,849,848,1, + 0,0,0,849,850,1,0,0,0,850,852,1,0,0,0,851,853,3,118,59,0,852,851,1,0, + 0,0,852,853,1,0,0,0,853,854,1,0,0,0,854,856,5,149,0,0,855,847,1,0,0,0, + 855,856,1,0,0,0,856,857,1,0,0,0,857,858,5,66,0,0,858,859,5,130,0,0,859, + 860,3,98,49,0,860,861,5,149,0,0,861,936,1,0,0,0,862,863,3,160,80,0,863, + 865,5,130,0,0,864,866,3,114,57,0,865,864,1,0,0,0,865,866,1,0,0,0,866, + 867,1,0,0,0,867,868,5,149,0,0,868,877,1,0,0,0,869,871,5,130,0,0,870,872, + 5,24,0,0,871,870,1,0,0,0,871,872,1,0,0,0,872,874,1,0,0,0,873,875,3,118, + 59,0,874,873,1,0,0,0,874,875,1,0,0,0,875,876,1,0,0,0,876,878,5,149,0, + 0,877,869,1,0,0,0,877,878,1,0,0,0,878,879,1,0,0,0,879,880,5,66,0,0,880, + 881,3,160,80,0,881,936,1,0,0,0,882,888,3,160,80,0,883,885,5,130,0,0,884, + 886,3,114,57,0,885,884,1,0,0,0,885,886,1,0,0,0,886,887,1,0,0,0,887,889, + 5,149,0,0,888,883,1,0,0,0,888,889,1,0,0,0,889,890,1,0,0,0,890,892,5,130, + 0,0,891,893,5,24,0,0,892,891,1,0,0,0,892,893,1,0,0,0,893,895,1,0,0,0, + 894,896,3,118,59,0,895,894,1,0,0,0,895,896,1,0,0,0,896,897,1,0,0,0,897, + 898,5,149,0,0,898,936,1,0,0,0,899,936,3,124,62,0,900,936,3,168,84,0,901, + 936,3,150,75,0,902,903,5,118,0,0,903,936,3,116,58,19,904,905,5,58,0,0, + 905,936,3,116,58,13,906,907,3,140,70,0,907,908,5,120,0,0,908,910,1,0, + 0,0,909,906,1,0,0,0,909,910,1,0,0,0,910,911,1,0,0,0,911,936,5,112,0,0, + 912,913,5,130,0,0,913,914,3,44,22,0,914,915,5,149,0,0,915,936,1,0,0,0, + 916,917,5,130,0,0,917,918,3,116,58,0,918,919,5,149,0,0,919,936,1,0,0, + 0,920,921,5,130,0,0,921,922,3,114,57,0,922,923,5,149,0,0,923,936,1,0, + 0,0,924,926,5,129,0,0,925,927,3,114,57,0,926,925,1,0,0,0,926,927,1,0, + 0,0,927,928,1,0,0,0,928,936,5,148,0,0,929,931,5,128,0,0,930,932,3,40, + 20,0,931,930,1,0,0,0,931,932,1,0,0,0,932,933,1,0,0,0,933,936,5,147,0, + 0,934,936,3,132,66,0,935,786,1,0,0,0,935,806,1,0,0,0,935,813,1,0,0,0, + 935,815,1,0,0,0,935,819,1,0,0,0,935,830,1,0,0,0,935,832,1,0,0,0,935,840, + 1,0,0,0,935,862,1,0,0,0,935,882,1,0,0,0,935,899,1,0,0,0,935,900,1,0,0, + 0,935,901,1,0,0,0,935,902,1,0,0,0,935,904,1,0,0,0,935,909,1,0,0,0,935, + 912,1,0,0,0,935,916,1,0,0,0,935,920,1,0,0,0,935,924,1,0,0,0,935,929,1, + 0,0,0,935,934,1,0,0,0,936,1041,1,0,0,0,937,941,10,18,0,0,938,942,5,112, + 0,0,939,942,5,151,0,0,940,942,5,138,0,0,941,938,1,0,0,0,941,939,1,0,0, + 0,941,940,1,0,0,0,942,943,1,0,0,0,943,1040,3,116,58,19,944,948,10,17, + 0,0,945,949,5,139,0,0,946,949,5,118,0,0,947,949,5,117,0,0,948,945,1,0, + 0,0,948,946,1,0,0,0,948,947,1,0,0,0,949,950,1,0,0,0,950,1040,3,116,58, + 18,951,976,10,16,0,0,952,977,5,121,0,0,953,977,5,122,0,0,954,977,5,133, + 0,0,955,977,5,131,0,0,956,977,5,132,0,0,957,977,5,123,0,0,958,977,5,124, + 0,0,959,961,5,58,0,0,960,959,1,0,0,0,960,961,1,0,0,0,961,962,1,0,0,0, + 962,964,5,42,0,0,963,965,5,15,0,0,964,963,1,0,0,0,964,965,1,0,0,0,965, + 977,1,0,0,0,966,968,5,58,0,0,967,966,1,0,0,0,967,968,1,0,0,0,968,969, + 1,0,0,0,969,977,7,10,0,0,970,977,5,145,0,0,971,977,5,146,0,0,972,977, + 5,135,0,0,973,977,5,126,0,0,974,977,5,127,0,0,975,977,5,134,0,0,976,952, + 1,0,0,0,976,953,1,0,0,0,976,954,1,0,0,0,976,955,1,0,0,0,976,956,1,0,0, + 0,976,957,1,0,0,0,976,958,1,0,0,0,976,960,1,0,0,0,976,967,1,0,0,0,976, + 970,1,0,0,0,976,971,1,0,0,0,976,972,1,0,0,0,976,973,1,0,0,0,976,974,1, + 0,0,0,976,975,1,0,0,0,977,978,1,0,0,0,978,1040,3,116,58,17,979,980,10, + 14,0,0,980,981,5,137,0,0,981,1040,3,116,58,15,982,983,10,12,0,0,983,984, + 5,2,0,0,984,1040,3,116,58,13,985,986,10,11,0,0,986,987,5,63,0,0,987,1040, + 3,116,58,12,988,990,10,10,0,0,989,991,5,58,0,0,990,989,1,0,0,0,990,991, + 1,0,0,0,991,992,1,0,0,0,992,993,5,9,0,0,993,994,3,116,58,0,994,995,5, + 2,0,0,995,996,3,116,58,11,996,1040,1,0,0,0,997,998,10,9,0,0,998,999,5, + 140,0,0,999,1000,3,116,58,0,1000,1001,5,115,0,0,1001,1002,3,116,58,9, + 1002,1040,1,0,0,0,1003,1004,10,25,0,0,1004,1005,5,129,0,0,1005,1006,3, + 116,58,0,1006,1007,5,148,0,0,1007,1040,1,0,0,0,1008,1009,10,24,0,0,1009, + 1010,5,120,0,0,1010,1040,5,108,0,0,1011,1012,10,23,0,0,1012,1013,5,120, + 0,0,1013,1040,3,160,80,0,1014,1015,10,22,0,0,1015,1016,5,136,0,0,1016, + 1017,5,129,0,0,1017,1018,3,116,58,0,1018,1019,5,148,0,0,1019,1040,1,0, + 0,0,1020,1021,10,21,0,0,1021,1022,5,136,0,0,1022,1040,5,108,0,0,1023, + 1024,10,20,0,0,1024,1025,5,136,0,0,1025,1040,3,160,80,0,1026,1027,10, + 15,0,0,1027,1029,5,46,0,0,1028,1030,5,58,0,0,1029,1028,1,0,0,0,1029,1030, + 1,0,0,0,1030,1031,1,0,0,0,1031,1040,5,59,0,0,1032,1037,10,8,0,0,1033, + 1034,5,6,0,0,1034,1038,3,160,80,0,1035,1036,5,6,0,0,1036,1038,5,110,0, + 0,1037,1033,1,0,0,0,1037,1035,1,0,0,0,1038,1040,1,0,0,0,1039,937,1,0, + 0,0,1039,944,1,0,0,0,1039,951,1,0,0,0,1039,979,1,0,0,0,1039,982,1,0,0, + 0,1039,985,1,0,0,0,1039,988,1,0,0,0,1039,997,1,0,0,0,1039,1003,1,0,0, + 0,1039,1008,1,0,0,0,1039,1011,1,0,0,0,1039,1014,1,0,0,0,1039,1020,1,0, + 0,0,1039,1023,1,0,0,0,1039,1026,1,0,0,0,1039,1032,1,0,0,0,1040,1043,1, + 0,0,0,1041,1039,1,0,0,0,1041,1042,1,0,0,0,1042,117,1,0,0,0,1043,1041, + 1,0,0,0,1044,1049,3,120,60,0,1045,1046,5,116,0,0,1046,1048,3,120,60,0, + 1047,1045,1,0,0,0,1048,1051,1,0,0,0,1049,1047,1,0,0,0,1049,1050,1,0,0, + 0,1050,1053,1,0,0,0,1051,1049,1,0,0,0,1052,1054,5,116,0,0,1053,1052,1, + 0,0,0,1053,1054,1,0,0,0,1054,119,1,0,0,0,1055,1058,3,122,61,0,1056,1058, + 3,116,58,0,1057,1055,1,0,0,0,1057,1056,1,0,0,0,1058,121,1,0,0,0,1059, + 1060,5,130,0,0,1060,1065,3,160,80,0,1061,1062,5,116,0,0,1062,1064,3,160, + 80,0,1063,1061,1,0,0,0,1064,1067,1,0,0,0,1065,1063,1,0,0,0,1065,1066, + 1,0,0,0,1066,1069,1,0,0,0,1067,1065,1,0,0,0,1068,1070,5,116,0,0,1069, + 1068,1,0,0,0,1069,1070,1,0,0,0,1070,1071,1,0,0,0,1071,1072,5,149,0,0, + 1072,1085,1,0,0,0,1073,1078,3,160,80,0,1074,1075,5,116,0,0,1075,1077, + 3,160,80,0,1076,1074,1,0,0,0,1077,1080,1,0,0,0,1078,1076,1,0,0,0,1078, + 1079,1,0,0,0,1079,1082,1,0,0,0,1080,1078,1,0,0,0,1081,1083,5,116,0,0, + 1082,1081,1,0,0,0,1082,1083,1,0,0,0,1083,1085,1,0,0,0,1084,1059,1,0,0, + 0,1084,1073,1,0,0,0,1085,1086,1,0,0,0,1086,1087,5,111,0,0,1087,1088,3, + 116,58,0,1088,123,1,0,0,0,1089,1090,5,132,0,0,1090,1094,3,160,80,0,1091, + 1093,3,126,63,0,1092,1091,1,0,0,0,1093,1096,1,0,0,0,1094,1092,1,0,0,0, + 1094,1095,1,0,0,0,1095,1097,1,0,0,0,1096,1094,1,0,0,0,1097,1098,5,151, + 0,0,1098,1099,5,124,0,0,1099,1122,1,0,0,0,1100,1101,5,132,0,0,1101,1105, + 3,160,80,0,1102,1104,3,126,63,0,1103,1102,1,0,0,0,1104,1107,1,0,0,0,1105, + 1103,1,0,0,0,1105,1106,1,0,0,0,1106,1108,1,0,0,0,1107,1105,1,0,0,0,1108, + 1114,5,124,0,0,1109,1115,3,124,62,0,1110,1111,5,128,0,0,1111,1112,3,116, + 58,0,1112,1113,5,147,0,0,1113,1115,1,0,0,0,1114,1109,1,0,0,0,1114,1110, + 1,0,0,0,1114,1115,1,0,0,0,1115,1116,1,0,0,0,1116,1117,5,132,0,0,1117, + 1118,5,151,0,0,1118,1119,3,160,80,0,1119,1120,5,124,0,0,1120,1122,1,0, + 0,0,1121,1089,1,0,0,0,1121,1100,1,0,0,0,1122,125,1,0,0,0,1123,1124,3, + 160,80,0,1124,1125,5,122,0,0,1125,1126,3,166,83,0,1126,1135,1,0,0,0,1127, + 1128,3,160,80,0,1128,1129,5,122,0,0,1129,1130,5,128,0,0,1130,1131,3,116, + 58,0,1131,1132,5,147,0,0,1132,1135,1,0,0,0,1133,1135,3,160,80,0,1134, + 1123,1,0,0,0,1134,1127,1,0,0,0,1134,1133,1,0,0,0,1135,127,1,0,0,0,1136, + 1141,3,130,65,0,1137,1138,5,116,0,0,1138,1140,3,130,65,0,1139,1137,1, + 0,0,0,1140,1143,1,0,0,0,1141,1139,1,0,0,0,1141,1142,1,0,0,0,1142,1145, + 1,0,0,0,1143,1141,1,0,0,0,1144,1146,5,116,0,0,1145,1144,1,0,0,0,1145, + 1146,1,0,0,0,1146,129,1,0,0,0,1147,1148,3,160,80,0,1148,1149,5,6,0,0, + 1149,1150,5,130,0,0,1150,1151,3,44,22,0,1151,1152,5,149,0,0,1152,1158, + 1,0,0,0,1153,1154,3,116,58,0,1154,1155,5,6,0,0,1155,1156,3,160,80,0,1156, + 1158,1,0,0,0,1157,1147,1,0,0,0,1157,1153,1,0,0,0,1158,131,1,0,0,0,1159, + 1167,3,164,82,0,1160,1161,3,140,70,0,1161,1162,5,120,0,0,1162,1164,1, + 0,0,0,1163,1160,1,0,0,0,1163,1164,1,0,0,0,1164,1165,1,0,0,0,1165,1167, + 3,134,67,0,1166,1159,1,0,0,0,1166,1163,1,0,0,0,1167,133,1,0,0,0,1168, + 1173,3,160,80,0,1169,1170,5,120,0,0,1170,1172,3,160,80,0,1171,1169,1, + 0,0,0,1172,1175,1,0,0,0,1173,1171,1,0,0,0,1173,1174,1,0,0,0,1174,135, + 1,0,0,0,1175,1173,1,0,0,0,1176,1177,6,68,-1,0,1177,1186,3,140,70,0,1178, + 1186,3,138,69,0,1179,1180,5,130,0,0,1180,1181,3,44,22,0,1181,1182,5,149, + 0,0,1182,1186,1,0,0,0,1183,1186,3,124,62,0,1184,1186,3,164,82,0,1185, + 1176,1,0,0,0,1185,1178,1,0,0,0,1185,1179,1,0,0,0,1185,1183,1,0,0,0,1185, + 1184,1,0,0,0,1186,1195,1,0,0,0,1187,1191,10,3,0,0,1188,1192,3,158,79, + 0,1189,1190,5,6,0,0,1190,1192,3,160,80,0,1191,1188,1,0,0,0,1191,1189, + 1,0,0,0,1192,1194,1,0,0,0,1193,1187,1,0,0,0,1194,1197,1,0,0,0,1195,1193, + 1,0,0,0,1195,1196,1,0,0,0,1196,137,1,0,0,0,1197,1195,1,0,0,0,1198,1199, + 3,160,80,0,1199,1201,5,130,0,0,1200,1202,3,142,71,0,1201,1200,1,0,0,0, + 1201,1202,1,0,0,0,1202,1203,1,0,0,0,1203,1204,5,149,0,0,1204,139,1,0, + 0,0,1205,1206,3,144,72,0,1206,1207,5,120,0,0,1207,1209,1,0,0,0,1208,1205, + 1,0,0,0,1208,1209,1,0,0,0,1209,1210,1,0,0,0,1210,1211,3,160,80,0,1211, + 141,1,0,0,0,1212,1217,3,116,58,0,1213,1214,5,116,0,0,1214,1216,3,116, + 58,0,1215,1213,1,0,0,0,1216,1219,1,0,0,0,1217,1215,1,0,0,0,1217,1218, + 1,0,0,0,1218,1221,1,0,0,0,1219,1217,1,0,0,0,1220,1222,5,116,0,0,1221, + 1220,1,0,0,0,1221,1222,1,0,0,0,1222,143,1,0,0,0,1223,1224,3,160,80,0, + 1224,145,1,0,0,0,1225,1234,5,106,0,0,1226,1227,5,120,0,0,1227,1234,7, + 11,0,0,1228,1229,5,108,0,0,1229,1231,5,120,0,0,1230,1232,7,11,0,0,1231, + 1230,1,0,0,0,1231,1232,1,0,0,0,1232,1234,1,0,0,0,1233,1225,1,0,0,0,1233, + 1226,1,0,0,0,1233,1228,1,0,0,0,1234,147,1,0,0,0,1235,1237,7,12,0,0,1236, + 1235,1,0,0,0,1236,1237,1,0,0,0,1237,1244,1,0,0,0,1238,1245,3,146,73,0, + 1239,1245,5,107,0,0,1240,1245,5,108,0,0,1241,1245,5,109,0,0,1242,1245, + 5,43,0,0,1243,1245,5,57,0,0,1244,1238,1,0,0,0,1244,1239,1,0,0,0,1244, + 1240,1,0,0,0,1244,1241,1,0,0,0,1244,1242,1,0,0,0,1244,1243,1,0,0,0,1245, + 149,1,0,0,0,1246,1250,3,148,74,0,1247,1250,5,110,0,0,1248,1250,5,59,0, + 0,1249,1246,1,0,0,0,1249,1247,1,0,0,0,1249,1248,1,0,0,0,1250,151,1,0, + 0,0,1251,1252,7,13,0,0,1252,153,1,0,0,0,1253,1254,7,14,0,0,1254,155,1, + 0,0,0,1255,1256,7,15,0,0,1256,157,1,0,0,0,1257,1260,5,105,0,0,1258,1260, + 3,156,78,0,1259,1257,1,0,0,0,1259,1258,1,0,0,0,1260,159,1,0,0,0,1261, + 1265,5,105,0,0,1262,1265,3,152,76,0,1263,1265,3,154,77,0,1264,1261,1, + 0,0,0,1264,1262,1,0,0,0,1264,1263,1,0,0,0,1265,161,1,0,0,0,1266,1267, + 3,166,83,0,1267,1268,5,122,0,0,1268,1269,3,148,74,0,1269,163,1,0,0,0, + 1270,1271,5,128,0,0,1271,1272,3,160,80,0,1272,1273,5,147,0,0,1273,165, + 1,0,0,0,1274,1277,5,110,0,0,1275,1277,3,168,84,0,1276,1274,1,0,0,0,1276, + 1275,1,0,0,0,1277,167,1,0,0,0,1278,1282,5,142,0,0,1279,1281,3,170,85, + 0,1280,1279,1,0,0,0,1281,1284,1,0,0,0,1282,1280,1,0,0,0,1282,1283,1,0, + 0,0,1283,1285,1,0,0,0,1284,1282,1,0,0,0,1285,1286,5,144,0,0,1286,169, + 1,0,0,0,1287,1288,5,157,0,0,1288,1289,3,116,58,0,1289,1290,5,147,0,0, + 1290,1293,1,0,0,0,1291,1293,5,156,0,0,1292,1287,1,0,0,0,1292,1291,1,0, + 0,0,1293,171,1,0,0,0,1294,1298,5,143,0,0,1295,1297,3,174,87,0,1296,1295, + 1,0,0,0,1297,1300,1,0,0,0,1298,1296,1,0,0,0,1298,1299,1,0,0,0,1299,1301, + 1,0,0,0,1300,1298,1,0,0,0,1301,1302,5,0,0,1,1302,173,1,0,0,0,1303,1304, + 5,159,0,0,1304,1305,3,116,58,0,1305,1306,5,147,0,0,1306,1309,1,0,0,0, + 1307,1309,5,158,0,0,1308,1303,1,0,0,0,1308,1307,1,0,0,0,1309,175,1,0, + 0,0,168,179,186,195,202,206,220,224,227,231,234,241,245,254,259,268,276, + 283,287,293,298,306,313,319,331,339,353,357,362,372,381,384,388,391,395, + 398,401,404,407,411,415,418,421,424,428,431,440,446,467,484,501,507,513, + 524,526,537,540,546,554,560,562,566,571,574,577,581,585,588,590,593,597, + 601,604,606,608,613,624,630,637,642,646,650,656,658,665,673,676,679,698, + 712,728,732,743,747,758,762,769,773,780,784,789,798,802,826,843,849,852, + 855,865,871,874,877,885,888,892,895,909,926,931,935,941,948,960,964,967, + 976,990,1029,1037,1039,1041,1049,1053,1057,1065,1069,1078,1082,1084,1094, + 1105,1114,1121,1134,1141,1145,1157,1163,1166,1173,1185,1191,1195,1201, + 1208,1217,1221,1231,1233,1236,1244,1249,1259,1264,1276,1282,1292,1298, + 1308 }; staticData->serializedATN = antlr4::atn::SerializedATNView(serializedATNSegment, sizeof(serializedATNSegment) / sizeof(serializedATNSegment[0])); @@ -9259,6 +9261,18 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::HogqlxTagElementNestedContext return getRuleContext(0); } +tree::TerminalNode* HogQLParser::HogqlxTagElementNestedContext::LBRACE() { + return getToken(HogQLParser::LBRACE, 0); +} + +HogQLParser::ColumnExprContext* HogQLParser::HogqlxTagElementNestedContext::columnExpr() { + return getRuleContext(0); +} + +tree::TerminalNode* HogQLParser::HogqlxTagElementNestedContext::RBRACE() { + return getToken(HogQLParser::RBRACE, 0); +} + HogQLParser::HogqlxTagElementNestedContext::HogqlxTagElementNestedContext(HogqlxTagElementContext *ctx) { copyFrom(ctx); } @@ -9281,7 +9295,7 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() { exitRule(); }); try { - setState(1117); + setState(1121); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 141, _ctx)) { case 1: { @@ -9331,7 +9345,7 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() { } setState(1108); match(HogQLParser::GT); - setState(1110); + setState(1114); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 140, _ctx)) { @@ -9341,16 +9355,26 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() { break; } + case 2: { + setState(1110); + match(HogQLParser::LBRACE); + setState(1111); + columnExpr(0); + setState(1112); + match(HogQLParser::RBRACE); + break; + } + default: break; } - setState(1112); + setState(1116); match(HogQLParser::LT); - setState(1113); + setState(1117); match(HogQLParser::SLASH); - setState(1114); + setState(1118); identifier(); - setState(1115); + setState(1119); match(HogQLParser::GT); break; } @@ -9424,38 +9448,38 @@ HogQLParser::HogqlxTagAttributeContext* HogQLParser::hogqlxTagAttribute() { exitRule(); }); try { - setState(1130); + setState(1134); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 142, _ctx)) { case 1: { enterOuterAlt(_localctx, 1); - setState(1119); + setState(1123); identifier(); - setState(1120); + setState(1124); match(HogQLParser::EQ_SINGLE); - setState(1121); + setState(1125); string(); break; } case 2: { enterOuterAlt(_localctx, 2); - setState(1123); + setState(1127); identifier(); - setState(1124); + setState(1128); match(HogQLParser::EQ_SINGLE); - setState(1125); + setState(1129); match(HogQLParser::LBRACE); - setState(1126); + setState(1130); columnExpr(0); - setState(1127); + setState(1131); match(HogQLParser::RBRACE); break; } case 3: { enterOuterAlt(_localctx, 3); - setState(1129); + setState(1133); identifier(); break; } @@ -9524,28 +9548,28 @@ HogQLParser::WithExprListContext* HogQLParser::withExprList() { try { size_t alt; enterOuterAlt(_localctx, 1); - setState(1132); + setState(1136); withExpr(); - setState(1137); + setState(1141); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 143, _ctx); while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { if (alt == 1) { - setState(1133); + setState(1137); match(HogQLParser::COMMA); - setState(1134); + setState(1138); withExpr(); } - setState(1139); + setState(1143); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 143, _ctx); } - setState(1141); + setState(1145); _errHandler->sync(this); _la = _input->LA(1); if (_la == HogQLParser::COMMA) { - setState(1140); + setState(1144); match(HogQLParser::COMMA); } @@ -9640,21 +9664,21 @@ HogQLParser::WithExprContext* HogQLParser::withExpr() { exitRule(); }); try { - setState(1153); + setState(1157); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 145, _ctx)) { case 1: { _localctx = _tracker.createInstance(_localctx); enterOuterAlt(_localctx, 1); - setState(1143); + setState(1147); identifier(); - setState(1144); + setState(1148); match(HogQLParser::AS); - setState(1145); + setState(1149); match(HogQLParser::LPAREN); - setState(1146); + setState(1150); selectUnionStmt(); - setState(1147); + setState(1151); match(HogQLParser::RPAREN); break; } @@ -9662,11 +9686,11 @@ HogQLParser::WithExprContext* HogQLParser::withExpr() { case 2: { _localctx = _tracker.createInstance(_localctx); enterOuterAlt(_localctx, 2); - setState(1149); + setState(1153); columnExpr(0); - setState(1150); + setState(1154); match(HogQLParser::AS); - setState(1151); + setState(1155); identifier(); break; } @@ -9732,12 +9756,12 @@ HogQLParser::ColumnIdentifierContext* HogQLParser::columnIdentifier() { exitRule(); }); try { - setState(1162); + setState(1166); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::LBRACE: { enterOuterAlt(_localctx, 1); - setState(1155); + setState(1159); placeholder(); break; } @@ -9837,14 +9861,14 @@ HogQLParser::ColumnIdentifierContext* HogQLParser::columnIdentifier() { case HogQLParser::YEAR: case HogQLParser::IDENTIFIER: { enterOuterAlt(_localctx, 2); - setState(1159); + setState(1163); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 146, _ctx)) { case 1: { - setState(1156); + setState(1160); tableIdentifier(); - setState(1157); + setState(1161); match(HogQLParser::DOT); break; } @@ -9852,7 +9876,7 @@ HogQLParser::ColumnIdentifierContext* HogQLParser::columnIdentifier() { default: break; } - setState(1161); + setState(1165); nestedIdentifier(); break; } @@ -9920,19 +9944,19 @@ HogQLParser::NestedIdentifierContext* HogQLParser::nestedIdentifier() { try { size_t alt; enterOuterAlt(_localctx, 1); - setState(1164); + setState(1168); identifier(); - setState(1169); + setState(1173); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 148, _ctx); while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { if (alt == 1) { - setState(1165); + setState(1169); match(HogQLParser::DOT); - setState(1166); + setState(1170); identifier(); } - setState(1171); + setState(1175); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 148, _ctx); } @@ -10098,7 +10122,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { try { size_t alt; enterOuterAlt(_localctx, 1); - setState(1181); + setState(1185); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 149, _ctx)) { case 1: { @@ -10106,7 +10130,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { _ctx = _localctx; previousContext = _localctx; - setState(1173); + setState(1177); tableIdentifier(); break; } @@ -10115,7 +10139,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(1174); + setState(1178); tableFunctionExpr(); break; } @@ -10124,11 +10148,11 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(1175); + setState(1179); match(HogQLParser::LPAREN); - setState(1176); + setState(1180); selectUnionStmt(); - setState(1177); + setState(1181); match(HogQLParser::RPAREN); break; } @@ -10137,7 +10161,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(1179); + setState(1183); hogqlxTagElement(); break; } @@ -10146,7 +10170,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(1180); + setState(1184); placeholder(); break; } @@ -10155,7 +10179,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { break; } _ctx->stop = _input->LT(-1); - setState(1191); + setState(1195); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 151, _ctx); while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { @@ -10166,10 +10190,10 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); _localctx = newContext; pushNewRecursionContext(newContext, startState, RuleTableExpr); - setState(1183); + setState(1187); if (!(precpred(_ctx, 3))) throw FailedPredicateException(this, "precpred(_ctx, 3)"); - setState(1187); + setState(1191); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::DATE: @@ -10177,15 +10201,15 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { case HogQLParser::ID: case HogQLParser::KEY: case HogQLParser::IDENTIFIER: { - setState(1184); + setState(1188); alias(); break; } case HogQLParser::AS: { - setState(1185); + setState(1189); match(HogQLParser::AS); - setState(1186); + setState(1190); identifier(); break; } @@ -10194,7 +10218,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) { throw NoViableAltException(this); } } - setState(1193); + setState(1197); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 151, _ctx); } @@ -10256,11 +10280,11 @@ HogQLParser::TableFunctionExprContext* HogQLParser::tableFunctionExpr() { }); try { enterOuterAlt(_localctx, 1); - setState(1194); + setState(1198); identifier(); - setState(1195); + setState(1199); match(HogQLParser::LPAREN); - setState(1197); + setState(1201); _errHandler->sync(this); _la = _input->LA(1); @@ -10268,10 +10292,10 @@ HogQLParser::TableFunctionExprContext* HogQLParser::tableFunctionExpr() { ((1ULL << _la) & -4503602311741442) != 0) || ((((_la - 64) & ~ 0x3fULL) == 0) && ((1ULL << (_la - 64)) & 90493036243451903) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) && ((1ULL << (_la - 128)) & 18455) != 0)) { - setState(1196); + setState(1200); tableArgList(); } - setState(1199); + setState(1203); match(HogQLParser::RPAREN); } @@ -10328,14 +10352,14 @@ HogQLParser::TableIdentifierContext* HogQLParser::tableIdentifier() { }); try { enterOuterAlt(_localctx, 1); - setState(1204); + setState(1208); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 153, _ctx)) { case 1: { - setState(1201); + setState(1205); databaseIdentifier(); - setState(1202); + setState(1206); match(HogQLParser::DOT); break; } @@ -10343,7 +10367,7 @@ HogQLParser::TableIdentifierContext* HogQLParser::tableIdentifier() { default: break; } - setState(1206); + setState(1210); identifier(); } @@ -10406,28 +10430,28 @@ HogQLParser::TableArgListContext* HogQLParser::tableArgList() { try { size_t alt; enterOuterAlt(_localctx, 1); - setState(1208); + setState(1212); columnExpr(0); - setState(1213); + setState(1217); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 154, _ctx); while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { if (alt == 1) { - setState(1209); + setState(1213); match(HogQLParser::COMMA); - setState(1210); + setState(1214); columnExpr(0); } - setState(1215); + setState(1219); _errHandler->sync(this); alt = getInterpreter()->adaptivePredict(_input, 154, _ctx); } - setState(1217); + setState(1221); _errHandler->sync(this); _la = _input->LA(1); if (_la == HogQLParser::COMMA) { - setState(1216); + setState(1220); match(HogQLParser::COMMA); } @@ -10477,7 +10501,7 @@ HogQLParser::DatabaseIdentifierContext* HogQLParser::databaseIdentifier() { }); try { enterOuterAlt(_localctx, 1); - setState(1219); + setState(1223); identifier(); } @@ -10542,21 +10566,21 @@ HogQLParser::FloatingLiteralContext* HogQLParser::floatingLiteral() { exitRule(); }); try { - setState(1229); + setState(1233); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::FLOATING_LITERAL: { enterOuterAlt(_localctx, 1); - setState(1221); + setState(1225); match(HogQLParser::FLOATING_LITERAL); break; } case HogQLParser::DOT: { enterOuterAlt(_localctx, 2); - setState(1222); + setState(1226); match(HogQLParser::DOT); - setState(1223); + setState(1227); _la = _input->LA(1); if (!(_la == HogQLParser::OCTAL_LITERAL @@ -10572,16 +10596,16 @@ HogQLParser::FloatingLiteralContext* HogQLParser::floatingLiteral() { case HogQLParser::DECIMAL_LITERAL: { enterOuterAlt(_localctx, 3); - setState(1224); + setState(1228); match(HogQLParser::DECIMAL_LITERAL); - setState(1225); + setState(1229); match(HogQLParser::DOT); - setState(1227); + setState(1231); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 156, _ctx)) { case 1: { - setState(1226); + setState(1230); _la = _input->LA(1); if (!(_la == HogQLParser::OCTAL_LITERAL @@ -10680,14 +10704,14 @@ HogQLParser::NumberLiteralContext* HogQLParser::numberLiteral() { }); try { enterOuterAlt(_localctx, 1); - setState(1232); + setState(1236); _errHandler->sync(this); _la = _input->LA(1); if (_la == HogQLParser::DASH || _la == HogQLParser::PLUS) { - setState(1231); + setState(1235); _la = _input->LA(1); if (!(_la == HogQLParser::DASH @@ -10699,41 +10723,41 @@ HogQLParser::NumberLiteralContext* HogQLParser::numberLiteral() { consume(); } } - setState(1240); + setState(1244); _errHandler->sync(this); switch (getInterpreter()->adaptivePredict(_input, 159, _ctx)) { case 1: { - setState(1234); + setState(1238); floatingLiteral(); break; } case 2: { - setState(1235); + setState(1239); match(HogQLParser::OCTAL_LITERAL); break; } case 3: { - setState(1236); + setState(1240); match(HogQLParser::DECIMAL_LITERAL); break; } case 4: { - setState(1237); + setState(1241); match(HogQLParser::HEXADECIMAL_LITERAL); break; } case 5: { - setState(1238); + setState(1242); match(HogQLParser::INF); break; } case 6: { - setState(1239); + setState(1243); match(HogQLParser::NAN_SQL); break; } @@ -10795,7 +10819,7 @@ HogQLParser::LiteralContext* HogQLParser::literal() { exitRule(); }); try { - setState(1245); + setState(1249); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::INF: @@ -10808,21 +10832,21 @@ HogQLParser::LiteralContext* HogQLParser::literal() { case HogQLParser::DOT: case HogQLParser::PLUS: { enterOuterAlt(_localctx, 1); - setState(1242); + setState(1246); numberLiteral(); break; } case HogQLParser::STRING_LITERAL: { enterOuterAlt(_localctx, 2); - setState(1243); + setState(1247); match(HogQLParser::STRING_LITERAL); break; } case HogQLParser::NULL_SQL: { enterOuterAlt(_localctx, 3); - setState(1244); + setState(1248); match(HogQLParser::NULL_SQL); break; } @@ -10906,7 +10930,7 @@ HogQLParser::IntervalContext* HogQLParser::interval() { }); try { enterOuterAlt(_localctx, 1); - setState(1247); + setState(1251); _la = _input->LA(1); if (!((((_la & ~ 0x3fULL) == 0) && ((1ULL << _la) & 108086665936896000) != 0) || ((((_la - 70) & ~ 0x3fULL) == 0) && @@ -11301,7 +11325,7 @@ HogQLParser::KeywordContext* HogQLParser::keyword() { }); try { enterOuterAlt(_localctx, 1); - setState(1249); + setState(1253); _la = _input->LA(1); if (!((((_la & ~ 0x3fULL) == 0) && ((1ULL << _la) & -833175004720939010) != 0) || ((((_la - 64) & ~ 0x3fULL) == 0) && @@ -11372,7 +11396,7 @@ HogQLParser::KeywordForAliasContext* HogQLParser::keywordForAlias() { }); try { enterOuterAlt(_localctx, 1); - setState(1251); + setState(1255); _la = _input->LA(1); if (!((((_la & ~ 0x3fULL) == 0) && ((1ULL << _la) & 282025807314944) != 0))) { @@ -11432,12 +11456,12 @@ HogQLParser::AliasContext* HogQLParser::alias() { exitRule(); }); try { - setState(1255); + setState(1259); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::IDENTIFIER: { enterOuterAlt(_localctx, 1); - setState(1253); + setState(1257); match(HogQLParser::IDENTIFIER); break; } @@ -11447,7 +11471,7 @@ HogQLParser::AliasContext* HogQLParser::alias() { case HogQLParser::ID: case HogQLParser::KEY: { enterOuterAlt(_localctx, 2); - setState(1254); + setState(1258); keywordForAlias(); break; } @@ -11509,12 +11533,12 @@ HogQLParser::IdentifierContext* HogQLParser::identifier() { exitRule(); }); try { - setState(1260); + setState(1264); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::IDENTIFIER: { enterOuterAlt(_localctx, 1); - setState(1257); + setState(1261); match(HogQLParser::IDENTIFIER); break; } @@ -11528,7 +11552,7 @@ HogQLParser::IdentifierContext* HogQLParser::identifier() { case HogQLParser::WEEK: case HogQLParser::YEAR: { enterOuterAlt(_localctx, 2); - setState(1258); + setState(1262); interval(); break; } @@ -11619,7 +11643,7 @@ HogQLParser::IdentifierContext* HogQLParser::identifier() { case HogQLParser::WINDOW: case HogQLParser::WITH: { enterOuterAlt(_localctx, 3); - setState(1259); + setState(1263); keyword(); break; } @@ -11682,11 +11706,11 @@ HogQLParser::EnumValueContext* HogQLParser::enumValue() { }); try { enterOuterAlt(_localctx, 1); - setState(1262); + setState(1266); string(); - setState(1263); + setState(1267); match(HogQLParser::EQ_SINGLE); - setState(1264); + setState(1268); numberLiteral(); } @@ -11743,11 +11767,11 @@ HogQLParser::PlaceholderContext* HogQLParser::placeholder() { }); try { enterOuterAlt(_localctx, 1); - setState(1266); + setState(1270); match(HogQLParser::LBRACE); - setState(1267); + setState(1271); identifier(); - setState(1268); + setState(1272); match(HogQLParser::RBRACE); } @@ -11799,19 +11823,19 @@ HogQLParser::StringContext* HogQLParser::string() { exitRule(); }); try { - setState(1272); + setState(1276); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::STRING_LITERAL: { enterOuterAlt(_localctx, 1); - setState(1270); + setState(1274); match(HogQLParser::STRING_LITERAL); break; } case HogQLParser::QUOTE_SINGLE_TEMPLATE: { enterOuterAlt(_localctx, 2); - setState(1271); + setState(1275); templateString(); break; } @@ -11879,21 +11903,21 @@ HogQLParser::TemplateStringContext* HogQLParser::templateString() { }); try { enterOuterAlt(_localctx, 1); - setState(1274); - match(HogQLParser::QUOTE_SINGLE_TEMPLATE); setState(1278); + match(HogQLParser::QUOTE_SINGLE_TEMPLATE); + setState(1282); _errHandler->sync(this); _la = _input->LA(1); while (_la == HogQLParser::STRING_TEXT || _la == HogQLParser::STRING_ESCAPE_TRIGGER) { - setState(1275); + setState(1279); stringContents(); - setState(1280); + setState(1284); _errHandler->sync(this); _la = _input->LA(1); } - setState(1281); + setState(1285); match(HogQLParser::QUOTE_SINGLE); } @@ -11953,23 +11977,23 @@ HogQLParser::StringContentsContext* HogQLParser::stringContents() { exitRule(); }); try { - setState(1288); + setState(1292); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::STRING_ESCAPE_TRIGGER: { enterOuterAlt(_localctx, 1); - setState(1283); + setState(1287); match(HogQLParser::STRING_ESCAPE_TRIGGER); - setState(1284); + setState(1288); columnExpr(0); - setState(1285); + setState(1289); match(HogQLParser::RBRACE); break; } case HogQLParser::STRING_TEXT: { enterOuterAlt(_localctx, 2); - setState(1287); + setState(1291); match(HogQLParser::STRING_TEXT); break; } @@ -12037,21 +12061,21 @@ HogQLParser::FullTemplateStringContext* HogQLParser::fullTemplateString() { }); try { enterOuterAlt(_localctx, 1); - setState(1290); - match(HogQLParser::QUOTE_SINGLE_TEMPLATE_FULL); setState(1294); + match(HogQLParser::QUOTE_SINGLE_TEMPLATE_FULL); + setState(1298); _errHandler->sync(this); _la = _input->LA(1); while (_la == HogQLParser::FULL_STRING_TEXT || _la == HogQLParser::FULL_STRING_ESCAPE_TRIGGER) { - setState(1291); + setState(1295); stringContentsFull(); - setState(1296); + setState(1300); _errHandler->sync(this); _la = _input->LA(1); } - setState(1297); + setState(1301); match(HogQLParser::EOF); } @@ -12111,23 +12135,23 @@ HogQLParser::StringContentsFullContext* HogQLParser::stringContentsFull() { exitRule(); }); try { - setState(1304); + setState(1308); _errHandler->sync(this); switch (_input->LA(1)) { case HogQLParser::FULL_STRING_ESCAPE_TRIGGER: { enterOuterAlt(_localctx, 1); - setState(1299); + setState(1303); match(HogQLParser::FULL_STRING_ESCAPE_TRIGGER); - setState(1300); + setState(1304); columnExpr(0); - setState(1301); + setState(1305); match(HogQLParser::RBRACE); break; } case HogQLParser::FULL_STRING_TEXT: { enterOuterAlt(_localctx, 2); - setState(1303); + setState(1307); match(HogQLParser::FULL_STRING_TEXT); break; } diff --git a/hogql_parser/HogQLParser.h b/hogql_parser/HogQLParser.h index a5ee0acf8c2ef..d5a5253ad25f0 100644 --- a/hogql_parser/HogQLParser.h +++ b/hogql_parser/HogQLParser.h @@ -1929,6 +1929,9 @@ class HogQLParser : public antlr4::Parser { std::vector hogqlxTagAttribute(); HogqlxTagAttributeContext* hogqlxTagAttribute(size_t i); HogqlxTagElementContext *hogqlxTagElement(); + antlr4::tree::TerminalNode *LBRACE(); + ColumnExprContext *columnExpr(); + antlr4::tree::TerminalNode *RBRACE(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; diff --git a/hogql_parser/HogQLParser.interp b/hogql_parser/HogQLParser.interp index 20c37a5916320..e31bf92fee7e9 100644 --- a/hogql_parser/HogQLParser.interp +++ b/hogql_parser/HogQLParser.interp @@ -414,4 +414,4 @@ stringContentsFull atn: -[4, 1, 159, 1307, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 1, 0, 5, 0, 178, 8, 0, 10, 0, 12, 0, 181, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 187, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 196, 8, 3, 1, 4, 1, 4, 1, 4, 5, 4, 201, 8, 4, 10, 4, 12, 4, 204, 9, 4, 1, 4, 3, 4, 207, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 221, 8, 5, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 6, 3, 6, 228, 8, 6, 1, 7, 1, 7, 3, 7, 232, 8, 7, 1, 7, 3, 7, 235, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 242, 8, 8, 1, 8, 1, 8, 3, 8, 246, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 5, 9, 253, 8, 9, 10, 9, 12, 9, 256, 9, 9, 1, 9, 1, 9, 3, 9, 260, 8, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 269, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 277, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 284, 8, 12, 1, 12, 1, 12, 3, 12, 288, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 294, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 299, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 307, 8, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 314, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 320, 8, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 3, 16, 332, 8, 16, 1, 17, 1, 17, 1, 18, 1, 18, 5, 18, 338, 8, 18, 10, 18, 12, 18, 341, 9, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 352, 8, 20, 10, 20, 12, 20, 355, 9, 20, 1, 20, 3, 20, 358, 8, 20, 1, 21, 1, 21, 1, 21, 3, 21, 363, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 371, 8, 22, 10, 22, 12, 22, 374, 9, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 382, 8, 23, 1, 24, 3, 24, 385, 8, 24, 1, 24, 1, 24, 3, 24, 389, 8, 24, 1, 24, 3, 24, 392, 8, 24, 1, 24, 1, 24, 3, 24, 396, 8, 24, 1, 24, 3, 24, 399, 8, 24, 1, 24, 3, 24, 402, 8, 24, 1, 24, 3, 24, 405, 8, 24, 1, 24, 3, 24, 408, 8, 24, 1, 24, 1, 24, 3, 24, 412, 8, 24, 1, 24, 1, 24, 3, 24, 416, 8, 24, 1, 24, 3, 24, 419, 8, 24, 1, 24, 3, 24, 422, 8, 24, 1, 24, 3, 24, 425, 8, 24, 1, 24, 1, 24, 3, 24, 429, 8, 24, 1, 24, 3, 24, 432, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 441, 8, 26, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 447, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 466, 8, 29, 10, 29, 12, 29, 469, 9, 29, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 485, 8, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 502, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 508, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 514, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 525, 8, 36, 3, 36, 527, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 3, 39, 538, 8, 39, 1, 39, 3, 39, 541, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 547, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 555, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 561, 8, 39, 10, 39, 12, 39, 564, 9, 39, 1, 40, 3, 40, 567, 8, 40, 1, 40, 1, 40, 1, 40, 3, 40, 572, 8, 40, 1, 40, 3, 40, 575, 8, 40, 1, 40, 3, 40, 578, 8, 40, 1, 40, 1, 40, 3, 40, 582, 8, 40, 1, 40, 1, 40, 3, 40, 586, 8, 40, 1, 40, 3, 40, 589, 8, 40, 3, 40, 591, 8, 40, 1, 40, 3, 40, 594, 8, 40, 1, 40, 1, 40, 3, 40, 598, 8, 40, 1, 40, 1, 40, 3, 40, 602, 8, 40, 1, 40, 3, 40, 605, 8, 40, 3, 40, 607, 8, 40, 3, 40, 609, 8, 40, 1, 41, 1, 41, 1, 41, 3, 41, 614, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 625, 8, 42, 1, 43, 1, 43, 1, 43, 1, 43, 3, 43, 631, 8, 43, 1, 44, 1, 44, 1, 44, 5, 44, 636, 8, 44, 10, 44, 12, 44, 639, 9, 44, 1, 45, 1, 45, 3, 45, 643, 8, 45, 1, 45, 1, 45, 3, 45, 647, 8, 45, 1, 45, 1, 45, 3, 45, 651, 8, 45, 1, 46, 1, 46, 1, 46, 1, 46, 3, 46, 657, 8, 46, 3, 46, 659, 8, 46, 1, 47, 1, 47, 1, 47, 5, 47, 664, 8, 47, 10, 47, 12, 47, 667, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 3, 49, 674, 8, 49, 1, 49, 3, 49, 677, 8, 49, 1, 49, 3, 49, 680, 8, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 699, 8, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 3, 54, 713, 8, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 727, 8, 56, 10, 56, 12, 56, 730, 9, 56, 1, 56, 3, 56, 733, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 742, 8, 56, 10, 56, 12, 56, 745, 9, 56, 1, 56, 3, 56, 748, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 757, 8, 56, 10, 56, 12, 56, 760, 9, 56, 1, 56, 3, 56, 763, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 770, 8, 56, 1, 56, 1, 56, 3, 56, 774, 8, 56, 1, 57, 1, 57, 1, 57, 5, 57, 779, 8, 57, 10, 57, 12, 57, 782, 9, 57, 1, 57, 3, 57, 785, 8, 57, 1, 58, 1, 58, 1, 58, 3, 58, 790, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 4, 58, 797, 8, 58, 11, 58, 12, 58, 798, 1, 58, 1, 58, 3, 58, 803, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 827, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 844, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 850, 8, 58, 1, 58, 3, 58, 853, 8, 58, 1, 58, 3, 58, 856, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 866, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 872, 8, 58, 1, 58, 3, 58, 875, 8, 58, 1, 58, 3, 58, 878, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 886, 8, 58, 1, 58, 3, 58, 889, 8, 58, 1, 58, 1, 58, 3, 58, 893, 8, 58, 1, 58, 3, 58, 896, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 910, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 927, 8, 58, 1, 58, 1, 58, 1, 58, 3, 58, 932, 8, 58, 1, 58, 1, 58, 3, 58, 936, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 942, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 949, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 961, 8, 58, 1, 58, 1, 58, 3, 58, 965, 8, 58, 1, 58, 3, 58, 968, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 977, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 991, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1030, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1038, 8, 58, 5, 58, 1040, 8, 58, 10, 58, 12, 58, 1043, 9, 58, 1, 59, 1, 59, 1, 59, 5, 59, 1048, 8, 59, 10, 59, 12, 59, 1051, 9, 59, 1, 59, 3, 59, 1054, 8, 59, 1, 60, 1, 60, 3, 60, 1058, 8, 60, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1064, 8, 61, 10, 61, 12, 61, 1067, 9, 61, 1, 61, 3, 61, 1070, 8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1077, 8, 61, 10, 61, 12, 61, 1080, 9, 61, 1, 61, 3, 61, 1083, 8, 61, 3, 61, 1085, 8, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 5, 62, 1093, 8, 62, 10, 62, 12, 62, 1096, 9, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 5, 62, 1104, 8, 62, 10, 62, 12, 62, 1107, 9, 62, 1, 62, 1, 62, 3, 62, 1111, 8, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1118, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 1131, 8, 63, 1, 64, 1, 64, 1, 64, 5, 64, 1136, 8, 64, 10, 64, 12, 64, 1139, 9, 64, 1, 64, 3, 64, 1142, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1154, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 1160, 8, 66, 1, 66, 3, 66, 1163, 8, 66, 1, 67, 1, 67, 1, 67, 5, 67, 1168, 8, 67, 10, 67, 12, 67, 1171, 9, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1182, 8, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1188, 8, 68, 5, 68, 1190, 8, 68, 10, 68, 12, 68, 1193, 9, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1198, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, 1205, 8, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 5, 71, 1212, 8, 71, 10, 71, 12, 71, 1215, 9, 71, 1, 71, 3, 71, 1218, 8, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 1228, 8, 73, 3, 73, 1230, 8, 73, 1, 74, 3, 74, 1233, 8, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 3, 74, 1241, 8, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1246, 8, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 3, 79, 1256, 8, 79, 1, 80, 1, 80, 1, 80, 3, 80, 1261, 8, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 3, 83, 1273, 8, 83, 1, 84, 1, 84, 5, 84, 1277, 8, 84, 10, 84, 12, 84, 1280, 9, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 1289, 8, 85, 1, 86, 1, 86, 5, 86, 1293, 8, 86, 10, 86, 12, 86, 1296, 9, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 3, 87, 1305, 8, 87, 1, 87, 0, 3, 78, 116, 136, 88, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 0, 16, 2, 0, 18, 18, 74, 74, 2, 0, 44, 44, 51, 51, 3, 0, 1, 1, 4, 4, 8, 8, 4, 0, 1, 1, 3, 4, 8, 8, 80, 80, 2, 0, 51, 51, 73, 73, 2, 0, 1, 1, 4, 4, 2, 0, 7, 7, 22, 23, 2, 0, 30, 30, 49, 49, 2, 0, 71, 71, 76, 76, 3, 0, 10, 10, 50, 50, 90, 90, 2, 0, 41, 41, 53, 53, 1, 0, 107, 108, 2, 0, 118, 118, 139, 139, 7, 0, 21, 21, 38, 38, 55, 56, 70, 70, 78, 78, 97, 97, 103, 103, 16, 0, 1, 13, 15, 20, 22, 28, 30, 30, 32, 37, 39, 42, 44, 51, 53, 54, 58, 58, 60, 69, 71, 77, 79, 83, 85, 92, 94, 96, 98, 99, 101, 102, 4, 0, 20, 20, 30, 30, 39, 39, 48, 48, 1474, 0, 179, 1, 0, 0, 0, 2, 186, 1, 0, 0, 0, 4, 188, 1, 0, 0, 0, 6, 190, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 220, 1, 0, 0, 0, 12, 222, 1, 0, 0, 0, 14, 229, 1, 0, 0, 0, 16, 236, 1, 0, 0, 0, 18, 249, 1, 0, 0, 0, 20, 261, 1, 0, 0, 0, 22, 270, 1, 0, 0, 0, 24, 278, 1, 0, 0, 0, 26, 300, 1, 0, 0, 0, 28, 315, 1, 0, 0, 0, 30, 324, 1, 0, 0, 0, 32, 329, 1, 0, 0, 0, 34, 333, 1, 0, 0, 0, 36, 335, 1, 0, 0, 0, 38, 344, 1, 0, 0, 0, 40, 348, 1, 0, 0, 0, 42, 362, 1, 0, 0, 0, 44, 366, 1, 0, 0, 0, 46, 381, 1, 0, 0, 0, 48, 384, 1, 0, 0, 0, 50, 433, 1, 0, 0, 0, 52, 436, 1, 0, 0, 0, 54, 442, 1, 0, 0, 0, 56, 446, 1, 0, 0, 0, 58, 452, 1, 0, 0, 0, 60, 470, 1, 0, 0, 0, 62, 473, 1, 0, 0, 0, 64, 476, 1, 0, 0, 0, 66, 486, 1, 0, 0, 0, 68, 489, 1, 0, 0, 0, 70, 493, 1, 0, 0, 0, 72, 526, 1, 0, 0, 0, 74, 528, 1, 0, 0, 0, 76, 531, 1, 0, 0, 0, 78, 546, 1, 0, 0, 0, 80, 608, 1, 0, 0, 0, 82, 613, 1, 0, 0, 0, 84, 624, 1, 0, 0, 0, 86, 626, 1, 0, 0, 0, 88, 632, 1, 0, 0, 0, 90, 640, 1, 0, 0, 0, 92, 658, 1, 0, 0, 0, 94, 660, 1, 0, 0, 0, 96, 668, 1, 0, 0, 0, 98, 673, 1, 0, 0, 0, 100, 681, 1, 0, 0, 0, 102, 685, 1, 0, 0, 0, 104, 689, 1, 0, 0, 0, 106, 698, 1, 0, 0, 0, 108, 712, 1, 0, 0, 0, 110, 714, 1, 0, 0, 0, 112, 773, 1, 0, 0, 0, 114, 775, 1, 0, 0, 0, 116, 935, 1, 0, 0, 0, 118, 1044, 1, 0, 0, 0, 120, 1057, 1, 0, 0, 0, 122, 1084, 1, 0, 0, 0, 124, 1117, 1, 0, 0, 0, 126, 1130, 1, 0, 0, 0, 128, 1132, 1, 0, 0, 0, 130, 1153, 1, 0, 0, 0, 132, 1162, 1, 0, 0, 0, 134, 1164, 1, 0, 0, 0, 136, 1181, 1, 0, 0, 0, 138, 1194, 1, 0, 0, 0, 140, 1204, 1, 0, 0, 0, 142, 1208, 1, 0, 0, 0, 144, 1219, 1, 0, 0, 0, 146, 1229, 1, 0, 0, 0, 148, 1232, 1, 0, 0, 0, 150, 1245, 1, 0, 0, 0, 152, 1247, 1, 0, 0, 0, 154, 1249, 1, 0, 0, 0, 156, 1251, 1, 0, 0, 0, 158, 1255, 1, 0, 0, 0, 160, 1260, 1, 0, 0, 0, 162, 1262, 1, 0, 0, 0, 164, 1266, 1, 0, 0, 0, 166, 1272, 1, 0, 0, 0, 168, 1274, 1, 0, 0, 0, 170, 1288, 1, 0, 0, 0, 172, 1290, 1, 0, 0, 0, 174, 1304, 1, 0, 0, 0, 176, 178, 3, 2, 1, 0, 177, 176, 1, 0, 0, 0, 178, 181, 1, 0, 0, 0, 179, 177, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 182, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 182, 183, 5, 0, 0, 1, 183, 1, 1, 0, 0, 0, 184, 187, 3, 6, 3, 0, 185, 187, 3, 10, 5, 0, 186, 184, 1, 0, 0, 0, 186, 185, 1, 0, 0, 0, 187, 3, 1, 0, 0, 0, 188, 189, 3, 116, 58, 0, 189, 5, 1, 0, 0, 0, 190, 191, 5, 52, 0, 0, 191, 195, 3, 160, 80, 0, 192, 193, 5, 115, 0, 0, 193, 194, 5, 122, 0, 0, 194, 196, 3, 4, 2, 0, 195, 192, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 202, 3, 160, 80, 0, 198, 199, 5, 116, 0, 0, 199, 201, 3, 160, 80, 0, 200, 198, 1, 0, 0, 0, 201, 204, 1, 0, 0, 0, 202, 200, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 206, 1, 0, 0, 0, 204, 202, 1, 0, 0, 0, 205, 207, 5, 116, 0, 0, 206, 205, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 9, 1, 0, 0, 0, 208, 221, 3, 12, 6, 0, 209, 221, 3, 14, 7, 0, 210, 221, 3, 18, 9, 0, 211, 221, 3, 20, 10, 0, 212, 221, 3, 22, 11, 0, 213, 221, 3, 26, 13, 0, 214, 221, 3, 24, 12, 0, 215, 221, 3, 28, 14, 0, 216, 221, 3, 30, 15, 0, 217, 221, 3, 36, 18, 0, 218, 221, 3, 32, 16, 0, 219, 221, 3, 34, 17, 0, 220, 208, 1, 0, 0, 0, 220, 209, 1, 0, 0, 0, 220, 210, 1, 0, 0, 0, 220, 211, 1, 0, 0, 0, 220, 212, 1, 0, 0, 0, 220, 213, 1, 0, 0, 0, 220, 214, 1, 0, 0, 0, 220, 215, 1, 0, 0, 0, 220, 216, 1, 0, 0, 0, 220, 217, 1, 0, 0, 0, 220, 218, 1, 0, 0, 0, 220, 219, 1, 0, 0, 0, 221, 11, 1, 0, 0, 0, 222, 224, 5, 72, 0, 0, 223, 225, 3, 4, 2, 0, 224, 223, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 227, 1, 0, 0, 0, 226, 228, 5, 150, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 13, 1, 0, 0, 0, 229, 231, 5, 84, 0, 0, 230, 232, 3, 4, 2, 0, 231, 230, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 234, 1, 0, 0, 0, 233, 235, 5, 150, 0, 0, 234, 233, 1, 0, 0, 0, 234, 235, 1, 0, 0, 0, 235, 15, 1, 0, 0, 0, 236, 245, 5, 14, 0, 0, 237, 238, 5, 130, 0, 0, 238, 241, 3, 160, 80, 0, 239, 240, 5, 115, 0, 0, 240, 242, 3, 160, 80, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 244, 5, 149, 0, 0, 244, 246, 1, 0, 0, 0, 245, 237, 1, 0, 0, 0, 245, 246, 1, 0, 0, 0, 246, 247, 1, 0, 0, 0, 247, 248, 3, 36, 18, 0, 248, 17, 1, 0, 0, 0, 249, 250, 5, 93, 0, 0, 250, 254, 3, 36, 18, 0, 251, 253, 3, 16, 8, 0, 252, 251, 1, 0, 0, 0, 253, 256, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 254, 255, 1, 0, 0, 0, 255, 259, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 257, 258, 5, 29, 0, 0, 258, 260, 3, 36, 18, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 19, 1, 0, 0, 0, 261, 262, 5, 40, 0, 0, 262, 263, 5, 130, 0, 0, 263, 264, 3, 4, 2, 0, 264, 265, 5, 149, 0, 0, 265, 268, 3, 10, 5, 0, 266, 267, 5, 25, 0, 0, 267, 269, 3, 10, 5, 0, 268, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 21, 1, 0, 0, 0, 270, 271, 5, 100, 0, 0, 271, 272, 5, 130, 0, 0, 272, 273, 3, 4, 2, 0, 273, 274, 5, 149, 0, 0, 274, 276, 3, 10, 5, 0, 275, 277, 5, 150, 0, 0, 276, 275, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 23, 1, 0, 0, 0, 278, 279, 5, 33, 0, 0, 279, 283, 5, 130, 0, 0, 280, 284, 3, 6, 3, 0, 281, 284, 3, 30, 15, 0, 282, 284, 3, 4, 2, 0, 283, 280, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 287, 5, 150, 0, 0, 286, 288, 3, 4, 2, 0, 287, 286, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 293, 5, 150, 0, 0, 290, 294, 3, 6, 3, 0, 291, 294, 3, 30, 15, 0, 292, 294, 3, 4, 2, 0, 293, 290, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 293, 292, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 295, 1, 0, 0, 0, 295, 296, 5, 149, 0, 0, 296, 298, 3, 10, 5, 0, 297, 299, 5, 150, 0, 0, 298, 297, 1, 0, 0, 0, 298, 299, 1, 0, 0, 0, 299, 25, 1, 0, 0, 0, 300, 301, 5, 33, 0, 0, 301, 302, 5, 130, 0, 0, 302, 303, 5, 52, 0, 0, 303, 306, 3, 160, 80, 0, 304, 305, 5, 116, 0, 0, 305, 307, 3, 160, 80, 0, 306, 304, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 309, 5, 42, 0, 0, 309, 310, 3, 4, 2, 0, 310, 311, 5, 149, 0, 0, 311, 313, 3, 10, 5, 0, 312, 314, 5, 150, 0, 0, 313, 312, 1, 0, 0, 0, 313, 314, 1, 0, 0, 0, 314, 27, 1, 0, 0, 0, 315, 316, 5, 31, 0, 0, 316, 317, 3, 160, 80, 0, 317, 319, 5, 130, 0, 0, 318, 320, 3, 8, 4, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 149, 0, 0, 322, 323, 3, 36, 18, 0, 323, 29, 1, 0, 0, 0, 324, 325, 3, 4, 2, 0, 325, 326, 5, 115, 0, 0, 326, 327, 5, 122, 0, 0, 327, 328, 3, 4, 2, 0, 328, 31, 1, 0, 0, 0, 329, 331, 3, 4, 2, 0, 330, 332, 5, 150, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 33, 1, 0, 0, 0, 333, 334, 5, 150, 0, 0, 334, 35, 1, 0, 0, 0, 335, 339, 5, 128, 0, 0, 336, 338, 3, 2, 1, 0, 337, 336, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 342, 1, 0, 0, 0, 341, 339, 1, 0, 0, 0, 342, 343, 5, 147, 0, 0, 343, 37, 1, 0, 0, 0, 344, 345, 3, 4, 2, 0, 345, 346, 5, 115, 0, 0, 346, 347, 3, 4, 2, 0, 347, 39, 1, 0, 0, 0, 348, 353, 3, 38, 19, 0, 349, 350, 5, 116, 0, 0, 350, 352, 3, 38, 19, 0, 351, 349, 1, 0, 0, 0, 352, 355, 1, 0, 0, 0, 353, 351, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 356, 358, 5, 116, 0, 0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 41, 1, 0, 0, 0, 359, 363, 3, 44, 22, 0, 360, 363, 3, 48, 24, 0, 361, 363, 3, 124, 62, 0, 362, 359, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 365, 5, 0, 0, 1, 365, 43, 1, 0, 0, 0, 366, 372, 3, 46, 23, 0, 367, 368, 5, 95, 0, 0, 368, 369, 5, 1, 0, 0, 369, 371, 3, 46, 23, 0, 370, 367, 1, 0, 0, 0, 371, 374, 1, 0, 0, 0, 372, 370, 1, 0, 0, 0, 372, 373, 1, 0, 0, 0, 373, 45, 1, 0, 0, 0, 374, 372, 1, 0, 0, 0, 375, 382, 3, 48, 24, 0, 376, 377, 5, 130, 0, 0, 377, 378, 3, 44, 22, 0, 378, 379, 5, 149, 0, 0, 379, 382, 1, 0, 0, 0, 380, 382, 3, 164, 82, 0, 381, 375, 1, 0, 0, 0, 381, 376, 1, 0, 0, 0, 381, 380, 1, 0, 0, 0, 382, 47, 1, 0, 0, 0, 383, 385, 3, 50, 25, 0, 384, 383, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 5, 79, 0, 0, 387, 389, 5, 24, 0, 0, 388, 387, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 391, 1, 0, 0, 0, 390, 392, 3, 52, 26, 0, 391, 390, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 393, 1, 0, 0, 0, 393, 395, 3, 114, 57, 0, 394, 396, 3, 54, 27, 0, 395, 394, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 398, 1, 0, 0, 0, 397, 399, 3, 56, 28, 0, 398, 397, 1, 0, 0, 0, 398, 399, 1, 0, 0, 0, 399, 401, 1, 0, 0, 0, 400, 402, 3, 60, 30, 0, 401, 400, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 404, 1, 0, 0, 0, 403, 405, 3, 62, 31, 0, 404, 403, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 408, 3, 64, 32, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 102, 0, 0, 410, 412, 7, 0, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 102, 0, 0, 414, 416, 5, 89, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 418, 1, 0, 0, 0, 417, 419, 3, 66, 33, 0, 418, 417, 1, 0, 0, 0, 418, 419, 1, 0, 0, 0, 419, 421, 1, 0, 0, 0, 420, 422, 3, 58, 29, 0, 421, 420, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 425, 3, 68, 34, 0, 424, 423, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 428, 1, 0, 0, 0, 426, 429, 3, 72, 36, 0, 427, 429, 3, 74, 37, 0, 428, 426, 1, 0, 0, 0, 428, 427, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 431, 1, 0, 0, 0, 430, 432, 3, 76, 38, 0, 431, 430, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 49, 1, 0, 0, 0, 433, 434, 5, 102, 0, 0, 434, 435, 3, 128, 64, 0, 435, 51, 1, 0, 0, 0, 436, 437, 5, 88, 0, 0, 437, 440, 5, 108, 0, 0, 438, 439, 5, 102, 0, 0, 439, 441, 5, 85, 0, 0, 440, 438, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0, 441, 53, 1, 0, 0, 0, 442, 443, 5, 34, 0, 0, 443, 444, 3, 78, 39, 0, 444, 55, 1, 0, 0, 0, 445, 447, 7, 1, 0, 0, 446, 445, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 449, 5, 5, 0, 0, 449, 450, 5, 47, 0, 0, 450, 451, 3, 114, 57, 0, 451, 57, 1, 0, 0, 0, 452, 453, 5, 101, 0, 0, 453, 454, 3, 160, 80, 0, 454, 455, 5, 6, 0, 0, 455, 456, 5, 130, 0, 0, 456, 457, 3, 98, 49, 0, 457, 467, 5, 149, 0, 0, 458, 459, 5, 116, 0, 0, 459, 460, 3, 160, 80, 0, 460, 461, 5, 6, 0, 0, 461, 462, 5, 130, 0, 0, 462, 463, 3, 98, 49, 0, 463, 464, 5, 149, 0, 0, 464, 466, 1, 0, 0, 0, 465, 458, 1, 0, 0, 0, 466, 469, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0, 0, 0, 468, 59, 1, 0, 0, 0, 469, 467, 1, 0, 0, 0, 470, 471, 5, 69, 0, 0, 471, 472, 3, 116, 58, 0, 472, 61, 1, 0, 0, 0, 473, 474, 5, 99, 0, 0, 474, 475, 3, 116, 58, 0, 475, 63, 1, 0, 0, 0, 476, 477, 5, 36, 0, 0, 477, 484, 5, 11, 0, 0, 478, 479, 7, 0, 0, 0, 479, 480, 5, 130, 0, 0, 480, 481, 3, 114, 57, 0, 481, 482, 5, 149, 0, 0, 482, 485, 1, 0, 0, 0, 483, 485, 3, 114, 57, 0, 484, 478, 1, 0, 0, 0, 484, 483, 1, 0, 0, 0, 485, 65, 1, 0, 0, 0, 486, 487, 5, 37, 0, 0, 487, 488, 3, 116, 58, 0, 488, 67, 1, 0, 0, 0, 489, 490, 5, 64, 0, 0, 490, 491, 5, 11, 0, 0, 491, 492, 3, 88, 44, 0, 492, 69, 1, 0, 0, 0, 493, 494, 5, 64, 0, 0, 494, 495, 5, 11, 0, 0, 495, 496, 3, 114, 57, 0, 496, 71, 1, 0, 0, 0, 497, 498, 5, 54, 0, 0, 498, 501, 3, 116, 58, 0, 499, 500, 5, 116, 0, 0, 500, 502, 3, 116, 58, 0, 501, 499, 1, 0, 0, 0, 501, 502, 1, 0, 0, 0, 502, 507, 1, 0, 0, 0, 503, 504, 5, 102, 0, 0, 504, 508, 5, 85, 0, 0, 505, 506, 5, 11, 0, 0, 506, 508, 3, 114, 57, 0, 507, 503, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 527, 1, 0, 0, 0, 509, 510, 5, 54, 0, 0, 510, 513, 3, 116, 58, 0, 511, 512, 5, 102, 0, 0, 512, 514, 5, 85, 0, 0, 513, 511, 1, 0, 0, 0, 513, 514, 1, 0, 0, 0, 514, 515, 1, 0, 0, 0, 515, 516, 5, 61, 0, 0, 516, 517, 3, 116, 58, 0, 517, 527, 1, 0, 0, 0, 518, 519, 5, 54, 0, 0, 519, 520, 3, 116, 58, 0, 520, 521, 5, 61, 0, 0, 521, 524, 3, 116, 58, 0, 522, 523, 5, 11, 0, 0, 523, 525, 3, 114, 57, 0, 524, 522, 1, 0, 0, 0, 524, 525, 1, 0, 0, 0, 525, 527, 1, 0, 0, 0, 526, 497, 1, 0, 0, 0, 526, 509, 1, 0, 0, 0, 526, 518, 1, 0, 0, 0, 527, 73, 1, 0, 0, 0, 528, 529, 5, 61, 0, 0, 529, 530, 3, 116, 58, 0, 530, 75, 1, 0, 0, 0, 531, 532, 5, 81, 0, 0, 532, 533, 3, 94, 47, 0, 533, 77, 1, 0, 0, 0, 534, 535, 6, 39, -1, 0, 535, 537, 3, 136, 68, 0, 536, 538, 5, 28, 0, 0, 537, 536, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 540, 1, 0, 0, 0, 539, 541, 3, 86, 43, 0, 540, 539, 1, 0, 0, 0, 540, 541, 1, 0, 0, 0, 541, 547, 1, 0, 0, 0, 542, 543, 5, 130, 0, 0, 543, 544, 3, 78, 39, 0, 544, 545, 5, 149, 0, 0, 545, 547, 1, 0, 0, 0, 546, 534, 1, 0, 0, 0, 546, 542, 1, 0, 0, 0, 547, 562, 1, 0, 0, 0, 548, 549, 10, 3, 0, 0, 549, 550, 3, 82, 41, 0, 550, 551, 3, 78, 39, 4, 551, 561, 1, 0, 0, 0, 552, 554, 10, 4, 0, 0, 553, 555, 3, 80, 40, 0, 554, 553, 1, 0, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 5, 47, 0, 0, 557, 558, 3, 78, 39, 0, 558, 559, 3, 84, 42, 0, 559, 561, 1, 0, 0, 0, 560, 548, 1, 0, 0, 0, 560, 552, 1, 0, 0, 0, 561, 564, 1, 0, 0, 0, 562, 560, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 79, 1, 0, 0, 0, 564, 562, 1, 0, 0, 0, 565, 567, 7, 2, 0, 0, 566, 565, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 575, 5, 44, 0, 0, 569, 571, 5, 44, 0, 0, 570, 572, 7, 2, 0, 0, 571, 570, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 575, 1, 0, 0, 0, 573, 575, 7, 2, 0, 0, 574, 566, 1, 0, 0, 0, 574, 569, 1, 0, 0, 0, 574, 573, 1, 0, 0, 0, 575, 609, 1, 0, 0, 0, 576, 578, 7, 3, 0, 0, 577, 576, 1, 0, 0, 0, 577, 578, 1, 0, 0, 0, 578, 579, 1, 0, 0, 0, 579, 581, 7, 4, 0, 0, 580, 582, 5, 65, 0, 0, 581, 580, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 591, 1, 0, 0, 0, 583, 585, 7, 4, 0, 0, 584, 586, 5, 65, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 588, 1, 0, 0, 0, 587, 589, 7, 3, 0, 0, 588, 587, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 591, 1, 0, 0, 0, 590, 577, 1, 0, 0, 0, 590, 583, 1, 0, 0, 0, 591, 609, 1, 0, 0, 0, 592, 594, 7, 5, 0, 0, 593, 592, 1, 0, 0, 0, 593, 594, 1, 0, 0, 0, 594, 595, 1, 0, 0, 0, 595, 597, 5, 35, 0, 0, 596, 598, 5, 65, 0, 0, 597, 596, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 607, 1, 0, 0, 0, 599, 601, 5, 35, 0, 0, 600, 602, 5, 65, 0, 0, 601, 600, 1, 0, 0, 0, 601, 602, 1, 0, 0, 0, 602, 604, 1, 0, 0, 0, 603, 605, 7, 5, 0, 0, 604, 603, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 607, 1, 0, 0, 0, 606, 593, 1, 0, 0, 0, 606, 599, 1, 0, 0, 0, 607, 609, 1, 0, 0, 0, 608, 574, 1, 0, 0, 0, 608, 590, 1, 0, 0, 0, 608, 606, 1, 0, 0, 0, 609, 81, 1, 0, 0, 0, 610, 611, 5, 17, 0, 0, 611, 614, 5, 47, 0, 0, 612, 614, 5, 116, 0, 0, 613, 610, 1, 0, 0, 0, 613, 612, 1, 0, 0, 0, 614, 83, 1, 0, 0, 0, 615, 616, 5, 62, 0, 0, 616, 625, 3, 114, 57, 0, 617, 618, 5, 96, 0, 0, 618, 619, 5, 130, 0, 0, 619, 620, 3, 114, 57, 0, 620, 621, 5, 149, 0, 0, 621, 625, 1, 0, 0, 0, 622, 623, 5, 96, 0, 0, 623, 625, 3, 114, 57, 0, 624, 615, 1, 0, 0, 0, 624, 617, 1, 0, 0, 0, 624, 622, 1, 0, 0, 0, 625, 85, 1, 0, 0, 0, 626, 627, 5, 77, 0, 0, 627, 630, 3, 92, 46, 0, 628, 629, 5, 61, 0, 0, 629, 631, 3, 92, 46, 0, 630, 628, 1, 0, 0, 0, 630, 631, 1, 0, 0, 0, 631, 87, 1, 0, 0, 0, 632, 637, 3, 90, 45, 0, 633, 634, 5, 116, 0, 0, 634, 636, 3, 90, 45, 0, 635, 633, 1, 0, 0, 0, 636, 639, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 89, 1, 0, 0, 0, 639, 637, 1, 0, 0, 0, 640, 642, 3, 116, 58, 0, 641, 643, 7, 6, 0, 0, 642, 641, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 646, 1, 0, 0, 0, 644, 645, 5, 60, 0, 0, 645, 647, 7, 7, 0, 0, 646, 644, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 650, 1, 0, 0, 0, 648, 649, 5, 16, 0, 0, 649, 651, 5, 110, 0, 0, 650, 648, 1, 0, 0, 0, 650, 651, 1, 0, 0, 0, 651, 91, 1, 0, 0, 0, 652, 659, 3, 164, 82, 0, 653, 656, 3, 148, 74, 0, 654, 655, 5, 151, 0, 0, 655, 657, 3, 148, 74, 0, 656, 654, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 659, 1, 0, 0, 0, 658, 652, 1, 0, 0, 0, 658, 653, 1, 0, 0, 0, 659, 93, 1, 0, 0, 0, 660, 665, 3, 96, 48, 0, 661, 662, 5, 116, 0, 0, 662, 664, 3, 96, 48, 0, 663, 661, 1, 0, 0, 0, 664, 667, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 95, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 668, 669, 3, 160, 80, 0, 669, 670, 5, 122, 0, 0, 670, 671, 3, 150, 75, 0, 671, 97, 1, 0, 0, 0, 672, 674, 3, 100, 50, 0, 673, 672, 1, 0, 0, 0, 673, 674, 1, 0, 0, 0, 674, 676, 1, 0, 0, 0, 675, 677, 3, 102, 51, 0, 676, 675, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 679, 1, 0, 0, 0, 678, 680, 3, 104, 52, 0, 679, 678, 1, 0, 0, 0, 679, 680, 1, 0, 0, 0, 680, 99, 1, 0, 0, 0, 681, 682, 5, 67, 0, 0, 682, 683, 5, 11, 0, 0, 683, 684, 3, 114, 57, 0, 684, 101, 1, 0, 0, 0, 685, 686, 5, 64, 0, 0, 686, 687, 5, 11, 0, 0, 687, 688, 3, 88, 44, 0, 688, 103, 1, 0, 0, 0, 689, 690, 7, 8, 0, 0, 690, 691, 3, 106, 53, 0, 691, 105, 1, 0, 0, 0, 692, 699, 3, 108, 54, 0, 693, 694, 5, 9, 0, 0, 694, 695, 3, 108, 54, 0, 695, 696, 5, 2, 0, 0, 696, 697, 3, 108, 54, 0, 697, 699, 1, 0, 0, 0, 698, 692, 1, 0, 0, 0, 698, 693, 1, 0, 0, 0, 699, 107, 1, 0, 0, 0, 700, 701, 5, 19, 0, 0, 701, 713, 5, 75, 0, 0, 702, 703, 5, 94, 0, 0, 703, 713, 5, 68, 0, 0, 704, 705, 5, 94, 0, 0, 705, 713, 5, 32, 0, 0, 706, 707, 3, 148, 74, 0, 707, 708, 5, 68, 0, 0, 708, 713, 1, 0, 0, 0, 709, 710, 3, 148, 74, 0, 710, 711, 5, 32, 0, 0, 711, 713, 1, 0, 0, 0, 712, 700, 1, 0, 0, 0, 712, 702, 1, 0, 0, 0, 712, 704, 1, 0, 0, 0, 712, 706, 1, 0, 0, 0, 712, 709, 1, 0, 0, 0, 713, 109, 1, 0, 0, 0, 714, 715, 3, 116, 58, 0, 715, 716, 5, 0, 0, 1, 716, 111, 1, 0, 0, 0, 717, 774, 3, 160, 80, 0, 718, 719, 3, 160, 80, 0, 719, 720, 5, 130, 0, 0, 720, 721, 3, 160, 80, 0, 721, 728, 3, 112, 56, 0, 722, 723, 5, 116, 0, 0, 723, 724, 3, 160, 80, 0, 724, 725, 3, 112, 56, 0, 725, 727, 1, 0, 0, 0, 726, 722, 1, 0, 0, 0, 727, 730, 1, 0, 0, 0, 728, 726, 1, 0, 0, 0, 728, 729, 1, 0, 0, 0, 729, 732, 1, 0, 0, 0, 730, 728, 1, 0, 0, 0, 731, 733, 5, 116, 0, 0, 732, 731, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 5, 149, 0, 0, 735, 774, 1, 0, 0, 0, 736, 737, 3, 160, 80, 0, 737, 738, 5, 130, 0, 0, 738, 743, 3, 162, 81, 0, 739, 740, 5, 116, 0, 0, 740, 742, 3, 162, 81, 0, 741, 739, 1, 0, 0, 0, 742, 745, 1, 0, 0, 0, 743, 741, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 747, 1, 0, 0, 0, 745, 743, 1, 0, 0, 0, 746, 748, 5, 116, 0, 0, 747, 746, 1, 0, 0, 0, 747, 748, 1, 0, 0, 0, 748, 749, 1, 0, 0, 0, 749, 750, 5, 149, 0, 0, 750, 774, 1, 0, 0, 0, 751, 752, 3, 160, 80, 0, 752, 753, 5, 130, 0, 0, 753, 758, 3, 112, 56, 0, 754, 755, 5, 116, 0, 0, 755, 757, 3, 112, 56, 0, 756, 754, 1, 0, 0, 0, 757, 760, 1, 0, 0, 0, 758, 756, 1, 0, 0, 0, 758, 759, 1, 0, 0, 0, 759, 762, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 763, 5, 116, 0, 0, 762, 761, 1, 0, 0, 0, 762, 763, 1, 0, 0, 0, 763, 764, 1, 0, 0, 0, 764, 765, 5, 149, 0, 0, 765, 774, 1, 0, 0, 0, 766, 767, 3, 160, 80, 0, 767, 769, 5, 130, 0, 0, 768, 770, 3, 114, 57, 0, 769, 768, 1, 0, 0, 0, 769, 770, 1, 0, 0, 0, 770, 771, 1, 0, 0, 0, 771, 772, 5, 149, 0, 0, 772, 774, 1, 0, 0, 0, 773, 717, 1, 0, 0, 0, 773, 718, 1, 0, 0, 0, 773, 736, 1, 0, 0, 0, 773, 751, 1, 0, 0, 0, 773, 766, 1, 0, 0, 0, 774, 113, 1, 0, 0, 0, 775, 780, 3, 116, 58, 0, 776, 777, 5, 116, 0, 0, 777, 779, 3, 116, 58, 0, 778, 776, 1, 0, 0, 0, 779, 782, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 780, 781, 1, 0, 0, 0, 781, 784, 1, 0, 0, 0, 782, 780, 1, 0, 0, 0, 783, 785, 5, 116, 0, 0, 784, 783, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 115, 1, 0, 0, 0, 786, 787, 6, 58, -1, 0, 787, 789, 5, 12, 0, 0, 788, 790, 3, 116, 58, 0, 789, 788, 1, 0, 0, 0, 789, 790, 1, 0, 0, 0, 790, 796, 1, 0, 0, 0, 791, 792, 5, 98, 0, 0, 792, 793, 3, 116, 58, 0, 793, 794, 5, 83, 0, 0, 794, 795, 3, 116, 58, 0, 795, 797, 1, 0, 0, 0, 796, 791, 1, 0, 0, 0, 797, 798, 1, 0, 0, 0, 798, 796, 1, 0, 0, 0, 798, 799, 1, 0, 0, 0, 799, 802, 1, 0, 0, 0, 800, 801, 5, 25, 0, 0, 801, 803, 3, 116, 58, 0, 802, 800, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 1, 0, 0, 0, 804, 805, 5, 26, 0, 0, 805, 936, 1, 0, 0, 0, 806, 807, 5, 13, 0, 0, 807, 808, 5, 130, 0, 0, 808, 809, 3, 116, 58, 0, 809, 810, 5, 6, 0, 0, 810, 811, 3, 112, 56, 0, 811, 812, 5, 149, 0, 0, 812, 936, 1, 0, 0, 0, 813, 814, 5, 20, 0, 0, 814, 936, 5, 110, 0, 0, 815, 816, 5, 45, 0, 0, 816, 817, 3, 116, 58, 0, 817, 818, 3, 152, 76, 0, 818, 936, 1, 0, 0, 0, 819, 820, 5, 82, 0, 0, 820, 821, 5, 130, 0, 0, 821, 822, 3, 116, 58, 0, 822, 823, 5, 34, 0, 0, 823, 826, 3, 116, 58, 0, 824, 825, 5, 33, 0, 0, 825, 827, 3, 116, 58, 0, 826, 824, 1, 0, 0, 0, 826, 827, 1, 0, 0, 0, 827, 828, 1, 0, 0, 0, 828, 829, 5, 149, 0, 0, 829, 936, 1, 0, 0, 0, 830, 831, 5, 86, 0, 0, 831, 936, 5, 110, 0, 0, 832, 833, 5, 91, 0, 0, 833, 834, 5, 130, 0, 0, 834, 835, 7, 9, 0, 0, 835, 836, 3, 166, 83, 0, 836, 837, 5, 34, 0, 0, 837, 838, 3, 116, 58, 0, 838, 839, 5, 149, 0, 0, 839, 936, 1, 0, 0, 0, 840, 841, 3, 160, 80, 0, 841, 843, 5, 130, 0, 0, 842, 844, 3, 114, 57, 0, 843, 842, 1, 0, 0, 0, 843, 844, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 846, 5, 149, 0, 0, 846, 855, 1, 0, 0, 0, 847, 849, 5, 130, 0, 0, 848, 850, 5, 24, 0, 0, 849, 848, 1, 0, 0, 0, 849, 850, 1, 0, 0, 0, 850, 852, 1, 0, 0, 0, 851, 853, 3, 118, 59, 0, 852, 851, 1, 0, 0, 0, 852, 853, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854, 856, 5, 149, 0, 0, 855, 847, 1, 0, 0, 0, 855, 856, 1, 0, 0, 0, 856, 857, 1, 0, 0, 0, 857, 858, 5, 66, 0, 0, 858, 859, 5, 130, 0, 0, 859, 860, 3, 98, 49, 0, 860, 861, 5, 149, 0, 0, 861, 936, 1, 0, 0, 0, 862, 863, 3, 160, 80, 0, 863, 865, 5, 130, 0, 0, 864, 866, 3, 114, 57, 0, 865, 864, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 868, 5, 149, 0, 0, 868, 877, 1, 0, 0, 0, 869, 871, 5, 130, 0, 0, 870, 872, 5, 24, 0, 0, 871, 870, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 874, 1, 0, 0, 0, 873, 875, 3, 118, 59, 0, 874, 873, 1, 0, 0, 0, 874, 875, 1, 0, 0, 0, 875, 876, 1, 0, 0, 0, 876, 878, 5, 149, 0, 0, 877, 869, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 880, 5, 66, 0, 0, 880, 881, 3, 160, 80, 0, 881, 936, 1, 0, 0, 0, 882, 888, 3, 160, 80, 0, 883, 885, 5, 130, 0, 0, 884, 886, 3, 114, 57, 0, 885, 884, 1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 889, 5, 149, 0, 0, 888, 883, 1, 0, 0, 0, 888, 889, 1, 0, 0, 0, 889, 890, 1, 0, 0, 0, 890, 892, 5, 130, 0, 0, 891, 893, 5, 24, 0, 0, 892, 891, 1, 0, 0, 0, 892, 893, 1, 0, 0, 0, 893, 895, 1, 0, 0, 0, 894, 896, 3, 118, 59, 0, 895, 894, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 897, 1, 0, 0, 0, 897, 898, 5, 149, 0, 0, 898, 936, 1, 0, 0, 0, 899, 936, 3, 124, 62, 0, 900, 936, 3, 168, 84, 0, 901, 936, 3, 150, 75, 0, 902, 903, 5, 118, 0, 0, 903, 936, 3, 116, 58, 19, 904, 905, 5, 58, 0, 0, 905, 936, 3, 116, 58, 13, 906, 907, 3, 140, 70, 0, 907, 908, 5, 120, 0, 0, 908, 910, 1, 0, 0, 0, 909, 906, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 1, 0, 0, 0, 911, 936, 5, 112, 0, 0, 912, 913, 5, 130, 0, 0, 913, 914, 3, 44, 22, 0, 914, 915, 5, 149, 0, 0, 915, 936, 1, 0, 0, 0, 916, 917, 5, 130, 0, 0, 917, 918, 3, 116, 58, 0, 918, 919, 5, 149, 0, 0, 919, 936, 1, 0, 0, 0, 920, 921, 5, 130, 0, 0, 921, 922, 3, 114, 57, 0, 922, 923, 5, 149, 0, 0, 923, 936, 1, 0, 0, 0, 924, 926, 5, 129, 0, 0, 925, 927, 3, 114, 57, 0, 926, 925, 1, 0, 0, 0, 926, 927, 1, 0, 0, 0, 927, 928, 1, 0, 0, 0, 928, 936, 5, 148, 0, 0, 929, 931, 5, 128, 0, 0, 930, 932, 3, 40, 20, 0, 931, 930, 1, 0, 0, 0, 931, 932, 1, 0, 0, 0, 932, 933, 1, 0, 0, 0, 933, 936, 5, 147, 0, 0, 934, 936, 3, 132, 66, 0, 935, 786, 1, 0, 0, 0, 935, 806, 1, 0, 0, 0, 935, 813, 1, 0, 0, 0, 935, 815, 1, 0, 0, 0, 935, 819, 1, 0, 0, 0, 935, 830, 1, 0, 0, 0, 935, 832, 1, 0, 0, 0, 935, 840, 1, 0, 0, 0, 935, 862, 1, 0, 0, 0, 935, 882, 1, 0, 0, 0, 935, 899, 1, 0, 0, 0, 935, 900, 1, 0, 0, 0, 935, 901, 1, 0, 0, 0, 935, 902, 1, 0, 0, 0, 935, 904, 1, 0, 0, 0, 935, 909, 1, 0, 0, 0, 935, 912, 1, 0, 0, 0, 935, 916, 1, 0, 0, 0, 935, 920, 1, 0, 0, 0, 935, 924, 1, 0, 0, 0, 935, 929, 1, 0, 0, 0, 935, 934, 1, 0, 0, 0, 936, 1041, 1, 0, 0, 0, 937, 941, 10, 18, 0, 0, 938, 942, 5, 112, 0, 0, 939, 942, 5, 151, 0, 0, 940, 942, 5, 138, 0, 0, 941, 938, 1, 0, 0, 0, 941, 939, 1, 0, 0, 0, 941, 940, 1, 0, 0, 0, 942, 943, 1, 0, 0, 0, 943, 1040, 3, 116, 58, 19, 944, 948, 10, 17, 0, 0, 945, 949, 5, 139, 0, 0, 946, 949, 5, 118, 0, 0, 947, 949, 5, 117, 0, 0, 948, 945, 1, 0, 0, 0, 948, 946, 1, 0, 0, 0, 948, 947, 1, 0, 0, 0, 949, 950, 1, 0, 0, 0, 950, 1040, 3, 116, 58, 18, 951, 976, 10, 16, 0, 0, 952, 977, 5, 121, 0, 0, 953, 977, 5, 122, 0, 0, 954, 977, 5, 133, 0, 0, 955, 977, 5, 131, 0, 0, 956, 977, 5, 132, 0, 0, 957, 977, 5, 123, 0, 0, 958, 977, 5, 124, 0, 0, 959, 961, 5, 58, 0, 0, 960, 959, 1, 0, 0, 0, 960, 961, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 964, 5, 42, 0, 0, 963, 965, 5, 15, 0, 0, 964, 963, 1, 0, 0, 0, 964, 965, 1, 0, 0, 0, 965, 977, 1, 0, 0, 0, 966, 968, 5, 58, 0, 0, 967, 966, 1, 0, 0, 0, 967, 968, 1, 0, 0, 0, 968, 969, 1, 0, 0, 0, 969, 977, 7, 10, 0, 0, 970, 977, 5, 145, 0, 0, 971, 977, 5, 146, 0, 0, 972, 977, 5, 135, 0, 0, 973, 977, 5, 126, 0, 0, 974, 977, 5, 127, 0, 0, 975, 977, 5, 134, 0, 0, 976, 952, 1, 0, 0, 0, 976, 953, 1, 0, 0, 0, 976, 954, 1, 0, 0, 0, 976, 955, 1, 0, 0, 0, 976, 956, 1, 0, 0, 0, 976, 957, 1, 0, 0, 0, 976, 958, 1, 0, 0, 0, 976, 960, 1, 0, 0, 0, 976, 967, 1, 0, 0, 0, 976, 970, 1, 0, 0, 0, 976, 971, 1, 0, 0, 0, 976, 972, 1, 0, 0, 0, 976, 973, 1, 0, 0, 0, 976, 974, 1, 0, 0, 0, 976, 975, 1, 0, 0, 0, 977, 978, 1, 0, 0, 0, 978, 1040, 3, 116, 58, 17, 979, 980, 10, 14, 0, 0, 980, 981, 5, 137, 0, 0, 981, 1040, 3, 116, 58, 15, 982, 983, 10, 12, 0, 0, 983, 984, 5, 2, 0, 0, 984, 1040, 3, 116, 58, 13, 985, 986, 10, 11, 0, 0, 986, 987, 5, 63, 0, 0, 987, 1040, 3, 116, 58, 12, 988, 990, 10, 10, 0, 0, 989, 991, 5, 58, 0, 0, 990, 989, 1, 0, 0, 0, 990, 991, 1, 0, 0, 0, 991, 992, 1, 0, 0, 0, 992, 993, 5, 9, 0, 0, 993, 994, 3, 116, 58, 0, 994, 995, 5, 2, 0, 0, 995, 996, 3, 116, 58, 11, 996, 1040, 1, 0, 0, 0, 997, 998, 10, 9, 0, 0, 998, 999, 5, 140, 0, 0, 999, 1000, 3, 116, 58, 0, 1000, 1001, 5, 115, 0, 0, 1001, 1002, 3, 116, 58, 9, 1002, 1040, 1, 0, 0, 0, 1003, 1004, 10, 25, 0, 0, 1004, 1005, 5, 129, 0, 0, 1005, 1006, 3, 116, 58, 0, 1006, 1007, 5, 148, 0, 0, 1007, 1040, 1, 0, 0, 0, 1008, 1009, 10, 24, 0, 0, 1009, 1010, 5, 120, 0, 0, 1010, 1040, 5, 108, 0, 0, 1011, 1012, 10, 23, 0, 0, 1012, 1013, 5, 120, 0, 0, 1013, 1040, 3, 160, 80, 0, 1014, 1015, 10, 22, 0, 0, 1015, 1016, 5, 136, 0, 0, 1016, 1017, 5, 129, 0, 0, 1017, 1018, 3, 116, 58, 0, 1018, 1019, 5, 148, 0, 0, 1019, 1040, 1, 0, 0, 0, 1020, 1021, 10, 21, 0, 0, 1021, 1022, 5, 136, 0, 0, 1022, 1040, 5, 108, 0, 0, 1023, 1024, 10, 20, 0, 0, 1024, 1025, 5, 136, 0, 0, 1025, 1040, 3, 160, 80, 0, 1026, 1027, 10, 15, 0, 0, 1027, 1029, 5, 46, 0, 0, 1028, 1030, 5, 58, 0, 0, 1029, 1028, 1, 0, 0, 0, 1029, 1030, 1, 0, 0, 0, 1030, 1031, 1, 0, 0, 0, 1031, 1040, 5, 59, 0, 0, 1032, 1037, 10, 8, 0, 0, 1033, 1034, 5, 6, 0, 0, 1034, 1038, 3, 160, 80, 0, 1035, 1036, 5, 6, 0, 0, 1036, 1038, 5, 110, 0, 0, 1037, 1033, 1, 0, 0, 0, 1037, 1035, 1, 0, 0, 0, 1038, 1040, 1, 0, 0, 0, 1039, 937, 1, 0, 0, 0, 1039, 944, 1, 0, 0, 0, 1039, 951, 1, 0, 0, 0, 1039, 979, 1, 0, 0, 0, 1039, 982, 1, 0, 0, 0, 1039, 985, 1, 0, 0, 0, 1039, 988, 1, 0, 0, 0, 1039, 997, 1, 0, 0, 0, 1039, 1003, 1, 0, 0, 0, 1039, 1008, 1, 0, 0, 0, 1039, 1011, 1, 0, 0, 0, 1039, 1014, 1, 0, 0, 0, 1039, 1020, 1, 0, 0, 0, 1039, 1023, 1, 0, 0, 0, 1039, 1026, 1, 0, 0, 0, 1039, 1032, 1, 0, 0, 0, 1040, 1043, 1, 0, 0, 0, 1041, 1039, 1, 0, 0, 0, 1041, 1042, 1, 0, 0, 0, 1042, 117, 1, 0, 0, 0, 1043, 1041, 1, 0, 0, 0, 1044, 1049, 3, 120, 60, 0, 1045, 1046, 5, 116, 0, 0, 1046, 1048, 3, 120, 60, 0, 1047, 1045, 1, 0, 0, 0, 1048, 1051, 1, 0, 0, 0, 1049, 1047, 1, 0, 0, 0, 1049, 1050, 1, 0, 0, 0, 1050, 1053, 1, 0, 0, 0, 1051, 1049, 1, 0, 0, 0, 1052, 1054, 5, 116, 0, 0, 1053, 1052, 1, 0, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 119, 1, 0, 0, 0, 1055, 1058, 3, 122, 61, 0, 1056, 1058, 3, 116, 58, 0, 1057, 1055, 1, 0, 0, 0, 1057, 1056, 1, 0, 0, 0, 1058, 121, 1, 0, 0, 0, 1059, 1060, 5, 130, 0, 0, 1060, 1065, 3, 160, 80, 0, 1061, 1062, 5, 116, 0, 0, 1062, 1064, 3, 160, 80, 0, 1063, 1061, 1, 0, 0, 0, 1064, 1067, 1, 0, 0, 0, 1065, 1063, 1, 0, 0, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1069, 1, 0, 0, 0, 1067, 1065, 1, 0, 0, 0, 1068, 1070, 5, 116, 0, 0, 1069, 1068, 1, 0, 0, 0, 1069, 1070, 1, 0, 0, 0, 1070, 1071, 1, 0, 0, 0, 1071, 1072, 5, 149, 0, 0, 1072, 1085, 1, 0, 0, 0, 1073, 1078, 3, 160, 80, 0, 1074, 1075, 5, 116, 0, 0, 1075, 1077, 3, 160, 80, 0, 1076, 1074, 1, 0, 0, 0, 1077, 1080, 1, 0, 0, 0, 1078, 1076, 1, 0, 0, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1082, 1, 0, 0, 0, 1080, 1078, 1, 0, 0, 0, 1081, 1083, 5, 116, 0, 0, 1082, 1081, 1, 0, 0, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1085, 1, 0, 0, 0, 1084, 1059, 1, 0, 0, 0, 1084, 1073, 1, 0, 0, 0, 1085, 1086, 1, 0, 0, 0, 1086, 1087, 5, 111, 0, 0, 1087, 1088, 3, 116, 58, 0, 1088, 123, 1, 0, 0, 0, 1089, 1090, 5, 132, 0, 0, 1090, 1094, 3, 160, 80, 0, 1091, 1093, 3, 126, 63, 0, 1092, 1091, 1, 0, 0, 0, 1093, 1096, 1, 0, 0, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1097, 1, 0, 0, 0, 1096, 1094, 1, 0, 0, 0, 1097, 1098, 5, 151, 0, 0, 1098, 1099, 5, 124, 0, 0, 1099, 1118, 1, 0, 0, 0, 1100, 1101, 5, 132, 0, 0, 1101, 1105, 3, 160, 80, 0, 1102, 1104, 3, 126, 63, 0, 1103, 1102, 1, 0, 0, 0, 1104, 1107, 1, 0, 0, 0, 1105, 1103, 1, 0, 0, 0, 1105, 1106, 1, 0, 0, 0, 1106, 1108, 1, 0, 0, 0, 1107, 1105, 1, 0, 0, 0, 1108, 1110, 5, 124, 0, 0, 1109, 1111, 3, 124, 62, 0, 1110, 1109, 1, 0, 0, 0, 1110, 1111, 1, 0, 0, 0, 1111, 1112, 1, 0, 0, 0, 1112, 1113, 5, 132, 0, 0, 1113, 1114, 5, 151, 0, 0, 1114, 1115, 3, 160, 80, 0, 1115, 1116, 5, 124, 0, 0, 1116, 1118, 1, 0, 0, 0, 1117, 1089, 1, 0, 0, 0, 1117, 1100, 1, 0, 0, 0, 1118, 125, 1, 0, 0, 0, 1119, 1120, 3, 160, 80, 0, 1120, 1121, 5, 122, 0, 0, 1121, 1122, 3, 166, 83, 0, 1122, 1131, 1, 0, 0, 0, 1123, 1124, 3, 160, 80, 0, 1124, 1125, 5, 122, 0, 0, 1125, 1126, 5, 128, 0, 0, 1126, 1127, 3, 116, 58, 0, 1127, 1128, 5, 147, 0, 0, 1128, 1131, 1, 0, 0, 0, 1129, 1131, 3, 160, 80, 0, 1130, 1119, 1, 0, 0, 0, 1130, 1123, 1, 0, 0, 0, 1130, 1129, 1, 0, 0, 0, 1131, 127, 1, 0, 0, 0, 1132, 1137, 3, 130, 65, 0, 1133, 1134, 5, 116, 0, 0, 1134, 1136, 3, 130, 65, 0, 1135, 1133, 1, 0, 0, 0, 1136, 1139, 1, 0, 0, 0, 1137, 1135, 1, 0, 0, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1141, 1, 0, 0, 0, 1139, 1137, 1, 0, 0, 0, 1140, 1142, 5, 116, 0, 0, 1141, 1140, 1, 0, 0, 0, 1141, 1142, 1, 0, 0, 0, 1142, 129, 1, 0, 0, 0, 1143, 1144, 3, 160, 80, 0, 1144, 1145, 5, 6, 0, 0, 1145, 1146, 5, 130, 0, 0, 1146, 1147, 3, 44, 22, 0, 1147, 1148, 5, 149, 0, 0, 1148, 1154, 1, 0, 0, 0, 1149, 1150, 3, 116, 58, 0, 1150, 1151, 5, 6, 0, 0, 1151, 1152, 3, 160, 80, 0, 1152, 1154, 1, 0, 0, 0, 1153, 1143, 1, 0, 0, 0, 1153, 1149, 1, 0, 0, 0, 1154, 131, 1, 0, 0, 0, 1155, 1163, 3, 164, 82, 0, 1156, 1157, 3, 140, 70, 0, 1157, 1158, 5, 120, 0, 0, 1158, 1160, 1, 0, 0, 0, 1159, 1156, 1, 0, 0, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1161, 1, 0, 0, 0, 1161, 1163, 3, 134, 67, 0, 1162, 1155, 1, 0, 0, 0, 1162, 1159, 1, 0, 0, 0, 1163, 133, 1, 0, 0, 0, 1164, 1169, 3, 160, 80, 0, 1165, 1166, 5, 120, 0, 0, 1166, 1168, 3, 160, 80, 0, 1167, 1165, 1, 0, 0, 0, 1168, 1171, 1, 0, 0, 0, 1169, 1167, 1, 0, 0, 0, 1169, 1170, 1, 0, 0, 0, 1170, 135, 1, 0, 0, 0, 1171, 1169, 1, 0, 0, 0, 1172, 1173, 6, 68, -1, 0, 1173, 1182, 3, 140, 70, 0, 1174, 1182, 3, 138, 69, 0, 1175, 1176, 5, 130, 0, 0, 1176, 1177, 3, 44, 22, 0, 1177, 1178, 5, 149, 0, 0, 1178, 1182, 1, 0, 0, 0, 1179, 1182, 3, 124, 62, 0, 1180, 1182, 3, 164, 82, 0, 1181, 1172, 1, 0, 0, 0, 1181, 1174, 1, 0, 0, 0, 1181, 1175, 1, 0, 0, 0, 1181, 1179, 1, 0, 0, 0, 1181, 1180, 1, 0, 0, 0, 1182, 1191, 1, 0, 0, 0, 1183, 1187, 10, 3, 0, 0, 1184, 1188, 3, 158, 79, 0, 1185, 1186, 5, 6, 0, 0, 1186, 1188, 3, 160, 80, 0, 1187, 1184, 1, 0, 0, 0, 1187, 1185, 1, 0, 0, 0, 1188, 1190, 1, 0, 0, 0, 1189, 1183, 1, 0, 0, 0, 1190, 1193, 1, 0, 0, 0, 1191, 1189, 1, 0, 0, 0, 1191, 1192, 1, 0, 0, 0, 1192, 137, 1, 0, 0, 0, 1193, 1191, 1, 0, 0, 0, 1194, 1195, 3, 160, 80, 0, 1195, 1197, 5, 130, 0, 0, 1196, 1198, 3, 142, 71, 0, 1197, 1196, 1, 0, 0, 0, 1197, 1198, 1, 0, 0, 0, 1198, 1199, 1, 0, 0, 0, 1199, 1200, 5, 149, 0, 0, 1200, 139, 1, 0, 0, 0, 1201, 1202, 3, 144, 72, 0, 1202, 1203, 5, 120, 0, 0, 1203, 1205, 1, 0, 0, 0, 1204, 1201, 1, 0, 0, 0, 1204, 1205, 1, 0, 0, 0, 1205, 1206, 1, 0, 0, 0, 1206, 1207, 3, 160, 80, 0, 1207, 141, 1, 0, 0, 0, 1208, 1213, 3, 116, 58, 0, 1209, 1210, 5, 116, 0, 0, 1210, 1212, 3, 116, 58, 0, 1211, 1209, 1, 0, 0, 0, 1212, 1215, 1, 0, 0, 0, 1213, 1211, 1, 0, 0, 0, 1213, 1214, 1, 0, 0, 0, 1214, 1217, 1, 0, 0, 0, 1215, 1213, 1, 0, 0, 0, 1216, 1218, 5, 116, 0, 0, 1217, 1216, 1, 0, 0, 0, 1217, 1218, 1, 0, 0, 0, 1218, 143, 1, 0, 0, 0, 1219, 1220, 3, 160, 80, 0, 1220, 145, 1, 0, 0, 0, 1221, 1230, 5, 106, 0, 0, 1222, 1223, 5, 120, 0, 0, 1223, 1230, 7, 11, 0, 0, 1224, 1225, 5, 108, 0, 0, 1225, 1227, 5, 120, 0, 0, 1226, 1228, 7, 11, 0, 0, 1227, 1226, 1, 0, 0, 0, 1227, 1228, 1, 0, 0, 0, 1228, 1230, 1, 0, 0, 0, 1229, 1221, 1, 0, 0, 0, 1229, 1222, 1, 0, 0, 0, 1229, 1224, 1, 0, 0, 0, 1230, 147, 1, 0, 0, 0, 1231, 1233, 7, 12, 0, 0, 1232, 1231, 1, 0, 0, 0, 1232, 1233, 1, 0, 0, 0, 1233, 1240, 1, 0, 0, 0, 1234, 1241, 3, 146, 73, 0, 1235, 1241, 5, 107, 0, 0, 1236, 1241, 5, 108, 0, 0, 1237, 1241, 5, 109, 0, 0, 1238, 1241, 5, 43, 0, 0, 1239, 1241, 5, 57, 0, 0, 1240, 1234, 1, 0, 0, 0, 1240, 1235, 1, 0, 0, 0, 1240, 1236, 1, 0, 0, 0, 1240, 1237, 1, 0, 0, 0, 1240, 1238, 1, 0, 0, 0, 1240, 1239, 1, 0, 0, 0, 1241, 149, 1, 0, 0, 0, 1242, 1246, 3, 148, 74, 0, 1243, 1246, 5, 110, 0, 0, 1244, 1246, 5, 59, 0, 0, 1245, 1242, 1, 0, 0, 0, 1245, 1243, 1, 0, 0, 0, 1245, 1244, 1, 0, 0, 0, 1246, 151, 1, 0, 0, 0, 1247, 1248, 7, 13, 0, 0, 1248, 153, 1, 0, 0, 0, 1249, 1250, 7, 14, 0, 0, 1250, 155, 1, 0, 0, 0, 1251, 1252, 7, 15, 0, 0, 1252, 157, 1, 0, 0, 0, 1253, 1256, 5, 105, 0, 0, 1254, 1256, 3, 156, 78, 0, 1255, 1253, 1, 0, 0, 0, 1255, 1254, 1, 0, 0, 0, 1256, 159, 1, 0, 0, 0, 1257, 1261, 5, 105, 0, 0, 1258, 1261, 3, 152, 76, 0, 1259, 1261, 3, 154, 77, 0, 1260, 1257, 1, 0, 0, 0, 1260, 1258, 1, 0, 0, 0, 1260, 1259, 1, 0, 0, 0, 1261, 161, 1, 0, 0, 0, 1262, 1263, 3, 166, 83, 0, 1263, 1264, 5, 122, 0, 0, 1264, 1265, 3, 148, 74, 0, 1265, 163, 1, 0, 0, 0, 1266, 1267, 5, 128, 0, 0, 1267, 1268, 3, 160, 80, 0, 1268, 1269, 5, 147, 0, 0, 1269, 165, 1, 0, 0, 0, 1270, 1273, 5, 110, 0, 0, 1271, 1273, 3, 168, 84, 0, 1272, 1270, 1, 0, 0, 0, 1272, 1271, 1, 0, 0, 0, 1273, 167, 1, 0, 0, 0, 1274, 1278, 5, 142, 0, 0, 1275, 1277, 3, 170, 85, 0, 1276, 1275, 1, 0, 0, 0, 1277, 1280, 1, 0, 0, 0, 1278, 1276, 1, 0, 0, 0, 1278, 1279, 1, 0, 0, 0, 1279, 1281, 1, 0, 0, 0, 1280, 1278, 1, 0, 0, 0, 1281, 1282, 5, 144, 0, 0, 1282, 169, 1, 0, 0, 0, 1283, 1284, 5, 157, 0, 0, 1284, 1285, 3, 116, 58, 0, 1285, 1286, 5, 147, 0, 0, 1286, 1289, 1, 0, 0, 0, 1287, 1289, 5, 156, 0, 0, 1288, 1283, 1, 0, 0, 0, 1288, 1287, 1, 0, 0, 0, 1289, 171, 1, 0, 0, 0, 1290, 1294, 5, 143, 0, 0, 1291, 1293, 3, 174, 87, 0, 1292, 1291, 1, 0, 0, 0, 1293, 1296, 1, 0, 0, 0, 1294, 1292, 1, 0, 0, 0, 1294, 1295, 1, 0, 0, 0, 1295, 1297, 1, 0, 0, 0, 1296, 1294, 1, 0, 0, 0, 1297, 1298, 5, 0, 0, 1, 1298, 173, 1, 0, 0, 0, 1299, 1300, 5, 159, 0, 0, 1300, 1301, 3, 116, 58, 0, 1301, 1302, 5, 147, 0, 0, 1302, 1305, 1, 0, 0, 0, 1303, 1305, 5, 158, 0, 0, 1304, 1299, 1, 0, 0, 0, 1304, 1303, 1, 0, 0, 0, 1305, 175, 1, 0, 0, 0, 168, 179, 186, 195, 202, 206, 220, 224, 227, 231, 234, 241, 245, 254, 259, 268, 276, 283, 287, 293, 298, 306, 313, 319, 331, 339, 353, 357, 362, 372, 381, 384, 388, 391, 395, 398, 401, 404, 407, 411, 415, 418, 421, 424, 428, 431, 440, 446, 467, 484, 501, 507, 513, 524, 526, 537, 540, 546, 554, 560, 562, 566, 571, 574, 577, 581, 585, 588, 590, 593, 597, 601, 604, 606, 608, 613, 624, 630, 637, 642, 646, 650, 656, 658, 665, 673, 676, 679, 698, 712, 728, 732, 743, 747, 758, 762, 769, 773, 780, 784, 789, 798, 802, 826, 843, 849, 852, 855, 865, 871, 874, 877, 885, 888, 892, 895, 909, 926, 931, 935, 941, 948, 960, 964, 967, 976, 990, 1029, 1037, 1039, 1041, 1049, 1053, 1057, 1065, 1069, 1078, 1082, 1084, 1094, 1105, 1110, 1117, 1130, 1137, 1141, 1153, 1159, 1162, 1169, 1181, 1187, 1191, 1197, 1204, 1213, 1217, 1227, 1229, 1232, 1240, 1245, 1255, 1260, 1272, 1278, 1288, 1294, 1304] \ No newline at end of file +[4, 1, 159, 1311, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 1, 0, 5, 0, 178, 8, 0, 10, 0, 12, 0, 181, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 187, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 196, 8, 3, 1, 4, 1, 4, 1, 4, 5, 4, 201, 8, 4, 10, 4, 12, 4, 204, 9, 4, 1, 4, 3, 4, 207, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 221, 8, 5, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 6, 3, 6, 228, 8, 6, 1, 7, 1, 7, 3, 7, 232, 8, 7, 1, 7, 3, 7, 235, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 242, 8, 8, 1, 8, 1, 8, 3, 8, 246, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 5, 9, 253, 8, 9, 10, 9, 12, 9, 256, 9, 9, 1, 9, 1, 9, 3, 9, 260, 8, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 269, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 277, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 284, 8, 12, 1, 12, 1, 12, 3, 12, 288, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 294, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 299, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 307, 8, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 314, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 320, 8, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 3, 16, 332, 8, 16, 1, 17, 1, 17, 1, 18, 1, 18, 5, 18, 338, 8, 18, 10, 18, 12, 18, 341, 9, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 352, 8, 20, 10, 20, 12, 20, 355, 9, 20, 1, 20, 3, 20, 358, 8, 20, 1, 21, 1, 21, 1, 21, 3, 21, 363, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 371, 8, 22, 10, 22, 12, 22, 374, 9, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 382, 8, 23, 1, 24, 3, 24, 385, 8, 24, 1, 24, 1, 24, 3, 24, 389, 8, 24, 1, 24, 3, 24, 392, 8, 24, 1, 24, 1, 24, 3, 24, 396, 8, 24, 1, 24, 3, 24, 399, 8, 24, 1, 24, 3, 24, 402, 8, 24, 1, 24, 3, 24, 405, 8, 24, 1, 24, 3, 24, 408, 8, 24, 1, 24, 1, 24, 3, 24, 412, 8, 24, 1, 24, 1, 24, 3, 24, 416, 8, 24, 1, 24, 3, 24, 419, 8, 24, 1, 24, 3, 24, 422, 8, 24, 1, 24, 3, 24, 425, 8, 24, 1, 24, 1, 24, 3, 24, 429, 8, 24, 1, 24, 3, 24, 432, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 441, 8, 26, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 447, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 466, 8, 29, 10, 29, 12, 29, 469, 9, 29, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 485, 8, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 502, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 508, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 514, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 525, 8, 36, 3, 36, 527, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 3, 39, 538, 8, 39, 1, 39, 3, 39, 541, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 547, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 555, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 561, 8, 39, 10, 39, 12, 39, 564, 9, 39, 1, 40, 3, 40, 567, 8, 40, 1, 40, 1, 40, 1, 40, 3, 40, 572, 8, 40, 1, 40, 3, 40, 575, 8, 40, 1, 40, 3, 40, 578, 8, 40, 1, 40, 1, 40, 3, 40, 582, 8, 40, 1, 40, 1, 40, 3, 40, 586, 8, 40, 1, 40, 3, 40, 589, 8, 40, 3, 40, 591, 8, 40, 1, 40, 3, 40, 594, 8, 40, 1, 40, 1, 40, 3, 40, 598, 8, 40, 1, 40, 1, 40, 3, 40, 602, 8, 40, 1, 40, 3, 40, 605, 8, 40, 3, 40, 607, 8, 40, 3, 40, 609, 8, 40, 1, 41, 1, 41, 1, 41, 3, 41, 614, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 625, 8, 42, 1, 43, 1, 43, 1, 43, 1, 43, 3, 43, 631, 8, 43, 1, 44, 1, 44, 1, 44, 5, 44, 636, 8, 44, 10, 44, 12, 44, 639, 9, 44, 1, 45, 1, 45, 3, 45, 643, 8, 45, 1, 45, 1, 45, 3, 45, 647, 8, 45, 1, 45, 1, 45, 3, 45, 651, 8, 45, 1, 46, 1, 46, 1, 46, 1, 46, 3, 46, 657, 8, 46, 3, 46, 659, 8, 46, 1, 47, 1, 47, 1, 47, 5, 47, 664, 8, 47, 10, 47, 12, 47, 667, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 3, 49, 674, 8, 49, 1, 49, 3, 49, 677, 8, 49, 1, 49, 3, 49, 680, 8, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 699, 8, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 3, 54, 713, 8, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 727, 8, 56, 10, 56, 12, 56, 730, 9, 56, 1, 56, 3, 56, 733, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 742, 8, 56, 10, 56, 12, 56, 745, 9, 56, 1, 56, 3, 56, 748, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 757, 8, 56, 10, 56, 12, 56, 760, 9, 56, 1, 56, 3, 56, 763, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 770, 8, 56, 1, 56, 1, 56, 3, 56, 774, 8, 56, 1, 57, 1, 57, 1, 57, 5, 57, 779, 8, 57, 10, 57, 12, 57, 782, 9, 57, 1, 57, 3, 57, 785, 8, 57, 1, 58, 1, 58, 1, 58, 3, 58, 790, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 4, 58, 797, 8, 58, 11, 58, 12, 58, 798, 1, 58, 1, 58, 3, 58, 803, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 827, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 844, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 850, 8, 58, 1, 58, 3, 58, 853, 8, 58, 1, 58, 3, 58, 856, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 866, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 872, 8, 58, 1, 58, 3, 58, 875, 8, 58, 1, 58, 3, 58, 878, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 886, 8, 58, 1, 58, 3, 58, 889, 8, 58, 1, 58, 1, 58, 3, 58, 893, 8, 58, 1, 58, 3, 58, 896, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 910, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 927, 8, 58, 1, 58, 1, 58, 1, 58, 3, 58, 932, 8, 58, 1, 58, 1, 58, 3, 58, 936, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 942, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 949, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 961, 8, 58, 1, 58, 1, 58, 3, 58, 965, 8, 58, 1, 58, 3, 58, 968, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 977, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 991, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1030, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1038, 8, 58, 5, 58, 1040, 8, 58, 10, 58, 12, 58, 1043, 9, 58, 1, 59, 1, 59, 1, 59, 5, 59, 1048, 8, 59, 10, 59, 12, 59, 1051, 9, 59, 1, 59, 3, 59, 1054, 8, 59, 1, 60, 1, 60, 3, 60, 1058, 8, 60, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1064, 8, 61, 10, 61, 12, 61, 1067, 9, 61, 1, 61, 3, 61, 1070, 8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1077, 8, 61, 10, 61, 12, 61, 1080, 9, 61, 1, 61, 3, 61, 1083, 8, 61, 3, 61, 1085, 8, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 5, 62, 1093, 8, 62, 10, 62, 12, 62, 1096, 9, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 5, 62, 1104, 8, 62, 10, 62, 12, 62, 1107, 9, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1115, 8, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1122, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 1135, 8, 63, 1, 64, 1, 64, 1, 64, 5, 64, 1140, 8, 64, 10, 64, 12, 64, 1143, 9, 64, 1, 64, 3, 64, 1146, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1158, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 1164, 8, 66, 1, 66, 3, 66, 1167, 8, 66, 1, 67, 1, 67, 1, 67, 5, 67, 1172, 8, 67, 10, 67, 12, 67, 1175, 9, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1186, 8, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1192, 8, 68, 5, 68, 1194, 8, 68, 10, 68, 12, 68, 1197, 9, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1202, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, 1209, 8, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 5, 71, 1216, 8, 71, 10, 71, 12, 71, 1219, 9, 71, 1, 71, 3, 71, 1222, 8, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 1232, 8, 73, 3, 73, 1234, 8, 73, 1, 74, 3, 74, 1237, 8, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 3, 74, 1245, 8, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1250, 8, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 3, 79, 1260, 8, 79, 1, 80, 1, 80, 1, 80, 3, 80, 1265, 8, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 3, 83, 1277, 8, 83, 1, 84, 1, 84, 5, 84, 1281, 8, 84, 10, 84, 12, 84, 1284, 9, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 1293, 8, 85, 1, 86, 1, 86, 5, 86, 1297, 8, 86, 10, 86, 12, 86, 1300, 9, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 3, 87, 1309, 8, 87, 1, 87, 0, 3, 78, 116, 136, 88, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 0, 16, 2, 0, 18, 18, 74, 74, 2, 0, 44, 44, 51, 51, 3, 0, 1, 1, 4, 4, 8, 8, 4, 0, 1, 1, 3, 4, 8, 8, 80, 80, 2, 0, 51, 51, 73, 73, 2, 0, 1, 1, 4, 4, 2, 0, 7, 7, 22, 23, 2, 0, 30, 30, 49, 49, 2, 0, 71, 71, 76, 76, 3, 0, 10, 10, 50, 50, 90, 90, 2, 0, 41, 41, 53, 53, 1, 0, 107, 108, 2, 0, 118, 118, 139, 139, 7, 0, 21, 21, 38, 38, 55, 56, 70, 70, 78, 78, 97, 97, 103, 103, 16, 0, 1, 13, 15, 20, 22, 28, 30, 30, 32, 37, 39, 42, 44, 51, 53, 54, 58, 58, 60, 69, 71, 77, 79, 83, 85, 92, 94, 96, 98, 99, 101, 102, 4, 0, 20, 20, 30, 30, 39, 39, 48, 48, 1479, 0, 179, 1, 0, 0, 0, 2, 186, 1, 0, 0, 0, 4, 188, 1, 0, 0, 0, 6, 190, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 220, 1, 0, 0, 0, 12, 222, 1, 0, 0, 0, 14, 229, 1, 0, 0, 0, 16, 236, 1, 0, 0, 0, 18, 249, 1, 0, 0, 0, 20, 261, 1, 0, 0, 0, 22, 270, 1, 0, 0, 0, 24, 278, 1, 0, 0, 0, 26, 300, 1, 0, 0, 0, 28, 315, 1, 0, 0, 0, 30, 324, 1, 0, 0, 0, 32, 329, 1, 0, 0, 0, 34, 333, 1, 0, 0, 0, 36, 335, 1, 0, 0, 0, 38, 344, 1, 0, 0, 0, 40, 348, 1, 0, 0, 0, 42, 362, 1, 0, 0, 0, 44, 366, 1, 0, 0, 0, 46, 381, 1, 0, 0, 0, 48, 384, 1, 0, 0, 0, 50, 433, 1, 0, 0, 0, 52, 436, 1, 0, 0, 0, 54, 442, 1, 0, 0, 0, 56, 446, 1, 0, 0, 0, 58, 452, 1, 0, 0, 0, 60, 470, 1, 0, 0, 0, 62, 473, 1, 0, 0, 0, 64, 476, 1, 0, 0, 0, 66, 486, 1, 0, 0, 0, 68, 489, 1, 0, 0, 0, 70, 493, 1, 0, 0, 0, 72, 526, 1, 0, 0, 0, 74, 528, 1, 0, 0, 0, 76, 531, 1, 0, 0, 0, 78, 546, 1, 0, 0, 0, 80, 608, 1, 0, 0, 0, 82, 613, 1, 0, 0, 0, 84, 624, 1, 0, 0, 0, 86, 626, 1, 0, 0, 0, 88, 632, 1, 0, 0, 0, 90, 640, 1, 0, 0, 0, 92, 658, 1, 0, 0, 0, 94, 660, 1, 0, 0, 0, 96, 668, 1, 0, 0, 0, 98, 673, 1, 0, 0, 0, 100, 681, 1, 0, 0, 0, 102, 685, 1, 0, 0, 0, 104, 689, 1, 0, 0, 0, 106, 698, 1, 0, 0, 0, 108, 712, 1, 0, 0, 0, 110, 714, 1, 0, 0, 0, 112, 773, 1, 0, 0, 0, 114, 775, 1, 0, 0, 0, 116, 935, 1, 0, 0, 0, 118, 1044, 1, 0, 0, 0, 120, 1057, 1, 0, 0, 0, 122, 1084, 1, 0, 0, 0, 124, 1121, 1, 0, 0, 0, 126, 1134, 1, 0, 0, 0, 128, 1136, 1, 0, 0, 0, 130, 1157, 1, 0, 0, 0, 132, 1166, 1, 0, 0, 0, 134, 1168, 1, 0, 0, 0, 136, 1185, 1, 0, 0, 0, 138, 1198, 1, 0, 0, 0, 140, 1208, 1, 0, 0, 0, 142, 1212, 1, 0, 0, 0, 144, 1223, 1, 0, 0, 0, 146, 1233, 1, 0, 0, 0, 148, 1236, 1, 0, 0, 0, 150, 1249, 1, 0, 0, 0, 152, 1251, 1, 0, 0, 0, 154, 1253, 1, 0, 0, 0, 156, 1255, 1, 0, 0, 0, 158, 1259, 1, 0, 0, 0, 160, 1264, 1, 0, 0, 0, 162, 1266, 1, 0, 0, 0, 164, 1270, 1, 0, 0, 0, 166, 1276, 1, 0, 0, 0, 168, 1278, 1, 0, 0, 0, 170, 1292, 1, 0, 0, 0, 172, 1294, 1, 0, 0, 0, 174, 1308, 1, 0, 0, 0, 176, 178, 3, 2, 1, 0, 177, 176, 1, 0, 0, 0, 178, 181, 1, 0, 0, 0, 179, 177, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 182, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 182, 183, 5, 0, 0, 1, 183, 1, 1, 0, 0, 0, 184, 187, 3, 6, 3, 0, 185, 187, 3, 10, 5, 0, 186, 184, 1, 0, 0, 0, 186, 185, 1, 0, 0, 0, 187, 3, 1, 0, 0, 0, 188, 189, 3, 116, 58, 0, 189, 5, 1, 0, 0, 0, 190, 191, 5, 52, 0, 0, 191, 195, 3, 160, 80, 0, 192, 193, 5, 115, 0, 0, 193, 194, 5, 122, 0, 0, 194, 196, 3, 4, 2, 0, 195, 192, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 202, 3, 160, 80, 0, 198, 199, 5, 116, 0, 0, 199, 201, 3, 160, 80, 0, 200, 198, 1, 0, 0, 0, 201, 204, 1, 0, 0, 0, 202, 200, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 206, 1, 0, 0, 0, 204, 202, 1, 0, 0, 0, 205, 207, 5, 116, 0, 0, 206, 205, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 9, 1, 0, 0, 0, 208, 221, 3, 12, 6, 0, 209, 221, 3, 14, 7, 0, 210, 221, 3, 18, 9, 0, 211, 221, 3, 20, 10, 0, 212, 221, 3, 22, 11, 0, 213, 221, 3, 26, 13, 0, 214, 221, 3, 24, 12, 0, 215, 221, 3, 28, 14, 0, 216, 221, 3, 30, 15, 0, 217, 221, 3, 36, 18, 0, 218, 221, 3, 32, 16, 0, 219, 221, 3, 34, 17, 0, 220, 208, 1, 0, 0, 0, 220, 209, 1, 0, 0, 0, 220, 210, 1, 0, 0, 0, 220, 211, 1, 0, 0, 0, 220, 212, 1, 0, 0, 0, 220, 213, 1, 0, 0, 0, 220, 214, 1, 0, 0, 0, 220, 215, 1, 0, 0, 0, 220, 216, 1, 0, 0, 0, 220, 217, 1, 0, 0, 0, 220, 218, 1, 0, 0, 0, 220, 219, 1, 0, 0, 0, 221, 11, 1, 0, 0, 0, 222, 224, 5, 72, 0, 0, 223, 225, 3, 4, 2, 0, 224, 223, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 227, 1, 0, 0, 0, 226, 228, 5, 150, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 13, 1, 0, 0, 0, 229, 231, 5, 84, 0, 0, 230, 232, 3, 4, 2, 0, 231, 230, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 234, 1, 0, 0, 0, 233, 235, 5, 150, 0, 0, 234, 233, 1, 0, 0, 0, 234, 235, 1, 0, 0, 0, 235, 15, 1, 0, 0, 0, 236, 245, 5, 14, 0, 0, 237, 238, 5, 130, 0, 0, 238, 241, 3, 160, 80, 0, 239, 240, 5, 115, 0, 0, 240, 242, 3, 160, 80, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 244, 5, 149, 0, 0, 244, 246, 1, 0, 0, 0, 245, 237, 1, 0, 0, 0, 245, 246, 1, 0, 0, 0, 246, 247, 1, 0, 0, 0, 247, 248, 3, 36, 18, 0, 248, 17, 1, 0, 0, 0, 249, 250, 5, 93, 0, 0, 250, 254, 3, 36, 18, 0, 251, 253, 3, 16, 8, 0, 252, 251, 1, 0, 0, 0, 253, 256, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 254, 255, 1, 0, 0, 0, 255, 259, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 257, 258, 5, 29, 0, 0, 258, 260, 3, 36, 18, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 19, 1, 0, 0, 0, 261, 262, 5, 40, 0, 0, 262, 263, 5, 130, 0, 0, 263, 264, 3, 4, 2, 0, 264, 265, 5, 149, 0, 0, 265, 268, 3, 10, 5, 0, 266, 267, 5, 25, 0, 0, 267, 269, 3, 10, 5, 0, 268, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 21, 1, 0, 0, 0, 270, 271, 5, 100, 0, 0, 271, 272, 5, 130, 0, 0, 272, 273, 3, 4, 2, 0, 273, 274, 5, 149, 0, 0, 274, 276, 3, 10, 5, 0, 275, 277, 5, 150, 0, 0, 276, 275, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 23, 1, 0, 0, 0, 278, 279, 5, 33, 0, 0, 279, 283, 5, 130, 0, 0, 280, 284, 3, 6, 3, 0, 281, 284, 3, 30, 15, 0, 282, 284, 3, 4, 2, 0, 283, 280, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 287, 5, 150, 0, 0, 286, 288, 3, 4, 2, 0, 287, 286, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 293, 5, 150, 0, 0, 290, 294, 3, 6, 3, 0, 291, 294, 3, 30, 15, 0, 292, 294, 3, 4, 2, 0, 293, 290, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 293, 292, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 295, 1, 0, 0, 0, 295, 296, 5, 149, 0, 0, 296, 298, 3, 10, 5, 0, 297, 299, 5, 150, 0, 0, 298, 297, 1, 0, 0, 0, 298, 299, 1, 0, 0, 0, 299, 25, 1, 0, 0, 0, 300, 301, 5, 33, 0, 0, 301, 302, 5, 130, 0, 0, 302, 303, 5, 52, 0, 0, 303, 306, 3, 160, 80, 0, 304, 305, 5, 116, 0, 0, 305, 307, 3, 160, 80, 0, 306, 304, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 309, 5, 42, 0, 0, 309, 310, 3, 4, 2, 0, 310, 311, 5, 149, 0, 0, 311, 313, 3, 10, 5, 0, 312, 314, 5, 150, 0, 0, 313, 312, 1, 0, 0, 0, 313, 314, 1, 0, 0, 0, 314, 27, 1, 0, 0, 0, 315, 316, 5, 31, 0, 0, 316, 317, 3, 160, 80, 0, 317, 319, 5, 130, 0, 0, 318, 320, 3, 8, 4, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 149, 0, 0, 322, 323, 3, 36, 18, 0, 323, 29, 1, 0, 0, 0, 324, 325, 3, 4, 2, 0, 325, 326, 5, 115, 0, 0, 326, 327, 5, 122, 0, 0, 327, 328, 3, 4, 2, 0, 328, 31, 1, 0, 0, 0, 329, 331, 3, 4, 2, 0, 330, 332, 5, 150, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 33, 1, 0, 0, 0, 333, 334, 5, 150, 0, 0, 334, 35, 1, 0, 0, 0, 335, 339, 5, 128, 0, 0, 336, 338, 3, 2, 1, 0, 337, 336, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 342, 1, 0, 0, 0, 341, 339, 1, 0, 0, 0, 342, 343, 5, 147, 0, 0, 343, 37, 1, 0, 0, 0, 344, 345, 3, 4, 2, 0, 345, 346, 5, 115, 0, 0, 346, 347, 3, 4, 2, 0, 347, 39, 1, 0, 0, 0, 348, 353, 3, 38, 19, 0, 349, 350, 5, 116, 0, 0, 350, 352, 3, 38, 19, 0, 351, 349, 1, 0, 0, 0, 352, 355, 1, 0, 0, 0, 353, 351, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 356, 358, 5, 116, 0, 0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 41, 1, 0, 0, 0, 359, 363, 3, 44, 22, 0, 360, 363, 3, 48, 24, 0, 361, 363, 3, 124, 62, 0, 362, 359, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 365, 5, 0, 0, 1, 365, 43, 1, 0, 0, 0, 366, 372, 3, 46, 23, 0, 367, 368, 5, 95, 0, 0, 368, 369, 5, 1, 0, 0, 369, 371, 3, 46, 23, 0, 370, 367, 1, 0, 0, 0, 371, 374, 1, 0, 0, 0, 372, 370, 1, 0, 0, 0, 372, 373, 1, 0, 0, 0, 373, 45, 1, 0, 0, 0, 374, 372, 1, 0, 0, 0, 375, 382, 3, 48, 24, 0, 376, 377, 5, 130, 0, 0, 377, 378, 3, 44, 22, 0, 378, 379, 5, 149, 0, 0, 379, 382, 1, 0, 0, 0, 380, 382, 3, 164, 82, 0, 381, 375, 1, 0, 0, 0, 381, 376, 1, 0, 0, 0, 381, 380, 1, 0, 0, 0, 382, 47, 1, 0, 0, 0, 383, 385, 3, 50, 25, 0, 384, 383, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 5, 79, 0, 0, 387, 389, 5, 24, 0, 0, 388, 387, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 391, 1, 0, 0, 0, 390, 392, 3, 52, 26, 0, 391, 390, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 393, 1, 0, 0, 0, 393, 395, 3, 114, 57, 0, 394, 396, 3, 54, 27, 0, 395, 394, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 398, 1, 0, 0, 0, 397, 399, 3, 56, 28, 0, 398, 397, 1, 0, 0, 0, 398, 399, 1, 0, 0, 0, 399, 401, 1, 0, 0, 0, 400, 402, 3, 60, 30, 0, 401, 400, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 404, 1, 0, 0, 0, 403, 405, 3, 62, 31, 0, 404, 403, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 408, 3, 64, 32, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 102, 0, 0, 410, 412, 7, 0, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 102, 0, 0, 414, 416, 5, 89, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 418, 1, 0, 0, 0, 417, 419, 3, 66, 33, 0, 418, 417, 1, 0, 0, 0, 418, 419, 1, 0, 0, 0, 419, 421, 1, 0, 0, 0, 420, 422, 3, 58, 29, 0, 421, 420, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 425, 3, 68, 34, 0, 424, 423, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 428, 1, 0, 0, 0, 426, 429, 3, 72, 36, 0, 427, 429, 3, 74, 37, 0, 428, 426, 1, 0, 0, 0, 428, 427, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 431, 1, 0, 0, 0, 430, 432, 3, 76, 38, 0, 431, 430, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 49, 1, 0, 0, 0, 433, 434, 5, 102, 0, 0, 434, 435, 3, 128, 64, 0, 435, 51, 1, 0, 0, 0, 436, 437, 5, 88, 0, 0, 437, 440, 5, 108, 0, 0, 438, 439, 5, 102, 0, 0, 439, 441, 5, 85, 0, 0, 440, 438, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0, 441, 53, 1, 0, 0, 0, 442, 443, 5, 34, 0, 0, 443, 444, 3, 78, 39, 0, 444, 55, 1, 0, 0, 0, 445, 447, 7, 1, 0, 0, 446, 445, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 449, 5, 5, 0, 0, 449, 450, 5, 47, 0, 0, 450, 451, 3, 114, 57, 0, 451, 57, 1, 0, 0, 0, 452, 453, 5, 101, 0, 0, 453, 454, 3, 160, 80, 0, 454, 455, 5, 6, 0, 0, 455, 456, 5, 130, 0, 0, 456, 457, 3, 98, 49, 0, 457, 467, 5, 149, 0, 0, 458, 459, 5, 116, 0, 0, 459, 460, 3, 160, 80, 0, 460, 461, 5, 6, 0, 0, 461, 462, 5, 130, 0, 0, 462, 463, 3, 98, 49, 0, 463, 464, 5, 149, 0, 0, 464, 466, 1, 0, 0, 0, 465, 458, 1, 0, 0, 0, 466, 469, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0, 0, 0, 468, 59, 1, 0, 0, 0, 469, 467, 1, 0, 0, 0, 470, 471, 5, 69, 0, 0, 471, 472, 3, 116, 58, 0, 472, 61, 1, 0, 0, 0, 473, 474, 5, 99, 0, 0, 474, 475, 3, 116, 58, 0, 475, 63, 1, 0, 0, 0, 476, 477, 5, 36, 0, 0, 477, 484, 5, 11, 0, 0, 478, 479, 7, 0, 0, 0, 479, 480, 5, 130, 0, 0, 480, 481, 3, 114, 57, 0, 481, 482, 5, 149, 0, 0, 482, 485, 1, 0, 0, 0, 483, 485, 3, 114, 57, 0, 484, 478, 1, 0, 0, 0, 484, 483, 1, 0, 0, 0, 485, 65, 1, 0, 0, 0, 486, 487, 5, 37, 0, 0, 487, 488, 3, 116, 58, 0, 488, 67, 1, 0, 0, 0, 489, 490, 5, 64, 0, 0, 490, 491, 5, 11, 0, 0, 491, 492, 3, 88, 44, 0, 492, 69, 1, 0, 0, 0, 493, 494, 5, 64, 0, 0, 494, 495, 5, 11, 0, 0, 495, 496, 3, 114, 57, 0, 496, 71, 1, 0, 0, 0, 497, 498, 5, 54, 0, 0, 498, 501, 3, 116, 58, 0, 499, 500, 5, 116, 0, 0, 500, 502, 3, 116, 58, 0, 501, 499, 1, 0, 0, 0, 501, 502, 1, 0, 0, 0, 502, 507, 1, 0, 0, 0, 503, 504, 5, 102, 0, 0, 504, 508, 5, 85, 0, 0, 505, 506, 5, 11, 0, 0, 506, 508, 3, 114, 57, 0, 507, 503, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 527, 1, 0, 0, 0, 509, 510, 5, 54, 0, 0, 510, 513, 3, 116, 58, 0, 511, 512, 5, 102, 0, 0, 512, 514, 5, 85, 0, 0, 513, 511, 1, 0, 0, 0, 513, 514, 1, 0, 0, 0, 514, 515, 1, 0, 0, 0, 515, 516, 5, 61, 0, 0, 516, 517, 3, 116, 58, 0, 517, 527, 1, 0, 0, 0, 518, 519, 5, 54, 0, 0, 519, 520, 3, 116, 58, 0, 520, 521, 5, 61, 0, 0, 521, 524, 3, 116, 58, 0, 522, 523, 5, 11, 0, 0, 523, 525, 3, 114, 57, 0, 524, 522, 1, 0, 0, 0, 524, 525, 1, 0, 0, 0, 525, 527, 1, 0, 0, 0, 526, 497, 1, 0, 0, 0, 526, 509, 1, 0, 0, 0, 526, 518, 1, 0, 0, 0, 527, 73, 1, 0, 0, 0, 528, 529, 5, 61, 0, 0, 529, 530, 3, 116, 58, 0, 530, 75, 1, 0, 0, 0, 531, 532, 5, 81, 0, 0, 532, 533, 3, 94, 47, 0, 533, 77, 1, 0, 0, 0, 534, 535, 6, 39, -1, 0, 535, 537, 3, 136, 68, 0, 536, 538, 5, 28, 0, 0, 537, 536, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 540, 1, 0, 0, 0, 539, 541, 3, 86, 43, 0, 540, 539, 1, 0, 0, 0, 540, 541, 1, 0, 0, 0, 541, 547, 1, 0, 0, 0, 542, 543, 5, 130, 0, 0, 543, 544, 3, 78, 39, 0, 544, 545, 5, 149, 0, 0, 545, 547, 1, 0, 0, 0, 546, 534, 1, 0, 0, 0, 546, 542, 1, 0, 0, 0, 547, 562, 1, 0, 0, 0, 548, 549, 10, 3, 0, 0, 549, 550, 3, 82, 41, 0, 550, 551, 3, 78, 39, 4, 551, 561, 1, 0, 0, 0, 552, 554, 10, 4, 0, 0, 553, 555, 3, 80, 40, 0, 554, 553, 1, 0, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 5, 47, 0, 0, 557, 558, 3, 78, 39, 0, 558, 559, 3, 84, 42, 0, 559, 561, 1, 0, 0, 0, 560, 548, 1, 0, 0, 0, 560, 552, 1, 0, 0, 0, 561, 564, 1, 0, 0, 0, 562, 560, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 79, 1, 0, 0, 0, 564, 562, 1, 0, 0, 0, 565, 567, 7, 2, 0, 0, 566, 565, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 575, 5, 44, 0, 0, 569, 571, 5, 44, 0, 0, 570, 572, 7, 2, 0, 0, 571, 570, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 575, 1, 0, 0, 0, 573, 575, 7, 2, 0, 0, 574, 566, 1, 0, 0, 0, 574, 569, 1, 0, 0, 0, 574, 573, 1, 0, 0, 0, 575, 609, 1, 0, 0, 0, 576, 578, 7, 3, 0, 0, 577, 576, 1, 0, 0, 0, 577, 578, 1, 0, 0, 0, 578, 579, 1, 0, 0, 0, 579, 581, 7, 4, 0, 0, 580, 582, 5, 65, 0, 0, 581, 580, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 591, 1, 0, 0, 0, 583, 585, 7, 4, 0, 0, 584, 586, 5, 65, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 588, 1, 0, 0, 0, 587, 589, 7, 3, 0, 0, 588, 587, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 591, 1, 0, 0, 0, 590, 577, 1, 0, 0, 0, 590, 583, 1, 0, 0, 0, 591, 609, 1, 0, 0, 0, 592, 594, 7, 5, 0, 0, 593, 592, 1, 0, 0, 0, 593, 594, 1, 0, 0, 0, 594, 595, 1, 0, 0, 0, 595, 597, 5, 35, 0, 0, 596, 598, 5, 65, 0, 0, 597, 596, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 607, 1, 0, 0, 0, 599, 601, 5, 35, 0, 0, 600, 602, 5, 65, 0, 0, 601, 600, 1, 0, 0, 0, 601, 602, 1, 0, 0, 0, 602, 604, 1, 0, 0, 0, 603, 605, 7, 5, 0, 0, 604, 603, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 607, 1, 0, 0, 0, 606, 593, 1, 0, 0, 0, 606, 599, 1, 0, 0, 0, 607, 609, 1, 0, 0, 0, 608, 574, 1, 0, 0, 0, 608, 590, 1, 0, 0, 0, 608, 606, 1, 0, 0, 0, 609, 81, 1, 0, 0, 0, 610, 611, 5, 17, 0, 0, 611, 614, 5, 47, 0, 0, 612, 614, 5, 116, 0, 0, 613, 610, 1, 0, 0, 0, 613, 612, 1, 0, 0, 0, 614, 83, 1, 0, 0, 0, 615, 616, 5, 62, 0, 0, 616, 625, 3, 114, 57, 0, 617, 618, 5, 96, 0, 0, 618, 619, 5, 130, 0, 0, 619, 620, 3, 114, 57, 0, 620, 621, 5, 149, 0, 0, 621, 625, 1, 0, 0, 0, 622, 623, 5, 96, 0, 0, 623, 625, 3, 114, 57, 0, 624, 615, 1, 0, 0, 0, 624, 617, 1, 0, 0, 0, 624, 622, 1, 0, 0, 0, 625, 85, 1, 0, 0, 0, 626, 627, 5, 77, 0, 0, 627, 630, 3, 92, 46, 0, 628, 629, 5, 61, 0, 0, 629, 631, 3, 92, 46, 0, 630, 628, 1, 0, 0, 0, 630, 631, 1, 0, 0, 0, 631, 87, 1, 0, 0, 0, 632, 637, 3, 90, 45, 0, 633, 634, 5, 116, 0, 0, 634, 636, 3, 90, 45, 0, 635, 633, 1, 0, 0, 0, 636, 639, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 89, 1, 0, 0, 0, 639, 637, 1, 0, 0, 0, 640, 642, 3, 116, 58, 0, 641, 643, 7, 6, 0, 0, 642, 641, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 646, 1, 0, 0, 0, 644, 645, 5, 60, 0, 0, 645, 647, 7, 7, 0, 0, 646, 644, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 650, 1, 0, 0, 0, 648, 649, 5, 16, 0, 0, 649, 651, 5, 110, 0, 0, 650, 648, 1, 0, 0, 0, 650, 651, 1, 0, 0, 0, 651, 91, 1, 0, 0, 0, 652, 659, 3, 164, 82, 0, 653, 656, 3, 148, 74, 0, 654, 655, 5, 151, 0, 0, 655, 657, 3, 148, 74, 0, 656, 654, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 659, 1, 0, 0, 0, 658, 652, 1, 0, 0, 0, 658, 653, 1, 0, 0, 0, 659, 93, 1, 0, 0, 0, 660, 665, 3, 96, 48, 0, 661, 662, 5, 116, 0, 0, 662, 664, 3, 96, 48, 0, 663, 661, 1, 0, 0, 0, 664, 667, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 95, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 668, 669, 3, 160, 80, 0, 669, 670, 5, 122, 0, 0, 670, 671, 3, 150, 75, 0, 671, 97, 1, 0, 0, 0, 672, 674, 3, 100, 50, 0, 673, 672, 1, 0, 0, 0, 673, 674, 1, 0, 0, 0, 674, 676, 1, 0, 0, 0, 675, 677, 3, 102, 51, 0, 676, 675, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 679, 1, 0, 0, 0, 678, 680, 3, 104, 52, 0, 679, 678, 1, 0, 0, 0, 679, 680, 1, 0, 0, 0, 680, 99, 1, 0, 0, 0, 681, 682, 5, 67, 0, 0, 682, 683, 5, 11, 0, 0, 683, 684, 3, 114, 57, 0, 684, 101, 1, 0, 0, 0, 685, 686, 5, 64, 0, 0, 686, 687, 5, 11, 0, 0, 687, 688, 3, 88, 44, 0, 688, 103, 1, 0, 0, 0, 689, 690, 7, 8, 0, 0, 690, 691, 3, 106, 53, 0, 691, 105, 1, 0, 0, 0, 692, 699, 3, 108, 54, 0, 693, 694, 5, 9, 0, 0, 694, 695, 3, 108, 54, 0, 695, 696, 5, 2, 0, 0, 696, 697, 3, 108, 54, 0, 697, 699, 1, 0, 0, 0, 698, 692, 1, 0, 0, 0, 698, 693, 1, 0, 0, 0, 699, 107, 1, 0, 0, 0, 700, 701, 5, 19, 0, 0, 701, 713, 5, 75, 0, 0, 702, 703, 5, 94, 0, 0, 703, 713, 5, 68, 0, 0, 704, 705, 5, 94, 0, 0, 705, 713, 5, 32, 0, 0, 706, 707, 3, 148, 74, 0, 707, 708, 5, 68, 0, 0, 708, 713, 1, 0, 0, 0, 709, 710, 3, 148, 74, 0, 710, 711, 5, 32, 0, 0, 711, 713, 1, 0, 0, 0, 712, 700, 1, 0, 0, 0, 712, 702, 1, 0, 0, 0, 712, 704, 1, 0, 0, 0, 712, 706, 1, 0, 0, 0, 712, 709, 1, 0, 0, 0, 713, 109, 1, 0, 0, 0, 714, 715, 3, 116, 58, 0, 715, 716, 5, 0, 0, 1, 716, 111, 1, 0, 0, 0, 717, 774, 3, 160, 80, 0, 718, 719, 3, 160, 80, 0, 719, 720, 5, 130, 0, 0, 720, 721, 3, 160, 80, 0, 721, 728, 3, 112, 56, 0, 722, 723, 5, 116, 0, 0, 723, 724, 3, 160, 80, 0, 724, 725, 3, 112, 56, 0, 725, 727, 1, 0, 0, 0, 726, 722, 1, 0, 0, 0, 727, 730, 1, 0, 0, 0, 728, 726, 1, 0, 0, 0, 728, 729, 1, 0, 0, 0, 729, 732, 1, 0, 0, 0, 730, 728, 1, 0, 0, 0, 731, 733, 5, 116, 0, 0, 732, 731, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 5, 149, 0, 0, 735, 774, 1, 0, 0, 0, 736, 737, 3, 160, 80, 0, 737, 738, 5, 130, 0, 0, 738, 743, 3, 162, 81, 0, 739, 740, 5, 116, 0, 0, 740, 742, 3, 162, 81, 0, 741, 739, 1, 0, 0, 0, 742, 745, 1, 0, 0, 0, 743, 741, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 747, 1, 0, 0, 0, 745, 743, 1, 0, 0, 0, 746, 748, 5, 116, 0, 0, 747, 746, 1, 0, 0, 0, 747, 748, 1, 0, 0, 0, 748, 749, 1, 0, 0, 0, 749, 750, 5, 149, 0, 0, 750, 774, 1, 0, 0, 0, 751, 752, 3, 160, 80, 0, 752, 753, 5, 130, 0, 0, 753, 758, 3, 112, 56, 0, 754, 755, 5, 116, 0, 0, 755, 757, 3, 112, 56, 0, 756, 754, 1, 0, 0, 0, 757, 760, 1, 0, 0, 0, 758, 756, 1, 0, 0, 0, 758, 759, 1, 0, 0, 0, 759, 762, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 763, 5, 116, 0, 0, 762, 761, 1, 0, 0, 0, 762, 763, 1, 0, 0, 0, 763, 764, 1, 0, 0, 0, 764, 765, 5, 149, 0, 0, 765, 774, 1, 0, 0, 0, 766, 767, 3, 160, 80, 0, 767, 769, 5, 130, 0, 0, 768, 770, 3, 114, 57, 0, 769, 768, 1, 0, 0, 0, 769, 770, 1, 0, 0, 0, 770, 771, 1, 0, 0, 0, 771, 772, 5, 149, 0, 0, 772, 774, 1, 0, 0, 0, 773, 717, 1, 0, 0, 0, 773, 718, 1, 0, 0, 0, 773, 736, 1, 0, 0, 0, 773, 751, 1, 0, 0, 0, 773, 766, 1, 0, 0, 0, 774, 113, 1, 0, 0, 0, 775, 780, 3, 116, 58, 0, 776, 777, 5, 116, 0, 0, 777, 779, 3, 116, 58, 0, 778, 776, 1, 0, 0, 0, 779, 782, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 780, 781, 1, 0, 0, 0, 781, 784, 1, 0, 0, 0, 782, 780, 1, 0, 0, 0, 783, 785, 5, 116, 0, 0, 784, 783, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 115, 1, 0, 0, 0, 786, 787, 6, 58, -1, 0, 787, 789, 5, 12, 0, 0, 788, 790, 3, 116, 58, 0, 789, 788, 1, 0, 0, 0, 789, 790, 1, 0, 0, 0, 790, 796, 1, 0, 0, 0, 791, 792, 5, 98, 0, 0, 792, 793, 3, 116, 58, 0, 793, 794, 5, 83, 0, 0, 794, 795, 3, 116, 58, 0, 795, 797, 1, 0, 0, 0, 796, 791, 1, 0, 0, 0, 797, 798, 1, 0, 0, 0, 798, 796, 1, 0, 0, 0, 798, 799, 1, 0, 0, 0, 799, 802, 1, 0, 0, 0, 800, 801, 5, 25, 0, 0, 801, 803, 3, 116, 58, 0, 802, 800, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 1, 0, 0, 0, 804, 805, 5, 26, 0, 0, 805, 936, 1, 0, 0, 0, 806, 807, 5, 13, 0, 0, 807, 808, 5, 130, 0, 0, 808, 809, 3, 116, 58, 0, 809, 810, 5, 6, 0, 0, 810, 811, 3, 112, 56, 0, 811, 812, 5, 149, 0, 0, 812, 936, 1, 0, 0, 0, 813, 814, 5, 20, 0, 0, 814, 936, 5, 110, 0, 0, 815, 816, 5, 45, 0, 0, 816, 817, 3, 116, 58, 0, 817, 818, 3, 152, 76, 0, 818, 936, 1, 0, 0, 0, 819, 820, 5, 82, 0, 0, 820, 821, 5, 130, 0, 0, 821, 822, 3, 116, 58, 0, 822, 823, 5, 34, 0, 0, 823, 826, 3, 116, 58, 0, 824, 825, 5, 33, 0, 0, 825, 827, 3, 116, 58, 0, 826, 824, 1, 0, 0, 0, 826, 827, 1, 0, 0, 0, 827, 828, 1, 0, 0, 0, 828, 829, 5, 149, 0, 0, 829, 936, 1, 0, 0, 0, 830, 831, 5, 86, 0, 0, 831, 936, 5, 110, 0, 0, 832, 833, 5, 91, 0, 0, 833, 834, 5, 130, 0, 0, 834, 835, 7, 9, 0, 0, 835, 836, 3, 166, 83, 0, 836, 837, 5, 34, 0, 0, 837, 838, 3, 116, 58, 0, 838, 839, 5, 149, 0, 0, 839, 936, 1, 0, 0, 0, 840, 841, 3, 160, 80, 0, 841, 843, 5, 130, 0, 0, 842, 844, 3, 114, 57, 0, 843, 842, 1, 0, 0, 0, 843, 844, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 846, 5, 149, 0, 0, 846, 855, 1, 0, 0, 0, 847, 849, 5, 130, 0, 0, 848, 850, 5, 24, 0, 0, 849, 848, 1, 0, 0, 0, 849, 850, 1, 0, 0, 0, 850, 852, 1, 0, 0, 0, 851, 853, 3, 118, 59, 0, 852, 851, 1, 0, 0, 0, 852, 853, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854, 856, 5, 149, 0, 0, 855, 847, 1, 0, 0, 0, 855, 856, 1, 0, 0, 0, 856, 857, 1, 0, 0, 0, 857, 858, 5, 66, 0, 0, 858, 859, 5, 130, 0, 0, 859, 860, 3, 98, 49, 0, 860, 861, 5, 149, 0, 0, 861, 936, 1, 0, 0, 0, 862, 863, 3, 160, 80, 0, 863, 865, 5, 130, 0, 0, 864, 866, 3, 114, 57, 0, 865, 864, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 868, 5, 149, 0, 0, 868, 877, 1, 0, 0, 0, 869, 871, 5, 130, 0, 0, 870, 872, 5, 24, 0, 0, 871, 870, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 874, 1, 0, 0, 0, 873, 875, 3, 118, 59, 0, 874, 873, 1, 0, 0, 0, 874, 875, 1, 0, 0, 0, 875, 876, 1, 0, 0, 0, 876, 878, 5, 149, 0, 0, 877, 869, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 880, 5, 66, 0, 0, 880, 881, 3, 160, 80, 0, 881, 936, 1, 0, 0, 0, 882, 888, 3, 160, 80, 0, 883, 885, 5, 130, 0, 0, 884, 886, 3, 114, 57, 0, 885, 884, 1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 889, 5, 149, 0, 0, 888, 883, 1, 0, 0, 0, 888, 889, 1, 0, 0, 0, 889, 890, 1, 0, 0, 0, 890, 892, 5, 130, 0, 0, 891, 893, 5, 24, 0, 0, 892, 891, 1, 0, 0, 0, 892, 893, 1, 0, 0, 0, 893, 895, 1, 0, 0, 0, 894, 896, 3, 118, 59, 0, 895, 894, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 897, 1, 0, 0, 0, 897, 898, 5, 149, 0, 0, 898, 936, 1, 0, 0, 0, 899, 936, 3, 124, 62, 0, 900, 936, 3, 168, 84, 0, 901, 936, 3, 150, 75, 0, 902, 903, 5, 118, 0, 0, 903, 936, 3, 116, 58, 19, 904, 905, 5, 58, 0, 0, 905, 936, 3, 116, 58, 13, 906, 907, 3, 140, 70, 0, 907, 908, 5, 120, 0, 0, 908, 910, 1, 0, 0, 0, 909, 906, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 1, 0, 0, 0, 911, 936, 5, 112, 0, 0, 912, 913, 5, 130, 0, 0, 913, 914, 3, 44, 22, 0, 914, 915, 5, 149, 0, 0, 915, 936, 1, 0, 0, 0, 916, 917, 5, 130, 0, 0, 917, 918, 3, 116, 58, 0, 918, 919, 5, 149, 0, 0, 919, 936, 1, 0, 0, 0, 920, 921, 5, 130, 0, 0, 921, 922, 3, 114, 57, 0, 922, 923, 5, 149, 0, 0, 923, 936, 1, 0, 0, 0, 924, 926, 5, 129, 0, 0, 925, 927, 3, 114, 57, 0, 926, 925, 1, 0, 0, 0, 926, 927, 1, 0, 0, 0, 927, 928, 1, 0, 0, 0, 928, 936, 5, 148, 0, 0, 929, 931, 5, 128, 0, 0, 930, 932, 3, 40, 20, 0, 931, 930, 1, 0, 0, 0, 931, 932, 1, 0, 0, 0, 932, 933, 1, 0, 0, 0, 933, 936, 5, 147, 0, 0, 934, 936, 3, 132, 66, 0, 935, 786, 1, 0, 0, 0, 935, 806, 1, 0, 0, 0, 935, 813, 1, 0, 0, 0, 935, 815, 1, 0, 0, 0, 935, 819, 1, 0, 0, 0, 935, 830, 1, 0, 0, 0, 935, 832, 1, 0, 0, 0, 935, 840, 1, 0, 0, 0, 935, 862, 1, 0, 0, 0, 935, 882, 1, 0, 0, 0, 935, 899, 1, 0, 0, 0, 935, 900, 1, 0, 0, 0, 935, 901, 1, 0, 0, 0, 935, 902, 1, 0, 0, 0, 935, 904, 1, 0, 0, 0, 935, 909, 1, 0, 0, 0, 935, 912, 1, 0, 0, 0, 935, 916, 1, 0, 0, 0, 935, 920, 1, 0, 0, 0, 935, 924, 1, 0, 0, 0, 935, 929, 1, 0, 0, 0, 935, 934, 1, 0, 0, 0, 936, 1041, 1, 0, 0, 0, 937, 941, 10, 18, 0, 0, 938, 942, 5, 112, 0, 0, 939, 942, 5, 151, 0, 0, 940, 942, 5, 138, 0, 0, 941, 938, 1, 0, 0, 0, 941, 939, 1, 0, 0, 0, 941, 940, 1, 0, 0, 0, 942, 943, 1, 0, 0, 0, 943, 1040, 3, 116, 58, 19, 944, 948, 10, 17, 0, 0, 945, 949, 5, 139, 0, 0, 946, 949, 5, 118, 0, 0, 947, 949, 5, 117, 0, 0, 948, 945, 1, 0, 0, 0, 948, 946, 1, 0, 0, 0, 948, 947, 1, 0, 0, 0, 949, 950, 1, 0, 0, 0, 950, 1040, 3, 116, 58, 18, 951, 976, 10, 16, 0, 0, 952, 977, 5, 121, 0, 0, 953, 977, 5, 122, 0, 0, 954, 977, 5, 133, 0, 0, 955, 977, 5, 131, 0, 0, 956, 977, 5, 132, 0, 0, 957, 977, 5, 123, 0, 0, 958, 977, 5, 124, 0, 0, 959, 961, 5, 58, 0, 0, 960, 959, 1, 0, 0, 0, 960, 961, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 964, 5, 42, 0, 0, 963, 965, 5, 15, 0, 0, 964, 963, 1, 0, 0, 0, 964, 965, 1, 0, 0, 0, 965, 977, 1, 0, 0, 0, 966, 968, 5, 58, 0, 0, 967, 966, 1, 0, 0, 0, 967, 968, 1, 0, 0, 0, 968, 969, 1, 0, 0, 0, 969, 977, 7, 10, 0, 0, 970, 977, 5, 145, 0, 0, 971, 977, 5, 146, 0, 0, 972, 977, 5, 135, 0, 0, 973, 977, 5, 126, 0, 0, 974, 977, 5, 127, 0, 0, 975, 977, 5, 134, 0, 0, 976, 952, 1, 0, 0, 0, 976, 953, 1, 0, 0, 0, 976, 954, 1, 0, 0, 0, 976, 955, 1, 0, 0, 0, 976, 956, 1, 0, 0, 0, 976, 957, 1, 0, 0, 0, 976, 958, 1, 0, 0, 0, 976, 960, 1, 0, 0, 0, 976, 967, 1, 0, 0, 0, 976, 970, 1, 0, 0, 0, 976, 971, 1, 0, 0, 0, 976, 972, 1, 0, 0, 0, 976, 973, 1, 0, 0, 0, 976, 974, 1, 0, 0, 0, 976, 975, 1, 0, 0, 0, 977, 978, 1, 0, 0, 0, 978, 1040, 3, 116, 58, 17, 979, 980, 10, 14, 0, 0, 980, 981, 5, 137, 0, 0, 981, 1040, 3, 116, 58, 15, 982, 983, 10, 12, 0, 0, 983, 984, 5, 2, 0, 0, 984, 1040, 3, 116, 58, 13, 985, 986, 10, 11, 0, 0, 986, 987, 5, 63, 0, 0, 987, 1040, 3, 116, 58, 12, 988, 990, 10, 10, 0, 0, 989, 991, 5, 58, 0, 0, 990, 989, 1, 0, 0, 0, 990, 991, 1, 0, 0, 0, 991, 992, 1, 0, 0, 0, 992, 993, 5, 9, 0, 0, 993, 994, 3, 116, 58, 0, 994, 995, 5, 2, 0, 0, 995, 996, 3, 116, 58, 11, 996, 1040, 1, 0, 0, 0, 997, 998, 10, 9, 0, 0, 998, 999, 5, 140, 0, 0, 999, 1000, 3, 116, 58, 0, 1000, 1001, 5, 115, 0, 0, 1001, 1002, 3, 116, 58, 9, 1002, 1040, 1, 0, 0, 0, 1003, 1004, 10, 25, 0, 0, 1004, 1005, 5, 129, 0, 0, 1005, 1006, 3, 116, 58, 0, 1006, 1007, 5, 148, 0, 0, 1007, 1040, 1, 0, 0, 0, 1008, 1009, 10, 24, 0, 0, 1009, 1010, 5, 120, 0, 0, 1010, 1040, 5, 108, 0, 0, 1011, 1012, 10, 23, 0, 0, 1012, 1013, 5, 120, 0, 0, 1013, 1040, 3, 160, 80, 0, 1014, 1015, 10, 22, 0, 0, 1015, 1016, 5, 136, 0, 0, 1016, 1017, 5, 129, 0, 0, 1017, 1018, 3, 116, 58, 0, 1018, 1019, 5, 148, 0, 0, 1019, 1040, 1, 0, 0, 0, 1020, 1021, 10, 21, 0, 0, 1021, 1022, 5, 136, 0, 0, 1022, 1040, 5, 108, 0, 0, 1023, 1024, 10, 20, 0, 0, 1024, 1025, 5, 136, 0, 0, 1025, 1040, 3, 160, 80, 0, 1026, 1027, 10, 15, 0, 0, 1027, 1029, 5, 46, 0, 0, 1028, 1030, 5, 58, 0, 0, 1029, 1028, 1, 0, 0, 0, 1029, 1030, 1, 0, 0, 0, 1030, 1031, 1, 0, 0, 0, 1031, 1040, 5, 59, 0, 0, 1032, 1037, 10, 8, 0, 0, 1033, 1034, 5, 6, 0, 0, 1034, 1038, 3, 160, 80, 0, 1035, 1036, 5, 6, 0, 0, 1036, 1038, 5, 110, 0, 0, 1037, 1033, 1, 0, 0, 0, 1037, 1035, 1, 0, 0, 0, 1038, 1040, 1, 0, 0, 0, 1039, 937, 1, 0, 0, 0, 1039, 944, 1, 0, 0, 0, 1039, 951, 1, 0, 0, 0, 1039, 979, 1, 0, 0, 0, 1039, 982, 1, 0, 0, 0, 1039, 985, 1, 0, 0, 0, 1039, 988, 1, 0, 0, 0, 1039, 997, 1, 0, 0, 0, 1039, 1003, 1, 0, 0, 0, 1039, 1008, 1, 0, 0, 0, 1039, 1011, 1, 0, 0, 0, 1039, 1014, 1, 0, 0, 0, 1039, 1020, 1, 0, 0, 0, 1039, 1023, 1, 0, 0, 0, 1039, 1026, 1, 0, 0, 0, 1039, 1032, 1, 0, 0, 0, 1040, 1043, 1, 0, 0, 0, 1041, 1039, 1, 0, 0, 0, 1041, 1042, 1, 0, 0, 0, 1042, 117, 1, 0, 0, 0, 1043, 1041, 1, 0, 0, 0, 1044, 1049, 3, 120, 60, 0, 1045, 1046, 5, 116, 0, 0, 1046, 1048, 3, 120, 60, 0, 1047, 1045, 1, 0, 0, 0, 1048, 1051, 1, 0, 0, 0, 1049, 1047, 1, 0, 0, 0, 1049, 1050, 1, 0, 0, 0, 1050, 1053, 1, 0, 0, 0, 1051, 1049, 1, 0, 0, 0, 1052, 1054, 5, 116, 0, 0, 1053, 1052, 1, 0, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 119, 1, 0, 0, 0, 1055, 1058, 3, 122, 61, 0, 1056, 1058, 3, 116, 58, 0, 1057, 1055, 1, 0, 0, 0, 1057, 1056, 1, 0, 0, 0, 1058, 121, 1, 0, 0, 0, 1059, 1060, 5, 130, 0, 0, 1060, 1065, 3, 160, 80, 0, 1061, 1062, 5, 116, 0, 0, 1062, 1064, 3, 160, 80, 0, 1063, 1061, 1, 0, 0, 0, 1064, 1067, 1, 0, 0, 0, 1065, 1063, 1, 0, 0, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1069, 1, 0, 0, 0, 1067, 1065, 1, 0, 0, 0, 1068, 1070, 5, 116, 0, 0, 1069, 1068, 1, 0, 0, 0, 1069, 1070, 1, 0, 0, 0, 1070, 1071, 1, 0, 0, 0, 1071, 1072, 5, 149, 0, 0, 1072, 1085, 1, 0, 0, 0, 1073, 1078, 3, 160, 80, 0, 1074, 1075, 5, 116, 0, 0, 1075, 1077, 3, 160, 80, 0, 1076, 1074, 1, 0, 0, 0, 1077, 1080, 1, 0, 0, 0, 1078, 1076, 1, 0, 0, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1082, 1, 0, 0, 0, 1080, 1078, 1, 0, 0, 0, 1081, 1083, 5, 116, 0, 0, 1082, 1081, 1, 0, 0, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1085, 1, 0, 0, 0, 1084, 1059, 1, 0, 0, 0, 1084, 1073, 1, 0, 0, 0, 1085, 1086, 1, 0, 0, 0, 1086, 1087, 5, 111, 0, 0, 1087, 1088, 3, 116, 58, 0, 1088, 123, 1, 0, 0, 0, 1089, 1090, 5, 132, 0, 0, 1090, 1094, 3, 160, 80, 0, 1091, 1093, 3, 126, 63, 0, 1092, 1091, 1, 0, 0, 0, 1093, 1096, 1, 0, 0, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1097, 1, 0, 0, 0, 1096, 1094, 1, 0, 0, 0, 1097, 1098, 5, 151, 0, 0, 1098, 1099, 5, 124, 0, 0, 1099, 1122, 1, 0, 0, 0, 1100, 1101, 5, 132, 0, 0, 1101, 1105, 3, 160, 80, 0, 1102, 1104, 3, 126, 63, 0, 1103, 1102, 1, 0, 0, 0, 1104, 1107, 1, 0, 0, 0, 1105, 1103, 1, 0, 0, 0, 1105, 1106, 1, 0, 0, 0, 1106, 1108, 1, 0, 0, 0, 1107, 1105, 1, 0, 0, 0, 1108, 1114, 5, 124, 0, 0, 1109, 1115, 3, 124, 62, 0, 1110, 1111, 5, 128, 0, 0, 1111, 1112, 3, 116, 58, 0, 1112, 1113, 5, 147, 0, 0, 1113, 1115, 1, 0, 0, 0, 1114, 1109, 1, 0, 0, 0, 1114, 1110, 1, 0, 0, 0, 1114, 1115, 1, 0, 0, 0, 1115, 1116, 1, 0, 0, 0, 1116, 1117, 5, 132, 0, 0, 1117, 1118, 5, 151, 0, 0, 1118, 1119, 3, 160, 80, 0, 1119, 1120, 5, 124, 0, 0, 1120, 1122, 1, 0, 0, 0, 1121, 1089, 1, 0, 0, 0, 1121, 1100, 1, 0, 0, 0, 1122, 125, 1, 0, 0, 0, 1123, 1124, 3, 160, 80, 0, 1124, 1125, 5, 122, 0, 0, 1125, 1126, 3, 166, 83, 0, 1126, 1135, 1, 0, 0, 0, 1127, 1128, 3, 160, 80, 0, 1128, 1129, 5, 122, 0, 0, 1129, 1130, 5, 128, 0, 0, 1130, 1131, 3, 116, 58, 0, 1131, 1132, 5, 147, 0, 0, 1132, 1135, 1, 0, 0, 0, 1133, 1135, 3, 160, 80, 0, 1134, 1123, 1, 0, 0, 0, 1134, 1127, 1, 0, 0, 0, 1134, 1133, 1, 0, 0, 0, 1135, 127, 1, 0, 0, 0, 1136, 1141, 3, 130, 65, 0, 1137, 1138, 5, 116, 0, 0, 1138, 1140, 3, 130, 65, 0, 1139, 1137, 1, 0, 0, 0, 1140, 1143, 1, 0, 0, 0, 1141, 1139, 1, 0, 0, 0, 1141, 1142, 1, 0, 0, 0, 1142, 1145, 1, 0, 0, 0, 1143, 1141, 1, 0, 0, 0, 1144, 1146, 5, 116, 0, 0, 1145, 1144, 1, 0, 0, 0, 1145, 1146, 1, 0, 0, 0, 1146, 129, 1, 0, 0, 0, 1147, 1148, 3, 160, 80, 0, 1148, 1149, 5, 6, 0, 0, 1149, 1150, 5, 130, 0, 0, 1150, 1151, 3, 44, 22, 0, 1151, 1152, 5, 149, 0, 0, 1152, 1158, 1, 0, 0, 0, 1153, 1154, 3, 116, 58, 0, 1154, 1155, 5, 6, 0, 0, 1155, 1156, 3, 160, 80, 0, 1156, 1158, 1, 0, 0, 0, 1157, 1147, 1, 0, 0, 0, 1157, 1153, 1, 0, 0, 0, 1158, 131, 1, 0, 0, 0, 1159, 1167, 3, 164, 82, 0, 1160, 1161, 3, 140, 70, 0, 1161, 1162, 5, 120, 0, 0, 1162, 1164, 1, 0, 0, 0, 1163, 1160, 1, 0, 0, 0, 1163, 1164, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1167, 3, 134, 67, 0, 1166, 1159, 1, 0, 0, 0, 1166, 1163, 1, 0, 0, 0, 1167, 133, 1, 0, 0, 0, 1168, 1173, 3, 160, 80, 0, 1169, 1170, 5, 120, 0, 0, 1170, 1172, 3, 160, 80, 0, 1171, 1169, 1, 0, 0, 0, 1172, 1175, 1, 0, 0, 0, 1173, 1171, 1, 0, 0, 0, 1173, 1174, 1, 0, 0, 0, 1174, 135, 1, 0, 0, 0, 1175, 1173, 1, 0, 0, 0, 1176, 1177, 6, 68, -1, 0, 1177, 1186, 3, 140, 70, 0, 1178, 1186, 3, 138, 69, 0, 1179, 1180, 5, 130, 0, 0, 1180, 1181, 3, 44, 22, 0, 1181, 1182, 5, 149, 0, 0, 1182, 1186, 1, 0, 0, 0, 1183, 1186, 3, 124, 62, 0, 1184, 1186, 3, 164, 82, 0, 1185, 1176, 1, 0, 0, 0, 1185, 1178, 1, 0, 0, 0, 1185, 1179, 1, 0, 0, 0, 1185, 1183, 1, 0, 0, 0, 1185, 1184, 1, 0, 0, 0, 1186, 1195, 1, 0, 0, 0, 1187, 1191, 10, 3, 0, 0, 1188, 1192, 3, 158, 79, 0, 1189, 1190, 5, 6, 0, 0, 1190, 1192, 3, 160, 80, 0, 1191, 1188, 1, 0, 0, 0, 1191, 1189, 1, 0, 0, 0, 1192, 1194, 1, 0, 0, 0, 1193, 1187, 1, 0, 0, 0, 1194, 1197, 1, 0, 0, 0, 1195, 1193, 1, 0, 0, 0, 1195, 1196, 1, 0, 0, 0, 1196, 137, 1, 0, 0, 0, 1197, 1195, 1, 0, 0, 0, 1198, 1199, 3, 160, 80, 0, 1199, 1201, 5, 130, 0, 0, 1200, 1202, 3, 142, 71, 0, 1201, 1200, 1, 0, 0, 0, 1201, 1202, 1, 0, 0, 0, 1202, 1203, 1, 0, 0, 0, 1203, 1204, 5, 149, 0, 0, 1204, 139, 1, 0, 0, 0, 1205, 1206, 3, 144, 72, 0, 1206, 1207, 5, 120, 0, 0, 1207, 1209, 1, 0, 0, 0, 1208, 1205, 1, 0, 0, 0, 1208, 1209, 1, 0, 0, 0, 1209, 1210, 1, 0, 0, 0, 1210, 1211, 3, 160, 80, 0, 1211, 141, 1, 0, 0, 0, 1212, 1217, 3, 116, 58, 0, 1213, 1214, 5, 116, 0, 0, 1214, 1216, 3, 116, 58, 0, 1215, 1213, 1, 0, 0, 0, 1216, 1219, 1, 0, 0, 0, 1217, 1215, 1, 0, 0, 0, 1217, 1218, 1, 0, 0, 0, 1218, 1221, 1, 0, 0, 0, 1219, 1217, 1, 0, 0, 0, 1220, 1222, 5, 116, 0, 0, 1221, 1220, 1, 0, 0, 0, 1221, 1222, 1, 0, 0, 0, 1222, 143, 1, 0, 0, 0, 1223, 1224, 3, 160, 80, 0, 1224, 145, 1, 0, 0, 0, 1225, 1234, 5, 106, 0, 0, 1226, 1227, 5, 120, 0, 0, 1227, 1234, 7, 11, 0, 0, 1228, 1229, 5, 108, 0, 0, 1229, 1231, 5, 120, 0, 0, 1230, 1232, 7, 11, 0, 0, 1231, 1230, 1, 0, 0, 0, 1231, 1232, 1, 0, 0, 0, 1232, 1234, 1, 0, 0, 0, 1233, 1225, 1, 0, 0, 0, 1233, 1226, 1, 0, 0, 0, 1233, 1228, 1, 0, 0, 0, 1234, 147, 1, 0, 0, 0, 1235, 1237, 7, 12, 0, 0, 1236, 1235, 1, 0, 0, 0, 1236, 1237, 1, 0, 0, 0, 1237, 1244, 1, 0, 0, 0, 1238, 1245, 3, 146, 73, 0, 1239, 1245, 5, 107, 0, 0, 1240, 1245, 5, 108, 0, 0, 1241, 1245, 5, 109, 0, 0, 1242, 1245, 5, 43, 0, 0, 1243, 1245, 5, 57, 0, 0, 1244, 1238, 1, 0, 0, 0, 1244, 1239, 1, 0, 0, 0, 1244, 1240, 1, 0, 0, 0, 1244, 1241, 1, 0, 0, 0, 1244, 1242, 1, 0, 0, 0, 1244, 1243, 1, 0, 0, 0, 1245, 149, 1, 0, 0, 0, 1246, 1250, 3, 148, 74, 0, 1247, 1250, 5, 110, 0, 0, 1248, 1250, 5, 59, 0, 0, 1249, 1246, 1, 0, 0, 0, 1249, 1247, 1, 0, 0, 0, 1249, 1248, 1, 0, 0, 0, 1250, 151, 1, 0, 0, 0, 1251, 1252, 7, 13, 0, 0, 1252, 153, 1, 0, 0, 0, 1253, 1254, 7, 14, 0, 0, 1254, 155, 1, 0, 0, 0, 1255, 1256, 7, 15, 0, 0, 1256, 157, 1, 0, 0, 0, 1257, 1260, 5, 105, 0, 0, 1258, 1260, 3, 156, 78, 0, 1259, 1257, 1, 0, 0, 0, 1259, 1258, 1, 0, 0, 0, 1260, 159, 1, 0, 0, 0, 1261, 1265, 5, 105, 0, 0, 1262, 1265, 3, 152, 76, 0, 1263, 1265, 3, 154, 77, 0, 1264, 1261, 1, 0, 0, 0, 1264, 1262, 1, 0, 0, 0, 1264, 1263, 1, 0, 0, 0, 1265, 161, 1, 0, 0, 0, 1266, 1267, 3, 166, 83, 0, 1267, 1268, 5, 122, 0, 0, 1268, 1269, 3, 148, 74, 0, 1269, 163, 1, 0, 0, 0, 1270, 1271, 5, 128, 0, 0, 1271, 1272, 3, 160, 80, 0, 1272, 1273, 5, 147, 0, 0, 1273, 165, 1, 0, 0, 0, 1274, 1277, 5, 110, 0, 0, 1275, 1277, 3, 168, 84, 0, 1276, 1274, 1, 0, 0, 0, 1276, 1275, 1, 0, 0, 0, 1277, 167, 1, 0, 0, 0, 1278, 1282, 5, 142, 0, 0, 1279, 1281, 3, 170, 85, 0, 1280, 1279, 1, 0, 0, 0, 1281, 1284, 1, 0, 0, 0, 1282, 1280, 1, 0, 0, 0, 1282, 1283, 1, 0, 0, 0, 1283, 1285, 1, 0, 0, 0, 1284, 1282, 1, 0, 0, 0, 1285, 1286, 5, 144, 0, 0, 1286, 169, 1, 0, 0, 0, 1287, 1288, 5, 157, 0, 0, 1288, 1289, 3, 116, 58, 0, 1289, 1290, 5, 147, 0, 0, 1290, 1293, 1, 0, 0, 0, 1291, 1293, 5, 156, 0, 0, 1292, 1287, 1, 0, 0, 0, 1292, 1291, 1, 0, 0, 0, 1293, 171, 1, 0, 0, 0, 1294, 1298, 5, 143, 0, 0, 1295, 1297, 3, 174, 87, 0, 1296, 1295, 1, 0, 0, 0, 1297, 1300, 1, 0, 0, 0, 1298, 1296, 1, 0, 0, 0, 1298, 1299, 1, 0, 0, 0, 1299, 1301, 1, 0, 0, 0, 1300, 1298, 1, 0, 0, 0, 1301, 1302, 5, 0, 0, 1, 1302, 173, 1, 0, 0, 0, 1303, 1304, 5, 159, 0, 0, 1304, 1305, 3, 116, 58, 0, 1305, 1306, 5, 147, 0, 0, 1306, 1309, 1, 0, 0, 0, 1307, 1309, 5, 158, 0, 0, 1308, 1303, 1, 0, 0, 0, 1308, 1307, 1, 0, 0, 0, 1309, 175, 1, 0, 0, 0, 168, 179, 186, 195, 202, 206, 220, 224, 227, 231, 234, 241, 245, 254, 259, 268, 276, 283, 287, 293, 298, 306, 313, 319, 331, 339, 353, 357, 362, 372, 381, 384, 388, 391, 395, 398, 401, 404, 407, 411, 415, 418, 421, 424, 428, 431, 440, 446, 467, 484, 501, 507, 513, 524, 526, 537, 540, 546, 554, 560, 562, 566, 571, 574, 577, 581, 585, 588, 590, 593, 597, 601, 604, 606, 608, 613, 624, 630, 637, 642, 646, 650, 656, 658, 665, 673, 676, 679, 698, 712, 728, 732, 743, 747, 758, 762, 769, 773, 780, 784, 789, 798, 802, 826, 843, 849, 852, 855, 865, 871, 874, 877, 885, 888, 892, 895, 909, 926, 931, 935, 941, 948, 960, 964, 967, 976, 990, 1029, 1037, 1039, 1041, 1049, 1053, 1057, 1065, 1069, 1078, 1082, 1084, 1094, 1105, 1114, 1121, 1134, 1141, 1145, 1157, 1163, 1166, 1173, 1185, 1191, 1195, 1201, 1208, 1217, 1221, 1231, 1233, 1236, 1244, 1249, 1259, 1264, 1276, 1282, 1292, 1298, 1308] \ No newline at end of file diff --git a/hogql_parser/parser.cpp b/hogql_parser/parser.cpp index 759e11ce8405b..f82dcd2bf476c 100644 --- a/hogql_parser/parser.cpp +++ b/hogql_parser/parser.cpp @@ -469,12 +469,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor { } catch (...) { throw; } - PyObject* ret = build_ast_node("ThrowStatement", "{s:N}", "expr", expr); - if (!ret) { - Py_DECREF(expr); - throw PyInternalError(); - } - return ret; + RETURN_NEW_AST_NODE("ThrowStatement", "{s:N}", "expr", expr); } VISIT(CatchBlock) { @@ -484,8 +479,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor { catch_var = visitAsString(ctx->catchVar); catch_var_py = PyUnicode_FromStringAndSize(catch_var.data(), catch_var.size()); } else { - catch_var_py = Py_None; - Py_INCREF(catch_var_py); + catch_var_py = Py_NewRef(Py_None); } PyObject* catch_type_py; @@ -2490,8 +2484,9 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor { } auto tag_element_ctx = ctx->hogqlxTagElement(); + auto column_expr_ctx = ctx->columnExpr(); auto tag_attribute_ctx = ctx->hogqlxTagAttribute(); - PyObject* attributes = PyList_New(tag_attribute_ctx.size() + (tag_element_ctx ? 1 : 0)); + PyObject* attributes = PyList_New(tag_attribute_ctx.size() + (tag_element_ctx || column_expr_ctx ? 1 : 0)); if (!attributes) throw PyInternalError(); bool found_source = false; for (size_t i = 0; i < tag_attribute_ctx.size(); i++) { @@ -2540,6 +2535,19 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor { throw PyInternalError(); } PyList_SET_ITEM(attributes, tag_attribute_ctx.size(), source_attribute); + } else if (column_expr_ctx) { + if (found_source) { + Py_DECREF(attributes); + throw SyntaxError("Nested HogQLX tags cannot have a source attribute"); + } + PyObject* source_attribute = build_ast_node( + "HogQLXAttribute", "{s:s#,s:N}", "name", "source", 6, "value", visitAsPyObject(ctx->columnExpr()) + ); + if (!source_attribute) { + Py_DECREF(attributes); + throw PyInternalError(); + } + PyList_SET_ITEM(attributes, tag_attribute_ctx.size(), source_attribute); } RETURN_NEW_AST_NODE("HogQLXTag", "{s:s#,s:N}", "kind", opening.data(), opening.size(), "attributes", attributes); diff --git a/hogql_parser/setup.py b/hogql_parser/setup.py index deb55e9dea40d..3c7bc51026aa6 100644 --- a/hogql_parser/setup.py +++ b/hogql_parser/setup.py @@ -32,7 +32,7 @@ setup( name="hogql_parser", - version="1.0.30", + version="1.0.32", url="https://github.com/PostHog/posthog/tree/master/hogql_parser", author="PostHog Inc.", author_email="hey@posthog.com", diff --git a/hogvm/typescript/package.json b/hogvm/typescript/package.json index 6d2c5a3af3155..9c1c69e31b280 100644 --- a/hogvm/typescript/package.json +++ b/hogvm/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@posthog/hogvm", - "version": "1.0.28", + "version": "1.0.30", "description": "PostHog Hog Virtual Machine", "types": "dist/index.d.ts", "main": "dist/index.js", diff --git a/hogvm/typescript/src/__tests__/execute.test.ts b/hogvm/typescript/src/__tests__/execute.test.ts index 19365668f514d..435b7d873abfe 100644 --- a/hogvm/typescript/src/__tests__/execute.test.ts +++ b/hogvm/typescript/src/__tests__/execute.test.ts @@ -531,7 +531,7 @@ describe('hogvm execute', () => { maxMemUsed: 16, ops: 3, stack: [4.2], - syncDuration: 0, + syncDuration: expect.any(Number), }, }) }) @@ -547,6 +547,45 @@ describe('hogvm execute', () => { expect(exec(bytecode)).toEqual({ finished: true, result: '0.002', + state: { + asyncSteps: 0, + bytecode: [], + callStack: [], + declaredFunctions: {}, + ip: -1, + maxMemUsed: 13, + ops: 2, + stack: [], + throwStack: [], + syncDuration: expect.any(Number), + }, + }) + }) + test('exec runs at sync return', () => { + const bytecode = [ + '_h', + 33, + 0.002, // seconds to sleep + 2, + 'toString', + 1, + op.RETURN, + ] + expect(exec(bytecode)).toEqual({ + finished: true, + result: '0.002', + state: { + asyncSteps: 0, + bytecode: [], + callStack: [], + declaredFunctions: {}, + ip: -1, + maxMemUsed: 13, + ops: 3, + stack: [], + throwStack: [], + syncDuration: expect.any(Number), + }, }) }) test('test bytecode dicts', () => { diff --git a/hogvm/typescript/src/execute.ts b/hogvm/typescript/src/execute.ts index cf502e94ed194..389e1ded547f2 100644 --- a/hogvm/typescript/src/execute.ts +++ b/hogvm/typescript/src/execute.ts @@ -175,6 +175,20 @@ export function exec(code: any[] | VMState, options?: ExecOptions): ExecResult { throw new HogVMException(`Execution timed out after ${timeout / 1000} seconds. Performed ${ops} ops.`) } } + function getFinishedState(): VMState { + return { + bytecode: [], + stack: [], + callStack: [], + throwStack: [], + declaredFunctions: {}, + ip: -1, + ops, + asyncSteps, + syncDuration: syncDuration + (Date.now() - startTime), + maxMemUsed, + } + } for (; ip < bytecode.length; ip++) { ops += 1 @@ -314,6 +328,7 @@ export function exec(code: any[] | VMState, options?: ExecOptions): ExecResult { return { result: popStack(), finished: true, + state: getFinishedState(), } satisfies ExecResult } case Operation.GET_LOCAL: @@ -477,9 +492,11 @@ export function exec(code: any[] | VMState, options?: ExecOptions): ExecResult { if (stack.length > 1) { throw new HogVMException('Invalid bytecode. More than one value left on stack') - } else if (stack.length === 0) { - return { result: null, finished: true } satisfies ExecResult } - return { result: popStack() ?? null, finished: true } satisfies ExecResult + if (stack.length === 0) { + return { result: null, finished: true, state: getFinishedState() } satisfies ExecResult + } + + return { result: popStack() ?? null, finished: true, state: getFinishedState() } satisfies ExecResult } diff --git a/mypy-baseline.txt b/mypy-baseline.txt index 7ca3fda0ce461..76b7e1490f5ed 100644 --- a/mypy-baseline.txt +++ b/mypy-baseline.txt @@ -256,6 +256,9 @@ posthog/models/property/util.py:0: error: Argument 1 to "append" of "list" has i posthog/models/property/util.py:0: error: Argument 1 to "append" of "list" has incompatible type "str | int"; expected "str" [arg-type] posthog/models/property/util.py:0: error: Argument 1 to "append" of "list" has incompatible type "str | int"; expected "str" [arg-type] posthog/queries/trends/util.py:0: error: Argument 1 to "translate_hogql" has incompatible type "str | None"; expected "str" [arg-type] +posthog/hogql/property.py:0: error: Argument "chain" to "Field" has incompatible type "list[str]"; expected "list[str | int]" [arg-type] +posthog/hogql/property.py:0: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance +posthog/hogql/property.py:0: note: Consider using "Sequence" instead, which is covariant posthog/hogql/property.py:0: error: Incompatible type for lookup 'id': (got "str | int | list[str]", expected "str | int") [misc] posthog/hogql/property.py:0: error: Incompatible type for lookup 'pk': (got "str | float", expected "str | int") [misc] posthog/hogql/filters.py:0: error: Incompatible default for argument "team" (default has type "None", argument has type "Team") [assignment] diff --git a/plugin-server/package.json b/plugin-server/package.json index ca4a1b7503ffe..e7fe6138781a9 100644 --- a/plugin-server/package.json +++ b/plugin-server/package.json @@ -50,7 +50,7 @@ "@google-cloud/storage": "^5.8.5", "@maxmind/geoip2-node": "^3.4.0", "@posthog/clickhouse": "^1.7.0", - "@posthog/hogvm": "^1.0.28", + "@posthog/hogvm": "^1.0.30", "@posthog/plugin-scaffold": "1.4.4", "@sentry/node": "^7.49.0", "@sentry/profiling-node": "^0.3.0", diff --git a/plugin-server/pnpm-lock.yaml b/plugin-server/pnpm-lock.yaml index 3c287c8cd565b..323664424efff 100644 --- a/plugin-server/pnpm-lock.yaml +++ b/plugin-server/pnpm-lock.yaml @@ -44,8 +44,8 @@ dependencies: specifier: ^1.7.0 version: 1.7.0 '@posthog/hogvm': - specifier: ^1.0.28 - version: 1.0.28(luxon@3.4.4)(re2@1.20.3) + specifier: ^1.0.30 + version: 1.0.30(luxon@3.4.4)(re2@1.20.3) '@posthog/plugin-scaffold': specifier: 1.4.4 version: 1.4.4 @@ -3110,8 +3110,8 @@ packages: engines: {node: '>=12'} dev: false - /@posthog/hogvm@1.0.28(luxon@3.4.4)(re2@1.20.3): - resolution: {integrity: sha512-xkPcBj8kHCdeIA1dAoPDqFzk1pcuI+abbxSJyjfLqwglZtWSu1pASCLA+U0/CTKNe0yMcqVAC9kNc3yt9pujBQ==} + /@posthog/hogvm@1.0.30(luxon@3.4.4)(re2@1.20.3): + resolution: {integrity: sha512-u501rsyskUUnFgMUZjYDfU3pBKp17CKq7aHPAgFpQVFLt1fE9KOQT/hakBjhM9OFUHpjod3SJX3NpbXhOgjz3Q==} peerDependencies: luxon: ^3.4.4 re2: ^1.21.3 diff --git a/plugin-server/src/cdp/async-function-executor.ts b/plugin-server/src/cdp/async-function-executor.ts index 89d72005213a4..93dd7e285cb78 100644 --- a/plugin-server/src/cdp/async-function-executor.ts +++ b/plugin-server/src/cdp/async-function-executor.ts @@ -5,7 +5,7 @@ import { PluginsServerConfig, ValueMatcher } from '../types' import { trackedFetch } from '../utils/fetch' import { status } from '../utils/status' import { RustyHook } from '../worker/rusty-hook' -import { HogFunctionInvocationAsyncResponse, HogFunctionInvocationResult } from './types' +import { HogFunctionInvocationAsyncRequest, HogFunctionInvocationAsyncResponse } from './types' export const BUCKETS_KB_WRITTEN = [0, 128, 512, 1024, 2024, 4096, 10240, Infinity] @@ -33,7 +33,7 @@ export class AsyncFunctionExecutor { } async execute( - request: HogFunctionInvocationResult, + request: HogFunctionInvocationAsyncRequest, options: AsyncFunctionExecutorOptions = { sync: false } ): Promise { if (!request.asyncFunctionRequest) { @@ -42,7 +42,6 @@ export class AsyncFunctionExecutor { const loggingContext = { hogFunctionId: request.hogFunctionId, - invocationId: request.id, asyncFunctionName: request.asyncFunctionRequest.name, } status.info('🦔', `[AsyncFunctionExecutor] Executing async function`, loggingContext) @@ -61,7 +60,7 @@ export class AsyncFunctionExecutor { } private async asyncFunctionFetch( - request: HogFunctionInvocationResult, + request: HogFunctionInvocationAsyncRequest, options?: AsyncFunctionExecutorOptions ): Promise { if (!request.asyncFunctionRequest) { @@ -69,6 +68,7 @@ export class AsyncFunctionExecutor { } const asyncFunctionResponse: HogFunctionInvocationAsyncResponse['asyncFunctionResponse'] = { + response: null, timings: [], } @@ -130,7 +130,7 @@ export class AsyncFunctionExecutor { const duration = performance.now() - start - asyncFunctionResponse.timings.push({ + asyncFunctionResponse.timings!.push({ kind: 'async_function', duration_ms: duration, }) @@ -145,7 +145,9 @@ export class AsyncFunctionExecutor { } const response: HogFunctionInvocationAsyncResponse = { - ...request, + state: request.state, + teamId: request.teamId, + hogFunctionId: request.hogFunctionId, asyncFunctionResponse, } diff --git a/plugin-server/src/cdp/cdp-api.ts b/plugin-server/src/cdp/cdp-api.ts index 642061adef622..b0e3e2242c0aa 100644 --- a/plugin-server/src/cdp/cdp-api.ts +++ b/plugin-server/src/cdp/cdp-api.ts @@ -9,7 +9,7 @@ import { addLog, HogExecutor } from './hog-executor' import { HogFunctionManager } from './hog-function-manager' import { HogWatcher } from './hog-watcher/hog-watcher' import { HogWatcherState } from './hog-watcher/types' -import { HogFunctionInvocation, HogFunctionType } from './types' +import { HogFunctionInvocation, HogFunctionInvocationAsyncRequest, HogFunctionLogEntry, HogFunctionType } from './types' export class CdpApi { private hogExecutor: HogExecutor @@ -110,7 +110,6 @@ export class CdpApi { globals: globals, teamId: team.id, hogFunctionId: id, - logs: [], timings: [], } @@ -125,8 +124,11 @@ export class CdpApi { await this.hogFunctionManager.enrichWithIntegrations([compoundConfiguration]) let response = this.hogExecutor.execute(compoundConfiguration, invocation) + const logs: HogFunctionLogEntry[] = [] while (response.asyncFunctionRequest) { + invocation.vmState = response.invocation.vmState + const asyncFunctionRequest = response.asyncFunctionRequest if (mock_async_functions || asyncFunctionRequest.name !== 'fetch') { @@ -140,31 +142,34 @@ export class CdpApi { ) // Add the state, simulating what executeAsyncResponse would do - asyncFunctionRequest.vmState.stack.push(convertJSToHog({ status: 200, body: {} })) + invocation.vmState!.stack.push(convertJSToHog({ status: 200, body: {} })) } else { - const asyncRes = await this.asyncFunctionExecutor!.execute(response, { + const asyncInvocationRequest: HogFunctionInvocationAsyncRequest = { + state: '', // WE don't care about the state for this level of testing + teamId: team.id, + hogFunctionId: hogFunction.id, + asyncFunctionRequest, + } + const asyncRes = await this.asyncFunctionExecutor!.execute(asyncInvocationRequest, { sync: true, }) if (!asyncRes || asyncRes.asyncFunctionResponse.error) { addLog(response, 'error', 'Failed to execute async function') } - asyncFunctionRequest.vmState.stack.push( - convertJSToHog(asyncRes?.asyncFunctionResponse.response ?? null) - ) - response.timings.push(...(asyncRes?.asyncFunctionResponse.timings ?? [])) + invocation.vmState!.stack.push(convertJSToHog(asyncRes?.asyncFunctionResponse.response ?? null)) } - // Clear it so we can't ever end up in a loop - delete response.asyncFunctionRequest - - response = this.hogExecutor.execute(compoundConfiguration, response, asyncFunctionRequest.vmState) + logs.push(...response.logs) + response = this.hogExecutor.execute(compoundConfiguration, invocation) } + logs.push(...response.logs) + res.json({ status: response.finished ? 'success' : 'error', error: String(response.error), - logs: response.logs, + logs: logs, }) } catch (e) { console.error(e) diff --git a/plugin-server/src/cdp/cdp-consumers.ts b/plugin-server/src/cdp/cdp-consumers.ts index 93f0c8797bb0f..d9f453d4b90cb 100644 --- a/plugin-server/src/cdp/cdp-consumers.ts +++ b/plugin-server/src/cdp/cdp-consumers.ts @@ -1,3 +1,4 @@ +import { captureException } from '@sentry/node' import { features, librdkafkaVersion, Message } from 'node-rdkafka' import { Counter, Histogram } from 'prom-client' @@ -27,14 +28,18 @@ import { HogWatcher } from './hog-watcher/hog-watcher' import { HogWatcherState } from './hog-watcher/types' import { CdpOverflowMessage, + HogFunctionAsyncFunctionResponse, + HogFunctionInvocation, + HogFunctionInvocationAsyncRequest, HogFunctionInvocationAsyncResponse, HogFunctionInvocationGlobals, HogFunctionInvocationResult, + HogFunctionLogEntry, HogFunctionMessageToProduce, HogFunctionOverflowedGlobals, HogFunctionType, } from './types' -import { convertToCaptureEvent, convertToHogFunctionInvocationGlobals } from './utils' +import { convertToCaptureEvent, convertToHogFunctionInvocationGlobals, gzipObject, unGzipObject } from './utils' // Must require as `tsc` strips unused `import` statements and just requiring this seems to init some globals require('@sentry/tracing') @@ -145,6 +150,8 @@ abstract class CdpConsumerBase { value: Buffer.from(JSON.stringify(x.value)), key: x.key, waitForAck: true, + }).catch((reason) => { + status.error('⚠️', `failed to produce message: ${reason}`) }) ) ) @@ -168,6 +175,19 @@ abstract class CdpConsumerBase { counterFunctionInvocation.inc({ outcome: appMetric.metric_name }, appMetric.count) } + protected logLogEntry(logEntry: HogFunctionLogEntry) { + const sanitized = { + ...logEntry, + timestamp: castTimestampOrNow(logEntry.timestamp, TimestampFormat.ClickHouse), + } + // Convert timestamps to ISO strings + this.messagesToProduce.push({ + topic: KAFKA_LOG_ENTRIES, + value: sanitized, + key: sanitized.instance_id, + }) + } + protected async processInvocationResults(results: HogFunctionInvocationResult[]): Promise { await runInstrumentedFunction({ statsKey: `cdpConsumer.handleEachBatch.produceResults`, @@ -179,25 +199,14 @@ abstract class CdpConsumerBase { result.logs = [] this.logAppMetrics({ - team_id: result.teamId, - app_source_id: result.hogFunctionId, + team_id: result.invocation.teamId, + app_source_id: result.invocation.hogFunctionId, metric_kind: result.error ? 'failure' : 'success', metric_name: result.error ? 'failed' : 'succeeded', count: 1, }) - logs.forEach((x) => { - const sanitized = { - ...x, - timestamp: castTimestampOrNow(x.timestamp, TimestampFormat.ClickHouse), - } - // Convert timestamps to ISO strings - this.messagesToProduce.push({ - topic: KAFKA_LOG_ENTRIES, - value: sanitized, - key: sanitized.instance_id, - }) - }) + logs.forEach((x) => this.logLogEntry(x)) // PostHog capture events const capturedEvents = result.capturedPostHogEvents @@ -216,7 +225,13 @@ abstract class CdpConsumerBase { } if (result.asyncFunctionRequest) { - const res = await this.runWithHeartbeat(() => this.asyncFunctionExecutor.execute(result)) + const request: HogFunctionInvocationAsyncRequest = { + state: await gzipObject(result.invocation), + teamId: result.invocation.teamId, + hogFunctionId: result.invocation.hogFunctionId, + asyncFunctionRequest: result.asyncFunctionRequest, + } + const res = await this.runWithHeartbeat(() => this.asyncFunctionExecutor.execute(request)) // NOTE: This is very temporary as it is producing the response. the response will actually be produced by the 3rd party service // Later this will actually be the _request_ which we will push to the async function topic if we make one @@ -224,7 +239,7 @@ abstract class CdpConsumerBase { this.messagesToProduce.push({ topic: KAFKA_CDP_FUNCTION_CALLBACKS, value: res, - key: res.id, + key: res.hogFunctionId, }) } } @@ -261,7 +276,7 @@ abstract class CdpConsumerBase { source: 'hog_function_callback', payload: item, }, - key: item.id, + key: item.hogFunctionId, }) // We don't report overflowed metric to appmetrics as it is sort of a meta-metric counterFunctionInvocation.inc({ outcome: 'overflowed' }) @@ -282,8 +297,25 @@ abstract class CdpConsumerBase { } } - const results = await this.runManyWithHeartbeat(asyncResponsesToRun, (item) => - this.hogExecutor.executeAsyncResponse(item) + const invocationsWithResponses: [HogFunctionInvocation, HogFunctionAsyncFunctionResponse][] = [] + + // Deserialize the compressed data + await Promise.all( + asyncResponses.map(async (item) => { + try { + const invocation = await unGzipObject(item.state) + invocationsWithResponses.push([invocation, item.asyncFunctionResponse]) + } catch (e) { + status.error('Error unzipping message', e, item.state) + captureException(e, { + extra: { hogFunctionId: item.hogFunctionId, teamId: item.teamId }, + }) + } + }) + ) + + const results = await this.runManyWithHeartbeat(invocationsWithResponses, (item) => + this.hogExecutor.executeAsyncResponse(...item) ) this.hogWatcher.currentObservations.observeResults(results) @@ -547,8 +579,7 @@ export class CdpFunctionCallbackConsumer extends CdpConsumerBase { const events: HogFunctionInvocationAsyncResponse[] = [] messages.map((message) => { try { - const event = JSON.parse(message.value!.toString()) as unknown - + const event = JSON.parse(message.value!.toString()) events.push(event as HogFunctionInvocationAsyncResponse) } catch (e) { status.error('Error parsing message', e) diff --git a/plugin-server/src/cdp/hog-executor.ts b/plugin-server/src/cdp/hog-executor.ts index debab8c702561..db04a0f76e334 100644 --- a/plugin-server/src/cdp/hog-executor.ts +++ b/plugin-server/src/cdp/hog-executor.ts @@ -1,4 +1,4 @@ -import { convertHogToJS, convertJSToHog, exec, ExecResult, VMState } from '@posthog/hogvm' +import { calculateCost, convertHogToJS, convertJSToHog, exec, ExecResult } from '@posthog/hogvm' import { DateTime } from 'luxon' import { Histogram } from 'prom-client' @@ -67,10 +67,10 @@ export const addLog = (result: HogFunctionInvocationResult, level: HogFunctionLo } result.logs.push({ - team_id: result.teamId, + team_id: result.invocation.teamId, log_source: 'hog_function', - log_source_id: result.hogFunctionId, - instance_id: result.id, + log_source_id: result.invocation.hogFunctionId, + instance_id: result.invocation.id, timestamp: now, level, message, @@ -121,6 +121,7 @@ export class HogExecutor { } } } catch (error) { + // TODO: This should be reported as a log or metric status.error('🦔', `[HogExecutor] Error filtering function`, { hogFunctionId: hogFunction.id, hogFunctionName: hogFunction.name, @@ -174,7 +175,6 @@ export class HogExecutor { globals: modifiedGlobals, teamId: hogFunction.team_id, hogFunctionId: hogFunction.id, - logs: [], timings: [], }) } @@ -182,25 +182,19 @@ export class HogExecutor { /** * Intended to be invoked as a continuation from an async function */ - executeAsyncResponse(invocation: HogFunctionInvocationAsyncResponse): HogFunctionInvocationResult { + executeAsyncResponse( + invocation: HogFunctionInvocation, + asyncFunctionResponse: HogFunctionInvocationAsyncResponse['asyncFunctionResponse'] + ): HogFunctionInvocationResult { if (!invocation.hogFunctionId) { throw new Error('No hog function id provided') } - const baseInvocation: HogFunctionInvocation = { - id: invocation.id, - globals: invocation.globals, - teamId: invocation.teamId, - hogFunctionId: invocation.hogFunctionId, - timings: invocation.asyncFunctionResponse.timings, - // Logs we always reset as we don't want to carry over logs between calls - logs: [], - } - const errorRes = (error = 'Something went wrong'): HogFunctionInvocationResult => ({ - ...baseInvocation, + invocation, finished: false, error, + logs: [], }) const hogFunction = this.hogFunctionManager.getTeamHogFunction( @@ -212,24 +206,23 @@ export class HogExecutor { return errorRes(`Hog Function with ID ${invocation.hogFunctionId} not found`) } - const { vmState } = invocation.asyncFunctionRequest ?? {} - const { asyncFunctionResponse } = invocation - - if (!vmState || !asyncFunctionResponse.response || asyncFunctionResponse.error) { - return errorRes(invocation.error ?? 'No VM state provided for async response') + if (!invocation.vmState || !asyncFunctionResponse.response || asyncFunctionResponse.error) { + return errorRes(asyncFunctionResponse.error ?? 'No VM state provided for async response') } // Add the response to the stack to continue execution - vmState.stack.push(convertJSToHog(asyncFunctionResponse.response ?? null)) + invocation.vmState.stack.push(convertJSToHog(asyncFunctionResponse.response ?? null)) + invocation.timings.push(...(asyncFunctionResponse.timings ?? [])) + + const res = this.execute(hogFunction, invocation) + + // Add any timings and logs from the async function + res.logs = [...(asyncFunctionResponse.logs ?? []), ...res.logs] - return this.execute(hogFunction, baseInvocation, vmState) + return res } - execute( - hogFunction: HogFunctionType, - invocation: HogFunctionInvocation, - state?: VMState - ): HogFunctionInvocationResult { + execute(hogFunction: HogFunctionType, invocation: HogFunctionInvocation): HogFunctionInvocationResult { const loggingContext = { hogFunctionId: hogFunction.id, hogFunctionName: hogFunction.name, @@ -239,13 +232,14 @@ export class HogExecutor { status.debug('🦔', `[HogExecutor] Executing function`, loggingContext) const result: HogFunctionInvocationResult = { - ...invocation, + invocation, asyncFunctionRequest: undefined, finished: false, capturedPostHogEvents: [], + logs: [], } - if (!state) { + if (!invocation.vmState) { addLog(result, 'debug', `Executing function`) } else { addLog(result, 'debug', `Resuming function`) @@ -267,7 +261,7 @@ export class HogExecutor { try { let hogLogs = 0 - execRes = exec(state ?? hogFunction.bytecode, { + execRes = exec(invocation.vmState ?? hogFunction.bytecode, { globals, timeout: DEFAULT_TIMEOUT_MS, // TODO: Swap this to milliseconds when the package is updated maxAsyncSteps: MAX_ASYNC_STEPS, // NOTE: This will likely be configurable in the future @@ -336,33 +330,43 @@ export class HogExecutor { hogExecutionDuration.observe(duration) result.finished = execRes.finished - result.timings.push({ + invocation.timings.push({ kind: 'hog', duration_ms: duration, }) if (!execRes.finished) { - addLog(result, 'debug', `Suspending function due to async function call '${execRes.asyncFunctionName}'`) - const args = (execRes.asyncFunctionArgs ?? []).map((arg) => convertHogToJS(arg)) - if (!execRes.state) { // NOTE: This shouldn't be possible so is more of a type sanity check throw new Error('State should be provided for async function') } + addLog( + result, + 'debug', + `Suspending function due to async function call '${execRes.asyncFunctionName}'. Payload: ${ + calculateCost(execRes.state) + calculateCost(args) + } bytes` + ) + if (execRes.asyncFunctionName) { + result.invocation.vmState = execRes.state result.asyncFunctionRequest = { name: execRes.asyncFunctionName, args: args, - vmState: execRes.state, } } else { addLog(result, 'warn', `Function was not finished but also had no async function to execute.`) } } else { - const totalDuration = result.timings.reduce((acc, timing) => acc + timing.duration_ms, 0) - - addLog(result, 'debug', `Function completed. Processing time ${totalDuration}ms`) + const totalDuration = invocation.timings.reduce((acc, timing) => acc + timing.duration_ms, 0) + const messages = [`Function completed in ${totalDuration}ms.`] + if (execRes.state) { + messages.push(`Sync: ${execRes.state.syncDuration}ms.`) + messages.push(`Mem: ${execRes.state.maxMemUsed} bytes.`) + messages.push(`Ops: ${execRes.state.ops}.`) + } + addLog(result, 'debug', messages.join(' ')) } } catch (err) { result.error = err.message diff --git a/plugin-server/src/cdp/hog-watcher/hog-watcher.ts b/plugin-server/src/cdp/hog-watcher/hog-watcher.ts index 8d531d8b36410..d8fd248d7bc44 100644 --- a/plugin-server/src/cdp/hog-watcher/hog-watcher.ts +++ b/plugin-server/src/cdp/hog-watcher/hog-watcher.ts @@ -64,7 +64,7 @@ export class HogWatcherActiveObservations { observeResults(results: HogFunctionInvocationResult[]) { results.forEach((result) => - this.addObservations(result.hogFunctionId, { + this.addObservations(result.invocation.hogFunctionId, { successes: result.finished ? 1 : 0, failures: result.error ? 1 : 0, }) @@ -75,8 +75,8 @@ export class HogWatcherActiveObservations { // NOTE: This probably wants to be done using the response status instead :thinking: responses.forEach((response) => this.addObservations(response.hogFunctionId, { - asyncFunctionSuccesses: response.error ? 0 : 1, - asyncFunctionFailures: response.error ? 1 : 0, + asyncFunctionSuccesses: response.asyncFunctionResponse.error ? 0 : 1, + asyncFunctionFailures: response.asyncFunctionResponse.error ? 1 : 0, }) ) } diff --git a/plugin-server/src/cdp/types.ts b/plugin-server/src/cdp/types.ts index 7201f2b730c9e..9273f5a7210c3 100644 --- a/plugin-server/src/cdp/types.ts +++ b/plugin-server/src/cdp/types.ts @@ -149,36 +149,55 @@ export interface HogFunctionTiming { duration_ms: number } +// This is the "persistent" state of a hog function invocation export type HogFunctionInvocation = { id: string globals: HogFunctionInvocationGlobals teamId: number hogFunctionId: HogFunctionType['id'] - // Logs and timings _could_ be passed in from the async function service - logs: HogFunctionLogEntry[] + // The current vmstate (set if the invocation is paused) + vmState?: VMState timings: HogFunctionTiming[] } -export type HogFunctionInvocationResult = HogFunctionInvocation & { +export type HogFunctionAsyncFunctionRequest = { + name: string + args: any[] +} + +export type HogFunctionAsyncFunctionResponse = { + /** An error message to indicate something went wrong and the invocation should be stopped */ + error?: any + /** The data to be passed to the Hog function from the response */ + response: any + timings?: HogFunctionTiming[] + logs?: HogFunctionLogEntry[] +} + +// The result of an execution +export type HogFunctionInvocationResult = { + invocation: HogFunctionInvocation finished: boolean error?: any - asyncFunctionRequest?: { - name: string - args: any[] - vmState: VMState - } + asyncFunctionRequest?: HogFunctionAsyncFunctionRequest + logs: HogFunctionLogEntry[] capturedPostHogEvents?: HogFunctionCapturedEvent[] } -export type HogFunctionInvocationAsyncResponse = HogFunctionInvocationResult & { +export type HogFunctionInvocationAsyncRequest = { + state: string // Serialized HogFunctionInvocation without the asyncFunctionRequest + teamId: number + hogFunctionId: HogFunctionType['id'] + asyncFunctionRequest?: HogFunctionAsyncFunctionRequest +} + +export type HogFunctionInvocationAsyncResponse = { + state: string // Serialized HogFunctionInvocation + teamId: number + hogFunctionId: HogFunctionType['id'] + // FOLLOWUP: do we want to type this more strictly? - asyncFunctionResponse: { - /** An error message to indicate something went wrong and the invocation should be stopped */ - error?: any - /** The data to be passed to the Hog function from the response */ - response?: any - timings: HogFunctionTiming[] - } + asyncFunctionResponse: HogFunctionAsyncFunctionResponse } // Mostly copied from frontend types diff --git a/plugin-server/src/cdp/utils.ts b/plugin-server/src/cdp/utils.ts index f95494c9906e3..636213c27c10f 100644 --- a/plugin-server/src/cdp/utils.ts +++ b/plugin-server/src/cdp/utils.ts @@ -1,6 +1,7 @@ // NOTE: PostIngestionEvent is our context event - it should never be sent directly to an output, but rather transformed into a lightweight schema import { DateTime } from 'luxon' +import { gunzip, gzip } from 'zlib' import { RawClickHouseEvent, Team } from '../types' import { safeClickhouseString } from '../utils/db/utils' @@ -136,3 +137,24 @@ export const convertToCaptureEvent = (event: HogFunctionCapturedEvent, team: Tea token: team.api_token, } } + +export const gzipObject = async (object: T): Promise => { + const payload = JSON.stringify(object) + const buffer = await new Promise((res, rej) => + gzip(payload, (err, result) => (err ? rej(err) : res(result))) + ) + const res = buffer.toString('base64') + + // NOTE: Base64 encoding isn't as efficient but we would need to change the kafka producer/consumers to use ucs2 or something + // as well in order to support binary data better + + return res +} + +export const unGzipObject = async (data: string): Promise => { + const res = await new Promise((res, rej) => + gunzip(Buffer.from(data, 'base64'), (err, result) => (err ? rej(err) : res(result))) + ) + + return JSON.parse(res.toString()) +} diff --git a/plugin-server/tests/cdp/cdp-function-callbacks-consumer.test.ts b/plugin-server/tests/cdp/cdp-function-callbacks-consumer.test.ts index 24b8d9a337322..137c75d6594ac 100644 --- a/plugin-server/tests/cdp/cdp-function-callbacks-consumer.test.ts +++ b/plugin-server/tests/cdp/cdp-function-callbacks-consumer.test.ts @@ -163,7 +163,7 @@ describe('CDP Processed Events Consuner', () => { { log_source: 'hog_function', level: 'debug', - message: "Suspending function due to async function call 'fetch'", + message: "Suspending function due to async function call 'fetch'. Payload: 1140 bytes", }, { log_source: 'hog_function', @@ -188,7 +188,7 @@ describe('CDP Processed Events Consuner', () => { { log_source: 'hog_function', level: 'debug', - message: expect.stringContaining('Function completed. Processing time'), + message: expect.stringContaining('Function completed in '), }, ], }) @@ -218,7 +218,7 @@ describe('CDP Processed Events Consuner', () => { { log_source: 'hog_function', level: 'debug', - message: "Suspending function due to async function call 'fetch'", + message: "Suspending function due to async function call 'fetch'. Payload: 1140 bytes", }, { log_source: 'hog_function', @@ -233,7 +233,7 @@ describe('CDP Processed Events Consuner', () => { { log_source: 'hog_function', level: 'debug', - message: expect.stringContaining('Function completed. Processing time'), + message: expect.stringContaining('Function completed in'), }, ], }) diff --git a/plugin-server/tests/cdp/cdp-processed-events-consumer.test.ts b/plugin-server/tests/cdp/cdp-processed-events-consumer.test.ts index 78ba1f78dc2b7..4de26bd05fca0 100644 --- a/plugin-server/tests/cdp/cdp-processed-events-consumer.test.ts +++ b/plugin-server/tests/cdp/cdp-processed-events-consumer.test.ts @@ -49,7 +49,7 @@ jest.mock('../../src/utils/db/kafka-producer-wrapper', () => { connect: jest.fn(), }, disconnect: jest.fn(), - produce: jest.fn(), + produce: jest.fn(() => Promise.resolve()), } return { KafkaProducerWrapper: jest.fn(() => mockKafkaProducer), @@ -211,61 +211,20 @@ describe('CDP Processed Events Consuner', () => { topic: 'log_entries_test', value: { log_source: 'hog_function', - message: "Suspending function due to async function call 'fetch'", + message: "Suspending function due to async function call 'fetch'. Payload: 1497 bytes", team_id: 2, }, }) const msg = decodeKafkaMessage(mockProducer.produce.mock.calls[3][0]) - // Parse body so it can match by object equality rather than exact string equality - msg.value.asyncFunctionRequest.args[1].body = JSON.parse(msg.value.asyncFunctionRequest.args[1].body) + expect(msg).toEqual({ key: expect.any(String), topic: 'cdp_function_callbacks_test', value: { - id: expect.any(String), - globals: expect.objectContaining({ - project: { id: 2, name: 'TEST PROJECT', url: 'http://localhost:8000/project/2' }, - // We assume the rest is correct - }), + state: expect.any(String), + hogFunctionId: hogFunction.id, teamId: 2, - hogFunctionId: expect.any(String), - finished: false, - logs: [], - timings: [ - { - kind: 'hog', - duration_ms: expect.any(Number), - }, - ], - asyncFunctionRequest: { - name: 'fetch', - args: [ - 'https://example.com/posthog-webhook', - { - headers: { version: 'v=1.0.0' }, - body: { - event: { - uuid: 'b3a1fe86-b10c-43cc-acaf-d208977608d0', - name: '$pageview', - distinct_id: 'distinct_id_1', - properties: { $lib_version: '1.0.0', $elements_chain: '[]' }, - timestamp: null, - url: 'http://localhost:8000/project/2/events/b3a1fe86-b10c-43cc-acaf-d208977608d0/null', - }, - groups: {}, - nested: { - foo: 'http://localhost:8000/project/2/events/b3a1fe86-b10c-43cc-acaf-d208977608d0/null', - }, - person: null, - event_url: - 'http://localhost:8000/project/2/events/b3a1fe86-b10c-43cc-acaf-d208977608d0/null-test', - }, - method: 'POST', - }, - ], - vmState: expect.any(Object), - }, asyncFunctionResponse: { response: { status: 200, diff --git a/plugin-server/tests/cdp/hog-executor.test.ts b/plugin-server/tests/cdp/hog-executor.test.ts index 9ca43af1b56ab..ba336799b87e4 100644 --- a/plugin-server/tests/cdp/hog-executor.test.ts +++ b/plugin-server/tests/cdp/hog-executor.test.ts @@ -3,7 +3,7 @@ import { DateTime } from 'luxon' import { HogExecutor } from '../../src/cdp/hog-executor' import { HogFunctionManager } from '../../src/cdp/hog-function-manager' import { - HogFunctionInvocationAsyncResponse, + HogFunctionAsyncFunctionResponse, HogFunctionInvocationResult, HogFunctionLogEntry, HogFunctionType, @@ -13,20 +13,17 @@ import { castTimestampOrNow } from '../../src/utils/utils' import { HOG_EXAMPLES, HOG_FILTERS_EXAMPLES, HOG_INPUTS_EXAMPLES } from './examples' import { createHogExecutionGlobals, createHogFunction, insertHogFunction as _insertHogFunction } from './fixtures' -const simulateMockFetchAsyncResponse = (result: HogFunctionInvocationResult): HogFunctionInvocationAsyncResponse => { +const createAsyncFunctionResponse = (): HogFunctionAsyncFunctionResponse => { return { - ...result, - asyncFunctionResponse: { - timings: [ - { - kind: 'async_function', - duration_ms: 100, - }, - ], - response: { - status: 200, - body: 'success', + timings: [ + { + kind: 'async_function', + duration_ms: 100, }, + ], + response: { + status: 200, + body: 'success', }, } } @@ -61,15 +58,19 @@ describe('Hog Executor', () => { mockFunctionManager.getTeamHogFunction.mockReturnValue(hogFunction) }) - it('can parse incoming messages correctly', () => { + it('can execute messages', () => { const globals = createHogExecutionGlobals() const results = executor .findMatchingFunctions(createHogExecutionGlobals()) .matchingFunctions.map((x) => executor.executeFunction(globals, x) as HogFunctionInvocationResult) expect(results).toHaveLength(1) expect(results[0]).toMatchObject({ - id: expect.any(String), - hogFunctionId: hogFunction.id, + invocation: { + id: expect.any(String), + hogFunctionId: hogFunction.id, + }, + finished: false, + asyncFunctionRequest: {}, }) }) @@ -83,7 +84,7 @@ describe('Hog Executor', () => { team_id: 1, log_source: 'hog_function', log_source_id: hogFunction.id, - instance_id: results[0].id, + instance_id: results[0].invocation.id, timestamp: expect.any(DateTime), level: 'debug', message: 'Executing function', @@ -92,10 +93,10 @@ describe('Hog Executor', () => { team_id: 1, log_source: 'hog_function', log_source_id: hogFunction.id, - instance_id: results[0].id, + instance_id: results[0].invocation.id, timestamp: expect.any(DateTime), level: 'debug', - message: "Suspending function due to async function call 'fetch'", + message: "Suspending function due to async function call 'fetch'. Payload: 1299 bytes", }, ]) @@ -125,7 +126,7 @@ describe('Hog Executor', () => { "{\\"foo\\":\\"***REDACTED***\\"}", "substring: ***REDACTED***", "{\\"input_1\\":\\"test\\",\\"secret_input_2\\":{\\"foo\\":\\"***REDACTED***\\"},\\"secret_input_3\\":\\"***REDACTED***\\"}", - "Function completed. Processing time 0ms", + "Function completed in 0ms. Sync: 0ms. Mem: 129 bytes. Ops: 28.", ] `) }) @@ -136,24 +137,34 @@ describe('Hog Executor', () => { .findMatchingFunctions(createHogExecutionGlobals()) .matchingFunctions.map((x) => executor.executeFunction(globals, x) as HogFunctionInvocationResult) expect(results[0]).toMatchObject({ - id: results[0].id, - globals: { - project: { id: 1, name: 'test', url: 'http://localhost:8000/projects/1' }, - event: { - uuid: 'uuid', - name: 'test', - distinct_id: 'distinct_id', - url: 'http://localhost:8000/events/1', - properties: { $lib_version: '1.2.3' }, - timestamp: '2024-06-07T12:00:00.000Z', - }, - source: { - name: 'Test hog function', - url: `http://localhost:8000/projects/1/pipeline/destinations/hog-${hogFunction.id}/configuration/`, + invocation: { + id: results[0].invocation.id, + teamId: 1, + hogFunctionId: hogFunction.id, + vmState: expect.any(Object), + globals: { + project: { id: 1, name: 'test', url: 'http://localhost:8000/projects/1' }, + event: { + uuid: 'uuid', + name: 'test', + distinct_id: 'distinct_id', + url: 'http://localhost:8000/events/1', + properties: { $lib_version: '1.2.3' }, + timestamp: '2024-06-07T12:00:00.000Z', + }, + source: { + name: 'Test hog function', + url: `http://localhost:8000/projects/1/pipeline/destinations/hog-${hogFunction.id}/configuration/`, + }, }, + timings: [ + { + kind: 'hog', + duration_ms: 0, + }, + ], }, - teamId: 1, - hogFunctionId: hogFunction.id, + asyncFunctionRequest: { name: 'fetch', args: [ @@ -177,14 +188,7 @@ describe('Hog Executor', () => { method: 'POST', }, ], - vmState: expect.any(Object), }, - timings: [ - { - kind: 'hog', - duration_ms: 0, - }, - ], }) }) @@ -197,17 +201,17 @@ describe('Hog Executor', () => { const splicedLogs = results[0].logs.splice(0, 100) logs.push(...splicedLogs) - const asyncExecResult = executor.executeAsyncResponse(simulateMockFetchAsyncResponse(results[0])) + const asyncExecResult = executor.executeAsyncResponse(results[0].invocation, createAsyncFunctionResponse()) logs.push(...asyncExecResult.logs) expect(asyncExecResult.error).toBeUndefined() expect(asyncExecResult.finished).toBe(true) expect(logs.map((log) => log.message)).toEqual([ 'Executing function', - "Suspending function due to async function call 'fetch'", + "Suspending function due to async function call 'fetch'. Payload: 1299 bytes", 'Resuming function', 'Fetch response:, {"status":200,"body":"success"}', - 'Function completed. Processing time 100ms', + 'Function completed in 100ms. Sync: 0ms. Mem: 589 bytes. Ops: 22.', ]) }) }) @@ -259,13 +263,13 @@ describe('Hog Executor', () => { expect(results).toHaveLength(1) // Run the result one time simulating a successful fetch - const asyncResult1 = executor.executeAsyncResponse(simulateMockFetchAsyncResponse(results[0])) + const asyncResult1 = executor.executeAsyncResponse(results[0].invocation, createAsyncFunctionResponse()) expect(asyncResult1.finished).toBe(false) expect(asyncResult1.error).toBe(undefined) expect(asyncResult1.asyncFunctionRequest).toBeDefined() // Run the result one more time simulating a second successful fetch - const asyncResult2 = executor.executeAsyncResponse(simulateMockFetchAsyncResponse(asyncResult1)) + const asyncResult2 = executor.executeAsyncResponse(asyncResult1.invocation, createAsyncFunctionResponse()) // This time we should see an error for hitting the loop limit expect(asyncResult2.finished).toBe(false) expect(asyncResult2.error).toEqual('Exceeded maximum number of async steps: 2') diff --git a/plugin-server/tests/cdp/hog-watcher/hog-watcher.test.ts b/plugin-server/tests/cdp/hog-watcher/hog-watcher.test.ts index 52577df97bede..a36d72794ce99 100644 --- a/plugin-server/tests/cdp/hog-watcher/hog-watcher.test.ts +++ b/plugin-server/tests/cdp/hog-watcher/hog-watcher.test.ts @@ -17,17 +17,29 @@ const mockNow: jest.Mock = require('../../../src/utils/now').now as any const createResult = (id: string, finished = true, error?: string): HogFunctionInvocationResult => { return { - hogFunctionId: id, + invocation: { + id: 'invocation-id', + teamId: 2, + hogFunctionId: id, + globals: {} as any, + timings: [], + }, finished, error, - } as HogFunctionInvocationResult + logs: [], + } } const createAsyncResponse = (id: string, success = true): HogFunctionInvocationAsyncResponse => { return { + state: '', + teamId: 2, hogFunctionId: id, - error: success ? null : 'error', - } as HogFunctionInvocationAsyncResponse + asyncFunctionResponse: { + error: !success ? 'error' : null, + response: {}, + }, + } } const config = defaultConfig @@ -104,7 +116,6 @@ describe('HogWatcher', () => { const advanceTime = (ms: number) => { now += ms - console.log(`[TEST] Advancing time by ${ms}ms to ${now}`) mockNow.mockReturnValue(now) } diff --git a/plugin-server/tests/cdp/utils.test.ts b/plugin-server/tests/cdp/utils.test.ts new file mode 100644 index 0000000000000..a33cc79cf52d5 --- /dev/null +++ b/plugin-server/tests/cdp/utils.test.ts @@ -0,0 +1,14 @@ +import { gzipObject, unGzipObject } from '../../src/cdp/utils' +import { insertHogFunction as _insertHogFunction } from './fixtures' + +describe('Utils', () => { + describe('gzip compressions', () => { + it("should compress and decompress a string using gzip's sync functions", async () => { + const input = { foo: 'bar', foo2: 'bar' } + const compressed = await gzipObject(input) + expect(compressed).toHaveLength(52) + const decompressed = await unGzipObject(compressed) + expect(decompressed).toEqual(input) + }) + }) +}) diff --git a/posthog/api/action.py b/posthog/api/action.py index 816c34d2f4247..c43bf893ca7a4 100644 --- a/posthog/api/action.py +++ b/posthog/api/action.py @@ -3,13 +3,10 @@ from rest_framework import serializers, viewsets from django.db.models import Count from rest_framework import request -from rest_framework.decorators import action -from rest_framework.request import Request from rest_framework.response import Response from rest_framework.settings import api_settings from rest_framework_csv import renderers as csvrenderers -from posthog.api.plugin import PluginConfigSerializer from posthog.api.routing import TeamAndOrgViewSetMixin from posthog.api.shared import UserBasicSerializer from posthog.auth import ( @@ -19,7 +16,6 @@ from posthog.event_usage import report_user_action from posthog.models import Action from posthog.models.action.action import ACTION_STEP_MATCHING_OPTIONS -from posthog.models.plugin import PluginConfig from .forbid_destroy_model import ForbidDestroyModel from .tagged_item import TaggedItemSerializerMixin, TaggedItemViewSetMixin @@ -149,15 +145,3 @@ def list(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: actions, many=True, context={"request": request} ).data # type: ignore return Response({"results": actions_list}) - - @action(methods=["GET"], detail=True) - def plugin_configs(self, request: Request, *args: Any, **kwargs: Any) -> Response: - queryset = ( - PluginConfig.objects.all() - .filter(team=self.team_id, enabled=True) - .filter(filters__contains={"actions": [{"id": str(self.get_object().id)}]}) - ) - - page = self.paginate_queryset(queryset) - serializer = PluginConfigSerializer(page, many=True, context=self.get_serializer_context()) - return self.get_paginated_response(serializer.data) diff --git a/posthog/api/decide.py b/posthog/api/decide.py index 7a3d45480b1bf..747ba4d463f4e 100644 --- a/posthog/api/decide.py +++ b/posthog/api/decide.py @@ -318,8 +318,8 @@ def _session_recording_config_response(request: HttpRequest, team: Team) -> bool { "recordCanvas": record_canvas, # hard coded during beta while we decide on sensible values - "canvasFps": 4 if record_canvas else None, - "canvasQuality": "0.6" if record_canvas else None, + "canvasFps": 3 if record_canvas else None, + "canvasQuality": "0.4" if record_canvas else None, } ) except Exception as e: diff --git a/posthog/api/hog_function.py b/posthog/api/hog_function.py index 972178a875401..a9eddc7b1fae0 100644 --- a/posthog/api/hog_function.py +++ b/posthog/api/hog_function.py @@ -1,9 +1,10 @@ +import json from typing import Optional, cast import structlog from django_filters.rest_framework import DjangoFilterBackend from django.db.models import QuerySet -from rest_framework import serializers, viewsets +from rest_framework import serializers, viewsets, exceptions from rest_framework.serializers import BaseSerializer from rest_framework.decorators import action from rest_framework.request import Request @@ -50,6 +51,7 @@ class Meta: "hog", "filters", "icon_url", + "template", ] read_only_fields = fields @@ -100,9 +102,10 @@ def validate(self, attrs): attrs["team"] = team has_addon = team.organization.is_feature_available(AvailableFeature.DATA_PIPELINES) + instance = cast(Optional[HogFunction], self.context.get("instance", self.instance)) if not has_addon: - template_id = attrs.get("template_id") + template_id = attrs.get("template_id", instance.template_id if instance else None) template = HOG_FUNCTION_TEMPLATES_BY_ID.get(template_id, None) # In this case they are only allowed to create or update the function with free templates @@ -130,8 +133,6 @@ def validate(self, attrs): attrs["inputs_schema"] = template.inputs_schema attrs["hog"] = template.hog - instance = cast(Optional[HogFunction], self.context.get("instance", self.instance)) - if "inputs_schema" in attrs: attrs["inputs_schema"] = validate_inputs_schema(attrs["inputs_schema"]) @@ -213,6 +214,13 @@ def safely_get_queryset(self, queryset: QuerySet) -> QuerySet: if self.action == "list": queryset = queryset.filter(deleted=False) + if self.request.GET.get("filters"): + try: + filters = json.loads(self.request.GET["filters"]) + queryset = queryset.filter(filters__contains=filters) + except Exception: + raise exceptions.ValidationError({"filter": f"Invalid filter"}) + return queryset @action(detail=False, methods=["GET"]) diff --git a/posthog/api/test/test_action.py b/posthog/api/test/test_action.py index 3e4a0c4f56d87..2d162ff872ae1 100644 --- a/posthog/api/test/test_action.py +++ b/posthog/api/test/test_action.py @@ -136,7 +136,9 @@ def test_update_action(self, patch_capture, *args): action = Action.objects.create( name="user signed up", team=self.team, steps_json=[{"event": "$autocapture", "text": "sign me up!"}] ) + action.refresh_bytecode() action.save() + previous_bytecode = action.bytecode response = self.client.patch( f"/api/projects/{self.team.id}/actions/{action.pk}/", @@ -196,6 +198,8 @@ def test_update_action(self, patch_capture, *args): action.refresh_from_db() assert action.name == "user signed up 2" + assert previous_bytecode != action.bytecode + # Assert analytics are sent patch_capture.assert_called_with( user, diff --git a/posthog/api/test/test_decide.py b/posthog/api/test/test_decide.py index 352ab961c1297..bf781da00e635 100644 --- a/posthog/api/test/test_decide.py +++ b/posthog/api/test/test_decide.py @@ -356,8 +356,8 @@ def test_session_replay_config(self, *args): response = self._post_decide().json() self.assertEqual(response["sessionRecording"]["recordCanvas"], True) - self.assertEqual(response["sessionRecording"]["canvasFps"], 4) - self.assertEqual(response["sessionRecording"]["canvasQuality"], "0.6") + self.assertEqual(response["sessionRecording"]["canvasFps"], 3) + self.assertEqual(response["sessionRecording"]["canvasQuality"], "0.4") def test_exception_autocapture_opt_in(self, *args): # :TRICKY: Test for regression around caching diff --git a/posthog/api/test/test_hog_function.py b/posthog/api/test/test_hog_function.py index 23b33ff5f91a4..57f7290cd5fc5 100644 --- a/posthog/api/test/test_hog_function.py +++ b/posthog/api/test/test_hog_function.py @@ -1,5 +1,5 @@ import json -from typing import Optional +from typing import Any, Optional from unittest.mock import ANY, patch from rest_framework import status @@ -552,3 +552,62 @@ def test_patches_status_on_enabled_update(self, *args): f"http://localhost:6738/api/projects/{self.team.id}/hog_functions/{response.json()['id']}/status", json={"state": 2}, ) + + @patch("posthog.permissions.posthoganalytics.feature_enabled", return_value=True) + def test_list_with_filters_filter(self, *args): + action1 = Action.objects.create( + team=self.team, + name="test action", + steps_json=[{"event": "$pageview", "url": "docs", "url_matching": "contains"}], + ) + + action2 = Action.objects.create( + team=self.team, + name="test action", + steps_json=[{"event": "$pageview", "url": "docs", "url_matching": "contains"}], + ) + + self.team.test_account_filters = [ + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } + ] + self.team.save() + response = self.client.post( + f"/api/projects/{self.team.id}/hog_functions/", + data={ + **EXAMPLE_FULL, + "filters": { + "events": [{"id": "$pageview", "name": "$pageview", "type": "events", "order": 0}], + "actions": [ + {"id": f"{action1.id}", "name": "Test Action", "type": "actions", "order": 1}, + {"id": f"{action2.id}", "name": "Test Action 2", "type": "actions", "order": 1}, + ], + "filter_test_accounts": True, + }, + }, + ) + assert response.status_code == status.HTTP_201_CREATED, response.json() + + filters: Any = {"filter_test_accounts": True} + response = self.client.get(f"/api/projects/{self.team.id}/hog_functions/?filters={json.dumps(filters)}") + assert len(response.json()["results"]) == 1 + + filters = {"filter_test_accounts": False} + response = self.client.get(f"/api/projects/{self.team.id}/hog_functions/?filters={json.dumps(filters)}") + assert len(response.json()["results"]) == 0 + + filters = {"actions": [{"id": f"other"}]} + response = self.client.get(f"/api/projects/{self.team.id}/hog_functions/?filters={json.dumps(filters)}") + assert len(response.json()["results"]) == 0 + + filters = {"actions": [{"id": f"{action1.id}"}]} + response = self.client.get(f"/api/projects/{self.team.id}/hog_functions/?filters={json.dumps(filters)}") + assert len(response.json()["results"]) == 1 + + filters = {"actions": [{"id": f"{action2.id}"}]} + response = self.client.get(f"/api/projects/{self.team.id}/hog_functions/?filters={json.dumps(filters)}") + assert len(response.json()["results"]) == 1 diff --git a/posthog/api/test/test_query.py b/posthog/api/test/test_query.py index 5ef38ac548c2d..78339bd3f30c2 100644 --- a/posthog/api/test/test_query.py +++ b/posthog/api/test/test_query.py @@ -840,6 +840,7 @@ def test_full_hogql_query_async(self): { "query_status": { "complete": False, + "pickup_time": None, "end_time": None, "error": False, "error_message": None, diff --git a/posthog/batch_exports/models.py b/posthog/batch_exports/models.py index 2315575cf4ae1..e27e34ecd3ab7 100644 --- a/posthog/batch_exports/models.py +++ b/posthog/batch_exports/models.py @@ -31,9 +31,9 @@ class Destination(models.TextChoices): secret_fields = { "S3": {"aws_access_key_id", "aws_secret_access_key"}, - "Snowflake": set("password"), - "Postgres": set("password"), - "Redshift": set("password"), + "Snowflake": {"user", "password"}, + "Postgres": {"user", "password"}, + "Redshift": {"user", "password"}, "BigQuery": {"private_key", "private_key_id", "client_email", "token_uri"}, "HTTP": set("token"), "NoOp": set(), diff --git a/posthog/cdp/services/icons.py b/posthog/cdp/services/icons.py index f4cd744d5acb9..462783a7ba594 100644 --- a/posthog/cdp/services/icons.py +++ b/posthog/cdp/services/icons.py @@ -1,4 +1,6 @@ +from base64 import b64encode from django.conf import settings +from django.core.cache import cache from django.http import HttpResponse import requests @@ -14,25 +16,31 @@ def list_icons(self, query: str, icon_url_base: str): if not self.supported: return [] - res = requests.get( - f"https://search.logo.dev/api/icons", - params={ - "token": settings.LOGO_DEV_TOKEN, - "query": query, - }, - ) - data = res.json() - - parsed = [ - { - "id": item["domain"], - "name": item["name"], - "url": f"{icon_url_base}{item['domain']}", - } - for item in data - ] - - return parsed + cache_key = f"@cdp/list_icons/{b64encode(query.encode()).decode()}" + data = cache.get(cache_key) + + if data is None: + res = requests.get( + f"https://search.logo.dev/api/icons", + params={ + "token": settings.LOGO_DEV_TOKEN, + "query": query, + }, + ) + data = res.json() or [] + + data = [ + { + "id": item["domain"], + "name": item["name"], + "url": f"{icon_url_base}{item['domain']}", + } + for item in res.json() or [] + ] + + cache.set(cache_key, data, 60 * 60 * 24) + + return data def get_icon_http_response(self, id: str): if not self.supported: diff --git a/posthog/cdp/templates/aws_kinesis/template_aws_kinesis.py b/posthog/cdp/templates/aws_kinesis/template_aws_kinesis.py index 4e0ef38d793b1..df41fa266ecec 100644 --- a/posthog/cdp/templates/aws_kinesis/template_aws_kinesis.py +++ b/posthog/cdp/templates/aws_kinesis/template_aws_kinesis.py @@ -8,9 +8,8 @@ description="Put data to an AWS Kinesis stream", icon_url="/static/services/aws-kinesis.png", hog=""" -fn uploadToKinesis(data) { +fn getPayload() { let region := inputs.aws_region - let endpoint := f'https://kinesis.{region}.amazonaws.com' let service := 'kinesis' let amzDate := formatDateTime(now(), '%Y%m%dT%H%i%sZ') let date := formatDateTime(now(), '%Y%m%d') @@ -18,7 +17,7 @@ let payload := jsonStringify({ 'StreamName': inputs.aws_kinesis_stream_arn, 'PartitionKey': inputs.aws_kinesis_partition_key, - 'Data': base64Encode(data), + 'Data': base64Encode(jsonStringify(inputs.payload)), }) let requestHeaders := { @@ -69,21 +68,20 @@ requestHeaders['Authorization'] := authorizationHeader - let res := fetch(endpoint, { + return { 'headers': requestHeaders, 'body': payload, 'method': 'POST' - }) - - if (res.status >= 200 and res.status < 300) { - print('Event sent successfully!') - return } +} +let res := fetch(f'https://kinesis.{inputs.aws_region}.amazonaws.com', getPayload()) + +if (res.status >= 200 and res.status < 300) { + print('Event sent successfully!') +} else { print('Error sending event:', res.status, res.body) } - -uploadToKinesis(jsonStringify(inputs.payload)) """.strip(), inputs_schema=[ { diff --git a/posthog/cdp/templates/webhook/template_webhook.py b/posthog/cdp/templates/webhook/template_webhook.py index fb7ed6e63650c..b99e7f9f31f79 100644 --- a/posthog/cdp/templates/webhook/template_webhook.py +++ b/posthog/cdp/templates/webhook/template_webhook.py @@ -6,7 +6,7 @@ id="template-webhook", name="HTTP Webhook", description="Sends a webhook templated by the incoming event data", - icon_url="/static/posthog-icon.svg?temp=true", + icon_url="/static/posthog-icon.svg", hog=""" let res := fetch(inputs.url, { 'headers': inputs.headers, diff --git a/posthog/clickhouse/client/execute_async.py b/posthog/clickhouse/client/execute_async.py index e3e30d52884de..14e8cb4fae06d 100644 --- a/posthog/clickhouse/client/execute_async.py +++ b/posthog/clickhouse/client/execute_async.py @@ -150,8 +150,10 @@ def execute_process_query( team = Team.objects.get(pk=team_id) sentry_sdk.set_tag("team_id", team_id) + is_staff_user = False if user_id: - user = User.objects.get(pk=user_id) + user = User.objects.only("email", "is_staff").get(pk=user_id) + is_staff_user = user.is_staff sentry_sdk.set_user({"email": user.email, "id": user_id, "username": user.email}) query_status = manager.get_query_status() @@ -159,6 +161,9 @@ def execute_process_query( if query_status.complete: return + query_status.pickup_time = datetime.datetime.now(datetime.UTC) + manager.store_query_status(query_status) + query_status.error = True # Assume error in case nothing below ends up working query_status.complete = True @@ -166,9 +171,8 @@ def execute_process_query( if trigger == "chained": tag_queries(trigger="chaining") - pickup_time = datetime.datetime.now(datetime.UTC) if query_status.start_time: - wait_duration = (pickup_time - query_status.start_time) / datetime.timedelta(seconds=1) + wait_duration = (query_status.pickup_time - query_status.start_time) / datetime.timedelta(seconds=1) QUERY_WAIT_TIME.labels(team=team_id, mode=trigger).observe(wait_duration) try: @@ -186,23 +190,22 @@ def execute_process_query( logger.info("Got results for team %s query %s", team_id, query_id) query_status.error = False query_status.results = results - query_status.end_time = datetime.datetime.now(datetime.UTC) - process_duration = (query_status.end_time - pickup_time) / datetime.timedelta(seconds=1) + process_duration = (datetime.datetime.now(datetime.UTC) - query_status.pickup_time) / datetime.timedelta( + seconds=1 + ) QUERY_PROCESS_TIME.labels(team=team_id).observe(process_duration) except CHQueryErrorTooManySimultaneousQueries: raise - except (ExposedHogQLError, ExposedCHQueryError) as err: # We can expose the error to the user + except Exception as err: query_status.results = None # Clear results in case they are faulty - query_status.error_message = str(err) - logger.exception("Error processing query for team %s query %s", team_id, query_id) - sentry_sdk.capture_exception(err) - # Do not raise here, the task itself did its job and we cannot recover - except Exception as err: # We cannot reveal anything about the error - query_status.results = None # Clear results in case they are faulty - logger.exception("Error processing query for team %s query %s", team_id, query_id) + if isinstance(err, ExposedHogQLError | ExposedCHQueryError) or is_staff_user: + # We can only expose the error message if it's a known safe error OR if the user is PostHog staff + query_status.error_message = str(err) + logger.exception("Error processing query async", team_id=team_id, query_id=query_id, exc_info=True) sentry_sdk.capture_exception(err) # Do not raise here, the task itself did its job and we cannot recover finally: + query_status.end_time = datetime.datetime.now(datetime.UTC) manager.store_query_status(query_status) diff --git a/posthog/clickhouse/client/test/test_execute_async.py b/posthog/clickhouse/client/test/test_execute_async.py index 13ebfe90964b1..14199a488f712 100644 --- a/posthog/clickhouse/client/test/test_execute_async.py +++ b/posthog/clickhouse/client/test/test_execute_async.py @@ -128,7 +128,7 @@ def test_execute_process_query(self, mock_process_query_dict, mock_redis_client) mock_process_query_dict.assert_called_once() # Assert that Redis set method was called with the correct arguments - mock_redis.set.assert_called_once() + self.assertEqual(mock_redis.set.call_count, 2) # Once on pickup, once on completion args, kwargs = mock_redis.set.call_args args_loaded = json.loads(args[1]) self.assertEqual(args_loaded["results"], [None, None, None, 1.0, "👍"]) @@ -149,6 +149,9 @@ def test_async_query_client(self): result = client.get_query_status(self.team.id, query_id) self.assertFalse(result.error, result.error_message or "") self.assertTrue(result.complete) + self.assertIsNotNone(result.start_time) + self.assertIsNotNone(result.pickup_time) + self.assertIsNotNone(result.end_time) assert result.results is not None self.assertEqual(result.results["results"], [[2]]) @@ -165,6 +168,9 @@ def test_async_query_client_errors(self): result = client.get_query_status(self.team.id, query_id) self.assertTrue(result.error) self.assertTrue(result.complete) + self.assertIsNotNone(result.start_time) + self.assertIsNotNone(result.pickup_time) + self.assertIsNotNone(result.end_time) assert result.error_message self.assertRegex(result.error_message, "no viable alternative at input") @@ -191,6 +197,9 @@ def test_async_query_server_errors(self): result = client.get_query_status(self.team.id, query_id) self.assertTrue(result.error) assert result.error_message is None + self.assertIsNotNone(result.start_time) + self.assertIsNotNone(result.pickup_time) + self.assertIsNotNone(result.end_time) def test_async_query_client_uuid(self): query = build_query("SELECT toUUID('00000000-0000-0000-0000-000000000000')") diff --git a/posthog/clickhouse/test/__snapshots__/test_schema.ambr b/posthog/clickhouse/test/__snapshots__/test_schema.ambr index 69407e9000939..344ac139affa4 100644 --- a/posthog/clickhouse/test/__snapshots__/test_schema.ambr +++ b/posthog/clickhouse/test/__snapshots__/test_schema.ambr @@ -595,10 +595,6 @@ , $group_4 VARCHAR COMMENT 'column_materializer::$group_4' , $window_id VARCHAR COMMENT 'column_materializer::$window_id' , $session_id VARCHAR COMMENT 'column_materializer::$session_id' - , elements_chain_href String COMMENT 'column_materializer::elements_chain::href' - , elements_chain_texts Array(String) COMMENT 'column_materializer::elements_chain::texts' - , elements_chain_ids Array(String) COMMENT 'column_materializer::elements_chain::ids' - , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) COMMENT 'column_materializer::elements_chain::elements' , _timestamp DateTime @@ -2177,10 +2173,6 @@ , $group_4 VARCHAR MATERIALIZED replaceRegexpAll(JSONExtractRaw(properties, '$group_4'), '^"|"$', '') COMMENT 'column_materializer::$group_4' , $window_id VARCHAR MATERIALIZED replaceRegexpAll(JSONExtractRaw(properties, '$window_id'), '^"|"$', '') COMMENT 'column_materializer::$window_id' , $session_id VARCHAR MATERIALIZED replaceRegexpAll(JSONExtractRaw(properties, '$session_id'), '^"|"$', '') COMMENT 'column_materializer::$session_id' - , elements_chain_href String MATERIALIZED extract(elements_chain, '(?::|")href="(.*?)"') - , elements_chain_texts Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")text="(.*?)"')) - , elements_chain_ids Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")attr_id="(.*?)"')) - , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?:^|;)(a|button|form|input|select|textarea|label)(?:\.|$|:)')) , INDEX `minmax_$group_0` `$group_0` TYPE minmax GRANULARITY 1 , INDEX `minmax_$group_1` `$group_1` TYPE minmax GRANULARITY 1 , INDEX `minmax_$group_2` `$group_2` TYPE minmax GRANULARITY 1 @@ -2188,6 +2180,10 @@ , INDEX `minmax_$group_4` `$group_4` TYPE minmax GRANULARITY 1 , INDEX `minmax_$window_id` `$window_id` TYPE minmax GRANULARITY 1 , INDEX `minmax_$session_id` `$session_id` TYPE minmax GRANULARITY 1 + , elements_chain_href String MATERIALIZED extract(elements_chain, '(?::|")href="(.*?)"') + , elements_chain_texts Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")text="(.*?)"')) + , elements_chain_ids Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")attr_id="(.*?)"')) + , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?:^|;)(a|button|form|input|select|textarea|label)(?:\.|$|:)')) , _timestamp DateTime @@ -3271,10 +3267,6 @@ , $group_4 VARCHAR MATERIALIZED replaceRegexpAll(JSONExtractRaw(properties, '$group_4'), '^"|"$', '') COMMENT 'column_materializer::$group_4' , $window_id VARCHAR MATERIALIZED replaceRegexpAll(JSONExtractRaw(properties, '$window_id'), '^"|"$', '') COMMENT 'column_materializer::$window_id' , $session_id VARCHAR MATERIALIZED replaceRegexpAll(JSONExtractRaw(properties, '$session_id'), '^"|"$', '') COMMENT 'column_materializer::$session_id' - , elements_chain_href String MATERIALIZED extract(elements_chain, '(?::|")href="(.*?)"') - , elements_chain_texts Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")text="(.*?)"')) - , elements_chain_ids Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")attr_id="(.*?)"')) - , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?:^|;)(a|button|form|input|select|textarea|label)(?:\.|$|:)')) , INDEX `minmax_$group_0` `$group_0` TYPE minmax GRANULARITY 1 , INDEX `minmax_$group_1` `$group_1` TYPE minmax GRANULARITY 1 , INDEX `minmax_$group_2` `$group_2` TYPE minmax GRANULARITY 1 @@ -3282,6 +3274,10 @@ , INDEX `minmax_$group_4` `$group_4` TYPE minmax GRANULARITY 1 , INDEX `minmax_$window_id` `$window_id` TYPE minmax GRANULARITY 1 , INDEX `minmax_$session_id` `$session_id` TYPE minmax GRANULARITY 1 + , elements_chain_href String MATERIALIZED extract(elements_chain, '(?::|")href="(.*?)"') + , elements_chain_texts Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")text="(.*?)"')) + , elements_chain_ids Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|")attr_id="(.*?)"')) + , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?:^|;)(a|button|form|input|select|textarea|label)(?:\.|$|:)')) , _timestamp DateTime diff --git a/posthog/hogql/database/schema/events.py b/posthog/hogql/database/schema/events.py index a0225bd334b2d..1a489e5a9d90f 100644 --- a/posthog/hogql/database/schema/events.py +++ b/posthog/hogql/database/schema/events.py @@ -3,7 +3,6 @@ StringDatabaseField, DateTimeDatabaseField, StringJSONDatabaseField, - StringArrayDatabaseField, IntegerDatabaseField, Table, LazyJoin, @@ -115,10 +114,6 @@ class EventsTable(Table): join_table=SessionsTableV1(), join_function=join_events_table_to_sessions_table, ), - "elements_chain_href": StringDatabaseField(name="elements_chain_href"), - "elements_chain_texts": StringArrayDatabaseField(name="elements_chain_texts"), - "elements_chain_ids": StringArrayDatabaseField(name="elements_chain_ids"), - "elements_chain_elements": StringArrayDatabaseField(name="elements_chain_elements"), } def to_printed_clickhouse(self, context): diff --git a/posthog/hogql/database/test/__snapshots__/test_database.ambr b/posthog/hogql/database/test/__snapshots__/test_database.ambr index 77a2452922e7e..ce03813aa1004 100644 --- a/posthog/hogql/database/test/__snapshots__/test_database.ambr +++ b/posthog/hogql/database/test/__snapshots__/test_database.ambr @@ -377,42 +377,6 @@ "schema_valid": true, "table": "sessions", "type": "lazy_table" - }, - "elements_chain_href": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_href", - "name": "elements_chain_href", - "schema_valid": true, - "table": null, - "type": "string" - }, - "elements_chain_texts": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_texts", - "name": "elements_chain_texts", - "schema_valid": true, - "table": null, - "type": "array" - }, - "elements_chain_ids": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_ids", - "name": "elements_chain_ids", - "schema_valid": true, - "table": null, - "type": "array" - }, - "elements_chain_elements": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_elements", - "name": "elements_chain_elements", - "schema_valid": true, - "table": null, - "type": "array" } }, "id": "events", @@ -748,11 +712,7 @@ "group_3", "$group_4", "group_4", - "session", - "elements_chain_href", - "elements_chain_texts", - "elements_chain_ids", - "elements_chain_elements" + "session" ], "hogql_value": "events", "name": "events", @@ -1734,42 +1694,6 @@ "schema_valid": true, "table": "sessions", "type": "lazy_table" - }, - "elements_chain_href": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_href", - "name": "elements_chain_href", - "schema_valid": true, - "table": null, - "type": "string" - }, - "elements_chain_texts": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_texts", - "name": "elements_chain_texts", - "schema_valid": true, - "table": null, - "type": "array" - }, - "elements_chain_ids": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_ids", - "name": "elements_chain_ids", - "schema_valid": true, - "table": null, - "type": "array" - }, - "elements_chain_elements": { - "chain": null, - "fields": null, - "hogql_value": "elements_chain_elements", - "name": "elements_chain_elements", - "schema_valid": true, - "table": null, - "type": "array" } }, "id": "events", @@ -2105,11 +2029,7 @@ "group_3", "$group_4", "group_4", - "session", - "elements_chain_href", - "elements_chain_texts", - "elements_chain_ids", - "elements_chain_elements" + "session" ], "hogql_value": "events", "name": "events", diff --git a/posthog/hogql/grammar/HogQLParser.g4 b/posthog/hogql/grammar/HogQLParser.g4 index fa689fbacfd9b..871f549f41f02 100644 --- a/posthog/hogql/grammar/HogQLParser.g4 +++ b/posthog/hogql/grammar/HogQLParser.g4 @@ -221,7 +221,7 @@ columnLambdaExpr: hogqlxTagElement : LT identifier hogqlxTagAttribute* SLASH GT # HogqlxTagElementClosed - | LT identifier hogqlxTagAttribute* GT hogqlxTagElement? LT SLASH identifier GT # HogqlxTagElementNested + | LT identifier hogqlxTagAttribute* GT (hogqlxTagElement | (LBRACE columnExpr RBRACE))? LT SLASH identifier GT # HogqlxTagElementNested ; hogqlxTagAttribute : identifier '=' string diff --git a/posthog/hogql/grammar/HogQLParser.interp b/posthog/hogql/grammar/HogQLParser.interp index 20c37a5916320..e31bf92fee7e9 100644 --- a/posthog/hogql/grammar/HogQLParser.interp +++ b/posthog/hogql/grammar/HogQLParser.interp @@ -414,4 +414,4 @@ stringContentsFull atn: -[4, 1, 159, 1307, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 1, 0, 5, 0, 178, 8, 0, 10, 0, 12, 0, 181, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 187, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 196, 8, 3, 1, 4, 1, 4, 1, 4, 5, 4, 201, 8, 4, 10, 4, 12, 4, 204, 9, 4, 1, 4, 3, 4, 207, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 221, 8, 5, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 6, 3, 6, 228, 8, 6, 1, 7, 1, 7, 3, 7, 232, 8, 7, 1, 7, 3, 7, 235, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 242, 8, 8, 1, 8, 1, 8, 3, 8, 246, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 5, 9, 253, 8, 9, 10, 9, 12, 9, 256, 9, 9, 1, 9, 1, 9, 3, 9, 260, 8, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 269, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 277, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 284, 8, 12, 1, 12, 1, 12, 3, 12, 288, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 294, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 299, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 307, 8, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 314, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 320, 8, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 3, 16, 332, 8, 16, 1, 17, 1, 17, 1, 18, 1, 18, 5, 18, 338, 8, 18, 10, 18, 12, 18, 341, 9, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 352, 8, 20, 10, 20, 12, 20, 355, 9, 20, 1, 20, 3, 20, 358, 8, 20, 1, 21, 1, 21, 1, 21, 3, 21, 363, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 371, 8, 22, 10, 22, 12, 22, 374, 9, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 382, 8, 23, 1, 24, 3, 24, 385, 8, 24, 1, 24, 1, 24, 3, 24, 389, 8, 24, 1, 24, 3, 24, 392, 8, 24, 1, 24, 1, 24, 3, 24, 396, 8, 24, 1, 24, 3, 24, 399, 8, 24, 1, 24, 3, 24, 402, 8, 24, 1, 24, 3, 24, 405, 8, 24, 1, 24, 3, 24, 408, 8, 24, 1, 24, 1, 24, 3, 24, 412, 8, 24, 1, 24, 1, 24, 3, 24, 416, 8, 24, 1, 24, 3, 24, 419, 8, 24, 1, 24, 3, 24, 422, 8, 24, 1, 24, 3, 24, 425, 8, 24, 1, 24, 1, 24, 3, 24, 429, 8, 24, 1, 24, 3, 24, 432, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 441, 8, 26, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 447, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 466, 8, 29, 10, 29, 12, 29, 469, 9, 29, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 485, 8, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 502, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 508, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 514, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 525, 8, 36, 3, 36, 527, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 3, 39, 538, 8, 39, 1, 39, 3, 39, 541, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 547, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 555, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 561, 8, 39, 10, 39, 12, 39, 564, 9, 39, 1, 40, 3, 40, 567, 8, 40, 1, 40, 1, 40, 1, 40, 3, 40, 572, 8, 40, 1, 40, 3, 40, 575, 8, 40, 1, 40, 3, 40, 578, 8, 40, 1, 40, 1, 40, 3, 40, 582, 8, 40, 1, 40, 1, 40, 3, 40, 586, 8, 40, 1, 40, 3, 40, 589, 8, 40, 3, 40, 591, 8, 40, 1, 40, 3, 40, 594, 8, 40, 1, 40, 1, 40, 3, 40, 598, 8, 40, 1, 40, 1, 40, 3, 40, 602, 8, 40, 1, 40, 3, 40, 605, 8, 40, 3, 40, 607, 8, 40, 3, 40, 609, 8, 40, 1, 41, 1, 41, 1, 41, 3, 41, 614, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 625, 8, 42, 1, 43, 1, 43, 1, 43, 1, 43, 3, 43, 631, 8, 43, 1, 44, 1, 44, 1, 44, 5, 44, 636, 8, 44, 10, 44, 12, 44, 639, 9, 44, 1, 45, 1, 45, 3, 45, 643, 8, 45, 1, 45, 1, 45, 3, 45, 647, 8, 45, 1, 45, 1, 45, 3, 45, 651, 8, 45, 1, 46, 1, 46, 1, 46, 1, 46, 3, 46, 657, 8, 46, 3, 46, 659, 8, 46, 1, 47, 1, 47, 1, 47, 5, 47, 664, 8, 47, 10, 47, 12, 47, 667, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 3, 49, 674, 8, 49, 1, 49, 3, 49, 677, 8, 49, 1, 49, 3, 49, 680, 8, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 699, 8, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 3, 54, 713, 8, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 727, 8, 56, 10, 56, 12, 56, 730, 9, 56, 1, 56, 3, 56, 733, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 742, 8, 56, 10, 56, 12, 56, 745, 9, 56, 1, 56, 3, 56, 748, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 757, 8, 56, 10, 56, 12, 56, 760, 9, 56, 1, 56, 3, 56, 763, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 770, 8, 56, 1, 56, 1, 56, 3, 56, 774, 8, 56, 1, 57, 1, 57, 1, 57, 5, 57, 779, 8, 57, 10, 57, 12, 57, 782, 9, 57, 1, 57, 3, 57, 785, 8, 57, 1, 58, 1, 58, 1, 58, 3, 58, 790, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 4, 58, 797, 8, 58, 11, 58, 12, 58, 798, 1, 58, 1, 58, 3, 58, 803, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 827, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 844, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 850, 8, 58, 1, 58, 3, 58, 853, 8, 58, 1, 58, 3, 58, 856, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 866, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 872, 8, 58, 1, 58, 3, 58, 875, 8, 58, 1, 58, 3, 58, 878, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 886, 8, 58, 1, 58, 3, 58, 889, 8, 58, 1, 58, 1, 58, 3, 58, 893, 8, 58, 1, 58, 3, 58, 896, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 910, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 927, 8, 58, 1, 58, 1, 58, 1, 58, 3, 58, 932, 8, 58, 1, 58, 1, 58, 3, 58, 936, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 942, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 949, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 961, 8, 58, 1, 58, 1, 58, 3, 58, 965, 8, 58, 1, 58, 3, 58, 968, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 977, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 991, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1030, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1038, 8, 58, 5, 58, 1040, 8, 58, 10, 58, 12, 58, 1043, 9, 58, 1, 59, 1, 59, 1, 59, 5, 59, 1048, 8, 59, 10, 59, 12, 59, 1051, 9, 59, 1, 59, 3, 59, 1054, 8, 59, 1, 60, 1, 60, 3, 60, 1058, 8, 60, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1064, 8, 61, 10, 61, 12, 61, 1067, 9, 61, 1, 61, 3, 61, 1070, 8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1077, 8, 61, 10, 61, 12, 61, 1080, 9, 61, 1, 61, 3, 61, 1083, 8, 61, 3, 61, 1085, 8, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 5, 62, 1093, 8, 62, 10, 62, 12, 62, 1096, 9, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 5, 62, 1104, 8, 62, 10, 62, 12, 62, 1107, 9, 62, 1, 62, 1, 62, 3, 62, 1111, 8, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1118, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 1131, 8, 63, 1, 64, 1, 64, 1, 64, 5, 64, 1136, 8, 64, 10, 64, 12, 64, 1139, 9, 64, 1, 64, 3, 64, 1142, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1154, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 1160, 8, 66, 1, 66, 3, 66, 1163, 8, 66, 1, 67, 1, 67, 1, 67, 5, 67, 1168, 8, 67, 10, 67, 12, 67, 1171, 9, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1182, 8, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1188, 8, 68, 5, 68, 1190, 8, 68, 10, 68, 12, 68, 1193, 9, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1198, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, 1205, 8, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 5, 71, 1212, 8, 71, 10, 71, 12, 71, 1215, 9, 71, 1, 71, 3, 71, 1218, 8, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 1228, 8, 73, 3, 73, 1230, 8, 73, 1, 74, 3, 74, 1233, 8, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 3, 74, 1241, 8, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1246, 8, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 3, 79, 1256, 8, 79, 1, 80, 1, 80, 1, 80, 3, 80, 1261, 8, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 3, 83, 1273, 8, 83, 1, 84, 1, 84, 5, 84, 1277, 8, 84, 10, 84, 12, 84, 1280, 9, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 1289, 8, 85, 1, 86, 1, 86, 5, 86, 1293, 8, 86, 10, 86, 12, 86, 1296, 9, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 3, 87, 1305, 8, 87, 1, 87, 0, 3, 78, 116, 136, 88, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 0, 16, 2, 0, 18, 18, 74, 74, 2, 0, 44, 44, 51, 51, 3, 0, 1, 1, 4, 4, 8, 8, 4, 0, 1, 1, 3, 4, 8, 8, 80, 80, 2, 0, 51, 51, 73, 73, 2, 0, 1, 1, 4, 4, 2, 0, 7, 7, 22, 23, 2, 0, 30, 30, 49, 49, 2, 0, 71, 71, 76, 76, 3, 0, 10, 10, 50, 50, 90, 90, 2, 0, 41, 41, 53, 53, 1, 0, 107, 108, 2, 0, 118, 118, 139, 139, 7, 0, 21, 21, 38, 38, 55, 56, 70, 70, 78, 78, 97, 97, 103, 103, 16, 0, 1, 13, 15, 20, 22, 28, 30, 30, 32, 37, 39, 42, 44, 51, 53, 54, 58, 58, 60, 69, 71, 77, 79, 83, 85, 92, 94, 96, 98, 99, 101, 102, 4, 0, 20, 20, 30, 30, 39, 39, 48, 48, 1474, 0, 179, 1, 0, 0, 0, 2, 186, 1, 0, 0, 0, 4, 188, 1, 0, 0, 0, 6, 190, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 220, 1, 0, 0, 0, 12, 222, 1, 0, 0, 0, 14, 229, 1, 0, 0, 0, 16, 236, 1, 0, 0, 0, 18, 249, 1, 0, 0, 0, 20, 261, 1, 0, 0, 0, 22, 270, 1, 0, 0, 0, 24, 278, 1, 0, 0, 0, 26, 300, 1, 0, 0, 0, 28, 315, 1, 0, 0, 0, 30, 324, 1, 0, 0, 0, 32, 329, 1, 0, 0, 0, 34, 333, 1, 0, 0, 0, 36, 335, 1, 0, 0, 0, 38, 344, 1, 0, 0, 0, 40, 348, 1, 0, 0, 0, 42, 362, 1, 0, 0, 0, 44, 366, 1, 0, 0, 0, 46, 381, 1, 0, 0, 0, 48, 384, 1, 0, 0, 0, 50, 433, 1, 0, 0, 0, 52, 436, 1, 0, 0, 0, 54, 442, 1, 0, 0, 0, 56, 446, 1, 0, 0, 0, 58, 452, 1, 0, 0, 0, 60, 470, 1, 0, 0, 0, 62, 473, 1, 0, 0, 0, 64, 476, 1, 0, 0, 0, 66, 486, 1, 0, 0, 0, 68, 489, 1, 0, 0, 0, 70, 493, 1, 0, 0, 0, 72, 526, 1, 0, 0, 0, 74, 528, 1, 0, 0, 0, 76, 531, 1, 0, 0, 0, 78, 546, 1, 0, 0, 0, 80, 608, 1, 0, 0, 0, 82, 613, 1, 0, 0, 0, 84, 624, 1, 0, 0, 0, 86, 626, 1, 0, 0, 0, 88, 632, 1, 0, 0, 0, 90, 640, 1, 0, 0, 0, 92, 658, 1, 0, 0, 0, 94, 660, 1, 0, 0, 0, 96, 668, 1, 0, 0, 0, 98, 673, 1, 0, 0, 0, 100, 681, 1, 0, 0, 0, 102, 685, 1, 0, 0, 0, 104, 689, 1, 0, 0, 0, 106, 698, 1, 0, 0, 0, 108, 712, 1, 0, 0, 0, 110, 714, 1, 0, 0, 0, 112, 773, 1, 0, 0, 0, 114, 775, 1, 0, 0, 0, 116, 935, 1, 0, 0, 0, 118, 1044, 1, 0, 0, 0, 120, 1057, 1, 0, 0, 0, 122, 1084, 1, 0, 0, 0, 124, 1117, 1, 0, 0, 0, 126, 1130, 1, 0, 0, 0, 128, 1132, 1, 0, 0, 0, 130, 1153, 1, 0, 0, 0, 132, 1162, 1, 0, 0, 0, 134, 1164, 1, 0, 0, 0, 136, 1181, 1, 0, 0, 0, 138, 1194, 1, 0, 0, 0, 140, 1204, 1, 0, 0, 0, 142, 1208, 1, 0, 0, 0, 144, 1219, 1, 0, 0, 0, 146, 1229, 1, 0, 0, 0, 148, 1232, 1, 0, 0, 0, 150, 1245, 1, 0, 0, 0, 152, 1247, 1, 0, 0, 0, 154, 1249, 1, 0, 0, 0, 156, 1251, 1, 0, 0, 0, 158, 1255, 1, 0, 0, 0, 160, 1260, 1, 0, 0, 0, 162, 1262, 1, 0, 0, 0, 164, 1266, 1, 0, 0, 0, 166, 1272, 1, 0, 0, 0, 168, 1274, 1, 0, 0, 0, 170, 1288, 1, 0, 0, 0, 172, 1290, 1, 0, 0, 0, 174, 1304, 1, 0, 0, 0, 176, 178, 3, 2, 1, 0, 177, 176, 1, 0, 0, 0, 178, 181, 1, 0, 0, 0, 179, 177, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 182, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 182, 183, 5, 0, 0, 1, 183, 1, 1, 0, 0, 0, 184, 187, 3, 6, 3, 0, 185, 187, 3, 10, 5, 0, 186, 184, 1, 0, 0, 0, 186, 185, 1, 0, 0, 0, 187, 3, 1, 0, 0, 0, 188, 189, 3, 116, 58, 0, 189, 5, 1, 0, 0, 0, 190, 191, 5, 52, 0, 0, 191, 195, 3, 160, 80, 0, 192, 193, 5, 115, 0, 0, 193, 194, 5, 122, 0, 0, 194, 196, 3, 4, 2, 0, 195, 192, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 202, 3, 160, 80, 0, 198, 199, 5, 116, 0, 0, 199, 201, 3, 160, 80, 0, 200, 198, 1, 0, 0, 0, 201, 204, 1, 0, 0, 0, 202, 200, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 206, 1, 0, 0, 0, 204, 202, 1, 0, 0, 0, 205, 207, 5, 116, 0, 0, 206, 205, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 9, 1, 0, 0, 0, 208, 221, 3, 12, 6, 0, 209, 221, 3, 14, 7, 0, 210, 221, 3, 18, 9, 0, 211, 221, 3, 20, 10, 0, 212, 221, 3, 22, 11, 0, 213, 221, 3, 26, 13, 0, 214, 221, 3, 24, 12, 0, 215, 221, 3, 28, 14, 0, 216, 221, 3, 30, 15, 0, 217, 221, 3, 36, 18, 0, 218, 221, 3, 32, 16, 0, 219, 221, 3, 34, 17, 0, 220, 208, 1, 0, 0, 0, 220, 209, 1, 0, 0, 0, 220, 210, 1, 0, 0, 0, 220, 211, 1, 0, 0, 0, 220, 212, 1, 0, 0, 0, 220, 213, 1, 0, 0, 0, 220, 214, 1, 0, 0, 0, 220, 215, 1, 0, 0, 0, 220, 216, 1, 0, 0, 0, 220, 217, 1, 0, 0, 0, 220, 218, 1, 0, 0, 0, 220, 219, 1, 0, 0, 0, 221, 11, 1, 0, 0, 0, 222, 224, 5, 72, 0, 0, 223, 225, 3, 4, 2, 0, 224, 223, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 227, 1, 0, 0, 0, 226, 228, 5, 150, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 13, 1, 0, 0, 0, 229, 231, 5, 84, 0, 0, 230, 232, 3, 4, 2, 0, 231, 230, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 234, 1, 0, 0, 0, 233, 235, 5, 150, 0, 0, 234, 233, 1, 0, 0, 0, 234, 235, 1, 0, 0, 0, 235, 15, 1, 0, 0, 0, 236, 245, 5, 14, 0, 0, 237, 238, 5, 130, 0, 0, 238, 241, 3, 160, 80, 0, 239, 240, 5, 115, 0, 0, 240, 242, 3, 160, 80, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 244, 5, 149, 0, 0, 244, 246, 1, 0, 0, 0, 245, 237, 1, 0, 0, 0, 245, 246, 1, 0, 0, 0, 246, 247, 1, 0, 0, 0, 247, 248, 3, 36, 18, 0, 248, 17, 1, 0, 0, 0, 249, 250, 5, 93, 0, 0, 250, 254, 3, 36, 18, 0, 251, 253, 3, 16, 8, 0, 252, 251, 1, 0, 0, 0, 253, 256, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 254, 255, 1, 0, 0, 0, 255, 259, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 257, 258, 5, 29, 0, 0, 258, 260, 3, 36, 18, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 19, 1, 0, 0, 0, 261, 262, 5, 40, 0, 0, 262, 263, 5, 130, 0, 0, 263, 264, 3, 4, 2, 0, 264, 265, 5, 149, 0, 0, 265, 268, 3, 10, 5, 0, 266, 267, 5, 25, 0, 0, 267, 269, 3, 10, 5, 0, 268, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 21, 1, 0, 0, 0, 270, 271, 5, 100, 0, 0, 271, 272, 5, 130, 0, 0, 272, 273, 3, 4, 2, 0, 273, 274, 5, 149, 0, 0, 274, 276, 3, 10, 5, 0, 275, 277, 5, 150, 0, 0, 276, 275, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 23, 1, 0, 0, 0, 278, 279, 5, 33, 0, 0, 279, 283, 5, 130, 0, 0, 280, 284, 3, 6, 3, 0, 281, 284, 3, 30, 15, 0, 282, 284, 3, 4, 2, 0, 283, 280, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 287, 5, 150, 0, 0, 286, 288, 3, 4, 2, 0, 287, 286, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 293, 5, 150, 0, 0, 290, 294, 3, 6, 3, 0, 291, 294, 3, 30, 15, 0, 292, 294, 3, 4, 2, 0, 293, 290, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 293, 292, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 295, 1, 0, 0, 0, 295, 296, 5, 149, 0, 0, 296, 298, 3, 10, 5, 0, 297, 299, 5, 150, 0, 0, 298, 297, 1, 0, 0, 0, 298, 299, 1, 0, 0, 0, 299, 25, 1, 0, 0, 0, 300, 301, 5, 33, 0, 0, 301, 302, 5, 130, 0, 0, 302, 303, 5, 52, 0, 0, 303, 306, 3, 160, 80, 0, 304, 305, 5, 116, 0, 0, 305, 307, 3, 160, 80, 0, 306, 304, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 309, 5, 42, 0, 0, 309, 310, 3, 4, 2, 0, 310, 311, 5, 149, 0, 0, 311, 313, 3, 10, 5, 0, 312, 314, 5, 150, 0, 0, 313, 312, 1, 0, 0, 0, 313, 314, 1, 0, 0, 0, 314, 27, 1, 0, 0, 0, 315, 316, 5, 31, 0, 0, 316, 317, 3, 160, 80, 0, 317, 319, 5, 130, 0, 0, 318, 320, 3, 8, 4, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 149, 0, 0, 322, 323, 3, 36, 18, 0, 323, 29, 1, 0, 0, 0, 324, 325, 3, 4, 2, 0, 325, 326, 5, 115, 0, 0, 326, 327, 5, 122, 0, 0, 327, 328, 3, 4, 2, 0, 328, 31, 1, 0, 0, 0, 329, 331, 3, 4, 2, 0, 330, 332, 5, 150, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 33, 1, 0, 0, 0, 333, 334, 5, 150, 0, 0, 334, 35, 1, 0, 0, 0, 335, 339, 5, 128, 0, 0, 336, 338, 3, 2, 1, 0, 337, 336, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 342, 1, 0, 0, 0, 341, 339, 1, 0, 0, 0, 342, 343, 5, 147, 0, 0, 343, 37, 1, 0, 0, 0, 344, 345, 3, 4, 2, 0, 345, 346, 5, 115, 0, 0, 346, 347, 3, 4, 2, 0, 347, 39, 1, 0, 0, 0, 348, 353, 3, 38, 19, 0, 349, 350, 5, 116, 0, 0, 350, 352, 3, 38, 19, 0, 351, 349, 1, 0, 0, 0, 352, 355, 1, 0, 0, 0, 353, 351, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 356, 358, 5, 116, 0, 0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 41, 1, 0, 0, 0, 359, 363, 3, 44, 22, 0, 360, 363, 3, 48, 24, 0, 361, 363, 3, 124, 62, 0, 362, 359, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 365, 5, 0, 0, 1, 365, 43, 1, 0, 0, 0, 366, 372, 3, 46, 23, 0, 367, 368, 5, 95, 0, 0, 368, 369, 5, 1, 0, 0, 369, 371, 3, 46, 23, 0, 370, 367, 1, 0, 0, 0, 371, 374, 1, 0, 0, 0, 372, 370, 1, 0, 0, 0, 372, 373, 1, 0, 0, 0, 373, 45, 1, 0, 0, 0, 374, 372, 1, 0, 0, 0, 375, 382, 3, 48, 24, 0, 376, 377, 5, 130, 0, 0, 377, 378, 3, 44, 22, 0, 378, 379, 5, 149, 0, 0, 379, 382, 1, 0, 0, 0, 380, 382, 3, 164, 82, 0, 381, 375, 1, 0, 0, 0, 381, 376, 1, 0, 0, 0, 381, 380, 1, 0, 0, 0, 382, 47, 1, 0, 0, 0, 383, 385, 3, 50, 25, 0, 384, 383, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 5, 79, 0, 0, 387, 389, 5, 24, 0, 0, 388, 387, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 391, 1, 0, 0, 0, 390, 392, 3, 52, 26, 0, 391, 390, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 393, 1, 0, 0, 0, 393, 395, 3, 114, 57, 0, 394, 396, 3, 54, 27, 0, 395, 394, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 398, 1, 0, 0, 0, 397, 399, 3, 56, 28, 0, 398, 397, 1, 0, 0, 0, 398, 399, 1, 0, 0, 0, 399, 401, 1, 0, 0, 0, 400, 402, 3, 60, 30, 0, 401, 400, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 404, 1, 0, 0, 0, 403, 405, 3, 62, 31, 0, 404, 403, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 408, 3, 64, 32, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 102, 0, 0, 410, 412, 7, 0, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 102, 0, 0, 414, 416, 5, 89, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 418, 1, 0, 0, 0, 417, 419, 3, 66, 33, 0, 418, 417, 1, 0, 0, 0, 418, 419, 1, 0, 0, 0, 419, 421, 1, 0, 0, 0, 420, 422, 3, 58, 29, 0, 421, 420, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 425, 3, 68, 34, 0, 424, 423, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 428, 1, 0, 0, 0, 426, 429, 3, 72, 36, 0, 427, 429, 3, 74, 37, 0, 428, 426, 1, 0, 0, 0, 428, 427, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 431, 1, 0, 0, 0, 430, 432, 3, 76, 38, 0, 431, 430, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 49, 1, 0, 0, 0, 433, 434, 5, 102, 0, 0, 434, 435, 3, 128, 64, 0, 435, 51, 1, 0, 0, 0, 436, 437, 5, 88, 0, 0, 437, 440, 5, 108, 0, 0, 438, 439, 5, 102, 0, 0, 439, 441, 5, 85, 0, 0, 440, 438, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0, 441, 53, 1, 0, 0, 0, 442, 443, 5, 34, 0, 0, 443, 444, 3, 78, 39, 0, 444, 55, 1, 0, 0, 0, 445, 447, 7, 1, 0, 0, 446, 445, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 449, 5, 5, 0, 0, 449, 450, 5, 47, 0, 0, 450, 451, 3, 114, 57, 0, 451, 57, 1, 0, 0, 0, 452, 453, 5, 101, 0, 0, 453, 454, 3, 160, 80, 0, 454, 455, 5, 6, 0, 0, 455, 456, 5, 130, 0, 0, 456, 457, 3, 98, 49, 0, 457, 467, 5, 149, 0, 0, 458, 459, 5, 116, 0, 0, 459, 460, 3, 160, 80, 0, 460, 461, 5, 6, 0, 0, 461, 462, 5, 130, 0, 0, 462, 463, 3, 98, 49, 0, 463, 464, 5, 149, 0, 0, 464, 466, 1, 0, 0, 0, 465, 458, 1, 0, 0, 0, 466, 469, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0, 0, 0, 468, 59, 1, 0, 0, 0, 469, 467, 1, 0, 0, 0, 470, 471, 5, 69, 0, 0, 471, 472, 3, 116, 58, 0, 472, 61, 1, 0, 0, 0, 473, 474, 5, 99, 0, 0, 474, 475, 3, 116, 58, 0, 475, 63, 1, 0, 0, 0, 476, 477, 5, 36, 0, 0, 477, 484, 5, 11, 0, 0, 478, 479, 7, 0, 0, 0, 479, 480, 5, 130, 0, 0, 480, 481, 3, 114, 57, 0, 481, 482, 5, 149, 0, 0, 482, 485, 1, 0, 0, 0, 483, 485, 3, 114, 57, 0, 484, 478, 1, 0, 0, 0, 484, 483, 1, 0, 0, 0, 485, 65, 1, 0, 0, 0, 486, 487, 5, 37, 0, 0, 487, 488, 3, 116, 58, 0, 488, 67, 1, 0, 0, 0, 489, 490, 5, 64, 0, 0, 490, 491, 5, 11, 0, 0, 491, 492, 3, 88, 44, 0, 492, 69, 1, 0, 0, 0, 493, 494, 5, 64, 0, 0, 494, 495, 5, 11, 0, 0, 495, 496, 3, 114, 57, 0, 496, 71, 1, 0, 0, 0, 497, 498, 5, 54, 0, 0, 498, 501, 3, 116, 58, 0, 499, 500, 5, 116, 0, 0, 500, 502, 3, 116, 58, 0, 501, 499, 1, 0, 0, 0, 501, 502, 1, 0, 0, 0, 502, 507, 1, 0, 0, 0, 503, 504, 5, 102, 0, 0, 504, 508, 5, 85, 0, 0, 505, 506, 5, 11, 0, 0, 506, 508, 3, 114, 57, 0, 507, 503, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 527, 1, 0, 0, 0, 509, 510, 5, 54, 0, 0, 510, 513, 3, 116, 58, 0, 511, 512, 5, 102, 0, 0, 512, 514, 5, 85, 0, 0, 513, 511, 1, 0, 0, 0, 513, 514, 1, 0, 0, 0, 514, 515, 1, 0, 0, 0, 515, 516, 5, 61, 0, 0, 516, 517, 3, 116, 58, 0, 517, 527, 1, 0, 0, 0, 518, 519, 5, 54, 0, 0, 519, 520, 3, 116, 58, 0, 520, 521, 5, 61, 0, 0, 521, 524, 3, 116, 58, 0, 522, 523, 5, 11, 0, 0, 523, 525, 3, 114, 57, 0, 524, 522, 1, 0, 0, 0, 524, 525, 1, 0, 0, 0, 525, 527, 1, 0, 0, 0, 526, 497, 1, 0, 0, 0, 526, 509, 1, 0, 0, 0, 526, 518, 1, 0, 0, 0, 527, 73, 1, 0, 0, 0, 528, 529, 5, 61, 0, 0, 529, 530, 3, 116, 58, 0, 530, 75, 1, 0, 0, 0, 531, 532, 5, 81, 0, 0, 532, 533, 3, 94, 47, 0, 533, 77, 1, 0, 0, 0, 534, 535, 6, 39, -1, 0, 535, 537, 3, 136, 68, 0, 536, 538, 5, 28, 0, 0, 537, 536, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 540, 1, 0, 0, 0, 539, 541, 3, 86, 43, 0, 540, 539, 1, 0, 0, 0, 540, 541, 1, 0, 0, 0, 541, 547, 1, 0, 0, 0, 542, 543, 5, 130, 0, 0, 543, 544, 3, 78, 39, 0, 544, 545, 5, 149, 0, 0, 545, 547, 1, 0, 0, 0, 546, 534, 1, 0, 0, 0, 546, 542, 1, 0, 0, 0, 547, 562, 1, 0, 0, 0, 548, 549, 10, 3, 0, 0, 549, 550, 3, 82, 41, 0, 550, 551, 3, 78, 39, 4, 551, 561, 1, 0, 0, 0, 552, 554, 10, 4, 0, 0, 553, 555, 3, 80, 40, 0, 554, 553, 1, 0, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 5, 47, 0, 0, 557, 558, 3, 78, 39, 0, 558, 559, 3, 84, 42, 0, 559, 561, 1, 0, 0, 0, 560, 548, 1, 0, 0, 0, 560, 552, 1, 0, 0, 0, 561, 564, 1, 0, 0, 0, 562, 560, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 79, 1, 0, 0, 0, 564, 562, 1, 0, 0, 0, 565, 567, 7, 2, 0, 0, 566, 565, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 575, 5, 44, 0, 0, 569, 571, 5, 44, 0, 0, 570, 572, 7, 2, 0, 0, 571, 570, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 575, 1, 0, 0, 0, 573, 575, 7, 2, 0, 0, 574, 566, 1, 0, 0, 0, 574, 569, 1, 0, 0, 0, 574, 573, 1, 0, 0, 0, 575, 609, 1, 0, 0, 0, 576, 578, 7, 3, 0, 0, 577, 576, 1, 0, 0, 0, 577, 578, 1, 0, 0, 0, 578, 579, 1, 0, 0, 0, 579, 581, 7, 4, 0, 0, 580, 582, 5, 65, 0, 0, 581, 580, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 591, 1, 0, 0, 0, 583, 585, 7, 4, 0, 0, 584, 586, 5, 65, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 588, 1, 0, 0, 0, 587, 589, 7, 3, 0, 0, 588, 587, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 591, 1, 0, 0, 0, 590, 577, 1, 0, 0, 0, 590, 583, 1, 0, 0, 0, 591, 609, 1, 0, 0, 0, 592, 594, 7, 5, 0, 0, 593, 592, 1, 0, 0, 0, 593, 594, 1, 0, 0, 0, 594, 595, 1, 0, 0, 0, 595, 597, 5, 35, 0, 0, 596, 598, 5, 65, 0, 0, 597, 596, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 607, 1, 0, 0, 0, 599, 601, 5, 35, 0, 0, 600, 602, 5, 65, 0, 0, 601, 600, 1, 0, 0, 0, 601, 602, 1, 0, 0, 0, 602, 604, 1, 0, 0, 0, 603, 605, 7, 5, 0, 0, 604, 603, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 607, 1, 0, 0, 0, 606, 593, 1, 0, 0, 0, 606, 599, 1, 0, 0, 0, 607, 609, 1, 0, 0, 0, 608, 574, 1, 0, 0, 0, 608, 590, 1, 0, 0, 0, 608, 606, 1, 0, 0, 0, 609, 81, 1, 0, 0, 0, 610, 611, 5, 17, 0, 0, 611, 614, 5, 47, 0, 0, 612, 614, 5, 116, 0, 0, 613, 610, 1, 0, 0, 0, 613, 612, 1, 0, 0, 0, 614, 83, 1, 0, 0, 0, 615, 616, 5, 62, 0, 0, 616, 625, 3, 114, 57, 0, 617, 618, 5, 96, 0, 0, 618, 619, 5, 130, 0, 0, 619, 620, 3, 114, 57, 0, 620, 621, 5, 149, 0, 0, 621, 625, 1, 0, 0, 0, 622, 623, 5, 96, 0, 0, 623, 625, 3, 114, 57, 0, 624, 615, 1, 0, 0, 0, 624, 617, 1, 0, 0, 0, 624, 622, 1, 0, 0, 0, 625, 85, 1, 0, 0, 0, 626, 627, 5, 77, 0, 0, 627, 630, 3, 92, 46, 0, 628, 629, 5, 61, 0, 0, 629, 631, 3, 92, 46, 0, 630, 628, 1, 0, 0, 0, 630, 631, 1, 0, 0, 0, 631, 87, 1, 0, 0, 0, 632, 637, 3, 90, 45, 0, 633, 634, 5, 116, 0, 0, 634, 636, 3, 90, 45, 0, 635, 633, 1, 0, 0, 0, 636, 639, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 89, 1, 0, 0, 0, 639, 637, 1, 0, 0, 0, 640, 642, 3, 116, 58, 0, 641, 643, 7, 6, 0, 0, 642, 641, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 646, 1, 0, 0, 0, 644, 645, 5, 60, 0, 0, 645, 647, 7, 7, 0, 0, 646, 644, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 650, 1, 0, 0, 0, 648, 649, 5, 16, 0, 0, 649, 651, 5, 110, 0, 0, 650, 648, 1, 0, 0, 0, 650, 651, 1, 0, 0, 0, 651, 91, 1, 0, 0, 0, 652, 659, 3, 164, 82, 0, 653, 656, 3, 148, 74, 0, 654, 655, 5, 151, 0, 0, 655, 657, 3, 148, 74, 0, 656, 654, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 659, 1, 0, 0, 0, 658, 652, 1, 0, 0, 0, 658, 653, 1, 0, 0, 0, 659, 93, 1, 0, 0, 0, 660, 665, 3, 96, 48, 0, 661, 662, 5, 116, 0, 0, 662, 664, 3, 96, 48, 0, 663, 661, 1, 0, 0, 0, 664, 667, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 95, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 668, 669, 3, 160, 80, 0, 669, 670, 5, 122, 0, 0, 670, 671, 3, 150, 75, 0, 671, 97, 1, 0, 0, 0, 672, 674, 3, 100, 50, 0, 673, 672, 1, 0, 0, 0, 673, 674, 1, 0, 0, 0, 674, 676, 1, 0, 0, 0, 675, 677, 3, 102, 51, 0, 676, 675, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 679, 1, 0, 0, 0, 678, 680, 3, 104, 52, 0, 679, 678, 1, 0, 0, 0, 679, 680, 1, 0, 0, 0, 680, 99, 1, 0, 0, 0, 681, 682, 5, 67, 0, 0, 682, 683, 5, 11, 0, 0, 683, 684, 3, 114, 57, 0, 684, 101, 1, 0, 0, 0, 685, 686, 5, 64, 0, 0, 686, 687, 5, 11, 0, 0, 687, 688, 3, 88, 44, 0, 688, 103, 1, 0, 0, 0, 689, 690, 7, 8, 0, 0, 690, 691, 3, 106, 53, 0, 691, 105, 1, 0, 0, 0, 692, 699, 3, 108, 54, 0, 693, 694, 5, 9, 0, 0, 694, 695, 3, 108, 54, 0, 695, 696, 5, 2, 0, 0, 696, 697, 3, 108, 54, 0, 697, 699, 1, 0, 0, 0, 698, 692, 1, 0, 0, 0, 698, 693, 1, 0, 0, 0, 699, 107, 1, 0, 0, 0, 700, 701, 5, 19, 0, 0, 701, 713, 5, 75, 0, 0, 702, 703, 5, 94, 0, 0, 703, 713, 5, 68, 0, 0, 704, 705, 5, 94, 0, 0, 705, 713, 5, 32, 0, 0, 706, 707, 3, 148, 74, 0, 707, 708, 5, 68, 0, 0, 708, 713, 1, 0, 0, 0, 709, 710, 3, 148, 74, 0, 710, 711, 5, 32, 0, 0, 711, 713, 1, 0, 0, 0, 712, 700, 1, 0, 0, 0, 712, 702, 1, 0, 0, 0, 712, 704, 1, 0, 0, 0, 712, 706, 1, 0, 0, 0, 712, 709, 1, 0, 0, 0, 713, 109, 1, 0, 0, 0, 714, 715, 3, 116, 58, 0, 715, 716, 5, 0, 0, 1, 716, 111, 1, 0, 0, 0, 717, 774, 3, 160, 80, 0, 718, 719, 3, 160, 80, 0, 719, 720, 5, 130, 0, 0, 720, 721, 3, 160, 80, 0, 721, 728, 3, 112, 56, 0, 722, 723, 5, 116, 0, 0, 723, 724, 3, 160, 80, 0, 724, 725, 3, 112, 56, 0, 725, 727, 1, 0, 0, 0, 726, 722, 1, 0, 0, 0, 727, 730, 1, 0, 0, 0, 728, 726, 1, 0, 0, 0, 728, 729, 1, 0, 0, 0, 729, 732, 1, 0, 0, 0, 730, 728, 1, 0, 0, 0, 731, 733, 5, 116, 0, 0, 732, 731, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 5, 149, 0, 0, 735, 774, 1, 0, 0, 0, 736, 737, 3, 160, 80, 0, 737, 738, 5, 130, 0, 0, 738, 743, 3, 162, 81, 0, 739, 740, 5, 116, 0, 0, 740, 742, 3, 162, 81, 0, 741, 739, 1, 0, 0, 0, 742, 745, 1, 0, 0, 0, 743, 741, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 747, 1, 0, 0, 0, 745, 743, 1, 0, 0, 0, 746, 748, 5, 116, 0, 0, 747, 746, 1, 0, 0, 0, 747, 748, 1, 0, 0, 0, 748, 749, 1, 0, 0, 0, 749, 750, 5, 149, 0, 0, 750, 774, 1, 0, 0, 0, 751, 752, 3, 160, 80, 0, 752, 753, 5, 130, 0, 0, 753, 758, 3, 112, 56, 0, 754, 755, 5, 116, 0, 0, 755, 757, 3, 112, 56, 0, 756, 754, 1, 0, 0, 0, 757, 760, 1, 0, 0, 0, 758, 756, 1, 0, 0, 0, 758, 759, 1, 0, 0, 0, 759, 762, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 763, 5, 116, 0, 0, 762, 761, 1, 0, 0, 0, 762, 763, 1, 0, 0, 0, 763, 764, 1, 0, 0, 0, 764, 765, 5, 149, 0, 0, 765, 774, 1, 0, 0, 0, 766, 767, 3, 160, 80, 0, 767, 769, 5, 130, 0, 0, 768, 770, 3, 114, 57, 0, 769, 768, 1, 0, 0, 0, 769, 770, 1, 0, 0, 0, 770, 771, 1, 0, 0, 0, 771, 772, 5, 149, 0, 0, 772, 774, 1, 0, 0, 0, 773, 717, 1, 0, 0, 0, 773, 718, 1, 0, 0, 0, 773, 736, 1, 0, 0, 0, 773, 751, 1, 0, 0, 0, 773, 766, 1, 0, 0, 0, 774, 113, 1, 0, 0, 0, 775, 780, 3, 116, 58, 0, 776, 777, 5, 116, 0, 0, 777, 779, 3, 116, 58, 0, 778, 776, 1, 0, 0, 0, 779, 782, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 780, 781, 1, 0, 0, 0, 781, 784, 1, 0, 0, 0, 782, 780, 1, 0, 0, 0, 783, 785, 5, 116, 0, 0, 784, 783, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 115, 1, 0, 0, 0, 786, 787, 6, 58, -1, 0, 787, 789, 5, 12, 0, 0, 788, 790, 3, 116, 58, 0, 789, 788, 1, 0, 0, 0, 789, 790, 1, 0, 0, 0, 790, 796, 1, 0, 0, 0, 791, 792, 5, 98, 0, 0, 792, 793, 3, 116, 58, 0, 793, 794, 5, 83, 0, 0, 794, 795, 3, 116, 58, 0, 795, 797, 1, 0, 0, 0, 796, 791, 1, 0, 0, 0, 797, 798, 1, 0, 0, 0, 798, 796, 1, 0, 0, 0, 798, 799, 1, 0, 0, 0, 799, 802, 1, 0, 0, 0, 800, 801, 5, 25, 0, 0, 801, 803, 3, 116, 58, 0, 802, 800, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 1, 0, 0, 0, 804, 805, 5, 26, 0, 0, 805, 936, 1, 0, 0, 0, 806, 807, 5, 13, 0, 0, 807, 808, 5, 130, 0, 0, 808, 809, 3, 116, 58, 0, 809, 810, 5, 6, 0, 0, 810, 811, 3, 112, 56, 0, 811, 812, 5, 149, 0, 0, 812, 936, 1, 0, 0, 0, 813, 814, 5, 20, 0, 0, 814, 936, 5, 110, 0, 0, 815, 816, 5, 45, 0, 0, 816, 817, 3, 116, 58, 0, 817, 818, 3, 152, 76, 0, 818, 936, 1, 0, 0, 0, 819, 820, 5, 82, 0, 0, 820, 821, 5, 130, 0, 0, 821, 822, 3, 116, 58, 0, 822, 823, 5, 34, 0, 0, 823, 826, 3, 116, 58, 0, 824, 825, 5, 33, 0, 0, 825, 827, 3, 116, 58, 0, 826, 824, 1, 0, 0, 0, 826, 827, 1, 0, 0, 0, 827, 828, 1, 0, 0, 0, 828, 829, 5, 149, 0, 0, 829, 936, 1, 0, 0, 0, 830, 831, 5, 86, 0, 0, 831, 936, 5, 110, 0, 0, 832, 833, 5, 91, 0, 0, 833, 834, 5, 130, 0, 0, 834, 835, 7, 9, 0, 0, 835, 836, 3, 166, 83, 0, 836, 837, 5, 34, 0, 0, 837, 838, 3, 116, 58, 0, 838, 839, 5, 149, 0, 0, 839, 936, 1, 0, 0, 0, 840, 841, 3, 160, 80, 0, 841, 843, 5, 130, 0, 0, 842, 844, 3, 114, 57, 0, 843, 842, 1, 0, 0, 0, 843, 844, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 846, 5, 149, 0, 0, 846, 855, 1, 0, 0, 0, 847, 849, 5, 130, 0, 0, 848, 850, 5, 24, 0, 0, 849, 848, 1, 0, 0, 0, 849, 850, 1, 0, 0, 0, 850, 852, 1, 0, 0, 0, 851, 853, 3, 118, 59, 0, 852, 851, 1, 0, 0, 0, 852, 853, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854, 856, 5, 149, 0, 0, 855, 847, 1, 0, 0, 0, 855, 856, 1, 0, 0, 0, 856, 857, 1, 0, 0, 0, 857, 858, 5, 66, 0, 0, 858, 859, 5, 130, 0, 0, 859, 860, 3, 98, 49, 0, 860, 861, 5, 149, 0, 0, 861, 936, 1, 0, 0, 0, 862, 863, 3, 160, 80, 0, 863, 865, 5, 130, 0, 0, 864, 866, 3, 114, 57, 0, 865, 864, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 868, 5, 149, 0, 0, 868, 877, 1, 0, 0, 0, 869, 871, 5, 130, 0, 0, 870, 872, 5, 24, 0, 0, 871, 870, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 874, 1, 0, 0, 0, 873, 875, 3, 118, 59, 0, 874, 873, 1, 0, 0, 0, 874, 875, 1, 0, 0, 0, 875, 876, 1, 0, 0, 0, 876, 878, 5, 149, 0, 0, 877, 869, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 880, 5, 66, 0, 0, 880, 881, 3, 160, 80, 0, 881, 936, 1, 0, 0, 0, 882, 888, 3, 160, 80, 0, 883, 885, 5, 130, 0, 0, 884, 886, 3, 114, 57, 0, 885, 884, 1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 889, 5, 149, 0, 0, 888, 883, 1, 0, 0, 0, 888, 889, 1, 0, 0, 0, 889, 890, 1, 0, 0, 0, 890, 892, 5, 130, 0, 0, 891, 893, 5, 24, 0, 0, 892, 891, 1, 0, 0, 0, 892, 893, 1, 0, 0, 0, 893, 895, 1, 0, 0, 0, 894, 896, 3, 118, 59, 0, 895, 894, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 897, 1, 0, 0, 0, 897, 898, 5, 149, 0, 0, 898, 936, 1, 0, 0, 0, 899, 936, 3, 124, 62, 0, 900, 936, 3, 168, 84, 0, 901, 936, 3, 150, 75, 0, 902, 903, 5, 118, 0, 0, 903, 936, 3, 116, 58, 19, 904, 905, 5, 58, 0, 0, 905, 936, 3, 116, 58, 13, 906, 907, 3, 140, 70, 0, 907, 908, 5, 120, 0, 0, 908, 910, 1, 0, 0, 0, 909, 906, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 1, 0, 0, 0, 911, 936, 5, 112, 0, 0, 912, 913, 5, 130, 0, 0, 913, 914, 3, 44, 22, 0, 914, 915, 5, 149, 0, 0, 915, 936, 1, 0, 0, 0, 916, 917, 5, 130, 0, 0, 917, 918, 3, 116, 58, 0, 918, 919, 5, 149, 0, 0, 919, 936, 1, 0, 0, 0, 920, 921, 5, 130, 0, 0, 921, 922, 3, 114, 57, 0, 922, 923, 5, 149, 0, 0, 923, 936, 1, 0, 0, 0, 924, 926, 5, 129, 0, 0, 925, 927, 3, 114, 57, 0, 926, 925, 1, 0, 0, 0, 926, 927, 1, 0, 0, 0, 927, 928, 1, 0, 0, 0, 928, 936, 5, 148, 0, 0, 929, 931, 5, 128, 0, 0, 930, 932, 3, 40, 20, 0, 931, 930, 1, 0, 0, 0, 931, 932, 1, 0, 0, 0, 932, 933, 1, 0, 0, 0, 933, 936, 5, 147, 0, 0, 934, 936, 3, 132, 66, 0, 935, 786, 1, 0, 0, 0, 935, 806, 1, 0, 0, 0, 935, 813, 1, 0, 0, 0, 935, 815, 1, 0, 0, 0, 935, 819, 1, 0, 0, 0, 935, 830, 1, 0, 0, 0, 935, 832, 1, 0, 0, 0, 935, 840, 1, 0, 0, 0, 935, 862, 1, 0, 0, 0, 935, 882, 1, 0, 0, 0, 935, 899, 1, 0, 0, 0, 935, 900, 1, 0, 0, 0, 935, 901, 1, 0, 0, 0, 935, 902, 1, 0, 0, 0, 935, 904, 1, 0, 0, 0, 935, 909, 1, 0, 0, 0, 935, 912, 1, 0, 0, 0, 935, 916, 1, 0, 0, 0, 935, 920, 1, 0, 0, 0, 935, 924, 1, 0, 0, 0, 935, 929, 1, 0, 0, 0, 935, 934, 1, 0, 0, 0, 936, 1041, 1, 0, 0, 0, 937, 941, 10, 18, 0, 0, 938, 942, 5, 112, 0, 0, 939, 942, 5, 151, 0, 0, 940, 942, 5, 138, 0, 0, 941, 938, 1, 0, 0, 0, 941, 939, 1, 0, 0, 0, 941, 940, 1, 0, 0, 0, 942, 943, 1, 0, 0, 0, 943, 1040, 3, 116, 58, 19, 944, 948, 10, 17, 0, 0, 945, 949, 5, 139, 0, 0, 946, 949, 5, 118, 0, 0, 947, 949, 5, 117, 0, 0, 948, 945, 1, 0, 0, 0, 948, 946, 1, 0, 0, 0, 948, 947, 1, 0, 0, 0, 949, 950, 1, 0, 0, 0, 950, 1040, 3, 116, 58, 18, 951, 976, 10, 16, 0, 0, 952, 977, 5, 121, 0, 0, 953, 977, 5, 122, 0, 0, 954, 977, 5, 133, 0, 0, 955, 977, 5, 131, 0, 0, 956, 977, 5, 132, 0, 0, 957, 977, 5, 123, 0, 0, 958, 977, 5, 124, 0, 0, 959, 961, 5, 58, 0, 0, 960, 959, 1, 0, 0, 0, 960, 961, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 964, 5, 42, 0, 0, 963, 965, 5, 15, 0, 0, 964, 963, 1, 0, 0, 0, 964, 965, 1, 0, 0, 0, 965, 977, 1, 0, 0, 0, 966, 968, 5, 58, 0, 0, 967, 966, 1, 0, 0, 0, 967, 968, 1, 0, 0, 0, 968, 969, 1, 0, 0, 0, 969, 977, 7, 10, 0, 0, 970, 977, 5, 145, 0, 0, 971, 977, 5, 146, 0, 0, 972, 977, 5, 135, 0, 0, 973, 977, 5, 126, 0, 0, 974, 977, 5, 127, 0, 0, 975, 977, 5, 134, 0, 0, 976, 952, 1, 0, 0, 0, 976, 953, 1, 0, 0, 0, 976, 954, 1, 0, 0, 0, 976, 955, 1, 0, 0, 0, 976, 956, 1, 0, 0, 0, 976, 957, 1, 0, 0, 0, 976, 958, 1, 0, 0, 0, 976, 960, 1, 0, 0, 0, 976, 967, 1, 0, 0, 0, 976, 970, 1, 0, 0, 0, 976, 971, 1, 0, 0, 0, 976, 972, 1, 0, 0, 0, 976, 973, 1, 0, 0, 0, 976, 974, 1, 0, 0, 0, 976, 975, 1, 0, 0, 0, 977, 978, 1, 0, 0, 0, 978, 1040, 3, 116, 58, 17, 979, 980, 10, 14, 0, 0, 980, 981, 5, 137, 0, 0, 981, 1040, 3, 116, 58, 15, 982, 983, 10, 12, 0, 0, 983, 984, 5, 2, 0, 0, 984, 1040, 3, 116, 58, 13, 985, 986, 10, 11, 0, 0, 986, 987, 5, 63, 0, 0, 987, 1040, 3, 116, 58, 12, 988, 990, 10, 10, 0, 0, 989, 991, 5, 58, 0, 0, 990, 989, 1, 0, 0, 0, 990, 991, 1, 0, 0, 0, 991, 992, 1, 0, 0, 0, 992, 993, 5, 9, 0, 0, 993, 994, 3, 116, 58, 0, 994, 995, 5, 2, 0, 0, 995, 996, 3, 116, 58, 11, 996, 1040, 1, 0, 0, 0, 997, 998, 10, 9, 0, 0, 998, 999, 5, 140, 0, 0, 999, 1000, 3, 116, 58, 0, 1000, 1001, 5, 115, 0, 0, 1001, 1002, 3, 116, 58, 9, 1002, 1040, 1, 0, 0, 0, 1003, 1004, 10, 25, 0, 0, 1004, 1005, 5, 129, 0, 0, 1005, 1006, 3, 116, 58, 0, 1006, 1007, 5, 148, 0, 0, 1007, 1040, 1, 0, 0, 0, 1008, 1009, 10, 24, 0, 0, 1009, 1010, 5, 120, 0, 0, 1010, 1040, 5, 108, 0, 0, 1011, 1012, 10, 23, 0, 0, 1012, 1013, 5, 120, 0, 0, 1013, 1040, 3, 160, 80, 0, 1014, 1015, 10, 22, 0, 0, 1015, 1016, 5, 136, 0, 0, 1016, 1017, 5, 129, 0, 0, 1017, 1018, 3, 116, 58, 0, 1018, 1019, 5, 148, 0, 0, 1019, 1040, 1, 0, 0, 0, 1020, 1021, 10, 21, 0, 0, 1021, 1022, 5, 136, 0, 0, 1022, 1040, 5, 108, 0, 0, 1023, 1024, 10, 20, 0, 0, 1024, 1025, 5, 136, 0, 0, 1025, 1040, 3, 160, 80, 0, 1026, 1027, 10, 15, 0, 0, 1027, 1029, 5, 46, 0, 0, 1028, 1030, 5, 58, 0, 0, 1029, 1028, 1, 0, 0, 0, 1029, 1030, 1, 0, 0, 0, 1030, 1031, 1, 0, 0, 0, 1031, 1040, 5, 59, 0, 0, 1032, 1037, 10, 8, 0, 0, 1033, 1034, 5, 6, 0, 0, 1034, 1038, 3, 160, 80, 0, 1035, 1036, 5, 6, 0, 0, 1036, 1038, 5, 110, 0, 0, 1037, 1033, 1, 0, 0, 0, 1037, 1035, 1, 0, 0, 0, 1038, 1040, 1, 0, 0, 0, 1039, 937, 1, 0, 0, 0, 1039, 944, 1, 0, 0, 0, 1039, 951, 1, 0, 0, 0, 1039, 979, 1, 0, 0, 0, 1039, 982, 1, 0, 0, 0, 1039, 985, 1, 0, 0, 0, 1039, 988, 1, 0, 0, 0, 1039, 997, 1, 0, 0, 0, 1039, 1003, 1, 0, 0, 0, 1039, 1008, 1, 0, 0, 0, 1039, 1011, 1, 0, 0, 0, 1039, 1014, 1, 0, 0, 0, 1039, 1020, 1, 0, 0, 0, 1039, 1023, 1, 0, 0, 0, 1039, 1026, 1, 0, 0, 0, 1039, 1032, 1, 0, 0, 0, 1040, 1043, 1, 0, 0, 0, 1041, 1039, 1, 0, 0, 0, 1041, 1042, 1, 0, 0, 0, 1042, 117, 1, 0, 0, 0, 1043, 1041, 1, 0, 0, 0, 1044, 1049, 3, 120, 60, 0, 1045, 1046, 5, 116, 0, 0, 1046, 1048, 3, 120, 60, 0, 1047, 1045, 1, 0, 0, 0, 1048, 1051, 1, 0, 0, 0, 1049, 1047, 1, 0, 0, 0, 1049, 1050, 1, 0, 0, 0, 1050, 1053, 1, 0, 0, 0, 1051, 1049, 1, 0, 0, 0, 1052, 1054, 5, 116, 0, 0, 1053, 1052, 1, 0, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 119, 1, 0, 0, 0, 1055, 1058, 3, 122, 61, 0, 1056, 1058, 3, 116, 58, 0, 1057, 1055, 1, 0, 0, 0, 1057, 1056, 1, 0, 0, 0, 1058, 121, 1, 0, 0, 0, 1059, 1060, 5, 130, 0, 0, 1060, 1065, 3, 160, 80, 0, 1061, 1062, 5, 116, 0, 0, 1062, 1064, 3, 160, 80, 0, 1063, 1061, 1, 0, 0, 0, 1064, 1067, 1, 0, 0, 0, 1065, 1063, 1, 0, 0, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1069, 1, 0, 0, 0, 1067, 1065, 1, 0, 0, 0, 1068, 1070, 5, 116, 0, 0, 1069, 1068, 1, 0, 0, 0, 1069, 1070, 1, 0, 0, 0, 1070, 1071, 1, 0, 0, 0, 1071, 1072, 5, 149, 0, 0, 1072, 1085, 1, 0, 0, 0, 1073, 1078, 3, 160, 80, 0, 1074, 1075, 5, 116, 0, 0, 1075, 1077, 3, 160, 80, 0, 1076, 1074, 1, 0, 0, 0, 1077, 1080, 1, 0, 0, 0, 1078, 1076, 1, 0, 0, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1082, 1, 0, 0, 0, 1080, 1078, 1, 0, 0, 0, 1081, 1083, 5, 116, 0, 0, 1082, 1081, 1, 0, 0, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1085, 1, 0, 0, 0, 1084, 1059, 1, 0, 0, 0, 1084, 1073, 1, 0, 0, 0, 1085, 1086, 1, 0, 0, 0, 1086, 1087, 5, 111, 0, 0, 1087, 1088, 3, 116, 58, 0, 1088, 123, 1, 0, 0, 0, 1089, 1090, 5, 132, 0, 0, 1090, 1094, 3, 160, 80, 0, 1091, 1093, 3, 126, 63, 0, 1092, 1091, 1, 0, 0, 0, 1093, 1096, 1, 0, 0, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1097, 1, 0, 0, 0, 1096, 1094, 1, 0, 0, 0, 1097, 1098, 5, 151, 0, 0, 1098, 1099, 5, 124, 0, 0, 1099, 1118, 1, 0, 0, 0, 1100, 1101, 5, 132, 0, 0, 1101, 1105, 3, 160, 80, 0, 1102, 1104, 3, 126, 63, 0, 1103, 1102, 1, 0, 0, 0, 1104, 1107, 1, 0, 0, 0, 1105, 1103, 1, 0, 0, 0, 1105, 1106, 1, 0, 0, 0, 1106, 1108, 1, 0, 0, 0, 1107, 1105, 1, 0, 0, 0, 1108, 1110, 5, 124, 0, 0, 1109, 1111, 3, 124, 62, 0, 1110, 1109, 1, 0, 0, 0, 1110, 1111, 1, 0, 0, 0, 1111, 1112, 1, 0, 0, 0, 1112, 1113, 5, 132, 0, 0, 1113, 1114, 5, 151, 0, 0, 1114, 1115, 3, 160, 80, 0, 1115, 1116, 5, 124, 0, 0, 1116, 1118, 1, 0, 0, 0, 1117, 1089, 1, 0, 0, 0, 1117, 1100, 1, 0, 0, 0, 1118, 125, 1, 0, 0, 0, 1119, 1120, 3, 160, 80, 0, 1120, 1121, 5, 122, 0, 0, 1121, 1122, 3, 166, 83, 0, 1122, 1131, 1, 0, 0, 0, 1123, 1124, 3, 160, 80, 0, 1124, 1125, 5, 122, 0, 0, 1125, 1126, 5, 128, 0, 0, 1126, 1127, 3, 116, 58, 0, 1127, 1128, 5, 147, 0, 0, 1128, 1131, 1, 0, 0, 0, 1129, 1131, 3, 160, 80, 0, 1130, 1119, 1, 0, 0, 0, 1130, 1123, 1, 0, 0, 0, 1130, 1129, 1, 0, 0, 0, 1131, 127, 1, 0, 0, 0, 1132, 1137, 3, 130, 65, 0, 1133, 1134, 5, 116, 0, 0, 1134, 1136, 3, 130, 65, 0, 1135, 1133, 1, 0, 0, 0, 1136, 1139, 1, 0, 0, 0, 1137, 1135, 1, 0, 0, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1141, 1, 0, 0, 0, 1139, 1137, 1, 0, 0, 0, 1140, 1142, 5, 116, 0, 0, 1141, 1140, 1, 0, 0, 0, 1141, 1142, 1, 0, 0, 0, 1142, 129, 1, 0, 0, 0, 1143, 1144, 3, 160, 80, 0, 1144, 1145, 5, 6, 0, 0, 1145, 1146, 5, 130, 0, 0, 1146, 1147, 3, 44, 22, 0, 1147, 1148, 5, 149, 0, 0, 1148, 1154, 1, 0, 0, 0, 1149, 1150, 3, 116, 58, 0, 1150, 1151, 5, 6, 0, 0, 1151, 1152, 3, 160, 80, 0, 1152, 1154, 1, 0, 0, 0, 1153, 1143, 1, 0, 0, 0, 1153, 1149, 1, 0, 0, 0, 1154, 131, 1, 0, 0, 0, 1155, 1163, 3, 164, 82, 0, 1156, 1157, 3, 140, 70, 0, 1157, 1158, 5, 120, 0, 0, 1158, 1160, 1, 0, 0, 0, 1159, 1156, 1, 0, 0, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1161, 1, 0, 0, 0, 1161, 1163, 3, 134, 67, 0, 1162, 1155, 1, 0, 0, 0, 1162, 1159, 1, 0, 0, 0, 1163, 133, 1, 0, 0, 0, 1164, 1169, 3, 160, 80, 0, 1165, 1166, 5, 120, 0, 0, 1166, 1168, 3, 160, 80, 0, 1167, 1165, 1, 0, 0, 0, 1168, 1171, 1, 0, 0, 0, 1169, 1167, 1, 0, 0, 0, 1169, 1170, 1, 0, 0, 0, 1170, 135, 1, 0, 0, 0, 1171, 1169, 1, 0, 0, 0, 1172, 1173, 6, 68, -1, 0, 1173, 1182, 3, 140, 70, 0, 1174, 1182, 3, 138, 69, 0, 1175, 1176, 5, 130, 0, 0, 1176, 1177, 3, 44, 22, 0, 1177, 1178, 5, 149, 0, 0, 1178, 1182, 1, 0, 0, 0, 1179, 1182, 3, 124, 62, 0, 1180, 1182, 3, 164, 82, 0, 1181, 1172, 1, 0, 0, 0, 1181, 1174, 1, 0, 0, 0, 1181, 1175, 1, 0, 0, 0, 1181, 1179, 1, 0, 0, 0, 1181, 1180, 1, 0, 0, 0, 1182, 1191, 1, 0, 0, 0, 1183, 1187, 10, 3, 0, 0, 1184, 1188, 3, 158, 79, 0, 1185, 1186, 5, 6, 0, 0, 1186, 1188, 3, 160, 80, 0, 1187, 1184, 1, 0, 0, 0, 1187, 1185, 1, 0, 0, 0, 1188, 1190, 1, 0, 0, 0, 1189, 1183, 1, 0, 0, 0, 1190, 1193, 1, 0, 0, 0, 1191, 1189, 1, 0, 0, 0, 1191, 1192, 1, 0, 0, 0, 1192, 137, 1, 0, 0, 0, 1193, 1191, 1, 0, 0, 0, 1194, 1195, 3, 160, 80, 0, 1195, 1197, 5, 130, 0, 0, 1196, 1198, 3, 142, 71, 0, 1197, 1196, 1, 0, 0, 0, 1197, 1198, 1, 0, 0, 0, 1198, 1199, 1, 0, 0, 0, 1199, 1200, 5, 149, 0, 0, 1200, 139, 1, 0, 0, 0, 1201, 1202, 3, 144, 72, 0, 1202, 1203, 5, 120, 0, 0, 1203, 1205, 1, 0, 0, 0, 1204, 1201, 1, 0, 0, 0, 1204, 1205, 1, 0, 0, 0, 1205, 1206, 1, 0, 0, 0, 1206, 1207, 3, 160, 80, 0, 1207, 141, 1, 0, 0, 0, 1208, 1213, 3, 116, 58, 0, 1209, 1210, 5, 116, 0, 0, 1210, 1212, 3, 116, 58, 0, 1211, 1209, 1, 0, 0, 0, 1212, 1215, 1, 0, 0, 0, 1213, 1211, 1, 0, 0, 0, 1213, 1214, 1, 0, 0, 0, 1214, 1217, 1, 0, 0, 0, 1215, 1213, 1, 0, 0, 0, 1216, 1218, 5, 116, 0, 0, 1217, 1216, 1, 0, 0, 0, 1217, 1218, 1, 0, 0, 0, 1218, 143, 1, 0, 0, 0, 1219, 1220, 3, 160, 80, 0, 1220, 145, 1, 0, 0, 0, 1221, 1230, 5, 106, 0, 0, 1222, 1223, 5, 120, 0, 0, 1223, 1230, 7, 11, 0, 0, 1224, 1225, 5, 108, 0, 0, 1225, 1227, 5, 120, 0, 0, 1226, 1228, 7, 11, 0, 0, 1227, 1226, 1, 0, 0, 0, 1227, 1228, 1, 0, 0, 0, 1228, 1230, 1, 0, 0, 0, 1229, 1221, 1, 0, 0, 0, 1229, 1222, 1, 0, 0, 0, 1229, 1224, 1, 0, 0, 0, 1230, 147, 1, 0, 0, 0, 1231, 1233, 7, 12, 0, 0, 1232, 1231, 1, 0, 0, 0, 1232, 1233, 1, 0, 0, 0, 1233, 1240, 1, 0, 0, 0, 1234, 1241, 3, 146, 73, 0, 1235, 1241, 5, 107, 0, 0, 1236, 1241, 5, 108, 0, 0, 1237, 1241, 5, 109, 0, 0, 1238, 1241, 5, 43, 0, 0, 1239, 1241, 5, 57, 0, 0, 1240, 1234, 1, 0, 0, 0, 1240, 1235, 1, 0, 0, 0, 1240, 1236, 1, 0, 0, 0, 1240, 1237, 1, 0, 0, 0, 1240, 1238, 1, 0, 0, 0, 1240, 1239, 1, 0, 0, 0, 1241, 149, 1, 0, 0, 0, 1242, 1246, 3, 148, 74, 0, 1243, 1246, 5, 110, 0, 0, 1244, 1246, 5, 59, 0, 0, 1245, 1242, 1, 0, 0, 0, 1245, 1243, 1, 0, 0, 0, 1245, 1244, 1, 0, 0, 0, 1246, 151, 1, 0, 0, 0, 1247, 1248, 7, 13, 0, 0, 1248, 153, 1, 0, 0, 0, 1249, 1250, 7, 14, 0, 0, 1250, 155, 1, 0, 0, 0, 1251, 1252, 7, 15, 0, 0, 1252, 157, 1, 0, 0, 0, 1253, 1256, 5, 105, 0, 0, 1254, 1256, 3, 156, 78, 0, 1255, 1253, 1, 0, 0, 0, 1255, 1254, 1, 0, 0, 0, 1256, 159, 1, 0, 0, 0, 1257, 1261, 5, 105, 0, 0, 1258, 1261, 3, 152, 76, 0, 1259, 1261, 3, 154, 77, 0, 1260, 1257, 1, 0, 0, 0, 1260, 1258, 1, 0, 0, 0, 1260, 1259, 1, 0, 0, 0, 1261, 161, 1, 0, 0, 0, 1262, 1263, 3, 166, 83, 0, 1263, 1264, 5, 122, 0, 0, 1264, 1265, 3, 148, 74, 0, 1265, 163, 1, 0, 0, 0, 1266, 1267, 5, 128, 0, 0, 1267, 1268, 3, 160, 80, 0, 1268, 1269, 5, 147, 0, 0, 1269, 165, 1, 0, 0, 0, 1270, 1273, 5, 110, 0, 0, 1271, 1273, 3, 168, 84, 0, 1272, 1270, 1, 0, 0, 0, 1272, 1271, 1, 0, 0, 0, 1273, 167, 1, 0, 0, 0, 1274, 1278, 5, 142, 0, 0, 1275, 1277, 3, 170, 85, 0, 1276, 1275, 1, 0, 0, 0, 1277, 1280, 1, 0, 0, 0, 1278, 1276, 1, 0, 0, 0, 1278, 1279, 1, 0, 0, 0, 1279, 1281, 1, 0, 0, 0, 1280, 1278, 1, 0, 0, 0, 1281, 1282, 5, 144, 0, 0, 1282, 169, 1, 0, 0, 0, 1283, 1284, 5, 157, 0, 0, 1284, 1285, 3, 116, 58, 0, 1285, 1286, 5, 147, 0, 0, 1286, 1289, 1, 0, 0, 0, 1287, 1289, 5, 156, 0, 0, 1288, 1283, 1, 0, 0, 0, 1288, 1287, 1, 0, 0, 0, 1289, 171, 1, 0, 0, 0, 1290, 1294, 5, 143, 0, 0, 1291, 1293, 3, 174, 87, 0, 1292, 1291, 1, 0, 0, 0, 1293, 1296, 1, 0, 0, 0, 1294, 1292, 1, 0, 0, 0, 1294, 1295, 1, 0, 0, 0, 1295, 1297, 1, 0, 0, 0, 1296, 1294, 1, 0, 0, 0, 1297, 1298, 5, 0, 0, 1, 1298, 173, 1, 0, 0, 0, 1299, 1300, 5, 159, 0, 0, 1300, 1301, 3, 116, 58, 0, 1301, 1302, 5, 147, 0, 0, 1302, 1305, 1, 0, 0, 0, 1303, 1305, 5, 158, 0, 0, 1304, 1299, 1, 0, 0, 0, 1304, 1303, 1, 0, 0, 0, 1305, 175, 1, 0, 0, 0, 168, 179, 186, 195, 202, 206, 220, 224, 227, 231, 234, 241, 245, 254, 259, 268, 276, 283, 287, 293, 298, 306, 313, 319, 331, 339, 353, 357, 362, 372, 381, 384, 388, 391, 395, 398, 401, 404, 407, 411, 415, 418, 421, 424, 428, 431, 440, 446, 467, 484, 501, 507, 513, 524, 526, 537, 540, 546, 554, 560, 562, 566, 571, 574, 577, 581, 585, 588, 590, 593, 597, 601, 604, 606, 608, 613, 624, 630, 637, 642, 646, 650, 656, 658, 665, 673, 676, 679, 698, 712, 728, 732, 743, 747, 758, 762, 769, 773, 780, 784, 789, 798, 802, 826, 843, 849, 852, 855, 865, 871, 874, 877, 885, 888, 892, 895, 909, 926, 931, 935, 941, 948, 960, 964, 967, 976, 990, 1029, 1037, 1039, 1041, 1049, 1053, 1057, 1065, 1069, 1078, 1082, 1084, 1094, 1105, 1110, 1117, 1130, 1137, 1141, 1153, 1159, 1162, 1169, 1181, 1187, 1191, 1197, 1204, 1213, 1217, 1227, 1229, 1232, 1240, 1245, 1255, 1260, 1272, 1278, 1288, 1294, 1304] \ No newline at end of file +[4, 1, 159, 1311, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 1, 0, 5, 0, 178, 8, 0, 10, 0, 12, 0, 181, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 187, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 196, 8, 3, 1, 4, 1, 4, 1, 4, 5, 4, 201, 8, 4, 10, 4, 12, 4, 204, 9, 4, 1, 4, 3, 4, 207, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 221, 8, 5, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 6, 3, 6, 228, 8, 6, 1, 7, 1, 7, 3, 7, 232, 8, 7, 1, 7, 3, 7, 235, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 242, 8, 8, 1, 8, 1, 8, 3, 8, 246, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 5, 9, 253, 8, 9, 10, 9, 12, 9, 256, 9, 9, 1, 9, 1, 9, 3, 9, 260, 8, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 269, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 277, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 284, 8, 12, 1, 12, 1, 12, 3, 12, 288, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 294, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 299, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 307, 8, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 314, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 320, 8, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 3, 16, 332, 8, 16, 1, 17, 1, 17, 1, 18, 1, 18, 5, 18, 338, 8, 18, 10, 18, 12, 18, 341, 9, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 352, 8, 20, 10, 20, 12, 20, 355, 9, 20, 1, 20, 3, 20, 358, 8, 20, 1, 21, 1, 21, 1, 21, 3, 21, 363, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 371, 8, 22, 10, 22, 12, 22, 374, 9, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 382, 8, 23, 1, 24, 3, 24, 385, 8, 24, 1, 24, 1, 24, 3, 24, 389, 8, 24, 1, 24, 3, 24, 392, 8, 24, 1, 24, 1, 24, 3, 24, 396, 8, 24, 1, 24, 3, 24, 399, 8, 24, 1, 24, 3, 24, 402, 8, 24, 1, 24, 3, 24, 405, 8, 24, 1, 24, 3, 24, 408, 8, 24, 1, 24, 1, 24, 3, 24, 412, 8, 24, 1, 24, 1, 24, 3, 24, 416, 8, 24, 1, 24, 3, 24, 419, 8, 24, 1, 24, 3, 24, 422, 8, 24, 1, 24, 3, 24, 425, 8, 24, 1, 24, 1, 24, 3, 24, 429, 8, 24, 1, 24, 3, 24, 432, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 441, 8, 26, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 447, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 466, 8, 29, 10, 29, 12, 29, 469, 9, 29, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 485, 8, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 502, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 508, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 514, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 525, 8, 36, 3, 36, 527, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 3, 39, 538, 8, 39, 1, 39, 3, 39, 541, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 547, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 555, 8, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 561, 8, 39, 10, 39, 12, 39, 564, 9, 39, 1, 40, 3, 40, 567, 8, 40, 1, 40, 1, 40, 1, 40, 3, 40, 572, 8, 40, 1, 40, 3, 40, 575, 8, 40, 1, 40, 3, 40, 578, 8, 40, 1, 40, 1, 40, 3, 40, 582, 8, 40, 1, 40, 1, 40, 3, 40, 586, 8, 40, 1, 40, 3, 40, 589, 8, 40, 3, 40, 591, 8, 40, 1, 40, 3, 40, 594, 8, 40, 1, 40, 1, 40, 3, 40, 598, 8, 40, 1, 40, 1, 40, 3, 40, 602, 8, 40, 1, 40, 3, 40, 605, 8, 40, 3, 40, 607, 8, 40, 3, 40, 609, 8, 40, 1, 41, 1, 41, 1, 41, 3, 41, 614, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 625, 8, 42, 1, 43, 1, 43, 1, 43, 1, 43, 3, 43, 631, 8, 43, 1, 44, 1, 44, 1, 44, 5, 44, 636, 8, 44, 10, 44, 12, 44, 639, 9, 44, 1, 45, 1, 45, 3, 45, 643, 8, 45, 1, 45, 1, 45, 3, 45, 647, 8, 45, 1, 45, 1, 45, 3, 45, 651, 8, 45, 1, 46, 1, 46, 1, 46, 1, 46, 3, 46, 657, 8, 46, 3, 46, 659, 8, 46, 1, 47, 1, 47, 1, 47, 5, 47, 664, 8, 47, 10, 47, 12, 47, 667, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 3, 49, 674, 8, 49, 1, 49, 3, 49, 677, 8, 49, 1, 49, 3, 49, 680, 8, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 699, 8, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 3, 54, 713, 8, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 727, 8, 56, 10, 56, 12, 56, 730, 9, 56, 1, 56, 3, 56, 733, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 742, 8, 56, 10, 56, 12, 56, 745, 9, 56, 1, 56, 3, 56, 748, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 757, 8, 56, 10, 56, 12, 56, 760, 9, 56, 1, 56, 3, 56, 763, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 770, 8, 56, 1, 56, 1, 56, 3, 56, 774, 8, 56, 1, 57, 1, 57, 1, 57, 5, 57, 779, 8, 57, 10, 57, 12, 57, 782, 9, 57, 1, 57, 3, 57, 785, 8, 57, 1, 58, 1, 58, 1, 58, 3, 58, 790, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 4, 58, 797, 8, 58, 11, 58, 12, 58, 798, 1, 58, 1, 58, 3, 58, 803, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 827, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 844, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 850, 8, 58, 1, 58, 3, 58, 853, 8, 58, 1, 58, 3, 58, 856, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 866, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 872, 8, 58, 1, 58, 3, 58, 875, 8, 58, 1, 58, 3, 58, 878, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 886, 8, 58, 1, 58, 3, 58, 889, 8, 58, 1, 58, 1, 58, 3, 58, 893, 8, 58, 1, 58, 3, 58, 896, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 910, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 927, 8, 58, 1, 58, 1, 58, 1, 58, 3, 58, 932, 8, 58, 1, 58, 1, 58, 3, 58, 936, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 942, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 949, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 961, 8, 58, 1, 58, 1, 58, 3, 58, 965, 8, 58, 1, 58, 3, 58, 968, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 977, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 991, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1030, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 1038, 8, 58, 5, 58, 1040, 8, 58, 10, 58, 12, 58, 1043, 9, 58, 1, 59, 1, 59, 1, 59, 5, 59, 1048, 8, 59, 10, 59, 12, 59, 1051, 9, 59, 1, 59, 3, 59, 1054, 8, 59, 1, 60, 1, 60, 3, 60, 1058, 8, 60, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1064, 8, 61, 10, 61, 12, 61, 1067, 9, 61, 1, 61, 3, 61, 1070, 8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1077, 8, 61, 10, 61, 12, 61, 1080, 9, 61, 1, 61, 3, 61, 1083, 8, 61, 3, 61, 1085, 8, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 5, 62, 1093, 8, 62, 10, 62, 12, 62, 1096, 9, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 5, 62, 1104, 8, 62, 10, 62, 12, 62, 1107, 9, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1115, 8, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1122, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 1135, 8, 63, 1, 64, 1, 64, 1, 64, 5, 64, 1140, 8, 64, 10, 64, 12, 64, 1143, 9, 64, 1, 64, 3, 64, 1146, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 1158, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 1164, 8, 66, 1, 66, 3, 66, 1167, 8, 66, 1, 67, 1, 67, 1, 67, 5, 67, 1172, 8, 67, 10, 67, 12, 67, 1175, 9, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1186, 8, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 1192, 8, 68, 5, 68, 1194, 8, 68, 10, 68, 12, 68, 1197, 9, 68, 1, 69, 1, 69, 1, 69, 3, 69, 1202, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 3, 70, 1209, 8, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 5, 71, 1216, 8, 71, 10, 71, 12, 71, 1219, 9, 71, 1, 71, 3, 71, 1222, 8, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 1232, 8, 73, 3, 73, 1234, 8, 73, 1, 74, 3, 74, 1237, 8, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 3, 74, 1245, 8, 74, 1, 75, 1, 75, 1, 75, 3, 75, 1250, 8, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 3, 79, 1260, 8, 79, 1, 80, 1, 80, 1, 80, 3, 80, 1265, 8, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 3, 83, 1277, 8, 83, 1, 84, 1, 84, 5, 84, 1281, 8, 84, 10, 84, 12, 84, 1284, 9, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 1293, 8, 85, 1, 86, 1, 86, 5, 86, 1297, 8, 86, 10, 86, 12, 86, 1300, 9, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 3, 87, 1309, 8, 87, 1, 87, 0, 3, 78, 116, 136, 88, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 0, 16, 2, 0, 18, 18, 74, 74, 2, 0, 44, 44, 51, 51, 3, 0, 1, 1, 4, 4, 8, 8, 4, 0, 1, 1, 3, 4, 8, 8, 80, 80, 2, 0, 51, 51, 73, 73, 2, 0, 1, 1, 4, 4, 2, 0, 7, 7, 22, 23, 2, 0, 30, 30, 49, 49, 2, 0, 71, 71, 76, 76, 3, 0, 10, 10, 50, 50, 90, 90, 2, 0, 41, 41, 53, 53, 1, 0, 107, 108, 2, 0, 118, 118, 139, 139, 7, 0, 21, 21, 38, 38, 55, 56, 70, 70, 78, 78, 97, 97, 103, 103, 16, 0, 1, 13, 15, 20, 22, 28, 30, 30, 32, 37, 39, 42, 44, 51, 53, 54, 58, 58, 60, 69, 71, 77, 79, 83, 85, 92, 94, 96, 98, 99, 101, 102, 4, 0, 20, 20, 30, 30, 39, 39, 48, 48, 1479, 0, 179, 1, 0, 0, 0, 2, 186, 1, 0, 0, 0, 4, 188, 1, 0, 0, 0, 6, 190, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 220, 1, 0, 0, 0, 12, 222, 1, 0, 0, 0, 14, 229, 1, 0, 0, 0, 16, 236, 1, 0, 0, 0, 18, 249, 1, 0, 0, 0, 20, 261, 1, 0, 0, 0, 22, 270, 1, 0, 0, 0, 24, 278, 1, 0, 0, 0, 26, 300, 1, 0, 0, 0, 28, 315, 1, 0, 0, 0, 30, 324, 1, 0, 0, 0, 32, 329, 1, 0, 0, 0, 34, 333, 1, 0, 0, 0, 36, 335, 1, 0, 0, 0, 38, 344, 1, 0, 0, 0, 40, 348, 1, 0, 0, 0, 42, 362, 1, 0, 0, 0, 44, 366, 1, 0, 0, 0, 46, 381, 1, 0, 0, 0, 48, 384, 1, 0, 0, 0, 50, 433, 1, 0, 0, 0, 52, 436, 1, 0, 0, 0, 54, 442, 1, 0, 0, 0, 56, 446, 1, 0, 0, 0, 58, 452, 1, 0, 0, 0, 60, 470, 1, 0, 0, 0, 62, 473, 1, 0, 0, 0, 64, 476, 1, 0, 0, 0, 66, 486, 1, 0, 0, 0, 68, 489, 1, 0, 0, 0, 70, 493, 1, 0, 0, 0, 72, 526, 1, 0, 0, 0, 74, 528, 1, 0, 0, 0, 76, 531, 1, 0, 0, 0, 78, 546, 1, 0, 0, 0, 80, 608, 1, 0, 0, 0, 82, 613, 1, 0, 0, 0, 84, 624, 1, 0, 0, 0, 86, 626, 1, 0, 0, 0, 88, 632, 1, 0, 0, 0, 90, 640, 1, 0, 0, 0, 92, 658, 1, 0, 0, 0, 94, 660, 1, 0, 0, 0, 96, 668, 1, 0, 0, 0, 98, 673, 1, 0, 0, 0, 100, 681, 1, 0, 0, 0, 102, 685, 1, 0, 0, 0, 104, 689, 1, 0, 0, 0, 106, 698, 1, 0, 0, 0, 108, 712, 1, 0, 0, 0, 110, 714, 1, 0, 0, 0, 112, 773, 1, 0, 0, 0, 114, 775, 1, 0, 0, 0, 116, 935, 1, 0, 0, 0, 118, 1044, 1, 0, 0, 0, 120, 1057, 1, 0, 0, 0, 122, 1084, 1, 0, 0, 0, 124, 1121, 1, 0, 0, 0, 126, 1134, 1, 0, 0, 0, 128, 1136, 1, 0, 0, 0, 130, 1157, 1, 0, 0, 0, 132, 1166, 1, 0, 0, 0, 134, 1168, 1, 0, 0, 0, 136, 1185, 1, 0, 0, 0, 138, 1198, 1, 0, 0, 0, 140, 1208, 1, 0, 0, 0, 142, 1212, 1, 0, 0, 0, 144, 1223, 1, 0, 0, 0, 146, 1233, 1, 0, 0, 0, 148, 1236, 1, 0, 0, 0, 150, 1249, 1, 0, 0, 0, 152, 1251, 1, 0, 0, 0, 154, 1253, 1, 0, 0, 0, 156, 1255, 1, 0, 0, 0, 158, 1259, 1, 0, 0, 0, 160, 1264, 1, 0, 0, 0, 162, 1266, 1, 0, 0, 0, 164, 1270, 1, 0, 0, 0, 166, 1276, 1, 0, 0, 0, 168, 1278, 1, 0, 0, 0, 170, 1292, 1, 0, 0, 0, 172, 1294, 1, 0, 0, 0, 174, 1308, 1, 0, 0, 0, 176, 178, 3, 2, 1, 0, 177, 176, 1, 0, 0, 0, 178, 181, 1, 0, 0, 0, 179, 177, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 182, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 182, 183, 5, 0, 0, 1, 183, 1, 1, 0, 0, 0, 184, 187, 3, 6, 3, 0, 185, 187, 3, 10, 5, 0, 186, 184, 1, 0, 0, 0, 186, 185, 1, 0, 0, 0, 187, 3, 1, 0, 0, 0, 188, 189, 3, 116, 58, 0, 189, 5, 1, 0, 0, 0, 190, 191, 5, 52, 0, 0, 191, 195, 3, 160, 80, 0, 192, 193, 5, 115, 0, 0, 193, 194, 5, 122, 0, 0, 194, 196, 3, 4, 2, 0, 195, 192, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 202, 3, 160, 80, 0, 198, 199, 5, 116, 0, 0, 199, 201, 3, 160, 80, 0, 200, 198, 1, 0, 0, 0, 201, 204, 1, 0, 0, 0, 202, 200, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 206, 1, 0, 0, 0, 204, 202, 1, 0, 0, 0, 205, 207, 5, 116, 0, 0, 206, 205, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 9, 1, 0, 0, 0, 208, 221, 3, 12, 6, 0, 209, 221, 3, 14, 7, 0, 210, 221, 3, 18, 9, 0, 211, 221, 3, 20, 10, 0, 212, 221, 3, 22, 11, 0, 213, 221, 3, 26, 13, 0, 214, 221, 3, 24, 12, 0, 215, 221, 3, 28, 14, 0, 216, 221, 3, 30, 15, 0, 217, 221, 3, 36, 18, 0, 218, 221, 3, 32, 16, 0, 219, 221, 3, 34, 17, 0, 220, 208, 1, 0, 0, 0, 220, 209, 1, 0, 0, 0, 220, 210, 1, 0, 0, 0, 220, 211, 1, 0, 0, 0, 220, 212, 1, 0, 0, 0, 220, 213, 1, 0, 0, 0, 220, 214, 1, 0, 0, 0, 220, 215, 1, 0, 0, 0, 220, 216, 1, 0, 0, 0, 220, 217, 1, 0, 0, 0, 220, 218, 1, 0, 0, 0, 220, 219, 1, 0, 0, 0, 221, 11, 1, 0, 0, 0, 222, 224, 5, 72, 0, 0, 223, 225, 3, 4, 2, 0, 224, 223, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 227, 1, 0, 0, 0, 226, 228, 5, 150, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 13, 1, 0, 0, 0, 229, 231, 5, 84, 0, 0, 230, 232, 3, 4, 2, 0, 231, 230, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 234, 1, 0, 0, 0, 233, 235, 5, 150, 0, 0, 234, 233, 1, 0, 0, 0, 234, 235, 1, 0, 0, 0, 235, 15, 1, 0, 0, 0, 236, 245, 5, 14, 0, 0, 237, 238, 5, 130, 0, 0, 238, 241, 3, 160, 80, 0, 239, 240, 5, 115, 0, 0, 240, 242, 3, 160, 80, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 244, 5, 149, 0, 0, 244, 246, 1, 0, 0, 0, 245, 237, 1, 0, 0, 0, 245, 246, 1, 0, 0, 0, 246, 247, 1, 0, 0, 0, 247, 248, 3, 36, 18, 0, 248, 17, 1, 0, 0, 0, 249, 250, 5, 93, 0, 0, 250, 254, 3, 36, 18, 0, 251, 253, 3, 16, 8, 0, 252, 251, 1, 0, 0, 0, 253, 256, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 254, 255, 1, 0, 0, 0, 255, 259, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 257, 258, 5, 29, 0, 0, 258, 260, 3, 36, 18, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 19, 1, 0, 0, 0, 261, 262, 5, 40, 0, 0, 262, 263, 5, 130, 0, 0, 263, 264, 3, 4, 2, 0, 264, 265, 5, 149, 0, 0, 265, 268, 3, 10, 5, 0, 266, 267, 5, 25, 0, 0, 267, 269, 3, 10, 5, 0, 268, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 21, 1, 0, 0, 0, 270, 271, 5, 100, 0, 0, 271, 272, 5, 130, 0, 0, 272, 273, 3, 4, 2, 0, 273, 274, 5, 149, 0, 0, 274, 276, 3, 10, 5, 0, 275, 277, 5, 150, 0, 0, 276, 275, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 23, 1, 0, 0, 0, 278, 279, 5, 33, 0, 0, 279, 283, 5, 130, 0, 0, 280, 284, 3, 6, 3, 0, 281, 284, 3, 30, 15, 0, 282, 284, 3, 4, 2, 0, 283, 280, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 287, 5, 150, 0, 0, 286, 288, 3, 4, 2, 0, 287, 286, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 293, 5, 150, 0, 0, 290, 294, 3, 6, 3, 0, 291, 294, 3, 30, 15, 0, 292, 294, 3, 4, 2, 0, 293, 290, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 293, 292, 1, 0, 0, 0, 293, 294, 1, 0, 0, 0, 294, 295, 1, 0, 0, 0, 295, 296, 5, 149, 0, 0, 296, 298, 3, 10, 5, 0, 297, 299, 5, 150, 0, 0, 298, 297, 1, 0, 0, 0, 298, 299, 1, 0, 0, 0, 299, 25, 1, 0, 0, 0, 300, 301, 5, 33, 0, 0, 301, 302, 5, 130, 0, 0, 302, 303, 5, 52, 0, 0, 303, 306, 3, 160, 80, 0, 304, 305, 5, 116, 0, 0, 305, 307, 3, 160, 80, 0, 306, 304, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 309, 5, 42, 0, 0, 309, 310, 3, 4, 2, 0, 310, 311, 5, 149, 0, 0, 311, 313, 3, 10, 5, 0, 312, 314, 5, 150, 0, 0, 313, 312, 1, 0, 0, 0, 313, 314, 1, 0, 0, 0, 314, 27, 1, 0, 0, 0, 315, 316, 5, 31, 0, 0, 316, 317, 3, 160, 80, 0, 317, 319, 5, 130, 0, 0, 318, 320, 3, 8, 4, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 149, 0, 0, 322, 323, 3, 36, 18, 0, 323, 29, 1, 0, 0, 0, 324, 325, 3, 4, 2, 0, 325, 326, 5, 115, 0, 0, 326, 327, 5, 122, 0, 0, 327, 328, 3, 4, 2, 0, 328, 31, 1, 0, 0, 0, 329, 331, 3, 4, 2, 0, 330, 332, 5, 150, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 33, 1, 0, 0, 0, 333, 334, 5, 150, 0, 0, 334, 35, 1, 0, 0, 0, 335, 339, 5, 128, 0, 0, 336, 338, 3, 2, 1, 0, 337, 336, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 342, 1, 0, 0, 0, 341, 339, 1, 0, 0, 0, 342, 343, 5, 147, 0, 0, 343, 37, 1, 0, 0, 0, 344, 345, 3, 4, 2, 0, 345, 346, 5, 115, 0, 0, 346, 347, 3, 4, 2, 0, 347, 39, 1, 0, 0, 0, 348, 353, 3, 38, 19, 0, 349, 350, 5, 116, 0, 0, 350, 352, 3, 38, 19, 0, 351, 349, 1, 0, 0, 0, 352, 355, 1, 0, 0, 0, 353, 351, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 356, 358, 5, 116, 0, 0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 41, 1, 0, 0, 0, 359, 363, 3, 44, 22, 0, 360, 363, 3, 48, 24, 0, 361, 363, 3, 124, 62, 0, 362, 359, 1, 0, 0, 0, 362, 360, 1, 0, 0, 0, 362, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 365, 5, 0, 0, 1, 365, 43, 1, 0, 0, 0, 366, 372, 3, 46, 23, 0, 367, 368, 5, 95, 0, 0, 368, 369, 5, 1, 0, 0, 369, 371, 3, 46, 23, 0, 370, 367, 1, 0, 0, 0, 371, 374, 1, 0, 0, 0, 372, 370, 1, 0, 0, 0, 372, 373, 1, 0, 0, 0, 373, 45, 1, 0, 0, 0, 374, 372, 1, 0, 0, 0, 375, 382, 3, 48, 24, 0, 376, 377, 5, 130, 0, 0, 377, 378, 3, 44, 22, 0, 378, 379, 5, 149, 0, 0, 379, 382, 1, 0, 0, 0, 380, 382, 3, 164, 82, 0, 381, 375, 1, 0, 0, 0, 381, 376, 1, 0, 0, 0, 381, 380, 1, 0, 0, 0, 382, 47, 1, 0, 0, 0, 383, 385, 3, 50, 25, 0, 384, 383, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 388, 5, 79, 0, 0, 387, 389, 5, 24, 0, 0, 388, 387, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 391, 1, 0, 0, 0, 390, 392, 3, 52, 26, 0, 391, 390, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 393, 1, 0, 0, 0, 393, 395, 3, 114, 57, 0, 394, 396, 3, 54, 27, 0, 395, 394, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 398, 1, 0, 0, 0, 397, 399, 3, 56, 28, 0, 398, 397, 1, 0, 0, 0, 398, 399, 1, 0, 0, 0, 399, 401, 1, 0, 0, 0, 400, 402, 3, 60, 30, 0, 401, 400, 1, 0, 0, 0, 401, 402, 1, 0, 0, 0, 402, 404, 1, 0, 0, 0, 403, 405, 3, 62, 31, 0, 404, 403, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 407, 1, 0, 0, 0, 406, 408, 3, 64, 32, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 102, 0, 0, 410, 412, 7, 0, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 102, 0, 0, 414, 416, 5, 89, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 418, 1, 0, 0, 0, 417, 419, 3, 66, 33, 0, 418, 417, 1, 0, 0, 0, 418, 419, 1, 0, 0, 0, 419, 421, 1, 0, 0, 0, 420, 422, 3, 58, 29, 0, 421, 420, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 425, 3, 68, 34, 0, 424, 423, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 428, 1, 0, 0, 0, 426, 429, 3, 72, 36, 0, 427, 429, 3, 74, 37, 0, 428, 426, 1, 0, 0, 0, 428, 427, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 431, 1, 0, 0, 0, 430, 432, 3, 76, 38, 0, 431, 430, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 49, 1, 0, 0, 0, 433, 434, 5, 102, 0, 0, 434, 435, 3, 128, 64, 0, 435, 51, 1, 0, 0, 0, 436, 437, 5, 88, 0, 0, 437, 440, 5, 108, 0, 0, 438, 439, 5, 102, 0, 0, 439, 441, 5, 85, 0, 0, 440, 438, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0, 441, 53, 1, 0, 0, 0, 442, 443, 5, 34, 0, 0, 443, 444, 3, 78, 39, 0, 444, 55, 1, 0, 0, 0, 445, 447, 7, 1, 0, 0, 446, 445, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 449, 5, 5, 0, 0, 449, 450, 5, 47, 0, 0, 450, 451, 3, 114, 57, 0, 451, 57, 1, 0, 0, 0, 452, 453, 5, 101, 0, 0, 453, 454, 3, 160, 80, 0, 454, 455, 5, 6, 0, 0, 455, 456, 5, 130, 0, 0, 456, 457, 3, 98, 49, 0, 457, 467, 5, 149, 0, 0, 458, 459, 5, 116, 0, 0, 459, 460, 3, 160, 80, 0, 460, 461, 5, 6, 0, 0, 461, 462, 5, 130, 0, 0, 462, 463, 3, 98, 49, 0, 463, 464, 5, 149, 0, 0, 464, 466, 1, 0, 0, 0, 465, 458, 1, 0, 0, 0, 466, 469, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0, 0, 0, 468, 59, 1, 0, 0, 0, 469, 467, 1, 0, 0, 0, 470, 471, 5, 69, 0, 0, 471, 472, 3, 116, 58, 0, 472, 61, 1, 0, 0, 0, 473, 474, 5, 99, 0, 0, 474, 475, 3, 116, 58, 0, 475, 63, 1, 0, 0, 0, 476, 477, 5, 36, 0, 0, 477, 484, 5, 11, 0, 0, 478, 479, 7, 0, 0, 0, 479, 480, 5, 130, 0, 0, 480, 481, 3, 114, 57, 0, 481, 482, 5, 149, 0, 0, 482, 485, 1, 0, 0, 0, 483, 485, 3, 114, 57, 0, 484, 478, 1, 0, 0, 0, 484, 483, 1, 0, 0, 0, 485, 65, 1, 0, 0, 0, 486, 487, 5, 37, 0, 0, 487, 488, 3, 116, 58, 0, 488, 67, 1, 0, 0, 0, 489, 490, 5, 64, 0, 0, 490, 491, 5, 11, 0, 0, 491, 492, 3, 88, 44, 0, 492, 69, 1, 0, 0, 0, 493, 494, 5, 64, 0, 0, 494, 495, 5, 11, 0, 0, 495, 496, 3, 114, 57, 0, 496, 71, 1, 0, 0, 0, 497, 498, 5, 54, 0, 0, 498, 501, 3, 116, 58, 0, 499, 500, 5, 116, 0, 0, 500, 502, 3, 116, 58, 0, 501, 499, 1, 0, 0, 0, 501, 502, 1, 0, 0, 0, 502, 507, 1, 0, 0, 0, 503, 504, 5, 102, 0, 0, 504, 508, 5, 85, 0, 0, 505, 506, 5, 11, 0, 0, 506, 508, 3, 114, 57, 0, 507, 503, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 527, 1, 0, 0, 0, 509, 510, 5, 54, 0, 0, 510, 513, 3, 116, 58, 0, 511, 512, 5, 102, 0, 0, 512, 514, 5, 85, 0, 0, 513, 511, 1, 0, 0, 0, 513, 514, 1, 0, 0, 0, 514, 515, 1, 0, 0, 0, 515, 516, 5, 61, 0, 0, 516, 517, 3, 116, 58, 0, 517, 527, 1, 0, 0, 0, 518, 519, 5, 54, 0, 0, 519, 520, 3, 116, 58, 0, 520, 521, 5, 61, 0, 0, 521, 524, 3, 116, 58, 0, 522, 523, 5, 11, 0, 0, 523, 525, 3, 114, 57, 0, 524, 522, 1, 0, 0, 0, 524, 525, 1, 0, 0, 0, 525, 527, 1, 0, 0, 0, 526, 497, 1, 0, 0, 0, 526, 509, 1, 0, 0, 0, 526, 518, 1, 0, 0, 0, 527, 73, 1, 0, 0, 0, 528, 529, 5, 61, 0, 0, 529, 530, 3, 116, 58, 0, 530, 75, 1, 0, 0, 0, 531, 532, 5, 81, 0, 0, 532, 533, 3, 94, 47, 0, 533, 77, 1, 0, 0, 0, 534, 535, 6, 39, -1, 0, 535, 537, 3, 136, 68, 0, 536, 538, 5, 28, 0, 0, 537, 536, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 540, 1, 0, 0, 0, 539, 541, 3, 86, 43, 0, 540, 539, 1, 0, 0, 0, 540, 541, 1, 0, 0, 0, 541, 547, 1, 0, 0, 0, 542, 543, 5, 130, 0, 0, 543, 544, 3, 78, 39, 0, 544, 545, 5, 149, 0, 0, 545, 547, 1, 0, 0, 0, 546, 534, 1, 0, 0, 0, 546, 542, 1, 0, 0, 0, 547, 562, 1, 0, 0, 0, 548, 549, 10, 3, 0, 0, 549, 550, 3, 82, 41, 0, 550, 551, 3, 78, 39, 4, 551, 561, 1, 0, 0, 0, 552, 554, 10, 4, 0, 0, 553, 555, 3, 80, 40, 0, 554, 553, 1, 0, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 5, 47, 0, 0, 557, 558, 3, 78, 39, 0, 558, 559, 3, 84, 42, 0, 559, 561, 1, 0, 0, 0, 560, 548, 1, 0, 0, 0, 560, 552, 1, 0, 0, 0, 561, 564, 1, 0, 0, 0, 562, 560, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 79, 1, 0, 0, 0, 564, 562, 1, 0, 0, 0, 565, 567, 7, 2, 0, 0, 566, 565, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 575, 5, 44, 0, 0, 569, 571, 5, 44, 0, 0, 570, 572, 7, 2, 0, 0, 571, 570, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 575, 1, 0, 0, 0, 573, 575, 7, 2, 0, 0, 574, 566, 1, 0, 0, 0, 574, 569, 1, 0, 0, 0, 574, 573, 1, 0, 0, 0, 575, 609, 1, 0, 0, 0, 576, 578, 7, 3, 0, 0, 577, 576, 1, 0, 0, 0, 577, 578, 1, 0, 0, 0, 578, 579, 1, 0, 0, 0, 579, 581, 7, 4, 0, 0, 580, 582, 5, 65, 0, 0, 581, 580, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 591, 1, 0, 0, 0, 583, 585, 7, 4, 0, 0, 584, 586, 5, 65, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 588, 1, 0, 0, 0, 587, 589, 7, 3, 0, 0, 588, 587, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 591, 1, 0, 0, 0, 590, 577, 1, 0, 0, 0, 590, 583, 1, 0, 0, 0, 591, 609, 1, 0, 0, 0, 592, 594, 7, 5, 0, 0, 593, 592, 1, 0, 0, 0, 593, 594, 1, 0, 0, 0, 594, 595, 1, 0, 0, 0, 595, 597, 5, 35, 0, 0, 596, 598, 5, 65, 0, 0, 597, 596, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 607, 1, 0, 0, 0, 599, 601, 5, 35, 0, 0, 600, 602, 5, 65, 0, 0, 601, 600, 1, 0, 0, 0, 601, 602, 1, 0, 0, 0, 602, 604, 1, 0, 0, 0, 603, 605, 7, 5, 0, 0, 604, 603, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 607, 1, 0, 0, 0, 606, 593, 1, 0, 0, 0, 606, 599, 1, 0, 0, 0, 607, 609, 1, 0, 0, 0, 608, 574, 1, 0, 0, 0, 608, 590, 1, 0, 0, 0, 608, 606, 1, 0, 0, 0, 609, 81, 1, 0, 0, 0, 610, 611, 5, 17, 0, 0, 611, 614, 5, 47, 0, 0, 612, 614, 5, 116, 0, 0, 613, 610, 1, 0, 0, 0, 613, 612, 1, 0, 0, 0, 614, 83, 1, 0, 0, 0, 615, 616, 5, 62, 0, 0, 616, 625, 3, 114, 57, 0, 617, 618, 5, 96, 0, 0, 618, 619, 5, 130, 0, 0, 619, 620, 3, 114, 57, 0, 620, 621, 5, 149, 0, 0, 621, 625, 1, 0, 0, 0, 622, 623, 5, 96, 0, 0, 623, 625, 3, 114, 57, 0, 624, 615, 1, 0, 0, 0, 624, 617, 1, 0, 0, 0, 624, 622, 1, 0, 0, 0, 625, 85, 1, 0, 0, 0, 626, 627, 5, 77, 0, 0, 627, 630, 3, 92, 46, 0, 628, 629, 5, 61, 0, 0, 629, 631, 3, 92, 46, 0, 630, 628, 1, 0, 0, 0, 630, 631, 1, 0, 0, 0, 631, 87, 1, 0, 0, 0, 632, 637, 3, 90, 45, 0, 633, 634, 5, 116, 0, 0, 634, 636, 3, 90, 45, 0, 635, 633, 1, 0, 0, 0, 636, 639, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 89, 1, 0, 0, 0, 639, 637, 1, 0, 0, 0, 640, 642, 3, 116, 58, 0, 641, 643, 7, 6, 0, 0, 642, 641, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 646, 1, 0, 0, 0, 644, 645, 5, 60, 0, 0, 645, 647, 7, 7, 0, 0, 646, 644, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 650, 1, 0, 0, 0, 648, 649, 5, 16, 0, 0, 649, 651, 5, 110, 0, 0, 650, 648, 1, 0, 0, 0, 650, 651, 1, 0, 0, 0, 651, 91, 1, 0, 0, 0, 652, 659, 3, 164, 82, 0, 653, 656, 3, 148, 74, 0, 654, 655, 5, 151, 0, 0, 655, 657, 3, 148, 74, 0, 656, 654, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 659, 1, 0, 0, 0, 658, 652, 1, 0, 0, 0, 658, 653, 1, 0, 0, 0, 659, 93, 1, 0, 0, 0, 660, 665, 3, 96, 48, 0, 661, 662, 5, 116, 0, 0, 662, 664, 3, 96, 48, 0, 663, 661, 1, 0, 0, 0, 664, 667, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 95, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 668, 669, 3, 160, 80, 0, 669, 670, 5, 122, 0, 0, 670, 671, 3, 150, 75, 0, 671, 97, 1, 0, 0, 0, 672, 674, 3, 100, 50, 0, 673, 672, 1, 0, 0, 0, 673, 674, 1, 0, 0, 0, 674, 676, 1, 0, 0, 0, 675, 677, 3, 102, 51, 0, 676, 675, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 679, 1, 0, 0, 0, 678, 680, 3, 104, 52, 0, 679, 678, 1, 0, 0, 0, 679, 680, 1, 0, 0, 0, 680, 99, 1, 0, 0, 0, 681, 682, 5, 67, 0, 0, 682, 683, 5, 11, 0, 0, 683, 684, 3, 114, 57, 0, 684, 101, 1, 0, 0, 0, 685, 686, 5, 64, 0, 0, 686, 687, 5, 11, 0, 0, 687, 688, 3, 88, 44, 0, 688, 103, 1, 0, 0, 0, 689, 690, 7, 8, 0, 0, 690, 691, 3, 106, 53, 0, 691, 105, 1, 0, 0, 0, 692, 699, 3, 108, 54, 0, 693, 694, 5, 9, 0, 0, 694, 695, 3, 108, 54, 0, 695, 696, 5, 2, 0, 0, 696, 697, 3, 108, 54, 0, 697, 699, 1, 0, 0, 0, 698, 692, 1, 0, 0, 0, 698, 693, 1, 0, 0, 0, 699, 107, 1, 0, 0, 0, 700, 701, 5, 19, 0, 0, 701, 713, 5, 75, 0, 0, 702, 703, 5, 94, 0, 0, 703, 713, 5, 68, 0, 0, 704, 705, 5, 94, 0, 0, 705, 713, 5, 32, 0, 0, 706, 707, 3, 148, 74, 0, 707, 708, 5, 68, 0, 0, 708, 713, 1, 0, 0, 0, 709, 710, 3, 148, 74, 0, 710, 711, 5, 32, 0, 0, 711, 713, 1, 0, 0, 0, 712, 700, 1, 0, 0, 0, 712, 702, 1, 0, 0, 0, 712, 704, 1, 0, 0, 0, 712, 706, 1, 0, 0, 0, 712, 709, 1, 0, 0, 0, 713, 109, 1, 0, 0, 0, 714, 715, 3, 116, 58, 0, 715, 716, 5, 0, 0, 1, 716, 111, 1, 0, 0, 0, 717, 774, 3, 160, 80, 0, 718, 719, 3, 160, 80, 0, 719, 720, 5, 130, 0, 0, 720, 721, 3, 160, 80, 0, 721, 728, 3, 112, 56, 0, 722, 723, 5, 116, 0, 0, 723, 724, 3, 160, 80, 0, 724, 725, 3, 112, 56, 0, 725, 727, 1, 0, 0, 0, 726, 722, 1, 0, 0, 0, 727, 730, 1, 0, 0, 0, 728, 726, 1, 0, 0, 0, 728, 729, 1, 0, 0, 0, 729, 732, 1, 0, 0, 0, 730, 728, 1, 0, 0, 0, 731, 733, 5, 116, 0, 0, 732, 731, 1, 0, 0, 0, 732, 733, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 5, 149, 0, 0, 735, 774, 1, 0, 0, 0, 736, 737, 3, 160, 80, 0, 737, 738, 5, 130, 0, 0, 738, 743, 3, 162, 81, 0, 739, 740, 5, 116, 0, 0, 740, 742, 3, 162, 81, 0, 741, 739, 1, 0, 0, 0, 742, 745, 1, 0, 0, 0, 743, 741, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 747, 1, 0, 0, 0, 745, 743, 1, 0, 0, 0, 746, 748, 5, 116, 0, 0, 747, 746, 1, 0, 0, 0, 747, 748, 1, 0, 0, 0, 748, 749, 1, 0, 0, 0, 749, 750, 5, 149, 0, 0, 750, 774, 1, 0, 0, 0, 751, 752, 3, 160, 80, 0, 752, 753, 5, 130, 0, 0, 753, 758, 3, 112, 56, 0, 754, 755, 5, 116, 0, 0, 755, 757, 3, 112, 56, 0, 756, 754, 1, 0, 0, 0, 757, 760, 1, 0, 0, 0, 758, 756, 1, 0, 0, 0, 758, 759, 1, 0, 0, 0, 759, 762, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 763, 5, 116, 0, 0, 762, 761, 1, 0, 0, 0, 762, 763, 1, 0, 0, 0, 763, 764, 1, 0, 0, 0, 764, 765, 5, 149, 0, 0, 765, 774, 1, 0, 0, 0, 766, 767, 3, 160, 80, 0, 767, 769, 5, 130, 0, 0, 768, 770, 3, 114, 57, 0, 769, 768, 1, 0, 0, 0, 769, 770, 1, 0, 0, 0, 770, 771, 1, 0, 0, 0, 771, 772, 5, 149, 0, 0, 772, 774, 1, 0, 0, 0, 773, 717, 1, 0, 0, 0, 773, 718, 1, 0, 0, 0, 773, 736, 1, 0, 0, 0, 773, 751, 1, 0, 0, 0, 773, 766, 1, 0, 0, 0, 774, 113, 1, 0, 0, 0, 775, 780, 3, 116, 58, 0, 776, 777, 5, 116, 0, 0, 777, 779, 3, 116, 58, 0, 778, 776, 1, 0, 0, 0, 779, 782, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 780, 781, 1, 0, 0, 0, 781, 784, 1, 0, 0, 0, 782, 780, 1, 0, 0, 0, 783, 785, 5, 116, 0, 0, 784, 783, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 115, 1, 0, 0, 0, 786, 787, 6, 58, -1, 0, 787, 789, 5, 12, 0, 0, 788, 790, 3, 116, 58, 0, 789, 788, 1, 0, 0, 0, 789, 790, 1, 0, 0, 0, 790, 796, 1, 0, 0, 0, 791, 792, 5, 98, 0, 0, 792, 793, 3, 116, 58, 0, 793, 794, 5, 83, 0, 0, 794, 795, 3, 116, 58, 0, 795, 797, 1, 0, 0, 0, 796, 791, 1, 0, 0, 0, 797, 798, 1, 0, 0, 0, 798, 796, 1, 0, 0, 0, 798, 799, 1, 0, 0, 0, 799, 802, 1, 0, 0, 0, 800, 801, 5, 25, 0, 0, 801, 803, 3, 116, 58, 0, 802, 800, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 1, 0, 0, 0, 804, 805, 5, 26, 0, 0, 805, 936, 1, 0, 0, 0, 806, 807, 5, 13, 0, 0, 807, 808, 5, 130, 0, 0, 808, 809, 3, 116, 58, 0, 809, 810, 5, 6, 0, 0, 810, 811, 3, 112, 56, 0, 811, 812, 5, 149, 0, 0, 812, 936, 1, 0, 0, 0, 813, 814, 5, 20, 0, 0, 814, 936, 5, 110, 0, 0, 815, 816, 5, 45, 0, 0, 816, 817, 3, 116, 58, 0, 817, 818, 3, 152, 76, 0, 818, 936, 1, 0, 0, 0, 819, 820, 5, 82, 0, 0, 820, 821, 5, 130, 0, 0, 821, 822, 3, 116, 58, 0, 822, 823, 5, 34, 0, 0, 823, 826, 3, 116, 58, 0, 824, 825, 5, 33, 0, 0, 825, 827, 3, 116, 58, 0, 826, 824, 1, 0, 0, 0, 826, 827, 1, 0, 0, 0, 827, 828, 1, 0, 0, 0, 828, 829, 5, 149, 0, 0, 829, 936, 1, 0, 0, 0, 830, 831, 5, 86, 0, 0, 831, 936, 5, 110, 0, 0, 832, 833, 5, 91, 0, 0, 833, 834, 5, 130, 0, 0, 834, 835, 7, 9, 0, 0, 835, 836, 3, 166, 83, 0, 836, 837, 5, 34, 0, 0, 837, 838, 3, 116, 58, 0, 838, 839, 5, 149, 0, 0, 839, 936, 1, 0, 0, 0, 840, 841, 3, 160, 80, 0, 841, 843, 5, 130, 0, 0, 842, 844, 3, 114, 57, 0, 843, 842, 1, 0, 0, 0, 843, 844, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 846, 5, 149, 0, 0, 846, 855, 1, 0, 0, 0, 847, 849, 5, 130, 0, 0, 848, 850, 5, 24, 0, 0, 849, 848, 1, 0, 0, 0, 849, 850, 1, 0, 0, 0, 850, 852, 1, 0, 0, 0, 851, 853, 3, 118, 59, 0, 852, 851, 1, 0, 0, 0, 852, 853, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854, 856, 5, 149, 0, 0, 855, 847, 1, 0, 0, 0, 855, 856, 1, 0, 0, 0, 856, 857, 1, 0, 0, 0, 857, 858, 5, 66, 0, 0, 858, 859, 5, 130, 0, 0, 859, 860, 3, 98, 49, 0, 860, 861, 5, 149, 0, 0, 861, 936, 1, 0, 0, 0, 862, 863, 3, 160, 80, 0, 863, 865, 5, 130, 0, 0, 864, 866, 3, 114, 57, 0, 865, 864, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 868, 5, 149, 0, 0, 868, 877, 1, 0, 0, 0, 869, 871, 5, 130, 0, 0, 870, 872, 5, 24, 0, 0, 871, 870, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 874, 1, 0, 0, 0, 873, 875, 3, 118, 59, 0, 874, 873, 1, 0, 0, 0, 874, 875, 1, 0, 0, 0, 875, 876, 1, 0, 0, 0, 876, 878, 5, 149, 0, 0, 877, 869, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 880, 5, 66, 0, 0, 880, 881, 3, 160, 80, 0, 881, 936, 1, 0, 0, 0, 882, 888, 3, 160, 80, 0, 883, 885, 5, 130, 0, 0, 884, 886, 3, 114, 57, 0, 885, 884, 1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 889, 5, 149, 0, 0, 888, 883, 1, 0, 0, 0, 888, 889, 1, 0, 0, 0, 889, 890, 1, 0, 0, 0, 890, 892, 5, 130, 0, 0, 891, 893, 5, 24, 0, 0, 892, 891, 1, 0, 0, 0, 892, 893, 1, 0, 0, 0, 893, 895, 1, 0, 0, 0, 894, 896, 3, 118, 59, 0, 895, 894, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 897, 1, 0, 0, 0, 897, 898, 5, 149, 0, 0, 898, 936, 1, 0, 0, 0, 899, 936, 3, 124, 62, 0, 900, 936, 3, 168, 84, 0, 901, 936, 3, 150, 75, 0, 902, 903, 5, 118, 0, 0, 903, 936, 3, 116, 58, 19, 904, 905, 5, 58, 0, 0, 905, 936, 3, 116, 58, 13, 906, 907, 3, 140, 70, 0, 907, 908, 5, 120, 0, 0, 908, 910, 1, 0, 0, 0, 909, 906, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 1, 0, 0, 0, 911, 936, 5, 112, 0, 0, 912, 913, 5, 130, 0, 0, 913, 914, 3, 44, 22, 0, 914, 915, 5, 149, 0, 0, 915, 936, 1, 0, 0, 0, 916, 917, 5, 130, 0, 0, 917, 918, 3, 116, 58, 0, 918, 919, 5, 149, 0, 0, 919, 936, 1, 0, 0, 0, 920, 921, 5, 130, 0, 0, 921, 922, 3, 114, 57, 0, 922, 923, 5, 149, 0, 0, 923, 936, 1, 0, 0, 0, 924, 926, 5, 129, 0, 0, 925, 927, 3, 114, 57, 0, 926, 925, 1, 0, 0, 0, 926, 927, 1, 0, 0, 0, 927, 928, 1, 0, 0, 0, 928, 936, 5, 148, 0, 0, 929, 931, 5, 128, 0, 0, 930, 932, 3, 40, 20, 0, 931, 930, 1, 0, 0, 0, 931, 932, 1, 0, 0, 0, 932, 933, 1, 0, 0, 0, 933, 936, 5, 147, 0, 0, 934, 936, 3, 132, 66, 0, 935, 786, 1, 0, 0, 0, 935, 806, 1, 0, 0, 0, 935, 813, 1, 0, 0, 0, 935, 815, 1, 0, 0, 0, 935, 819, 1, 0, 0, 0, 935, 830, 1, 0, 0, 0, 935, 832, 1, 0, 0, 0, 935, 840, 1, 0, 0, 0, 935, 862, 1, 0, 0, 0, 935, 882, 1, 0, 0, 0, 935, 899, 1, 0, 0, 0, 935, 900, 1, 0, 0, 0, 935, 901, 1, 0, 0, 0, 935, 902, 1, 0, 0, 0, 935, 904, 1, 0, 0, 0, 935, 909, 1, 0, 0, 0, 935, 912, 1, 0, 0, 0, 935, 916, 1, 0, 0, 0, 935, 920, 1, 0, 0, 0, 935, 924, 1, 0, 0, 0, 935, 929, 1, 0, 0, 0, 935, 934, 1, 0, 0, 0, 936, 1041, 1, 0, 0, 0, 937, 941, 10, 18, 0, 0, 938, 942, 5, 112, 0, 0, 939, 942, 5, 151, 0, 0, 940, 942, 5, 138, 0, 0, 941, 938, 1, 0, 0, 0, 941, 939, 1, 0, 0, 0, 941, 940, 1, 0, 0, 0, 942, 943, 1, 0, 0, 0, 943, 1040, 3, 116, 58, 19, 944, 948, 10, 17, 0, 0, 945, 949, 5, 139, 0, 0, 946, 949, 5, 118, 0, 0, 947, 949, 5, 117, 0, 0, 948, 945, 1, 0, 0, 0, 948, 946, 1, 0, 0, 0, 948, 947, 1, 0, 0, 0, 949, 950, 1, 0, 0, 0, 950, 1040, 3, 116, 58, 18, 951, 976, 10, 16, 0, 0, 952, 977, 5, 121, 0, 0, 953, 977, 5, 122, 0, 0, 954, 977, 5, 133, 0, 0, 955, 977, 5, 131, 0, 0, 956, 977, 5, 132, 0, 0, 957, 977, 5, 123, 0, 0, 958, 977, 5, 124, 0, 0, 959, 961, 5, 58, 0, 0, 960, 959, 1, 0, 0, 0, 960, 961, 1, 0, 0, 0, 961, 962, 1, 0, 0, 0, 962, 964, 5, 42, 0, 0, 963, 965, 5, 15, 0, 0, 964, 963, 1, 0, 0, 0, 964, 965, 1, 0, 0, 0, 965, 977, 1, 0, 0, 0, 966, 968, 5, 58, 0, 0, 967, 966, 1, 0, 0, 0, 967, 968, 1, 0, 0, 0, 968, 969, 1, 0, 0, 0, 969, 977, 7, 10, 0, 0, 970, 977, 5, 145, 0, 0, 971, 977, 5, 146, 0, 0, 972, 977, 5, 135, 0, 0, 973, 977, 5, 126, 0, 0, 974, 977, 5, 127, 0, 0, 975, 977, 5, 134, 0, 0, 976, 952, 1, 0, 0, 0, 976, 953, 1, 0, 0, 0, 976, 954, 1, 0, 0, 0, 976, 955, 1, 0, 0, 0, 976, 956, 1, 0, 0, 0, 976, 957, 1, 0, 0, 0, 976, 958, 1, 0, 0, 0, 976, 960, 1, 0, 0, 0, 976, 967, 1, 0, 0, 0, 976, 970, 1, 0, 0, 0, 976, 971, 1, 0, 0, 0, 976, 972, 1, 0, 0, 0, 976, 973, 1, 0, 0, 0, 976, 974, 1, 0, 0, 0, 976, 975, 1, 0, 0, 0, 977, 978, 1, 0, 0, 0, 978, 1040, 3, 116, 58, 17, 979, 980, 10, 14, 0, 0, 980, 981, 5, 137, 0, 0, 981, 1040, 3, 116, 58, 15, 982, 983, 10, 12, 0, 0, 983, 984, 5, 2, 0, 0, 984, 1040, 3, 116, 58, 13, 985, 986, 10, 11, 0, 0, 986, 987, 5, 63, 0, 0, 987, 1040, 3, 116, 58, 12, 988, 990, 10, 10, 0, 0, 989, 991, 5, 58, 0, 0, 990, 989, 1, 0, 0, 0, 990, 991, 1, 0, 0, 0, 991, 992, 1, 0, 0, 0, 992, 993, 5, 9, 0, 0, 993, 994, 3, 116, 58, 0, 994, 995, 5, 2, 0, 0, 995, 996, 3, 116, 58, 11, 996, 1040, 1, 0, 0, 0, 997, 998, 10, 9, 0, 0, 998, 999, 5, 140, 0, 0, 999, 1000, 3, 116, 58, 0, 1000, 1001, 5, 115, 0, 0, 1001, 1002, 3, 116, 58, 9, 1002, 1040, 1, 0, 0, 0, 1003, 1004, 10, 25, 0, 0, 1004, 1005, 5, 129, 0, 0, 1005, 1006, 3, 116, 58, 0, 1006, 1007, 5, 148, 0, 0, 1007, 1040, 1, 0, 0, 0, 1008, 1009, 10, 24, 0, 0, 1009, 1010, 5, 120, 0, 0, 1010, 1040, 5, 108, 0, 0, 1011, 1012, 10, 23, 0, 0, 1012, 1013, 5, 120, 0, 0, 1013, 1040, 3, 160, 80, 0, 1014, 1015, 10, 22, 0, 0, 1015, 1016, 5, 136, 0, 0, 1016, 1017, 5, 129, 0, 0, 1017, 1018, 3, 116, 58, 0, 1018, 1019, 5, 148, 0, 0, 1019, 1040, 1, 0, 0, 0, 1020, 1021, 10, 21, 0, 0, 1021, 1022, 5, 136, 0, 0, 1022, 1040, 5, 108, 0, 0, 1023, 1024, 10, 20, 0, 0, 1024, 1025, 5, 136, 0, 0, 1025, 1040, 3, 160, 80, 0, 1026, 1027, 10, 15, 0, 0, 1027, 1029, 5, 46, 0, 0, 1028, 1030, 5, 58, 0, 0, 1029, 1028, 1, 0, 0, 0, 1029, 1030, 1, 0, 0, 0, 1030, 1031, 1, 0, 0, 0, 1031, 1040, 5, 59, 0, 0, 1032, 1037, 10, 8, 0, 0, 1033, 1034, 5, 6, 0, 0, 1034, 1038, 3, 160, 80, 0, 1035, 1036, 5, 6, 0, 0, 1036, 1038, 5, 110, 0, 0, 1037, 1033, 1, 0, 0, 0, 1037, 1035, 1, 0, 0, 0, 1038, 1040, 1, 0, 0, 0, 1039, 937, 1, 0, 0, 0, 1039, 944, 1, 0, 0, 0, 1039, 951, 1, 0, 0, 0, 1039, 979, 1, 0, 0, 0, 1039, 982, 1, 0, 0, 0, 1039, 985, 1, 0, 0, 0, 1039, 988, 1, 0, 0, 0, 1039, 997, 1, 0, 0, 0, 1039, 1003, 1, 0, 0, 0, 1039, 1008, 1, 0, 0, 0, 1039, 1011, 1, 0, 0, 0, 1039, 1014, 1, 0, 0, 0, 1039, 1020, 1, 0, 0, 0, 1039, 1023, 1, 0, 0, 0, 1039, 1026, 1, 0, 0, 0, 1039, 1032, 1, 0, 0, 0, 1040, 1043, 1, 0, 0, 0, 1041, 1039, 1, 0, 0, 0, 1041, 1042, 1, 0, 0, 0, 1042, 117, 1, 0, 0, 0, 1043, 1041, 1, 0, 0, 0, 1044, 1049, 3, 120, 60, 0, 1045, 1046, 5, 116, 0, 0, 1046, 1048, 3, 120, 60, 0, 1047, 1045, 1, 0, 0, 0, 1048, 1051, 1, 0, 0, 0, 1049, 1047, 1, 0, 0, 0, 1049, 1050, 1, 0, 0, 0, 1050, 1053, 1, 0, 0, 0, 1051, 1049, 1, 0, 0, 0, 1052, 1054, 5, 116, 0, 0, 1053, 1052, 1, 0, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 119, 1, 0, 0, 0, 1055, 1058, 3, 122, 61, 0, 1056, 1058, 3, 116, 58, 0, 1057, 1055, 1, 0, 0, 0, 1057, 1056, 1, 0, 0, 0, 1058, 121, 1, 0, 0, 0, 1059, 1060, 5, 130, 0, 0, 1060, 1065, 3, 160, 80, 0, 1061, 1062, 5, 116, 0, 0, 1062, 1064, 3, 160, 80, 0, 1063, 1061, 1, 0, 0, 0, 1064, 1067, 1, 0, 0, 0, 1065, 1063, 1, 0, 0, 0, 1065, 1066, 1, 0, 0, 0, 1066, 1069, 1, 0, 0, 0, 1067, 1065, 1, 0, 0, 0, 1068, 1070, 5, 116, 0, 0, 1069, 1068, 1, 0, 0, 0, 1069, 1070, 1, 0, 0, 0, 1070, 1071, 1, 0, 0, 0, 1071, 1072, 5, 149, 0, 0, 1072, 1085, 1, 0, 0, 0, 1073, 1078, 3, 160, 80, 0, 1074, 1075, 5, 116, 0, 0, 1075, 1077, 3, 160, 80, 0, 1076, 1074, 1, 0, 0, 0, 1077, 1080, 1, 0, 0, 0, 1078, 1076, 1, 0, 0, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1082, 1, 0, 0, 0, 1080, 1078, 1, 0, 0, 0, 1081, 1083, 5, 116, 0, 0, 1082, 1081, 1, 0, 0, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1085, 1, 0, 0, 0, 1084, 1059, 1, 0, 0, 0, 1084, 1073, 1, 0, 0, 0, 1085, 1086, 1, 0, 0, 0, 1086, 1087, 5, 111, 0, 0, 1087, 1088, 3, 116, 58, 0, 1088, 123, 1, 0, 0, 0, 1089, 1090, 5, 132, 0, 0, 1090, 1094, 3, 160, 80, 0, 1091, 1093, 3, 126, 63, 0, 1092, 1091, 1, 0, 0, 0, 1093, 1096, 1, 0, 0, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1097, 1, 0, 0, 0, 1096, 1094, 1, 0, 0, 0, 1097, 1098, 5, 151, 0, 0, 1098, 1099, 5, 124, 0, 0, 1099, 1122, 1, 0, 0, 0, 1100, 1101, 5, 132, 0, 0, 1101, 1105, 3, 160, 80, 0, 1102, 1104, 3, 126, 63, 0, 1103, 1102, 1, 0, 0, 0, 1104, 1107, 1, 0, 0, 0, 1105, 1103, 1, 0, 0, 0, 1105, 1106, 1, 0, 0, 0, 1106, 1108, 1, 0, 0, 0, 1107, 1105, 1, 0, 0, 0, 1108, 1114, 5, 124, 0, 0, 1109, 1115, 3, 124, 62, 0, 1110, 1111, 5, 128, 0, 0, 1111, 1112, 3, 116, 58, 0, 1112, 1113, 5, 147, 0, 0, 1113, 1115, 1, 0, 0, 0, 1114, 1109, 1, 0, 0, 0, 1114, 1110, 1, 0, 0, 0, 1114, 1115, 1, 0, 0, 0, 1115, 1116, 1, 0, 0, 0, 1116, 1117, 5, 132, 0, 0, 1117, 1118, 5, 151, 0, 0, 1118, 1119, 3, 160, 80, 0, 1119, 1120, 5, 124, 0, 0, 1120, 1122, 1, 0, 0, 0, 1121, 1089, 1, 0, 0, 0, 1121, 1100, 1, 0, 0, 0, 1122, 125, 1, 0, 0, 0, 1123, 1124, 3, 160, 80, 0, 1124, 1125, 5, 122, 0, 0, 1125, 1126, 3, 166, 83, 0, 1126, 1135, 1, 0, 0, 0, 1127, 1128, 3, 160, 80, 0, 1128, 1129, 5, 122, 0, 0, 1129, 1130, 5, 128, 0, 0, 1130, 1131, 3, 116, 58, 0, 1131, 1132, 5, 147, 0, 0, 1132, 1135, 1, 0, 0, 0, 1133, 1135, 3, 160, 80, 0, 1134, 1123, 1, 0, 0, 0, 1134, 1127, 1, 0, 0, 0, 1134, 1133, 1, 0, 0, 0, 1135, 127, 1, 0, 0, 0, 1136, 1141, 3, 130, 65, 0, 1137, 1138, 5, 116, 0, 0, 1138, 1140, 3, 130, 65, 0, 1139, 1137, 1, 0, 0, 0, 1140, 1143, 1, 0, 0, 0, 1141, 1139, 1, 0, 0, 0, 1141, 1142, 1, 0, 0, 0, 1142, 1145, 1, 0, 0, 0, 1143, 1141, 1, 0, 0, 0, 1144, 1146, 5, 116, 0, 0, 1145, 1144, 1, 0, 0, 0, 1145, 1146, 1, 0, 0, 0, 1146, 129, 1, 0, 0, 0, 1147, 1148, 3, 160, 80, 0, 1148, 1149, 5, 6, 0, 0, 1149, 1150, 5, 130, 0, 0, 1150, 1151, 3, 44, 22, 0, 1151, 1152, 5, 149, 0, 0, 1152, 1158, 1, 0, 0, 0, 1153, 1154, 3, 116, 58, 0, 1154, 1155, 5, 6, 0, 0, 1155, 1156, 3, 160, 80, 0, 1156, 1158, 1, 0, 0, 0, 1157, 1147, 1, 0, 0, 0, 1157, 1153, 1, 0, 0, 0, 1158, 131, 1, 0, 0, 0, 1159, 1167, 3, 164, 82, 0, 1160, 1161, 3, 140, 70, 0, 1161, 1162, 5, 120, 0, 0, 1162, 1164, 1, 0, 0, 0, 1163, 1160, 1, 0, 0, 0, 1163, 1164, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1167, 3, 134, 67, 0, 1166, 1159, 1, 0, 0, 0, 1166, 1163, 1, 0, 0, 0, 1167, 133, 1, 0, 0, 0, 1168, 1173, 3, 160, 80, 0, 1169, 1170, 5, 120, 0, 0, 1170, 1172, 3, 160, 80, 0, 1171, 1169, 1, 0, 0, 0, 1172, 1175, 1, 0, 0, 0, 1173, 1171, 1, 0, 0, 0, 1173, 1174, 1, 0, 0, 0, 1174, 135, 1, 0, 0, 0, 1175, 1173, 1, 0, 0, 0, 1176, 1177, 6, 68, -1, 0, 1177, 1186, 3, 140, 70, 0, 1178, 1186, 3, 138, 69, 0, 1179, 1180, 5, 130, 0, 0, 1180, 1181, 3, 44, 22, 0, 1181, 1182, 5, 149, 0, 0, 1182, 1186, 1, 0, 0, 0, 1183, 1186, 3, 124, 62, 0, 1184, 1186, 3, 164, 82, 0, 1185, 1176, 1, 0, 0, 0, 1185, 1178, 1, 0, 0, 0, 1185, 1179, 1, 0, 0, 0, 1185, 1183, 1, 0, 0, 0, 1185, 1184, 1, 0, 0, 0, 1186, 1195, 1, 0, 0, 0, 1187, 1191, 10, 3, 0, 0, 1188, 1192, 3, 158, 79, 0, 1189, 1190, 5, 6, 0, 0, 1190, 1192, 3, 160, 80, 0, 1191, 1188, 1, 0, 0, 0, 1191, 1189, 1, 0, 0, 0, 1192, 1194, 1, 0, 0, 0, 1193, 1187, 1, 0, 0, 0, 1194, 1197, 1, 0, 0, 0, 1195, 1193, 1, 0, 0, 0, 1195, 1196, 1, 0, 0, 0, 1196, 137, 1, 0, 0, 0, 1197, 1195, 1, 0, 0, 0, 1198, 1199, 3, 160, 80, 0, 1199, 1201, 5, 130, 0, 0, 1200, 1202, 3, 142, 71, 0, 1201, 1200, 1, 0, 0, 0, 1201, 1202, 1, 0, 0, 0, 1202, 1203, 1, 0, 0, 0, 1203, 1204, 5, 149, 0, 0, 1204, 139, 1, 0, 0, 0, 1205, 1206, 3, 144, 72, 0, 1206, 1207, 5, 120, 0, 0, 1207, 1209, 1, 0, 0, 0, 1208, 1205, 1, 0, 0, 0, 1208, 1209, 1, 0, 0, 0, 1209, 1210, 1, 0, 0, 0, 1210, 1211, 3, 160, 80, 0, 1211, 141, 1, 0, 0, 0, 1212, 1217, 3, 116, 58, 0, 1213, 1214, 5, 116, 0, 0, 1214, 1216, 3, 116, 58, 0, 1215, 1213, 1, 0, 0, 0, 1216, 1219, 1, 0, 0, 0, 1217, 1215, 1, 0, 0, 0, 1217, 1218, 1, 0, 0, 0, 1218, 1221, 1, 0, 0, 0, 1219, 1217, 1, 0, 0, 0, 1220, 1222, 5, 116, 0, 0, 1221, 1220, 1, 0, 0, 0, 1221, 1222, 1, 0, 0, 0, 1222, 143, 1, 0, 0, 0, 1223, 1224, 3, 160, 80, 0, 1224, 145, 1, 0, 0, 0, 1225, 1234, 5, 106, 0, 0, 1226, 1227, 5, 120, 0, 0, 1227, 1234, 7, 11, 0, 0, 1228, 1229, 5, 108, 0, 0, 1229, 1231, 5, 120, 0, 0, 1230, 1232, 7, 11, 0, 0, 1231, 1230, 1, 0, 0, 0, 1231, 1232, 1, 0, 0, 0, 1232, 1234, 1, 0, 0, 0, 1233, 1225, 1, 0, 0, 0, 1233, 1226, 1, 0, 0, 0, 1233, 1228, 1, 0, 0, 0, 1234, 147, 1, 0, 0, 0, 1235, 1237, 7, 12, 0, 0, 1236, 1235, 1, 0, 0, 0, 1236, 1237, 1, 0, 0, 0, 1237, 1244, 1, 0, 0, 0, 1238, 1245, 3, 146, 73, 0, 1239, 1245, 5, 107, 0, 0, 1240, 1245, 5, 108, 0, 0, 1241, 1245, 5, 109, 0, 0, 1242, 1245, 5, 43, 0, 0, 1243, 1245, 5, 57, 0, 0, 1244, 1238, 1, 0, 0, 0, 1244, 1239, 1, 0, 0, 0, 1244, 1240, 1, 0, 0, 0, 1244, 1241, 1, 0, 0, 0, 1244, 1242, 1, 0, 0, 0, 1244, 1243, 1, 0, 0, 0, 1245, 149, 1, 0, 0, 0, 1246, 1250, 3, 148, 74, 0, 1247, 1250, 5, 110, 0, 0, 1248, 1250, 5, 59, 0, 0, 1249, 1246, 1, 0, 0, 0, 1249, 1247, 1, 0, 0, 0, 1249, 1248, 1, 0, 0, 0, 1250, 151, 1, 0, 0, 0, 1251, 1252, 7, 13, 0, 0, 1252, 153, 1, 0, 0, 0, 1253, 1254, 7, 14, 0, 0, 1254, 155, 1, 0, 0, 0, 1255, 1256, 7, 15, 0, 0, 1256, 157, 1, 0, 0, 0, 1257, 1260, 5, 105, 0, 0, 1258, 1260, 3, 156, 78, 0, 1259, 1257, 1, 0, 0, 0, 1259, 1258, 1, 0, 0, 0, 1260, 159, 1, 0, 0, 0, 1261, 1265, 5, 105, 0, 0, 1262, 1265, 3, 152, 76, 0, 1263, 1265, 3, 154, 77, 0, 1264, 1261, 1, 0, 0, 0, 1264, 1262, 1, 0, 0, 0, 1264, 1263, 1, 0, 0, 0, 1265, 161, 1, 0, 0, 0, 1266, 1267, 3, 166, 83, 0, 1267, 1268, 5, 122, 0, 0, 1268, 1269, 3, 148, 74, 0, 1269, 163, 1, 0, 0, 0, 1270, 1271, 5, 128, 0, 0, 1271, 1272, 3, 160, 80, 0, 1272, 1273, 5, 147, 0, 0, 1273, 165, 1, 0, 0, 0, 1274, 1277, 5, 110, 0, 0, 1275, 1277, 3, 168, 84, 0, 1276, 1274, 1, 0, 0, 0, 1276, 1275, 1, 0, 0, 0, 1277, 167, 1, 0, 0, 0, 1278, 1282, 5, 142, 0, 0, 1279, 1281, 3, 170, 85, 0, 1280, 1279, 1, 0, 0, 0, 1281, 1284, 1, 0, 0, 0, 1282, 1280, 1, 0, 0, 0, 1282, 1283, 1, 0, 0, 0, 1283, 1285, 1, 0, 0, 0, 1284, 1282, 1, 0, 0, 0, 1285, 1286, 5, 144, 0, 0, 1286, 169, 1, 0, 0, 0, 1287, 1288, 5, 157, 0, 0, 1288, 1289, 3, 116, 58, 0, 1289, 1290, 5, 147, 0, 0, 1290, 1293, 1, 0, 0, 0, 1291, 1293, 5, 156, 0, 0, 1292, 1287, 1, 0, 0, 0, 1292, 1291, 1, 0, 0, 0, 1293, 171, 1, 0, 0, 0, 1294, 1298, 5, 143, 0, 0, 1295, 1297, 3, 174, 87, 0, 1296, 1295, 1, 0, 0, 0, 1297, 1300, 1, 0, 0, 0, 1298, 1296, 1, 0, 0, 0, 1298, 1299, 1, 0, 0, 0, 1299, 1301, 1, 0, 0, 0, 1300, 1298, 1, 0, 0, 0, 1301, 1302, 5, 0, 0, 1, 1302, 173, 1, 0, 0, 0, 1303, 1304, 5, 159, 0, 0, 1304, 1305, 3, 116, 58, 0, 1305, 1306, 5, 147, 0, 0, 1306, 1309, 1, 0, 0, 0, 1307, 1309, 5, 158, 0, 0, 1308, 1303, 1, 0, 0, 0, 1308, 1307, 1, 0, 0, 0, 1309, 175, 1, 0, 0, 0, 168, 179, 186, 195, 202, 206, 220, 224, 227, 231, 234, 241, 245, 254, 259, 268, 276, 283, 287, 293, 298, 306, 313, 319, 331, 339, 353, 357, 362, 372, 381, 384, 388, 391, 395, 398, 401, 404, 407, 411, 415, 418, 421, 424, 428, 431, 440, 446, 467, 484, 501, 507, 513, 524, 526, 537, 540, 546, 554, 560, 562, 566, 571, 574, 577, 581, 585, 588, 590, 593, 597, 601, 604, 606, 608, 613, 624, 630, 637, 642, 646, 650, 656, 658, 665, 673, 676, 679, 698, 712, 728, 732, 743, 747, 758, 762, 769, 773, 780, 784, 789, 798, 802, 826, 843, 849, 852, 855, 865, 871, 874, 877, 885, 888, 892, 895, 909, 926, 931, 935, 941, 948, 960, 964, 967, 976, 990, 1029, 1037, 1039, 1041, 1049, 1053, 1057, 1065, 1069, 1078, 1082, 1084, 1094, 1105, 1114, 1121, 1134, 1141, 1145, 1157, 1163, 1166, 1173, 1185, 1191, 1195, 1201, 1208, 1217, 1221, 1231, 1233, 1236, 1244, 1249, 1259, 1264, 1276, 1282, 1292, 1298, 1308] \ No newline at end of file diff --git a/posthog/hogql/grammar/HogQLParser.py b/posthog/hogql/grammar/HogQLParser.py index 719ab286bcf6d..6865c4c553220 100644 --- a/posthog/hogql/grammar/HogQLParser.py +++ b/posthog/hogql/grammar/HogQLParser.py @@ -10,7 +10,7 @@ def serializedATN(): return [ - 4,1,159,1307,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, + 4,1,159,1311,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, 7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7, 13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2, 20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7, @@ -105,143 +105,143 @@ def serializedATN(): 12,61,1080,9,61,1,61,3,61,1083,8,61,3,61,1085,8,61,1,61,1,61,1,61, 1,62,1,62,1,62,5,62,1093,8,62,10,62,12,62,1096,9,62,1,62,1,62,1, 62,1,62,1,62,1,62,5,62,1104,8,62,10,62,12,62,1107,9,62,1,62,1,62, - 3,62,1111,8,62,1,62,1,62,1,62,1,62,1,62,3,62,1118,8,62,1,63,1,63, - 1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,3,63,1131,8,63,1,64, - 1,64,1,64,5,64,1136,8,64,10,64,12,64,1139,9,64,1,64,3,64,1142,8, - 64,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,3,65,1154,8, - 65,1,66,1,66,1,66,1,66,3,66,1160,8,66,1,66,3,66,1163,8,66,1,67,1, - 67,1,67,5,67,1168,8,67,10,67,12,67,1171,9,67,1,68,1,68,1,68,1,68, - 1,68,1,68,1,68,1,68,1,68,3,68,1182,8,68,1,68,1,68,1,68,1,68,3,68, - 1188,8,68,5,68,1190,8,68,10,68,12,68,1193,9,68,1,69,1,69,1,69,3, - 69,1198,8,69,1,69,1,69,1,70,1,70,1,70,3,70,1205,8,70,1,70,1,70,1, - 71,1,71,1,71,5,71,1212,8,71,10,71,12,71,1215,9,71,1,71,3,71,1218, - 8,71,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1,73,3,73,1228,8,73,3,73, - 1230,8,73,1,74,3,74,1233,8,74,1,74,1,74,1,74,1,74,1,74,1,74,3,74, - 1241,8,74,1,75,1,75,1,75,3,75,1246,8,75,1,76,1,76,1,77,1,77,1,78, - 1,78,1,79,1,79,3,79,1256,8,79,1,80,1,80,1,80,3,80,1261,8,80,1,81, - 1,81,1,81,1,81,1,82,1,82,1,82,1,82,1,83,1,83,3,83,1273,8,83,1,84, - 1,84,5,84,1277,8,84,10,84,12,84,1280,9,84,1,84,1,84,1,85,1,85,1, - 85,1,85,1,85,3,85,1289,8,85,1,86,1,86,5,86,1293,8,86,10,86,12,86, - 1296,9,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87,3,87,1305,8,87,1,87, - 0,3,78,116,136,88,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32, - 34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76, - 78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114, - 116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146, - 148,150,152,154,156,158,160,162,164,166,168,170,172,174,0,16,2,0, - 18,18,74,74,2,0,44,44,51,51,3,0,1,1,4,4,8,8,4,0,1,1,3,4,8,8,80,80, - 2,0,51,51,73,73,2,0,1,1,4,4,2,0,7,7,22,23,2,0,30,30,49,49,2,0,71, - 71,76,76,3,0,10,10,50,50,90,90,2,0,41,41,53,53,1,0,107,108,2,0,118, - 118,139,139,7,0,21,21,38,38,55,56,70,70,78,78,97,97,103,103,16,0, - 1,13,15,20,22,28,30,30,32,37,39,42,44,51,53,54,58,58,60,69,71,77, - 79,83,85,92,94,96,98,99,101,102,4,0,20,20,30,30,39,39,48,48,1474, - 0,179,1,0,0,0,2,186,1,0,0,0,4,188,1,0,0,0,6,190,1,0,0,0,8,197,1, - 0,0,0,10,220,1,0,0,0,12,222,1,0,0,0,14,229,1,0,0,0,16,236,1,0,0, - 0,18,249,1,0,0,0,20,261,1,0,0,0,22,270,1,0,0,0,24,278,1,0,0,0,26, - 300,1,0,0,0,28,315,1,0,0,0,30,324,1,0,0,0,32,329,1,0,0,0,34,333, - 1,0,0,0,36,335,1,0,0,0,38,344,1,0,0,0,40,348,1,0,0,0,42,362,1,0, - 0,0,44,366,1,0,0,0,46,381,1,0,0,0,48,384,1,0,0,0,50,433,1,0,0,0, - 52,436,1,0,0,0,54,442,1,0,0,0,56,446,1,0,0,0,58,452,1,0,0,0,60,470, - 1,0,0,0,62,473,1,0,0,0,64,476,1,0,0,0,66,486,1,0,0,0,68,489,1,0, - 0,0,70,493,1,0,0,0,72,526,1,0,0,0,74,528,1,0,0,0,76,531,1,0,0,0, - 78,546,1,0,0,0,80,608,1,0,0,0,82,613,1,0,0,0,84,624,1,0,0,0,86,626, - 1,0,0,0,88,632,1,0,0,0,90,640,1,0,0,0,92,658,1,0,0,0,94,660,1,0, - 0,0,96,668,1,0,0,0,98,673,1,0,0,0,100,681,1,0,0,0,102,685,1,0,0, - 0,104,689,1,0,0,0,106,698,1,0,0,0,108,712,1,0,0,0,110,714,1,0,0, - 0,112,773,1,0,0,0,114,775,1,0,0,0,116,935,1,0,0,0,118,1044,1,0,0, - 0,120,1057,1,0,0,0,122,1084,1,0,0,0,124,1117,1,0,0,0,126,1130,1, - 0,0,0,128,1132,1,0,0,0,130,1153,1,0,0,0,132,1162,1,0,0,0,134,1164, - 1,0,0,0,136,1181,1,0,0,0,138,1194,1,0,0,0,140,1204,1,0,0,0,142,1208, - 1,0,0,0,144,1219,1,0,0,0,146,1229,1,0,0,0,148,1232,1,0,0,0,150,1245, - 1,0,0,0,152,1247,1,0,0,0,154,1249,1,0,0,0,156,1251,1,0,0,0,158,1255, - 1,0,0,0,160,1260,1,0,0,0,162,1262,1,0,0,0,164,1266,1,0,0,0,166,1272, - 1,0,0,0,168,1274,1,0,0,0,170,1288,1,0,0,0,172,1290,1,0,0,0,174,1304, - 1,0,0,0,176,178,3,2,1,0,177,176,1,0,0,0,178,181,1,0,0,0,179,177, - 1,0,0,0,179,180,1,0,0,0,180,182,1,0,0,0,181,179,1,0,0,0,182,183, - 5,0,0,1,183,1,1,0,0,0,184,187,3,6,3,0,185,187,3,10,5,0,186,184,1, - 0,0,0,186,185,1,0,0,0,187,3,1,0,0,0,188,189,3,116,58,0,189,5,1,0, - 0,0,190,191,5,52,0,0,191,195,3,160,80,0,192,193,5,115,0,0,193,194, - 5,122,0,0,194,196,3,4,2,0,195,192,1,0,0,0,195,196,1,0,0,0,196,7, - 1,0,0,0,197,202,3,160,80,0,198,199,5,116,0,0,199,201,3,160,80,0, - 200,198,1,0,0,0,201,204,1,0,0,0,202,200,1,0,0,0,202,203,1,0,0,0, - 203,206,1,0,0,0,204,202,1,0,0,0,205,207,5,116,0,0,206,205,1,0,0, - 0,206,207,1,0,0,0,207,9,1,0,0,0,208,221,3,12,6,0,209,221,3,14,7, - 0,210,221,3,18,9,0,211,221,3,20,10,0,212,221,3,22,11,0,213,221,3, - 26,13,0,214,221,3,24,12,0,215,221,3,28,14,0,216,221,3,30,15,0,217, - 221,3,36,18,0,218,221,3,32,16,0,219,221,3,34,17,0,220,208,1,0,0, - 0,220,209,1,0,0,0,220,210,1,0,0,0,220,211,1,0,0,0,220,212,1,0,0, - 0,220,213,1,0,0,0,220,214,1,0,0,0,220,215,1,0,0,0,220,216,1,0,0, - 0,220,217,1,0,0,0,220,218,1,0,0,0,220,219,1,0,0,0,221,11,1,0,0,0, - 222,224,5,72,0,0,223,225,3,4,2,0,224,223,1,0,0,0,224,225,1,0,0,0, - 225,227,1,0,0,0,226,228,5,150,0,0,227,226,1,0,0,0,227,228,1,0,0, - 0,228,13,1,0,0,0,229,231,5,84,0,0,230,232,3,4,2,0,231,230,1,0,0, - 0,231,232,1,0,0,0,232,234,1,0,0,0,233,235,5,150,0,0,234,233,1,0, - 0,0,234,235,1,0,0,0,235,15,1,0,0,0,236,245,5,14,0,0,237,238,5,130, - 0,0,238,241,3,160,80,0,239,240,5,115,0,0,240,242,3,160,80,0,241, - 239,1,0,0,0,241,242,1,0,0,0,242,243,1,0,0,0,243,244,5,149,0,0,244, - 246,1,0,0,0,245,237,1,0,0,0,245,246,1,0,0,0,246,247,1,0,0,0,247, - 248,3,36,18,0,248,17,1,0,0,0,249,250,5,93,0,0,250,254,3,36,18,0, - 251,253,3,16,8,0,252,251,1,0,0,0,253,256,1,0,0,0,254,252,1,0,0,0, - 254,255,1,0,0,0,255,259,1,0,0,0,256,254,1,0,0,0,257,258,5,29,0,0, - 258,260,3,36,18,0,259,257,1,0,0,0,259,260,1,0,0,0,260,19,1,0,0,0, - 261,262,5,40,0,0,262,263,5,130,0,0,263,264,3,4,2,0,264,265,5,149, - 0,0,265,268,3,10,5,0,266,267,5,25,0,0,267,269,3,10,5,0,268,266,1, - 0,0,0,268,269,1,0,0,0,269,21,1,0,0,0,270,271,5,100,0,0,271,272,5, - 130,0,0,272,273,3,4,2,0,273,274,5,149,0,0,274,276,3,10,5,0,275,277, - 5,150,0,0,276,275,1,0,0,0,276,277,1,0,0,0,277,23,1,0,0,0,278,279, - 5,33,0,0,279,283,5,130,0,0,280,284,3,6,3,0,281,284,3,30,15,0,282, - 284,3,4,2,0,283,280,1,0,0,0,283,281,1,0,0,0,283,282,1,0,0,0,283, - 284,1,0,0,0,284,285,1,0,0,0,285,287,5,150,0,0,286,288,3,4,2,0,287, - 286,1,0,0,0,287,288,1,0,0,0,288,289,1,0,0,0,289,293,5,150,0,0,290, - 294,3,6,3,0,291,294,3,30,15,0,292,294,3,4,2,0,293,290,1,0,0,0,293, - 291,1,0,0,0,293,292,1,0,0,0,293,294,1,0,0,0,294,295,1,0,0,0,295, - 296,5,149,0,0,296,298,3,10,5,0,297,299,5,150,0,0,298,297,1,0,0,0, - 298,299,1,0,0,0,299,25,1,0,0,0,300,301,5,33,0,0,301,302,5,130,0, - 0,302,303,5,52,0,0,303,306,3,160,80,0,304,305,5,116,0,0,305,307, - 3,160,80,0,306,304,1,0,0,0,306,307,1,0,0,0,307,308,1,0,0,0,308,309, - 5,42,0,0,309,310,3,4,2,0,310,311,5,149,0,0,311,313,3,10,5,0,312, - 314,5,150,0,0,313,312,1,0,0,0,313,314,1,0,0,0,314,27,1,0,0,0,315, - 316,5,31,0,0,316,317,3,160,80,0,317,319,5,130,0,0,318,320,3,8,4, - 0,319,318,1,0,0,0,319,320,1,0,0,0,320,321,1,0,0,0,321,322,5,149, - 0,0,322,323,3,36,18,0,323,29,1,0,0,0,324,325,3,4,2,0,325,326,5,115, - 0,0,326,327,5,122,0,0,327,328,3,4,2,0,328,31,1,0,0,0,329,331,3,4, - 2,0,330,332,5,150,0,0,331,330,1,0,0,0,331,332,1,0,0,0,332,33,1,0, - 0,0,333,334,5,150,0,0,334,35,1,0,0,0,335,339,5,128,0,0,336,338,3, - 2,1,0,337,336,1,0,0,0,338,341,1,0,0,0,339,337,1,0,0,0,339,340,1, - 0,0,0,340,342,1,0,0,0,341,339,1,0,0,0,342,343,5,147,0,0,343,37,1, - 0,0,0,344,345,3,4,2,0,345,346,5,115,0,0,346,347,3,4,2,0,347,39,1, - 0,0,0,348,353,3,38,19,0,349,350,5,116,0,0,350,352,3,38,19,0,351, - 349,1,0,0,0,352,355,1,0,0,0,353,351,1,0,0,0,353,354,1,0,0,0,354, - 357,1,0,0,0,355,353,1,0,0,0,356,358,5,116,0,0,357,356,1,0,0,0,357, - 358,1,0,0,0,358,41,1,0,0,0,359,363,3,44,22,0,360,363,3,48,24,0,361, - 363,3,124,62,0,362,359,1,0,0,0,362,360,1,0,0,0,362,361,1,0,0,0,363, - 364,1,0,0,0,364,365,5,0,0,1,365,43,1,0,0,0,366,372,3,46,23,0,367, - 368,5,95,0,0,368,369,5,1,0,0,369,371,3,46,23,0,370,367,1,0,0,0,371, - 374,1,0,0,0,372,370,1,0,0,0,372,373,1,0,0,0,373,45,1,0,0,0,374,372, - 1,0,0,0,375,382,3,48,24,0,376,377,5,130,0,0,377,378,3,44,22,0,378, - 379,5,149,0,0,379,382,1,0,0,0,380,382,3,164,82,0,381,375,1,0,0,0, - 381,376,1,0,0,0,381,380,1,0,0,0,382,47,1,0,0,0,383,385,3,50,25,0, - 384,383,1,0,0,0,384,385,1,0,0,0,385,386,1,0,0,0,386,388,5,79,0,0, - 387,389,5,24,0,0,388,387,1,0,0,0,388,389,1,0,0,0,389,391,1,0,0,0, - 390,392,3,52,26,0,391,390,1,0,0,0,391,392,1,0,0,0,392,393,1,0,0, - 0,393,395,3,114,57,0,394,396,3,54,27,0,395,394,1,0,0,0,395,396,1, - 0,0,0,396,398,1,0,0,0,397,399,3,56,28,0,398,397,1,0,0,0,398,399, - 1,0,0,0,399,401,1,0,0,0,400,402,3,60,30,0,401,400,1,0,0,0,401,402, - 1,0,0,0,402,404,1,0,0,0,403,405,3,62,31,0,404,403,1,0,0,0,404,405, - 1,0,0,0,405,407,1,0,0,0,406,408,3,64,32,0,407,406,1,0,0,0,407,408, - 1,0,0,0,408,411,1,0,0,0,409,410,5,102,0,0,410,412,7,0,0,0,411,409, - 1,0,0,0,411,412,1,0,0,0,412,415,1,0,0,0,413,414,5,102,0,0,414,416, - 5,89,0,0,415,413,1,0,0,0,415,416,1,0,0,0,416,418,1,0,0,0,417,419, - 3,66,33,0,418,417,1,0,0,0,418,419,1,0,0,0,419,421,1,0,0,0,420,422, - 3,58,29,0,421,420,1,0,0,0,421,422,1,0,0,0,422,424,1,0,0,0,423,425, - 3,68,34,0,424,423,1,0,0,0,424,425,1,0,0,0,425,428,1,0,0,0,426,429, - 3,72,36,0,427,429,3,74,37,0,428,426,1,0,0,0,428,427,1,0,0,0,428, - 429,1,0,0,0,429,431,1,0,0,0,430,432,3,76,38,0,431,430,1,0,0,0,431, - 432,1,0,0,0,432,49,1,0,0,0,433,434,5,102,0,0,434,435,3,128,64,0, - 435,51,1,0,0,0,436,437,5,88,0,0,437,440,5,108,0,0,438,439,5,102, - 0,0,439,441,5,85,0,0,440,438,1,0,0,0,440,441,1,0,0,0,441,53,1,0, - 0,0,442,443,5,34,0,0,443,444,3,78,39,0,444,55,1,0,0,0,445,447,7, - 1,0,0,446,445,1,0,0,0,446,447,1,0,0,0,447,448,1,0,0,0,448,449,5, - 5,0,0,449,450,5,47,0,0,450,451,3,114,57,0,451,57,1,0,0,0,452,453, + 1,62,1,62,1,62,1,62,3,62,1115,8,62,1,62,1,62,1,62,1,62,1,62,3,62, + 1122,8,62,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63, + 3,63,1135,8,63,1,64,1,64,1,64,5,64,1140,8,64,10,64,12,64,1143,9, + 64,1,64,3,64,1146,8,64,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1, + 65,1,65,3,65,1158,8,65,1,66,1,66,1,66,1,66,3,66,1164,8,66,1,66,3, + 66,1167,8,66,1,67,1,67,1,67,5,67,1172,8,67,10,67,12,67,1175,9,67, + 1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,3,68,1186,8,68,1,68, + 1,68,1,68,1,68,3,68,1192,8,68,5,68,1194,8,68,10,68,12,68,1197,9, + 68,1,69,1,69,1,69,3,69,1202,8,69,1,69,1,69,1,70,1,70,1,70,3,70,1209, + 8,70,1,70,1,70,1,71,1,71,1,71,5,71,1216,8,71,10,71,12,71,1219,9, + 71,1,71,3,71,1222,8,71,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1,73,3, + 73,1232,8,73,3,73,1234,8,73,1,74,3,74,1237,8,74,1,74,1,74,1,74,1, + 74,1,74,1,74,3,74,1245,8,74,1,75,1,75,1,75,3,75,1250,8,75,1,76,1, + 76,1,77,1,77,1,78,1,78,1,79,1,79,3,79,1260,8,79,1,80,1,80,1,80,3, + 80,1265,8,80,1,81,1,81,1,81,1,81,1,82,1,82,1,82,1,82,1,83,1,83,3, + 83,1277,8,83,1,84,1,84,5,84,1281,8,84,10,84,12,84,1284,9,84,1,84, + 1,84,1,85,1,85,1,85,1,85,1,85,3,85,1293,8,85,1,86,1,86,5,86,1297, + 8,86,10,86,12,86,1300,9,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87,3, + 87,1309,8,87,1,87,0,3,78,116,136,88,0,2,4,6,8,10,12,14,16,18,20, + 22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64, + 66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106, + 108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138, + 140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170, + 172,174,0,16,2,0,18,18,74,74,2,0,44,44,51,51,3,0,1,1,4,4,8,8,4,0, + 1,1,3,4,8,8,80,80,2,0,51,51,73,73,2,0,1,1,4,4,2,0,7,7,22,23,2,0, + 30,30,49,49,2,0,71,71,76,76,3,0,10,10,50,50,90,90,2,0,41,41,53,53, + 1,0,107,108,2,0,118,118,139,139,7,0,21,21,38,38,55,56,70,70,78,78, + 97,97,103,103,16,0,1,13,15,20,22,28,30,30,32,37,39,42,44,51,53,54, + 58,58,60,69,71,77,79,83,85,92,94,96,98,99,101,102,4,0,20,20,30,30, + 39,39,48,48,1479,0,179,1,0,0,0,2,186,1,0,0,0,4,188,1,0,0,0,6,190, + 1,0,0,0,8,197,1,0,0,0,10,220,1,0,0,0,12,222,1,0,0,0,14,229,1,0,0, + 0,16,236,1,0,0,0,18,249,1,0,0,0,20,261,1,0,0,0,22,270,1,0,0,0,24, + 278,1,0,0,0,26,300,1,0,0,0,28,315,1,0,0,0,30,324,1,0,0,0,32,329, + 1,0,0,0,34,333,1,0,0,0,36,335,1,0,0,0,38,344,1,0,0,0,40,348,1,0, + 0,0,42,362,1,0,0,0,44,366,1,0,0,0,46,381,1,0,0,0,48,384,1,0,0,0, + 50,433,1,0,0,0,52,436,1,0,0,0,54,442,1,0,0,0,56,446,1,0,0,0,58,452, + 1,0,0,0,60,470,1,0,0,0,62,473,1,0,0,0,64,476,1,0,0,0,66,486,1,0, + 0,0,68,489,1,0,0,0,70,493,1,0,0,0,72,526,1,0,0,0,74,528,1,0,0,0, + 76,531,1,0,0,0,78,546,1,0,0,0,80,608,1,0,0,0,82,613,1,0,0,0,84,624, + 1,0,0,0,86,626,1,0,0,0,88,632,1,0,0,0,90,640,1,0,0,0,92,658,1,0, + 0,0,94,660,1,0,0,0,96,668,1,0,0,0,98,673,1,0,0,0,100,681,1,0,0,0, + 102,685,1,0,0,0,104,689,1,0,0,0,106,698,1,0,0,0,108,712,1,0,0,0, + 110,714,1,0,0,0,112,773,1,0,0,0,114,775,1,0,0,0,116,935,1,0,0,0, + 118,1044,1,0,0,0,120,1057,1,0,0,0,122,1084,1,0,0,0,124,1121,1,0, + 0,0,126,1134,1,0,0,0,128,1136,1,0,0,0,130,1157,1,0,0,0,132,1166, + 1,0,0,0,134,1168,1,0,0,0,136,1185,1,0,0,0,138,1198,1,0,0,0,140,1208, + 1,0,0,0,142,1212,1,0,0,0,144,1223,1,0,0,0,146,1233,1,0,0,0,148,1236, + 1,0,0,0,150,1249,1,0,0,0,152,1251,1,0,0,0,154,1253,1,0,0,0,156,1255, + 1,0,0,0,158,1259,1,0,0,0,160,1264,1,0,0,0,162,1266,1,0,0,0,164,1270, + 1,0,0,0,166,1276,1,0,0,0,168,1278,1,0,0,0,170,1292,1,0,0,0,172,1294, + 1,0,0,0,174,1308,1,0,0,0,176,178,3,2,1,0,177,176,1,0,0,0,178,181, + 1,0,0,0,179,177,1,0,0,0,179,180,1,0,0,0,180,182,1,0,0,0,181,179, + 1,0,0,0,182,183,5,0,0,1,183,1,1,0,0,0,184,187,3,6,3,0,185,187,3, + 10,5,0,186,184,1,0,0,0,186,185,1,0,0,0,187,3,1,0,0,0,188,189,3,116, + 58,0,189,5,1,0,0,0,190,191,5,52,0,0,191,195,3,160,80,0,192,193,5, + 115,0,0,193,194,5,122,0,0,194,196,3,4,2,0,195,192,1,0,0,0,195,196, + 1,0,0,0,196,7,1,0,0,0,197,202,3,160,80,0,198,199,5,116,0,0,199,201, + 3,160,80,0,200,198,1,0,0,0,201,204,1,0,0,0,202,200,1,0,0,0,202,203, + 1,0,0,0,203,206,1,0,0,0,204,202,1,0,0,0,205,207,5,116,0,0,206,205, + 1,0,0,0,206,207,1,0,0,0,207,9,1,0,0,0,208,221,3,12,6,0,209,221,3, + 14,7,0,210,221,3,18,9,0,211,221,3,20,10,0,212,221,3,22,11,0,213, + 221,3,26,13,0,214,221,3,24,12,0,215,221,3,28,14,0,216,221,3,30,15, + 0,217,221,3,36,18,0,218,221,3,32,16,0,219,221,3,34,17,0,220,208, + 1,0,0,0,220,209,1,0,0,0,220,210,1,0,0,0,220,211,1,0,0,0,220,212, + 1,0,0,0,220,213,1,0,0,0,220,214,1,0,0,0,220,215,1,0,0,0,220,216, + 1,0,0,0,220,217,1,0,0,0,220,218,1,0,0,0,220,219,1,0,0,0,221,11,1, + 0,0,0,222,224,5,72,0,0,223,225,3,4,2,0,224,223,1,0,0,0,224,225,1, + 0,0,0,225,227,1,0,0,0,226,228,5,150,0,0,227,226,1,0,0,0,227,228, + 1,0,0,0,228,13,1,0,0,0,229,231,5,84,0,0,230,232,3,4,2,0,231,230, + 1,0,0,0,231,232,1,0,0,0,232,234,1,0,0,0,233,235,5,150,0,0,234,233, + 1,0,0,0,234,235,1,0,0,0,235,15,1,0,0,0,236,245,5,14,0,0,237,238, + 5,130,0,0,238,241,3,160,80,0,239,240,5,115,0,0,240,242,3,160,80, + 0,241,239,1,0,0,0,241,242,1,0,0,0,242,243,1,0,0,0,243,244,5,149, + 0,0,244,246,1,0,0,0,245,237,1,0,0,0,245,246,1,0,0,0,246,247,1,0, + 0,0,247,248,3,36,18,0,248,17,1,0,0,0,249,250,5,93,0,0,250,254,3, + 36,18,0,251,253,3,16,8,0,252,251,1,0,0,0,253,256,1,0,0,0,254,252, + 1,0,0,0,254,255,1,0,0,0,255,259,1,0,0,0,256,254,1,0,0,0,257,258, + 5,29,0,0,258,260,3,36,18,0,259,257,1,0,0,0,259,260,1,0,0,0,260,19, + 1,0,0,0,261,262,5,40,0,0,262,263,5,130,0,0,263,264,3,4,2,0,264,265, + 5,149,0,0,265,268,3,10,5,0,266,267,5,25,0,0,267,269,3,10,5,0,268, + 266,1,0,0,0,268,269,1,0,0,0,269,21,1,0,0,0,270,271,5,100,0,0,271, + 272,5,130,0,0,272,273,3,4,2,0,273,274,5,149,0,0,274,276,3,10,5,0, + 275,277,5,150,0,0,276,275,1,0,0,0,276,277,1,0,0,0,277,23,1,0,0,0, + 278,279,5,33,0,0,279,283,5,130,0,0,280,284,3,6,3,0,281,284,3,30, + 15,0,282,284,3,4,2,0,283,280,1,0,0,0,283,281,1,0,0,0,283,282,1,0, + 0,0,283,284,1,0,0,0,284,285,1,0,0,0,285,287,5,150,0,0,286,288,3, + 4,2,0,287,286,1,0,0,0,287,288,1,0,0,0,288,289,1,0,0,0,289,293,5, + 150,0,0,290,294,3,6,3,0,291,294,3,30,15,0,292,294,3,4,2,0,293,290, + 1,0,0,0,293,291,1,0,0,0,293,292,1,0,0,0,293,294,1,0,0,0,294,295, + 1,0,0,0,295,296,5,149,0,0,296,298,3,10,5,0,297,299,5,150,0,0,298, + 297,1,0,0,0,298,299,1,0,0,0,299,25,1,0,0,0,300,301,5,33,0,0,301, + 302,5,130,0,0,302,303,5,52,0,0,303,306,3,160,80,0,304,305,5,116, + 0,0,305,307,3,160,80,0,306,304,1,0,0,0,306,307,1,0,0,0,307,308,1, + 0,0,0,308,309,5,42,0,0,309,310,3,4,2,0,310,311,5,149,0,0,311,313, + 3,10,5,0,312,314,5,150,0,0,313,312,1,0,0,0,313,314,1,0,0,0,314,27, + 1,0,0,0,315,316,5,31,0,0,316,317,3,160,80,0,317,319,5,130,0,0,318, + 320,3,8,4,0,319,318,1,0,0,0,319,320,1,0,0,0,320,321,1,0,0,0,321, + 322,5,149,0,0,322,323,3,36,18,0,323,29,1,0,0,0,324,325,3,4,2,0,325, + 326,5,115,0,0,326,327,5,122,0,0,327,328,3,4,2,0,328,31,1,0,0,0,329, + 331,3,4,2,0,330,332,5,150,0,0,331,330,1,0,0,0,331,332,1,0,0,0,332, + 33,1,0,0,0,333,334,5,150,0,0,334,35,1,0,0,0,335,339,5,128,0,0,336, + 338,3,2,1,0,337,336,1,0,0,0,338,341,1,0,0,0,339,337,1,0,0,0,339, + 340,1,0,0,0,340,342,1,0,0,0,341,339,1,0,0,0,342,343,5,147,0,0,343, + 37,1,0,0,0,344,345,3,4,2,0,345,346,5,115,0,0,346,347,3,4,2,0,347, + 39,1,0,0,0,348,353,3,38,19,0,349,350,5,116,0,0,350,352,3,38,19,0, + 351,349,1,0,0,0,352,355,1,0,0,0,353,351,1,0,0,0,353,354,1,0,0,0, + 354,357,1,0,0,0,355,353,1,0,0,0,356,358,5,116,0,0,357,356,1,0,0, + 0,357,358,1,0,0,0,358,41,1,0,0,0,359,363,3,44,22,0,360,363,3,48, + 24,0,361,363,3,124,62,0,362,359,1,0,0,0,362,360,1,0,0,0,362,361, + 1,0,0,0,363,364,1,0,0,0,364,365,5,0,0,1,365,43,1,0,0,0,366,372,3, + 46,23,0,367,368,5,95,0,0,368,369,5,1,0,0,369,371,3,46,23,0,370,367, + 1,0,0,0,371,374,1,0,0,0,372,370,1,0,0,0,372,373,1,0,0,0,373,45,1, + 0,0,0,374,372,1,0,0,0,375,382,3,48,24,0,376,377,5,130,0,0,377,378, + 3,44,22,0,378,379,5,149,0,0,379,382,1,0,0,0,380,382,3,164,82,0,381, + 375,1,0,0,0,381,376,1,0,0,0,381,380,1,0,0,0,382,47,1,0,0,0,383,385, + 3,50,25,0,384,383,1,0,0,0,384,385,1,0,0,0,385,386,1,0,0,0,386,388, + 5,79,0,0,387,389,5,24,0,0,388,387,1,0,0,0,388,389,1,0,0,0,389,391, + 1,0,0,0,390,392,3,52,26,0,391,390,1,0,0,0,391,392,1,0,0,0,392,393, + 1,0,0,0,393,395,3,114,57,0,394,396,3,54,27,0,395,394,1,0,0,0,395, + 396,1,0,0,0,396,398,1,0,0,0,397,399,3,56,28,0,398,397,1,0,0,0,398, + 399,1,0,0,0,399,401,1,0,0,0,400,402,3,60,30,0,401,400,1,0,0,0,401, + 402,1,0,0,0,402,404,1,0,0,0,403,405,3,62,31,0,404,403,1,0,0,0,404, + 405,1,0,0,0,405,407,1,0,0,0,406,408,3,64,32,0,407,406,1,0,0,0,407, + 408,1,0,0,0,408,411,1,0,0,0,409,410,5,102,0,0,410,412,7,0,0,0,411, + 409,1,0,0,0,411,412,1,0,0,0,412,415,1,0,0,0,413,414,5,102,0,0,414, + 416,5,89,0,0,415,413,1,0,0,0,415,416,1,0,0,0,416,418,1,0,0,0,417, + 419,3,66,33,0,418,417,1,0,0,0,418,419,1,0,0,0,419,421,1,0,0,0,420, + 422,3,58,29,0,421,420,1,0,0,0,421,422,1,0,0,0,422,424,1,0,0,0,423, + 425,3,68,34,0,424,423,1,0,0,0,424,425,1,0,0,0,425,428,1,0,0,0,426, + 429,3,72,36,0,427,429,3,74,37,0,428,426,1,0,0,0,428,427,1,0,0,0, + 428,429,1,0,0,0,429,431,1,0,0,0,430,432,3,76,38,0,431,430,1,0,0, + 0,431,432,1,0,0,0,432,49,1,0,0,0,433,434,5,102,0,0,434,435,3,128, + 64,0,435,51,1,0,0,0,436,437,5,88,0,0,437,440,5,108,0,0,438,439,5, + 102,0,0,439,441,5,85,0,0,440,438,1,0,0,0,440,441,1,0,0,0,441,53, + 1,0,0,0,442,443,5,34,0,0,443,444,3,78,39,0,444,55,1,0,0,0,445,447, + 7,1,0,0,446,445,1,0,0,0,446,447,1,0,0,0,447,448,1,0,0,0,448,449, + 5,5,0,0,449,450,5,47,0,0,450,451,3,114,57,0,451,57,1,0,0,0,452,453, 5,101,0,0,453,454,3,160,80,0,454,455,5,6,0,0,455,456,5,130,0,0,456, 457,3,98,49,0,457,467,5,149,0,0,458,459,5,116,0,0,459,460,3,160, 80,0,460,461,5,6,0,0,461,462,5,130,0,0,462,463,3,98,49,0,463,464, @@ -453,78 +453,79 @@ def serializedATN(): 0,0,1090,1094,3,160,80,0,1091,1093,3,126,63,0,1092,1091,1,0,0,0, 1093,1096,1,0,0,0,1094,1092,1,0,0,0,1094,1095,1,0,0,0,1095,1097, 1,0,0,0,1096,1094,1,0,0,0,1097,1098,5,151,0,0,1098,1099,5,124,0, - 0,1099,1118,1,0,0,0,1100,1101,5,132,0,0,1101,1105,3,160,80,0,1102, + 0,1099,1122,1,0,0,0,1100,1101,5,132,0,0,1101,1105,3,160,80,0,1102, 1104,3,126,63,0,1103,1102,1,0,0,0,1104,1107,1,0,0,0,1105,1103,1, 0,0,0,1105,1106,1,0,0,0,1106,1108,1,0,0,0,1107,1105,1,0,0,0,1108, - 1110,5,124,0,0,1109,1111,3,124,62,0,1110,1109,1,0,0,0,1110,1111, - 1,0,0,0,1111,1112,1,0,0,0,1112,1113,5,132,0,0,1113,1114,5,151,0, - 0,1114,1115,3,160,80,0,1115,1116,5,124,0,0,1116,1118,1,0,0,0,1117, - 1089,1,0,0,0,1117,1100,1,0,0,0,1118,125,1,0,0,0,1119,1120,3,160, - 80,0,1120,1121,5,122,0,0,1121,1122,3,166,83,0,1122,1131,1,0,0,0, - 1123,1124,3,160,80,0,1124,1125,5,122,0,0,1125,1126,5,128,0,0,1126, - 1127,3,116,58,0,1127,1128,5,147,0,0,1128,1131,1,0,0,0,1129,1131, - 3,160,80,0,1130,1119,1,0,0,0,1130,1123,1,0,0,0,1130,1129,1,0,0,0, - 1131,127,1,0,0,0,1132,1137,3,130,65,0,1133,1134,5,116,0,0,1134,1136, - 3,130,65,0,1135,1133,1,0,0,0,1136,1139,1,0,0,0,1137,1135,1,0,0,0, - 1137,1138,1,0,0,0,1138,1141,1,0,0,0,1139,1137,1,0,0,0,1140,1142, - 5,116,0,0,1141,1140,1,0,0,0,1141,1142,1,0,0,0,1142,129,1,0,0,0,1143, - 1144,3,160,80,0,1144,1145,5,6,0,0,1145,1146,5,130,0,0,1146,1147, - 3,44,22,0,1147,1148,5,149,0,0,1148,1154,1,0,0,0,1149,1150,3,116, - 58,0,1150,1151,5,6,0,0,1151,1152,3,160,80,0,1152,1154,1,0,0,0,1153, - 1143,1,0,0,0,1153,1149,1,0,0,0,1154,131,1,0,0,0,1155,1163,3,164, - 82,0,1156,1157,3,140,70,0,1157,1158,5,120,0,0,1158,1160,1,0,0,0, - 1159,1156,1,0,0,0,1159,1160,1,0,0,0,1160,1161,1,0,0,0,1161,1163, - 3,134,67,0,1162,1155,1,0,0,0,1162,1159,1,0,0,0,1163,133,1,0,0,0, - 1164,1169,3,160,80,0,1165,1166,5,120,0,0,1166,1168,3,160,80,0,1167, - 1165,1,0,0,0,1168,1171,1,0,0,0,1169,1167,1,0,0,0,1169,1170,1,0,0, - 0,1170,135,1,0,0,0,1171,1169,1,0,0,0,1172,1173,6,68,-1,0,1173,1182, - 3,140,70,0,1174,1182,3,138,69,0,1175,1176,5,130,0,0,1176,1177,3, - 44,22,0,1177,1178,5,149,0,0,1178,1182,1,0,0,0,1179,1182,3,124,62, - 0,1180,1182,3,164,82,0,1181,1172,1,0,0,0,1181,1174,1,0,0,0,1181, - 1175,1,0,0,0,1181,1179,1,0,0,0,1181,1180,1,0,0,0,1182,1191,1,0,0, - 0,1183,1187,10,3,0,0,1184,1188,3,158,79,0,1185,1186,5,6,0,0,1186, - 1188,3,160,80,0,1187,1184,1,0,0,0,1187,1185,1,0,0,0,1188,1190,1, - 0,0,0,1189,1183,1,0,0,0,1190,1193,1,0,0,0,1191,1189,1,0,0,0,1191, - 1192,1,0,0,0,1192,137,1,0,0,0,1193,1191,1,0,0,0,1194,1195,3,160, - 80,0,1195,1197,5,130,0,0,1196,1198,3,142,71,0,1197,1196,1,0,0,0, - 1197,1198,1,0,0,0,1198,1199,1,0,0,0,1199,1200,5,149,0,0,1200,139, - 1,0,0,0,1201,1202,3,144,72,0,1202,1203,5,120,0,0,1203,1205,1,0,0, - 0,1204,1201,1,0,0,0,1204,1205,1,0,0,0,1205,1206,1,0,0,0,1206,1207, - 3,160,80,0,1207,141,1,0,0,0,1208,1213,3,116,58,0,1209,1210,5,116, - 0,0,1210,1212,3,116,58,0,1211,1209,1,0,0,0,1212,1215,1,0,0,0,1213, - 1211,1,0,0,0,1213,1214,1,0,0,0,1214,1217,1,0,0,0,1215,1213,1,0,0, - 0,1216,1218,5,116,0,0,1217,1216,1,0,0,0,1217,1218,1,0,0,0,1218,143, - 1,0,0,0,1219,1220,3,160,80,0,1220,145,1,0,0,0,1221,1230,5,106,0, - 0,1222,1223,5,120,0,0,1223,1230,7,11,0,0,1224,1225,5,108,0,0,1225, - 1227,5,120,0,0,1226,1228,7,11,0,0,1227,1226,1,0,0,0,1227,1228,1, - 0,0,0,1228,1230,1,0,0,0,1229,1221,1,0,0,0,1229,1222,1,0,0,0,1229, - 1224,1,0,0,0,1230,147,1,0,0,0,1231,1233,7,12,0,0,1232,1231,1,0,0, - 0,1232,1233,1,0,0,0,1233,1240,1,0,0,0,1234,1241,3,146,73,0,1235, - 1241,5,107,0,0,1236,1241,5,108,0,0,1237,1241,5,109,0,0,1238,1241, - 5,43,0,0,1239,1241,5,57,0,0,1240,1234,1,0,0,0,1240,1235,1,0,0,0, - 1240,1236,1,0,0,0,1240,1237,1,0,0,0,1240,1238,1,0,0,0,1240,1239, - 1,0,0,0,1241,149,1,0,0,0,1242,1246,3,148,74,0,1243,1246,5,110,0, - 0,1244,1246,5,59,0,0,1245,1242,1,0,0,0,1245,1243,1,0,0,0,1245,1244, - 1,0,0,0,1246,151,1,0,0,0,1247,1248,7,13,0,0,1248,153,1,0,0,0,1249, - 1250,7,14,0,0,1250,155,1,0,0,0,1251,1252,7,15,0,0,1252,157,1,0,0, - 0,1253,1256,5,105,0,0,1254,1256,3,156,78,0,1255,1253,1,0,0,0,1255, - 1254,1,0,0,0,1256,159,1,0,0,0,1257,1261,5,105,0,0,1258,1261,3,152, - 76,0,1259,1261,3,154,77,0,1260,1257,1,0,0,0,1260,1258,1,0,0,0,1260, - 1259,1,0,0,0,1261,161,1,0,0,0,1262,1263,3,166,83,0,1263,1264,5,122, - 0,0,1264,1265,3,148,74,0,1265,163,1,0,0,0,1266,1267,5,128,0,0,1267, - 1268,3,160,80,0,1268,1269,5,147,0,0,1269,165,1,0,0,0,1270,1273,5, - 110,0,0,1271,1273,3,168,84,0,1272,1270,1,0,0,0,1272,1271,1,0,0,0, - 1273,167,1,0,0,0,1274,1278,5,142,0,0,1275,1277,3,170,85,0,1276,1275, - 1,0,0,0,1277,1280,1,0,0,0,1278,1276,1,0,0,0,1278,1279,1,0,0,0,1279, - 1281,1,0,0,0,1280,1278,1,0,0,0,1281,1282,5,144,0,0,1282,169,1,0, - 0,0,1283,1284,5,157,0,0,1284,1285,3,116,58,0,1285,1286,5,147,0,0, - 1286,1289,1,0,0,0,1287,1289,5,156,0,0,1288,1283,1,0,0,0,1288,1287, - 1,0,0,0,1289,171,1,0,0,0,1290,1294,5,143,0,0,1291,1293,3,174,87, - 0,1292,1291,1,0,0,0,1293,1296,1,0,0,0,1294,1292,1,0,0,0,1294,1295, - 1,0,0,0,1295,1297,1,0,0,0,1296,1294,1,0,0,0,1297,1298,5,0,0,1,1298, - 173,1,0,0,0,1299,1300,5,159,0,0,1300,1301,3,116,58,0,1301,1302,5, - 147,0,0,1302,1305,1,0,0,0,1303,1305,5,158,0,0,1304,1299,1,0,0,0, - 1304,1303,1,0,0,0,1305,175,1,0,0,0,168,179,186,195,202,206,220,224, + 1114,5,124,0,0,1109,1115,3,124,62,0,1110,1111,5,128,0,0,1111,1112, + 3,116,58,0,1112,1113,5,147,0,0,1113,1115,1,0,0,0,1114,1109,1,0,0, + 0,1114,1110,1,0,0,0,1114,1115,1,0,0,0,1115,1116,1,0,0,0,1116,1117, + 5,132,0,0,1117,1118,5,151,0,0,1118,1119,3,160,80,0,1119,1120,5,124, + 0,0,1120,1122,1,0,0,0,1121,1089,1,0,0,0,1121,1100,1,0,0,0,1122,125, + 1,0,0,0,1123,1124,3,160,80,0,1124,1125,5,122,0,0,1125,1126,3,166, + 83,0,1126,1135,1,0,0,0,1127,1128,3,160,80,0,1128,1129,5,122,0,0, + 1129,1130,5,128,0,0,1130,1131,3,116,58,0,1131,1132,5,147,0,0,1132, + 1135,1,0,0,0,1133,1135,3,160,80,0,1134,1123,1,0,0,0,1134,1127,1, + 0,0,0,1134,1133,1,0,0,0,1135,127,1,0,0,0,1136,1141,3,130,65,0,1137, + 1138,5,116,0,0,1138,1140,3,130,65,0,1139,1137,1,0,0,0,1140,1143, + 1,0,0,0,1141,1139,1,0,0,0,1141,1142,1,0,0,0,1142,1145,1,0,0,0,1143, + 1141,1,0,0,0,1144,1146,5,116,0,0,1145,1144,1,0,0,0,1145,1146,1,0, + 0,0,1146,129,1,0,0,0,1147,1148,3,160,80,0,1148,1149,5,6,0,0,1149, + 1150,5,130,0,0,1150,1151,3,44,22,0,1151,1152,5,149,0,0,1152,1158, + 1,0,0,0,1153,1154,3,116,58,0,1154,1155,5,6,0,0,1155,1156,3,160,80, + 0,1156,1158,1,0,0,0,1157,1147,1,0,0,0,1157,1153,1,0,0,0,1158,131, + 1,0,0,0,1159,1167,3,164,82,0,1160,1161,3,140,70,0,1161,1162,5,120, + 0,0,1162,1164,1,0,0,0,1163,1160,1,0,0,0,1163,1164,1,0,0,0,1164,1165, + 1,0,0,0,1165,1167,3,134,67,0,1166,1159,1,0,0,0,1166,1163,1,0,0,0, + 1167,133,1,0,0,0,1168,1173,3,160,80,0,1169,1170,5,120,0,0,1170,1172, + 3,160,80,0,1171,1169,1,0,0,0,1172,1175,1,0,0,0,1173,1171,1,0,0,0, + 1173,1174,1,0,0,0,1174,135,1,0,0,0,1175,1173,1,0,0,0,1176,1177,6, + 68,-1,0,1177,1186,3,140,70,0,1178,1186,3,138,69,0,1179,1180,5,130, + 0,0,1180,1181,3,44,22,0,1181,1182,5,149,0,0,1182,1186,1,0,0,0,1183, + 1186,3,124,62,0,1184,1186,3,164,82,0,1185,1176,1,0,0,0,1185,1178, + 1,0,0,0,1185,1179,1,0,0,0,1185,1183,1,0,0,0,1185,1184,1,0,0,0,1186, + 1195,1,0,0,0,1187,1191,10,3,0,0,1188,1192,3,158,79,0,1189,1190,5, + 6,0,0,1190,1192,3,160,80,0,1191,1188,1,0,0,0,1191,1189,1,0,0,0,1192, + 1194,1,0,0,0,1193,1187,1,0,0,0,1194,1197,1,0,0,0,1195,1193,1,0,0, + 0,1195,1196,1,0,0,0,1196,137,1,0,0,0,1197,1195,1,0,0,0,1198,1199, + 3,160,80,0,1199,1201,5,130,0,0,1200,1202,3,142,71,0,1201,1200,1, + 0,0,0,1201,1202,1,0,0,0,1202,1203,1,0,0,0,1203,1204,5,149,0,0,1204, + 139,1,0,0,0,1205,1206,3,144,72,0,1206,1207,5,120,0,0,1207,1209,1, + 0,0,0,1208,1205,1,0,0,0,1208,1209,1,0,0,0,1209,1210,1,0,0,0,1210, + 1211,3,160,80,0,1211,141,1,0,0,0,1212,1217,3,116,58,0,1213,1214, + 5,116,0,0,1214,1216,3,116,58,0,1215,1213,1,0,0,0,1216,1219,1,0,0, + 0,1217,1215,1,0,0,0,1217,1218,1,0,0,0,1218,1221,1,0,0,0,1219,1217, + 1,0,0,0,1220,1222,5,116,0,0,1221,1220,1,0,0,0,1221,1222,1,0,0,0, + 1222,143,1,0,0,0,1223,1224,3,160,80,0,1224,145,1,0,0,0,1225,1234, + 5,106,0,0,1226,1227,5,120,0,0,1227,1234,7,11,0,0,1228,1229,5,108, + 0,0,1229,1231,5,120,0,0,1230,1232,7,11,0,0,1231,1230,1,0,0,0,1231, + 1232,1,0,0,0,1232,1234,1,0,0,0,1233,1225,1,0,0,0,1233,1226,1,0,0, + 0,1233,1228,1,0,0,0,1234,147,1,0,0,0,1235,1237,7,12,0,0,1236,1235, + 1,0,0,0,1236,1237,1,0,0,0,1237,1244,1,0,0,0,1238,1245,3,146,73,0, + 1239,1245,5,107,0,0,1240,1245,5,108,0,0,1241,1245,5,109,0,0,1242, + 1245,5,43,0,0,1243,1245,5,57,0,0,1244,1238,1,0,0,0,1244,1239,1,0, + 0,0,1244,1240,1,0,0,0,1244,1241,1,0,0,0,1244,1242,1,0,0,0,1244,1243, + 1,0,0,0,1245,149,1,0,0,0,1246,1250,3,148,74,0,1247,1250,5,110,0, + 0,1248,1250,5,59,0,0,1249,1246,1,0,0,0,1249,1247,1,0,0,0,1249,1248, + 1,0,0,0,1250,151,1,0,0,0,1251,1252,7,13,0,0,1252,153,1,0,0,0,1253, + 1254,7,14,0,0,1254,155,1,0,0,0,1255,1256,7,15,0,0,1256,157,1,0,0, + 0,1257,1260,5,105,0,0,1258,1260,3,156,78,0,1259,1257,1,0,0,0,1259, + 1258,1,0,0,0,1260,159,1,0,0,0,1261,1265,5,105,0,0,1262,1265,3,152, + 76,0,1263,1265,3,154,77,0,1264,1261,1,0,0,0,1264,1262,1,0,0,0,1264, + 1263,1,0,0,0,1265,161,1,0,0,0,1266,1267,3,166,83,0,1267,1268,5,122, + 0,0,1268,1269,3,148,74,0,1269,163,1,0,0,0,1270,1271,5,128,0,0,1271, + 1272,3,160,80,0,1272,1273,5,147,0,0,1273,165,1,0,0,0,1274,1277,5, + 110,0,0,1275,1277,3,168,84,0,1276,1274,1,0,0,0,1276,1275,1,0,0,0, + 1277,167,1,0,0,0,1278,1282,5,142,0,0,1279,1281,3,170,85,0,1280,1279, + 1,0,0,0,1281,1284,1,0,0,0,1282,1280,1,0,0,0,1282,1283,1,0,0,0,1283, + 1285,1,0,0,0,1284,1282,1,0,0,0,1285,1286,5,144,0,0,1286,169,1,0, + 0,0,1287,1288,5,157,0,0,1288,1289,3,116,58,0,1289,1290,5,147,0,0, + 1290,1293,1,0,0,0,1291,1293,5,156,0,0,1292,1287,1,0,0,0,1292,1291, + 1,0,0,0,1293,171,1,0,0,0,1294,1298,5,143,0,0,1295,1297,3,174,87, + 0,1296,1295,1,0,0,0,1297,1300,1,0,0,0,1298,1296,1,0,0,0,1298,1299, + 1,0,0,0,1299,1301,1,0,0,0,1300,1298,1,0,0,0,1301,1302,5,0,0,1,1302, + 173,1,0,0,0,1303,1304,5,159,0,0,1304,1305,3,116,58,0,1305,1306,5, + 147,0,0,1306,1309,1,0,0,0,1307,1309,5,158,0,0,1308,1303,1,0,0,0, + 1308,1307,1,0,0,0,1309,175,1,0,0,0,168,179,186,195,202,206,220,224, 227,231,234,241,245,254,259,268,276,283,287,293,298,306,313,319, 331,339,353,357,362,372,381,384,388,391,395,398,401,404,407,411, 415,418,421,424,428,431,440,446,467,484,501,507,513,524,526,537, @@ -533,9 +534,9 @@ def serializedATN(): 698,712,728,732,743,747,758,762,769,773,780,784,789,798,802,826, 843,849,852,855,865,871,874,877,885,888,892,895,909,926,931,935, 941,948,960,964,967,976,990,1029,1037,1039,1041,1049,1053,1057,1065, - 1069,1078,1082,1084,1094,1105,1110,1117,1130,1137,1141,1153,1159, - 1162,1169,1181,1187,1191,1197,1204,1213,1217,1227,1229,1232,1240, - 1245,1255,1260,1272,1278,1288,1294,1304 + 1069,1078,1082,1084,1094,1105,1114,1121,1134,1141,1145,1157,1163, + 1166,1173,1185,1191,1195,1201,1208,1217,1221,1231,1233,1236,1244, + 1249,1259,1264,1276,1282,1292,1298,1308 ] class HogQLParser ( Parser ): @@ -7890,6 +7891,13 @@ def hogqlxTagAttribute(self, i:int=None): def hogqlxTagElement(self): return self.getTypedRuleContext(HogQLParser.HogqlxTagElementContext,0) + def LBRACE(self): + return self.getToken(HogQLParser.LBRACE, 0) + def columnExpr(self): + return self.getTypedRuleContext(HogQLParser.ColumnExprContext,0) + + def RBRACE(self): + return self.getToken(HogQLParser.RBRACE, 0) def accept(self, visitor:ParseTreeVisitor): if hasattr( visitor, "visitHogqlxTagElementNested" ): @@ -7905,7 +7913,7 @@ def hogqlxTagElement(self): self.enterRule(localctx, 124, self.RULE_hogqlxTagElement) self._la = 0 # Token type try: - self.state = 1117 + self.state = 1121 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,141,self._ctx) if la_ == 1: @@ -7950,21 +7958,29 @@ def hogqlxTagElement(self): self.state = 1108 self.match(HogQLParser.GT) - self.state = 1110 + self.state = 1114 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,140,self._ctx) if la_ == 1: self.state = 1109 self.hogqlxTagElement() + elif la_ == 2: + self.state = 1110 + self.match(HogQLParser.LBRACE) + self.state = 1111 + self.columnExpr(0) + self.state = 1112 + self.match(HogQLParser.RBRACE) + - self.state = 1112 + self.state = 1116 self.match(HogQLParser.LT) - self.state = 1113 + self.state = 1117 self.match(HogQLParser.SLASH) - self.state = 1114 + self.state = 1118 self.identifier() - self.state = 1115 + self.state = 1119 self.match(HogQLParser.GT) pass @@ -8023,36 +8039,36 @@ def hogqlxTagAttribute(self): localctx = HogQLParser.HogqlxTagAttributeContext(self, self._ctx, self.state) self.enterRule(localctx, 126, self.RULE_hogqlxTagAttribute) try: - self.state = 1130 + self.state = 1134 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,142,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1119 + self.state = 1123 self.identifier() - self.state = 1120 + self.state = 1124 self.match(HogQLParser.EQ_SINGLE) - self.state = 1121 + self.state = 1125 self.string() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1123 + self.state = 1127 self.identifier() - self.state = 1124 + self.state = 1128 self.match(HogQLParser.EQ_SINGLE) - self.state = 1125 + self.state = 1129 self.match(HogQLParser.LBRACE) - self.state = 1126 + self.state = 1130 self.columnExpr(0) - self.state = 1127 + self.state = 1131 self.match(HogQLParser.RBRACE) pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 1129 + self.state = 1133 self.identifier() pass @@ -8105,26 +8121,26 @@ def withExprList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1132 + self.state = 1136 self.withExpr() - self.state = 1137 + self.state = 1141 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,143,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: - self.state = 1133 + self.state = 1137 self.match(HogQLParser.COMMA) - self.state = 1134 + self.state = 1138 self.withExpr() - self.state = 1139 + self.state = 1143 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,143,self._ctx) - self.state = 1141 + self.state = 1145 self._errHandler.sync(self) _la = self._input.LA(1) if _la==116: - self.state = 1140 + self.state = 1144 self.match(HogQLParser.COMMA) @@ -8208,32 +8224,32 @@ def withExpr(self): localctx = HogQLParser.WithExprContext(self, self._ctx, self.state) self.enterRule(localctx, 130, self.RULE_withExpr) try: - self.state = 1153 + self.state = 1157 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,145,self._ctx) if la_ == 1: localctx = HogQLParser.WithExprSubqueryContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1143 + self.state = 1147 self.identifier() - self.state = 1144 + self.state = 1148 self.match(HogQLParser.AS) - self.state = 1145 + self.state = 1149 self.match(HogQLParser.LPAREN) - self.state = 1146 + self.state = 1150 self.selectUnionStmt() - self.state = 1147 + self.state = 1151 self.match(HogQLParser.RPAREN) pass elif la_ == 2: localctx = HogQLParser.WithExprColumnContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1149 + self.state = 1153 self.columnExpr(0) - self.state = 1150 + self.state = 1154 self.match(HogQLParser.AS) - self.state = 1151 + self.state = 1155 self.identifier() pass @@ -8286,27 +8302,27 @@ def columnIdentifier(self): localctx = HogQLParser.ColumnIdentifierContext(self, self._ctx, self.state) self.enterRule(localctx, 132, self.RULE_columnIdentifier) try: - self.state = 1162 + self.state = 1166 self._errHandler.sync(self) token = self._input.LA(1) if token in [128]: self.enterOuterAlt(localctx, 1) - self.state = 1155 + self.state = 1159 self.placeholder() pass elif token in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 99, 101, 102, 103, 105]: self.enterOuterAlt(localctx, 2) - self.state = 1159 + self.state = 1163 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,146,self._ctx) if la_ == 1: - self.state = 1156 + self.state = 1160 self.tableIdentifier() - self.state = 1157 + self.state = 1161 self.match(HogQLParser.DOT) - self.state = 1161 + self.state = 1165 self.nestedIdentifier() pass else: @@ -8359,18 +8375,18 @@ def nestedIdentifier(self): self.enterRule(localctx, 134, self.RULE_nestedIdentifier) try: self.enterOuterAlt(localctx, 1) - self.state = 1164 + self.state = 1168 self.identifier() - self.state = 1169 + self.state = 1173 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,148,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: - self.state = 1165 + self.state = 1169 self.match(HogQLParser.DOT) - self.state = 1166 + self.state = 1170 self.identifier() - self.state = 1171 + self.state = 1175 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,148,self._ctx) @@ -8523,7 +8539,7 @@ def tableExpr(self, _p:int=0): self.enterRecursionRule(localctx, 136, self.RULE_tableExpr, _p) try: self.enterOuterAlt(localctx, 1) - self.state = 1181 + self.state = 1185 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,149,self._ctx) if la_ == 1: @@ -8531,7 +8547,7 @@ def tableExpr(self, _p:int=0): self._ctx = localctx _prevctx = localctx - self.state = 1173 + self.state = 1177 self.tableIdentifier() pass @@ -8539,7 +8555,7 @@ def tableExpr(self, _p:int=0): localctx = HogQLParser.TableExprFunctionContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 1174 + self.state = 1178 self.tableFunctionExpr() pass @@ -8547,11 +8563,11 @@ def tableExpr(self, _p:int=0): localctx = HogQLParser.TableExprSubqueryContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 1175 + self.state = 1179 self.match(HogQLParser.LPAREN) - self.state = 1176 + self.state = 1180 self.selectUnionStmt() - self.state = 1177 + self.state = 1181 self.match(HogQLParser.RPAREN) pass @@ -8559,7 +8575,7 @@ def tableExpr(self, _p:int=0): localctx = HogQLParser.TableExprTagContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 1179 + self.state = 1183 self.hogqlxTagElement() pass @@ -8567,13 +8583,13 @@ def tableExpr(self, _p:int=0): localctx = HogQLParser.TableExprPlaceholderContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 1180 + self.state = 1184 self.placeholder() pass self._ctx.stop = self._input.LT(-1) - self.state = 1191 + self.state = 1195 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,151,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -8583,27 +8599,27 @@ def tableExpr(self, _p:int=0): _prevctx = localctx localctx = HogQLParser.TableExprAliasContext(self, HogQLParser.TableExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_tableExpr) - self.state = 1183 + self.state = 1187 if not self.precpred(self._ctx, 3): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 3)") - self.state = 1187 + self.state = 1191 self._errHandler.sync(self) token = self._input.LA(1) if token in [20, 30, 39, 48, 105]: - self.state = 1184 + self.state = 1188 self.alias() pass elif token in [6]: - self.state = 1185 + self.state = 1189 self.match(HogQLParser.AS) - self.state = 1186 + self.state = 1190 self.identifier() pass else: raise NoViableAltException(self) - self.state = 1193 + self.state = 1197 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,151,self._ctx) @@ -8656,19 +8672,19 @@ def tableFunctionExpr(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1194 + self.state = 1198 self.identifier() - self.state = 1195 + self.state = 1199 self.match(HogQLParser.LPAREN) - self.state = 1197 + self.state = 1201 self._errHandler.sync(self) _la = self._input.LA(1) if (((_la) & ~0x3f) == 0 and ((1 << _la) & -4503602311741442) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & 90493036243451903) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & 18455) != 0): - self.state = 1196 + self.state = 1200 self.tableArgList() - self.state = 1199 + self.state = 1203 self.match(HogQLParser.RPAREN) except RecognitionException as re: localctx.exception = re @@ -8715,17 +8731,17 @@ def tableIdentifier(self): self.enterRule(localctx, 140, self.RULE_tableIdentifier) try: self.enterOuterAlt(localctx, 1) - self.state = 1204 + self.state = 1208 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,153,self._ctx) if la_ == 1: - self.state = 1201 + self.state = 1205 self.databaseIdentifier() - self.state = 1202 + self.state = 1206 self.match(HogQLParser.DOT) - self.state = 1206 + self.state = 1210 self.identifier() except RecognitionException as re: localctx.exception = re @@ -8775,26 +8791,26 @@ def tableArgList(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1208 + self.state = 1212 self.columnExpr(0) - self.state = 1213 + self.state = 1217 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,154,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: - self.state = 1209 + self.state = 1213 self.match(HogQLParser.COMMA) - self.state = 1210 + self.state = 1214 self.columnExpr(0) - self.state = 1215 + self.state = 1219 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,154,self._ctx) - self.state = 1217 + self.state = 1221 self._errHandler.sync(self) _la = self._input.LA(1) if _la==116: - self.state = 1216 + self.state = 1220 self.match(HogQLParser.COMMA) @@ -8836,7 +8852,7 @@ def databaseIdentifier(self): self.enterRule(localctx, 144, self.RULE_databaseIdentifier) try: self.enterOuterAlt(localctx, 1) - self.state = 1219 + self.state = 1223 self.identifier() except RecognitionException as re: localctx.exception = re @@ -8887,19 +8903,19 @@ def floatingLiteral(self): self.enterRule(localctx, 146, self.RULE_floatingLiteral) self._la = 0 # Token type try: - self.state = 1229 + self.state = 1233 self._errHandler.sync(self) token = self._input.LA(1) if token in [106]: self.enterOuterAlt(localctx, 1) - self.state = 1221 + self.state = 1225 self.match(HogQLParser.FLOATING_LITERAL) pass elif token in [120]: self.enterOuterAlt(localctx, 2) - self.state = 1222 + self.state = 1226 self.match(HogQLParser.DOT) - self.state = 1223 + self.state = 1227 _la = self._input.LA(1) if not(_la==107 or _la==108): self._errHandler.recoverInline(self) @@ -8909,15 +8925,15 @@ def floatingLiteral(self): pass elif token in [108]: self.enterOuterAlt(localctx, 3) - self.state = 1224 + self.state = 1228 self.match(HogQLParser.DECIMAL_LITERAL) - self.state = 1225 + self.state = 1229 self.match(HogQLParser.DOT) - self.state = 1227 + self.state = 1231 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,156,self._ctx) if la_ == 1: - self.state = 1226 + self.state = 1230 _la = self._input.LA(1) if not(_la==107 or _la==108): self._errHandler.recoverInline(self) @@ -8990,11 +9006,11 @@ def numberLiteral(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1232 + self.state = 1236 self._errHandler.sync(self) _la = self._input.LA(1) if _la==118 or _la==139: - self.state = 1231 + self.state = 1235 _la = self._input.LA(1) if not(_la==118 or _la==139): self._errHandler.recoverInline(self) @@ -9003,36 +9019,36 @@ def numberLiteral(self): self.consume() - self.state = 1240 + self.state = 1244 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,159,self._ctx) if la_ == 1: - self.state = 1234 + self.state = 1238 self.floatingLiteral() pass elif la_ == 2: - self.state = 1235 + self.state = 1239 self.match(HogQLParser.OCTAL_LITERAL) pass elif la_ == 3: - self.state = 1236 + self.state = 1240 self.match(HogQLParser.DECIMAL_LITERAL) pass elif la_ == 4: - self.state = 1237 + self.state = 1241 self.match(HogQLParser.HEXADECIMAL_LITERAL) pass elif la_ == 5: - self.state = 1238 + self.state = 1242 self.match(HogQLParser.INF) pass elif la_ == 6: - self.state = 1239 + self.state = 1243 self.match(HogQLParser.NAN_SQL) pass @@ -9080,22 +9096,22 @@ def literal(self): localctx = HogQLParser.LiteralContext(self, self._ctx, self.state) self.enterRule(localctx, 150, self.RULE_literal) try: - self.state = 1245 + self.state = 1249 self._errHandler.sync(self) token = self._input.LA(1) if token in [43, 57, 106, 107, 108, 109, 118, 120, 139]: self.enterOuterAlt(localctx, 1) - self.state = 1242 + self.state = 1246 self.numberLiteral() pass elif token in [110]: self.enterOuterAlt(localctx, 2) - self.state = 1243 + self.state = 1247 self.match(HogQLParser.STRING_LITERAL) pass elif token in [59]: self.enterOuterAlt(localctx, 3) - self.state = 1244 + self.state = 1248 self.match(HogQLParser.NULL_SQL) pass else: @@ -9160,7 +9176,7 @@ def interval(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1247 + self.state = 1251 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & 108086665936896000) != 0) or ((((_la - 70)) & ~0x3f) == 0 and ((1 << (_la - 70)) & 8724152577) != 0)): self._errHandler.recoverInline(self) @@ -9457,7 +9473,7 @@ def keyword(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1249 + self.state = 1253 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & -833175004720939010) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & 471908466623) != 0)): self._errHandler.recoverInline(self) @@ -9511,7 +9527,7 @@ def keywordForAlias(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1251 + self.state = 1255 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & 282025807314944) != 0)): self._errHandler.recoverInline(self) @@ -9558,17 +9574,17 @@ def alias(self): localctx = HogQLParser.AliasContext(self, self._ctx, self.state) self.enterRule(localctx, 158, self.RULE_alias) try: - self.state = 1255 + self.state = 1259 self._errHandler.sync(self) token = self._input.LA(1) if token in [105]: self.enterOuterAlt(localctx, 1) - self.state = 1253 + self.state = 1257 self.match(HogQLParser.IDENTIFIER) pass elif token in [20, 30, 39, 48]: self.enterOuterAlt(localctx, 2) - self.state = 1254 + self.state = 1258 self.keywordForAlias() pass else: @@ -9618,22 +9634,22 @@ def identifier(self): localctx = HogQLParser.IdentifierContext(self, self._ctx, self.state) self.enterRule(localctx, 160, self.RULE_identifier) try: - self.state = 1260 + self.state = 1264 self._errHandler.sync(self) token = self._input.LA(1) if token in [105]: self.enterOuterAlt(localctx, 1) - self.state = 1257 + self.state = 1261 self.match(HogQLParser.IDENTIFIER) pass elif token in [21, 38, 55, 56, 70, 78, 97, 103]: self.enterOuterAlt(localctx, 2) - self.state = 1258 + self.state = 1262 self.interval() pass elif token in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 94, 95, 96, 98, 99, 101, 102]: self.enterOuterAlt(localctx, 3) - self.state = 1259 + self.state = 1263 self.keyword() pass else: @@ -9684,11 +9700,11 @@ def enumValue(self): self.enterRule(localctx, 162, self.RULE_enumValue) try: self.enterOuterAlt(localctx, 1) - self.state = 1262 + self.state = 1266 self.string() - self.state = 1263 + self.state = 1267 self.match(HogQLParser.EQ_SINGLE) - self.state = 1264 + self.state = 1268 self.numberLiteral() except RecognitionException as re: localctx.exception = re @@ -9734,11 +9750,11 @@ def placeholder(self): self.enterRule(localctx, 164, self.RULE_placeholder) try: self.enterOuterAlt(localctx, 1) - self.state = 1266 + self.state = 1270 self.match(HogQLParser.LBRACE) - self.state = 1267 + self.state = 1271 self.identifier() - self.state = 1268 + self.state = 1272 self.match(HogQLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9780,17 +9796,17 @@ def string(self): localctx = HogQLParser.StringContext(self, self._ctx, self.state) self.enterRule(localctx, 166, self.RULE_string) try: - self.state = 1272 + self.state = 1276 self._errHandler.sync(self) token = self._input.LA(1) if token in [110]: self.enterOuterAlt(localctx, 1) - self.state = 1270 + self.state = 1274 self.match(HogQLParser.STRING_LITERAL) pass elif token in [142]: self.enterOuterAlt(localctx, 2) - self.state = 1271 + self.state = 1275 self.templateString() pass else: @@ -9844,19 +9860,19 @@ def templateString(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1274 - self.match(HogQLParser.QUOTE_SINGLE_TEMPLATE) self.state = 1278 + self.match(HogQLParser.QUOTE_SINGLE_TEMPLATE) + self.state = 1282 self._errHandler.sync(self) _la = self._input.LA(1) while _la==156 or _la==157: - self.state = 1275 + self.state = 1279 self.stringContents() - self.state = 1280 + self.state = 1284 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1281 + self.state = 1285 self.match(HogQLParser.QUOTE_SINGLE) except RecognitionException as re: localctx.exception = re @@ -9904,21 +9920,21 @@ def stringContents(self): localctx = HogQLParser.StringContentsContext(self, self._ctx, self.state) self.enterRule(localctx, 170, self.RULE_stringContents) try: - self.state = 1288 + self.state = 1292 self._errHandler.sync(self) token = self._input.LA(1) if token in [157]: self.enterOuterAlt(localctx, 1) - self.state = 1283 + self.state = 1287 self.match(HogQLParser.STRING_ESCAPE_TRIGGER) - self.state = 1284 + self.state = 1288 self.columnExpr(0) - self.state = 1285 + self.state = 1289 self.match(HogQLParser.RBRACE) pass elif token in [156]: self.enterOuterAlt(localctx, 2) - self.state = 1287 + self.state = 1291 self.match(HogQLParser.STRING_TEXT) pass else: @@ -9972,19 +9988,19 @@ def fullTemplateString(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1290 - self.match(HogQLParser.QUOTE_SINGLE_TEMPLATE_FULL) self.state = 1294 + self.match(HogQLParser.QUOTE_SINGLE_TEMPLATE_FULL) + self.state = 1298 self._errHandler.sync(self) _la = self._input.LA(1) while _la==158 or _la==159: - self.state = 1291 + self.state = 1295 self.stringContentsFull() - self.state = 1296 + self.state = 1300 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1297 + self.state = 1301 self.match(HogQLParser.EOF) except RecognitionException as re: localctx.exception = re @@ -10032,21 +10048,21 @@ def stringContentsFull(self): localctx = HogQLParser.StringContentsFullContext(self, self._ctx, self.state) self.enterRule(localctx, 174, self.RULE_stringContentsFull) try: - self.state = 1304 + self.state = 1308 self._errHandler.sync(self) token = self._input.LA(1) if token in [159]: self.enterOuterAlt(localctx, 1) - self.state = 1299 + self.state = 1303 self.match(HogQLParser.FULL_STRING_ESCAPE_TRIGGER) - self.state = 1300 + self.state = 1304 self.columnExpr(0) - self.state = 1301 + self.state = 1305 self.match(HogQLParser.RBRACE) pass elif token in [158]: self.enterOuterAlt(localctx, 2) - self.state = 1303 + self.state = 1307 self.match(HogQLParser.FULL_STRING_TEXT) pass else: diff --git a/posthog/hogql/hogqlx.py b/posthog/hogql/hogqlx.py index 3971c19f74cfb..81fb926eff1d4 100644 --- a/posthog/hogql/hogqlx.py +++ b/posthog/hogql/hogqlx.py @@ -2,7 +2,7 @@ from posthog.hogql import ast -HOGQLX_COMPONENTS = ["Sparkline"] +HOGQLX_COMPONENTS = ["Sparkline", "a", "em", "strong"] def convert_tag_to_hx(node: ast.HogQLXTag) -> ast.Tuple: diff --git a/posthog/hogql/parser.py b/posthog/hogql/parser.py index abcee4afb811f..a056d9fc682f6 100644 --- a/posthog/hogql/parser.py +++ b/posthog/hogql/parser.py @@ -1102,6 +1102,12 @@ def visitHogqlxTagElementNested(self, ctx: HogQLParser.HogqlxTagElementNestedCon if a.name == "source": raise SyntaxError(f"Nested HogQLX tags cannot have a source attribute") attributes.append(ast.HogQLXAttribute(name="source", value=source)) + if ctx.columnExpr(): + source = self.visit(ctx.columnExpr()) + for a in attributes: + if a.name == "source": + raise SyntaxError(f"Nested HogQLX tags cannot have a source attribute") + attributes.append(ast.HogQLXAttribute(name="source", value=source)) return ast.HogQLXTag(kind=opening, attributes=attributes) def visitHogqlxTagAttribute(self, ctx: HogQLParser.HogqlxTagAttributeContext): diff --git a/posthog/hogql/property.py b/posthog/hogql/property.py index 0cb47431844de..52236b64fb6dd 100644 --- a/posthog/hogql/property.py +++ b/posthog/hogql/property.py @@ -1,4 +1,5 @@ -from typing import Literal, Optional, cast +import re +from typing import Literal, Optional, Union, cast from pydantic import BaseModel @@ -21,28 +22,16 @@ Team, ) from posthog.models.event import Selector -from posthog.models.element import Element -from posthog.models.property import PropertyGroup, ValueT +from posthog.models.property import PropertyGroup from posthog.models.property.util import build_selector_regex from posthog.models.property_definition import PropertyType from posthog.schema import ( + EmptyPropertyFilter, FilterLogicalOperator, PropertyGroupFilter, PropertyGroupFilterValue, PropertyOperator, RetentionEntity, - EventPropertyFilter, - PersonPropertyFilter, - ElementPropertyFilter, - SessionPropertyFilter, - CohortPropertyFilter, - RecordingPropertyFilter, - GroupPropertyFilter, - FeaturePropertyFilter, - HogQLPropertyFilter, - EmptyPropertyFilter, - DataWarehousePropertyFilter, - DataWarehousePersonPropertyFilter, ) from posthog.warehouse.models import DataWarehouseJoin, DataWarehouseSavedQuery, DataWarehouseTable from posthog.utils import get_from_dict_or_attr @@ -78,194 +67,8 @@ def visit_call(self, node: ast.Call): self.visit(arg) -def _handle_bool_values(value: ValueT, field: ast.Field, property: Property, team: Team) -> ValueT | bool: - if value != "true" and value != "false": - return value - if property.type == "person": - property_types = PropertyDefinition.objects.filter( - team=team, - name=property.key, - type=PropertyDefinition.Type.PERSON, - ) - elif property.type == "group": - property_types = PropertyDefinition.objects.filter( - team=team, - name=property.key, - type=PropertyDefinition.Type.GROUP, - group_type_index=property.group_type_index, - ) - elif property.type == "data_warehouse_person_property": - key = field.chain[-2] - - # TODO: pass id of table item being filtered on instead of searching through joins - current_join: DataWarehouseJoin | None = ( - DataWarehouseJoin.objects.filter(Q(deleted__isnull=True) | Q(deleted=False)) - .filter(team=team, source_table_name="persons", field_name=key) - .first() - ) - - if not current_join: - raise Exception(f"Could not find join for key {key}") - - prop_type = None - - maybe_view = ( - DataWarehouseSavedQuery.objects.filter(Q(deleted__isnull=True) | Q(deleted=False)) - .filter(team=team, name=current_join.joining_table_name) - .first() - ) - - if maybe_view: - prop_type_dict = maybe_view.columns.get(property.key, None) - prop_type = prop_type_dict.get("hogql") - - maybe_table = ( - DataWarehouseTable.objects.filter(Q(deleted__isnull=True) | Q(deleted=False)) - .filter(team=team, name=current_join.joining_table_name) - .first() - ) - - if maybe_table: - prop_type_dict = maybe_table.columns.get(property.key, None) - prop_type = prop_type_dict.get("hogql") - - if not maybe_view and not maybe_table: - raise Exception(f"Could not find table or view for key {key}") - - if prop_type == "BooleanDatabaseField": - if value == "true": - value = True - if value == "false": - value = False - - return value - - else: - property_types = PropertyDefinition.objects.filter( - team=team, - name=property.key, - type=PropertyDefinition.Type.EVENT, - ) - property_type = property_types[0].property_type if len(property_types) > 0 else None - - if property_type == PropertyType.Boolean: - if value == "true": - return True - if value == "false": - return False - return value - - -def _field_to_compare_op( - field: ast.Field, value: ValueT, operator: PropertyOperator, property: Property, is_json_field: bool, team: Team -) -> ast.Expr: - if operator == PropertyOperator.IS_SET: - return ast.CompareOperation( - op=ast.CompareOperationOp.NotEq, - left=field, - right=ast.Constant(value=None), - ) - elif operator == PropertyOperator.IS_NOT_SET: - return ast.Or( - exprs=[ - ast.CompareOperation( - op=ast.CompareOperationOp.Eq, - left=field, - right=ast.Constant(value=None), - ) - ] - + ( - [ - ast.Not( - expr=ast.Call( - name="JSONHas", - args=[ast.Field(chain=field.chain[:-1]), ast.Constant(value=property.key)], - ) - ) - ] - if is_json_field - else [] - ) - ) - elif operator == PropertyOperator.ICONTAINS: - return ast.CompareOperation( - op=ast.CompareOperationOp.ILike, - left=field, - right=ast.Constant(value=f"%{value}%"), - ) - elif operator == PropertyOperator.NOT_ICONTAINS: - return ast.CompareOperation( - op=ast.CompareOperationOp.NotILike, - left=field, - right=ast.Constant(value=f"%{value}%"), - ) - elif operator == PropertyOperator.REGEX: - return ast.Call( - name="ifNull", - args=[ - ast.Call(name="match", args=[ast.Call(name="toString", args=[field]), ast.Constant(value=value)]), - ast.Constant(value=0), - ], - ) - elif operator == PropertyOperator.NOT_REGEX: - return ast.Call( - name="ifNull", - args=[ - ast.Call( - name="not", - args=[ - ast.Call( - name="match", args=[ast.Call(name="toString", args=[field]), ast.Constant(value=value)] - ) - ], - ), - ast.Constant(value=1), - ], - ) - elif operator == PropertyOperator.EXACT or operator == PropertyOperator.IS_DATE_EXACT: - return ast.CompareOperation( - op=ast.CompareOperationOp.Eq, - left=field, - right=ast.Constant(value=_handle_bool_values(value, field, property, team)), - ) - elif operator == PropertyOperator.IS_NOT: - return ast.CompareOperation( - op=ast.CompareOperationOp.NotEq, - left=field, - right=ast.Constant(value=_handle_bool_values(value, field, property, team)), - ) - elif operator == PropertyOperator.LT or operator == PropertyOperator.IS_DATE_BEFORE: - return ast.CompareOperation(op=ast.CompareOperationOp.Lt, left=field, right=ast.Constant(value=value)) - elif operator == PropertyOperator.GT or operator == PropertyOperator.IS_DATE_AFTER: - return ast.CompareOperation(op=ast.CompareOperationOp.Gt, left=field, right=ast.Constant(value=value)) - elif operator == PropertyOperator.LTE: - return ast.CompareOperation(op=ast.CompareOperationOp.LtEq, left=field, right=ast.Constant(value=value)) - elif operator == PropertyOperator.GTE: - return ast.CompareOperation(op=ast.CompareOperationOp.GtEq, left=field, right=ast.Constant(value=value)) - else: - raise NotImplementedError(f"PropertyOperator {operator} not implemented") - - def property_to_expr( - property: list - | dict - | PropertyGroup - | PropertyGroupFilter - | PropertyGroupFilterValue - | Property - | ast.Expr - | EventPropertyFilter - | PersonPropertyFilter - | ElementPropertyFilter - | SessionPropertyFilter - | CohortPropertyFilter - | RecordingPropertyFilter - | GroupPropertyFilter - | FeaturePropertyFilter - | HogQLPropertyFilter - | EmptyPropertyFilter - | DataWarehousePropertyFilter - | DataWarehousePersonPropertyFilter, + property: Union[BaseModel, PropertyGroup, Property, dict, list, ast.Expr], team: Team, scope: Literal["event", "person", "session", "replay", "replay_entity", "replay_pdi"] = "event", ) -> ast.Expr: @@ -367,11 +170,16 @@ def property_to_expr( else: chain = ["properties"] + if property.type == "session": + properties_field = None + else: + properties_field = ast.Field(chain=chain) + field = ast.Field(chain=[*chain, property.key]) if isinstance(value, list): if len(value) == 0: - return ast.Constant(value=1) + return ast.Constant(value=True) elif len(value) == 1: value = value[0] else: @@ -398,14 +206,164 @@ def property_to_expr( return ast.And(exprs=exprs) return ast.Or(exprs=exprs) - return _field_to_compare_op( - field=field, - value=value, - operator=operator, - team=team, - property=property, - is_json_field=property.type != "session", - ) + if operator == PropertyOperator.IS_SET: + return ast.CompareOperation( + op=ast.CompareOperationOp.NotEq, + left=field, + right=ast.Constant(value=None), + ) + elif operator == PropertyOperator.IS_NOT_SET: + return ast.Or( + exprs=[ + ast.CompareOperation( + op=ast.CompareOperationOp.Eq, + left=field, + right=ast.Constant(value=None), + ) + ] + + ( + [] + if not properties_field or properties_field == field + else [ + ast.Not( + expr=ast.Call( + name="JSONHas", + args=[properties_field, ast.Constant(value=property.key)], + ) + ) + ] + ) + ) + elif operator == PropertyOperator.ICONTAINS: + return ast.CompareOperation( + op=ast.CompareOperationOp.ILike, + left=field, + right=ast.Constant(value=f"%{value}%"), + ) + elif operator == PropertyOperator.NOT_ICONTAINS: + return ast.CompareOperation( + op=ast.CompareOperationOp.NotILike, + left=field, + right=ast.Constant(value=f"%{value}%"), + ) + elif operator == PropertyOperator.REGEX: + return ast.Call( + name="ifNull", + args=[ + ast.Call(name="match", args=[ast.Call(name="toString", args=[field]), ast.Constant(value=value)]), + ast.Constant(value=0), + ], + ) + elif operator == PropertyOperator.NOT_REGEX: + return ast.Call( + name="ifNull", + args=[ + ast.Call( + name="not", + args=[ + ast.Call( + name="match", args=[ast.Call(name="toString", args=[field]), ast.Constant(value=value)] + ) + ], + ), + ast.Constant(value=1), + ], + ) + elif operator == PropertyOperator.EXACT or operator == PropertyOperator.IS_DATE_EXACT: + op = ast.CompareOperationOp.Eq + elif operator == PropertyOperator.IS_NOT: + op = ast.CompareOperationOp.NotEq + elif operator == PropertyOperator.LT or operator == PropertyOperator.IS_DATE_BEFORE: + op = ast.CompareOperationOp.Lt + elif operator == PropertyOperator.GT or operator == PropertyOperator.IS_DATE_AFTER: + op = ast.CompareOperationOp.Gt + elif operator == PropertyOperator.LTE: + op = ast.CompareOperationOp.LtEq + elif operator == PropertyOperator.GTE: + op = ast.CompareOperationOp.GtEq + else: + raise NotImplementedError(f"PropertyOperator {operator} not implemented") + + # For Boolean and untyped properties, treat "true" and "false" as boolean values + if ( + (op == ast.CompareOperationOp.Eq or op == ast.CompareOperationOp.NotEq) + and team is not None + and (value == "true" or value == "false") + ): + if property.type == "person": + property_types = PropertyDefinition.objects.filter( + team=team, + name=property.key, + type=PropertyDefinition.Type.PERSON, + ) + elif property.type == "group": + property_types = PropertyDefinition.objects.filter( + team=team, + name=property.key, + type=PropertyDefinition.Type.GROUP, + group_type_index=property.group_type_index, + ) + elif property.type == "data_warehouse_person_property": + key = chain[-1] + + # TODO: pass id of table item being filtered on instead of searching through joins + current_join: DataWarehouseJoin | None = ( + DataWarehouseJoin.objects.filter(Q(deleted__isnull=True) | Q(deleted=False)) + .filter(team=team, source_table_name="persons", field_name=key) + .first() + ) + + if not current_join: + raise Exception(f"Could not find join for key {key}") + + prop_type = None + + maybe_view = ( + DataWarehouseSavedQuery.objects.filter(Q(deleted__isnull=True) | Q(deleted=False)) + .filter(team=team, name=current_join.joining_table_name) + .first() + ) + + if maybe_view: + prop_type_dict = maybe_view.columns.get(property.key, None) + prop_type = prop_type_dict.get("hogql") + + maybe_table = ( + DataWarehouseTable.objects.filter(Q(deleted__isnull=True) | Q(deleted=False)) + .filter(team=team, name=current_join.joining_table_name) + .first() + ) + + if maybe_table: + prop_type_dict = maybe_table.columns.get(property.key, None) + prop_type = prop_type_dict.get("hogql") + + if not maybe_view and not maybe_table: + raise Exception(f"Could not find table or view for key {key}") + + if prop_type == "BooleanDatabaseField": + if value == "true": + value = True + if value == "false": + value = False + + return ast.CompareOperation(op=op, left=field, right=ast.Constant(value=value)) + + else: + property_types = PropertyDefinition.objects.filter( + team=team, + name=property.key, + type=PropertyDefinition.Type.EVENT, + ) + property_type = property_types[0].property_type if len(property_types) > 0 else None + + if property_type == PropertyType.Boolean: + if value == "true": + value = True + if value == "false": + value = False + + return ast.CompareOperation(op=op, left=field, right=ast.Constant(value=value)) elif property.type == "element": if scope == "person": @@ -449,34 +407,10 @@ def property_to_expr( return expr if property.key == "href": - return parse_expr( - "arrayExists(href -> {compare}, elements_chain_hrefs)", - { - "compare": _field_to_compare_op( - field=ast.Field(chain=["href"]), - value=value, - operator=operator, - team=team, - property=property, - is_json_field=False, - ) - }, - ) + return element_chain_key_filter("href", str(value), operator) if property.key == "text": - return parse_expr( - "arrayExists(text -> {compare}, elements_chain_texts)", - { - "compare": _field_to_compare_op( - field=ast.Field(chain=["text"]), - value=value, - operator=operator, - team=team, - property=property, - is_json_field=False, - ) - }, - ) + return element_chain_key_filter("text", str(value), operator) raise NotImplementedError(f"property_to_expr for type element not implemented for key {property.key}") elif property.type == "cohort" or property.type == "static-cohort" or property.type == "precalculated-cohort": @@ -515,49 +449,21 @@ def action_to_expr(action: Action) -> ast.Expr: exprs.append(tag_name_to_expr(step.tag_name)) if step.href is not None: if step.href_matching == "regex": - exprs.append( - ast.CompareOperation( - op=ast.CompareOperationOp.Regex, - left=ast.Field(chain=["elements_chain_href"]), - right=ast.Constant(value=step.href), - ) - ) + operator = PropertyOperator.REGEX elif step.href_matching == "contains": - exprs.append( - ast.CompareOperation( - op=ast.CompareOperationOp.ILike, - left=ast.Field(chain=["elements_chain_href"]), - right=ast.Constant(value=f"%{step.href}%"), - ) - ) + operator = PropertyOperator.ICONTAINS else: - exprs.append( - ast.CompareOperation( - op=ast.CompareOperationOp.Eq, - left=ast.Field(chain=["elements_chain_href"]), - right=ast.Constant(value=step.href), - ) - ) + operator = PropertyOperator.EXACT + exprs.append(element_chain_key_filter("href", step.href, operator)) if step.text is not None: - value = step.text if step.text_matching == "regex": - match = ast.CompareOperationOp.Regex + operator = PropertyOperator.REGEX elif step.text_matching == "contains": - match = ast.CompareOperationOp.ILike - value = f"%{value}%" + operator = PropertyOperator.ICONTAINS else: - match = ast.CompareOperationOp.Eq - - exprs.append( - parse_expr( - "arrayExists(x -> {match}, elements_chain_texts)", - { - "match": ast.CompareOperation( - op=match, left=ast.Field(chain=["x"]), right=ast.Constant(value=value) - ) - }, - ) - ) + operator = PropertyOperator.EXACT + exprs.append(element_chain_key_filter("text", step.text, operator)) + if step.url: if step.url_matching == "exact": expr = parse_expr( @@ -606,41 +512,45 @@ def entity_to_expr(entity: RetentionEntity) -> ast.Expr: ) +def element_chain_key_filter(key: str, text: str, operator: PropertyOperator): + escaped = text.replace('"', r"\"") + if operator == PropertyOperator.IS_SET or operator == PropertyOperator.IS_NOT_SET: + value = r'[^"]+' + elif operator == PropertyOperator.ICONTAINS or operator == PropertyOperator.NOT_ICONTAINS: + value = rf'[^"]*{re.escape(escaped)}[^"]*' + elif operator == PropertyOperator.REGEX or operator == PropertyOperator.NOT_REGEX: + value = escaped + elif operator == PropertyOperator.EXACT or operator == PropertyOperator.IS_NOT: + value = re.escape(escaped) + else: + raise NotImplementedError(f"element_href_to_expr not implemented for operator {operator}") + + regex = f'({key}="{value}")' + if operator == PropertyOperator.ICONTAINS or operator == PropertyOperator.NOT_ICONTAINS: + expr = parse_expr("elements_chain =~* {regex}", {"regex": ast.Constant(value=str(regex))}) + else: + expr = parse_expr("elements_chain =~ {regex}", {"regex": ast.Constant(value=str(regex))}) + + if ( + operator == PropertyOperator.IS_NOT_SET + or operator == PropertyOperator.NOT_ICONTAINS + or operator == PropertyOperator.IS_NOT + or operator == PropertyOperator.NOT_REGEX + ): + expr = ast.Call(name="not", args=[expr]) + return expr + + def tag_name_to_expr(tag_name: str): regex = rf"(^|;){tag_name}(\.|$|;|:)" expr = parse_expr("elements_chain =~ {regex}", {"regex": ast.Constant(value=str(regex))}) return expr -def selector_to_expr(selector_string: str): - selector = Selector(selector_string, escape_slashes=False) - exprs = [] - regex = build_selector_regex(selector) - exprs.append(parse_expr("elements_chain =~ {regex}", {"regex": ast.Constant(value=regex)})) - - useful_elements: list[ast.Expr] = [] - for part in selector.parts: - if "tag_name" in part.data: - if part.data["tag_name"] in Element.USEFUL_ELEMENTS: - useful_elements.append(ast.Constant(value=part.data["tag_name"])) - - if "attr_id" in part.data: - exprs.append( - parse_expr( - "indexOf(elements_chain_ids, {value}) > 0", {"value": ast.Constant(value=part.data["attr_id"])} - ) - ) - if len(useful_elements) > 0: - exprs.append( - parse_expr( - "arrayCount(x -> x IN {value}, elements_chain_elements) > 0", - {"value": ast.Array(exprs=useful_elements)}, - ) - ) - - if len(exprs) == 1: - return exprs[0] - return ast.And(exprs=exprs) +def selector_to_expr(selector: str): + regex = build_selector_regex(Selector(selector, escape_slashes=False)) + expr = parse_expr("elements_chain =~ {regex}", {"regex": ast.Constant(value=regex)}) + return expr def get_property_type(property): diff --git a/posthog/hogql/test/__snapshots__/test_resolver.ambr b/posthog/hogql/test/__snapshots__/test_resolver.ambr index 9907d46ee7f89..d7d042252c55d 100644 --- a/posthog/hogql/test/__snapshots__/test_resolver.ambr +++ b/posthog/hogql/test/__snapshots__/test_resolver.ambr @@ -32,10 +32,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -124,34 +120,6 @@ table_type: } }, - elements_chain_elements: { - alias: "elements_chain_elements" - type: { - name: "elements_chain_elements" - table_type: - } - }, - elements_chain_href: { - alias: "elements_chain_href" - type: { - name: "elements_chain_href" - table_type: - } - }, - elements_chain_ids: { - alias: "elements_chain_ids" - type: { - name: "elements_chain_ids" - table_type: - } - }, - elements_chain_texts: { - alias: "elements_chain_texts" - type: { - name: "elements_chain_texts" - table_type: - } - }, event: { alias: "event" type: { @@ -414,74 +382,6 @@ alias: "$group_4" type: } - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: { - name: "elements_chain_href" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_href" - type: - } - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: { - name: "elements_chain_texts" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_texts" - type: - } - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: { - name: "elements_chain_ids" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_ids" - type: - } - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: { - name: "elements_chain_elements" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_elements" - type: - } } ] select_from: { @@ -640,50 +540,6 @@ } hidden: True type: - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: - } - hidden: True - type: - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: - } - hidden: True - type: - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: - } - hidden: True - type: - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: - } - hidden: True - type: } ] select_from: { @@ -715,10 +571,6 @@ created_at: , distinct_id: , elements_chain: , - elements_chain_elements: , - elements_chain_href: , - elements_chain_ids: , - elements_chain_texts: , event: , properties: , timestamp: , @@ -755,10 +607,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -1011,74 +859,6 @@ alias: "$group_4" type: } - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: { - name: "elements_chain_href" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_href" - type: - } - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: { - name: "elements_chain_texts" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_texts" - type: - } - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: { - name: "elements_chain_ids" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_ids" - type: - } - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: { - name: "elements_chain_elements" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_elements" - type: - } } ] select_from: { @@ -1104,10 +884,6 @@ created_at: , distinct_id: , elements_chain: , - elements_chain_elements: , - elements_chain_href: , - elements_chain_ids: , - elements_chain_texts: , event: , properties: , timestamp: , @@ -1154,10 +930,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -1246,34 +1018,6 @@ table_type: } }, - elements_chain_elements: { - alias: "elements_chain_elements" - type: { - name: "elements_chain_elements" - table_type: - } - }, - elements_chain_href: { - alias: "elements_chain_href" - type: { - name: "elements_chain_href" - table_type: - } - }, - elements_chain_ids: { - alias: "elements_chain_ids" - type: { - name: "elements_chain_ids" - table_type: - } - }, - elements_chain_texts: { - alias: "elements_chain_texts" - type: { - name: "elements_chain_texts" - table_type: - } - }, event: { alias: "event" type: { @@ -1536,74 +1280,6 @@ alias: "$group_4" type: } - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: { - name: "elements_chain_href" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_href" - type: - } - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: { - name: "elements_chain_texts" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_texts" - type: - } - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: { - name: "elements_chain_ids" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_ids" - type: - } - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: { - name: "elements_chain_elements" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_elements" - type: - } } ] select_from: { @@ -1764,50 +1440,6 @@ } hidden: True type: - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: - } - hidden: True - type: - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: - } - hidden: True - type: - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: - } - hidden: True - type: - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: - } - hidden: True - type: } ] select_from: { @@ -1844,10 +1476,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -2099,74 +1727,6 @@ alias: "$group_4" type: } - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: { - name: "elements_chain_href" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_href" - type: - } - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: { - name: "elements_chain_texts" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_texts" - type: - } - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: { - name: "elements_chain_ids" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_ids" - type: - } - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: { - name: "elements_chain_elements" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_elements" - type: - } } ] select_from: { @@ -2192,10 +1752,6 @@ created_at: , distinct_id: , elements_chain: , - elements_chain_elements: , - elements_chain_href: , - elements_chain_ids: , - elements_chain_texts: , event: , properties: , timestamp: , @@ -2233,10 +1789,6 @@ created_at: , distinct_id: , elements_chain: , - elements_chain_elements: , - elements_chain_href: , - elements_chain_ids: , - elements_chain_texts: , event: , properties: , timestamp: , @@ -2485,10 +2037,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -2740,74 +2288,6 @@ alias: "$group_4" type: } - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: { - name: "elements_chain_href" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_href" - type: - } - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: { - name: "elements_chain_texts" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_texts" - type: - } - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: { - name: "elements_chain_ids" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_ids" - type: - } - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: { - name: "elements_chain_elements" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_elements" - type: - } } ] select_from: { @@ -2833,10 +2313,6 @@ created_at: , distinct_id: , elements_chain: , - elements_chain_elements: , - elements_chain_href: , - elements_chain_ids: , - elements_chain_texts: , event: , properties: , timestamp: , @@ -2877,10 +2353,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -3133,74 +2605,6 @@ alias: "$group_4" type: } - }, - { - alias: "elements_chain_href" - expr: { - chain: [ - "elements_chain_href" - ] - type: { - name: "elements_chain_href" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_href" - type: - } - }, - { - alias: "elements_chain_texts" - expr: { - chain: [ - "elements_chain_texts" - ] - type: { - name: "elements_chain_texts" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_texts" - type: - } - }, - { - alias: "elements_chain_ids" - expr: { - chain: [ - "elements_chain_ids" - ] - type: { - name: "elements_chain_ids" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_ids" - type: - } - }, - { - alias: "elements_chain_elements" - expr: { - chain: [ - "elements_chain_elements" - ] - type: { - name: "elements_chain_elements" - table_type: - } - } - hidden: True - type: { - alias: "elements_chain_elements" - type: - } } ] select_from: { @@ -3227,10 +2631,6 @@ created_at: , distinct_id: , elements_chain: , - elements_chain_elements: , - elements_chain_href: , - elements_chain_ids: , - elements_chain_texts: , event: , properties: , timestamp: , @@ -3271,10 +2671,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -3374,10 +2770,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -3757,10 +3149,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -3894,10 +3282,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4035,10 +3419,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4212,10 +3592,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4394,10 +3770,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4529,10 +3901,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4665,10 +4033,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4788,10 +4152,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -4998,10 +4358,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -5096,10 +4452,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, @@ -5206,10 +4558,6 @@ created_at: {}, distinct_id: {}, elements_chain: {}, - elements_chain_elements: {}, - elements_chain_href: {}, - elements_chain_ids: {}, - elements_chain_texts: {}, event: {}, goe_0: {}, goe_1: {}, diff --git a/posthog/hogql/test/_test_parser.py b/posthog/hogql/test/_test_parser.py index 7de193fa458ff..e612a156762e6 100644 --- a/posthog/hogql/test/_test_parser.py +++ b/posthog/hogql/test/_test_parser.py @@ -1704,6 +1704,19 @@ def test_visit_hogqlx_tag_source(self): ], ) + def test_visit_hogqlx_tag_column_source(self): + query = """ + select {event} from events + """ + node = self._select(query) + assert isinstance(node, ast.SelectQuery) and cast(ast.HogQLXTag, node.select[0]) == ast.HogQLXTag( + kind="a", + attributes=[ + ast.HogQLXAttribute(name="href", value=Constant(value="https://google.com")), + ast.HogQLXAttribute(name="source", value=ast.Field(chain=["event"])), + ], + ) + def test_select_extract_as_function(self): node = self._select("select extract('string', 'other string') from events") diff --git a/posthog/hogql/test/test_property.py b/posthog/hogql/test/test_property.py index 5d51025fbe4e8..19b48e652808b 100644 --- a/posthog/hogql/test/test_property.py +++ b/posthog/hogql/test/test_property.py @@ -1,6 +1,4 @@ from typing import Union, cast, Optional, Any, Literal -from posthog.hogql.parser import parse_select -from posthog.hogql.query import execute_hogql_query from unittest.mock import MagicMock, patch from posthog.constants import PropertyOperatorType, TREND_FILTER_TYPE_ACTIONS, TREND_FILTER_TYPE_EVENTS @@ -8,6 +6,7 @@ from posthog.hogql.parser import parse_expr from posthog.hogql.property import ( action_to_expr, + element_chain_key_filter, has_aggregation, property_to_expr, selector_to_expr, @@ -24,8 +23,8 @@ ) from posthog.models.property import PropertyGroup from posthog.models.property_definition import PropertyType -from posthog.schema import HogQLPropertyFilter, RetentionEntity, EmptyPropertyFilter -from posthog.test.base import BaseTest, _create_event +from posthog.schema import HogQLPropertyFilter, PropertyOperator, RetentionEntity, EmptyPropertyFilter +from posthog.test.base import BaseTest from posthog.warehouse.models import DataWarehouseTable, DataWarehouseJoin, DataWarehouseCredential elements_chain_match = lambda x: parse_expr("elements_chain =~ {regex}", {"regex": ast.Constant(value=str(x))}) @@ -342,7 +341,7 @@ def test_property_to_expr_element(self): "operator": "exact", } ), - self._parse_expr("arrayExists(href -> href = 'href-text.', elements_chain_hrefs)"), + clear_locations(element_chain_key_filter("href", "href-text.", PropertyOperator.EXACT)), ) self.assertEqual( self._property_to_expr( @@ -353,9 +352,7 @@ def test_property_to_expr_element(self): "operator": "regex", } ), - self._parse_expr( - "arrayExists(text -> ifNull(match(toString(text), 'text-text.'), false), elements_chain_texts)" - ), + clear_locations(element_chain_key_filter("text", "text-text.", PropertyOperator.REGEX)), ) def test_property_groups(self): @@ -473,14 +470,7 @@ def test_selector_to_expr(self): self.assertEqual( self._selector_to_expr("a[href='boo']"), clear_locations( - parse_expr( - "{regex} and arrayCount(x -> x IN ['a'], elements_chain_elements) > 0", - { - "regex": elements_chain_match( - '(^|;)a.*?href="boo".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' - ) - }, - ) + elements_chain_match('(^|;)a.*?href="boo".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))') ), ) self.assertEqual( @@ -492,26 +482,14 @@ def test_selector_to_expr(self): self.assertEqual( self._selector_to_expr("#withid"), clear_locations( - parse_expr( - """{regex} and indexOf(elements_chain_ids, 'withid') > 0""", - { - "regex": elements_chain_match( - '(^|;).*?attr_id="withid".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' - ) - }, - ) + elements_chain_match('(^|;).*?attr_id="withid".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))') ), ) self.assertEqual( self._selector_to_expr("#with-dashed-id"), clear_locations( - parse_expr( - """{regex} and indexOf(elements_chain_ids, 'with-dashed-id') > 0""", - { - "regex": elements_chain_match( - '(^|;).*?attr_id="with\\-dashed\\-id".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' - ) - }, + elements_chain_match( + '(^|;).*?attr_id="with\\-dashed\\-id".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' ) ), ) @@ -522,55 +500,69 @@ def test_selector_to_expr(self): self.assertEqual( self._selector_to_expr("#with\\slashed\\id"), clear_locations( - parse_expr( - "{regex} and indexOf(elements_chain_ids, 'with\\\\slashed\\\\id') > 0", - { - "regex": elements_chain_match( - '(^|;).*?attr_id="with\\\\slashed\\\\id".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' - ) - }, + elements_chain_match( + '(^|;).*?attr_id="with\\\\slashed\\\\id".*?([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' ) ), ) - def test_action_to_expr(self): - _create_event( - event="$autocapture", team=self.team, distinct_id="some_id", elements_chain="a.active.nav-link:text='text'" + def test_elements_chain_key_filter(self): + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.IS_SET)), + clear_locations(elements_chain_match('(href="[^"]+")')), + ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.IS_NOT_SET)), + clear_locations(not_call(elements_chain_match('(href="[^"]+")'))), + ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.ICONTAINS)), + clear_locations(elements_chain_imatch('(href="[^"]*boo\\.\\.[^"]*")')), + ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.NOT_ICONTAINS)), + clear_locations(not_call(elements_chain_imatch('(href="[^"]*boo\\.\\.[^"]*")'))), + ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.REGEX)), + clear_locations(elements_chain_match('(href="boo..")')), + ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.NOT_REGEX)), + clear_locations(not_call(elements_chain_match('(href="boo..")'))), ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.EXACT)), + clear_locations(elements_chain_match('(href="boo\\.\\.")')), + ) + self.assertEqual( + clear_locations(element_chain_key_filter("href", "boo..", PropertyOperator.IS_NOT)), + clear_locations(not_call(elements_chain_match('(href="boo\\.\\.")'))), + ) + + def test_action_to_expr(self): action1 = Action.objects.create( team=self.team, steps_json=[ { "event": "$autocapture", "selector": "a.nav-link.active", + "tag_name": "a", } ], ) self.assertEqual( clear_locations(action_to_expr(action1)), self._parse_expr( - "event = '$autocapture' and {regex1}", + "event = '$autocapture' and elements_chain =~ {regex1} and elements_chain =~ {regex2}", { - "regex1": ast.And( - exprs=[ - self._parse_expr( - "elements_chain =~ {regex}", - { - "regex": ast.Constant( - value='(^|;)a.*?\\.active\\..*?nav\\-link([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' - ) - }, - ), - self._parse_expr("arrayCount(x -> x IN ['a'], elements_chain_elements) > 0"), - ] + "regex1": ast.Constant( + value='(^|;)a.*?\\.active\\..*?nav\\-link([-_a-zA-Z0-9\\.:"= ]*?)?($|;|:([^;^\\s]*(;|$|\\s)))' ), + "regex2": ast.Constant(value="(^|;)a(\\.|$|;|:)"), }, ), ) - resp = execute_hogql_query( - parse_select("select count() from events where {prop}", {"prop": action_to_expr(action1)}), self.team - ) - self.assertEqual(resp.results[0][0], 1) action2 = Action.objects.create( team=self.team, @@ -619,24 +611,6 @@ def test_action_to_expr(self): self._parse_expr("event = '$pageview' OR true"), # All events just resolve to "true" ) - action5 = Action.objects.create( - team=self.team, - steps_json=[{"event": "$autocapture", "href": "https://example4.com", "href_matching": "regex"}], - ) - self.assertEqual( - clear_locations(action_to_expr(action5)), - self._parse_expr("event = '$autocapture' and elements_chain_href =~ 'https://example4.com'"), - ) - - action6 = Action.objects.create( - team=self.team, - steps_json=[{"event": "$autocapture", "text": "blabla", "text_matching": "regex"}], - ) - self.assertEqual( - clear_locations(action_to_expr(action6)), - self._parse_expr("event = '$autocapture' and arrayExists(x -> x =~ 'blabla', elements_chain_texts)"), - ) - def test_cohort_filter_static(self): cohort = Cohort.objects.create( team=self.team, diff --git a/posthog/hogql_queries/insights/funnels/test/__snapshots__/test_funnel.ambr b/posthog/hogql_queries/insights/funnels/test/__snapshots__/test_funnel.ambr index d733159ba5ee0..9822999809a62 100644 --- a/posthog/hogql_queries/insights/funnels/test/__snapshots__/test_funnel.ambr +++ b/posthog/hogql_queries/insights/funnels/test/__snapshots__/test_funnel.ambr @@ -317,9 +317,9 @@ if(not(empty(e__override.distinct_id)), e__override.person_id, e.person_id) AS aggregation_target, if(equals(e.event, 'user signed up'), 1, 0) AS step_0, if(ifNull(equals(step_0, 1), 0), timestamp, NULL) AS latest_0, - if(and(equals(e.event, '$autocapture'), match(e.elements_chain, '(^|;)button(\\.|$|;|:)'), arrayExists(x -> ifNull(equals(x, 'Pay $10'), 0), e.elements_chain_texts)), 1, 0) AS step_1, + if(and(equals(e.event, '$autocapture'), match(e.elements_chain, '(^|;)button(\\.|$|;|:)'), match(e.elements_chain, '(text="Pay\\ \\$10")')), 1, 0) AS step_1, if(ifNull(equals(step_1, 1), 0), timestamp, NULL) AS latest_1, - if(and(equals(e.event, '$autocapture'), match(e.elements_chain, '(^|;)a(\\.|$|;|:)'), equals(e.elements_chain_href, '/movie')), 1, 0) AS step_2, + if(and(equals(e.event, '$autocapture'), match(e.elements_chain, '(^|;)a(\\.|$|;|:)'), match(e.elements_chain, '(href="/movie")')), 1, 0) AS step_2, if(ifNull(equals(step_2, 1), 0), timestamp, NULL) AS latest_2 FROM events AS e LEFT OUTER JOIN diff --git a/posthog/management/commands/change_plugin_config_referenced_plugin.py b/posthog/management/commands/change_plugin_config_referenced_plugin.py new file mode 100644 index 0000000000000..79b4704faf19f --- /dev/null +++ b/posthog/management/commands/change_plugin_config_referenced_plugin.py @@ -0,0 +1,38 @@ +import time +from django.core.management.base import BaseCommand +from posthog.models import PluginConfig, Plugin + + +class Command(BaseCommand): + help = "Set the plugin_id of a given config or set of configs to something else" + + def add_arguments(self, parser): + parser.add_argument("config_ids", type=str, help="Plugin config ID or list of ID's, separated by commas") + parser.add_argument("new_plugin_id", type=int, help="New Plugin ID") + parser.add_argument("--dry-run", type=bool, help="Print information instead of storing it") + + def handle(self, *args, **options): + dry_run = options["dry_run"] + config_ids = options["config_ids"] + new_plugin_id = options["new_plugin_id"] + + if "," in config_ids: + config_ids = {int(x) for x in config_ids.split(",")} + else: + config_ids = {int(config_ids)} + + new_plugin = Plugin.objects.get(id=new_plugin_id) + found_configs = PluginConfig.objects.filter(id__in=config_ids) + + existing_plugins = [(config.id, Plugin.objects.get(id=config.plugin_id).name) for config in found_configs] + + print(f"Going to update {len(found_configs)} rows, setting plugin_id to {new_plugin_id} ({new_plugin.name})") # noqa T201 + print(f"Current plugins (config_id, plugin_name) - MAKE SURE THESE MAKE SENSE: {existing_plugins}") # noqa T201 + print("Sleeping for 10 seconds, now is your chance to cancel") # noqa T201 + time.sleep(10) + print("Starting") # noqa T201 + if not dry_run: + updated = found_configs.update(plugin=new_plugin) + print(f"Updated {updated} rows") # noqa T201 + else: + print(f"Would update {len(config_ids)} rows") # noqa T201 diff --git a/posthog/models/event/sql.py b/posthog/models/event/sql.py index 8219bece6572b..33e7d2a2c3062 100644 --- a/posthog/models/event/sql.py +++ b/posthog/models/event/sql.py @@ -65,10 +65,6 @@ , $group_4 VARCHAR MATERIALIZED {trim_quotes_expr("JSONExtractRaw(properties, '$group_4')")} COMMENT 'column_materializer::$group_4' , $window_id VARCHAR MATERIALIZED {trim_quotes_expr("JSONExtractRaw(properties, '$window_id')")} COMMENT 'column_materializer::$window_id' , $session_id VARCHAR MATERIALIZED {trim_quotes_expr("JSONExtractRaw(properties, '$session_id')")} COMMENT 'column_materializer::$session_id' - , elements_chain_href String MATERIALIZED extract(elements_chain, '(?::|\")href="(.*?)"') - , elements_chain_texts Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|\")text="(.*?)"')) - , elements_chain_ids Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|\")attr_id="(.*?)"')) - , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?:^|;)(a|button|form|input|select|textarea|label)(?:\\.|$|:)')) , INDEX `minmax_$group_0` `$group_0` TYPE minmax GRANULARITY 1 , INDEX `minmax_$group_1` `$group_1` TYPE minmax GRANULARITY 1 , INDEX `minmax_$group_2` `$group_2` TYPE minmax GRANULARITY 1 @@ -76,6 +72,10 @@ , INDEX `minmax_$group_4` `$group_4` TYPE minmax GRANULARITY 1 , INDEX `minmax_$window_id` `$window_id` TYPE minmax GRANULARITY 1 , INDEX `minmax_$session_id` `$session_id` TYPE minmax GRANULARITY 1 + , elements_chain_href String MATERIALIZED extract(elements_chain, '(?::|\")href="(.*?)"') + , elements_chain_texts Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|\")text="(.*?)"')) + , elements_chain_ids Array(String) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?::|\")attr_id="(.*?)"')) + , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) MATERIALIZED arrayDistinct(extractAll(elements_chain, '(?:^|;)(a|button|form|input|select|textarea|label)(?:\\.|$|:)')) """ EVENTS_TABLE_PROXY_MATERIALIZED_COLUMNS = """ @@ -86,10 +86,6 @@ , $group_4 VARCHAR COMMENT 'column_materializer::$group_4' , $window_id VARCHAR COMMENT 'column_materializer::$window_id' , $session_id VARCHAR COMMENT 'column_materializer::$session_id' - , elements_chain_href String COMMENT 'column_materializer::elements_chain::href' - , elements_chain_texts Array(String) COMMENT 'column_materializer::elements_chain::texts' - , elements_chain_ids Array(String) COMMENT 'column_materializer::elements_chain::ids' - , elements_chain_elements Array(Enum('a', 'button', 'form', 'input', 'select', 'textarea', 'label')) COMMENT 'column_materializer::elements_chain::elements' """ EVENTS_DATA_TABLE_ENGINE = lambda: ReplacingMergeTree( diff --git a/posthog/models/event/util.py b/posthog/models/event/util.py index 609d7974f7cdd..8aa798cc12916 100644 --- a/posthog/models/event/util.py +++ b/posthog/models/event/util.py @@ -136,12 +136,8 @@ def bulk_create_events( timestamp = timestamp.astimezone(ZoneInfo("UTC")).strftime("%Y-%m-%d %H:%M:%S.%f") elements_chain = "" - if tentative_elements_chain := event.get("elements_chain"): - assert isinstance(tentative_elements_chain, str) - elements_chain = tentative_elements_chain - elif tentative_elements := event.get("elements"): - assert isinstance(tentative_elements, list) - elements_chain = elements_to_string(elements=tentative_elements) + if event.get("elements") and len(event["elements"]) > 0: + elements_chain = elements_to_string(elements=event.get("elements")) # type: ignore inserts.append( """( diff --git a/posthog/schema.py b/posthog/schema.py index 1c0e8a2a30670..bdd488c5306e5 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -844,7 +844,9 @@ class QueryStatus(BaseModel): ), ) dashboard_id: Optional[int] = None - end_time: Optional[AwareDatetime] = None + end_time: Optional[AwareDatetime] = Field( + default=None, description="When did the query execution task finish (whether successfully or not)." + ) error: Optional[bool] = Field( default=False, description=( @@ -856,10 +858,13 @@ class QueryStatus(BaseModel): id: str insight_id: Optional[int] = None labels: Optional[list[str]] = None + pickup_time: Optional[AwareDatetime] = Field( + default=None, description="When was the query execution task picked up by a worker." + ) query_async: Literal[True] = Field(default=True, description="ONLY async queries use QueryStatus.") query_progress: Optional[ClickhouseQueryProgress] = None results: Optional[Any] = None - start_time: Optional[AwareDatetime] = None + start_time: Optional[AwareDatetime] = Field(default=None, description="When was query execution task enqueued.") task_id: Optional[str] = None team_id: int diff --git a/posthog/test/base.py b/posthog/test/base.py index 6f23e9d8fbc05..6d1d608da930a 100644 --- a/posthog/test/base.py +++ b/posthog/test/base.py @@ -5,7 +5,6 @@ import threading import time import uuid -import unittest from collections.abc import Callable, Generator from contextlib import contextmanager from functools import wraps @@ -101,10 +100,6 @@ persons_ordering_int: int = 1 -# Expand string diffs -unittest.util._MAX_LENGTH = 2000 # type: ignore - - def _setup_test_data(klass): klass.organization = Organization.objects.create(name=klass.CONFIG_ORGANIZATION_NAME) klass.project, klass.team = Project.objects.create_with_team( diff --git a/requirements.in b/requirements.in index 9125c854e218b..c4c1e2358af9c 100644 --- a/requirements.in +++ b/requirements.in @@ -95,7 +95,7 @@ phonenumberslite==8.13.6 openai==1.10.0 tiktoken==0.6.0 nh3==0.2.14 -hogql-parser==1.0.30 +hogql-parser==1.0.32 zxcvbn==4.4.28 zstd==1.5.5.1 xmlsec==1.3.13 # Do not change this version - it will break SAML diff --git a/requirements.txt b/requirements.txt index a77665a2c80d2..70023bd9d8a9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -271,7 +271,7 @@ h11==0.13.0 # wsproto hexbytes==1.0.0 # via dlt -hogql-parser==1.0.30 +hogql-parser==1.0.32 # via -r requirements.in httpcore==1.0.2 # via httpx diff --git a/rust/hook-worker/src/worker.rs b/rust/hook-worker/src/worker.rs index 422030d2a48b5..678e866ad087c 100644 --- a/rust/hook-worker/src/worker.rs +++ b/rust/hook-worker/src/worker.rs @@ -7,7 +7,7 @@ use futures::channel::oneshot::Canceled; use futures::future::join_all; use health::HealthHandle; use http::StatusCode; -use rdkafka::error::KafkaError; +use rdkafka::error::{KafkaError, RDKafkaErrorCode}; use rdkafka::producer::{FutureProducer, FutureRecord}; use reqwest::{header, Client}; use serde_json::{json, Value}; @@ -278,6 +278,30 @@ async fn process_batch<'a>( headers: None, }) { Ok(future) => kafka_ack_futures.push(future), + Err(( + KafkaError::MessageProduction( + RDKafkaErrorCode::MessageSizeTooLarge, + ), + _, + )) => { + // HACK: While under development, we are dropping messages that + // are too large. This is temporary, as we expect the webhook + // handler for Hog to change soon. In the meantime, nobody needs + // to be alerted about this. + let team_id = metadata + .get("teamId") + .and_then(|t| t.as_number()) + .map(|t| t.to_string()) + .unwrap_or_else(|| "?".to_string()); + + let hog_function_id = metadata + .get("hogFunctionId") + .and_then(|h| h.as_str()) + .map(|h| h.to_string()) + .unwrap_or_else(|| "?".to_string()); + + error!("dropping message due to size limit, team_id: {}, hog_function_id: {}", team_id, hog_function_id); + } Err((error, _)) => { // Return early to avoid committing the batch. return log_kafka_error_and_sleep("send", Some(error)).await; @@ -928,6 +952,79 @@ mod tests { ); } + #[sqlx::test(migrations = "../migrations")] + async fn test_hoghook_drops_large_payloads(db: PgPool) { + use httpmock::prelude::*; + + let worker_id = worker_id(); + let queue_name = "test_hoghook_drops_large_payloads".to_string(); + let queue = PgQueue::new_from_pool(&queue_name, db).await; + let topic = "cdp_function_callbacks"; + + let server = MockServer::start(); + + server.mock(|when, then| { + when.method(POST).path("/"); + then.status(200) + .header("content-type", "application/json; charset=UTF-8") + .body(r#"{"message": "hello, world"}"#); + }); + + let mock_url = server.url("/"); + + let webhook_job_parameters = WebhookJobParameters { + body: "".to_owned(), + headers: collections::HashMap::new(), + method: HttpMethod::POST, + url: mock_url, + }; + + let webhook_job_metadata = json!({"hugeField": "a".repeat(2 * 1024 * 1024)}); + + enqueue_job( + &queue, + 1, + webhook_job_parameters.clone(), + serde_json::to_value(webhook_job_metadata).unwrap(), + ) + .await + .expect("failed to enqueue job"); + + let registry = HealthRegistry::new("liveness"); + let liveness = registry + .register("worker".to_string(), ::time::Duration::seconds(30)) + .await; + + let (_, mock_producer) = create_mock_kafka().await; + let hog_mode = true; + let worker = WebhookWorker::new( + &worker_id, + &queue, + 1, + time::Duration::from_millis(100), + time::Duration::from_millis(5000), + 10, + RetryPolicy::default(), + false, + mock_producer, + topic.to_string(), + hog_mode, + liveness, + ); + + let batch = worker.wait_for_jobs_tx().await; + + process_batch( + batch, + worker.http_client, + worker.retry_policy, + worker.kafka_producer, + worker.cdp_function_callbacks_topic, + hog_mode, + ) + .await; + } + #[tokio::test] async fn test_send_webhook() { let method = HttpMethod::POST;