A reverse proxy allows you to send events to PostHog Cloud using your own domain.
diff --git a/frontend/src/scenes/paths/pathsDataLogic.ts b/frontend/src/scenes/paths/pathsDataLogic.ts
index 750490efc64f4..67a2c3b7e9dd9 100644
--- a/frontend/src/scenes/paths/pathsDataLogic.ts
+++ b/frontend/src/scenes/paths/pathsDataLogic.ts
@@ -111,7 +111,8 @@ export const pathsDataLogic = kea([
],
hogQLInsightsPathsFlagEnabled: [
(s) => [s.featureFlags],
- (featureFlags) => !!featureFlags[FEATURE_FLAGS.HOGQL_INSIGHTS_PATHS],
+ (featureFlags) =>
+ !!(featureFlags[FEATURE_FLAGS.HOGQL_INSIGHTS] || featureFlags[FEATURE_FLAGS.HOGQL_INSIGHTS_PATHS]),
],
}),
diff --git a/frontend/src/scenes/retention/retentionModalLogic.ts b/frontend/src/scenes/retention/retentionModalLogic.ts
index 9aba029d17c2c..3310d730a1699 100644
--- a/frontend/src/scenes/retention/retentionModalLogic.ts
+++ b/frontend/src/scenes/retention/retentionModalLogic.ts
@@ -67,7 +67,11 @@ export const retentionModalLogic = kea([
exploreUrl: [
(s) => [s.actorsQuery, s.featureFlags],
(actorsQuery, featureFlags): string | null => {
- if (!actorsQuery || !featureFlags?.[FEATURE_FLAGS.HOGQL_INSIGHTS_RETENTION]) {
+ if (
+ !actorsQuery ||
+ (!featureFlags?.[FEATURE_FLAGS.HOGQL_INSIGHTS] &&
+ !featureFlags?.[FEATURE_FLAGS.HOGQL_INSIGHTS_RETENTION])
+ ) {
return null
}
const query: DataTableNode = {
diff --git a/frontend/src/scenes/retention/retentionPeopleLogic.ts b/frontend/src/scenes/retention/retentionPeopleLogic.ts
index 35daa1f0bd176..7bfd81aafe341 100644
--- a/frontend/src/scenes/retention/retentionPeopleLogic.ts
+++ b/frontend/src/scenes/retention/retentionPeopleLogic.ts
@@ -18,7 +18,10 @@ import type { retentionPeopleLogicType } from './retentionPeopleLogicType'
const DEFAULT_RETENTION_LOGIC_KEY = 'default_retention_key'
const hogQLInsightsRetentionFlagEnabled = (): boolean =>
- Boolean(featureFlagLogic.findMounted()?.values.featureFlags?.[FEATURE_FLAGS.HOGQL_INSIGHTS_RETENTION])
+ Boolean(
+ featureFlagLogic.findMounted()?.values.featureFlags?.[FEATURE_FLAGS.HOGQL_INSIGHTS] ||
+ featureFlagLogic.findMounted()?.values.featureFlags?.[FEATURE_FLAGS.HOGQL_INSIGHTS_RETENTION]
+ )
export const retentionPeopleLogic = kea([
props({} as InsightLogicProps),
diff --git a/frontend/src/scenes/sceneLogic.ts b/frontend/src/scenes/sceneLogic.ts
index 998726e131ec5..77b24b6407325 100644
--- a/frontend/src/scenes/sceneLogic.ts
+++ b/frontend/src/scenes/sceneLogic.ts
@@ -202,7 +202,7 @@ export const sceneLogic = kea([
!teamLogic.values.currentTeam.is_demo &&
!removeProjectIdIfPresent(location.pathname).startsWith(urls.onboarding('')) &&
!removeProjectIdIfPresent(location.pathname).startsWith(urls.products()) &&
- !removeProjectIdIfPresent(location.pathname).startsWith(urls.settings())
+ !removeProjectIdIfPresent(location.pathname).startsWith('/settings')
) {
const allProductUrls = Object.values(productUrlMapping).flat()
if (
diff --git a/frontend/src/scenes/session-recordings/player/rrweb/index.ts b/frontend/src/scenes/session-recordings/player/rrweb/index.ts
index 13efdc344b9cc..2739d32adfeca 100644
--- a/frontend/src/scenes/session-recordings/player/rrweb/index.ts
+++ b/frontend/src/scenes/session-recordings/player/rrweb/index.ts
@@ -1,5 +1,8 @@
import { playerConfig, ReplayPlugin } from 'rrweb/typings/types'
+export const PLACEHOLDER_SVG_DATA_IMAGE_URL =
+ 'url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNOCAwSDE2TDAgMTZWOEw4IDBaIiBmaWxsPSIjMkQyRDJEIi8+CjxwYXRoIGQ9Ik0xNiA4VjE2SDhMMTYgOFoiIGZpbGw9IiMyRDJEMkQiLz4KPC9zdmc+Cg==");'
+
const PROXY_URL = 'https://replay.ph-proxy.com' as const
export const CorsPlugin: ReplayPlugin & {
@@ -65,7 +68,5 @@ export const CorsPlugin: ReplayPlugin & {
export const COMMON_REPLAYER_CONFIG: Partial = {
triggerFocus: false,
- insertStyleRules: [
- `.ph-no-capture { background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNOCAwSDE2TDAgMTZWOEw4IDBaIiBmaWxsPSIjMkQyRDJEIi8+CjxwYXRoIGQ9Ik0xNiA4VjE2SDhMMTYgOFoiIGZpbGw9IiMyRDJEMkQiLz4KPC9zdmc+Cg=="); }`,
- ],
+ insertStyleRules: [`.ph-no-capture { background-image: ${PLACEHOLDER_SVG_DATA_IMAGE_URL} }`],
}
diff --git a/frontend/src/scenes/settings/user/UserDetails.tsx b/frontend/src/scenes/settings/user/UserDetails.tsx
index 587b54161b91d..b9ffad870537d 100644
--- a/frontend/src/scenes/settings/user/UserDetails.tsx
+++ b/frontend/src/scenes/settings/user/UserDetails.tsx
@@ -19,16 +19,25 @@ export function UserDetails(): JSX.Element {
maxWidth: '28rem',
}}
>
-
+
-
+
+
+
+
+
([
: null,
email: !email
? 'You need to have an email.'
- : first_name.length > 254
+ : email.length > 254
? 'This email is too long. Please keep it under 255 characters.'
: null,
}),
@@ -98,10 +98,12 @@ export const userLogic = kea([
{
loadUserSuccess: (_, { user }) => ({
first_name: user?.first_name || '',
+ last_name: user?.last_name || '',
email: user?.email || '',
}),
updateUserSuccess: (_, { user }) => ({
first_name: user?.first_name || '',
+ last_name: user?.last_name || '',
email: user?.email || '',
}),
},
diff --git a/frontend/src/toolbar/elements/heatmapLogic.ts b/frontend/src/toolbar/elements/heatmapLogic.ts
index de7232bd70dfd..45ec141630420 100644
--- a/frontend/src/toolbar/elements/heatmapLogic.ts
+++ b/frontend/src/toolbar/elements/heatmapLogic.ts
@@ -112,11 +112,8 @@ export const heatmapLogic = kea([
],
...values.heatmapFilter,
}
- const includeEventsParams = '&include=$autocapture&include=$rageclick'
- defaultUrl = `/api/element/stats/${encodeParams(
- { ...params, paginate_response: true },
- '?'
- )}${includeEventsParams}`
+
+ defaultUrl = `/api/element/stats/${encodeParams({ ...params, paginate_response: true }, '?')}`
}
// toolbar fetch collapses queryparams but this URL has multiple with the same name
diff --git a/hogql_parser/HogQLParser.cpp b/hogql_parser/HogQLParser.cpp
index f93862eec5c0d..de9386c795f09 100644
--- a/hogql_parser/HogQLParser.cpp
+++ b/hogql_parser/HogQLParser.cpp
@@ -127,7 +127,7 @@ void hogqlparserParserInitialize() {
}
);
static const int32_t serializedATNSegment[] = {
- 4,1,242,979,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,
+ 4,1,242,972,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,
@@ -171,319 +171,317 @@ void hogqlparserParserInitialize() {
5,36,535,8,36,10,36,12,36,538,9,36,1,37,1,37,1,37,3,37,543,8,37,1,37,
1,37,1,37,1,37,1,37,4,37,550,8,37,11,37,12,37,551,1,37,1,37,3,37,556,
8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,3,37,587,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,1,37,1,37,1,37,1,37,3,37,604,8,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,1,37,1,37,1,37,3,37,616,8,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,3,37,626,8,37,1,37,3,37,629,8,37,1,37,1,37,3,37,633,8,37,1,
- 37,3,37,636,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
- 37,3,37,649,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,3,37,666,8,37,1,37,1,37,3,37,670,8,37,1,37,1,37,
- 1,37,1,37,3,37,676,8,37,1,37,1,37,1,37,1,37,1,37,3,37,683,8,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,695,8,37,1,37,1,37,3,
- 37,699,8,37,1,37,3,37,702,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,
- 711,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 3,37,725,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 3,37,752,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,761,8,37,5,37,763,
- 8,37,10,37,12,37,766,9,37,1,38,1,38,1,38,5,38,771,8,38,10,38,12,38,774,
- 9,38,1,39,1,39,3,39,778,8,39,1,40,1,40,1,40,1,40,5,40,784,8,40,10,40,
- 12,40,787,9,40,1,40,1,40,1,40,1,40,1,40,5,40,794,8,40,10,40,12,40,797,
- 9,40,3,40,799,8,40,1,40,1,40,1,40,1,41,1,41,1,41,5,41,807,8,41,10,41,
- 12,41,810,9,41,1,41,1,41,1,41,1,41,1,41,1,41,5,41,818,8,41,10,41,12,41,
- 821,9,41,1,41,1,41,3,41,825,8,41,1,41,1,41,1,41,1,41,1,41,3,41,832,8,
- 41,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,3,42,845,8,
- 42,1,43,1,43,1,43,5,43,850,8,43,10,43,12,43,853,9,43,1,44,1,44,1,44,1,
- 44,1,44,1,44,1,44,1,44,1,44,1,44,3,44,865,8,44,1,45,1,45,1,45,1,45,3,
- 45,871,8,45,1,45,3,45,874,8,45,1,46,1,46,1,46,5,46,879,8,46,10,46,12,
- 46,882,9,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,3,47,893,8,47,
- 1,47,1,47,1,47,1,47,3,47,899,8,47,5,47,901,8,47,10,47,12,47,904,9,47,
- 1,48,1,48,1,48,3,48,909,8,48,1,48,1,48,1,49,1,49,1,49,3,49,916,8,49,1,
- 49,1,49,1,50,1,50,1,50,5,50,923,8,50,10,50,12,50,926,9,50,1,51,1,51,1,
- 52,1,52,1,52,1,52,1,52,1,52,3,52,936,8,52,3,52,938,8,52,1,53,3,53,941,
- 8,53,1,53,1,53,1,53,1,53,1,53,1,53,3,53,949,8,53,1,54,1,54,1,54,3,54,
- 954,8,54,1,55,1,55,1,56,1,56,1,57,1,57,1,58,1,58,3,58,964,8,58,1,59,1,
- 59,1,59,3,59,969,8,59,1,60,1,60,1,60,1,60,1,61,1,61,1,61,1,61,1,61,0,
- 3,36,74,94,62,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,
- 0,16,2,0,32,32,141,141,2,0,84,84,96,96,3,0,4,4,8,8,12,12,4,0,4,4,7,8,
- 12,12,147,147,2,0,96,96,140,140,2,0,4,4,8,8,2,0,11,11,42,43,2,0,62,62,
- 93,93,2,0,133,133,143,143,3,0,17,17,95,95,170,170,2,0,79,79,98,98,1,0,
- 197,198,2,0,208,208,228,228,8,0,37,37,76,76,108,108,110,110,132,132,145,
- 145,185,185,190,190,13,0,2,24,26,36,38,75,77,81,83,107,109,109,111,112,
- 114,115,117,130,133,144,146,184,186,189,191,192,4,0,36,36,62,62,77,77,
- 91,91,1107,0,127,1,0,0,0,2,131,1,0,0,0,4,146,1,0,0,0,6,149,1,0,0,0,8,
- 198,1,0,0,0,10,201,1,0,0,0,12,207,1,0,0,0,14,211,1,0,0,0,16,217,1,0,0,
- 0,18,235,1,0,0,0,20,238,1,0,0,0,22,241,1,0,0,0,24,251,1,0,0,0,26,254,
- 1,0,0,0,28,258,1,0,0,0,30,291,1,0,0,0,32,293,1,0,0,0,34,296,1,0,0,0,36,
- 311,1,0,0,0,38,373,1,0,0,0,40,378,1,0,0,0,42,389,1,0,0,0,44,391,1,0,0,
- 0,46,397,1,0,0,0,48,405,1,0,0,0,50,423,1,0,0,0,52,425,1,0,0,0,54,433,
- 1,0,0,0,56,438,1,0,0,0,58,446,1,0,0,0,60,450,1,0,0,0,62,454,1,0,0,0,64,
- 463,1,0,0,0,66,477,1,0,0,0,68,479,1,0,0,0,70,529,1,0,0,0,72,531,1,0,0,
- 0,74,669,1,0,0,0,76,767,1,0,0,0,78,777,1,0,0,0,80,798,1,0,0,0,82,831,
- 1,0,0,0,84,844,1,0,0,0,86,846,1,0,0,0,88,864,1,0,0,0,90,873,1,0,0,0,92,
- 875,1,0,0,0,94,892,1,0,0,0,96,905,1,0,0,0,98,915,1,0,0,0,100,919,1,0,
- 0,0,102,927,1,0,0,0,104,937,1,0,0,0,106,940,1,0,0,0,108,953,1,0,0,0,110,
- 955,1,0,0,0,112,957,1,0,0,0,114,959,1,0,0,0,116,963,1,0,0,0,118,968,1,
- 0,0,0,120,970,1,0,0,0,122,974,1,0,0,0,124,128,3,2,1,0,125,128,3,6,3,0,
- 126,128,3,82,41,0,127,124,1,0,0,0,127,125,1,0,0,0,127,126,1,0,0,0,128,
- 129,1,0,0,0,129,130,5,0,0,1,130,1,1,0,0,0,131,137,3,4,2,0,132,133,5,176,
- 0,0,133,134,5,4,0,0,134,136,3,4,2,0,135,132,1,0,0,0,136,139,1,0,0,0,137,
- 135,1,0,0,0,137,138,1,0,0,0,138,3,1,0,0,0,139,137,1,0,0,0,140,147,3,6,
- 3,0,141,142,5,220,0,0,142,143,3,2,1,0,143,144,5,236,0,0,144,147,1,0,0,
- 0,145,147,3,122,61,0,146,140,1,0,0,0,146,141,1,0,0,0,146,145,1,0,0,0,
- 147,5,1,0,0,0,148,150,3,8,4,0,149,148,1,0,0,0,149,150,1,0,0,0,150,151,
- 1,0,0,0,151,153,5,146,0,0,152,154,5,49,0,0,153,152,1,0,0,0,153,154,1,
- 0,0,0,154,156,1,0,0,0,155,157,3,10,5,0,156,155,1,0,0,0,156,157,1,0,0,
- 0,157,158,1,0,0,0,158,160,3,72,36,0,159,161,3,12,6,0,160,159,1,0,0,0,
- 160,161,1,0,0,0,161,163,1,0,0,0,162,164,3,14,7,0,163,162,1,0,0,0,163,
- 164,1,0,0,0,164,166,1,0,0,0,165,167,3,18,9,0,166,165,1,0,0,0,166,167,
- 1,0,0,0,167,169,1,0,0,0,168,170,3,20,10,0,169,168,1,0,0,0,169,170,1,0,
- 0,0,170,172,1,0,0,0,171,173,3,22,11,0,172,171,1,0,0,0,172,173,1,0,0,0,
- 173,176,1,0,0,0,174,175,5,189,0,0,175,177,7,0,0,0,176,174,1,0,0,0,176,
- 177,1,0,0,0,177,180,1,0,0,0,178,179,5,189,0,0,179,181,5,169,0,0,180,178,
- 1,0,0,0,180,181,1,0,0,0,181,183,1,0,0,0,182,184,3,24,12,0,183,182,1,0,
- 0,0,183,184,1,0,0,0,184,186,1,0,0,0,185,187,3,16,8,0,186,185,1,0,0,0,
- 186,187,1,0,0,0,187,189,1,0,0,0,188,190,3,26,13,0,189,188,1,0,0,0,189,
- 190,1,0,0,0,190,193,1,0,0,0,191,194,3,30,15,0,192,194,3,32,16,0,193,191,
- 1,0,0,0,193,192,1,0,0,0,193,194,1,0,0,0,194,196,1,0,0,0,195,197,3,34,
- 17,0,196,195,1,0,0,0,196,197,1,0,0,0,197,7,1,0,0,0,198,199,5,189,0,0,
- 199,200,3,86,43,0,200,9,1,0,0,0,201,202,5,168,0,0,202,205,5,198,0,0,203,
- 204,5,189,0,0,204,206,5,164,0,0,205,203,1,0,0,0,205,206,1,0,0,0,206,11,
- 1,0,0,0,207,208,5,68,0,0,208,209,3,36,18,0,209,13,1,0,0,0,210,212,7,1,
- 0,0,211,210,1,0,0,0,211,212,1,0,0,0,212,213,1,0,0,0,213,214,5,9,0,0,214,
- 215,5,90,0,0,215,216,3,72,36,0,216,15,1,0,0,0,217,218,5,188,0,0,218,219,
- 3,118,59,0,219,220,5,10,0,0,220,221,5,220,0,0,221,222,3,56,28,0,222,232,
- 5,236,0,0,223,224,5,206,0,0,224,225,3,118,59,0,225,226,5,10,0,0,226,227,
- 5,220,0,0,227,228,3,56,28,0,228,229,5,236,0,0,229,231,1,0,0,0,230,223,
- 1,0,0,0,231,234,1,0,0,0,232,230,1,0,0,0,232,233,1,0,0,0,233,17,1,0,0,
- 0,234,232,1,0,0,0,235,236,5,129,0,0,236,237,3,74,37,0,237,19,1,0,0,0,
- 238,239,5,187,0,0,239,240,3,74,37,0,240,21,1,0,0,0,241,242,5,73,0,0,242,
- 249,5,18,0,0,243,244,7,0,0,0,244,245,5,220,0,0,245,246,3,72,36,0,246,
- 247,5,236,0,0,247,250,1,0,0,0,248,250,3,72,36,0,249,243,1,0,0,0,249,248,
- 1,0,0,0,250,23,1,0,0,0,251,252,5,74,0,0,252,253,3,74,37,0,253,25,1,0,
- 0,0,254,255,5,122,0,0,255,256,5,18,0,0,256,257,3,46,23,0,257,27,1,0,0,
- 0,258,259,5,122,0,0,259,260,5,18,0,0,260,261,3,72,36,0,261,29,1,0,0,0,
- 262,263,5,99,0,0,263,266,3,74,37,0,264,265,5,206,0,0,265,267,3,74,37,
- 0,266,264,1,0,0,0,266,267,1,0,0,0,267,272,1,0,0,0,268,269,5,189,0,0,269,
- 273,5,164,0,0,270,271,5,18,0,0,271,273,3,72,36,0,272,268,1,0,0,0,272,
- 270,1,0,0,0,272,273,1,0,0,0,273,292,1,0,0,0,274,275,5,99,0,0,275,278,
- 3,74,37,0,276,277,5,189,0,0,277,279,5,164,0,0,278,276,1,0,0,0,278,279,
- 1,0,0,0,279,280,1,0,0,0,280,281,5,118,0,0,281,282,3,74,37,0,282,292,1,
- 0,0,0,283,284,5,99,0,0,284,285,3,74,37,0,285,286,5,118,0,0,286,289,3,
- 74,37,0,287,288,5,18,0,0,288,290,3,72,36,0,289,287,1,0,0,0,289,290,1,
- 0,0,0,290,292,1,0,0,0,291,262,1,0,0,0,291,274,1,0,0,0,291,283,1,0,0,0,
- 292,31,1,0,0,0,293,294,5,118,0,0,294,295,3,74,37,0,295,33,1,0,0,0,296,
- 297,5,150,0,0,297,298,3,52,26,0,298,35,1,0,0,0,299,300,6,18,-1,0,300,
- 302,3,94,47,0,301,303,5,61,0,0,302,301,1,0,0,0,302,303,1,0,0,0,303,305,
- 1,0,0,0,304,306,3,44,22,0,305,304,1,0,0,0,305,306,1,0,0,0,306,312,1,0,
- 0,0,307,308,5,220,0,0,308,309,3,36,18,0,309,310,5,236,0,0,310,312,1,0,
- 0,0,311,299,1,0,0,0,311,307,1,0,0,0,312,327,1,0,0,0,313,314,10,3,0,0,
- 314,315,3,40,20,0,315,316,3,36,18,4,316,326,1,0,0,0,317,319,10,4,0,0,
- 318,320,3,38,19,0,319,318,1,0,0,0,319,320,1,0,0,0,320,321,1,0,0,0,321,
- 322,5,90,0,0,322,323,3,36,18,0,323,324,3,42,21,0,324,326,1,0,0,0,325,
- 313,1,0,0,0,325,317,1,0,0,0,326,329,1,0,0,0,327,325,1,0,0,0,327,328,1,
- 0,0,0,328,37,1,0,0,0,329,327,1,0,0,0,330,332,7,2,0,0,331,330,1,0,0,0,
- 331,332,1,0,0,0,332,333,1,0,0,0,333,340,5,84,0,0,334,336,5,84,0,0,335,
- 337,7,2,0,0,336,335,1,0,0,0,336,337,1,0,0,0,337,340,1,0,0,0,338,340,7,
- 2,0,0,339,331,1,0,0,0,339,334,1,0,0,0,339,338,1,0,0,0,340,374,1,0,0,0,
- 341,343,7,3,0,0,342,341,1,0,0,0,342,343,1,0,0,0,343,344,1,0,0,0,344,346,
- 7,4,0,0,345,347,5,123,0,0,346,345,1,0,0,0,346,347,1,0,0,0,347,356,1,0,
- 0,0,348,350,7,4,0,0,349,351,5,123,0,0,350,349,1,0,0,0,350,351,1,0,0,0,
- 351,353,1,0,0,0,352,354,7,3,0,0,353,352,1,0,0,0,353,354,1,0,0,0,354,356,
- 1,0,0,0,355,342,1,0,0,0,355,348,1,0,0,0,356,374,1,0,0,0,357,359,7,5,0,
- 0,358,357,1,0,0,0,358,359,1,0,0,0,359,360,1,0,0,0,360,362,5,69,0,0,361,
- 363,5,123,0,0,362,361,1,0,0,0,362,363,1,0,0,0,363,372,1,0,0,0,364,366,
- 5,69,0,0,365,367,5,123,0,0,366,365,1,0,0,0,366,367,1,0,0,0,367,369,1,
- 0,0,0,368,370,7,5,0,0,369,368,1,0,0,0,369,370,1,0,0,0,370,372,1,0,0,0,
- 371,358,1,0,0,0,371,364,1,0,0,0,372,374,1,0,0,0,373,339,1,0,0,0,373,355,
- 1,0,0,0,373,371,1,0,0,0,374,39,1,0,0,0,375,376,5,31,0,0,376,379,5,90,
- 0,0,377,379,5,206,0,0,378,375,1,0,0,0,378,377,1,0,0,0,379,41,1,0,0,0,
- 380,381,5,119,0,0,381,390,3,72,36,0,382,383,5,179,0,0,383,384,5,220,0,
- 0,384,385,3,72,36,0,385,386,5,236,0,0,386,390,1,0,0,0,387,388,5,179,0,
- 0,388,390,3,72,36,0,389,380,1,0,0,0,389,382,1,0,0,0,389,387,1,0,0,0,390,
- 43,1,0,0,0,391,392,5,144,0,0,392,395,3,50,25,0,393,394,5,118,0,0,394,
- 396,3,50,25,0,395,393,1,0,0,0,395,396,1,0,0,0,396,45,1,0,0,0,397,402,
- 3,48,24,0,398,399,5,206,0,0,399,401,3,48,24,0,400,398,1,0,0,0,401,404,
- 1,0,0,0,402,400,1,0,0,0,402,403,1,0,0,0,403,47,1,0,0,0,404,402,1,0,0,
- 0,405,407,3,74,37,0,406,408,7,6,0,0,407,406,1,0,0,0,407,408,1,0,0,0,408,
- 411,1,0,0,0,409,410,5,117,0,0,410,412,7,7,0,0,411,409,1,0,0,0,411,412,
- 1,0,0,0,412,415,1,0,0,0,413,414,5,26,0,0,414,416,5,200,0,0,415,413,1,
- 0,0,0,415,416,1,0,0,0,416,49,1,0,0,0,417,424,3,122,61,0,418,421,3,106,
- 53,0,419,420,5,238,0,0,420,422,3,106,53,0,421,419,1,0,0,0,421,422,1,0,
- 0,0,422,424,1,0,0,0,423,417,1,0,0,0,423,418,1,0,0,0,424,51,1,0,0,0,425,
- 430,3,54,27,0,426,427,5,206,0,0,427,429,3,54,27,0,428,426,1,0,0,0,429,
- 432,1,0,0,0,430,428,1,0,0,0,430,431,1,0,0,0,431,53,1,0,0,0,432,430,1,
- 0,0,0,433,434,3,118,59,0,434,435,5,212,0,0,435,436,3,108,54,0,436,55,
- 1,0,0,0,437,439,3,58,29,0,438,437,1,0,0,0,438,439,1,0,0,0,439,441,1,0,
- 0,0,440,442,3,60,30,0,441,440,1,0,0,0,441,442,1,0,0,0,442,444,1,0,0,0,
- 443,445,3,62,31,0,444,443,1,0,0,0,444,445,1,0,0,0,445,57,1,0,0,0,446,
- 447,5,126,0,0,447,448,5,18,0,0,448,449,3,72,36,0,449,59,1,0,0,0,450,451,
- 5,122,0,0,451,452,5,18,0,0,452,453,3,46,23,0,453,61,1,0,0,0,454,455,7,
- 8,0,0,455,456,3,64,32,0,456,63,1,0,0,0,457,464,3,66,33,0,458,459,5,16,
- 0,0,459,460,3,66,33,0,460,461,5,6,0,0,461,462,3,66,33,0,462,464,1,0,0,
- 0,463,457,1,0,0,0,463,458,1,0,0,0,464,65,1,0,0,0,465,466,5,33,0,0,466,
- 478,5,142,0,0,467,468,5,175,0,0,468,478,5,128,0,0,469,470,5,175,0,0,470,
- 478,5,64,0,0,471,472,3,106,53,0,472,473,5,128,0,0,473,478,1,0,0,0,474,
- 475,3,106,53,0,475,476,5,64,0,0,476,478,1,0,0,0,477,465,1,0,0,0,477,467,
- 1,0,0,0,477,469,1,0,0,0,477,471,1,0,0,0,477,474,1,0,0,0,478,67,1,0,0,
- 0,479,480,3,74,37,0,480,481,5,0,0,1,481,69,1,0,0,0,482,530,3,118,59,0,
- 483,484,3,118,59,0,484,485,5,220,0,0,485,486,3,118,59,0,486,493,3,70,
- 35,0,487,488,5,206,0,0,488,489,3,118,59,0,489,490,3,70,35,0,490,492,1,
- 0,0,0,491,487,1,0,0,0,492,495,1,0,0,0,493,491,1,0,0,0,493,494,1,0,0,0,
- 494,496,1,0,0,0,495,493,1,0,0,0,496,497,5,236,0,0,497,530,1,0,0,0,498,
- 499,3,118,59,0,499,500,5,220,0,0,500,505,3,120,60,0,501,502,5,206,0,0,
- 502,504,3,120,60,0,503,501,1,0,0,0,504,507,1,0,0,0,505,503,1,0,0,0,505,
- 506,1,0,0,0,506,508,1,0,0,0,507,505,1,0,0,0,508,509,5,236,0,0,509,530,
- 1,0,0,0,510,511,3,118,59,0,511,512,5,220,0,0,512,517,3,70,35,0,513,514,
- 5,206,0,0,514,516,3,70,35,0,515,513,1,0,0,0,516,519,1,0,0,0,517,515,1,
- 0,0,0,517,518,1,0,0,0,518,520,1,0,0,0,519,517,1,0,0,0,520,521,5,236,0,
- 0,521,530,1,0,0,0,522,523,3,118,59,0,523,525,5,220,0,0,524,526,3,72,36,
- 0,525,524,1,0,0,0,525,526,1,0,0,0,526,527,1,0,0,0,527,528,5,236,0,0,528,
- 530,1,0,0,0,529,482,1,0,0,0,529,483,1,0,0,0,529,498,1,0,0,0,529,510,1,
- 0,0,0,529,522,1,0,0,0,530,71,1,0,0,0,531,536,3,74,37,0,532,533,5,206,
- 0,0,533,535,3,74,37,0,534,532,1,0,0,0,535,538,1,0,0,0,536,534,1,0,0,0,
- 536,537,1,0,0,0,537,73,1,0,0,0,538,536,1,0,0,0,539,540,6,37,-1,0,540,
- 542,5,19,0,0,541,543,3,74,37,0,542,541,1,0,0,0,542,543,1,0,0,0,543,549,
- 1,0,0,0,544,545,5,186,0,0,545,546,3,74,37,0,546,547,5,163,0,0,547,548,
- 3,74,37,0,548,550,1,0,0,0,549,544,1,0,0,0,550,551,1,0,0,0,551,549,1,0,
- 0,0,551,552,1,0,0,0,552,555,1,0,0,0,553,554,5,52,0,0,554,556,3,74,37,
- 0,555,553,1,0,0,0,555,556,1,0,0,0,556,557,1,0,0,0,557,558,5,53,0,0,558,
- 670,1,0,0,0,559,560,5,20,0,0,560,561,5,220,0,0,561,562,3,74,37,0,562,
- 563,5,10,0,0,563,564,3,70,35,0,564,565,5,236,0,0,565,670,1,0,0,0,566,
- 567,5,36,0,0,567,670,5,200,0,0,568,569,5,59,0,0,569,570,5,220,0,0,570,
- 571,3,110,55,0,571,572,5,68,0,0,572,573,3,74,37,0,573,574,5,236,0,0,574,
- 670,1,0,0,0,575,576,5,86,0,0,576,577,3,74,37,0,577,578,3,110,55,0,578,
- 670,1,0,0,0,579,580,5,155,0,0,580,581,5,220,0,0,581,582,3,74,37,0,582,
- 583,5,68,0,0,583,586,3,74,37,0,584,585,5,65,0,0,585,587,3,74,37,0,586,
- 584,1,0,0,0,586,587,1,0,0,0,587,588,1,0,0,0,588,589,5,236,0,0,589,670,
- 1,0,0,0,590,591,5,166,0,0,591,670,5,200,0,0,592,593,5,171,0,0,593,594,
- 5,220,0,0,594,595,7,9,0,0,595,596,5,200,0,0,596,597,5,68,0,0,597,598,
- 3,74,37,0,598,599,5,236,0,0,599,670,1,0,0,0,600,601,3,118,59,0,601,603,
- 5,220,0,0,602,604,3,72,36,0,603,602,1,0,0,0,603,604,1,0,0,0,604,605,1,
- 0,0,0,605,606,5,236,0,0,606,607,1,0,0,0,607,608,5,125,0,0,608,609,5,220,
- 0,0,609,610,3,56,28,0,610,611,5,236,0,0,611,670,1,0,0,0,612,613,3,118,
- 59,0,613,615,5,220,0,0,614,616,3,72,36,0,615,614,1,0,0,0,615,616,1,0,
- 0,0,616,617,1,0,0,0,617,618,5,236,0,0,618,619,1,0,0,0,619,620,5,125,0,
- 0,620,621,3,118,59,0,621,670,1,0,0,0,622,628,3,118,59,0,623,625,5,220,
- 0,0,624,626,3,72,36,0,625,624,1,0,0,0,625,626,1,0,0,0,626,627,1,0,0,0,
- 627,629,5,236,0,0,628,623,1,0,0,0,628,629,1,0,0,0,629,630,1,0,0,0,630,
- 632,5,220,0,0,631,633,5,49,0,0,632,631,1,0,0,0,632,633,1,0,0,0,633,635,
- 1,0,0,0,634,636,3,76,38,0,635,634,1,0,0,0,635,636,1,0,0,0,636,637,1,0,
- 0,0,637,638,5,236,0,0,638,670,1,0,0,0,639,670,3,82,41,0,640,670,3,108,
- 54,0,641,642,5,208,0,0,642,670,3,74,37,18,643,644,5,115,0,0,644,670,3,
- 74,37,12,645,646,3,98,49,0,646,647,5,210,0,0,647,649,1,0,0,0,648,645,
- 1,0,0,0,648,649,1,0,0,0,649,650,1,0,0,0,650,670,5,202,0,0,651,652,5,220,
- 0,0,652,653,3,2,1,0,653,654,5,236,0,0,654,670,1,0,0,0,655,656,5,220,0,
- 0,656,657,3,74,37,0,657,658,5,236,0,0,658,670,1,0,0,0,659,660,5,220,0,
- 0,660,661,3,72,36,0,661,662,5,236,0,0,662,670,1,0,0,0,663,665,5,219,0,
- 0,664,666,3,72,36,0,665,664,1,0,0,0,665,666,1,0,0,0,666,667,1,0,0,0,667,
- 670,5,235,0,0,668,670,3,90,45,0,669,539,1,0,0,0,669,559,1,0,0,0,669,566,
- 1,0,0,0,669,568,1,0,0,0,669,575,1,0,0,0,669,579,1,0,0,0,669,590,1,0,0,
- 0,669,592,1,0,0,0,669,600,1,0,0,0,669,612,1,0,0,0,669,622,1,0,0,0,669,
- 639,1,0,0,0,669,640,1,0,0,0,669,641,1,0,0,0,669,643,1,0,0,0,669,648,1,
- 0,0,0,669,651,1,0,0,0,669,655,1,0,0,0,669,659,1,0,0,0,669,663,1,0,0,0,
- 669,668,1,0,0,0,670,764,1,0,0,0,671,675,10,17,0,0,672,676,5,202,0,0,673,
- 676,5,238,0,0,674,676,5,227,0,0,675,672,1,0,0,0,675,673,1,0,0,0,675,674,
- 1,0,0,0,676,677,1,0,0,0,677,763,3,74,37,18,678,682,10,16,0,0,679,683,
- 5,228,0,0,680,683,5,208,0,0,681,683,5,207,0,0,682,679,1,0,0,0,682,680,
- 1,0,0,0,682,681,1,0,0,0,683,684,1,0,0,0,684,763,3,74,37,17,685,710,10,
- 15,0,0,686,711,5,211,0,0,687,711,5,212,0,0,688,711,5,223,0,0,689,711,
- 5,221,0,0,690,711,5,222,0,0,691,711,5,213,0,0,692,711,5,214,0,0,693,695,
- 5,115,0,0,694,693,1,0,0,0,694,695,1,0,0,0,695,696,1,0,0,0,696,698,5,80,
- 0,0,697,699,5,25,0,0,698,697,1,0,0,0,698,699,1,0,0,0,699,711,1,0,0,0,
- 700,702,5,115,0,0,701,700,1,0,0,0,701,702,1,0,0,0,702,703,1,0,0,0,703,
- 711,7,10,0,0,704,711,5,232,0,0,705,711,5,233,0,0,706,711,5,225,0,0,707,
- 711,5,216,0,0,708,711,5,217,0,0,709,711,5,224,0,0,710,686,1,0,0,0,710,
- 687,1,0,0,0,710,688,1,0,0,0,710,689,1,0,0,0,710,690,1,0,0,0,710,691,1,
- 0,0,0,710,692,1,0,0,0,710,694,1,0,0,0,710,701,1,0,0,0,710,704,1,0,0,0,
- 710,705,1,0,0,0,710,706,1,0,0,0,710,707,1,0,0,0,710,708,1,0,0,0,710,709,
- 1,0,0,0,711,712,1,0,0,0,712,763,3,74,37,16,713,714,10,13,0,0,714,715,
- 5,226,0,0,715,763,3,74,37,14,716,717,10,11,0,0,717,718,5,6,0,0,718,763,
- 3,74,37,12,719,720,10,10,0,0,720,721,5,121,0,0,721,763,3,74,37,11,722,
- 724,10,9,0,0,723,725,5,115,0,0,724,723,1,0,0,0,724,725,1,0,0,0,725,726,
- 1,0,0,0,726,727,5,16,0,0,727,728,3,74,37,0,728,729,5,6,0,0,729,730,3,
- 74,37,10,730,763,1,0,0,0,731,732,10,8,0,0,732,733,5,229,0,0,733,734,3,
- 74,37,0,734,735,5,205,0,0,735,736,3,74,37,8,736,763,1,0,0,0,737,738,10,
- 21,0,0,738,739,5,219,0,0,739,740,3,74,37,0,740,741,5,235,0,0,741,763,
- 1,0,0,0,742,743,10,20,0,0,743,744,5,210,0,0,744,763,5,198,0,0,745,746,
- 10,19,0,0,746,747,5,210,0,0,747,763,3,118,59,0,748,749,10,14,0,0,749,
- 751,5,88,0,0,750,752,5,115,0,0,751,750,1,0,0,0,751,752,1,0,0,0,752,753,
- 1,0,0,0,753,763,5,116,0,0,754,760,10,7,0,0,755,761,3,116,58,0,756,757,
- 5,10,0,0,757,761,3,118,59,0,758,759,5,10,0,0,759,761,5,200,0,0,760,755,
- 1,0,0,0,760,756,1,0,0,0,760,758,1,0,0,0,761,763,1,0,0,0,762,671,1,0,0,
- 0,762,678,1,0,0,0,762,685,1,0,0,0,762,713,1,0,0,0,762,716,1,0,0,0,762,
- 719,1,0,0,0,762,722,1,0,0,0,762,731,1,0,0,0,762,737,1,0,0,0,762,742,1,
- 0,0,0,762,745,1,0,0,0,762,748,1,0,0,0,762,754,1,0,0,0,763,766,1,0,0,0,
- 764,762,1,0,0,0,764,765,1,0,0,0,765,75,1,0,0,0,766,764,1,0,0,0,767,772,
- 3,78,39,0,768,769,5,206,0,0,769,771,3,78,39,0,770,768,1,0,0,0,771,774,
- 1,0,0,0,772,770,1,0,0,0,772,773,1,0,0,0,773,77,1,0,0,0,774,772,1,0,0,
- 0,775,778,3,80,40,0,776,778,3,74,37,0,777,775,1,0,0,0,777,776,1,0,0,0,
- 778,79,1,0,0,0,779,780,5,220,0,0,780,785,3,118,59,0,781,782,5,206,0,0,
- 782,784,3,118,59,0,783,781,1,0,0,0,784,787,1,0,0,0,785,783,1,0,0,0,785,
- 786,1,0,0,0,786,788,1,0,0,0,787,785,1,0,0,0,788,789,5,236,0,0,789,799,
- 1,0,0,0,790,795,3,118,59,0,791,792,5,206,0,0,792,794,3,118,59,0,793,791,
- 1,0,0,0,794,797,1,0,0,0,795,793,1,0,0,0,795,796,1,0,0,0,796,799,1,0,0,
- 0,797,795,1,0,0,0,798,779,1,0,0,0,798,790,1,0,0,0,799,800,1,0,0,0,800,
- 801,5,201,0,0,801,802,3,74,37,0,802,81,1,0,0,0,803,804,5,222,0,0,804,
- 808,3,118,59,0,805,807,3,84,42,0,806,805,1,0,0,0,807,810,1,0,0,0,808,
- 806,1,0,0,0,808,809,1,0,0,0,809,811,1,0,0,0,810,808,1,0,0,0,811,812,5,
- 238,0,0,812,813,5,214,0,0,813,832,1,0,0,0,814,815,5,222,0,0,815,819,3,
- 118,59,0,816,818,3,84,42,0,817,816,1,0,0,0,818,821,1,0,0,0,819,817,1,
- 0,0,0,819,820,1,0,0,0,820,822,1,0,0,0,821,819,1,0,0,0,822,824,5,214,0,
- 0,823,825,3,82,41,0,824,823,1,0,0,0,824,825,1,0,0,0,825,826,1,0,0,0,826,
- 827,5,222,0,0,827,828,5,238,0,0,828,829,3,118,59,0,829,830,5,214,0,0,
- 830,832,1,0,0,0,831,803,1,0,0,0,831,814,1,0,0,0,832,83,1,0,0,0,833,834,
- 3,118,59,0,834,835,5,212,0,0,835,836,5,200,0,0,836,845,1,0,0,0,837,838,
- 3,118,59,0,838,839,5,212,0,0,839,840,5,218,0,0,840,841,3,74,37,0,841,
- 842,5,234,0,0,842,845,1,0,0,0,843,845,3,118,59,0,844,833,1,0,0,0,844,
- 837,1,0,0,0,844,843,1,0,0,0,845,85,1,0,0,0,846,851,3,88,44,0,847,848,
- 5,206,0,0,848,850,3,88,44,0,849,847,1,0,0,0,850,853,1,0,0,0,851,849,1,
- 0,0,0,851,852,1,0,0,0,852,87,1,0,0,0,853,851,1,0,0,0,854,855,3,118,59,
- 0,855,856,5,10,0,0,856,857,5,220,0,0,857,858,3,2,1,0,858,859,5,236,0,
- 0,859,865,1,0,0,0,860,861,3,74,37,0,861,862,5,10,0,0,862,863,3,118,59,
- 0,863,865,1,0,0,0,864,854,1,0,0,0,864,860,1,0,0,0,865,89,1,0,0,0,866,
- 874,3,122,61,0,867,868,3,98,49,0,868,869,5,210,0,0,869,871,1,0,0,0,870,
- 867,1,0,0,0,870,871,1,0,0,0,871,872,1,0,0,0,872,874,3,92,46,0,873,866,
- 1,0,0,0,873,870,1,0,0,0,874,91,1,0,0,0,875,880,3,118,59,0,876,877,5,210,
- 0,0,877,879,3,118,59,0,878,876,1,0,0,0,879,882,1,0,0,0,880,878,1,0,0,
- 0,880,881,1,0,0,0,881,93,1,0,0,0,882,880,1,0,0,0,883,884,6,47,-1,0,884,
- 893,3,98,49,0,885,893,3,96,48,0,886,887,5,220,0,0,887,888,3,2,1,0,888,
- 889,5,236,0,0,889,893,1,0,0,0,890,893,3,82,41,0,891,893,3,122,61,0,892,
- 883,1,0,0,0,892,885,1,0,0,0,892,886,1,0,0,0,892,890,1,0,0,0,892,891,1,
- 0,0,0,893,902,1,0,0,0,894,898,10,3,0,0,895,899,3,116,58,0,896,897,5,10,
- 0,0,897,899,3,118,59,0,898,895,1,0,0,0,898,896,1,0,0,0,899,901,1,0,0,
- 0,900,894,1,0,0,0,901,904,1,0,0,0,902,900,1,0,0,0,902,903,1,0,0,0,903,
- 95,1,0,0,0,904,902,1,0,0,0,905,906,3,118,59,0,906,908,5,220,0,0,907,909,
- 3,100,50,0,908,907,1,0,0,0,908,909,1,0,0,0,909,910,1,0,0,0,910,911,5,
- 236,0,0,911,97,1,0,0,0,912,913,3,102,51,0,913,914,5,210,0,0,914,916,1,
- 0,0,0,915,912,1,0,0,0,915,916,1,0,0,0,916,917,1,0,0,0,917,918,3,118,59,
- 0,918,99,1,0,0,0,919,924,3,74,37,0,920,921,5,206,0,0,921,923,3,74,37,
- 0,922,920,1,0,0,0,923,926,1,0,0,0,924,922,1,0,0,0,924,925,1,0,0,0,925,
- 101,1,0,0,0,926,924,1,0,0,0,927,928,3,118,59,0,928,103,1,0,0,0,929,938,
- 5,196,0,0,930,931,5,210,0,0,931,938,7,11,0,0,932,933,5,198,0,0,933,935,
- 5,210,0,0,934,936,7,11,0,0,935,934,1,0,0,0,935,936,1,0,0,0,936,938,1,
- 0,0,0,937,929,1,0,0,0,937,930,1,0,0,0,937,932,1,0,0,0,938,105,1,0,0,0,
- 939,941,7,12,0,0,940,939,1,0,0,0,940,941,1,0,0,0,941,948,1,0,0,0,942,
- 949,3,104,52,0,943,949,5,197,0,0,944,949,5,198,0,0,945,949,5,199,0,0,
- 946,949,5,82,0,0,947,949,5,113,0,0,948,942,1,0,0,0,948,943,1,0,0,0,948,
- 944,1,0,0,0,948,945,1,0,0,0,948,946,1,0,0,0,948,947,1,0,0,0,949,107,1,
- 0,0,0,950,954,3,106,53,0,951,954,5,200,0,0,952,954,5,116,0,0,953,950,
- 1,0,0,0,953,951,1,0,0,0,953,952,1,0,0,0,954,109,1,0,0,0,955,956,7,13,
- 0,0,956,111,1,0,0,0,957,958,7,14,0,0,958,113,1,0,0,0,959,960,7,15,0,0,
- 960,115,1,0,0,0,961,964,5,195,0,0,962,964,3,114,57,0,963,961,1,0,0,0,
- 963,962,1,0,0,0,964,117,1,0,0,0,965,969,5,195,0,0,966,969,3,110,55,0,
- 967,969,3,112,56,0,968,965,1,0,0,0,968,966,1,0,0,0,968,967,1,0,0,0,969,
- 119,1,0,0,0,970,971,5,200,0,0,971,972,5,212,0,0,972,973,3,106,53,0,973,
- 121,1,0,0,0,974,975,5,218,0,0,975,976,3,118,59,0,976,977,5,234,0,0,977,
- 123,1,0,0,0,120,127,137,146,149,153,156,160,163,166,169,172,176,180,183,
- 186,189,193,196,205,211,232,249,266,272,278,289,291,302,305,311,319,325,
- 327,331,336,339,342,346,350,353,355,358,362,366,369,371,373,378,389,395,
- 402,407,411,415,421,423,430,438,441,444,463,477,493,505,517,525,529,536,
- 542,551,555,586,603,615,625,628,632,635,648,665,669,675,682,694,698,701,
- 710,724,751,760,762,764,772,777,785,795,798,808,819,824,831,844,851,864,
- 870,873,880,892,898,902,908,915,924,935,937,940,948,953,963,968
+ 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,580,8,37,1,37,1,37,
+ 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,
+ 597,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,609,8,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,619,8,37,1,37,3,37,622,
+ 8,37,1,37,1,37,3,37,626,8,37,1,37,3,37,629,8,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,642,8,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,659,8,37,1,
+ 37,1,37,3,37,663,8,37,1,37,1,37,1,37,1,37,3,37,669,8,37,1,37,1,37,1,37,
+ 1,37,1,37,3,37,676,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
+ 1,37,3,37,688,8,37,1,37,1,37,3,37,692,8,37,1,37,3,37,695,8,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,1,37,3,37,704,8,37,1,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,718,8,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,745,8,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,3,37,754,8,37,5,37,756,8,37,10,37,12,37,759,9,37,1,38,1,
+ 38,1,38,5,38,764,8,38,10,38,12,38,767,9,38,1,39,1,39,3,39,771,8,39,1,
+ 40,1,40,1,40,1,40,5,40,777,8,40,10,40,12,40,780,9,40,1,40,1,40,1,40,1,
+ 40,1,40,5,40,787,8,40,10,40,12,40,790,9,40,3,40,792,8,40,1,40,1,40,1,
+ 40,1,41,1,41,1,41,5,41,800,8,41,10,41,12,41,803,9,41,1,41,1,41,1,41,1,
+ 41,1,41,1,41,5,41,811,8,41,10,41,12,41,814,9,41,1,41,1,41,3,41,818,8,
+ 41,1,41,1,41,1,41,1,41,1,41,3,41,825,8,41,1,42,1,42,1,42,1,42,1,42,1,
+ 42,1,42,1,42,1,42,1,42,1,42,3,42,838,8,42,1,43,1,43,1,43,5,43,843,8,43,
+ 10,43,12,43,846,9,43,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,
+ 3,44,858,8,44,1,45,1,45,1,45,1,45,3,45,864,8,45,1,45,3,45,867,8,45,1,
+ 46,1,46,1,46,5,46,872,8,46,10,46,12,46,875,9,46,1,47,1,47,1,47,1,47,1,
+ 47,1,47,1,47,1,47,1,47,3,47,886,8,47,1,47,1,47,1,47,1,47,3,47,892,8,47,
+ 5,47,894,8,47,10,47,12,47,897,9,47,1,48,1,48,1,48,3,48,902,8,48,1,48,
+ 1,48,1,49,1,49,1,49,3,49,909,8,49,1,49,1,49,1,50,1,50,1,50,5,50,916,8,
+ 50,10,50,12,50,919,9,50,1,51,1,51,1,52,1,52,1,52,1,52,1,52,1,52,3,52,
+ 929,8,52,3,52,931,8,52,1,53,3,53,934,8,53,1,53,1,53,1,53,1,53,1,53,1,
+ 53,3,53,942,8,53,1,54,1,54,1,54,3,54,947,8,54,1,55,1,55,1,56,1,56,1,57,
+ 1,57,1,58,1,58,3,58,957,8,58,1,59,1,59,1,59,3,59,962,8,59,1,60,1,60,1,
+ 60,1,60,1,61,1,61,1,61,1,61,1,61,0,3,36,74,94,62,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,0,16,2,0,32,32,141,141,2,0,84,84,96,96,
+ 3,0,4,4,8,8,12,12,4,0,4,4,7,8,12,12,147,147,2,0,96,96,140,140,2,0,4,4,
+ 8,8,2,0,11,11,42,43,2,0,62,62,93,93,2,0,133,133,143,143,3,0,17,17,95,
+ 95,170,170,2,0,79,79,98,98,1,0,197,198,2,0,208,208,228,228,8,0,37,37,
+ 76,76,108,108,110,110,132,132,145,145,185,185,190,190,13,0,2,24,26,36,
+ 38,75,77,81,83,107,109,109,111,112,114,115,117,130,133,144,146,184,186,
+ 189,191,192,4,0,36,36,62,62,77,77,91,91,1099,0,127,1,0,0,0,2,131,1,0,
+ 0,0,4,146,1,0,0,0,6,149,1,0,0,0,8,198,1,0,0,0,10,201,1,0,0,0,12,207,1,
+ 0,0,0,14,211,1,0,0,0,16,217,1,0,0,0,18,235,1,0,0,0,20,238,1,0,0,0,22,
+ 241,1,0,0,0,24,251,1,0,0,0,26,254,1,0,0,0,28,258,1,0,0,0,30,291,1,0,0,
+ 0,32,293,1,0,0,0,34,296,1,0,0,0,36,311,1,0,0,0,38,373,1,0,0,0,40,378,
+ 1,0,0,0,42,389,1,0,0,0,44,391,1,0,0,0,46,397,1,0,0,0,48,405,1,0,0,0,50,
+ 423,1,0,0,0,52,425,1,0,0,0,54,433,1,0,0,0,56,438,1,0,0,0,58,446,1,0,0,
+ 0,60,450,1,0,0,0,62,454,1,0,0,0,64,463,1,0,0,0,66,477,1,0,0,0,68,479,
+ 1,0,0,0,70,529,1,0,0,0,72,531,1,0,0,0,74,662,1,0,0,0,76,760,1,0,0,0,78,
+ 770,1,0,0,0,80,791,1,0,0,0,82,824,1,0,0,0,84,837,1,0,0,0,86,839,1,0,0,
+ 0,88,857,1,0,0,0,90,866,1,0,0,0,92,868,1,0,0,0,94,885,1,0,0,0,96,898,
+ 1,0,0,0,98,908,1,0,0,0,100,912,1,0,0,0,102,920,1,0,0,0,104,930,1,0,0,
+ 0,106,933,1,0,0,0,108,946,1,0,0,0,110,948,1,0,0,0,112,950,1,0,0,0,114,
+ 952,1,0,0,0,116,956,1,0,0,0,118,961,1,0,0,0,120,963,1,0,0,0,122,967,1,
+ 0,0,0,124,128,3,2,1,0,125,128,3,6,3,0,126,128,3,82,41,0,127,124,1,0,0,
+ 0,127,125,1,0,0,0,127,126,1,0,0,0,128,129,1,0,0,0,129,130,5,0,0,1,130,
+ 1,1,0,0,0,131,137,3,4,2,0,132,133,5,176,0,0,133,134,5,4,0,0,134,136,3,
+ 4,2,0,135,132,1,0,0,0,136,139,1,0,0,0,137,135,1,0,0,0,137,138,1,0,0,0,
+ 138,3,1,0,0,0,139,137,1,0,0,0,140,147,3,6,3,0,141,142,5,220,0,0,142,143,
+ 3,2,1,0,143,144,5,236,0,0,144,147,1,0,0,0,145,147,3,122,61,0,146,140,
+ 1,0,0,0,146,141,1,0,0,0,146,145,1,0,0,0,147,5,1,0,0,0,148,150,3,8,4,0,
+ 149,148,1,0,0,0,149,150,1,0,0,0,150,151,1,0,0,0,151,153,5,146,0,0,152,
+ 154,5,49,0,0,153,152,1,0,0,0,153,154,1,0,0,0,154,156,1,0,0,0,155,157,
+ 3,10,5,0,156,155,1,0,0,0,156,157,1,0,0,0,157,158,1,0,0,0,158,160,3,72,
+ 36,0,159,161,3,12,6,0,160,159,1,0,0,0,160,161,1,0,0,0,161,163,1,0,0,0,
+ 162,164,3,14,7,0,163,162,1,0,0,0,163,164,1,0,0,0,164,166,1,0,0,0,165,
+ 167,3,18,9,0,166,165,1,0,0,0,166,167,1,0,0,0,167,169,1,0,0,0,168,170,
+ 3,20,10,0,169,168,1,0,0,0,169,170,1,0,0,0,170,172,1,0,0,0,171,173,3,22,
+ 11,0,172,171,1,0,0,0,172,173,1,0,0,0,173,176,1,0,0,0,174,175,5,189,0,
+ 0,175,177,7,0,0,0,176,174,1,0,0,0,176,177,1,0,0,0,177,180,1,0,0,0,178,
+ 179,5,189,0,0,179,181,5,169,0,0,180,178,1,0,0,0,180,181,1,0,0,0,181,183,
+ 1,0,0,0,182,184,3,24,12,0,183,182,1,0,0,0,183,184,1,0,0,0,184,186,1,0,
+ 0,0,185,187,3,16,8,0,186,185,1,0,0,0,186,187,1,0,0,0,187,189,1,0,0,0,
+ 188,190,3,26,13,0,189,188,1,0,0,0,189,190,1,0,0,0,190,193,1,0,0,0,191,
+ 194,3,30,15,0,192,194,3,32,16,0,193,191,1,0,0,0,193,192,1,0,0,0,193,194,
+ 1,0,0,0,194,196,1,0,0,0,195,197,3,34,17,0,196,195,1,0,0,0,196,197,1,0,
+ 0,0,197,7,1,0,0,0,198,199,5,189,0,0,199,200,3,86,43,0,200,9,1,0,0,0,201,
+ 202,5,168,0,0,202,205,5,198,0,0,203,204,5,189,0,0,204,206,5,164,0,0,205,
+ 203,1,0,0,0,205,206,1,0,0,0,206,11,1,0,0,0,207,208,5,68,0,0,208,209,3,
+ 36,18,0,209,13,1,0,0,0,210,212,7,1,0,0,211,210,1,0,0,0,211,212,1,0,0,
+ 0,212,213,1,0,0,0,213,214,5,9,0,0,214,215,5,90,0,0,215,216,3,72,36,0,
+ 216,15,1,0,0,0,217,218,5,188,0,0,218,219,3,118,59,0,219,220,5,10,0,0,
+ 220,221,5,220,0,0,221,222,3,56,28,0,222,232,5,236,0,0,223,224,5,206,0,
+ 0,224,225,3,118,59,0,225,226,5,10,0,0,226,227,5,220,0,0,227,228,3,56,
+ 28,0,228,229,5,236,0,0,229,231,1,0,0,0,230,223,1,0,0,0,231,234,1,0,0,
+ 0,232,230,1,0,0,0,232,233,1,0,0,0,233,17,1,0,0,0,234,232,1,0,0,0,235,
+ 236,5,129,0,0,236,237,3,74,37,0,237,19,1,0,0,0,238,239,5,187,0,0,239,
+ 240,3,74,37,0,240,21,1,0,0,0,241,242,5,73,0,0,242,249,5,18,0,0,243,244,
+ 7,0,0,0,244,245,5,220,0,0,245,246,3,72,36,0,246,247,5,236,0,0,247,250,
+ 1,0,0,0,248,250,3,72,36,0,249,243,1,0,0,0,249,248,1,0,0,0,250,23,1,0,
+ 0,0,251,252,5,74,0,0,252,253,3,74,37,0,253,25,1,0,0,0,254,255,5,122,0,
+ 0,255,256,5,18,0,0,256,257,3,46,23,0,257,27,1,0,0,0,258,259,5,122,0,0,
+ 259,260,5,18,0,0,260,261,3,72,36,0,261,29,1,0,0,0,262,263,5,99,0,0,263,
+ 266,3,74,37,0,264,265,5,206,0,0,265,267,3,74,37,0,266,264,1,0,0,0,266,
+ 267,1,0,0,0,267,272,1,0,0,0,268,269,5,189,0,0,269,273,5,164,0,0,270,271,
+ 5,18,0,0,271,273,3,72,36,0,272,268,1,0,0,0,272,270,1,0,0,0,272,273,1,
+ 0,0,0,273,292,1,0,0,0,274,275,5,99,0,0,275,278,3,74,37,0,276,277,5,189,
+ 0,0,277,279,5,164,0,0,278,276,1,0,0,0,278,279,1,0,0,0,279,280,1,0,0,0,
+ 280,281,5,118,0,0,281,282,3,74,37,0,282,292,1,0,0,0,283,284,5,99,0,0,
+ 284,285,3,74,37,0,285,286,5,118,0,0,286,289,3,74,37,0,287,288,5,18,0,
+ 0,288,290,3,72,36,0,289,287,1,0,0,0,289,290,1,0,0,0,290,292,1,0,0,0,291,
+ 262,1,0,0,0,291,274,1,0,0,0,291,283,1,0,0,0,292,31,1,0,0,0,293,294,5,
+ 118,0,0,294,295,3,74,37,0,295,33,1,0,0,0,296,297,5,150,0,0,297,298,3,
+ 52,26,0,298,35,1,0,0,0,299,300,6,18,-1,0,300,302,3,94,47,0,301,303,5,
+ 61,0,0,302,301,1,0,0,0,302,303,1,0,0,0,303,305,1,0,0,0,304,306,3,44,22,
+ 0,305,304,1,0,0,0,305,306,1,0,0,0,306,312,1,0,0,0,307,308,5,220,0,0,308,
+ 309,3,36,18,0,309,310,5,236,0,0,310,312,1,0,0,0,311,299,1,0,0,0,311,307,
+ 1,0,0,0,312,327,1,0,0,0,313,314,10,3,0,0,314,315,3,40,20,0,315,316,3,
+ 36,18,4,316,326,1,0,0,0,317,319,10,4,0,0,318,320,3,38,19,0,319,318,1,
+ 0,0,0,319,320,1,0,0,0,320,321,1,0,0,0,321,322,5,90,0,0,322,323,3,36,18,
+ 0,323,324,3,42,21,0,324,326,1,0,0,0,325,313,1,0,0,0,325,317,1,0,0,0,326,
+ 329,1,0,0,0,327,325,1,0,0,0,327,328,1,0,0,0,328,37,1,0,0,0,329,327,1,
+ 0,0,0,330,332,7,2,0,0,331,330,1,0,0,0,331,332,1,0,0,0,332,333,1,0,0,0,
+ 333,340,5,84,0,0,334,336,5,84,0,0,335,337,7,2,0,0,336,335,1,0,0,0,336,
+ 337,1,0,0,0,337,340,1,0,0,0,338,340,7,2,0,0,339,331,1,0,0,0,339,334,1,
+ 0,0,0,339,338,1,0,0,0,340,374,1,0,0,0,341,343,7,3,0,0,342,341,1,0,0,0,
+ 342,343,1,0,0,0,343,344,1,0,0,0,344,346,7,4,0,0,345,347,5,123,0,0,346,
+ 345,1,0,0,0,346,347,1,0,0,0,347,356,1,0,0,0,348,350,7,4,0,0,349,351,5,
+ 123,0,0,350,349,1,0,0,0,350,351,1,0,0,0,351,353,1,0,0,0,352,354,7,3,0,
+ 0,353,352,1,0,0,0,353,354,1,0,0,0,354,356,1,0,0,0,355,342,1,0,0,0,355,
+ 348,1,0,0,0,356,374,1,0,0,0,357,359,7,5,0,0,358,357,1,0,0,0,358,359,1,
+ 0,0,0,359,360,1,0,0,0,360,362,5,69,0,0,361,363,5,123,0,0,362,361,1,0,
+ 0,0,362,363,1,0,0,0,363,372,1,0,0,0,364,366,5,69,0,0,365,367,5,123,0,
+ 0,366,365,1,0,0,0,366,367,1,0,0,0,367,369,1,0,0,0,368,370,7,5,0,0,369,
+ 368,1,0,0,0,369,370,1,0,0,0,370,372,1,0,0,0,371,358,1,0,0,0,371,364,1,
+ 0,0,0,372,374,1,0,0,0,373,339,1,0,0,0,373,355,1,0,0,0,373,371,1,0,0,0,
+ 374,39,1,0,0,0,375,376,5,31,0,0,376,379,5,90,0,0,377,379,5,206,0,0,378,
+ 375,1,0,0,0,378,377,1,0,0,0,379,41,1,0,0,0,380,381,5,119,0,0,381,390,
+ 3,72,36,0,382,383,5,179,0,0,383,384,5,220,0,0,384,385,3,72,36,0,385,386,
+ 5,236,0,0,386,390,1,0,0,0,387,388,5,179,0,0,388,390,3,72,36,0,389,380,
+ 1,0,0,0,389,382,1,0,0,0,389,387,1,0,0,0,390,43,1,0,0,0,391,392,5,144,
+ 0,0,392,395,3,50,25,0,393,394,5,118,0,0,394,396,3,50,25,0,395,393,1,0,
+ 0,0,395,396,1,0,0,0,396,45,1,0,0,0,397,402,3,48,24,0,398,399,5,206,0,
+ 0,399,401,3,48,24,0,400,398,1,0,0,0,401,404,1,0,0,0,402,400,1,0,0,0,402,
+ 403,1,0,0,0,403,47,1,0,0,0,404,402,1,0,0,0,405,407,3,74,37,0,406,408,
+ 7,6,0,0,407,406,1,0,0,0,407,408,1,0,0,0,408,411,1,0,0,0,409,410,5,117,
+ 0,0,410,412,7,7,0,0,411,409,1,0,0,0,411,412,1,0,0,0,412,415,1,0,0,0,413,
+ 414,5,26,0,0,414,416,5,200,0,0,415,413,1,0,0,0,415,416,1,0,0,0,416,49,
+ 1,0,0,0,417,424,3,122,61,0,418,421,3,106,53,0,419,420,5,238,0,0,420,422,
+ 3,106,53,0,421,419,1,0,0,0,421,422,1,0,0,0,422,424,1,0,0,0,423,417,1,
+ 0,0,0,423,418,1,0,0,0,424,51,1,0,0,0,425,430,3,54,27,0,426,427,5,206,
+ 0,0,427,429,3,54,27,0,428,426,1,0,0,0,429,432,1,0,0,0,430,428,1,0,0,0,
+ 430,431,1,0,0,0,431,53,1,0,0,0,432,430,1,0,0,0,433,434,3,118,59,0,434,
+ 435,5,212,0,0,435,436,3,108,54,0,436,55,1,0,0,0,437,439,3,58,29,0,438,
+ 437,1,0,0,0,438,439,1,0,0,0,439,441,1,0,0,0,440,442,3,60,30,0,441,440,
+ 1,0,0,0,441,442,1,0,0,0,442,444,1,0,0,0,443,445,3,62,31,0,444,443,1,0,
+ 0,0,444,445,1,0,0,0,445,57,1,0,0,0,446,447,5,126,0,0,447,448,5,18,0,0,
+ 448,449,3,72,36,0,449,59,1,0,0,0,450,451,5,122,0,0,451,452,5,18,0,0,452,
+ 453,3,46,23,0,453,61,1,0,0,0,454,455,7,8,0,0,455,456,3,64,32,0,456,63,
+ 1,0,0,0,457,464,3,66,33,0,458,459,5,16,0,0,459,460,3,66,33,0,460,461,
+ 5,6,0,0,461,462,3,66,33,0,462,464,1,0,0,0,463,457,1,0,0,0,463,458,1,0,
+ 0,0,464,65,1,0,0,0,465,466,5,33,0,0,466,478,5,142,0,0,467,468,5,175,0,
+ 0,468,478,5,128,0,0,469,470,5,175,0,0,470,478,5,64,0,0,471,472,3,106,
+ 53,0,472,473,5,128,0,0,473,478,1,0,0,0,474,475,3,106,53,0,475,476,5,64,
+ 0,0,476,478,1,0,0,0,477,465,1,0,0,0,477,467,1,0,0,0,477,469,1,0,0,0,477,
+ 471,1,0,0,0,477,474,1,0,0,0,478,67,1,0,0,0,479,480,3,74,37,0,480,481,
+ 5,0,0,1,481,69,1,0,0,0,482,530,3,118,59,0,483,484,3,118,59,0,484,485,
+ 5,220,0,0,485,486,3,118,59,0,486,493,3,70,35,0,487,488,5,206,0,0,488,
+ 489,3,118,59,0,489,490,3,70,35,0,490,492,1,0,0,0,491,487,1,0,0,0,492,
+ 495,1,0,0,0,493,491,1,0,0,0,493,494,1,0,0,0,494,496,1,0,0,0,495,493,1,
+ 0,0,0,496,497,5,236,0,0,497,530,1,0,0,0,498,499,3,118,59,0,499,500,5,
+ 220,0,0,500,505,3,120,60,0,501,502,5,206,0,0,502,504,3,120,60,0,503,501,
+ 1,0,0,0,504,507,1,0,0,0,505,503,1,0,0,0,505,506,1,0,0,0,506,508,1,0,0,
+ 0,507,505,1,0,0,0,508,509,5,236,0,0,509,530,1,0,0,0,510,511,3,118,59,
+ 0,511,512,5,220,0,0,512,517,3,70,35,0,513,514,5,206,0,0,514,516,3,70,
+ 35,0,515,513,1,0,0,0,516,519,1,0,0,0,517,515,1,0,0,0,517,518,1,0,0,0,
+ 518,520,1,0,0,0,519,517,1,0,0,0,520,521,5,236,0,0,521,530,1,0,0,0,522,
+ 523,3,118,59,0,523,525,5,220,0,0,524,526,3,72,36,0,525,524,1,0,0,0,525,
+ 526,1,0,0,0,526,527,1,0,0,0,527,528,5,236,0,0,528,530,1,0,0,0,529,482,
+ 1,0,0,0,529,483,1,0,0,0,529,498,1,0,0,0,529,510,1,0,0,0,529,522,1,0,0,
+ 0,530,71,1,0,0,0,531,536,3,74,37,0,532,533,5,206,0,0,533,535,3,74,37,
+ 0,534,532,1,0,0,0,535,538,1,0,0,0,536,534,1,0,0,0,536,537,1,0,0,0,537,
+ 73,1,0,0,0,538,536,1,0,0,0,539,540,6,37,-1,0,540,542,5,19,0,0,541,543,
+ 3,74,37,0,542,541,1,0,0,0,542,543,1,0,0,0,543,549,1,0,0,0,544,545,5,186,
+ 0,0,545,546,3,74,37,0,546,547,5,163,0,0,547,548,3,74,37,0,548,550,1,0,
+ 0,0,549,544,1,0,0,0,550,551,1,0,0,0,551,549,1,0,0,0,551,552,1,0,0,0,552,
+ 555,1,0,0,0,553,554,5,52,0,0,554,556,3,74,37,0,555,553,1,0,0,0,555,556,
+ 1,0,0,0,556,557,1,0,0,0,557,558,5,53,0,0,558,663,1,0,0,0,559,560,5,20,
+ 0,0,560,561,5,220,0,0,561,562,3,74,37,0,562,563,5,10,0,0,563,564,3,70,
+ 35,0,564,565,5,236,0,0,565,663,1,0,0,0,566,567,5,36,0,0,567,663,5,200,
+ 0,0,568,569,5,86,0,0,569,570,3,74,37,0,570,571,3,110,55,0,571,663,1,0,
+ 0,0,572,573,5,155,0,0,573,574,5,220,0,0,574,575,3,74,37,0,575,576,5,68,
+ 0,0,576,579,3,74,37,0,577,578,5,65,0,0,578,580,3,74,37,0,579,577,1,0,
+ 0,0,579,580,1,0,0,0,580,581,1,0,0,0,581,582,5,236,0,0,582,663,1,0,0,0,
+ 583,584,5,166,0,0,584,663,5,200,0,0,585,586,5,171,0,0,586,587,5,220,0,
+ 0,587,588,7,9,0,0,588,589,5,200,0,0,589,590,5,68,0,0,590,591,3,74,37,
+ 0,591,592,5,236,0,0,592,663,1,0,0,0,593,594,3,118,59,0,594,596,5,220,
+ 0,0,595,597,3,72,36,0,596,595,1,0,0,0,596,597,1,0,0,0,597,598,1,0,0,0,
+ 598,599,5,236,0,0,599,600,1,0,0,0,600,601,5,125,0,0,601,602,5,220,0,0,
+ 602,603,3,56,28,0,603,604,5,236,0,0,604,663,1,0,0,0,605,606,3,118,59,
+ 0,606,608,5,220,0,0,607,609,3,72,36,0,608,607,1,0,0,0,608,609,1,0,0,0,
+ 609,610,1,0,0,0,610,611,5,236,0,0,611,612,1,0,0,0,612,613,5,125,0,0,613,
+ 614,3,118,59,0,614,663,1,0,0,0,615,621,3,118,59,0,616,618,5,220,0,0,617,
+ 619,3,72,36,0,618,617,1,0,0,0,618,619,1,0,0,0,619,620,1,0,0,0,620,622,
+ 5,236,0,0,621,616,1,0,0,0,621,622,1,0,0,0,622,623,1,0,0,0,623,625,5,220,
+ 0,0,624,626,5,49,0,0,625,624,1,0,0,0,625,626,1,0,0,0,626,628,1,0,0,0,
+ 627,629,3,76,38,0,628,627,1,0,0,0,628,629,1,0,0,0,629,630,1,0,0,0,630,
+ 631,5,236,0,0,631,663,1,0,0,0,632,663,3,82,41,0,633,663,3,108,54,0,634,
+ 635,5,208,0,0,635,663,3,74,37,18,636,637,5,115,0,0,637,663,3,74,37,12,
+ 638,639,3,98,49,0,639,640,5,210,0,0,640,642,1,0,0,0,641,638,1,0,0,0,641,
+ 642,1,0,0,0,642,643,1,0,0,0,643,663,5,202,0,0,644,645,5,220,0,0,645,646,
+ 3,2,1,0,646,647,5,236,0,0,647,663,1,0,0,0,648,649,5,220,0,0,649,650,3,
+ 74,37,0,650,651,5,236,0,0,651,663,1,0,0,0,652,653,5,220,0,0,653,654,3,
+ 72,36,0,654,655,5,236,0,0,655,663,1,0,0,0,656,658,5,219,0,0,657,659,3,
+ 72,36,0,658,657,1,0,0,0,658,659,1,0,0,0,659,660,1,0,0,0,660,663,5,235,
+ 0,0,661,663,3,90,45,0,662,539,1,0,0,0,662,559,1,0,0,0,662,566,1,0,0,0,
+ 662,568,1,0,0,0,662,572,1,0,0,0,662,583,1,0,0,0,662,585,1,0,0,0,662,593,
+ 1,0,0,0,662,605,1,0,0,0,662,615,1,0,0,0,662,632,1,0,0,0,662,633,1,0,0,
+ 0,662,634,1,0,0,0,662,636,1,0,0,0,662,641,1,0,0,0,662,644,1,0,0,0,662,
+ 648,1,0,0,0,662,652,1,0,0,0,662,656,1,0,0,0,662,661,1,0,0,0,663,757,1,
+ 0,0,0,664,668,10,17,0,0,665,669,5,202,0,0,666,669,5,238,0,0,667,669,5,
+ 227,0,0,668,665,1,0,0,0,668,666,1,0,0,0,668,667,1,0,0,0,669,670,1,0,0,
+ 0,670,756,3,74,37,18,671,675,10,16,0,0,672,676,5,228,0,0,673,676,5,208,
+ 0,0,674,676,5,207,0,0,675,672,1,0,0,0,675,673,1,0,0,0,675,674,1,0,0,0,
+ 676,677,1,0,0,0,677,756,3,74,37,17,678,703,10,15,0,0,679,704,5,211,0,
+ 0,680,704,5,212,0,0,681,704,5,223,0,0,682,704,5,221,0,0,683,704,5,222,
+ 0,0,684,704,5,213,0,0,685,704,5,214,0,0,686,688,5,115,0,0,687,686,1,0,
+ 0,0,687,688,1,0,0,0,688,689,1,0,0,0,689,691,5,80,0,0,690,692,5,25,0,0,
+ 691,690,1,0,0,0,691,692,1,0,0,0,692,704,1,0,0,0,693,695,5,115,0,0,694,
+ 693,1,0,0,0,694,695,1,0,0,0,695,696,1,0,0,0,696,704,7,10,0,0,697,704,
+ 5,232,0,0,698,704,5,233,0,0,699,704,5,225,0,0,700,704,5,216,0,0,701,704,
+ 5,217,0,0,702,704,5,224,0,0,703,679,1,0,0,0,703,680,1,0,0,0,703,681,1,
+ 0,0,0,703,682,1,0,0,0,703,683,1,0,0,0,703,684,1,0,0,0,703,685,1,0,0,0,
+ 703,687,1,0,0,0,703,694,1,0,0,0,703,697,1,0,0,0,703,698,1,0,0,0,703,699,
+ 1,0,0,0,703,700,1,0,0,0,703,701,1,0,0,0,703,702,1,0,0,0,704,705,1,0,0,
+ 0,705,756,3,74,37,16,706,707,10,13,0,0,707,708,5,226,0,0,708,756,3,74,
+ 37,14,709,710,10,11,0,0,710,711,5,6,0,0,711,756,3,74,37,12,712,713,10,
+ 10,0,0,713,714,5,121,0,0,714,756,3,74,37,11,715,717,10,9,0,0,716,718,
+ 5,115,0,0,717,716,1,0,0,0,717,718,1,0,0,0,718,719,1,0,0,0,719,720,5,16,
+ 0,0,720,721,3,74,37,0,721,722,5,6,0,0,722,723,3,74,37,10,723,756,1,0,
+ 0,0,724,725,10,8,0,0,725,726,5,229,0,0,726,727,3,74,37,0,727,728,5,205,
+ 0,0,728,729,3,74,37,8,729,756,1,0,0,0,730,731,10,21,0,0,731,732,5,219,
+ 0,0,732,733,3,74,37,0,733,734,5,235,0,0,734,756,1,0,0,0,735,736,10,20,
+ 0,0,736,737,5,210,0,0,737,756,5,198,0,0,738,739,10,19,0,0,739,740,5,210,
+ 0,0,740,756,3,118,59,0,741,742,10,14,0,0,742,744,5,88,0,0,743,745,5,115,
+ 0,0,744,743,1,0,0,0,744,745,1,0,0,0,745,746,1,0,0,0,746,756,5,116,0,0,
+ 747,753,10,7,0,0,748,754,3,116,58,0,749,750,5,10,0,0,750,754,3,118,59,
+ 0,751,752,5,10,0,0,752,754,5,200,0,0,753,748,1,0,0,0,753,749,1,0,0,0,
+ 753,751,1,0,0,0,754,756,1,0,0,0,755,664,1,0,0,0,755,671,1,0,0,0,755,678,
+ 1,0,0,0,755,706,1,0,0,0,755,709,1,0,0,0,755,712,1,0,0,0,755,715,1,0,0,
+ 0,755,724,1,0,0,0,755,730,1,0,0,0,755,735,1,0,0,0,755,738,1,0,0,0,755,
+ 741,1,0,0,0,755,747,1,0,0,0,756,759,1,0,0,0,757,755,1,0,0,0,757,758,1,
+ 0,0,0,758,75,1,0,0,0,759,757,1,0,0,0,760,765,3,78,39,0,761,762,5,206,
+ 0,0,762,764,3,78,39,0,763,761,1,0,0,0,764,767,1,0,0,0,765,763,1,0,0,0,
+ 765,766,1,0,0,0,766,77,1,0,0,0,767,765,1,0,0,0,768,771,3,80,40,0,769,
+ 771,3,74,37,0,770,768,1,0,0,0,770,769,1,0,0,0,771,79,1,0,0,0,772,773,
+ 5,220,0,0,773,778,3,118,59,0,774,775,5,206,0,0,775,777,3,118,59,0,776,
+ 774,1,0,0,0,777,780,1,0,0,0,778,776,1,0,0,0,778,779,1,0,0,0,779,781,1,
+ 0,0,0,780,778,1,0,0,0,781,782,5,236,0,0,782,792,1,0,0,0,783,788,3,118,
+ 59,0,784,785,5,206,0,0,785,787,3,118,59,0,786,784,1,0,0,0,787,790,1,0,
+ 0,0,788,786,1,0,0,0,788,789,1,0,0,0,789,792,1,0,0,0,790,788,1,0,0,0,791,
+ 772,1,0,0,0,791,783,1,0,0,0,792,793,1,0,0,0,793,794,5,201,0,0,794,795,
+ 3,74,37,0,795,81,1,0,0,0,796,797,5,222,0,0,797,801,3,118,59,0,798,800,
+ 3,84,42,0,799,798,1,0,0,0,800,803,1,0,0,0,801,799,1,0,0,0,801,802,1,0,
+ 0,0,802,804,1,0,0,0,803,801,1,0,0,0,804,805,5,238,0,0,805,806,5,214,0,
+ 0,806,825,1,0,0,0,807,808,5,222,0,0,808,812,3,118,59,0,809,811,3,84,42,
+ 0,810,809,1,0,0,0,811,814,1,0,0,0,812,810,1,0,0,0,812,813,1,0,0,0,813,
+ 815,1,0,0,0,814,812,1,0,0,0,815,817,5,214,0,0,816,818,3,82,41,0,817,816,
+ 1,0,0,0,817,818,1,0,0,0,818,819,1,0,0,0,819,820,5,222,0,0,820,821,5,238,
+ 0,0,821,822,3,118,59,0,822,823,5,214,0,0,823,825,1,0,0,0,824,796,1,0,
+ 0,0,824,807,1,0,0,0,825,83,1,0,0,0,826,827,3,118,59,0,827,828,5,212,0,
+ 0,828,829,5,200,0,0,829,838,1,0,0,0,830,831,3,118,59,0,831,832,5,212,
+ 0,0,832,833,5,218,0,0,833,834,3,74,37,0,834,835,5,234,0,0,835,838,1,0,
+ 0,0,836,838,3,118,59,0,837,826,1,0,0,0,837,830,1,0,0,0,837,836,1,0,0,
+ 0,838,85,1,0,0,0,839,844,3,88,44,0,840,841,5,206,0,0,841,843,3,88,44,
+ 0,842,840,1,0,0,0,843,846,1,0,0,0,844,842,1,0,0,0,844,845,1,0,0,0,845,
+ 87,1,0,0,0,846,844,1,0,0,0,847,848,3,118,59,0,848,849,5,10,0,0,849,850,
+ 5,220,0,0,850,851,3,2,1,0,851,852,5,236,0,0,852,858,1,0,0,0,853,854,3,
+ 74,37,0,854,855,5,10,0,0,855,856,3,118,59,0,856,858,1,0,0,0,857,847,1,
+ 0,0,0,857,853,1,0,0,0,858,89,1,0,0,0,859,867,3,122,61,0,860,861,3,98,
+ 49,0,861,862,5,210,0,0,862,864,1,0,0,0,863,860,1,0,0,0,863,864,1,0,0,
+ 0,864,865,1,0,0,0,865,867,3,92,46,0,866,859,1,0,0,0,866,863,1,0,0,0,867,
+ 91,1,0,0,0,868,873,3,118,59,0,869,870,5,210,0,0,870,872,3,118,59,0,871,
+ 869,1,0,0,0,872,875,1,0,0,0,873,871,1,0,0,0,873,874,1,0,0,0,874,93,1,
+ 0,0,0,875,873,1,0,0,0,876,877,6,47,-1,0,877,886,3,98,49,0,878,886,3,96,
+ 48,0,879,880,5,220,0,0,880,881,3,2,1,0,881,882,5,236,0,0,882,886,1,0,
+ 0,0,883,886,3,82,41,0,884,886,3,122,61,0,885,876,1,0,0,0,885,878,1,0,
+ 0,0,885,879,1,0,0,0,885,883,1,0,0,0,885,884,1,0,0,0,886,895,1,0,0,0,887,
+ 891,10,3,0,0,888,892,3,116,58,0,889,890,5,10,0,0,890,892,3,118,59,0,891,
+ 888,1,0,0,0,891,889,1,0,0,0,892,894,1,0,0,0,893,887,1,0,0,0,894,897,1,
+ 0,0,0,895,893,1,0,0,0,895,896,1,0,0,0,896,95,1,0,0,0,897,895,1,0,0,0,
+ 898,899,3,118,59,0,899,901,5,220,0,0,900,902,3,100,50,0,901,900,1,0,0,
+ 0,901,902,1,0,0,0,902,903,1,0,0,0,903,904,5,236,0,0,904,97,1,0,0,0,905,
+ 906,3,102,51,0,906,907,5,210,0,0,907,909,1,0,0,0,908,905,1,0,0,0,908,
+ 909,1,0,0,0,909,910,1,0,0,0,910,911,3,118,59,0,911,99,1,0,0,0,912,917,
+ 3,74,37,0,913,914,5,206,0,0,914,916,3,74,37,0,915,913,1,0,0,0,916,919,
+ 1,0,0,0,917,915,1,0,0,0,917,918,1,0,0,0,918,101,1,0,0,0,919,917,1,0,0,
+ 0,920,921,3,118,59,0,921,103,1,0,0,0,922,931,5,196,0,0,923,924,5,210,
+ 0,0,924,931,7,11,0,0,925,926,5,198,0,0,926,928,5,210,0,0,927,929,7,11,
+ 0,0,928,927,1,0,0,0,928,929,1,0,0,0,929,931,1,0,0,0,930,922,1,0,0,0,930,
+ 923,1,0,0,0,930,925,1,0,0,0,931,105,1,0,0,0,932,934,7,12,0,0,933,932,
+ 1,0,0,0,933,934,1,0,0,0,934,941,1,0,0,0,935,942,3,104,52,0,936,942,5,
+ 197,0,0,937,942,5,198,0,0,938,942,5,199,0,0,939,942,5,82,0,0,940,942,
+ 5,113,0,0,941,935,1,0,0,0,941,936,1,0,0,0,941,937,1,0,0,0,941,938,1,0,
+ 0,0,941,939,1,0,0,0,941,940,1,0,0,0,942,107,1,0,0,0,943,947,3,106,53,
+ 0,944,947,5,200,0,0,945,947,5,116,0,0,946,943,1,0,0,0,946,944,1,0,0,0,
+ 946,945,1,0,0,0,947,109,1,0,0,0,948,949,7,13,0,0,949,111,1,0,0,0,950,
+ 951,7,14,0,0,951,113,1,0,0,0,952,953,7,15,0,0,953,115,1,0,0,0,954,957,
+ 5,195,0,0,955,957,3,114,57,0,956,954,1,0,0,0,956,955,1,0,0,0,957,117,
+ 1,0,0,0,958,962,5,195,0,0,959,962,3,110,55,0,960,962,3,112,56,0,961,958,
+ 1,0,0,0,961,959,1,0,0,0,961,960,1,0,0,0,962,119,1,0,0,0,963,964,5,200,
+ 0,0,964,965,5,212,0,0,965,966,3,106,53,0,966,121,1,0,0,0,967,968,5,218,
+ 0,0,968,969,3,118,59,0,969,970,5,234,0,0,970,123,1,0,0,0,120,127,137,
+ 146,149,153,156,160,163,166,169,172,176,180,183,186,189,193,196,205,211,
+ 232,249,266,272,278,289,291,302,305,311,319,325,327,331,336,339,342,346,
+ 350,353,355,358,362,366,369,371,373,378,389,395,402,407,411,415,421,423,
+ 430,438,441,444,463,477,493,505,517,525,529,536,542,551,555,579,596,608,
+ 618,621,625,628,641,658,662,668,675,687,691,694,703,717,744,753,755,757,
+ 765,770,778,788,791,801,812,817,824,837,844,857,863,866,873,885,891,895,
+ 901,908,917,928,930,933,941,946,956,961
};
staticData->serializedATN = antlr4::atn::SerializedATNView(serializedATNSegment, sizeof(serializedATNSegment) / sizeof(serializedATNSegment[0]));
@@ -4552,41 +4550,6 @@ std::any HogQLParser::ColumnExprAliasContext::accept(tree::ParseTreeVisitor *vis
else
return visitor->visitChildren(this);
}
-//----------------- ColumnExprExtractContext ------------------------------------------------------------------
-
-tree::TerminalNode* HogQLParser::ColumnExprExtractContext::EXTRACT() {
- return getToken(HogQLParser::EXTRACT, 0);
-}
-
-tree::TerminalNode* HogQLParser::ColumnExprExtractContext::LPAREN() {
- return getToken(HogQLParser::LPAREN, 0);
-}
-
-HogQLParser::IntervalContext* HogQLParser::ColumnExprExtractContext::interval() {
- return getRuleContext(0);
-}
-
-tree::TerminalNode* HogQLParser::ColumnExprExtractContext::FROM() {
- return getToken(HogQLParser::FROM, 0);
-}
-
-HogQLParser::ColumnExprContext* HogQLParser::ColumnExprExtractContext::columnExpr() {
- return getRuleContext(0);
-}
-
-tree::TerminalNode* HogQLParser::ColumnExprExtractContext::RPAREN() {
- return getToken(HogQLParser::RPAREN, 0);
-}
-
-HogQLParser::ColumnExprExtractContext::ColumnExprExtractContext(ColumnExprContext *ctx) { copyFrom(ctx); }
-
-
-std::any HogQLParser::ColumnExprExtractContext::accept(tree::ParseTreeVisitor *visitor) {
- if (auto parserVisitor = dynamic_cast(visitor))
- return parserVisitor->visitColumnExprExtract(this);
- else
- return visitor->visitChildren(this);
-}
//----------------- ColumnExprNegateContext ------------------------------------------------------------------
tree::TerminalNode* HogQLParser::ColumnExprNegateContext::DASH() {
@@ -5514,7 +5477,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
try {
size_t alt;
enterOuterAlt(_localctx, 1);
- setState(669);
+ setState(662);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 80, _ctx)) {
case 1: {
@@ -5599,86 +5562,67 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
}
case 4: {
- _localctx = _tracker.createInstance(_localctx);
+ _localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
setState(568);
- match(HogQLParser::EXTRACT);
+ match(HogQLParser::INTERVAL);
setState(569);
- match(HogQLParser::LPAREN);
+ columnExpr(0);
setState(570);
interval();
- setState(571);
- match(HogQLParser::FROM);
- setState(572);
- columnExpr(0);
- setState(573);
- match(HogQLParser::RPAREN);
break;
}
case 5: {
- _localctx = _tracker.createInstance(_localctx);
- _ctx = _localctx;
- previousContext = _localctx;
- setState(575);
- match(HogQLParser::INTERVAL);
- setState(576);
- columnExpr(0);
- setState(577);
- interval();
- break;
- }
-
- case 6: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(579);
+ setState(572);
match(HogQLParser::SUBSTRING);
- setState(580);
+ setState(573);
match(HogQLParser::LPAREN);
- setState(581);
+ setState(574);
columnExpr(0);
- setState(582);
+ setState(575);
match(HogQLParser::FROM);
- setState(583);
+ setState(576);
columnExpr(0);
- setState(586);
+ setState(579);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::FOR) {
- setState(584);
+ setState(577);
match(HogQLParser::FOR);
- setState(585);
+ setState(578);
columnExpr(0);
}
- setState(588);
+ setState(581);
match(HogQLParser::RPAREN);
break;
}
- case 7: {
+ case 6: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(590);
+ setState(583);
match(HogQLParser::TIMESTAMP);
- setState(591);
+ setState(584);
match(HogQLParser::STRING_LITERAL);
break;
}
- case 8: {
+ case 7: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(592);
+ setState(585);
match(HogQLParser::TRIM);
- setState(593);
+ setState(586);
match(HogQLParser::LPAREN);
- setState(594);
+ setState(587);
_la = _input->LA(1);
if (!(_la == HogQLParser::BOTH || _la == HogQLParser::LEADING || _la == HogQLParser::TRAILING)) {
_errHandler->recoverInline(this);
@@ -5687,27 +5631,27 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
_errHandler->reportMatch(this);
consume();
}
- setState(595);
+ setState(588);
match(HogQLParser::STRING_LITERAL);
- setState(596);
+ setState(589);
match(HogQLParser::FROM);
- setState(597);
+ setState(590);
columnExpr(0);
- setState(598);
+ setState(591);
match(HogQLParser::RPAREN);
break;
}
- case 9: {
+ case 8: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(600);
+ setState(593);
identifier();
- setState(601);
+ setState(594);
match(HogQLParser::LPAREN);
- setState(603);
+ setState(596);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -5716,32 +5660,32 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
((1ULL << (_la - 64)) & -1) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 128)) & -9) != 0) || ((((_la - 192) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 192)) & 70263309817) != 0)) {
- setState(602);
+ setState(595);
columnExprList();
}
- setState(605);
+ setState(598);
match(HogQLParser::RPAREN);
- setState(607);
+ setState(600);
match(HogQLParser::OVER);
- setState(608);
+ setState(601);
match(HogQLParser::LPAREN);
- setState(609);
+ setState(602);
windowExpr();
- setState(610);
+ setState(603);
match(HogQLParser::RPAREN);
break;
}
- case 10: {
+ case 9: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(612);
+ setState(605);
identifier();
- setState(613);
+ setState(606);
match(HogQLParser::LPAREN);
- setState(615);
+ setState(608);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -5750,32 +5694,32 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
((1ULL << (_la - 64)) & -1) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 128)) & -9) != 0) || ((((_la - 192) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 192)) & 70263309817) != 0)) {
- setState(614);
+ setState(607);
columnExprList();
}
- setState(617);
+ setState(610);
match(HogQLParser::RPAREN);
- setState(619);
+ setState(612);
match(HogQLParser::OVER);
- setState(620);
+ setState(613);
identifier();
break;
}
- case 11: {
+ case 10: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(622);
+ setState(615);
identifier();
- setState(628);
+ setState(621);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 75, _ctx)) {
case 1: {
- setState(623);
+ setState(616);
match(HogQLParser::LPAREN);
- setState(625);
+ setState(618);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -5784,10 +5728,10 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
((1ULL << (_la - 64)) & -1) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 128)) & -9) != 0) || ((((_la - 192) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 192)) & 70263309817) != 0)) {
- setState(624);
+ setState(617);
columnExprList();
}
- setState(627);
+ setState(620);
match(HogQLParser::RPAREN);
break;
}
@@ -5795,14 +5739,14 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
default:
break;
}
- setState(630);
+ setState(623);
match(HogQLParser::LPAREN);
- setState(632);
+ setState(625);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 76, _ctx)) {
case 1: {
- setState(631);
+ setState(624);
match(HogQLParser::DISTINCT);
break;
}
@@ -5810,7 +5754,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
default:
break;
}
- setState(635);
+ setState(628);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -5819,59 +5763,59 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
((1ULL << (_la - 64)) & -1) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 128)) & -9) != 0) || ((((_la - 192) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 192)) & 70263309817) != 0)) {
- setState(634);
+ setState(627);
columnArgList();
}
- setState(637);
+ setState(630);
match(HogQLParser::RPAREN);
break;
}
- case 12: {
+ case 11: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(639);
+ setState(632);
hogqlxTagElement();
break;
}
- case 13: {
+ case 12: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(640);
+ setState(633);
literal();
break;
}
- case 14: {
+ case 13: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(641);
+ setState(634);
match(HogQLParser::DASH);
- setState(642);
+ setState(635);
columnExpr(18);
break;
}
- case 15: {
+ case 14: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(643);
+ setState(636);
match(HogQLParser::NOT);
- setState(644);
+ setState(637);
columnExpr(12);
break;
}
- case 16: {
+ case 15: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(648);
+ setState(641);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -5881,62 +5825,62 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
((1ULL << (_la - 128)) & -9) != 0) || _la == HogQLParser::JSON_TRUE
|| _la == HogQLParser::IDENTIFIER) {
- setState(645);
+ setState(638);
tableIdentifier();
- setState(646);
+ setState(639);
match(HogQLParser::DOT);
}
- setState(650);
+ setState(643);
match(HogQLParser::ASTERISK);
break;
}
- case 17: {
+ case 16: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(651);
+ setState(644);
match(HogQLParser::LPAREN);
- setState(652);
+ setState(645);
selectUnionStmt();
- setState(653);
+ setState(646);
match(HogQLParser::RPAREN);
break;
}
- case 18: {
+ case 17: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(655);
+ setState(648);
match(HogQLParser::LPAREN);
- setState(656);
+ setState(649);
columnExpr(0);
- setState(657);
+ setState(650);
match(HogQLParser::RPAREN);
break;
}
- case 19: {
+ case 18: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(659);
+ setState(652);
match(HogQLParser::LPAREN);
- setState(660);
+ setState(653);
columnExprList();
- setState(661);
+ setState(654);
match(HogQLParser::RPAREN);
break;
}
- case 20: {
+ case 19: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(663);
+ setState(656);
match(HogQLParser::LBRACKET);
- setState(665);
+ setState(658);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -5945,19 +5889,19 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
((1ULL << (_la - 64)) & -1) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 128)) & -9) != 0) || ((((_la - 192) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 192)) & 70263309817) != 0)) {
- setState(664);
+ setState(657);
columnExprList();
}
- setState(667);
+ setState(660);
match(HogQLParser::RBRACKET);
break;
}
- case 21: {
+ case 20: {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(668);
+ setState(661);
columnIdentifier();
break;
}
@@ -5966,7 +5910,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
break;
}
_ctx->stop = _input->LT(-1);
- setState(764);
+ setState(757);
_errHandler->sync(this);
alt = getInterpreter()->adaptivePredict(_input, 91, _ctx);
while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) {
@@ -5974,7 +5918,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
if (!_parseListeners.empty())
triggerExitRuleEvent();
previousContext = _localctx;
- setState(762);
+ setState(755);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 90, _ctx)) {
case 1: {
@@ -5982,26 +5926,26 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
_localctx = newContext;
newContext->left = previousContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(671);
+ setState(664);
if (!(precpred(_ctx, 17))) throw FailedPredicateException(this, "precpred(_ctx, 17)");
- setState(675);
+ setState(668);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::ASTERISK: {
- setState(672);
+ setState(665);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::ASTERISK);
break;
}
case HogQLParser::SLASH: {
- setState(673);
+ setState(666);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::SLASH);
break;
}
case HogQLParser::PERCENT: {
- setState(674);
+ setState(667);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::PERCENT);
break;
}
@@ -6009,7 +5953,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
default:
throw NoViableAltException(this);
}
- setState(677);
+ setState(670);
antlrcpp::downCast(_localctx)->right = columnExpr(18);
break;
}
@@ -6019,26 +5963,26 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
_localctx = newContext;
newContext->left = previousContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(678);
+ setState(671);
if (!(precpred(_ctx, 16))) throw FailedPredicateException(this, "precpred(_ctx, 16)");
- setState(682);
+ setState(675);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::PLUS: {
- setState(679);
+ setState(672);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::PLUS);
break;
}
case HogQLParser::DASH: {
- setState(680);
+ setState(673);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::DASH);
break;
}
case HogQLParser::CONCAT: {
- setState(681);
+ setState(674);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::CONCAT);
break;
}
@@ -6046,7 +5990,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
default:
throw NoViableAltException(this);
}
- setState(684);
+ setState(677);
antlrcpp::downCast(_localctx)->right = columnExpr(17);
break;
}
@@ -6056,86 +6000,86 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
_localctx = newContext;
newContext->left = previousContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(685);
+ setState(678);
if (!(precpred(_ctx, 15))) throw FailedPredicateException(this, "precpred(_ctx, 15)");
- setState(710);
+ setState(703);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 86, _ctx)) {
case 1: {
- setState(686);
+ setState(679);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::EQ_DOUBLE);
break;
}
case 2: {
- setState(687);
+ setState(680);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::EQ_SINGLE);
break;
}
case 3: {
- setState(688);
+ setState(681);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::NOT_EQ);
break;
}
case 4: {
- setState(689);
+ setState(682);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::LT_EQ);
break;
}
case 5: {
- setState(690);
+ setState(683);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::LT);
break;
}
case 6: {
- setState(691);
+ setState(684);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::GT_EQ);
break;
}
case 7: {
- setState(692);
+ setState(685);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::GT);
break;
}
case 8: {
- setState(694);
+ setState(687);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::NOT) {
- setState(693);
+ setState(686);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::NOT);
}
- setState(696);
+ setState(689);
match(HogQLParser::IN);
- setState(698);
+ setState(691);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::COHORT) {
- setState(697);
+ setState(690);
match(HogQLParser::COHORT);
}
break;
}
case 9: {
- setState(701);
+ setState(694);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::NOT) {
- setState(700);
+ setState(693);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::NOT);
}
- setState(703);
+ setState(696);
_la = _input->LA(1);
if (!(_la == HogQLParser::ILIKE
@@ -6150,37 +6094,37 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
}
case 10: {
- setState(704);
+ setState(697);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::REGEX_SINGLE);
break;
}
case 11: {
- setState(705);
+ setState(698);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::REGEX_DOUBLE);
break;
}
case 12: {
- setState(706);
+ setState(699);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::NOT_REGEX);
break;
}
case 13: {
- setState(707);
+ setState(700);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::IREGEX_SINGLE);
break;
}
case 14: {
- setState(708);
+ setState(701);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::IREGEX_DOUBLE);
break;
}
case 15: {
- setState(709);
+ setState(702);
antlrcpp::downCast(_localctx)->operator_ = match(HogQLParser::NOT_IREGEX);
break;
}
@@ -6188,7 +6132,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
default:
break;
}
- setState(712);
+ setState(705);
antlrcpp::downCast(_localctx)->right = columnExpr(16);
break;
}
@@ -6197,12 +6141,12 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(713);
+ setState(706);
if (!(precpred(_ctx, 13))) throw FailedPredicateException(this, "precpred(_ctx, 13)");
- setState(714);
+ setState(707);
match(HogQLParser::NULLISH);
- setState(715);
+ setState(708);
columnExpr(14);
break;
}
@@ -6211,12 +6155,12 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(716);
+ setState(709);
if (!(precpred(_ctx, 11))) throw FailedPredicateException(this, "precpred(_ctx, 11)");
- setState(717);
+ setState(710);
match(HogQLParser::AND);
- setState(718);
+ setState(711);
columnExpr(12);
break;
}
@@ -6225,12 +6169,12 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(719);
+ setState(712);
if (!(precpred(_ctx, 10))) throw FailedPredicateException(this, "precpred(_ctx, 10)");
- setState(720);
+ setState(713);
match(HogQLParser::OR);
- setState(721);
+ setState(714);
columnExpr(11);
break;
}
@@ -6239,24 +6183,24 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(722);
+ setState(715);
if (!(precpred(_ctx, 9))) throw FailedPredicateException(this, "precpred(_ctx, 9)");
- setState(724);
+ setState(717);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::NOT) {
- setState(723);
+ setState(716);
match(HogQLParser::NOT);
}
- setState(726);
+ setState(719);
match(HogQLParser::BETWEEN);
- setState(727);
+ setState(720);
columnExpr(0);
- setState(728);
+ setState(721);
match(HogQLParser::AND);
- setState(729);
+ setState(722);
columnExpr(10);
break;
}
@@ -6265,16 +6209,16 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(731);
+ setState(724);
if (!(precpred(_ctx, 8))) throw FailedPredicateException(this, "precpred(_ctx, 8)");
- setState(732);
+ setState(725);
match(HogQLParser::QUERY);
- setState(733);
+ setState(726);
columnExpr(0);
- setState(734);
+ setState(727);
match(HogQLParser::COLON);
- setState(735);
+ setState(728);
columnExpr(8);
break;
}
@@ -6283,14 +6227,14 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(737);
+ setState(730);
if (!(precpred(_ctx, 21))) throw FailedPredicateException(this, "precpred(_ctx, 21)");
- setState(738);
+ setState(731);
match(HogQLParser::LBRACKET);
- setState(739);
+ setState(732);
columnExpr(0);
- setState(740);
+ setState(733);
match(HogQLParser::RBRACKET);
break;
}
@@ -6299,12 +6243,12 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(742);
+ setState(735);
if (!(precpred(_ctx, 20))) throw FailedPredicateException(this, "precpred(_ctx, 20)");
- setState(743);
+ setState(736);
match(HogQLParser::DOT);
- setState(744);
+ setState(737);
match(HogQLParser::DECIMAL_LITERAL);
break;
}
@@ -6313,12 +6257,12 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(745);
+ setState(738);
if (!(precpred(_ctx, 19))) throw FailedPredicateException(this, "precpred(_ctx, 19)");
- setState(746);
+ setState(739);
match(HogQLParser::DOT);
- setState(747);
+ setState(740);
identifier();
break;
}
@@ -6327,20 +6271,20 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(748);
+ setState(741);
if (!(precpred(_ctx, 14))) throw FailedPredicateException(this, "precpred(_ctx, 14)");
- setState(749);
+ setState(742);
match(HogQLParser::IS);
- setState(751);
+ setState(744);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::NOT) {
- setState(750);
+ setState(743);
match(HogQLParser::NOT);
}
- setState(753);
+ setState(746);
match(HogQLParser::NULL_SQL);
break;
}
@@ -6349,30 +6293,30 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleColumnExpr);
- setState(754);
+ setState(747);
if (!(precpred(_ctx, 7))) throw FailedPredicateException(this, "precpred(_ctx, 7)");
- setState(760);
+ setState(753);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 89, _ctx)) {
case 1: {
- setState(755);
+ setState(748);
alias();
break;
}
case 2: {
- setState(756);
+ setState(749);
match(HogQLParser::AS);
- setState(757);
+ setState(750);
identifier();
break;
}
case 3: {
- setState(758);
+ setState(751);
match(HogQLParser::AS);
- setState(759);
+ setState(752);
match(HogQLParser::STRING_LITERAL);
break;
}
@@ -6387,7 +6331,7 @@ HogQLParser::ColumnExprContext* HogQLParser::columnExpr(int precedence) {
break;
}
}
- setState(766);
+ setState(759);
_errHandler->sync(this);
alt = getInterpreter()->adaptivePredict(_input, 91, _ctx);
}
@@ -6449,17 +6393,17 @@ HogQLParser::ColumnArgListContext* HogQLParser::columnArgList() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(767);
+ setState(760);
columnArgExpr();
- setState(772);
+ setState(765);
_errHandler->sync(this);
_la = _input->LA(1);
while (_la == HogQLParser::COMMA) {
- setState(768);
+ setState(761);
match(HogQLParser::COMMA);
- setState(769);
+ setState(762);
columnArgExpr();
- setState(774);
+ setState(767);
_errHandler->sync(this);
_la = _input->LA(1);
}
@@ -6513,19 +6457,19 @@ HogQLParser::ColumnArgExprContext* HogQLParser::columnArgExpr() {
exitRule();
});
try {
- setState(777);
+ setState(770);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 93, _ctx)) {
case 1: {
enterOuterAlt(_localctx, 1);
- setState(775);
+ setState(768);
columnLambdaExpr();
break;
}
case 2: {
enterOuterAlt(_localctx, 2);
- setState(776);
+ setState(769);
columnExpr(0);
break;
}
@@ -6609,27 +6553,27 @@ HogQLParser::ColumnLambdaExprContext* HogQLParser::columnLambdaExpr() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(798);
+ setState(791);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::LPAREN: {
- setState(779);
+ setState(772);
match(HogQLParser::LPAREN);
- setState(780);
+ setState(773);
identifier();
- setState(785);
+ setState(778);
_errHandler->sync(this);
_la = _input->LA(1);
while (_la == HogQLParser::COMMA) {
- setState(781);
+ setState(774);
match(HogQLParser::COMMA);
- setState(782);
+ setState(775);
identifier();
- setState(787);
+ setState(780);
_errHandler->sync(this);
_la = _input->LA(1);
}
- setState(788);
+ setState(781);
match(HogQLParser::RPAREN);
break;
}
@@ -6821,17 +6765,17 @@ HogQLParser::ColumnLambdaExprContext* HogQLParser::columnLambdaExpr() {
case HogQLParser::JSON_FALSE:
case HogQLParser::JSON_TRUE:
case HogQLParser::IDENTIFIER: {
- setState(790);
+ setState(783);
identifier();
- setState(795);
+ setState(788);
_errHandler->sync(this);
_la = _input->LA(1);
while (_la == HogQLParser::COMMA) {
- setState(791);
+ setState(784);
match(HogQLParser::COMMA);
- setState(792);
+ setState(785);
identifier();
- setState(797);
+ setState(790);
_errHandler->sync(this);
_la = _input->LA(1);
}
@@ -6841,9 +6785,9 @@ HogQLParser::ColumnLambdaExprContext* HogQLParser::columnLambdaExpr() {
default:
throw NoViableAltException(this);
}
- setState(800);
+ setState(793);
match(HogQLParser::ARROW);
- setState(801);
+ setState(794);
columnExpr(0);
}
@@ -6970,17 +6914,17 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() {
exitRule();
});
try {
- setState(831);
+ setState(824);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 100, _ctx)) {
case 1: {
_localctx = _tracker.createInstance(_localctx);
enterOuterAlt(_localctx, 1);
- setState(803);
+ setState(796);
match(HogQLParser::LT);
- setState(804);
+ setState(797);
identifier();
- setState(808);
+ setState(801);
_errHandler->sync(this);
_la = _input->LA(1);
while ((((_la & ~ 0x3fULL) == 0) &&
@@ -6989,15 +6933,15 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() {
((1ULL << (_la - 128)) & -9) != 0) || _la == HogQLParser::JSON_TRUE
|| _la == HogQLParser::IDENTIFIER) {
- setState(805);
+ setState(798);
hogqlxTagAttribute();
- setState(810);
+ setState(803);
_errHandler->sync(this);
_la = _input->LA(1);
}
- setState(811);
+ setState(804);
match(HogQLParser::SLASH);
- setState(812);
+ setState(805);
match(HogQLParser::GT);
break;
}
@@ -7005,11 +6949,11 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() {
case 2: {
_localctx = _tracker.createInstance(_localctx);
enterOuterAlt(_localctx, 2);
- setState(814);
+ setState(807);
match(HogQLParser::LT);
- setState(815);
+ setState(808);
identifier();
- setState(819);
+ setState(812);
_errHandler->sync(this);
_la = _input->LA(1);
while ((((_la & ~ 0x3fULL) == 0) &&
@@ -7018,20 +6962,20 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() {
((1ULL << (_la - 128)) & -9) != 0) || _la == HogQLParser::JSON_TRUE
|| _la == HogQLParser::IDENTIFIER) {
- setState(816);
+ setState(809);
hogqlxTagAttribute();
- setState(821);
+ setState(814);
_errHandler->sync(this);
_la = _input->LA(1);
}
- setState(822);
+ setState(815);
match(HogQLParser::GT);
- setState(824);
+ setState(817);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 99, _ctx)) {
case 1: {
- setState(823);
+ setState(816);
hogqlxTagElement();
break;
}
@@ -7039,13 +6983,13 @@ HogQLParser::HogqlxTagElementContext* HogQLParser::hogqlxTagElement() {
default:
break;
}
- setState(826);
+ setState(819);
match(HogQLParser::LT);
- setState(827);
+ setState(820);
match(HogQLParser::SLASH);
- setState(828);
+ setState(821);
identifier();
- setState(829);
+ setState(822);
match(HogQLParser::GT);
break;
}
@@ -7119,38 +7063,38 @@ HogQLParser::HogqlxTagAttributeContext* HogQLParser::hogqlxTagAttribute() {
exitRule();
});
try {
- setState(844);
+ setState(837);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 101, _ctx)) {
case 1: {
enterOuterAlt(_localctx, 1);
- setState(833);
+ setState(826);
identifier();
- setState(834);
+ setState(827);
match(HogQLParser::EQ_SINGLE);
- setState(835);
+ setState(828);
match(HogQLParser::STRING_LITERAL);
break;
}
case 2: {
enterOuterAlt(_localctx, 2);
- setState(837);
+ setState(830);
identifier();
- setState(838);
+ setState(831);
match(HogQLParser::EQ_SINGLE);
- setState(839);
+ setState(832);
match(HogQLParser::LBRACE);
- setState(840);
+ setState(833);
columnExpr(0);
- setState(841);
+ setState(834);
match(HogQLParser::RBRACE);
break;
}
case 3: {
enterOuterAlt(_localctx, 3);
- setState(843);
+ setState(836);
identifier();
break;
}
@@ -7218,17 +7162,17 @@ HogQLParser::WithExprListContext* HogQLParser::withExprList() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(846);
+ setState(839);
withExpr();
- setState(851);
+ setState(844);
_errHandler->sync(this);
_la = _input->LA(1);
while (_la == HogQLParser::COMMA) {
- setState(847);
+ setState(840);
match(HogQLParser::COMMA);
- setState(848);
+ setState(841);
withExpr();
- setState(853);
+ setState(846);
_errHandler->sync(this);
_la = _input->LA(1);
}
@@ -7324,21 +7268,21 @@ HogQLParser::WithExprContext* HogQLParser::withExpr() {
exitRule();
});
try {
- setState(864);
+ setState(857);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 103, _ctx)) {
case 1: {
_localctx = _tracker.createInstance(_localctx);
enterOuterAlt(_localctx, 1);
- setState(854);
+ setState(847);
identifier();
- setState(855);
+ setState(848);
match(HogQLParser::AS);
- setState(856);
+ setState(849);
match(HogQLParser::LPAREN);
- setState(857);
+ setState(850);
selectUnionStmt();
- setState(858);
+ setState(851);
match(HogQLParser::RPAREN);
break;
}
@@ -7346,11 +7290,11 @@ HogQLParser::WithExprContext* HogQLParser::withExpr() {
case 2: {
_localctx = _tracker.createInstance(_localctx);
enterOuterAlt(_localctx, 2);
- setState(860);
+ setState(853);
columnExpr(0);
- setState(861);
+ setState(854);
match(HogQLParser::AS);
- setState(862);
+ setState(855);
identifier();
break;
}
@@ -7416,12 +7360,12 @@ HogQLParser::ColumnIdentifierContext* HogQLParser::columnIdentifier() {
exitRule();
});
try {
- setState(873);
+ setState(866);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::LBRACE: {
enterOuterAlt(_localctx, 1);
- setState(866);
+ setState(859);
placeholder();
break;
}
@@ -7614,14 +7558,14 @@ HogQLParser::ColumnIdentifierContext* HogQLParser::columnIdentifier() {
case HogQLParser::JSON_TRUE:
case HogQLParser::IDENTIFIER: {
enterOuterAlt(_localctx, 2);
- setState(870);
+ setState(863);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 104, _ctx)) {
case 1: {
- setState(867);
+ setState(860);
tableIdentifier();
- setState(868);
+ setState(861);
match(HogQLParser::DOT);
break;
}
@@ -7629,7 +7573,7 @@ HogQLParser::ColumnIdentifierContext* HogQLParser::columnIdentifier() {
default:
break;
}
- setState(872);
+ setState(865);
nestedIdentifier();
break;
}
@@ -7697,19 +7641,19 @@ HogQLParser::NestedIdentifierContext* HogQLParser::nestedIdentifier() {
try {
size_t alt;
enterOuterAlt(_localctx, 1);
- setState(875);
+ setState(868);
identifier();
- setState(880);
+ setState(873);
_errHandler->sync(this);
alt = getInterpreter()->adaptivePredict(_input, 106, _ctx);
while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) {
if (alt == 1) {
- setState(876);
+ setState(869);
match(HogQLParser::DOT);
- setState(877);
+ setState(870);
identifier();
}
- setState(882);
+ setState(875);
_errHandler->sync(this);
alt = getInterpreter()->adaptivePredict(_input, 106, _ctx);
}
@@ -7875,7 +7819,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
try {
size_t alt;
enterOuterAlt(_localctx, 1);
- setState(892);
+ setState(885);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 107, _ctx)) {
case 1: {
@@ -7883,7 +7827,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
_ctx = _localctx;
previousContext = _localctx;
- setState(884);
+ setState(877);
tableIdentifier();
break;
}
@@ -7892,7 +7836,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(885);
+ setState(878);
tableFunctionExpr();
break;
}
@@ -7901,11 +7845,11 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(886);
+ setState(879);
match(HogQLParser::LPAREN);
- setState(887);
+ setState(880);
selectUnionStmt();
- setState(888);
+ setState(881);
match(HogQLParser::RPAREN);
break;
}
@@ -7914,7 +7858,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(890);
+ setState(883);
hogqlxTagElement();
break;
}
@@ -7923,7 +7867,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
_localctx = _tracker.createInstance(_localctx);
_ctx = _localctx;
previousContext = _localctx;
- setState(891);
+ setState(884);
placeholder();
break;
}
@@ -7932,7 +7876,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
break;
}
_ctx->stop = _input->LT(-1);
- setState(902);
+ setState(895);
_errHandler->sync(this);
alt = getInterpreter()->adaptivePredict(_input, 109, _ctx);
while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) {
@@ -7943,10 +7887,10 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState));
_localctx = newContext;
pushNewRecursionContext(newContext, startState, RuleTableExpr);
- setState(894);
+ setState(887);
if (!(precpred(_ctx, 3))) throw FailedPredicateException(this, "precpred(_ctx, 3)");
- setState(898);
+ setState(891);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::DATE:
@@ -7954,15 +7898,15 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
case HogQLParser::ID:
case HogQLParser::KEY:
case HogQLParser::IDENTIFIER: {
- setState(895);
+ setState(888);
alias();
break;
}
case HogQLParser::AS: {
- setState(896);
+ setState(889);
match(HogQLParser::AS);
- setState(897);
+ setState(890);
identifier();
break;
}
@@ -7971,7 +7915,7 @@ HogQLParser::TableExprContext* HogQLParser::tableExpr(int precedence) {
throw NoViableAltException(this);
}
}
- setState(904);
+ setState(897);
_errHandler->sync(this);
alt = getInterpreter()->adaptivePredict(_input, 109, _ctx);
}
@@ -8033,11 +7977,11 @@ HogQLParser::TableFunctionExprContext* HogQLParser::tableFunctionExpr() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(905);
+ setState(898);
identifier();
- setState(906);
+ setState(899);
match(HogQLParser::LPAREN);
- setState(908);
+ setState(901);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -8046,10 +7990,10 @@ HogQLParser::TableFunctionExprContext* HogQLParser::tableFunctionExpr() {
((1ULL << (_la - 64)) & -1) != 0) || ((((_la - 128) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 128)) & -9) != 0) || ((((_la - 192) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 192)) & 70263309817) != 0)) {
- setState(907);
+ setState(900);
tableArgList();
}
- setState(910);
+ setState(903);
match(HogQLParser::RPAREN);
}
@@ -8106,14 +8050,14 @@ HogQLParser::TableIdentifierContext* HogQLParser::tableIdentifier() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(915);
+ setState(908);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 111, _ctx)) {
case 1: {
- setState(912);
+ setState(905);
databaseIdentifier();
- setState(913);
+ setState(906);
match(HogQLParser::DOT);
break;
}
@@ -8121,7 +8065,7 @@ HogQLParser::TableIdentifierContext* HogQLParser::tableIdentifier() {
default:
break;
}
- setState(917);
+ setState(910);
identifier();
}
@@ -8183,17 +8127,17 @@ HogQLParser::TableArgListContext* HogQLParser::tableArgList() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(919);
+ setState(912);
columnExpr(0);
- setState(924);
+ setState(917);
_errHandler->sync(this);
_la = _input->LA(1);
while (_la == HogQLParser::COMMA) {
- setState(920);
+ setState(913);
match(HogQLParser::COMMA);
- setState(921);
+ setState(914);
columnExpr(0);
- setState(926);
+ setState(919);
_errHandler->sync(this);
_la = _input->LA(1);
}
@@ -8244,7 +8188,7 @@ HogQLParser::DatabaseIdentifierContext* HogQLParser::databaseIdentifier() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(927);
+ setState(920);
identifier();
}
@@ -8309,21 +8253,21 @@ HogQLParser::FloatingLiteralContext* HogQLParser::floatingLiteral() {
exitRule();
});
try {
- setState(937);
+ setState(930);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::FLOATING_LITERAL: {
enterOuterAlt(_localctx, 1);
- setState(929);
+ setState(922);
match(HogQLParser::FLOATING_LITERAL);
break;
}
case HogQLParser::DOT: {
enterOuterAlt(_localctx, 2);
- setState(930);
+ setState(923);
match(HogQLParser::DOT);
- setState(931);
+ setState(924);
_la = _input->LA(1);
if (!(_la == HogQLParser::OCTAL_LITERAL
@@ -8339,16 +8283,16 @@ HogQLParser::FloatingLiteralContext* HogQLParser::floatingLiteral() {
case HogQLParser::DECIMAL_LITERAL: {
enterOuterAlt(_localctx, 3);
- setState(932);
+ setState(925);
match(HogQLParser::DECIMAL_LITERAL);
- setState(933);
+ setState(926);
match(HogQLParser::DOT);
- setState(935);
+ setState(928);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 113, _ctx)) {
case 1: {
- setState(934);
+ setState(927);
_la = _input->LA(1);
if (!(_la == HogQLParser::OCTAL_LITERAL
@@ -8447,14 +8391,14 @@ HogQLParser::NumberLiteralContext* HogQLParser::numberLiteral() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(940);
+ setState(933);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == HogQLParser::DASH
|| _la == HogQLParser::PLUS) {
- setState(939);
+ setState(932);
_la = _input->LA(1);
if (!(_la == HogQLParser::DASH
@@ -8466,41 +8410,41 @@ HogQLParser::NumberLiteralContext* HogQLParser::numberLiteral() {
consume();
}
}
- setState(948);
+ setState(941);
_errHandler->sync(this);
switch (getInterpreter()->adaptivePredict(_input, 116, _ctx)) {
case 1: {
- setState(942);
+ setState(935);
floatingLiteral();
break;
}
case 2: {
- setState(943);
+ setState(936);
match(HogQLParser::OCTAL_LITERAL);
break;
}
case 3: {
- setState(944);
+ setState(937);
match(HogQLParser::DECIMAL_LITERAL);
break;
}
case 4: {
- setState(945);
+ setState(938);
match(HogQLParser::HEXADECIMAL_LITERAL);
break;
}
case 5: {
- setState(946);
+ setState(939);
match(HogQLParser::INF);
break;
}
case 6: {
- setState(947);
+ setState(940);
match(HogQLParser::NAN_SQL);
break;
}
@@ -8562,7 +8506,7 @@ HogQLParser::LiteralContext* HogQLParser::literal() {
exitRule();
});
try {
- setState(953);
+ setState(946);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::INF:
@@ -8575,21 +8519,21 @@ HogQLParser::LiteralContext* HogQLParser::literal() {
case HogQLParser::DOT:
case HogQLParser::PLUS: {
enterOuterAlt(_localctx, 1);
- setState(950);
+ setState(943);
numberLiteral();
break;
}
case HogQLParser::STRING_LITERAL: {
enterOuterAlt(_localctx, 2);
- setState(951);
+ setState(944);
match(HogQLParser::STRING_LITERAL);
break;
}
case HogQLParser::NULL_SQL: {
enterOuterAlt(_localctx, 3);
- setState(952);
+ setState(945);
match(HogQLParser::NULL_SQL);
break;
}
@@ -8673,7 +8617,7 @@ HogQLParser::IntervalContext* HogQLParser::interval() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(955);
+ setState(948);
_la = _input->LA(1);
if (!(_la == HogQLParser::DAY || ((((_la - 76) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 76)) & 72057615512764417) != 0) || ((((_la - 145) & ~ 0x3fULL) == 0) &&
@@ -9440,7 +9384,7 @@ HogQLParser::KeywordContext* HogQLParser::keyword() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(957);
+ setState(950);
_la = _input->LA(1);
if (!(((((_la - 2) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 2)) & -34368126977) != 0) || ((((_la - 66) & ~ 0x3fULL) == 0) &&
@@ -9512,7 +9456,7 @@ HogQLParser::KeywordForAliasContext* HogQLParser::keywordForAlias() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(959);
+ setState(952);
_la = _input->LA(1);
if (!(((((_la - 36) & ~ 0x3fULL) == 0) &&
((1ULL << (_la - 36)) & 36030996109328385) != 0))) {
@@ -9572,12 +9516,12 @@ HogQLParser::AliasContext* HogQLParser::alias() {
exitRule();
});
try {
- setState(963);
+ setState(956);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::IDENTIFIER: {
enterOuterAlt(_localctx, 1);
- setState(961);
+ setState(954);
match(HogQLParser::IDENTIFIER);
break;
}
@@ -9587,7 +9531,7 @@ HogQLParser::AliasContext* HogQLParser::alias() {
case HogQLParser::ID:
case HogQLParser::KEY: {
enterOuterAlt(_localctx, 2);
- setState(962);
+ setState(955);
keywordForAlias();
break;
}
@@ -9649,12 +9593,12 @@ HogQLParser::IdentifierContext* HogQLParser::identifier() {
exitRule();
});
try {
- setState(968);
+ setState(961);
_errHandler->sync(this);
switch (_input->LA(1)) {
case HogQLParser::IDENTIFIER: {
enterOuterAlt(_localctx, 1);
- setState(965);
+ setState(958);
match(HogQLParser::IDENTIFIER);
break;
}
@@ -9668,7 +9612,7 @@ HogQLParser::IdentifierContext* HogQLParser::identifier() {
case HogQLParser::WEEK:
case HogQLParser::YEAR: {
enterOuterAlt(_localctx, 2);
- setState(966);
+ setState(959);
interval();
break;
}
@@ -9852,7 +9796,7 @@ HogQLParser::IdentifierContext* HogQLParser::identifier() {
case HogQLParser::JSON_FALSE:
case HogQLParser::JSON_TRUE: {
enterOuterAlt(_localctx, 3);
- setState(967);
+ setState(960);
keyword();
break;
}
@@ -9915,11 +9859,11 @@ HogQLParser::EnumValueContext* HogQLParser::enumValue() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(970);
+ setState(963);
match(HogQLParser::STRING_LITERAL);
- setState(971);
+ setState(964);
match(HogQLParser::EQ_SINGLE);
- setState(972);
+ setState(965);
numberLiteral();
}
@@ -9976,11 +9920,11 @@ HogQLParser::PlaceholderContext* HogQLParser::placeholder() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(974);
+ setState(967);
match(HogQLParser::LBRACE);
- setState(975);
+ setState(968);
identifier();
- setState(976);
+ setState(969);
match(HogQLParser::RBRACE);
}
diff --git a/hogql_parser/HogQLParser.h b/hogql_parser/HogQLParser.h
index 49c38fad2be89..058a3332af50c 100644
--- a/hogql_parser/HogQLParser.h
+++ b/hogql_parser/HogQLParser.h
@@ -988,20 +988,6 @@ class HogQLParser : public antlr4::Parser {
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
- class ColumnExprExtractContext : public ColumnExprContext {
- public:
- ColumnExprExtractContext(ColumnExprContext *ctx);
-
- antlr4::tree::TerminalNode *EXTRACT();
- antlr4::tree::TerminalNode *LPAREN();
- IntervalContext *interval();
- antlr4::tree::TerminalNode *FROM();
- ColumnExprContext *columnExpr();
- antlr4::tree::TerminalNode *RPAREN();
-
- virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
- };
-
class ColumnExprNegateContext : public ColumnExprContext {
public:
ColumnExprNegateContext(ColumnExprContext *ctx);
diff --git a/hogql_parser/HogQLParser.interp b/hogql_parser/HogQLParser.interp
index 2b24b72a2819d..b159bc05eb424 100644
--- a/hogql_parser/HogQLParser.interp
+++ b/hogql_parser/HogQLParser.interp
@@ -554,4 +554,4 @@ placeholder
atn:
-[4, 1, 242, 979, 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, 1, 0, 1, 0, 1, 0, 3, 0, 128, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 136, 8, 1, 10, 1, 12, 1, 139, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 147, 8, 2, 1, 3, 3, 3, 150, 8, 3, 1, 3, 1, 3, 3, 3, 154, 8, 3, 1, 3, 3, 3, 157, 8, 3, 1, 3, 1, 3, 3, 3, 161, 8, 3, 1, 3, 3, 3, 164, 8, 3, 1, 3, 3, 3, 167, 8, 3, 1, 3, 3, 3, 170, 8, 3, 1, 3, 3, 3, 173, 8, 3, 1, 3, 1, 3, 3, 3, 177, 8, 3, 1, 3, 1, 3, 3, 3, 181, 8, 3, 1, 3, 3, 3, 184, 8, 3, 1, 3, 3, 3, 187, 8, 3, 1, 3, 3, 3, 190, 8, 3, 1, 3, 1, 3, 3, 3, 194, 8, 3, 1, 3, 3, 3, 197, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 206, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 3, 7, 212, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 231, 8, 8, 10, 8, 12, 8, 234, 9, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 250, 8, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 267, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 273, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 279, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 290, 8, 15, 3, 15, 292, 8, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 3, 18, 303, 8, 18, 1, 18, 3, 18, 306, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 312, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 320, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 326, 8, 18, 10, 18, 12, 18, 329, 9, 18, 1, 19, 3, 19, 332, 8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 337, 8, 19, 1, 19, 3, 19, 340, 8, 19, 1, 19, 3, 19, 343, 8, 19, 1, 19, 1, 19, 3, 19, 347, 8, 19, 1, 19, 1, 19, 3, 19, 351, 8, 19, 1, 19, 3, 19, 354, 8, 19, 3, 19, 356, 8, 19, 1, 19, 3, 19, 359, 8, 19, 1, 19, 1, 19, 3, 19, 363, 8, 19, 1, 19, 1, 19, 3, 19, 367, 8, 19, 1, 19, 3, 19, 370, 8, 19, 3, 19, 372, 8, 19, 3, 19, 374, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 379, 8, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 390, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 396, 8, 22, 1, 23, 1, 23, 1, 23, 5, 23, 401, 8, 23, 10, 23, 12, 23, 404, 9, 23, 1, 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, 25, 1, 25, 1, 25, 1, 25, 3, 25, 422, 8, 25, 3, 25, 424, 8, 25, 1, 26, 1, 26, 1, 26, 5, 26, 429, 8, 26, 10, 26, 12, 26, 432, 9, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 439, 8, 28, 1, 28, 3, 28, 442, 8, 28, 1, 28, 3, 28, 445, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 464, 8, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 478, 8, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 492, 8, 35, 10, 35, 12, 35, 495, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 504, 8, 35, 10, 35, 12, 35, 507, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 516, 8, 35, 10, 35, 12, 35, 519, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 3, 35, 526, 8, 35, 1, 35, 1, 35, 3, 35, 530, 8, 35, 1, 36, 1, 36, 1, 36, 5, 36, 535, 8, 36, 10, 36, 12, 36, 538, 9, 36, 1, 37, 1, 37, 1, 37, 3, 37, 543, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 550, 8, 37, 11, 37, 12, 37, 551, 1, 37, 1, 37, 3, 37, 556, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 587, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 604, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 616, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 626, 8, 37, 1, 37, 3, 37, 629, 8, 37, 1, 37, 1, 37, 3, 37, 633, 8, 37, 1, 37, 3, 37, 636, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 649, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 666, 8, 37, 1, 37, 1, 37, 3, 37, 670, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 676, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 683, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 695, 8, 37, 1, 37, 1, 37, 3, 37, 699, 8, 37, 1, 37, 3, 37, 702, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 711, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 725, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 752, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 761, 8, 37, 5, 37, 763, 8, 37, 10, 37, 12, 37, 766, 9, 37, 1, 38, 1, 38, 1, 38, 5, 38, 771, 8, 38, 10, 38, 12, 38, 774, 9, 38, 1, 39, 1, 39, 3, 39, 778, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 784, 8, 40, 10, 40, 12, 40, 787, 9, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 794, 8, 40, 10, 40, 12, 40, 797, 9, 40, 3, 40, 799, 8, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 5, 41, 807, 8, 41, 10, 41, 12, 41, 810, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 818, 8, 41, 10, 41, 12, 41, 821, 9, 41, 1, 41, 1, 41, 3, 41, 825, 8, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 832, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 845, 8, 42, 1, 43, 1, 43, 1, 43, 5, 43, 850, 8, 43, 10, 43, 12, 43, 853, 9, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 865, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 3, 45, 871, 8, 45, 1, 45, 3, 45, 874, 8, 45, 1, 46, 1, 46, 1, 46, 5, 46, 879, 8, 46, 10, 46, 12, 46, 882, 9, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 893, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 899, 8, 47, 5, 47, 901, 8, 47, 10, 47, 12, 47, 904, 9, 47, 1, 48, 1, 48, 1, 48, 3, 48, 909, 8, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 3, 49, 916, 8, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 5, 50, 923, 8, 50, 10, 50, 12, 50, 926, 9, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 936, 8, 52, 3, 52, 938, 8, 52, 1, 53, 3, 53, 941, 8, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 949, 8, 53, 1, 54, 1, 54, 1, 54, 3, 54, 954, 8, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 3, 58, 964, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 969, 8, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 0, 3, 36, 74, 94, 62, 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, 0, 16, 2, 0, 32, 32, 141, 141, 2, 0, 84, 84, 96, 96, 3, 0, 4, 4, 8, 8, 12, 12, 4, 0, 4, 4, 7, 8, 12, 12, 147, 147, 2, 0, 96, 96, 140, 140, 2, 0, 4, 4, 8, 8, 2, 0, 11, 11, 42, 43, 2, 0, 62, 62, 93, 93, 2, 0, 133, 133, 143, 143, 3, 0, 17, 17, 95, 95, 170, 170, 2, 0, 79, 79, 98, 98, 1, 0, 197, 198, 2, 0, 208, 208, 228, 228, 8, 0, 37, 37, 76, 76, 108, 108, 110, 110, 132, 132, 145, 145, 185, 185, 190, 190, 13, 0, 2, 24, 26, 36, 38, 75, 77, 81, 83, 107, 109, 109, 111, 112, 114, 115, 117, 130, 133, 144, 146, 184, 186, 189, 191, 192, 4, 0, 36, 36, 62, 62, 77, 77, 91, 91, 1107, 0, 127, 1, 0, 0, 0, 2, 131, 1, 0, 0, 0, 4, 146, 1, 0, 0, 0, 6, 149, 1, 0, 0, 0, 8, 198, 1, 0, 0, 0, 10, 201, 1, 0, 0, 0, 12, 207, 1, 0, 0, 0, 14, 211, 1, 0, 0, 0, 16, 217, 1, 0, 0, 0, 18, 235, 1, 0, 0, 0, 20, 238, 1, 0, 0, 0, 22, 241, 1, 0, 0, 0, 24, 251, 1, 0, 0, 0, 26, 254, 1, 0, 0, 0, 28, 258, 1, 0, 0, 0, 30, 291, 1, 0, 0, 0, 32, 293, 1, 0, 0, 0, 34, 296, 1, 0, 0, 0, 36, 311, 1, 0, 0, 0, 38, 373, 1, 0, 0, 0, 40, 378, 1, 0, 0, 0, 42, 389, 1, 0, 0, 0, 44, 391, 1, 0, 0, 0, 46, 397, 1, 0, 0, 0, 48, 405, 1, 0, 0, 0, 50, 423, 1, 0, 0, 0, 52, 425, 1, 0, 0, 0, 54, 433, 1, 0, 0, 0, 56, 438, 1, 0, 0, 0, 58, 446, 1, 0, 0, 0, 60, 450, 1, 0, 0, 0, 62, 454, 1, 0, 0, 0, 64, 463, 1, 0, 0, 0, 66, 477, 1, 0, 0, 0, 68, 479, 1, 0, 0, 0, 70, 529, 1, 0, 0, 0, 72, 531, 1, 0, 0, 0, 74, 669, 1, 0, 0, 0, 76, 767, 1, 0, 0, 0, 78, 777, 1, 0, 0, 0, 80, 798, 1, 0, 0, 0, 82, 831, 1, 0, 0, 0, 84, 844, 1, 0, 0, 0, 86, 846, 1, 0, 0, 0, 88, 864, 1, 0, 0, 0, 90, 873, 1, 0, 0, 0, 92, 875, 1, 0, 0, 0, 94, 892, 1, 0, 0, 0, 96, 905, 1, 0, 0, 0, 98, 915, 1, 0, 0, 0, 100, 919, 1, 0, 0, 0, 102, 927, 1, 0, 0, 0, 104, 937, 1, 0, 0, 0, 106, 940, 1, 0, 0, 0, 108, 953, 1, 0, 0, 0, 110, 955, 1, 0, 0, 0, 112, 957, 1, 0, 0, 0, 114, 959, 1, 0, 0, 0, 116, 963, 1, 0, 0, 0, 118, 968, 1, 0, 0, 0, 120, 970, 1, 0, 0, 0, 122, 974, 1, 0, 0, 0, 124, 128, 3, 2, 1, 0, 125, 128, 3, 6, 3, 0, 126, 128, 3, 82, 41, 0, 127, 124, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 130, 5, 0, 0, 1, 130, 1, 1, 0, 0, 0, 131, 137, 3, 4, 2, 0, 132, 133, 5, 176, 0, 0, 133, 134, 5, 4, 0, 0, 134, 136, 3, 4, 2, 0, 135, 132, 1, 0, 0, 0, 136, 139, 1, 0, 0, 0, 137, 135, 1, 0, 0, 0, 137, 138, 1, 0, 0, 0, 138, 3, 1, 0, 0, 0, 139, 137, 1, 0, 0, 0, 140, 147, 3, 6, 3, 0, 141, 142, 5, 220, 0, 0, 142, 143, 3, 2, 1, 0, 143, 144, 5, 236, 0, 0, 144, 147, 1, 0, 0, 0, 145, 147, 3, 122, 61, 0, 146, 140, 1, 0, 0, 0, 146, 141, 1, 0, 0, 0, 146, 145, 1, 0, 0, 0, 147, 5, 1, 0, 0, 0, 148, 150, 3, 8, 4, 0, 149, 148, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 153, 5, 146, 0, 0, 152, 154, 5, 49, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 156, 1, 0, 0, 0, 155, 157, 3, 10, 5, 0, 156, 155, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 160, 3, 72, 36, 0, 159, 161, 3, 12, 6, 0, 160, 159, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 163, 1, 0, 0, 0, 162, 164, 3, 14, 7, 0, 163, 162, 1, 0, 0, 0, 163, 164, 1, 0, 0, 0, 164, 166, 1, 0, 0, 0, 165, 167, 3, 18, 9, 0, 166, 165, 1, 0, 0, 0, 166, 167, 1, 0, 0, 0, 167, 169, 1, 0, 0, 0, 168, 170, 3, 20, 10, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 172, 1, 0, 0, 0, 171, 173, 3, 22, 11, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 175, 5, 189, 0, 0, 175, 177, 7, 0, 0, 0, 176, 174, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 180, 1, 0, 0, 0, 178, 179, 5, 189, 0, 0, 179, 181, 5, 169, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 183, 1, 0, 0, 0, 182, 184, 3, 24, 12, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 187, 3, 16, 8, 0, 186, 185, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 190, 3, 26, 13, 0, 189, 188, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 194, 3, 30, 15, 0, 192, 194, 3, 32, 16, 0, 193, 191, 1, 0, 0, 0, 193, 192, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 196, 1, 0, 0, 0, 195, 197, 3, 34, 17, 0, 196, 195, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 7, 1, 0, 0, 0, 198, 199, 5, 189, 0, 0, 199, 200, 3, 86, 43, 0, 200, 9, 1, 0, 0, 0, 201, 202, 5, 168, 0, 0, 202, 205, 5, 198, 0, 0, 203, 204, 5, 189, 0, 0, 204, 206, 5, 164, 0, 0, 205, 203, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 11, 1, 0, 0, 0, 207, 208, 5, 68, 0, 0, 208, 209, 3, 36, 18, 0, 209, 13, 1, 0, 0, 0, 210, 212, 7, 1, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 5, 9, 0, 0, 214, 215, 5, 90, 0, 0, 215, 216, 3, 72, 36, 0, 216, 15, 1, 0, 0, 0, 217, 218, 5, 188, 0, 0, 218, 219, 3, 118, 59, 0, 219, 220, 5, 10, 0, 0, 220, 221, 5, 220, 0, 0, 221, 222, 3, 56, 28, 0, 222, 232, 5, 236, 0, 0, 223, 224, 5, 206, 0, 0, 224, 225, 3, 118, 59, 0, 225, 226, 5, 10, 0, 0, 226, 227, 5, 220, 0, 0, 227, 228, 3, 56, 28, 0, 228, 229, 5, 236, 0, 0, 229, 231, 1, 0, 0, 0, 230, 223, 1, 0, 0, 0, 231, 234, 1, 0, 0, 0, 232, 230, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 17, 1, 0, 0, 0, 234, 232, 1, 0, 0, 0, 235, 236, 5, 129, 0, 0, 236, 237, 3, 74, 37, 0, 237, 19, 1, 0, 0, 0, 238, 239, 5, 187, 0, 0, 239, 240, 3, 74, 37, 0, 240, 21, 1, 0, 0, 0, 241, 242, 5, 73, 0, 0, 242, 249, 5, 18, 0, 0, 243, 244, 7, 0, 0, 0, 244, 245, 5, 220, 0, 0, 245, 246, 3, 72, 36, 0, 246, 247, 5, 236, 0, 0, 247, 250, 1, 0, 0, 0, 248, 250, 3, 72, 36, 0, 249, 243, 1, 0, 0, 0, 249, 248, 1, 0, 0, 0, 250, 23, 1, 0, 0, 0, 251, 252, 5, 74, 0, 0, 252, 253, 3, 74, 37, 0, 253, 25, 1, 0, 0, 0, 254, 255, 5, 122, 0, 0, 255, 256, 5, 18, 0, 0, 256, 257, 3, 46, 23, 0, 257, 27, 1, 0, 0, 0, 258, 259, 5, 122, 0, 0, 259, 260, 5, 18, 0, 0, 260, 261, 3, 72, 36, 0, 261, 29, 1, 0, 0, 0, 262, 263, 5, 99, 0, 0, 263, 266, 3, 74, 37, 0, 264, 265, 5, 206, 0, 0, 265, 267, 3, 74, 37, 0, 266, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 272, 1, 0, 0, 0, 268, 269, 5, 189, 0, 0, 269, 273, 5, 164, 0, 0, 270, 271, 5, 18, 0, 0, 271, 273, 3, 72, 36, 0, 272, 268, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 292, 1, 0, 0, 0, 274, 275, 5, 99, 0, 0, 275, 278, 3, 74, 37, 0, 276, 277, 5, 189, 0, 0, 277, 279, 5, 164, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 5, 118, 0, 0, 281, 282, 3, 74, 37, 0, 282, 292, 1, 0, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 3, 74, 37, 0, 285, 286, 5, 118, 0, 0, 286, 289, 3, 74, 37, 0, 287, 288, 5, 18, 0, 0, 288, 290, 3, 72, 36, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 292, 1, 0, 0, 0, 291, 262, 1, 0, 0, 0, 291, 274, 1, 0, 0, 0, 291, 283, 1, 0, 0, 0, 292, 31, 1, 0, 0, 0, 293, 294, 5, 118, 0, 0, 294, 295, 3, 74, 37, 0, 295, 33, 1, 0, 0, 0, 296, 297, 5, 150, 0, 0, 297, 298, 3, 52, 26, 0, 298, 35, 1, 0, 0, 0, 299, 300, 6, 18, -1, 0, 300, 302, 3, 94, 47, 0, 301, 303, 5, 61, 0, 0, 302, 301, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 305, 1, 0, 0, 0, 304, 306, 3, 44, 22, 0, 305, 304, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 312, 1, 0, 0, 0, 307, 308, 5, 220, 0, 0, 308, 309, 3, 36, 18, 0, 309, 310, 5, 236, 0, 0, 310, 312, 1, 0, 0, 0, 311, 299, 1, 0, 0, 0, 311, 307, 1, 0, 0, 0, 312, 327, 1, 0, 0, 0, 313, 314, 10, 3, 0, 0, 314, 315, 3, 40, 20, 0, 315, 316, 3, 36, 18, 4, 316, 326, 1, 0, 0, 0, 317, 319, 10, 4, 0, 0, 318, 320, 3, 38, 19, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 90, 0, 0, 322, 323, 3, 36, 18, 0, 323, 324, 3, 42, 21, 0, 324, 326, 1, 0, 0, 0, 325, 313, 1, 0, 0, 0, 325, 317, 1, 0, 0, 0, 326, 329, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 37, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 330, 332, 7, 2, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 340, 5, 84, 0, 0, 334, 336, 5, 84, 0, 0, 335, 337, 7, 2, 0, 0, 336, 335, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 340, 1, 0, 0, 0, 338, 340, 7, 2, 0, 0, 339, 331, 1, 0, 0, 0, 339, 334, 1, 0, 0, 0, 339, 338, 1, 0, 0, 0, 340, 374, 1, 0, 0, 0, 341, 343, 7, 3, 0, 0, 342, 341, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 344, 1, 0, 0, 0, 344, 346, 7, 4, 0, 0, 345, 347, 5, 123, 0, 0, 346, 345, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 347, 356, 1, 0, 0, 0, 348, 350, 7, 4, 0, 0, 349, 351, 5, 123, 0, 0, 350, 349, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 353, 1, 0, 0, 0, 352, 354, 7, 3, 0, 0, 353, 352, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 356, 1, 0, 0, 0, 355, 342, 1, 0, 0, 0, 355, 348, 1, 0, 0, 0, 356, 374, 1, 0, 0, 0, 357, 359, 7, 5, 0, 0, 358, 357, 1, 0, 0, 0, 358, 359, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 362, 5, 69, 0, 0, 361, 363, 5, 123, 0, 0, 362, 361, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 372, 1, 0, 0, 0, 364, 366, 5, 69, 0, 0, 365, 367, 5, 123, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 369, 1, 0, 0, 0, 368, 370, 7, 5, 0, 0, 369, 368, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 372, 1, 0, 0, 0, 371, 358, 1, 0, 0, 0, 371, 364, 1, 0, 0, 0, 372, 374, 1, 0, 0, 0, 373, 339, 1, 0, 0, 0, 373, 355, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 374, 39, 1, 0, 0, 0, 375, 376, 5, 31, 0, 0, 376, 379, 5, 90, 0, 0, 377, 379, 5, 206, 0, 0, 378, 375, 1, 0, 0, 0, 378, 377, 1, 0, 0, 0, 379, 41, 1, 0, 0, 0, 380, 381, 5, 119, 0, 0, 381, 390, 3, 72, 36, 0, 382, 383, 5, 179, 0, 0, 383, 384, 5, 220, 0, 0, 384, 385, 3, 72, 36, 0, 385, 386, 5, 236, 0, 0, 386, 390, 1, 0, 0, 0, 387, 388, 5, 179, 0, 0, 388, 390, 3, 72, 36, 0, 389, 380, 1, 0, 0, 0, 389, 382, 1, 0, 0, 0, 389, 387, 1, 0, 0, 0, 390, 43, 1, 0, 0, 0, 391, 392, 5, 144, 0, 0, 392, 395, 3, 50, 25, 0, 393, 394, 5, 118, 0, 0, 394, 396, 3, 50, 25, 0, 395, 393, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 45, 1, 0, 0, 0, 397, 402, 3, 48, 24, 0, 398, 399, 5, 206, 0, 0, 399, 401, 3, 48, 24, 0, 400, 398, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 47, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 405, 407, 3, 74, 37, 0, 406, 408, 7, 6, 0, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 117, 0, 0, 410, 412, 7, 7, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 26, 0, 0, 414, 416, 5, 200, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 49, 1, 0, 0, 0, 417, 424, 3, 122, 61, 0, 418, 421, 3, 106, 53, 0, 419, 420, 5, 238, 0, 0, 420, 422, 3, 106, 53, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 417, 1, 0, 0, 0, 423, 418, 1, 0, 0, 0, 424, 51, 1, 0, 0, 0, 425, 430, 3, 54, 27, 0, 426, 427, 5, 206, 0, 0, 427, 429, 3, 54, 27, 0, 428, 426, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 53, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 433, 434, 3, 118, 59, 0, 434, 435, 5, 212, 0, 0, 435, 436, 3, 108, 54, 0, 436, 55, 1, 0, 0, 0, 437, 439, 3, 58, 29, 0, 438, 437, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 441, 1, 0, 0, 0, 440, 442, 3, 60, 30, 0, 441, 440, 1, 0, 0, 0, 441, 442, 1, 0, 0, 0, 442, 444, 1, 0, 0, 0, 443, 445, 3, 62, 31, 0, 444, 443, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, 57, 1, 0, 0, 0, 446, 447, 5, 126, 0, 0, 447, 448, 5, 18, 0, 0, 448, 449, 3, 72, 36, 0, 449, 59, 1, 0, 0, 0, 450, 451, 5, 122, 0, 0, 451, 452, 5, 18, 0, 0, 452, 453, 3, 46, 23, 0, 453, 61, 1, 0, 0, 0, 454, 455, 7, 8, 0, 0, 455, 456, 3, 64, 32, 0, 456, 63, 1, 0, 0, 0, 457, 464, 3, 66, 33, 0, 458, 459, 5, 16, 0, 0, 459, 460, 3, 66, 33, 0, 460, 461, 5, 6, 0, 0, 461, 462, 3, 66, 33, 0, 462, 464, 1, 0, 0, 0, 463, 457, 1, 0, 0, 0, 463, 458, 1, 0, 0, 0, 464, 65, 1, 0, 0, 0, 465, 466, 5, 33, 0, 0, 466, 478, 5, 142, 0, 0, 467, 468, 5, 175, 0, 0, 468, 478, 5, 128, 0, 0, 469, 470, 5, 175, 0, 0, 470, 478, 5, 64, 0, 0, 471, 472, 3, 106, 53, 0, 472, 473, 5, 128, 0, 0, 473, 478, 1, 0, 0, 0, 474, 475, 3, 106, 53, 0, 475, 476, 5, 64, 0, 0, 476, 478, 1, 0, 0, 0, 477, 465, 1, 0, 0, 0, 477, 467, 1, 0, 0, 0, 477, 469, 1, 0, 0, 0, 477, 471, 1, 0, 0, 0, 477, 474, 1, 0, 0, 0, 478, 67, 1, 0, 0, 0, 479, 480, 3, 74, 37, 0, 480, 481, 5, 0, 0, 1, 481, 69, 1, 0, 0, 0, 482, 530, 3, 118, 59, 0, 483, 484, 3, 118, 59, 0, 484, 485, 5, 220, 0, 0, 485, 486, 3, 118, 59, 0, 486, 493, 3, 70, 35, 0, 487, 488, 5, 206, 0, 0, 488, 489, 3, 118, 59, 0, 489, 490, 3, 70, 35, 0, 490, 492, 1, 0, 0, 0, 491, 487, 1, 0, 0, 0, 492, 495, 1, 0, 0, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 496, 1, 0, 0, 0, 495, 493, 1, 0, 0, 0, 496, 497, 5, 236, 0, 0, 497, 530, 1, 0, 0, 0, 498, 499, 3, 118, 59, 0, 499, 500, 5, 220, 0, 0, 500, 505, 3, 120, 60, 0, 501, 502, 5, 206, 0, 0, 502, 504, 3, 120, 60, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 508, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 509, 5, 236, 0, 0, 509, 530, 1, 0, 0, 0, 510, 511, 3, 118, 59, 0, 511, 512, 5, 220, 0, 0, 512, 517, 3, 70, 35, 0, 513, 514, 5, 206, 0, 0, 514, 516, 3, 70, 35, 0, 515, 513, 1, 0, 0, 0, 516, 519, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 518, 1, 0, 0, 0, 518, 520, 1, 0, 0, 0, 519, 517, 1, 0, 0, 0, 520, 521, 5, 236, 0, 0, 521, 530, 1, 0, 0, 0, 522, 523, 3, 118, 59, 0, 523, 525, 5, 220, 0, 0, 524, 526, 3, 72, 36, 0, 525, 524, 1, 0, 0, 0, 525, 526, 1, 0, 0, 0, 526, 527, 1, 0, 0, 0, 527, 528, 5, 236, 0, 0, 528, 530, 1, 0, 0, 0, 529, 482, 1, 0, 0, 0, 529, 483, 1, 0, 0, 0, 529, 498, 1, 0, 0, 0, 529, 510, 1, 0, 0, 0, 529, 522, 1, 0, 0, 0, 530, 71, 1, 0, 0, 0, 531, 536, 3, 74, 37, 0, 532, 533, 5, 206, 0, 0, 533, 535, 3, 74, 37, 0, 534, 532, 1, 0, 0, 0, 535, 538, 1, 0, 0, 0, 536, 534, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 537, 73, 1, 0, 0, 0, 538, 536, 1, 0, 0, 0, 539, 540, 6, 37, -1, 0, 540, 542, 5, 19, 0, 0, 541, 543, 3, 74, 37, 0, 542, 541, 1, 0, 0, 0, 542, 543, 1, 0, 0, 0, 543, 549, 1, 0, 0, 0, 544, 545, 5, 186, 0, 0, 545, 546, 3, 74, 37, 0, 546, 547, 5, 163, 0, 0, 547, 548, 3, 74, 37, 0, 548, 550, 1, 0, 0, 0, 549, 544, 1, 0, 0, 0, 550, 551, 1, 0, 0, 0, 551, 549, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 554, 5, 52, 0, 0, 554, 556, 3, 74, 37, 0, 555, 553, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 5, 53, 0, 0, 558, 670, 1, 0, 0, 0, 559, 560, 5, 20, 0, 0, 560, 561, 5, 220, 0, 0, 561, 562, 3, 74, 37, 0, 562, 563, 5, 10, 0, 0, 563, 564, 3, 70, 35, 0, 564, 565, 5, 236, 0, 0, 565, 670, 1, 0, 0, 0, 566, 567, 5, 36, 0, 0, 567, 670, 5, 200, 0, 0, 568, 569, 5, 59, 0, 0, 569, 570, 5, 220, 0, 0, 570, 571, 3, 110, 55, 0, 571, 572, 5, 68, 0, 0, 572, 573, 3, 74, 37, 0, 573, 574, 5, 236, 0, 0, 574, 670, 1, 0, 0, 0, 575, 576, 5, 86, 0, 0, 576, 577, 3, 74, 37, 0, 577, 578, 3, 110, 55, 0, 578, 670, 1, 0, 0, 0, 579, 580, 5, 155, 0, 0, 580, 581, 5, 220, 0, 0, 581, 582, 3, 74, 37, 0, 582, 583, 5, 68, 0, 0, 583, 586, 3, 74, 37, 0, 584, 585, 5, 65, 0, 0, 585, 587, 3, 74, 37, 0, 586, 584, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 1, 0, 0, 0, 588, 589, 5, 236, 0, 0, 589, 670, 1, 0, 0, 0, 590, 591, 5, 166, 0, 0, 591, 670, 5, 200, 0, 0, 592, 593, 5, 171, 0, 0, 593, 594, 5, 220, 0, 0, 594, 595, 7, 9, 0, 0, 595, 596, 5, 200, 0, 0, 596, 597, 5, 68, 0, 0, 597, 598, 3, 74, 37, 0, 598, 599, 5, 236, 0, 0, 599, 670, 1, 0, 0, 0, 600, 601, 3, 118, 59, 0, 601, 603, 5, 220, 0, 0, 602, 604, 3, 72, 36, 0, 603, 602, 1, 0, 0, 0, 603, 604, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 606, 5, 236, 0, 0, 606, 607, 1, 0, 0, 0, 607, 608, 5, 125, 0, 0, 608, 609, 5, 220, 0, 0, 609, 610, 3, 56, 28, 0, 610, 611, 5, 236, 0, 0, 611, 670, 1, 0, 0, 0, 612, 613, 3, 118, 59, 0, 613, 615, 5, 220, 0, 0, 614, 616, 3, 72, 36, 0, 615, 614, 1, 0, 0, 0, 615, 616, 1, 0, 0, 0, 616, 617, 1, 0, 0, 0, 617, 618, 5, 236, 0, 0, 618, 619, 1, 0, 0, 0, 619, 620, 5, 125, 0, 0, 620, 621, 3, 118, 59, 0, 621, 670, 1, 0, 0, 0, 622, 628, 3, 118, 59, 0, 623, 625, 5, 220, 0, 0, 624, 626, 3, 72, 36, 0, 625, 624, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 627, 1, 0, 0, 0, 627, 629, 5, 236, 0, 0, 628, 623, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 632, 5, 220, 0, 0, 631, 633, 5, 49, 0, 0, 632, 631, 1, 0, 0, 0, 632, 633, 1, 0, 0, 0, 633, 635, 1, 0, 0, 0, 634, 636, 3, 76, 38, 0, 635, 634, 1, 0, 0, 0, 635, 636, 1, 0, 0, 0, 636, 637, 1, 0, 0, 0, 637, 638, 5, 236, 0, 0, 638, 670, 1, 0, 0, 0, 639, 670, 3, 82, 41, 0, 640, 670, 3, 108, 54, 0, 641, 642, 5, 208, 0, 0, 642, 670, 3, 74, 37, 18, 643, 644, 5, 115, 0, 0, 644, 670, 3, 74, 37, 12, 645, 646, 3, 98, 49, 0, 646, 647, 5, 210, 0, 0, 647, 649, 1, 0, 0, 0, 648, 645, 1, 0, 0, 0, 648, 649, 1, 0, 0, 0, 649, 650, 1, 0, 0, 0, 650, 670, 5, 202, 0, 0, 651, 652, 5, 220, 0, 0, 652, 653, 3, 2, 1, 0, 653, 654, 5, 236, 0, 0, 654, 670, 1, 0, 0, 0, 655, 656, 5, 220, 0, 0, 656, 657, 3, 74, 37, 0, 657, 658, 5, 236, 0, 0, 658, 670, 1, 0, 0, 0, 659, 660, 5, 220, 0, 0, 660, 661, 3, 72, 36, 0, 661, 662, 5, 236, 0, 0, 662, 670, 1, 0, 0, 0, 663, 665, 5, 219, 0, 0, 664, 666, 3, 72, 36, 0, 665, 664, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 667, 1, 0, 0, 0, 667, 670, 5, 235, 0, 0, 668, 670, 3, 90, 45, 0, 669, 539, 1, 0, 0, 0, 669, 559, 1, 0, 0, 0, 669, 566, 1, 0, 0, 0, 669, 568, 1, 0, 0, 0, 669, 575, 1, 0, 0, 0, 669, 579, 1, 0, 0, 0, 669, 590, 1, 0, 0, 0, 669, 592, 1, 0, 0, 0, 669, 600, 1, 0, 0, 0, 669, 612, 1, 0, 0, 0, 669, 622, 1, 0, 0, 0, 669, 639, 1, 0, 0, 0, 669, 640, 1, 0, 0, 0, 669, 641, 1, 0, 0, 0, 669, 643, 1, 0, 0, 0, 669, 648, 1, 0, 0, 0, 669, 651, 1, 0, 0, 0, 669, 655, 1, 0, 0, 0, 669, 659, 1, 0, 0, 0, 669, 663, 1, 0, 0, 0, 669, 668, 1, 0, 0, 0, 670, 764, 1, 0, 0, 0, 671, 675, 10, 17, 0, 0, 672, 676, 5, 202, 0, 0, 673, 676, 5, 238, 0, 0, 674, 676, 5, 227, 0, 0, 675, 672, 1, 0, 0, 0, 675, 673, 1, 0, 0, 0, 675, 674, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 763, 3, 74, 37, 18, 678, 682, 10, 16, 0, 0, 679, 683, 5, 228, 0, 0, 680, 683, 5, 208, 0, 0, 681, 683, 5, 207, 0, 0, 682, 679, 1, 0, 0, 0, 682, 680, 1, 0, 0, 0, 682, 681, 1, 0, 0, 0, 683, 684, 1, 0, 0, 0, 684, 763, 3, 74, 37, 17, 685, 710, 10, 15, 0, 0, 686, 711, 5, 211, 0, 0, 687, 711, 5, 212, 0, 0, 688, 711, 5, 223, 0, 0, 689, 711, 5, 221, 0, 0, 690, 711, 5, 222, 0, 0, 691, 711, 5, 213, 0, 0, 692, 711, 5, 214, 0, 0, 693, 695, 5, 115, 0, 0, 694, 693, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 696, 1, 0, 0, 0, 696, 698, 5, 80, 0, 0, 697, 699, 5, 25, 0, 0, 698, 697, 1, 0, 0, 0, 698, 699, 1, 0, 0, 0, 699, 711, 1, 0, 0, 0, 700, 702, 5, 115, 0, 0, 701, 700, 1, 0, 0, 0, 701, 702, 1, 0, 0, 0, 702, 703, 1, 0, 0, 0, 703, 711, 7, 10, 0, 0, 704, 711, 5, 232, 0, 0, 705, 711, 5, 233, 0, 0, 706, 711, 5, 225, 0, 0, 707, 711, 5, 216, 0, 0, 708, 711, 5, 217, 0, 0, 709, 711, 5, 224, 0, 0, 710, 686, 1, 0, 0, 0, 710, 687, 1, 0, 0, 0, 710, 688, 1, 0, 0, 0, 710, 689, 1, 0, 0, 0, 710, 690, 1, 0, 0, 0, 710, 691, 1, 0, 0, 0, 710, 692, 1, 0, 0, 0, 710, 694, 1, 0, 0, 0, 710, 701, 1, 0, 0, 0, 710, 704, 1, 0, 0, 0, 710, 705, 1, 0, 0, 0, 710, 706, 1, 0, 0, 0, 710, 707, 1, 0, 0, 0, 710, 708, 1, 0, 0, 0, 710, 709, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712, 763, 3, 74, 37, 16, 713, 714, 10, 13, 0, 0, 714, 715, 5, 226, 0, 0, 715, 763, 3, 74, 37, 14, 716, 717, 10, 11, 0, 0, 717, 718, 5, 6, 0, 0, 718, 763, 3, 74, 37, 12, 719, 720, 10, 10, 0, 0, 720, 721, 5, 121, 0, 0, 721, 763, 3, 74, 37, 11, 722, 724, 10, 9, 0, 0, 723, 725, 5, 115, 0, 0, 724, 723, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726, 727, 5, 16, 0, 0, 727, 728, 3, 74, 37, 0, 728, 729, 5, 6, 0, 0, 729, 730, 3, 74, 37, 10, 730, 763, 1, 0, 0, 0, 731, 732, 10, 8, 0, 0, 732, 733, 5, 229, 0, 0, 733, 734, 3, 74, 37, 0, 734, 735, 5, 205, 0, 0, 735, 736, 3, 74, 37, 8, 736, 763, 1, 0, 0, 0, 737, 738, 10, 21, 0, 0, 738, 739, 5, 219, 0, 0, 739, 740, 3, 74, 37, 0, 740, 741, 5, 235, 0, 0, 741, 763, 1, 0, 0, 0, 742, 743, 10, 20, 0, 0, 743, 744, 5, 210, 0, 0, 744, 763, 5, 198, 0, 0, 745, 746, 10, 19, 0, 0, 746, 747, 5, 210, 0, 0, 747, 763, 3, 118, 59, 0, 748, 749, 10, 14, 0, 0, 749, 751, 5, 88, 0, 0, 750, 752, 5, 115, 0, 0, 751, 750, 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 752, 753, 1, 0, 0, 0, 753, 763, 5, 116, 0, 0, 754, 760, 10, 7, 0, 0, 755, 761, 3, 116, 58, 0, 756, 757, 5, 10, 0, 0, 757, 761, 3, 118, 59, 0, 758, 759, 5, 10, 0, 0, 759, 761, 5, 200, 0, 0, 760, 755, 1, 0, 0, 0, 760, 756, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 763, 1, 0, 0, 0, 762, 671, 1, 0, 0, 0, 762, 678, 1, 0, 0, 0, 762, 685, 1, 0, 0, 0, 762, 713, 1, 0, 0, 0, 762, 716, 1, 0, 0, 0, 762, 719, 1, 0, 0, 0, 762, 722, 1, 0, 0, 0, 762, 731, 1, 0, 0, 0, 762, 737, 1, 0, 0, 0, 762, 742, 1, 0, 0, 0, 762, 745, 1, 0, 0, 0, 762, 748, 1, 0, 0, 0, 762, 754, 1, 0, 0, 0, 763, 766, 1, 0, 0, 0, 764, 762, 1, 0, 0, 0, 764, 765, 1, 0, 0, 0, 765, 75, 1, 0, 0, 0, 766, 764, 1, 0, 0, 0, 767, 772, 3, 78, 39, 0, 768, 769, 5, 206, 0, 0, 769, 771, 3, 78, 39, 0, 770, 768, 1, 0, 0, 0, 771, 774, 1, 0, 0, 0, 772, 770, 1, 0, 0, 0, 772, 773, 1, 0, 0, 0, 773, 77, 1, 0, 0, 0, 774, 772, 1, 0, 0, 0, 775, 778, 3, 80, 40, 0, 776, 778, 3, 74, 37, 0, 777, 775, 1, 0, 0, 0, 777, 776, 1, 0, 0, 0, 778, 79, 1, 0, 0, 0, 779, 780, 5, 220, 0, 0, 780, 785, 3, 118, 59, 0, 781, 782, 5, 206, 0, 0, 782, 784, 3, 118, 59, 0, 783, 781, 1, 0, 0, 0, 784, 787, 1, 0, 0, 0, 785, 783, 1, 0, 0, 0, 785, 786, 1, 0, 0, 0, 786, 788, 1, 0, 0, 0, 787, 785, 1, 0, 0, 0, 788, 789, 5, 236, 0, 0, 789, 799, 1, 0, 0, 0, 790, 795, 3, 118, 59, 0, 791, 792, 5, 206, 0, 0, 792, 794, 3, 118, 59, 0, 793, 791, 1, 0, 0, 0, 794, 797, 1, 0, 0, 0, 795, 793, 1, 0, 0, 0, 795, 796, 1, 0, 0, 0, 796, 799, 1, 0, 0, 0, 797, 795, 1, 0, 0, 0, 798, 779, 1, 0, 0, 0, 798, 790, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0, 800, 801, 5, 201, 0, 0, 801, 802, 3, 74, 37, 0, 802, 81, 1, 0, 0, 0, 803, 804, 5, 222, 0, 0, 804, 808, 3, 118, 59, 0, 805, 807, 3, 84, 42, 0, 806, 805, 1, 0, 0, 0, 807, 810, 1, 0, 0, 0, 808, 806, 1, 0, 0, 0, 808, 809, 1, 0, 0, 0, 809, 811, 1, 0, 0, 0, 810, 808, 1, 0, 0, 0, 811, 812, 5, 238, 0, 0, 812, 813, 5, 214, 0, 0, 813, 832, 1, 0, 0, 0, 814, 815, 5, 222, 0, 0, 815, 819, 3, 118, 59, 0, 816, 818, 3, 84, 42, 0, 817, 816, 1, 0, 0, 0, 818, 821, 1, 0, 0, 0, 819, 817, 1, 0, 0, 0, 819, 820, 1, 0, 0, 0, 820, 822, 1, 0, 0, 0, 821, 819, 1, 0, 0, 0, 822, 824, 5, 214, 0, 0, 823, 825, 3, 82, 41, 0, 824, 823, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 827, 5, 222, 0, 0, 827, 828, 5, 238, 0, 0, 828, 829, 3, 118, 59, 0, 829, 830, 5, 214, 0, 0, 830, 832, 1, 0, 0, 0, 831, 803, 1, 0, 0, 0, 831, 814, 1, 0, 0, 0, 832, 83, 1, 0, 0, 0, 833, 834, 3, 118, 59, 0, 834, 835, 5, 212, 0, 0, 835, 836, 5, 200, 0, 0, 836, 845, 1, 0, 0, 0, 837, 838, 3, 118, 59, 0, 838, 839, 5, 212, 0, 0, 839, 840, 5, 218, 0, 0, 840, 841, 3, 74, 37, 0, 841, 842, 5, 234, 0, 0, 842, 845, 1, 0, 0, 0, 843, 845, 3, 118, 59, 0, 844, 833, 1, 0, 0, 0, 844, 837, 1, 0, 0, 0, 844, 843, 1, 0, 0, 0, 845, 85, 1, 0, 0, 0, 846, 851, 3, 88, 44, 0, 847, 848, 5, 206, 0, 0, 848, 850, 3, 88, 44, 0, 849, 847, 1, 0, 0, 0, 850, 853, 1, 0, 0, 0, 851, 849, 1, 0, 0, 0, 851, 852, 1, 0, 0, 0, 852, 87, 1, 0, 0, 0, 853, 851, 1, 0, 0, 0, 854, 855, 3, 118, 59, 0, 855, 856, 5, 10, 0, 0, 856, 857, 5, 220, 0, 0, 857, 858, 3, 2, 1, 0, 858, 859, 5, 236, 0, 0, 859, 865, 1, 0, 0, 0, 860, 861, 3, 74, 37, 0, 861, 862, 5, 10, 0, 0, 862, 863, 3, 118, 59, 0, 863, 865, 1, 0, 0, 0, 864, 854, 1, 0, 0, 0, 864, 860, 1, 0, 0, 0, 865, 89, 1, 0, 0, 0, 866, 874, 3, 122, 61, 0, 867, 868, 3, 98, 49, 0, 868, 869, 5, 210, 0, 0, 869, 871, 1, 0, 0, 0, 870, 867, 1, 0, 0, 0, 870, 871, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 874, 3, 92, 46, 0, 873, 866, 1, 0, 0, 0, 873, 870, 1, 0, 0, 0, 874, 91, 1, 0, 0, 0, 875, 880, 3, 118, 59, 0, 876, 877, 5, 210, 0, 0, 877, 879, 3, 118, 59, 0, 878, 876, 1, 0, 0, 0, 879, 882, 1, 0, 0, 0, 880, 878, 1, 0, 0, 0, 880, 881, 1, 0, 0, 0, 881, 93, 1, 0, 0, 0, 882, 880, 1, 0, 0, 0, 883, 884, 6, 47, -1, 0, 884, 893, 3, 98, 49, 0, 885, 893, 3, 96, 48, 0, 886, 887, 5, 220, 0, 0, 887, 888, 3, 2, 1, 0, 888, 889, 5, 236, 0, 0, 889, 893, 1, 0, 0, 0, 890, 893, 3, 82, 41, 0, 891, 893, 3, 122, 61, 0, 892, 883, 1, 0, 0, 0, 892, 885, 1, 0, 0, 0, 892, 886, 1, 0, 0, 0, 892, 890, 1, 0, 0, 0, 892, 891, 1, 0, 0, 0, 893, 902, 1, 0, 0, 0, 894, 898, 10, 3, 0, 0, 895, 899, 3, 116, 58, 0, 896, 897, 5, 10, 0, 0, 897, 899, 3, 118, 59, 0, 898, 895, 1, 0, 0, 0, 898, 896, 1, 0, 0, 0, 899, 901, 1, 0, 0, 0, 900, 894, 1, 0, 0, 0, 901, 904, 1, 0, 0, 0, 902, 900, 1, 0, 0, 0, 902, 903, 1, 0, 0, 0, 903, 95, 1, 0, 0, 0, 904, 902, 1, 0, 0, 0, 905, 906, 3, 118, 59, 0, 906, 908, 5, 220, 0, 0, 907, 909, 3, 100, 50, 0, 908, 907, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 5, 236, 0, 0, 911, 97, 1, 0, 0, 0, 912, 913, 3, 102, 51, 0, 913, 914, 5, 210, 0, 0, 914, 916, 1, 0, 0, 0, 915, 912, 1, 0, 0, 0, 915, 916, 1, 0, 0, 0, 916, 917, 1, 0, 0, 0, 917, 918, 3, 118, 59, 0, 918, 99, 1, 0, 0, 0, 919, 924, 3, 74, 37, 0, 920, 921, 5, 206, 0, 0, 921, 923, 3, 74, 37, 0, 922, 920, 1, 0, 0, 0, 923, 926, 1, 0, 0, 0, 924, 922, 1, 0, 0, 0, 924, 925, 1, 0, 0, 0, 925, 101, 1, 0, 0, 0, 926, 924, 1, 0, 0, 0, 927, 928, 3, 118, 59, 0, 928, 103, 1, 0, 0, 0, 929, 938, 5, 196, 0, 0, 930, 931, 5, 210, 0, 0, 931, 938, 7, 11, 0, 0, 932, 933, 5, 198, 0, 0, 933, 935, 5, 210, 0, 0, 934, 936, 7, 11, 0, 0, 935, 934, 1, 0, 0, 0, 935, 936, 1, 0, 0, 0, 936, 938, 1, 0, 0, 0, 937, 929, 1, 0, 0, 0, 937, 930, 1, 0, 0, 0, 937, 932, 1, 0, 0, 0, 938, 105, 1, 0, 0, 0, 939, 941, 7, 12, 0, 0, 940, 939, 1, 0, 0, 0, 940, 941, 1, 0, 0, 0, 941, 948, 1, 0, 0, 0, 942, 949, 3, 104, 52, 0, 943, 949, 5, 197, 0, 0, 944, 949, 5, 198, 0, 0, 945, 949, 5, 199, 0, 0, 946, 949, 5, 82, 0, 0, 947, 949, 5, 113, 0, 0, 948, 942, 1, 0, 0, 0, 948, 943, 1, 0, 0, 0, 948, 944, 1, 0, 0, 0, 948, 945, 1, 0, 0, 0, 948, 946, 1, 0, 0, 0, 948, 947, 1, 0, 0, 0, 949, 107, 1, 0, 0, 0, 950, 954, 3, 106, 53, 0, 951, 954, 5, 200, 0, 0, 952, 954, 5, 116, 0, 0, 953, 950, 1, 0, 0, 0, 953, 951, 1, 0, 0, 0, 953, 952, 1, 0, 0, 0, 954, 109, 1, 0, 0, 0, 955, 956, 7, 13, 0, 0, 956, 111, 1, 0, 0, 0, 957, 958, 7, 14, 0, 0, 958, 113, 1, 0, 0, 0, 959, 960, 7, 15, 0, 0, 960, 115, 1, 0, 0, 0, 961, 964, 5, 195, 0, 0, 962, 964, 3, 114, 57, 0, 963, 961, 1, 0, 0, 0, 963, 962, 1, 0, 0, 0, 964, 117, 1, 0, 0, 0, 965, 969, 5, 195, 0, 0, 966, 969, 3, 110, 55, 0, 967, 969, 3, 112, 56, 0, 968, 965, 1, 0, 0, 0, 968, 966, 1, 0, 0, 0, 968, 967, 1, 0, 0, 0, 969, 119, 1, 0, 0, 0, 970, 971, 5, 200, 0, 0, 971, 972, 5, 212, 0, 0, 972, 973, 3, 106, 53, 0, 973, 121, 1, 0, 0, 0, 974, 975, 5, 218, 0, 0, 975, 976, 3, 118, 59, 0, 976, 977, 5, 234, 0, 0, 977, 123, 1, 0, 0, 0, 120, 127, 137, 146, 149, 153, 156, 160, 163, 166, 169, 172, 176, 180, 183, 186, 189, 193, 196, 205, 211, 232, 249, 266, 272, 278, 289, 291, 302, 305, 311, 319, 325, 327, 331, 336, 339, 342, 346, 350, 353, 355, 358, 362, 366, 369, 371, 373, 378, 389, 395, 402, 407, 411, 415, 421, 423, 430, 438, 441, 444, 463, 477, 493, 505, 517, 525, 529, 536, 542, 551, 555, 586, 603, 615, 625, 628, 632, 635, 648, 665, 669, 675, 682, 694, 698, 701, 710, 724, 751, 760, 762, 764, 772, 777, 785, 795, 798, 808, 819, 824, 831, 844, 851, 864, 870, 873, 880, 892, 898, 902, 908, 915, 924, 935, 937, 940, 948, 953, 963, 968]
\ No newline at end of file
+[4, 1, 242, 972, 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, 1, 0, 1, 0, 1, 0, 3, 0, 128, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 136, 8, 1, 10, 1, 12, 1, 139, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 147, 8, 2, 1, 3, 3, 3, 150, 8, 3, 1, 3, 1, 3, 3, 3, 154, 8, 3, 1, 3, 3, 3, 157, 8, 3, 1, 3, 1, 3, 3, 3, 161, 8, 3, 1, 3, 3, 3, 164, 8, 3, 1, 3, 3, 3, 167, 8, 3, 1, 3, 3, 3, 170, 8, 3, 1, 3, 3, 3, 173, 8, 3, 1, 3, 1, 3, 3, 3, 177, 8, 3, 1, 3, 1, 3, 3, 3, 181, 8, 3, 1, 3, 3, 3, 184, 8, 3, 1, 3, 3, 3, 187, 8, 3, 1, 3, 3, 3, 190, 8, 3, 1, 3, 1, 3, 3, 3, 194, 8, 3, 1, 3, 3, 3, 197, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 206, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 3, 7, 212, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 231, 8, 8, 10, 8, 12, 8, 234, 9, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 250, 8, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 267, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 273, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 279, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 290, 8, 15, 3, 15, 292, 8, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 3, 18, 303, 8, 18, 1, 18, 3, 18, 306, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 312, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 320, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 326, 8, 18, 10, 18, 12, 18, 329, 9, 18, 1, 19, 3, 19, 332, 8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 337, 8, 19, 1, 19, 3, 19, 340, 8, 19, 1, 19, 3, 19, 343, 8, 19, 1, 19, 1, 19, 3, 19, 347, 8, 19, 1, 19, 1, 19, 3, 19, 351, 8, 19, 1, 19, 3, 19, 354, 8, 19, 3, 19, 356, 8, 19, 1, 19, 3, 19, 359, 8, 19, 1, 19, 1, 19, 3, 19, 363, 8, 19, 1, 19, 1, 19, 3, 19, 367, 8, 19, 1, 19, 3, 19, 370, 8, 19, 3, 19, 372, 8, 19, 3, 19, 374, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 379, 8, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 390, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 396, 8, 22, 1, 23, 1, 23, 1, 23, 5, 23, 401, 8, 23, 10, 23, 12, 23, 404, 9, 23, 1, 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, 25, 1, 25, 1, 25, 1, 25, 3, 25, 422, 8, 25, 3, 25, 424, 8, 25, 1, 26, 1, 26, 1, 26, 5, 26, 429, 8, 26, 10, 26, 12, 26, 432, 9, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 439, 8, 28, 1, 28, 3, 28, 442, 8, 28, 1, 28, 3, 28, 445, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 464, 8, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 478, 8, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 492, 8, 35, 10, 35, 12, 35, 495, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 504, 8, 35, 10, 35, 12, 35, 507, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 516, 8, 35, 10, 35, 12, 35, 519, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 3, 35, 526, 8, 35, 1, 35, 1, 35, 3, 35, 530, 8, 35, 1, 36, 1, 36, 1, 36, 5, 36, 535, 8, 36, 10, 36, 12, 36, 538, 9, 36, 1, 37, 1, 37, 1, 37, 3, 37, 543, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 550, 8, 37, 11, 37, 12, 37, 551, 1, 37, 1, 37, 3, 37, 556, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 580, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 597, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 609, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 619, 8, 37, 1, 37, 3, 37, 622, 8, 37, 1, 37, 1, 37, 3, 37, 626, 8, 37, 1, 37, 3, 37, 629, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 642, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 659, 8, 37, 1, 37, 1, 37, 3, 37, 663, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 669, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 676, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 688, 8, 37, 1, 37, 1, 37, 3, 37, 692, 8, 37, 1, 37, 3, 37, 695, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 704, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 718, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 745, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 754, 8, 37, 5, 37, 756, 8, 37, 10, 37, 12, 37, 759, 9, 37, 1, 38, 1, 38, 1, 38, 5, 38, 764, 8, 38, 10, 38, 12, 38, 767, 9, 38, 1, 39, 1, 39, 3, 39, 771, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 777, 8, 40, 10, 40, 12, 40, 780, 9, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 787, 8, 40, 10, 40, 12, 40, 790, 9, 40, 3, 40, 792, 8, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 5, 41, 800, 8, 41, 10, 41, 12, 41, 803, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 811, 8, 41, 10, 41, 12, 41, 814, 9, 41, 1, 41, 1, 41, 3, 41, 818, 8, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 825, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 838, 8, 42, 1, 43, 1, 43, 1, 43, 5, 43, 843, 8, 43, 10, 43, 12, 43, 846, 9, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 858, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 3, 45, 864, 8, 45, 1, 45, 3, 45, 867, 8, 45, 1, 46, 1, 46, 1, 46, 5, 46, 872, 8, 46, 10, 46, 12, 46, 875, 9, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 886, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 892, 8, 47, 5, 47, 894, 8, 47, 10, 47, 12, 47, 897, 9, 47, 1, 48, 1, 48, 1, 48, 3, 48, 902, 8, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 3, 49, 909, 8, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 5, 50, 916, 8, 50, 10, 50, 12, 50, 919, 9, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 929, 8, 52, 3, 52, 931, 8, 52, 1, 53, 3, 53, 934, 8, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 942, 8, 53, 1, 54, 1, 54, 1, 54, 3, 54, 947, 8, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 3, 58, 957, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 962, 8, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 0, 3, 36, 74, 94, 62, 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, 0, 16, 2, 0, 32, 32, 141, 141, 2, 0, 84, 84, 96, 96, 3, 0, 4, 4, 8, 8, 12, 12, 4, 0, 4, 4, 7, 8, 12, 12, 147, 147, 2, 0, 96, 96, 140, 140, 2, 0, 4, 4, 8, 8, 2, 0, 11, 11, 42, 43, 2, 0, 62, 62, 93, 93, 2, 0, 133, 133, 143, 143, 3, 0, 17, 17, 95, 95, 170, 170, 2, 0, 79, 79, 98, 98, 1, 0, 197, 198, 2, 0, 208, 208, 228, 228, 8, 0, 37, 37, 76, 76, 108, 108, 110, 110, 132, 132, 145, 145, 185, 185, 190, 190, 13, 0, 2, 24, 26, 36, 38, 75, 77, 81, 83, 107, 109, 109, 111, 112, 114, 115, 117, 130, 133, 144, 146, 184, 186, 189, 191, 192, 4, 0, 36, 36, 62, 62, 77, 77, 91, 91, 1099, 0, 127, 1, 0, 0, 0, 2, 131, 1, 0, 0, 0, 4, 146, 1, 0, 0, 0, 6, 149, 1, 0, 0, 0, 8, 198, 1, 0, 0, 0, 10, 201, 1, 0, 0, 0, 12, 207, 1, 0, 0, 0, 14, 211, 1, 0, 0, 0, 16, 217, 1, 0, 0, 0, 18, 235, 1, 0, 0, 0, 20, 238, 1, 0, 0, 0, 22, 241, 1, 0, 0, 0, 24, 251, 1, 0, 0, 0, 26, 254, 1, 0, 0, 0, 28, 258, 1, 0, 0, 0, 30, 291, 1, 0, 0, 0, 32, 293, 1, 0, 0, 0, 34, 296, 1, 0, 0, 0, 36, 311, 1, 0, 0, 0, 38, 373, 1, 0, 0, 0, 40, 378, 1, 0, 0, 0, 42, 389, 1, 0, 0, 0, 44, 391, 1, 0, 0, 0, 46, 397, 1, 0, 0, 0, 48, 405, 1, 0, 0, 0, 50, 423, 1, 0, 0, 0, 52, 425, 1, 0, 0, 0, 54, 433, 1, 0, 0, 0, 56, 438, 1, 0, 0, 0, 58, 446, 1, 0, 0, 0, 60, 450, 1, 0, 0, 0, 62, 454, 1, 0, 0, 0, 64, 463, 1, 0, 0, 0, 66, 477, 1, 0, 0, 0, 68, 479, 1, 0, 0, 0, 70, 529, 1, 0, 0, 0, 72, 531, 1, 0, 0, 0, 74, 662, 1, 0, 0, 0, 76, 760, 1, 0, 0, 0, 78, 770, 1, 0, 0, 0, 80, 791, 1, 0, 0, 0, 82, 824, 1, 0, 0, 0, 84, 837, 1, 0, 0, 0, 86, 839, 1, 0, 0, 0, 88, 857, 1, 0, 0, 0, 90, 866, 1, 0, 0, 0, 92, 868, 1, 0, 0, 0, 94, 885, 1, 0, 0, 0, 96, 898, 1, 0, 0, 0, 98, 908, 1, 0, 0, 0, 100, 912, 1, 0, 0, 0, 102, 920, 1, 0, 0, 0, 104, 930, 1, 0, 0, 0, 106, 933, 1, 0, 0, 0, 108, 946, 1, 0, 0, 0, 110, 948, 1, 0, 0, 0, 112, 950, 1, 0, 0, 0, 114, 952, 1, 0, 0, 0, 116, 956, 1, 0, 0, 0, 118, 961, 1, 0, 0, 0, 120, 963, 1, 0, 0, 0, 122, 967, 1, 0, 0, 0, 124, 128, 3, 2, 1, 0, 125, 128, 3, 6, 3, 0, 126, 128, 3, 82, 41, 0, 127, 124, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 130, 5, 0, 0, 1, 130, 1, 1, 0, 0, 0, 131, 137, 3, 4, 2, 0, 132, 133, 5, 176, 0, 0, 133, 134, 5, 4, 0, 0, 134, 136, 3, 4, 2, 0, 135, 132, 1, 0, 0, 0, 136, 139, 1, 0, 0, 0, 137, 135, 1, 0, 0, 0, 137, 138, 1, 0, 0, 0, 138, 3, 1, 0, 0, 0, 139, 137, 1, 0, 0, 0, 140, 147, 3, 6, 3, 0, 141, 142, 5, 220, 0, 0, 142, 143, 3, 2, 1, 0, 143, 144, 5, 236, 0, 0, 144, 147, 1, 0, 0, 0, 145, 147, 3, 122, 61, 0, 146, 140, 1, 0, 0, 0, 146, 141, 1, 0, 0, 0, 146, 145, 1, 0, 0, 0, 147, 5, 1, 0, 0, 0, 148, 150, 3, 8, 4, 0, 149, 148, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 153, 5, 146, 0, 0, 152, 154, 5, 49, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 156, 1, 0, 0, 0, 155, 157, 3, 10, 5, 0, 156, 155, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 160, 3, 72, 36, 0, 159, 161, 3, 12, 6, 0, 160, 159, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 163, 1, 0, 0, 0, 162, 164, 3, 14, 7, 0, 163, 162, 1, 0, 0, 0, 163, 164, 1, 0, 0, 0, 164, 166, 1, 0, 0, 0, 165, 167, 3, 18, 9, 0, 166, 165, 1, 0, 0, 0, 166, 167, 1, 0, 0, 0, 167, 169, 1, 0, 0, 0, 168, 170, 3, 20, 10, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 172, 1, 0, 0, 0, 171, 173, 3, 22, 11, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 175, 5, 189, 0, 0, 175, 177, 7, 0, 0, 0, 176, 174, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 180, 1, 0, 0, 0, 178, 179, 5, 189, 0, 0, 179, 181, 5, 169, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 183, 1, 0, 0, 0, 182, 184, 3, 24, 12, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 187, 3, 16, 8, 0, 186, 185, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 190, 3, 26, 13, 0, 189, 188, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 194, 3, 30, 15, 0, 192, 194, 3, 32, 16, 0, 193, 191, 1, 0, 0, 0, 193, 192, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 196, 1, 0, 0, 0, 195, 197, 3, 34, 17, 0, 196, 195, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 7, 1, 0, 0, 0, 198, 199, 5, 189, 0, 0, 199, 200, 3, 86, 43, 0, 200, 9, 1, 0, 0, 0, 201, 202, 5, 168, 0, 0, 202, 205, 5, 198, 0, 0, 203, 204, 5, 189, 0, 0, 204, 206, 5, 164, 0, 0, 205, 203, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 11, 1, 0, 0, 0, 207, 208, 5, 68, 0, 0, 208, 209, 3, 36, 18, 0, 209, 13, 1, 0, 0, 0, 210, 212, 7, 1, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 5, 9, 0, 0, 214, 215, 5, 90, 0, 0, 215, 216, 3, 72, 36, 0, 216, 15, 1, 0, 0, 0, 217, 218, 5, 188, 0, 0, 218, 219, 3, 118, 59, 0, 219, 220, 5, 10, 0, 0, 220, 221, 5, 220, 0, 0, 221, 222, 3, 56, 28, 0, 222, 232, 5, 236, 0, 0, 223, 224, 5, 206, 0, 0, 224, 225, 3, 118, 59, 0, 225, 226, 5, 10, 0, 0, 226, 227, 5, 220, 0, 0, 227, 228, 3, 56, 28, 0, 228, 229, 5, 236, 0, 0, 229, 231, 1, 0, 0, 0, 230, 223, 1, 0, 0, 0, 231, 234, 1, 0, 0, 0, 232, 230, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 17, 1, 0, 0, 0, 234, 232, 1, 0, 0, 0, 235, 236, 5, 129, 0, 0, 236, 237, 3, 74, 37, 0, 237, 19, 1, 0, 0, 0, 238, 239, 5, 187, 0, 0, 239, 240, 3, 74, 37, 0, 240, 21, 1, 0, 0, 0, 241, 242, 5, 73, 0, 0, 242, 249, 5, 18, 0, 0, 243, 244, 7, 0, 0, 0, 244, 245, 5, 220, 0, 0, 245, 246, 3, 72, 36, 0, 246, 247, 5, 236, 0, 0, 247, 250, 1, 0, 0, 0, 248, 250, 3, 72, 36, 0, 249, 243, 1, 0, 0, 0, 249, 248, 1, 0, 0, 0, 250, 23, 1, 0, 0, 0, 251, 252, 5, 74, 0, 0, 252, 253, 3, 74, 37, 0, 253, 25, 1, 0, 0, 0, 254, 255, 5, 122, 0, 0, 255, 256, 5, 18, 0, 0, 256, 257, 3, 46, 23, 0, 257, 27, 1, 0, 0, 0, 258, 259, 5, 122, 0, 0, 259, 260, 5, 18, 0, 0, 260, 261, 3, 72, 36, 0, 261, 29, 1, 0, 0, 0, 262, 263, 5, 99, 0, 0, 263, 266, 3, 74, 37, 0, 264, 265, 5, 206, 0, 0, 265, 267, 3, 74, 37, 0, 266, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 272, 1, 0, 0, 0, 268, 269, 5, 189, 0, 0, 269, 273, 5, 164, 0, 0, 270, 271, 5, 18, 0, 0, 271, 273, 3, 72, 36, 0, 272, 268, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 292, 1, 0, 0, 0, 274, 275, 5, 99, 0, 0, 275, 278, 3, 74, 37, 0, 276, 277, 5, 189, 0, 0, 277, 279, 5, 164, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 5, 118, 0, 0, 281, 282, 3, 74, 37, 0, 282, 292, 1, 0, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 3, 74, 37, 0, 285, 286, 5, 118, 0, 0, 286, 289, 3, 74, 37, 0, 287, 288, 5, 18, 0, 0, 288, 290, 3, 72, 36, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 292, 1, 0, 0, 0, 291, 262, 1, 0, 0, 0, 291, 274, 1, 0, 0, 0, 291, 283, 1, 0, 0, 0, 292, 31, 1, 0, 0, 0, 293, 294, 5, 118, 0, 0, 294, 295, 3, 74, 37, 0, 295, 33, 1, 0, 0, 0, 296, 297, 5, 150, 0, 0, 297, 298, 3, 52, 26, 0, 298, 35, 1, 0, 0, 0, 299, 300, 6, 18, -1, 0, 300, 302, 3, 94, 47, 0, 301, 303, 5, 61, 0, 0, 302, 301, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 305, 1, 0, 0, 0, 304, 306, 3, 44, 22, 0, 305, 304, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 312, 1, 0, 0, 0, 307, 308, 5, 220, 0, 0, 308, 309, 3, 36, 18, 0, 309, 310, 5, 236, 0, 0, 310, 312, 1, 0, 0, 0, 311, 299, 1, 0, 0, 0, 311, 307, 1, 0, 0, 0, 312, 327, 1, 0, 0, 0, 313, 314, 10, 3, 0, 0, 314, 315, 3, 40, 20, 0, 315, 316, 3, 36, 18, 4, 316, 326, 1, 0, 0, 0, 317, 319, 10, 4, 0, 0, 318, 320, 3, 38, 19, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 90, 0, 0, 322, 323, 3, 36, 18, 0, 323, 324, 3, 42, 21, 0, 324, 326, 1, 0, 0, 0, 325, 313, 1, 0, 0, 0, 325, 317, 1, 0, 0, 0, 326, 329, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 37, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 330, 332, 7, 2, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 340, 5, 84, 0, 0, 334, 336, 5, 84, 0, 0, 335, 337, 7, 2, 0, 0, 336, 335, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 340, 1, 0, 0, 0, 338, 340, 7, 2, 0, 0, 339, 331, 1, 0, 0, 0, 339, 334, 1, 0, 0, 0, 339, 338, 1, 0, 0, 0, 340, 374, 1, 0, 0, 0, 341, 343, 7, 3, 0, 0, 342, 341, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 344, 1, 0, 0, 0, 344, 346, 7, 4, 0, 0, 345, 347, 5, 123, 0, 0, 346, 345, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 347, 356, 1, 0, 0, 0, 348, 350, 7, 4, 0, 0, 349, 351, 5, 123, 0, 0, 350, 349, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 353, 1, 0, 0, 0, 352, 354, 7, 3, 0, 0, 353, 352, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 356, 1, 0, 0, 0, 355, 342, 1, 0, 0, 0, 355, 348, 1, 0, 0, 0, 356, 374, 1, 0, 0, 0, 357, 359, 7, 5, 0, 0, 358, 357, 1, 0, 0, 0, 358, 359, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 362, 5, 69, 0, 0, 361, 363, 5, 123, 0, 0, 362, 361, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 372, 1, 0, 0, 0, 364, 366, 5, 69, 0, 0, 365, 367, 5, 123, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 369, 1, 0, 0, 0, 368, 370, 7, 5, 0, 0, 369, 368, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 372, 1, 0, 0, 0, 371, 358, 1, 0, 0, 0, 371, 364, 1, 0, 0, 0, 372, 374, 1, 0, 0, 0, 373, 339, 1, 0, 0, 0, 373, 355, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 374, 39, 1, 0, 0, 0, 375, 376, 5, 31, 0, 0, 376, 379, 5, 90, 0, 0, 377, 379, 5, 206, 0, 0, 378, 375, 1, 0, 0, 0, 378, 377, 1, 0, 0, 0, 379, 41, 1, 0, 0, 0, 380, 381, 5, 119, 0, 0, 381, 390, 3, 72, 36, 0, 382, 383, 5, 179, 0, 0, 383, 384, 5, 220, 0, 0, 384, 385, 3, 72, 36, 0, 385, 386, 5, 236, 0, 0, 386, 390, 1, 0, 0, 0, 387, 388, 5, 179, 0, 0, 388, 390, 3, 72, 36, 0, 389, 380, 1, 0, 0, 0, 389, 382, 1, 0, 0, 0, 389, 387, 1, 0, 0, 0, 390, 43, 1, 0, 0, 0, 391, 392, 5, 144, 0, 0, 392, 395, 3, 50, 25, 0, 393, 394, 5, 118, 0, 0, 394, 396, 3, 50, 25, 0, 395, 393, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 45, 1, 0, 0, 0, 397, 402, 3, 48, 24, 0, 398, 399, 5, 206, 0, 0, 399, 401, 3, 48, 24, 0, 400, 398, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 47, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 405, 407, 3, 74, 37, 0, 406, 408, 7, 6, 0, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 117, 0, 0, 410, 412, 7, 7, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 26, 0, 0, 414, 416, 5, 200, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 49, 1, 0, 0, 0, 417, 424, 3, 122, 61, 0, 418, 421, 3, 106, 53, 0, 419, 420, 5, 238, 0, 0, 420, 422, 3, 106, 53, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 417, 1, 0, 0, 0, 423, 418, 1, 0, 0, 0, 424, 51, 1, 0, 0, 0, 425, 430, 3, 54, 27, 0, 426, 427, 5, 206, 0, 0, 427, 429, 3, 54, 27, 0, 428, 426, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 53, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 433, 434, 3, 118, 59, 0, 434, 435, 5, 212, 0, 0, 435, 436, 3, 108, 54, 0, 436, 55, 1, 0, 0, 0, 437, 439, 3, 58, 29, 0, 438, 437, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 441, 1, 0, 0, 0, 440, 442, 3, 60, 30, 0, 441, 440, 1, 0, 0, 0, 441, 442, 1, 0, 0, 0, 442, 444, 1, 0, 0, 0, 443, 445, 3, 62, 31, 0, 444, 443, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, 57, 1, 0, 0, 0, 446, 447, 5, 126, 0, 0, 447, 448, 5, 18, 0, 0, 448, 449, 3, 72, 36, 0, 449, 59, 1, 0, 0, 0, 450, 451, 5, 122, 0, 0, 451, 452, 5, 18, 0, 0, 452, 453, 3, 46, 23, 0, 453, 61, 1, 0, 0, 0, 454, 455, 7, 8, 0, 0, 455, 456, 3, 64, 32, 0, 456, 63, 1, 0, 0, 0, 457, 464, 3, 66, 33, 0, 458, 459, 5, 16, 0, 0, 459, 460, 3, 66, 33, 0, 460, 461, 5, 6, 0, 0, 461, 462, 3, 66, 33, 0, 462, 464, 1, 0, 0, 0, 463, 457, 1, 0, 0, 0, 463, 458, 1, 0, 0, 0, 464, 65, 1, 0, 0, 0, 465, 466, 5, 33, 0, 0, 466, 478, 5, 142, 0, 0, 467, 468, 5, 175, 0, 0, 468, 478, 5, 128, 0, 0, 469, 470, 5, 175, 0, 0, 470, 478, 5, 64, 0, 0, 471, 472, 3, 106, 53, 0, 472, 473, 5, 128, 0, 0, 473, 478, 1, 0, 0, 0, 474, 475, 3, 106, 53, 0, 475, 476, 5, 64, 0, 0, 476, 478, 1, 0, 0, 0, 477, 465, 1, 0, 0, 0, 477, 467, 1, 0, 0, 0, 477, 469, 1, 0, 0, 0, 477, 471, 1, 0, 0, 0, 477, 474, 1, 0, 0, 0, 478, 67, 1, 0, 0, 0, 479, 480, 3, 74, 37, 0, 480, 481, 5, 0, 0, 1, 481, 69, 1, 0, 0, 0, 482, 530, 3, 118, 59, 0, 483, 484, 3, 118, 59, 0, 484, 485, 5, 220, 0, 0, 485, 486, 3, 118, 59, 0, 486, 493, 3, 70, 35, 0, 487, 488, 5, 206, 0, 0, 488, 489, 3, 118, 59, 0, 489, 490, 3, 70, 35, 0, 490, 492, 1, 0, 0, 0, 491, 487, 1, 0, 0, 0, 492, 495, 1, 0, 0, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 496, 1, 0, 0, 0, 495, 493, 1, 0, 0, 0, 496, 497, 5, 236, 0, 0, 497, 530, 1, 0, 0, 0, 498, 499, 3, 118, 59, 0, 499, 500, 5, 220, 0, 0, 500, 505, 3, 120, 60, 0, 501, 502, 5, 206, 0, 0, 502, 504, 3, 120, 60, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 508, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 509, 5, 236, 0, 0, 509, 530, 1, 0, 0, 0, 510, 511, 3, 118, 59, 0, 511, 512, 5, 220, 0, 0, 512, 517, 3, 70, 35, 0, 513, 514, 5, 206, 0, 0, 514, 516, 3, 70, 35, 0, 515, 513, 1, 0, 0, 0, 516, 519, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 518, 1, 0, 0, 0, 518, 520, 1, 0, 0, 0, 519, 517, 1, 0, 0, 0, 520, 521, 5, 236, 0, 0, 521, 530, 1, 0, 0, 0, 522, 523, 3, 118, 59, 0, 523, 525, 5, 220, 0, 0, 524, 526, 3, 72, 36, 0, 525, 524, 1, 0, 0, 0, 525, 526, 1, 0, 0, 0, 526, 527, 1, 0, 0, 0, 527, 528, 5, 236, 0, 0, 528, 530, 1, 0, 0, 0, 529, 482, 1, 0, 0, 0, 529, 483, 1, 0, 0, 0, 529, 498, 1, 0, 0, 0, 529, 510, 1, 0, 0, 0, 529, 522, 1, 0, 0, 0, 530, 71, 1, 0, 0, 0, 531, 536, 3, 74, 37, 0, 532, 533, 5, 206, 0, 0, 533, 535, 3, 74, 37, 0, 534, 532, 1, 0, 0, 0, 535, 538, 1, 0, 0, 0, 536, 534, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 537, 73, 1, 0, 0, 0, 538, 536, 1, 0, 0, 0, 539, 540, 6, 37, -1, 0, 540, 542, 5, 19, 0, 0, 541, 543, 3, 74, 37, 0, 542, 541, 1, 0, 0, 0, 542, 543, 1, 0, 0, 0, 543, 549, 1, 0, 0, 0, 544, 545, 5, 186, 0, 0, 545, 546, 3, 74, 37, 0, 546, 547, 5, 163, 0, 0, 547, 548, 3, 74, 37, 0, 548, 550, 1, 0, 0, 0, 549, 544, 1, 0, 0, 0, 550, 551, 1, 0, 0, 0, 551, 549, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 554, 5, 52, 0, 0, 554, 556, 3, 74, 37, 0, 555, 553, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 5, 53, 0, 0, 558, 663, 1, 0, 0, 0, 559, 560, 5, 20, 0, 0, 560, 561, 5, 220, 0, 0, 561, 562, 3, 74, 37, 0, 562, 563, 5, 10, 0, 0, 563, 564, 3, 70, 35, 0, 564, 565, 5, 236, 0, 0, 565, 663, 1, 0, 0, 0, 566, 567, 5, 36, 0, 0, 567, 663, 5, 200, 0, 0, 568, 569, 5, 86, 0, 0, 569, 570, 3, 74, 37, 0, 570, 571, 3, 110, 55, 0, 571, 663, 1, 0, 0, 0, 572, 573, 5, 155, 0, 0, 573, 574, 5, 220, 0, 0, 574, 575, 3, 74, 37, 0, 575, 576, 5, 68, 0, 0, 576, 579, 3, 74, 37, 0, 577, 578, 5, 65, 0, 0, 578, 580, 3, 74, 37, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 582, 5, 236, 0, 0, 582, 663, 1, 0, 0, 0, 583, 584, 5, 166, 0, 0, 584, 663, 5, 200, 0, 0, 585, 586, 5, 171, 0, 0, 586, 587, 5, 220, 0, 0, 587, 588, 7, 9, 0, 0, 588, 589, 5, 200, 0, 0, 589, 590, 5, 68, 0, 0, 590, 591, 3, 74, 37, 0, 591, 592, 5, 236, 0, 0, 592, 663, 1, 0, 0, 0, 593, 594, 3, 118, 59, 0, 594, 596, 5, 220, 0, 0, 595, 597, 3, 72, 36, 0, 596, 595, 1, 0, 0, 0, 596, 597, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 599, 5, 236, 0, 0, 599, 600, 1, 0, 0, 0, 600, 601, 5, 125, 0, 0, 601, 602, 5, 220, 0, 0, 602, 603, 3, 56, 28, 0, 603, 604, 5, 236, 0, 0, 604, 663, 1, 0, 0, 0, 605, 606, 3, 118, 59, 0, 606, 608, 5, 220, 0, 0, 607, 609, 3, 72, 36, 0, 608, 607, 1, 0, 0, 0, 608, 609, 1, 0, 0, 0, 609, 610, 1, 0, 0, 0, 610, 611, 5, 236, 0, 0, 611, 612, 1, 0, 0, 0, 612, 613, 5, 125, 0, 0, 613, 614, 3, 118, 59, 0, 614, 663, 1, 0, 0, 0, 615, 621, 3, 118, 59, 0, 616, 618, 5, 220, 0, 0, 617, 619, 3, 72, 36, 0, 618, 617, 1, 0, 0, 0, 618, 619, 1, 0, 0, 0, 619, 620, 1, 0, 0, 0, 620, 622, 5, 236, 0, 0, 621, 616, 1, 0, 0, 0, 621, 622, 1, 0, 0, 0, 622, 623, 1, 0, 0, 0, 623, 625, 5, 220, 0, 0, 624, 626, 5, 49, 0, 0, 625, 624, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 628, 1, 0, 0, 0, 627, 629, 3, 76, 38, 0, 628, 627, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 631, 5, 236, 0, 0, 631, 663, 1, 0, 0, 0, 632, 663, 3, 82, 41, 0, 633, 663, 3, 108, 54, 0, 634, 635, 5, 208, 0, 0, 635, 663, 3, 74, 37, 18, 636, 637, 5, 115, 0, 0, 637, 663, 3, 74, 37, 12, 638, 639, 3, 98, 49, 0, 639, 640, 5, 210, 0, 0, 640, 642, 1, 0, 0, 0, 641, 638, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 663, 5, 202, 0, 0, 644, 645, 5, 220, 0, 0, 645, 646, 3, 2, 1, 0, 646, 647, 5, 236, 0, 0, 647, 663, 1, 0, 0, 0, 648, 649, 5, 220, 0, 0, 649, 650, 3, 74, 37, 0, 650, 651, 5, 236, 0, 0, 651, 663, 1, 0, 0, 0, 652, 653, 5, 220, 0, 0, 653, 654, 3, 72, 36, 0, 654, 655, 5, 236, 0, 0, 655, 663, 1, 0, 0, 0, 656, 658, 5, 219, 0, 0, 657, 659, 3, 72, 36, 0, 658, 657, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 660, 1, 0, 0, 0, 660, 663, 5, 235, 0, 0, 661, 663, 3, 90, 45, 0, 662, 539, 1, 0, 0, 0, 662, 559, 1, 0, 0, 0, 662, 566, 1, 0, 0, 0, 662, 568, 1, 0, 0, 0, 662, 572, 1, 0, 0, 0, 662, 583, 1, 0, 0, 0, 662, 585, 1, 0, 0, 0, 662, 593, 1, 0, 0, 0, 662, 605, 1, 0, 0, 0, 662, 615, 1, 0, 0, 0, 662, 632, 1, 0, 0, 0, 662, 633, 1, 0, 0, 0, 662, 634, 1, 0, 0, 0, 662, 636, 1, 0, 0, 0, 662, 641, 1, 0, 0, 0, 662, 644, 1, 0, 0, 0, 662, 648, 1, 0, 0, 0, 662, 652, 1, 0, 0, 0, 662, 656, 1, 0, 0, 0, 662, 661, 1, 0, 0, 0, 663, 757, 1, 0, 0, 0, 664, 668, 10, 17, 0, 0, 665, 669, 5, 202, 0, 0, 666, 669, 5, 238, 0, 0, 667, 669, 5, 227, 0, 0, 668, 665, 1, 0, 0, 0, 668, 666, 1, 0, 0, 0, 668, 667, 1, 0, 0, 0, 669, 670, 1, 0, 0, 0, 670, 756, 3, 74, 37, 18, 671, 675, 10, 16, 0, 0, 672, 676, 5, 228, 0, 0, 673, 676, 5, 208, 0, 0, 674, 676, 5, 207, 0, 0, 675, 672, 1, 0, 0, 0, 675, 673, 1, 0, 0, 0, 675, 674, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 756, 3, 74, 37, 17, 678, 703, 10, 15, 0, 0, 679, 704, 5, 211, 0, 0, 680, 704, 5, 212, 0, 0, 681, 704, 5, 223, 0, 0, 682, 704, 5, 221, 0, 0, 683, 704, 5, 222, 0, 0, 684, 704, 5, 213, 0, 0, 685, 704, 5, 214, 0, 0, 686, 688, 5, 115, 0, 0, 687, 686, 1, 0, 0, 0, 687, 688, 1, 0, 0, 0, 688, 689, 1, 0, 0, 0, 689, 691, 5, 80, 0, 0, 690, 692, 5, 25, 0, 0, 691, 690, 1, 0, 0, 0, 691, 692, 1, 0, 0, 0, 692, 704, 1, 0, 0, 0, 693, 695, 5, 115, 0, 0, 694, 693, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 696, 1, 0, 0, 0, 696, 704, 7, 10, 0, 0, 697, 704, 5, 232, 0, 0, 698, 704, 5, 233, 0, 0, 699, 704, 5, 225, 0, 0, 700, 704, 5, 216, 0, 0, 701, 704, 5, 217, 0, 0, 702, 704, 5, 224, 0, 0, 703, 679, 1, 0, 0, 0, 703, 680, 1, 0, 0, 0, 703, 681, 1, 0, 0, 0, 703, 682, 1, 0, 0, 0, 703, 683, 1, 0, 0, 0, 703, 684, 1, 0, 0, 0, 703, 685, 1, 0, 0, 0, 703, 687, 1, 0, 0, 0, 703, 694, 1, 0, 0, 0, 703, 697, 1, 0, 0, 0, 703, 698, 1, 0, 0, 0, 703, 699, 1, 0, 0, 0, 703, 700, 1, 0, 0, 0, 703, 701, 1, 0, 0, 0, 703, 702, 1, 0, 0, 0, 704, 705, 1, 0, 0, 0, 705, 756, 3, 74, 37, 16, 706, 707, 10, 13, 0, 0, 707, 708, 5, 226, 0, 0, 708, 756, 3, 74, 37, 14, 709, 710, 10, 11, 0, 0, 710, 711, 5, 6, 0, 0, 711, 756, 3, 74, 37, 12, 712, 713, 10, 10, 0, 0, 713, 714, 5, 121, 0, 0, 714, 756, 3, 74, 37, 11, 715, 717, 10, 9, 0, 0, 716, 718, 5, 115, 0, 0, 717, 716, 1, 0, 0, 0, 717, 718, 1, 0, 0, 0, 718, 719, 1, 0, 0, 0, 719, 720, 5, 16, 0, 0, 720, 721, 3, 74, 37, 0, 721, 722, 5, 6, 0, 0, 722, 723, 3, 74, 37, 10, 723, 756, 1, 0, 0, 0, 724, 725, 10, 8, 0, 0, 725, 726, 5, 229, 0, 0, 726, 727, 3, 74, 37, 0, 727, 728, 5, 205, 0, 0, 728, 729, 3, 74, 37, 8, 729, 756, 1, 0, 0, 0, 730, 731, 10, 21, 0, 0, 731, 732, 5, 219, 0, 0, 732, 733, 3, 74, 37, 0, 733, 734, 5, 235, 0, 0, 734, 756, 1, 0, 0, 0, 735, 736, 10, 20, 0, 0, 736, 737, 5, 210, 0, 0, 737, 756, 5, 198, 0, 0, 738, 739, 10, 19, 0, 0, 739, 740, 5, 210, 0, 0, 740, 756, 3, 118, 59, 0, 741, 742, 10, 14, 0, 0, 742, 744, 5, 88, 0, 0, 743, 745, 5, 115, 0, 0, 744, 743, 1, 0, 0, 0, 744, 745, 1, 0, 0, 0, 745, 746, 1, 0, 0, 0, 746, 756, 5, 116, 0, 0, 747, 753, 10, 7, 0, 0, 748, 754, 3, 116, 58, 0, 749, 750, 5, 10, 0, 0, 750, 754, 3, 118, 59, 0, 751, 752, 5, 10, 0, 0, 752, 754, 5, 200, 0, 0, 753, 748, 1, 0, 0, 0, 753, 749, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 754, 756, 1, 0, 0, 0, 755, 664, 1, 0, 0, 0, 755, 671, 1, 0, 0, 0, 755, 678, 1, 0, 0, 0, 755, 706, 1, 0, 0, 0, 755, 709, 1, 0, 0, 0, 755, 712, 1, 0, 0, 0, 755, 715, 1, 0, 0, 0, 755, 724, 1, 0, 0, 0, 755, 730, 1, 0, 0, 0, 755, 735, 1, 0, 0, 0, 755, 738, 1, 0, 0, 0, 755, 741, 1, 0, 0, 0, 755, 747, 1, 0, 0, 0, 756, 759, 1, 0, 0, 0, 757, 755, 1, 0, 0, 0, 757, 758, 1, 0, 0, 0, 758, 75, 1, 0, 0, 0, 759, 757, 1, 0, 0, 0, 760, 765, 3, 78, 39, 0, 761, 762, 5, 206, 0, 0, 762, 764, 3, 78, 39, 0, 763, 761, 1, 0, 0, 0, 764, 767, 1, 0, 0, 0, 765, 763, 1, 0, 0, 0, 765, 766, 1, 0, 0, 0, 766, 77, 1, 0, 0, 0, 767, 765, 1, 0, 0, 0, 768, 771, 3, 80, 40, 0, 769, 771, 3, 74, 37, 0, 770, 768, 1, 0, 0, 0, 770, 769, 1, 0, 0, 0, 771, 79, 1, 0, 0, 0, 772, 773, 5, 220, 0, 0, 773, 778, 3, 118, 59, 0, 774, 775, 5, 206, 0, 0, 775, 777, 3, 118, 59, 0, 776, 774, 1, 0, 0, 0, 777, 780, 1, 0, 0, 0, 778, 776, 1, 0, 0, 0, 778, 779, 1, 0, 0, 0, 779, 781, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 781, 782, 5, 236, 0, 0, 782, 792, 1, 0, 0, 0, 783, 788, 3, 118, 59, 0, 784, 785, 5, 206, 0, 0, 785, 787, 3, 118, 59, 0, 786, 784, 1, 0, 0, 0, 787, 790, 1, 0, 0, 0, 788, 786, 1, 0, 0, 0, 788, 789, 1, 0, 0, 0, 789, 792, 1, 0, 0, 0, 790, 788, 1, 0, 0, 0, 791, 772, 1, 0, 0, 0, 791, 783, 1, 0, 0, 0, 792, 793, 1, 0, 0, 0, 793, 794, 5, 201, 0, 0, 794, 795, 3, 74, 37, 0, 795, 81, 1, 0, 0, 0, 796, 797, 5, 222, 0, 0, 797, 801, 3, 118, 59, 0, 798, 800, 3, 84, 42, 0, 799, 798, 1, 0, 0, 0, 800, 803, 1, 0, 0, 0, 801, 799, 1, 0, 0, 0, 801, 802, 1, 0, 0, 0, 802, 804, 1, 0, 0, 0, 803, 801, 1, 0, 0, 0, 804, 805, 5, 238, 0, 0, 805, 806, 5, 214, 0, 0, 806, 825, 1, 0, 0, 0, 807, 808, 5, 222, 0, 0, 808, 812, 3, 118, 59, 0, 809, 811, 3, 84, 42, 0, 810, 809, 1, 0, 0, 0, 811, 814, 1, 0, 0, 0, 812, 810, 1, 0, 0, 0, 812, 813, 1, 0, 0, 0, 813, 815, 1, 0, 0, 0, 814, 812, 1, 0, 0, 0, 815, 817, 5, 214, 0, 0, 816, 818, 3, 82, 41, 0, 817, 816, 1, 0, 0, 0, 817, 818, 1, 0, 0, 0, 818, 819, 1, 0, 0, 0, 819, 820, 5, 222, 0, 0, 820, 821, 5, 238, 0, 0, 821, 822, 3, 118, 59, 0, 822, 823, 5, 214, 0, 0, 823, 825, 1, 0, 0, 0, 824, 796, 1, 0, 0, 0, 824, 807, 1, 0, 0, 0, 825, 83, 1, 0, 0, 0, 826, 827, 3, 118, 59, 0, 827, 828, 5, 212, 0, 0, 828, 829, 5, 200, 0, 0, 829, 838, 1, 0, 0, 0, 830, 831, 3, 118, 59, 0, 831, 832, 5, 212, 0, 0, 832, 833, 5, 218, 0, 0, 833, 834, 3, 74, 37, 0, 834, 835, 5, 234, 0, 0, 835, 838, 1, 0, 0, 0, 836, 838, 3, 118, 59, 0, 837, 826, 1, 0, 0, 0, 837, 830, 1, 0, 0, 0, 837, 836, 1, 0, 0, 0, 838, 85, 1, 0, 0, 0, 839, 844, 3, 88, 44, 0, 840, 841, 5, 206, 0, 0, 841, 843, 3, 88, 44, 0, 842, 840, 1, 0, 0, 0, 843, 846, 1, 0, 0, 0, 844, 842, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 87, 1, 0, 0, 0, 846, 844, 1, 0, 0, 0, 847, 848, 3, 118, 59, 0, 848, 849, 5, 10, 0, 0, 849, 850, 5, 220, 0, 0, 850, 851, 3, 2, 1, 0, 851, 852, 5, 236, 0, 0, 852, 858, 1, 0, 0, 0, 853, 854, 3, 74, 37, 0, 854, 855, 5, 10, 0, 0, 855, 856, 3, 118, 59, 0, 856, 858, 1, 0, 0, 0, 857, 847, 1, 0, 0, 0, 857, 853, 1, 0, 0, 0, 858, 89, 1, 0, 0, 0, 859, 867, 3, 122, 61, 0, 860, 861, 3, 98, 49, 0, 861, 862, 5, 210, 0, 0, 862, 864, 1, 0, 0, 0, 863, 860, 1, 0, 0, 0, 863, 864, 1, 0, 0, 0, 864, 865, 1, 0, 0, 0, 865, 867, 3, 92, 46, 0, 866, 859, 1, 0, 0, 0, 866, 863, 1, 0, 0, 0, 867, 91, 1, 0, 0, 0, 868, 873, 3, 118, 59, 0, 869, 870, 5, 210, 0, 0, 870, 872, 3, 118, 59, 0, 871, 869, 1, 0, 0, 0, 872, 875, 1, 0, 0, 0, 873, 871, 1, 0, 0, 0, 873, 874, 1, 0, 0, 0, 874, 93, 1, 0, 0, 0, 875, 873, 1, 0, 0, 0, 876, 877, 6, 47, -1, 0, 877, 886, 3, 98, 49, 0, 878, 886, 3, 96, 48, 0, 879, 880, 5, 220, 0, 0, 880, 881, 3, 2, 1, 0, 881, 882, 5, 236, 0, 0, 882, 886, 1, 0, 0, 0, 883, 886, 3, 82, 41, 0, 884, 886, 3, 122, 61, 0, 885, 876, 1, 0, 0, 0, 885, 878, 1, 0, 0, 0, 885, 879, 1, 0, 0, 0, 885, 883, 1, 0, 0, 0, 885, 884, 1, 0, 0, 0, 886, 895, 1, 0, 0, 0, 887, 891, 10, 3, 0, 0, 888, 892, 3, 116, 58, 0, 889, 890, 5, 10, 0, 0, 890, 892, 3, 118, 59, 0, 891, 888, 1, 0, 0, 0, 891, 889, 1, 0, 0, 0, 892, 894, 1, 0, 0, 0, 893, 887, 1, 0, 0, 0, 894, 897, 1, 0, 0, 0, 895, 893, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 95, 1, 0, 0, 0, 897, 895, 1, 0, 0, 0, 898, 899, 3, 118, 59, 0, 899, 901, 5, 220, 0, 0, 900, 902, 3, 100, 50, 0, 901, 900, 1, 0, 0, 0, 901, 902, 1, 0, 0, 0, 902, 903, 1, 0, 0, 0, 903, 904, 5, 236, 0, 0, 904, 97, 1, 0, 0, 0, 905, 906, 3, 102, 51, 0, 906, 907, 5, 210, 0, 0, 907, 909, 1, 0, 0, 0, 908, 905, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 3, 118, 59, 0, 911, 99, 1, 0, 0, 0, 912, 917, 3, 74, 37, 0, 913, 914, 5, 206, 0, 0, 914, 916, 3, 74, 37, 0, 915, 913, 1, 0, 0, 0, 916, 919, 1, 0, 0, 0, 917, 915, 1, 0, 0, 0, 917, 918, 1, 0, 0, 0, 918, 101, 1, 0, 0, 0, 919, 917, 1, 0, 0, 0, 920, 921, 3, 118, 59, 0, 921, 103, 1, 0, 0, 0, 922, 931, 5, 196, 0, 0, 923, 924, 5, 210, 0, 0, 924, 931, 7, 11, 0, 0, 925, 926, 5, 198, 0, 0, 926, 928, 5, 210, 0, 0, 927, 929, 7, 11, 0, 0, 928, 927, 1, 0, 0, 0, 928, 929, 1, 0, 0, 0, 929, 931, 1, 0, 0, 0, 930, 922, 1, 0, 0, 0, 930, 923, 1, 0, 0, 0, 930, 925, 1, 0, 0, 0, 931, 105, 1, 0, 0, 0, 932, 934, 7, 12, 0, 0, 933, 932, 1, 0, 0, 0, 933, 934, 1, 0, 0, 0, 934, 941, 1, 0, 0, 0, 935, 942, 3, 104, 52, 0, 936, 942, 5, 197, 0, 0, 937, 942, 5, 198, 0, 0, 938, 942, 5, 199, 0, 0, 939, 942, 5, 82, 0, 0, 940, 942, 5, 113, 0, 0, 941, 935, 1, 0, 0, 0, 941, 936, 1, 0, 0, 0, 941, 937, 1, 0, 0, 0, 941, 938, 1, 0, 0, 0, 941, 939, 1, 0, 0, 0, 941, 940, 1, 0, 0, 0, 942, 107, 1, 0, 0, 0, 943, 947, 3, 106, 53, 0, 944, 947, 5, 200, 0, 0, 945, 947, 5, 116, 0, 0, 946, 943, 1, 0, 0, 0, 946, 944, 1, 0, 0, 0, 946, 945, 1, 0, 0, 0, 947, 109, 1, 0, 0, 0, 948, 949, 7, 13, 0, 0, 949, 111, 1, 0, 0, 0, 950, 951, 7, 14, 0, 0, 951, 113, 1, 0, 0, 0, 952, 953, 7, 15, 0, 0, 953, 115, 1, 0, 0, 0, 954, 957, 5, 195, 0, 0, 955, 957, 3, 114, 57, 0, 956, 954, 1, 0, 0, 0, 956, 955, 1, 0, 0, 0, 957, 117, 1, 0, 0, 0, 958, 962, 5, 195, 0, 0, 959, 962, 3, 110, 55, 0, 960, 962, 3, 112, 56, 0, 961, 958, 1, 0, 0, 0, 961, 959, 1, 0, 0, 0, 961, 960, 1, 0, 0, 0, 962, 119, 1, 0, 0, 0, 963, 964, 5, 200, 0, 0, 964, 965, 5, 212, 0, 0, 965, 966, 3, 106, 53, 0, 966, 121, 1, 0, 0, 0, 967, 968, 5, 218, 0, 0, 968, 969, 3, 118, 59, 0, 969, 970, 5, 234, 0, 0, 970, 123, 1, 0, 0, 0, 120, 127, 137, 146, 149, 153, 156, 160, 163, 166, 169, 172, 176, 180, 183, 186, 189, 193, 196, 205, 211, 232, 249, 266, 272, 278, 289, 291, 302, 305, 311, 319, 325, 327, 331, 336, 339, 342, 346, 350, 353, 355, 358, 362, 366, 369, 371, 373, 378, 389, 395, 402, 407, 411, 415, 421, 423, 430, 438, 441, 444, 463, 477, 493, 505, 517, 525, 529, 536, 542, 551, 555, 579, 596, 608, 618, 621, 625, 628, 641, 658, 662, 668, 675, 687, 691, 694, 703, 717, 744, 753, 755, 757, 765, 770, 778, 788, 791, 801, 812, 817, 824, 837, 844, 857, 863, 866, 873, 885, 891, 895, 901, 908, 917, 928, 930, 933, 941, 946, 956, 961]
\ No newline at end of file
diff --git a/hogql_parser/HogQLParserBaseVisitor.h b/hogql_parser/HogQLParserBaseVisitor.h
index 00e3cd4e391ad..9d8132683af38 100644
--- a/hogql_parser/HogQLParserBaseVisitor.h
+++ b/hogql_parser/HogQLParserBaseVisitor.h
@@ -211,10 +211,6 @@ class HogQLParserBaseVisitor : public HogQLParserVisitor {
return visitChildren(ctx);
}
- virtual std::any visitColumnExprExtract(HogQLParser::ColumnExprExtractContext *ctx) override {
- return visitChildren(ctx);
- }
-
virtual std::any visitColumnExprNegate(HogQLParser::ColumnExprNegateContext *ctx) override {
return visitChildren(ctx);
}
diff --git a/hogql_parser/HogQLParserVisitor.h b/hogql_parser/HogQLParserVisitor.h
index 8355b14ae1ea4..72a7eb7aaddc6 100644
--- a/hogql_parser/HogQLParserVisitor.h
+++ b/hogql_parser/HogQLParserVisitor.h
@@ -117,8 +117,6 @@ class HogQLParserVisitor : public antlr4::tree::AbstractParseTreeVisitor {
virtual std::any visitColumnExprAlias(HogQLParser::ColumnExprAliasContext *context) = 0;
- virtual std::any visitColumnExprExtract(HogQLParser::ColumnExprExtractContext *context) = 0;
-
virtual std::any visitColumnExprNegate(HogQLParser::ColumnExprNegateContext *context) = 0;
virtual std::any visitColumnExprSubquery(HogQLParser::ColumnExprSubqueryContext *context) = 0;
diff --git a/hogql_parser/parser.cpp b/hogql_parser/parser.cpp
index 1c16cbe1280c1..1ee0cc910f8f6 100644
--- a/hogql_parser/parser.cpp
+++ b/hogql_parser/parser.cpp
@@ -1082,8 +1082,6 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
RETURN_NEW_AST_NODE("Alias", "{s:N,s:s#}", "expr", expr, "alias", alias.data(), alias.size());
}
- VISIT_UNSUPPORTED(ColumnExprExtract)
-
VISIT(ColumnExprNegate) {
PyObject* left = build_ast_node("Constant", "{s:i}", "value", 0);
if (!left) throw PyInternalException();
diff --git a/hogql_parser/setup.py b/hogql_parser/setup.py
index 6a95b379acd90..25b732863871c 100644
--- a/hogql_parser/setup.py
+++ b/hogql_parser/setup.py
@@ -32,7 +32,7 @@
setup(
name="hogql_parser",
- version="1.0.3",
+ version="1.0.4",
url="https://github.com/PostHog/posthog/tree/master/hogql_parser",
author="PostHog Inc.",
author_email="hey@posthog.com",
diff --git a/latest_migrations.manifest b/latest_migrations.manifest
index f88359530eb78..970d033f08d66 100644
--- a/latest_migrations.manifest
+++ b/latest_migrations.manifest
@@ -5,7 +5,7 @@ contenttypes: 0002_remove_content_type_name
ee: 0016_rolemembership_organization_member
otp_static: 0002_throttling
otp_totp: 0002_auto_20190420_0723
-posthog: 0398_alter_externaldatasource_source_type
+posthog: 0399_batchexportrun_records_total_count
sessions: 0001_initial
social_django: 0010_uid_db_index
two_factor: 0007_auto_20201201_1019
diff --git a/mypy-baseline.txt b/mypy-baseline.txt
index b8d2d1c94da64..b0ce8847d444c 100644
--- a/mypy-baseline.txt
+++ b/mypy-baseline.txt
@@ -133,11 +133,6 @@ posthog/hogql_queries/utils/query_date_range.py:0: error: Incompatible default f
posthog/hogql_queries/utils/query_date_range.py:0: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
posthog/hogql_queries/utils/query_date_range.py:0: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
posthog/hogql_queries/utils/query_date_range.py:0: error: Item "None" of "IntervalType | None" has no attribute "name" [union-attr]
-posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Argument 1 to "filter" has incompatible type "Callable[[Any], bool]"; expected "Callable[[Any], TypeGuard[bool]]" [arg-type]
-posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Argument 1 to "filter" has incompatible type "Callable[[Any], bool]"; expected "Callable[[Any], TypeGuard[Any]]" [arg-type]
-posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Argument 2 to "filter" has incompatible type "Any | None"; expected "Iterable[Any]" [arg-type]
-posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Argument 2 to "map" has incompatible type "Any | None"; expected "Iterable[Any]" [arg-type]
-posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Argument 2 to "map" has incompatible type "Any | None"; expected "Iterable[Any]" [arg-type]
posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Dict entry 4 has incompatible type "str": "Literal[0, 1, 2, 3, 4] | None"; expected "str": "str | None" [dict-item]
posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Item "None" of "Any | None" has no attribute "__iter__" (not iterable) [union-attr]
posthog/hogql_queries/legacy_compatibility/filter_to_query.py:0: error: Argument 1 to "float" has incompatible type "Any | None"; expected "str | Buffer | SupportsFloat | SupportsIndex" [arg-type]
@@ -758,12 +753,8 @@ posthog/api/dashboards/dashboard_templates.py:0: error: Metaclass conflict: the
ee/api/feature_flag_role_access.py:0: error: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases [misc]
posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Unused "type: ignore" comment [unused-ignore]
posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Unused "type: ignore" comment [unused-ignore]
-posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Item "None" of "BatchExportRun | None" has no attribute "data_interval_start" [union-attr]
-posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Item "None" of "BatchExportRun | None" has no attribute "data_interval_end" [union-attr]
posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Unused "type: ignore" comment [unused-ignore]
-posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Item "None" of "BatchExportRun | None" has no attribute "status" [union-attr]
posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Unused "type: ignore" comment [unused-ignore]
-posthog/temporal/tests/batch_exports/test_run_updates.py:0: error: Item "None" of "BatchExportRun | None" has no attribute "status" [union-attr]
posthog/temporal/tests/batch_exports/test_batch_exports.py:0: error: TypedDict key must be a string literal; expected one of ("_timestamp", "created_at", "distinct_id", "elements", "elements_chain", ...) [literal-required]
posthog/queries/app_metrics/test/test_app_metrics.py:0: error: Argument 3 to "AppMetricsErrorDetailsQuery" has incompatible type "AppMetricsRequestSerializer"; expected "AppMetricsErrorsRequestSerializer" [arg-type]
posthog/queries/app_metrics/test/test_app_metrics.py:0: error: Argument 3 to "AppMetricsErrorDetailsQuery" has incompatible type "AppMetricsRequestSerializer"; expected "AppMetricsErrorsRequestSerializer" [arg-type]
diff --git a/plugin-server/src/config/config.ts b/plugin-server/src/config/config.ts
index def72eea474bb..a6ee4e91a9b15 100644
--- a/plugin-server/src/config/config.ts
+++ b/plugin-server/src/config/config.ts
@@ -134,6 +134,7 @@ export function getDefaultConfig(): PluginsServerConfig {
RUSTY_HOOK_FOR_TEAMS: '',
RUSTY_HOOK_ROLLOUT_PERCENTAGE: 0,
RUSTY_HOOK_URL: '',
+ CAPTURE_CONFIG_REDIS_HOST: null,
STARTUP_PROFILE_DURATION_SECONDS: 300, // 5 minutes
STARTUP_PROFILE_CPU: false,
diff --git a/plugin-server/src/main/ingestion-queues/session-recording/services/overflow-detection.ts b/plugin-server/src/main/ingestion-queues/session-recording/services/overflow-detection.ts
deleted file mode 100644
index 8b478b781bc95..0000000000000
--- a/plugin-server/src/main/ingestion-queues/session-recording/services/overflow-detection.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import LRUCache from 'lru-cache'
-import { Gauge } from 'prom-client'
-
-import { Limiter } from '../../../../utils/token-bucket'
-
-export enum OverflowState {
- Okay,
- Triggered, // Recently triggered the overflow detection
- Cooldown, // Already triggered the overflow detection earlier than cooldownSeconds
-}
-
-export const overflowTriggeredGauge = new Gauge({
- name: 'overflow_detection_triggered_total',
- help: 'Number of entities that triggered overflow detection.',
-})
-
-/**
- * OverflowDetection handles consumer-side detection of hot partitions by
- * accounting for data volumes per entity (a session_id, a distinct_id...).
- *
- * The first time that the observed spike crosses the thresholds set via burstCapacity
- * and replenishRate, observe returns Triggered. Subsequent calls will return Cooldown
- * until cooldownSeconds is reached.
- */
-export class OverflowDetection {
- private limiter: Limiter
- private triggered: LRUCache
-
- constructor(burstCapacity: number, replenishRate: number, cooldownSeconds: number) {
- this.limiter = new Limiter(burstCapacity, replenishRate)
- this.triggered = new LRUCache({ max: 1_000_000, maxAge: cooldownSeconds * 1000 })
- }
-
- public observe(key: string, quantity: number, now?: number): OverflowState {
- if (this.triggered.has(key)) {
- return OverflowState.Cooldown
- }
- if (this.limiter.consume(key, quantity, now)) {
- return OverflowState.Okay
- }
- this.triggered.set(key, true)
- overflowTriggeredGauge.inc(1)
- return OverflowState.Triggered
- }
-}
diff --git a/plugin-server/src/main/ingestion-queues/session-recording/services/overflow-manager.ts b/plugin-server/src/main/ingestion-queues/session-recording/services/overflow-manager.ts
new file mode 100644
index 0000000000000..f7a10a6a63593
--- /dev/null
+++ b/plugin-server/src/main/ingestion-queues/session-recording/services/overflow-manager.ts
@@ -0,0 +1,60 @@
+import { Redis } from 'ioredis'
+import LRUCache from 'lru-cache'
+import { Gauge } from 'prom-client'
+
+import { Limiter } from '../../../../utils/token-bucket'
+
+export const overflowTriggeredGauge = new Gauge({
+ name: 'overflow_detection_triggered_total',
+ help: 'Number of entities that triggered overflow detection.',
+})
+
+/**
+ * OverflowManager handles consumer-side detection of hot partitions by
+ * accounting for data volumes per entity (a session_id, a distinct_id...)
+ * and maintains the Redis set that capture reads to route messages.
+ *
+ * The first time that the observed spike crosses the thresholds set via burstCapacity
+ * and replenishRate, the key is added to Redis and the metrics incremented, subsequent
+ * calls will return early until cooldownSeconds is reached.
+ */
+export class OverflowManager {
+ private limiter: Limiter
+ private triggered: LRUCache
+
+ constructor(
+ burstCapacity: number,
+ replenishRate: number,
+ private cooldownSeconds: number,
+ private redisKey: string,
+ private redisClient: Redis
+ ) {
+ this.limiter = new Limiter(burstCapacity, replenishRate)
+ this.triggered = new LRUCache({ max: 1_000_000, maxAge: cooldownSeconds * 1000 })
+ }
+
+ public async observe(key: string, quantity: number, now?: number): Promise {
+ if (this.triggered.has(key)) {
+ // Cooldown state, return early
+ return
+ }
+ if (this.limiter.consume(key, quantity, now)) {
+ // Not triggering overflow, return early
+ return
+ }
+ this.triggered.set(key, true)
+ overflowTriggeredGauge.inc(1)
+
+ // Set the `NX` arguments to not update existing entries: if a session already triggered overflow,
+ // it's cooldown will not be extended after we restart the consumers.
+ // The zset value is a timestamp in seconds.
+ const expiration = (now ?? Date.now()) / 1000 + this.cooldownSeconds
+ await this.redisClient.zadd(this.redisKey, 'NX', expiration, key)
+
+ // Cleanup old entries with values expired more than one hour ago.
+ // We run the cleanup here because we assume this will only run a dozen times per day per region.
+ // If this code path becomes too hot, it should move to a singleton loop.
+ const expired = (now ?? Date.now()) / 1000 - 3600
+ await this.redisClient.zremrangebyscore(this.redisKey, 0, expired)
+ }
+}
diff --git a/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer.ts b/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer.ts
index 491044652d80f..2e84d7826c002 100644
--- a/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer.ts
+++ b/plugin-server/src/main/ingestion-queues/session-recording/session-recordings-consumer.ts
@@ -1,5 +1,6 @@
import { captureException } from '@sentry/node'
import crypto from 'crypto'
+import { Redis } from 'ioredis'
import { mkdirSync, rmSync } from 'node:fs'
import { CODES, features, KafkaConsumer, librdkafkaVersion, Message, TopicPartition } from 'node-rdkafka'
import { Counter, Gauge, Histogram } from 'prom-client'
@@ -20,7 +21,7 @@ import { addSentryBreadcrumbsEventListeners } from '../kafka-metrics'
import { eventDroppedCounter } from '../metrics'
import { ConsoleLogsIngester } from './services/console-logs-ingester'
import { OffsetHighWaterMarker } from './services/offset-high-water-marker'
-import { OverflowDetection } from './services/overflow-detection'
+import { OverflowManager } from './services/overflow-manager'
import { RealtimeManager } from './services/realtime-manager'
import { ReplayEventsIngester } from './services/replay-events-ingester'
import { BUCKETS_KB_WRITTEN, SessionManager } from './services/session-manager'
@@ -42,6 +43,7 @@ require('@sentry/tracing')
const KAFKA_CONSUMER_GROUP_ID = 'session-recordings-blob'
const KAFKA_CONSUMER_SESSION_TIMEOUT_MS = 30000
const SHUTDOWN_FLUSH_TIMEOUT_MS = 30000
+const CAPTURE_OVERFLOW_REDIS_KEY = '@posthog/capture-overflow/replay'
const gaugeSessionsHandled = new Gauge({
name: 'recording_blob_ingestion_session_manager_count',
@@ -129,7 +131,7 @@ export class SessionRecordingIngester {
sessionHighWaterMarker: OffsetHighWaterMarker
persistentHighWaterMarker: OffsetHighWaterMarker
realtimeManager: RealtimeManager
- overflowDetection?: OverflowDetection
+ overflowDetection?: OverflowManager
replayEventsIngester?: ReplayEventsIngester
consoleLogsIngester?: ConsoleLogsIngester
batchConsumer?: BatchConsumer
@@ -149,7 +151,8 @@ export class SessionRecordingIngester {
constructor(
private globalServerConfig: PluginsServerConfig,
private postgres: PostgresRouter,
- private objectStorage: ObjectStorage
+ private objectStorage: ObjectStorage,
+ captureRedis: Redis | undefined
) {
this.debugPartition = globalServerConfig.SESSION_RECORDING_DEBUG_PARTITION
? parseInt(globalServerConfig.SESSION_RECORDING_DEBUG_PARTITION)
@@ -162,11 +165,13 @@ export class SessionRecordingIngester {
this.realtimeManager = new RealtimeManager(this.redisPool, this.config)
- if (globalServerConfig.SESSION_RECORDING_OVERFLOW_ENABLED) {
- this.overflowDetection = new OverflowDetection(
+ if (globalServerConfig.SESSION_RECORDING_OVERFLOW_ENABLED && captureRedis) {
+ this.overflowDetection = new OverflowManager(
globalServerConfig.SESSION_RECORDING_OVERFLOW_BUCKET_CAPACITY,
globalServerConfig.SESSION_RECORDING_OVERFLOW_BUCKET_REPLENISH_RATE,
- 24 * 3600 // One day
+ 24 * 3600, // One day,
+ CAPTURE_OVERFLOW_REDIS_KEY,
+ captureRedis
)
}
@@ -250,6 +255,8 @@ export class SessionRecordingIngester {
const { team_id, session_id } = event
const key = `${team_id}-${session_id}`
+ // TODO: use this for session key too if it's safe to do so
+ const overflowKey = `${team_id}:${session_id}`
const { partition, highOffset } = event.metadata
if (this.debugPartition === partition) {
@@ -285,9 +292,6 @@ export class SessionRecordingIngester {
return
}
- // TODO: update Redis if this triggers
- this.overflowDetection?.observe(key, event.metadata.rawSize, event.metadata.timestamp)
-
if (!this.sessions[key]) {
const { partition, topic } = event.metadata
@@ -304,7 +308,10 @@ export class SessionRecordingIngester {
)
}
- await this.sessions[key]?.add(event)
+ await Promise.allSettled([
+ this.sessions[key]?.add(event),
+ this.overflowDetection?.observe(overflowKey, event.metadata.rawSize, event.metadata.timestamp),
+ ])
}
public async handleEachBatch(messages: Message[], heartbeat: () => void): Promise {
diff --git a/plugin-server/src/main/pluginsServer.ts b/plugin-server/src/main/pluginsServer.ts
index f3a4362db6f83..8c910e1857b06 100644
--- a/plugin-server/src/main/pluginsServer.ts
+++ b/plugin-server/src/main/pluginsServer.ts
@@ -18,7 +18,7 @@ import { cancelAllScheduledJobs } from '../utils/node-schedule'
import { PeriodicTask } from '../utils/periodic-task'
import { PubSub } from '../utils/pubsub'
import { status } from '../utils/status'
-import { delay } from '../utils/utils'
+import { createRedisClient, delay } from '../utils/utils'
import { AppMetrics } from '../worker/ingestion/app-metrics'
import { OrganizationManager } from '../worker/ingestion/organization-manager'
import { DeferredPersonOverrideWorker, FlatPersonOverrideWriter } from '../worker/ingestion/person-state'
@@ -243,6 +243,12 @@ export async function startPluginsServer(
// be super lightweight and ideally not do any IO.
const healthChecks: { [service: string]: () => Promise | boolean } = {}
+ // Creating a dedicated single-connection redis client to this Redis, as it's not relevant for hobby
+ // and cloud deploys don't have concurrent uses. We should abstract multi-Redis into a router util.
+ const captureRedis = serverConfig.CAPTURE_CONFIG_REDIS_HOST
+ ? await createRedisClient(serverConfig.CAPTURE_CONFIG_REDIS_HOST)
+ : undefined
+
try {
// Based on the mode the plugin server was started, we start a number of
// different services. Mostly this is reasonably obvious from the name.
@@ -440,7 +446,7 @@ export async function startPluginsServer(
throw new Error("Can't start session recording blob ingestion without object storage")
}
// NOTE: We intentionally pass in the original serverConfig as the ingester uses both kafkas
- const ingester = new SessionRecordingIngester(serverConfig, postgres, s3)
+ const ingester = new SessionRecordingIngester(serverConfig, postgres, s3, captureRedis)
await ingester.start()
const batchConsumer = ingester.batchConsumer
diff --git a/plugin-server/src/types.ts b/plugin-server/src/types.ts
index d70238307eaac..db9350490bd70 100644
--- a/plugin-server/src/types.ts
+++ b/plugin-server/src/types.ts
@@ -207,6 +207,7 @@ export interface PluginsServerConfig {
RUSTY_HOOK_URL: string
SKIP_UPDATE_EVENT_AND_PROPERTIES_STEP: boolean
PIPELINE_STEP_STALLED_LOG_TIMEOUT: number
+ CAPTURE_CONFIG_REDIS_HOST: string | null // Redis cluster to use to coordinate with capture (overflow, routing)
// dump profiles to disk, covering the first N seconds of runtime
STARTUP_PROFILE_DURATION_SECONDS: number
diff --git a/plugin-server/src/utils/utils.ts b/plugin-server/src/utils/utils.ts
index 87fbe9e9e0640..a49a5161b4b3a 100644
--- a/plugin-server/src/utils/utils.ts
+++ b/plugin-server/src/utils/utils.ts
@@ -339,8 +339,12 @@ export async function createRedis(serverConfig: PluginsServerConfig): Promise {
+ const redis = new Redis(url, {
+ ...options,
maxRetriesPerRequest: -1,
})
let errorCounter = 0
diff --git a/plugin-server/tests/main/ingestion-queues/session-recording/services/overflow-manager.test.ts b/plugin-server/tests/main/ingestion-queues/session-recording/services/overflow-manager.test.ts
new file mode 100644
index 0000000000000..875a7157dcf12
--- /dev/null
+++ b/plugin-server/tests/main/ingestion-queues/session-recording/services/overflow-manager.test.ts
@@ -0,0 +1,104 @@
+import { Redis } from 'ioredis'
+
+import { OverflowManager } from '../../../../../src/main/ingestion-queues/session-recording/services/overflow-manager'
+import { Hub } from '../../../../../src/types'
+import { createHub } from '../../../../../src/utils/db/hub'
+
+jest.mock('../../../../../src/utils/status')
+jest.mock('../../../../../src/kafka/producer')
+
+const CAPTURE_OVERFLOW_REDIS_KEY = '@posthog/capture-overflow/replay'
+
+describe('overflow manager', () => {
+ let hub: Hub
+ let closeHub: () => Promise
+ let redis: Redis
+ let overflowManager: OverflowManager
+
+ beforeAll(async () => {
+ ;[hub, closeHub] = await createHub()
+ redis = await hub.redisPool.acquire()
+ })
+ beforeEach(async () => {
+ await redis.del(CAPTURE_OVERFLOW_REDIS_KEY)
+ overflowManager = new OverflowManager(10, 1, 3600, CAPTURE_OVERFLOW_REDIS_KEY, redis)
+ })
+
+ afterAll(async () => {
+ await redis.flushdb()
+ await hub.redisPool.release(redis)
+ await closeHub?.()
+ })
+
+ test('it does not trigger if several keys are under threshold', async () => {
+ await overflowManager.observe('key1', 8)
+ await overflowManager.observe('key2', 8)
+ await overflowManager.observe('key3', 8)
+
+ expect(await redis.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(0)
+ })
+
+ test('it triggers for hot keys', async () => {
+ await overflowManager.observe('key1', 4)
+ await overflowManager.observe('key1', 4)
+ await overflowManager.observe('key2', 8)
+ expect(await redis.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(0)
+
+ await overflowManager.observe('key1', 4)
+ expect(await redis.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1)).toEqual(['key1'])
+ })
+
+ test('it does not triggers twice when cooling down', async () => {
+ await overflowManager.observe('key1', 11)
+ expect(await redis.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1)).toEqual(['key1'])
+
+ // Delete the key to confirm that OverflowManager is in cooldown for key1 and does not re-create it
+ await redis.del(CAPTURE_OVERFLOW_REDIS_KEY)
+ await overflowManager.observe('key1', 11)
+ expect(await redis.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(0)
+
+ // But it triggers for key2
+ await overflowManager.observe('key2', 11)
+ expect(await redis.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1)).toEqual(['key2'])
+ })
+
+ test('it does not update existing values', async () => {
+ const timestamp = 1711280335000
+ const oldTimestamp = timestamp / 1000 - 200
+ await redis.zadd(CAPTURE_OVERFLOW_REDIS_KEY, oldTimestamp, 'key1')
+
+ await overflowManager.observe('key1', 11, timestamp)
+ expect(await redis.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1, 'WITHSCORES')).toEqual([
+ 'key1',
+ oldTimestamp.toString(),
+ ])
+ })
+
+ test('it set the expected expiration on new values', async () => {
+ const timestamp = 1711280335000
+ const oldTimestamp = timestamp / 1000 - 200
+ await redis.zadd(CAPTURE_OVERFLOW_REDIS_KEY, oldTimestamp, 'key1')
+
+ const expectedExpiration = timestamp / 1000 + 3600
+ await overflowManager.observe('key2', 11, timestamp)
+ expect(await redis.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1, 'WITHSCORES')).toEqual([
+ 'key1',
+ oldTimestamp.toString(),
+ 'key2',
+ expectedExpiration.toString(),
+ ])
+ })
+
+ test('it removes old values when adding one', async () => {
+ const timestamp = 1711280335000
+ const oldTimestamp = timestamp / 1000 - 8000
+ await redis.zadd(CAPTURE_OVERFLOW_REDIS_KEY, oldTimestamp, 'key1')
+
+ const expectedExpiration = timestamp / 1000 + 3600
+ await overflowManager.observe('key2', 11, timestamp)
+ expect(await redis.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1, 'WITHSCORES')).toEqual([
+ 'key2',
+ expectedExpiration.toString(),
+ ])
+ })
+})
diff --git a/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer.test.ts b/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer.test.ts
index 18dc39c7e5b2e..730fe28f481ac 100644
--- a/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer.test.ts
+++ b/plugin-server/tests/main/ingestion-queues/session-recording/session-recordings-consumer.test.ts
@@ -1,6 +1,7 @@
import { randomUUID } from 'crypto'
+import { Redis } from 'ioredis'
import { mkdirSync, readdirSync, rmSync } from 'node:fs'
-import { TopicPartition, TopicPartitionOffset } from 'node-rdkafka'
+import { Message, TopicPartition, TopicPartitionOffset } from 'node-rdkafka'
import path from 'path'
import { waitForExpect } from '../../../../functional_tests/expectations'
@@ -12,10 +13,14 @@ import { getFirstTeam, resetTestDatabase } from '../../../helpers/sql'
import { createIncomingRecordingMessage, createKafkaMessage, createTP } from './fixtures'
const SESSION_RECORDING_REDIS_PREFIX = '@posthog-tests/replay/'
+const CAPTURE_OVERFLOW_REDIS_KEY = '@posthog/capture-overflow/replay'
const config: PluginsServerConfig = {
...defaultConfig,
SESSION_RECORDING_PARTITION_REVOKE_OPTIMIZATION: true,
+ SESSION_RECORDING_OVERFLOW_ENABLED: true,
+ SESSION_RECORDING_OVERFLOW_BUCKET_CAPACITY: 1_000_000, // 1MB burst
+ SESSION_RECORDING_OVERFLOW_BUCKET_REPLENISH_RATE: 1_000, // 1kB/s replenish
SESSION_RECORDING_REDIS_PREFIX,
}
@@ -68,6 +73,7 @@ describe('ingester', () => {
let teamToken = ''
let mockOffsets: Record = {}
let mockCommittedOffsets: Record = {}
+ let redisConn: Redis
beforeAll(async () => {
mkdirSync(path.join(config.SESSION_RECORDING_LOCAL_DIRECTORY, 'session-buffer-files'), { recursive: true })
@@ -103,9 +109,12 @@ describe('ingester', () => {
;[hub, closeHub] = await createHub()
team = await getFirstTeam(hub)
teamToken = team.api_token
+ redisConn = await hub.redisPool.acquire(0)
+ await redisConn.del(CAPTURE_OVERFLOW_REDIS_KEY)
+
await deleteKeysWithPrefix(hub)
- ingester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage)
+ ingester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage, redisConn)
await ingester.start()
mockConsumer.assignments.mockImplementation(() => [createTP(0), createTP(1)])
@@ -113,6 +122,8 @@ describe('ingester', () => {
afterEach(async () => {
jest.setTimeout(10000)
+ await redisConn.del(CAPTURE_OVERFLOW_REDIS_KEY)
+ await hub.redisPool.release(redisConn)
await deleteKeysWithPrefix(hub)
await ingester.stop()
await closeHub()
@@ -128,7 +139,7 @@ describe('ingester', () => {
await ingester.commitAllOffsets(ingester.partitionMetrics, Object.values(ingester.sessions))
}
- const createMessage = (session_id: string, partition = 1) => {
+ const createMessage = (session_id: string, partition = 1, messageOverrides: Partial = {}) => {
mockOffsets[partition] = mockOffsets[partition] ?? 0
mockOffsets[partition]++
@@ -137,6 +148,7 @@ describe('ingester', () => {
{
partition,
offset: mockOffsets[partition],
+ ...messageOverrides,
},
{
$session_id: session_id,
@@ -150,7 +162,7 @@ describe('ingester', () => {
KAFKA_HOSTS: 'localhost:9092',
} satisfies Partial as PluginsServerConfig
- const ingester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage)
+ const ingester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage, undefined)
expect(ingester['debugPartition']).toEqual(103)
})
@@ -159,7 +171,7 @@ describe('ingester', () => {
KAFKA_HOSTS: 'localhost:9092',
} satisfies Partial as PluginsServerConfig
- const ingester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage)
+ const ingester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage, undefined)
expect(ingester['debugPartition']).toBeUndefined()
})
@@ -424,7 +436,7 @@ describe('ingester', () => {
jest.setTimeout(5000) // Increased to cover lock delay
beforeEach(async () => {
- otherIngester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage)
+ otherIngester = new SessionRecordingIngester(config, hub.postgres, hub.objectStorage, undefined)
await otherIngester.start()
})
@@ -561,6 +573,62 @@ describe('ingester', () => {
})
})
+ describe('overflow detection', () => {
+ const ingestBurst = async (count: number, size_bytes: number, timestamp_delta: number) => {
+ const first_timestamp = Date.now() - 2 * timestamp_delta * count
+
+ // Because messages from the same batch are reduced into a single one, we call handleEachBatch
+ // with individual messages to have better control on the message timestamp
+ for (let n = 0; n < count; n++) {
+ const message = createMessage('sid1', 1, {
+ size: size_bytes,
+ timestamp: first_timestamp + n * timestamp_delta,
+ })
+ await ingester.handleEachBatch([message], noop)
+ }
+ }
+
+ it('should not trigger overflow if under threshold', async () => {
+ await ingestBurst(10, 100, 10)
+ expect(await redisConn.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(0)
+ })
+
+ it('should trigger overflow during bursts', async () => {
+ const expected_expiration = Math.floor(Date.now() / 1000) + 24 * 3600 // 24 hours from now, in seconds
+ await ingestBurst(10, 150_000, 10)
+
+ expect(await redisConn.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(1)
+ expect(
+ await redisConn.zrangebyscore(
+ CAPTURE_OVERFLOW_REDIS_KEY,
+ expected_expiration - 10,
+ expected_expiration + 10
+ )
+ ).toEqual([`${team.id}:sid1`])
+ })
+
+ it('should not trigger overflow during backfills', async () => {
+ await ingestBurst(10, 150_000, 150_000)
+ expect(await redisConn.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(0)
+ })
+
+ it('should cleanup older entries when triggering', async () => {
+ await redisConn.zadd(CAPTURE_OVERFLOW_REDIS_KEY, 'NX', Date.now() / 1000 - 7000, 'expired:session')
+ await redisConn.zadd(CAPTURE_OVERFLOW_REDIS_KEY, 'NX', Date.now() / 1000 - 1000, 'not_expired:session')
+ expect(await redisConn.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1)).toEqual([
+ 'expired:session',
+ 'not_expired:session',
+ ])
+
+ await ingestBurst(10, 150_000, 10)
+ expect(await redisConn.exists(CAPTURE_OVERFLOW_REDIS_KEY)).toEqual(1)
+ expect(await redisConn.zrange(CAPTURE_OVERFLOW_REDIS_KEY, 0, -1)).toEqual([
+ 'not_expired:session',
+ `${team.id}:sid1`,
+ ])
+ })
+ })
+
describe('lag reporting', () => {
it('should return the latest offsets', async () => {
mockConsumer.queryWatermarkOffsets.mockImplementation((_topic, partition, _timeout, cb) => {
diff --git a/posthog/api/element.py b/posthog/api/element.py
index 1ade5baa0977b..d7b721dee8195 100644
--- a/posthog/api/element.py
+++ b/posthog/api/element.py
@@ -130,9 +130,14 @@ def stats(self, request: request.Request, **kwargs) -> response.Response:
def _events_filter(self, request) -> Tuple[Literal["$autocapture", "$rageclick"], ...]:
event_to_filter: Tuple[Literal["$autocapture", "$rageclick"], ...] = ()
+ # when multiple includes are sent expects them as separate parameters
+ # e.g. ?include=a&include=b
events_to_include = request.query_params.getlist("include", [])
+
if not events_to_include:
+ # sensible default when not provided
event_to_filter += ("$autocapture",)
+ event_to_filter += ("$rageclick",)
else:
if "$rageclick" in events_to_include:
events_to_include.remove("$rageclick")
diff --git a/posthog/api/signup.py b/posthog/api/signup.py
index 13f171b906485..b8c3db86c3341 100644
--- a/posthog/api/signup.py
+++ b/posthog/api/signup.py
@@ -51,6 +51,7 @@ def get_redirect_url(uuid: str, is_email_verified: bool) -> str:
class SignupSerializer(serializers.Serializer):
first_name: serializers.Field = serializers.CharField(max_length=128)
+ last_name: serializers.Field = serializers.CharField(max_length=128, required=False, allow_blank=True)
email: serializers.Field = serializers.EmailField()
password: serializers.Field = serializers.CharField(allow_null=True, required=True)
organization_name: serializers.Field = serializers.CharField(max_length=128, required=False, allow_blank=True)
@@ -92,7 +93,7 @@ def create(self, validated_data, **kwargs):
is_instance_first_user: bool = not User.objects.exists()
- organization_name = validated_data.pop("organization_name", validated_data["first_name"])
+ organization_name = validated_data.pop("organization_name", f"{validated_data['first_name']}'s Organization")
role_at_organization = validated_data.pop("role_at_organization", "")
referral_source = validated_data.pop("referral_source", "")
diff --git a/posthog/api/test/__snapshots__/test_feature_flag.ambr b/posthog/api/test/__snapshots__/test_feature_flag.ambr
index f38f19faf3f04..a70e9efd7a670 100644
--- a/posthog/api/test/__snapshots__/test_feature_flag.ambr
+++ b/posthog/api/test/__snapshots__/test_feature_flag.ambr
@@ -1739,7 +1739,7 @@
# ---
# name: TestFeatureFlag.test_creating_static_cohort.14
'''
- /* user_id:200 celery:posthog.tasks.calculate_cohort.insert_cohort_from_feature_flag */
+ /* user_id:201 celery:posthog.tasks.calculate_cohort.insert_cohort_from_feature_flag */
SELECT count(DISTINCT person_id)
FROM person_static_cohort
WHERE team_id = 2
diff --git a/posthog/api/test/__snapshots__/test_insight.ambr b/posthog/api/test/__snapshots__/test_insight.ambr
index 5bdf7b792790b..6495d532782b2 100644
--- a/posthog/api/test/__snapshots__/test_insight.ambr
+++ b/posthog/api/test/__snapshots__/test_insight.ambr
@@ -1616,6 +1616,24 @@
LIMIT 21 /*controller='project_insights-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/insights/%3F%24'*/
'''
# ---
+# name: TestInsight.test_listing_insights_does_not_nplus1.30
+ '''
+ SELECT "posthog_taggeditem"."id",
+ "posthog_taggeditem"."tag_id",
+ "posthog_taggeditem"."dashboard_id",
+ "posthog_taggeditem"."insight_id",
+ "posthog_taggeditem"."event_definition_id",
+ "posthog_taggeditem"."property_definition_id",
+ "posthog_taggeditem"."action_id",
+ "posthog_taggeditem"."feature_flag_id"
+ FROM "posthog_taggeditem"
+ WHERE "posthog_taggeditem"."insight_id" IN (1,
+ 2,
+ 3,
+ 4,
+ 5 /* ... */) /*controller='project_insights-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/insights/%3F%24'*/
+ '''
+# ---
# name: TestInsight.test_listing_insights_does_not_nplus1.4
'''
SELECT "posthog_team"."id",
diff --git a/posthog/api/test/__snapshots__/test_query.ambr b/posthog/api/test/__snapshots__/test_query.ambr
index 246efec9566f1..c9fdc628b2242 100644
--- a/posthog/api/test/__snapshots__/test_query.ambr
+++ b/posthog/api/test/__snapshots__/test_query.ambr
@@ -157,7 +157,7 @@
# ---
# name: TestQuery.test_full_hogql_query_async
'''
- /* user_id:467 celery:posthog.tasks.tasks.process_query_task */
+ /* user_id:468 celery:posthog.tasks.tasks.process_query_task */
SELECT events.uuid AS uuid,
events.event AS event,
events.properties AS properties,
diff --git a/posthog/api/test/test_element.py b/posthog/api/test/test_element.py
index b7cf8f944a7e9..72a97ea2b9b43 100644
--- a/posthog/api/test/test_element.py
+++ b/posthog/api/test/test_element.py
@@ -4,6 +4,7 @@
from django.test import override_settings
from freezegun import freeze_time
+from parameterized import parameterized
from rest_framework import status
from posthog.models import Element, ElementGroup, Organization
@@ -16,9 +17,9 @@
snapshot_postgres_queries,
)
-expected_all_data_response_results: List[Dict] = [
+expected_autocapture_data_response_results: List[Dict] = [
{
- "count": 2,
+ "count": 3,
"hash": None,
"type": "$autocapture",
"elements": [
@@ -158,7 +159,7 @@ def test_element_stats_can_filter_by_properties(self) -> None:
self._setup_events()
response = self.client.get("/api/element/stats/?paginate_response=true").json()
- assert len(response["results"]) == 2
+ assert len(response["results"]) == 3
properties_filter = json.dumps([{"key": "$current_url", "value": "http://example.com/another_page"}])
response = self.client.get(f"/api/element/stats/?paginate_response=true&properties={properties_filter}").json()
@@ -183,7 +184,7 @@ def test_element_stats_without_pagination(self) -> None:
response = self.client.get("/api/element/stats").json()
# not nested into a results property
- assert response == expected_all_data_response_results
+ assert response == expected_autocapture_data_response_results + expected_rage_click_data_response_results
def test_element_stats_clamps_date_from_to_start_of_day(self) -> None:
event_start = "2012-01-14T03:21:34.000Z"
@@ -244,7 +245,7 @@ def test_element_stats_can_load_all_the_data(self) -> None:
assert response_json["next"] is None # loaded all the data, so no next link
results = response_json["results"]
- assert results == expected_all_data_response_results
+ assert results == expected_autocapture_data_response_results + expected_rage_click_data_response_results
def test_element_stats_can_load_only_rageclick_data(self) -> None:
self._setup_events()
@@ -258,38 +259,52 @@ def test_element_stats_can_load_only_rageclick_data(self) -> None:
assert results == expected_rage_click_data_response_results
- def test_element_stats_can_load_rageclick_and_autocapture_data(self) -> None:
+ # no include params is equivalent to autocapture and rageclick
+ @parameterized.expand(["&include=$rageclick&include=$autocapture", ""])
+ def test_element_stats_can_load_rageclick_and_autocapture_data(self, include_params) -> None:
self._setup_events()
- response = self.client.get(
- f"/api/element/stats/?paginate_response=true&include=$rageclick&include=$autocapture"
- )
+ response = self.client.get(f"/api/element/stats/?paginate_response=true{include_params}")
self.assertEqual(response.status_code, status.HTTP_200_OK)
response_json = response.json()
assert response_json["next"] is None # loaded all the data, so no next link
results = response_json["results"]
- assert results == expected_all_data_response_results + expected_rage_click_data_response_results
+ assert results == expected_autocapture_data_response_results + expected_rage_click_data_response_results
def test_element_stats_obeys_limit_parameter(self) -> None:
self._setup_events()
- response = self.client.get(f"/api/element/stats/?paginate_response=true&limit=1")
- self.assertEqual(response.status_code, status.HTTP_200_OK)
+ page_one_response = self.client.get(f"/api/element/stats/?paginate_response=true&limit=1")
+ self.assertEqual(page_one_response.status_code, status.HTTP_200_OK)
- response_json = response.json()
- assert response_json["next"] == "http://testserver/api/element/stats/?paginate_response=true&limit=1&offset=1"
- limit_to_one_results = response_json["results"]
- assert limit_to_one_results == [expected_all_data_response_results[0]]
+ page_one_response_json = page_one_response.json()
+ assert (
+ page_one_response_json["next"]
+ == "http://testserver/api/element/stats/?paginate_response=true&limit=1&offset=1"
+ )
+ limit_to_one_results = page_one_response_json["results"]
+ assert limit_to_one_results == [expected_autocapture_data_response_results[0]]
- response = self.client.get(f"/api/element/stats/?paginate_response=true&limit=1&offset=1")
- self.assertEqual(response.status_code, status.HTTP_200_OK)
+ page_two_response = self.client.get(f"/api/element/stats/?paginate_response=true&limit=1&offset=1")
+ self.assertEqual(page_two_response.status_code, status.HTTP_200_OK)
- response_json = response.json()
- assert response_json["next"] is None
- limit_to_one_results = response_json["results"]
- assert limit_to_one_results == [expected_all_data_response_results[1]]
+ page_two_response_json = page_two_response.json()
+ assert (
+ page_two_response_json["next"]
+ == "http://testserver/api/element/stats/?paginate_response=true&limit=1&offset=2"
+ )
+ limit_to_one_results_page_two = page_two_response_json["results"]
+ assert limit_to_one_results_page_two == [expected_autocapture_data_response_results[1]]
+
+ page_three_response = self.client.get(f"/api/element/stats/?paginate_response=true&limit=1&offset=2")
+ self.assertEqual(page_three_response.status_code, status.HTTP_200_OK)
+
+ page_three_response_json = page_three_response.json()
+ assert page_three_response_json["next"] is None
+ limit_to_one_results_page_three = page_three_response_json["results"]
+ assert limit_to_one_results_page_three == [expected_rage_click_data_response_results[0]]
def test_element_stats_does_not_allow_non_numeric_limit(self) -> None:
response = self.client.get(f"/api/element/stats/?limit=not-a-number")
@@ -351,6 +366,26 @@ def _setup_events(self):
distinct_id="one",
properties={"$current_url": "http://example.com/demo"},
)
+ _create_event(
+ team=self.team,
+ elements=[
+ Element(
+ tag_name="a",
+ href="https://posthog.com/event-1",
+ text="event 1",
+ order=0,
+ ),
+ Element(
+ tag_name="div",
+ href="https://posthog.com/event-1",
+ text="event 1",
+ order=1,
+ ),
+ ],
+ event="$autocapture",
+ distinct_id="one",
+ properties={"$current_url": "http://example.com/demo"},
+ )
_create_event(
team=self.team,
elements=[
diff --git a/posthog/api/test/test_signup.py b/posthog/api/test/test_signup.py
index e62be1ffd4893..1587c0b365e9e 100644
--- a/posthog/api/test/test_signup.py
+++ b/posthog/api/test/test_signup.py
@@ -43,6 +43,7 @@ def test_api_sign_up(self, mock_capture):
"/api/signup/",
{
"first_name": "John",
+ "last_name": "Doe",
"email": "hedgehog@posthog.com",
"password": "notsecure",
"organization_name": "Hedgehogs United, LLC",
@@ -62,8 +63,8 @@ def test_api_sign_up(self, mock_capture):
"id": user.pk,
"uuid": str(user.uuid),
"distinct_id": user.distinct_id,
- "last_name": "",
"first_name": "John",
+ "last_name": "Doe",
"email": "hedgehog@posthog.com",
"redirect_url": "/",
"is_email_verified": False,
@@ -72,6 +73,7 @@ def test_api_sign_up(self, mock_capture):
# Assert that the user was properly created
self.assertEqual(user.first_name, "John")
+ self.assertEqual(user.last_name, "Doe")
self.assertEqual(user.email, "hedgehog@posthog.com")
self.assertFalse(user.email_opt_in)
self.assertTrue(user.is_staff) # True because this is the first user in the instance
@@ -223,7 +225,7 @@ def test_signup_minimum_attrs(self, mock_capture):
self.assertEqual(user.first_name, "Jane")
self.assertEqual(user.email, "hedgehog2@posthog.com")
self.assertTrue(user.email_opt_in) # Defaults to True
- self.assertEqual(organization.name, "Jane")
+ self.assertEqual(organization.name, f"{user.first_name}'s Organization")
self.assertTrue(user.is_staff) # True because this is the first user in the instance
# Assert that the sign up event & identify calls were sent to PostHog analytics
diff --git a/posthog/batch_exports/models.py b/posthog/batch_exports/models.py
index 70b85c4d35bde..db51865560a33 100644
--- a/posthog/batch_exports/models.py
+++ b/posthog/batch_exports/models.py
@@ -111,6 +111,9 @@ class Status(models.TextChoices):
auto_now=True,
help_text="The timestamp at which this BatchExportRun was last updated.",
)
+ records_total_count: models.IntegerField = models.IntegerField(
+ null=True, help_text="The total count of records that should be exported in this BatchExportRun."
+ )
BATCH_EXPORT_INTERVALS = [
diff --git a/posthog/batch_exports/service.py b/posthog/batch_exports/service.py
index d51dfdb2fbc3c..f98dea7a9ebf8 100644
--- a/posthog/batch_exports/service.py
+++ b/posthog/batch_exports/service.py
@@ -417,6 +417,7 @@ def create_batch_export_run(
data_interval_start: str,
data_interval_end: str,
status: str = BatchExportRun.Status.STARTING,
+ records_total_count: int | None = None,
) -> BatchExportRun:
"""Create a BatchExportRun after a Temporal Workflow execution.
@@ -434,6 +435,7 @@ def create_batch_export_run(
status=status,
data_interval_start=dt.datetime.fromisoformat(data_interval_start),
data_interval_end=dt.datetime.fromisoformat(data_interval_end),
+ records_total_count=records_total_count,
)
run.save()
@@ -442,22 +444,18 @@ def create_batch_export_run(
def update_batch_export_run(
run_id: UUID,
- status: str,
- latest_error: str | None,
- records_completed: int = 0,
+ **kwargs,
) -> BatchExportRun:
- """Update the status of an BatchExportRun with given id.
+ """Update the BatchExportRun with given run_id and provided **kwargs.
Arguments:
- id: The id of the BatchExportRun to update.
+ run_id: The id of the BatchExportRun to update.
"""
model = BatchExportRun.objects.filter(id=run_id)
update_at = dt.datetime.now()
updated = model.update(
- status=status,
- latest_error=latest_error,
- records_completed=records_completed,
+ **kwargs,
last_updated_at=update_at,
)
diff --git a/posthog/hogql/functions/mapping.py b/posthog/hogql/functions/mapping.py
index 5edf1a68a826a..cd908d725341d 100644
--- a/posthog/hogql/functions/mapping.py
+++ b/posthog/hogql/functions/mapping.py
@@ -161,22 +161,22 @@ class HogQLFunctionMeta:
"toDate": HogQLFunctionMeta(
"toDateOrNull",
1,
- 1,
+ 2,
overloads=[((ast.DateTimeType, ast.DateType), "toDate")],
tz_aware=True,
),
"toDateTime": HogQLFunctionMeta(
"parseDateTime64BestEffortOrNull",
1,
- 1,
+ 2,
overloads=[((ast.DateTimeType, ast.DateType, ast.IntegerType), "toDateTime")],
tz_aware=True,
),
"toUUID": HogQLFunctionMeta("toUUIDOrNull", 1, 1),
"toString": HogQLFunctionMeta("toString", 1, 1),
"toJSONString": HogQLFunctionMeta("toJSONString", 1, 1),
- "parseDateTime": HogQLFunctionMeta("parseDateTimeOrNull", 2, 2, tz_aware=True),
- "parseDateTimeBestEffort": HogQLFunctionMeta("parseDateTime64BestEffortOrNull", 1, 1, tz_aware=True),
+ "parseDateTime": HogQLFunctionMeta("parseDateTimeOrNull", 2, 3, tz_aware=True),
+ "parseDateTimeBestEffort": HogQLFunctionMeta("parseDateTime64BestEffortOrNull", 1, 2, tz_aware=True),
# dates and times
"toTimeZone": HogQLFunctionMeta("toTimeZone", 2, 2),
"timeZoneOf": HogQLFunctionMeta("timeZoneOf", 1, 1),
@@ -219,8 +219,8 @@ class HogQLFunctionMeta:
"dateSub": HogQLFunctionMeta("dateSub", 3, 3),
"timeStampAdd": HogQLFunctionMeta("timeStampAdd", 2, 2),
"timeStampSub": HogQLFunctionMeta("timeStampSub", 2, 2),
- "now": HogQLFunctionMeta("now64", tz_aware=True),
- "NOW": HogQLFunctionMeta("now64", tz_aware=True),
+ "now": HogQLFunctionMeta("now64", 0, 1, tz_aware=True),
+ "NOW": HogQLFunctionMeta("now64", 0, 1, tz_aware=True),
"nowInBlock": HogQLFunctionMeta("nowInBlock", 1, 1),
"today": HogQLFunctionMeta("today"),
"yesterday": HogQLFunctionMeta("yesterday"),
diff --git a/posthog/hogql/grammar/HogQLParser.g4 b/posthog/hogql/grammar/HogQLParser.g4
index a0f22ae3cdb0a..0729a05215653 100644
--- a/posthog/hogql/grammar/HogQLParser.g4
+++ b/posthog/hogql/grammar/HogQLParser.g4
@@ -103,7 +103,7 @@ columnExpr
: CASE caseExpr=columnExpr? (WHEN whenExpr=columnExpr THEN thenExpr=columnExpr)+ (ELSE elseExpr=columnExpr)? END # ColumnExprCase
| CAST LPAREN columnExpr AS columnTypeExpr RPAREN # ColumnExprCast
| DATE STRING_LITERAL # ColumnExprDate
- | EXTRACT LPAREN interval FROM columnExpr RPAREN # ColumnExprExtract
+// | EXTRACT LPAREN interval FROM columnExpr RPAREN # ColumnExprExtract // Interferes with a function call
| INTERVAL columnExpr interval # ColumnExprInterval
| SUBSTRING LPAREN columnExpr FROM columnExpr (FOR columnExpr)? RPAREN # ColumnExprSubstring
| TIMESTAMP STRING_LITERAL # ColumnExprTimestamp
diff --git a/posthog/hogql/grammar/HogQLParser.interp b/posthog/hogql/grammar/HogQLParser.interp
index 2b24b72a2819d..b159bc05eb424 100644
--- a/posthog/hogql/grammar/HogQLParser.interp
+++ b/posthog/hogql/grammar/HogQLParser.interp
@@ -554,4 +554,4 @@ placeholder
atn:
-[4, 1, 242, 979, 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, 1, 0, 1, 0, 1, 0, 3, 0, 128, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 136, 8, 1, 10, 1, 12, 1, 139, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 147, 8, 2, 1, 3, 3, 3, 150, 8, 3, 1, 3, 1, 3, 3, 3, 154, 8, 3, 1, 3, 3, 3, 157, 8, 3, 1, 3, 1, 3, 3, 3, 161, 8, 3, 1, 3, 3, 3, 164, 8, 3, 1, 3, 3, 3, 167, 8, 3, 1, 3, 3, 3, 170, 8, 3, 1, 3, 3, 3, 173, 8, 3, 1, 3, 1, 3, 3, 3, 177, 8, 3, 1, 3, 1, 3, 3, 3, 181, 8, 3, 1, 3, 3, 3, 184, 8, 3, 1, 3, 3, 3, 187, 8, 3, 1, 3, 3, 3, 190, 8, 3, 1, 3, 1, 3, 3, 3, 194, 8, 3, 1, 3, 3, 3, 197, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 206, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 3, 7, 212, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 231, 8, 8, 10, 8, 12, 8, 234, 9, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 250, 8, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 267, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 273, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 279, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 290, 8, 15, 3, 15, 292, 8, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 3, 18, 303, 8, 18, 1, 18, 3, 18, 306, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 312, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 320, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 326, 8, 18, 10, 18, 12, 18, 329, 9, 18, 1, 19, 3, 19, 332, 8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 337, 8, 19, 1, 19, 3, 19, 340, 8, 19, 1, 19, 3, 19, 343, 8, 19, 1, 19, 1, 19, 3, 19, 347, 8, 19, 1, 19, 1, 19, 3, 19, 351, 8, 19, 1, 19, 3, 19, 354, 8, 19, 3, 19, 356, 8, 19, 1, 19, 3, 19, 359, 8, 19, 1, 19, 1, 19, 3, 19, 363, 8, 19, 1, 19, 1, 19, 3, 19, 367, 8, 19, 1, 19, 3, 19, 370, 8, 19, 3, 19, 372, 8, 19, 3, 19, 374, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 379, 8, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 390, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 396, 8, 22, 1, 23, 1, 23, 1, 23, 5, 23, 401, 8, 23, 10, 23, 12, 23, 404, 9, 23, 1, 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, 25, 1, 25, 1, 25, 1, 25, 3, 25, 422, 8, 25, 3, 25, 424, 8, 25, 1, 26, 1, 26, 1, 26, 5, 26, 429, 8, 26, 10, 26, 12, 26, 432, 9, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 439, 8, 28, 1, 28, 3, 28, 442, 8, 28, 1, 28, 3, 28, 445, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 464, 8, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 478, 8, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 492, 8, 35, 10, 35, 12, 35, 495, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 504, 8, 35, 10, 35, 12, 35, 507, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 516, 8, 35, 10, 35, 12, 35, 519, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 3, 35, 526, 8, 35, 1, 35, 1, 35, 3, 35, 530, 8, 35, 1, 36, 1, 36, 1, 36, 5, 36, 535, 8, 36, 10, 36, 12, 36, 538, 9, 36, 1, 37, 1, 37, 1, 37, 3, 37, 543, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 550, 8, 37, 11, 37, 12, 37, 551, 1, 37, 1, 37, 3, 37, 556, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 587, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 604, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 616, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 626, 8, 37, 1, 37, 3, 37, 629, 8, 37, 1, 37, 1, 37, 3, 37, 633, 8, 37, 1, 37, 3, 37, 636, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 649, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 666, 8, 37, 1, 37, 1, 37, 3, 37, 670, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 676, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 683, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 695, 8, 37, 1, 37, 1, 37, 3, 37, 699, 8, 37, 1, 37, 3, 37, 702, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 711, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 725, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 752, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 761, 8, 37, 5, 37, 763, 8, 37, 10, 37, 12, 37, 766, 9, 37, 1, 38, 1, 38, 1, 38, 5, 38, 771, 8, 38, 10, 38, 12, 38, 774, 9, 38, 1, 39, 1, 39, 3, 39, 778, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 784, 8, 40, 10, 40, 12, 40, 787, 9, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 794, 8, 40, 10, 40, 12, 40, 797, 9, 40, 3, 40, 799, 8, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 5, 41, 807, 8, 41, 10, 41, 12, 41, 810, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 818, 8, 41, 10, 41, 12, 41, 821, 9, 41, 1, 41, 1, 41, 3, 41, 825, 8, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 832, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 845, 8, 42, 1, 43, 1, 43, 1, 43, 5, 43, 850, 8, 43, 10, 43, 12, 43, 853, 9, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 865, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 3, 45, 871, 8, 45, 1, 45, 3, 45, 874, 8, 45, 1, 46, 1, 46, 1, 46, 5, 46, 879, 8, 46, 10, 46, 12, 46, 882, 9, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 893, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 899, 8, 47, 5, 47, 901, 8, 47, 10, 47, 12, 47, 904, 9, 47, 1, 48, 1, 48, 1, 48, 3, 48, 909, 8, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 3, 49, 916, 8, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 5, 50, 923, 8, 50, 10, 50, 12, 50, 926, 9, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 936, 8, 52, 3, 52, 938, 8, 52, 1, 53, 3, 53, 941, 8, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 949, 8, 53, 1, 54, 1, 54, 1, 54, 3, 54, 954, 8, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 3, 58, 964, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 969, 8, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 0, 3, 36, 74, 94, 62, 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, 0, 16, 2, 0, 32, 32, 141, 141, 2, 0, 84, 84, 96, 96, 3, 0, 4, 4, 8, 8, 12, 12, 4, 0, 4, 4, 7, 8, 12, 12, 147, 147, 2, 0, 96, 96, 140, 140, 2, 0, 4, 4, 8, 8, 2, 0, 11, 11, 42, 43, 2, 0, 62, 62, 93, 93, 2, 0, 133, 133, 143, 143, 3, 0, 17, 17, 95, 95, 170, 170, 2, 0, 79, 79, 98, 98, 1, 0, 197, 198, 2, 0, 208, 208, 228, 228, 8, 0, 37, 37, 76, 76, 108, 108, 110, 110, 132, 132, 145, 145, 185, 185, 190, 190, 13, 0, 2, 24, 26, 36, 38, 75, 77, 81, 83, 107, 109, 109, 111, 112, 114, 115, 117, 130, 133, 144, 146, 184, 186, 189, 191, 192, 4, 0, 36, 36, 62, 62, 77, 77, 91, 91, 1107, 0, 127, 1, 0, 0, 0, 2, 131, 1, 0, 0, 0, 4, 146, 1, 0, 0, 0, 6, 149, 1, 0, 0, 0, 8, 198, 1, 0, 0, 0, 10, 201, 1, 0, 0, 0, 12, 207, 1, 0, 0, 0, 14, 211, 1, 0, 0, 0, 16, 217, 1, 0, 0, 0, 18, 235, 1, 0, 0, 0, 20, 238, 1, 0, 0, 0, 22, 241, 1, 0, 0, 0, 24, 251, 1, 0, 0, 0, 26, 254, 1, 0, 0, 0, 28, 258, 1, 0, 0, 0, 30, 291, 1, 0, 0, 0, 32, 293, 1, 0, 0, 0, 34, 296, 1, 0, 0, 0, 36, 311, 1, 0, 0, 0, 38, 373, 1, 0, 0, 0, 40, 378, 1, 0, 0, 0, 42, 389, 1, 0, 0, 0, 44, 391, 1, 0, 0, 0, 46, 397, 1, 0, 0, 0, 48, 405, 1, 0, 0, 0, 50, 423, 1, 0, 0, 0, 52, 425, 1, 0, 0, 0, 54, 433, 1, 0, 0, 0, 56, 438, 1, 0, 0, 0, 58, 446, 1, 0, 0, 0, 60, 450, 1, 0, 0, 0, 62, 454, 1, 0, 0, 0, 64, 463, 1, 0, 0, 0, 66, 477, 1, 0, 0, 0, 68, 479, 1, 0, 0, 0, 70, 529, 1, 0, 0, 0, 72, 531, 1, 0, 0, 0, 74, 669, 1, 0, 0, 0, 76, 767, 1, 0, 0, 0, 78, 777, 1, 0, 0, 0, 80, 798, 1, 0, 0, 0, 82, 831, 1, 0, 0, 0, 84, 844, 1, 0, 0, 0, 86, 846, 1, 0, 0, 0, 88, 864, 1, 0, 0, 0, 90, 873, 1, 0, 0, 0, 92, 875, 1, 0, 0, 0, 94, 892, 1, 0, 0, 0, 96, 905, 1, 0, 0, 0, 98, 915, 1, 0, 0, 0, 100, 919, 1, 0, 0, 0, 102, 927, 1, 0, 0, 0, 104, 937, 1, 0, 0, 0, 106, 940, 1, 0, 0, 0, 108, 953, 1, 0, 0, 0, 110, 955, 1, 0, 0, 0, 112, 957, 1, 0, 0, 0, 114, 959, 1, 0, 0, 0, 116, 963, 1, 0, 0, 0, 118, 968, 1, 0, 0, 0, 120, 970, 1, 0, 0, 0, 122, 974, 1, 0, 0, 0, 124, 128, 3, 2, 1, 0, 125, 128, 3, 6, 3, 0, 126, 128, 3, 82, 41, 0, 127, 124, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 130, 5, 0, 0, 1, 130, 1, 1, 0, 0, 0, 131, 137, 3, 4, 2, 0, 132, 133, 5, 176, 0, 0, 133, 134, 5, 4, 0, 0, 134, 136, 3, 4, 2, 0, 135, 132, 1, 0, 0, 0, 136, 139, 1, 0, 0, 0, 137, 135, 1, 0, 0, 0, 137, 138, 1, 0, 0, 0, 138, 3, 1, 0, 0, 0, 139, 137, 1, 0, 0, 0, 140, 147, 3, 6, 3, 0, 141, 142, 5, 220, 0, 0, 142, 143, 3, 2, 1, 0, 143, 144, 5, 236, 0, 0, 144, 147, 1, 0, 0, 0, 145, 147, 3, 122, 61, 0, 146, 140, 1, 0, 0, 0, 146, 141, 1, 0, 0, 0, 146, 145, 1, 0, 0, 0, 147, 5, 1, 0, 0, 0, 148, 150, 3, 8, 4, 0, 149, 148, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 153, 5, 146, 0, 0, 152, 154, 5, 49, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 156, 1, 0, 0, 0, 155, 157, 3, 10, 5, 0, 156, 155, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 160, 3, 72, 36, 0, 159, 161, 3, 12, 6, 0, 160, 159, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 163, 1, 0, 0, 0, 162, 164, 3, 14, 7, 0, 163, 162, 1, 0, 0, 0, 163, 164, 1, 0, 0, 0, 164, 166, 1, 0, 0, 0, 165, 167, 3, 18, 9, 0, 166, 165, 1, 0, 0, 0, 166, 167, 1, 0, 0, 0, 167, 169, 1, 0, 0, 0, 168, 170, 3, 20, 10, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 172, 1, 0, 0, 0, 171, 173, 3, 22, 11, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 175, 5, 189, 0, 0, 175, 177, 7, 0, 0, 0, 176, 174, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 180, 1, 0, 0, 0, 178, 179, 5, 189, 0, 0, 179, 181, 5, 169, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 183, 1, 0, 0, 0, 182, 184, 3, 24, 12, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 187, 3, 16, 8, 0, 186, 185, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 190, 3, 26, 13, 0, 189, 188, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 194, 3, 30, 15, 0, 192, 194, 3, 32, 16, 0, 193, 191, 1, 0, 0, 0, 193, 192, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 196, 1, 0, 0, 0, 195, 197, 3, 34, 17, 0, 196, 195, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 7, 1, 0, 0, 0, 198, 199, 5, 189, 0, 0, 199, 200, 3, 86, 43, 0, 200, 9, 1, 0, 0, 0, 201, 202, 5, 168, 0, 0, 202, 205, 5, 198, 0, 0, 203, 204, 5, 189, 0, 0, 204, 206, 5, 164, 0, 0, 205, 203, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 11, 1, 0, 0, 0, 207, 208, 5, 68, 0, 0, 208, 209, 3, 36, 18, 0, 209, 13, 1, 0, 0, 0, 210, 212, 7, 1, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 5, 9, 0, 0, 214, 215, 5, 90, 0, 0, 215, 216, 3, 72, 36, 0, 216, 15, 1, 0, 0, 0, 217, 218, 5, 188, 0, 0, 218, 219, 3, 118, 59, 0, 219, 220, 5, 10, 0, 0, 220, 221, 5, 220, 0, 0, 221, 222, 3, 56, 28, 0, 222, 232, 5, 236, 0, 0, 223, 224, 5, 206, 0, 0, 224, 225, 3, 118, 59, 0, 225, 226, 5, 10, 0, 0, 226, 227, 5, 220, 0, 0, 227, 228, 3, 56, 28, 0, 228, 229, 5, 236, 0, 0, 229, 231, 1, 0, 0, 0, 230, 223, 1, 0, 0, 0, 231, 234, 1, 0, 0, 0, 232, 230, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 17, 1, 0, 0, 0, 234, 232, 1, 0, 0, 0, 235, 236, 5, 129, 0, 0, 236, 237, 3, 74, 37, 0, 237, 19, 1, 0, 0, 0, 238, 239, 5, 187, 0, 0, 239, 240, 3, 74, 37, 0, 240, 21, 1, 0, 0, 0, 241, 242, 5, 73, 0, 0, 242, 249, 5, 18, 0, 0, 243, 244, 7, 0, 0, 0, 244, 245, 5, 220, 0, 0, 245, 246, 3, 72, 36, 0, 246, 247, 5, 236, 0, 0, 247, 250, 1, 0, 0, 0, 248, 250, 3, 72, 36, 0, 249, 243, 1, 0, 0, 0, 249, 248, 1, 0, 0, 0, 250, 23, 1, 0, 0, 0, 251, 252, 5, 74, 0, 0, 252, 253, 3, 74, 37, 0, 253, 25, 1, 0, 0, 0, 254, 255, 5, 122, 0, 0, 255, 256, 5, 18, 0, 0, 256, 257, 3, 46, 23, 0, 257, 27, 1, 0, 0, 0, 258, 259, 5, 122, 0, 0, 259, 260, 5, 18, 0, 0, 260, 261, 3, 72, 36, 0, 261, 29, 1, 0, 0, 0, 262, 263, 5, 99, 0, 0, 263, 266, 3, 74, 37, 0, 264, 265, 5, 206, 0, 0, 265, 267, 3, 74, 37, 0, 266, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 272, 1, 0, 0, 0, 268, 269, 5, 189, 0, 0, 269, 273, 5, 164, 0, 0, 270, 271, 5, 18, 0, 0, 271, 273, 3, 72, 36, 0, 272, 268, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 292, 1, 0, 0, 0, 274, 275, 5, 99, 0, 0, 275, 278, 3, 74, 37, 0, 276, 277, 5, 189, 0, 0, 277, 279, 5, 164, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 5, 118, 0, 0, 281, 282, 3, 74, 37, 0, 282, 292, 1, 0, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 3, 74, 37, 0, 285, 286, 5, 118, 0, 0, 286, 289, 3, 74, 37, 0, 287, 288, 5, 18, 0, 0, 288, 290, 3, 72, 36, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 292, 1, 0, 0, 0, 291, 262, 1, 0, 0, 0, 291, 274, 1, 0, 0, 0, 291, 283, 1, 0, 0, 0, 292, 31, 1, 0, 0, 0, 293, 294, 5, 118, 0, 0, 294, 295, 3, 74, 37, 0, 295, 33, 1, 0, 0, 0, 296, 297, 5, 150, 0, 0, 297, 298, 3, 52, 26, 0, 298, 35, 1, 0, 0, 0, 299, 300, 6, 18, -1, 0, 300, 302, 3, 94, 47, 0, 301, 303, 5, 61, 0, 0, 302, 301, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 305, 1, 0, 0, 0, 304, 306, 3, 44, 22, 0, 305, 304, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 312, 1, 0, 0, 0, 307, 308, 5, 220, 0, 0, 308, 309, 3, 36, 18, 0, 309, 310, 5, 236, 0, 0, 310, 312, 1, 0, 0, 0, 311, 299, 1, 0, 0, 0, 311, 307, 1, 0, 0, 0, 312, 327, 1, 0, 0, 0, 313, 314, 10, 3, 0, 0, 314, 315, 3, 40, 20, 0, 315, 316, 3, 36, 18, 4, 316, 326, 1, 0, 0, 0, 317, 319, 10, 4, 0, 0, 318, 320, 3, 38, 19, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 90, 0, 0, 322, 323, 3, 36, 18, 0, 323, 324, 3, 42, 21, 0, 324, 326, 1, 0, 0, 0, 325, 313, 1, 0, 0, 0, 325, 317, 1, 0, 0, 0, 326, 329, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 37, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 330, 332, 7, 2, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 340, 5, 84, 0, 0, 334, 336, 5, 84, 0, 0, 335, 337, 7, 2, 0, 0, 336, 335, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 340, 1, 0, 0, 0, 338, 340, 7, 2, 0, 0, 339, 331, 1, 0, 0, 0, 339, 334, 1, 0, 0, 0, 339, 338, 1, 0, 0, 0, 340, 374, 1, 0, 0, 0, 341, 343, 7, 3, 0, 0, 342, 341, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 344, 1, 0, 0, 0, 344, 346, 7, 4, 0, 0, 345, 347, 5, 123, 0, 0, 346, 345, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 347, 356, 1, 0, 0, 0, 348, 350, 7, 4, 0, 0, 349, 351, 5, 123, 0, 0, 350, 349, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 353, 1, 0, 0, 0, 352, 354, 7, 3, 0, 0, 353, 352, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 356, 1, 0, 0, 0, 355, 342, 1, 0, 0, 0, 355, 348, 1, 0, 0, 0, 356, 374, 1, 0, 0, 0, 357, 359, 7, 5, 0, 0, 358, 357, 1, 0, 0, 0, 358, 359, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 362, 5, 69, 0, 0, 361, 363, 5, 123, 0, 0, 362, 361, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 372, 1, 0, 0, 0, 364, 366, 5, 69, 0, 0, 365, 367, 5, 123, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 369, 1, 0, 0, 0, 368, 370, 7, 5, 0, 0, 369, 368, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 372, 1, 0, 0, 0, 371, 358, 1, 0, 0, 0, 371, 364, 1, 0, 0, 0, 372, 374, 1, 0, 0, 0, 373, 339, 1, 0, 0, 0, 373, 355, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 374, 39, 1, 0, 0, 0, 375, 376, 5, 31, 0, 0, 376, 379, 5, 90, 0, 0, 377, 379, 5, 206, 0, 0, 378, 375, 1, 0, 0, 0, 378, 377, 1, 0, 0, 0, 379, 41, 1, 0, 0, 0, 380, 381, 5, 119, 0, 0, 381, 390, 3, 72, 36, 0, 382, 383, 5, 179, 0, 0, 383, 384, 5, 220, 0, 0, 384, 385, 3, 72, 36, 0, 385, 386, 5, 236, 0, 0, 386, 390, 1, 0, 0, 0, 387, 388, 5, 179, 0, 0, 388, 390, 3, 72, 36, 0, 389, 380, 1, 0, 0, 0, 389, 382, 1, 0, 0, 0, 389, 387, 1, 0, 0, 0, 390, 43, 1, 0, 0, 0, 391, 392, 5, 144, 0, 0, 392, 395, 3, 50, 25, 0, 393, 394, 5, 118, 0, 0, 394, 396, 3, 50, 25, 0, 395, 393, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 45, 1, 0, 0, 0, 397, 402, 3, 48, 24, 0, 398, 399, 5, 206, 0, 0, 399, 401, 3, 48, 24, 0, 400, 398, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 47, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 405, 407, 3, 74, 37, 0, 406, 408, 7, 6, 0, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 117, 0, 0, 410, 412, 7, 7, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 26, 0, 0, 414, 416, 5, 200, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 49, 1, 0, 0, 0, 417, 424, 3, 122, 61, 0, 418, 421, 3, 106, 53, 0, 419, 420, 5, 238, 0, 0, 420, 422, 3, 106, 53, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 417, 1, 0, 0, 0, 423, 418, 1, 0, 0, 0, 424, 51, 1, 0, 0, 0, 425, 430, 3, 54, 27, 0, 426, 427, 5, 206, 0, 0, 427, 429, 3, 54, 27, 0, 428, 426, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 53, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 433, 434, 3, 118, 59, 0, 434, 435, 5, 212, 0, 0, 435, 436, 3, 108, 54, 0, 436, 55, 1, 0, 0, 0, 437, 439, 3, 58, 29, 0, 438, 437, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 441, 1, 0, 0, 0, 440, 442, 3, 60, 30, 0, 441, 440, 1, 0, 0, 0, 441, 442, 1, 0, 0, 0, 442, 444, 1, 0, 0, 0, 443, 445, 3, 62, 31, 0, 444, 443, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, 57, 1, 0, 0, 0, 446, 447, 5, 126, 0, 0, 447, 448, 5, 18, 0, 0, 448, 449, 3, 72, 36, 0, 449, 59, 1, 0, 0, 0, 450, 451, 5, 122, 0, 0, 451, 452, 5, 18, 0, 0, 452, 453, 3, 46, 23, 0, 453, 61, 1, 0, 0, 0, 454, 455, 7, 8, 0, 0, 455, 456, 3, 64, 32, 0, 456, 63, 1, 0, 0, 0, 457, 464, 3, 66, 33, 0, 458, 459, 5, 16, 0, 0, 459, 460, 3, 66, 33, 0, 460, 461, 5, 6, 0, 0, 461, 462, 3, 66, 33, 0, 462, 464, 1, 0, 0, 0, 463, 457, 1, 0, 0, 0, 463, 458, 1, 0, 0, 0, 464, 65, 1, 0, 0, 0, 465, 466, 5, 33, 0, 0, 466, 478, 5, 142, 0, 0, 467, 468, 5, 175, 0, 0, 468, 478, 5, 128, 0, 0, 469, 470, 5, 175, 0, 0, 470, 478, 5, 64, 0, 0, 471, 472, 3, 106, 53, 0, 472, 473, 5, 128, 0, 0, 473, 478, 1, 0, 0, 0, 474, 475, 3, 106, 53, 0, 475, 476, 5, 64, 0, 0, 476, 478, 1, 0, 0, 0, 477, 465, 1, 0, 0, 0, 477, 467, 1, 0, 0, 0, 477, 469, 1, 0, 0, 0, 477, 471, 1, 0, 0, 0, 477, 474, 1, 0, 0, 0, 478, 67, 1, 0, 0, 0, 479, 480, 3, 74, 37, 0, 480, 481, 5, 0, 0, 1, 481, 69, 1, 0, 0, 0, 482, 530, 3, 118, 59, 0, 483, 484, 3, 118, 59, 0, 484, 485, 5, 220, 0, 0, 485, 486, 3, 118, 59, 0, 486, 493, 3, 70, 35, 0, 487, 488, 5, 206, 0, 0, 488, 489, 3, 118, 59, 0, 489, 490, 3, 70, 35, 0, 490, 492, 1, 0, 0, 0, 491, 487, 1, 0, 0, 0, 492, 495, 1, 0, 0, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 496, 1, 0, 0, 0, 495, 493, 1, 0, 0, 0, 496, 497, 5, 236, 0, 0, 497, 530, 1, 0, 0, 0, 498, 499, 3, 118, 59, 0, 499, 500, 5, 220, 0, 0, 500, 505, 3, 120, 60, 0, 501, 502, 5, 206, 0, 0, 502, 504, 3, 120, 60, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 508, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 509, 5, 236, 0, 0, 509, 530, 1, 0, 0, 0, 510, 511, 3, 118, 59, 0, 511, 512, 5, 220, 0, 0, 512, 517, 3, 70, 35, 0, 513, 514, 5, 206, 0, 0, 514, 516, 3, 70, 35, 0, 515, 513, 1, 0, 0, 0, 516, 519, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 518, 1, 0, 0, 0, 518, 520, 1, 0, 0, 0, 519, 517, 1, 0, 0, 0, 520, 521, 5, 236, 0, 0, 521, 530, 1, 0, 0, 0, 522, 523, 3, 118, 59, 0, 523, 525, 5, 220, 0, 0, 524, 526, 3, 72, 36, 0, 525, 524, 1, 0, 0, 0, 525, 526, 1, 0, 0, 0, 526, 527, 1, 0, 0, 0, 527, 528, 5, 236, 0, 0, 528, 530, 1, 0, 0, 0, 529, 482, 1, 0, 0, 0, 529, 483, 1, 0, 0, 0, 529, 498, 1, 0, 0, 0, 529, 510, 1, 0, 0, 0, 529, 522, 1, 0, 0, 0, 530, 71, 1, 0, 0, 0, 531, 536, 3, 74, 37, 0, 532, 533, 5, 206, 0, 0, 533, 535, 3, 74, 37, 0, 534, 532, 1, 0, 0, 0, 535, 538, 1, 0, 0, 0, 536, 534, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 537, 73, 1, 0, 0, 0, 538, 536, 1, 0, 0, 0, 539, 540, 6, 37, -1, 0, 540, 542, 5, 19, 0, 0, 541, 543, 3, 74, 37, 0, 542, 541, 1, 0, 0, 0, 542, 543, 1, 0, 0, 0, 543, 549, 1, 0, 0, 0, 544, 545, 5, 186, 0, 0, 545, 546, 3, 74, 37, 0, 546, 547, 5, 163, 0, 0, 547, 548, 3, 74, 37, 0, 548, 550, 1, 0, 0, 0, 549, 544, 1, 0, 0, 0, 550, 551, 1, 0, 0, 0, 551, 549, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 554, 5, 52, 0, 0, 554, 556, 3, 74, 37, 0, 555, 553, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 5, 53, 0, 0, 558, 670, 1, 0, 0, 0, 559, 560, 5, 20, 0, 0, 560, 561, 5, 220, 0, 0, 561, 562, 3, 74, 37, 0, 562, 563, 5, 10, 0, 0, 563, 564, 3, 70, 35, 0, 564, 565, 5, 236, 0, 0, 565, 670, 1, 0, 0, 0, 566, 567, 5, 36, 0, 0, 567, 670, 5, 200, 0, 0, 568, 569, 5, 59, 0, 0, 569, 570, 5, 220, 0, 0, 570, 571, 3, 110, 55, 0, 571, 572, 5, 68, 0, 0, 572, 573, 3, 74, 37, 0, 573, 574, 5, 236, 0, 0, 574, 670, 1, 0, 0, 0, 575, 576, 5, 86, 0, 0, 576, 577, 3, 74, 37, 0, 577, 578, 3, 110, 55, 0, 578, 670, 1, 0, 0, 0, 579, 580, 5, 155, 0, 0, 580, 581, 5, 220, 0, 0, 581, 582, 3, 74, 37, 0, 582, 583, 5, 68, 0, 0, 583, 586, 3, 74, 37, 0, 584, 585, 5, 65, 0, 0, 585, 587, 3, 74, 37, 0, 586, 584, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 1, 0, 0, 0, 588, 589, 5, 236, 0, 0, 589, 670, 1, 0, 0, 0, 590, 591, 5, 166, 0, 0, 591, 670, 5, 200, 0, 0, 592, 593, 5, 171, 0, 0, 593, 594, 5, 220, 0, 0, 594, 595, 7, 9, 0, 0, 595, 596, 5, 200, 0, 0, 596, 597, 5, 68, 0, 0, 597, 598, 3, 74, 37, 0, 598, 599, 5, 236, 0, 0, 599, 670, 1, 0, 0, 0, 600, 601, 3, 118, 59, 0, 601, 603, 5, 220, 0, 0, 602, 604, 3, 72, 36, 0, 603, 602, 1, 0, 0, 0, 603, 604, 1, 0, 0, 0, 604, 605, 1, 0, 0, 0, 605, 606, 5, 236, 0, 0, 606, 607, 1, 0, 0, 0, 607, 608, 5, 125, 0, 0, 608, 609, 5, 220, 0, 0, 609, 610, 3, 56, 28, 0, 610, 611, 5, 236, 0, 0, 611, 670, 1, 0, 0, 0, 612, 613, 3, 118, 59, 0, 613, 615, 5, 220, 0, 0, 614, 616, 3, 72, 36, 0, 615, 614, 1, 0, 0, 0, 615, 616, 1, 0, 0, 0, 616, 617, 1, 0, 0, 0, 617, 618, 5, 236, 0, 0, 618, 619, 1, 0, 0, 0, 619, 620, 5, 125, 0, 0, 620, 621, 3, 118, 59, 0, 621, 670, 1, 0, 0, 0, 622, 628, 3, 118, 59, 0, 623, 625, 5, 220, 0, 0, 624, 626, 3, 72, 36, 0, 625, 624, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 627, 1, 0, 0, 0, 627, 629, 5, 236, 0, 0, 628, 623, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 632, 5, 220, 0, 0, 631, 633, 5, 49, 0, 0, 632, 631, 1, 0, 0, 0, 632, 633, 1, 0, 0, 0, 633, 635, 1, 0, 0, 0, 634, 636, 3, 76, 38, 0, 635, 634, 1, 0, 0, 0, 635, 636, 1, 0, 0, 0, 636, 637, 1, 0, 0, 0, 637, 638, 5, 236, 0, 0, 638, 670, 1, 0, 0, 0, 639, 670, 3, 82, 41, 0, 640, 670, 3, 108, 54, 0, 641, 642, 5, 208, 0, 0, 642, 670, 3, 74, 37, 18, 643, 644, 5, 115, 0, 0, 644, 670, 3, 74, 37, 12, 645, 646, 3, 98, 49, 0, 646, 647, 5, 210, 0, 0, 647, 649, 1, 0, 0, 0, 648, 645, 1, 0, 0, 0, 648, 649, 1, 0, 0, 0, 649, 650, 1, 0, 0, 0, 650, 670, 5, 202, 0, 0, 651, 652, 5, 220, 0, 0, 652, 653, 3, 2, 1, 0, 653, 654, 5, 236, 0, 0, 654, 670, 1, 0, 0, 0, 655, 656, 5, 220, 0, 0, 656, 657, 3, 74, 37, 0, 657, 658, 5, 236, 0, 0, 658, 670, 1, 0, 0, 0, 659, 660, 5, 220, 0, 0, 660, 661, 3, 72, 36, 0, 661, 662, 5, 236, 0, 0, 662, 670, 1, 0, 0, 0, 663, 665, 5, 219, 0, 0, 664, 666, 3, 72, 36, 0, 665, 664, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 667, 1, 0, 0, 0, 667, 670, 5, 235, 0, 0, 668, 670, 3, 90, 45, 0, 669, 539, 1, 0, 0, 0, 669, 559, 1, 0, 0, 0, 669, 566, 1, 0, 0, 0, 669, 568, 1, 0, 0, 0, 669, 575, 1, 0, 0, 0, 669, 579, 1, 0, 0, 0, 669, 590, 1, 0, 0, 0, 669, 592, 1, 0, 0, 0, 669, 600, 1, 0, 0, 0, 669, 612, 1, 0, 0, 0, 669, 622, 1, 0, 0, 0, 669, 639, 1, 0, 0, 0, 669, 640, 1, 0, 0, 0, 669, 641, 1, 0, 0, 0, 669, 643, 1, 0, 0, 0, 669, 648, 1, 0, 0, 0, 669, 651, 1, 0, 0, 0, 669, 655, 1, 0, 0, 0, 669, 659, 1, 0, 0, 0, 669, 663, 1, 0, 0, 0, 669, 668, 1, 0, 0, 0, 670, 764, 1, 0, 0, 0, 671, 675, 10, 17, 0, 0, 672, 676, 5, 202, 0, 0, 673, 676, 5, 238, 0, 0, 674, 676, 5, 227, 0, 0, 675, 672, 1, 0, 0, 0, 675, 673, 1, 0, 0, 0, 675, 674, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 763, 3, 74, 37, 18, 678, 682, 10, 16, 0, 0, 679, 683, 5, 228, 0, 0, 680, 683, 5, 208, 0, 0, 681, 683, 5, 207, 0, 0, 682, 679, 1, 0, 0, 0, 682, 680, 1, 0, 0, 0, 682, 681, 1, 0, 0, 0, 683, 684, 1, 0, 0, 0, 684, 763, 3, 74, 37, 17, 685, 710, 10, 15, 0, 0, 686, 711, 5, 211, 0, 0, 687, 711, 5, 212, 0, 0, 688, 711, 5, 223, 0, 0, 689, 711, 5, 221, 0, 0, 690, 711, 5, 222, 0, 0, 691, 711, 5, 213, 0, 0, 692, 711, 5, 214, 0, 0, 693, 695, 5, 115, 0, 0, 694, 693, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 696, 1, 0, 0, 0, 696, 698, 5, 80, 0, 0, 697, 699, 5, 25, 0, 0, 698, 697, 1, 0, 0, 0, 698, 699, 1, 0, 0, 0, 699, 711, 1, 0, 0, 0, 700, 702, 5, 115, 0, 0, 701, 700, 1, 0, 0, 0, 701, 702, 1, 0, 0, 0, 702, 703, 1, 0, 0, 0, 703, 711, 7, 10, 0, 0, 704, 711, 5, 232, 0, 0, 705, 711, 5, 233, 0, 0, 706, 711, 5, 225, 0, 0, 707, 711, 5, 216, 0, 0, 708, 711, 5, 217, 0, 0, 709, 711, 5, 224, 0, 0, 710, 686, 1, 0, 0, 0, 710, 687, 1, 0, 0, 0, 710, 688, 1, 0, 0, 0, 710, 689, 1, 0, 0, 0, 710, 690, 1, 0, 0, 0, 710, 691, 1, 0, 0, 0, 710, 692, 1, 0, 0, 0, 710, 694, 1, 0, 0, 0, 710, 701, 1, 0, 0, 0, 710, 704, 1, 0, 0, 0, 710, 705, 1, 0, 0, 0, 710, 706, 1, 0, 0, 0, 710, 707, 1, 0, 0, 0, 710, 708, 1, 0, 0, 0, 710, 709, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712, 763, 3, 74, 37, 16, 713, 714, 10, 13, 0, 0, 714, 715, 5, 226, 0, 0, 715, 763, 3, 74, 37, 14, 716, 717, 10, 11, 0, 0, 717, 718, 5, 6, 0, 0, 718, 763, 3, 74, 37, 12, 719, 720, 10, 10, 0, 0, 720, 721, 5, 121, 0, 0, 721, 763, 3, 74, 37, 11, 722, 724, 10, 9, 0, 0, 723, 725, 5, 115, 0, 0, 724, 723, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726, 727, 5, 16, 0, 0, 727, 728, 3, 74, 37, 0, 728, 729, 5, 6, 0, 0, 729, 730, 3, 74, 37, 10, 730, 763, 1, 0, 0, 0, 731, 732, 10, 8, 0, 0, 732, 733, 5, 229, 0, 0, 733, 734, 3, 74, 37, 0, 734, 735, 5, 205, 0, 0, 735, 736, 3, 74, 37, 8, 736, 763, 1, 0, 0, 0, 737, 738, 10, 21, 0, 0, 738, 739, 5, 219, 0, 0, 739, 740, 3, 74, 37, 0, 740, 741, 5, 235, 0, 0, 741, 763, 1, 0, 0, 0, 742, 743, 10, 20, 0, 0, 743, 744, 5, 210, 0, 0, 744, 763, 5, 198, 0, 0, 745, 746, 10, 19, 0, 0, 746, 747, 5, 210, 0, 0, 747, 763, 3, 118, 59, 0, 748, 749, 10, 14, 0, 0, 749, 751, 5, 88, 0, 0, 750, 752, 5, 115, 0, 0, 751, 750, 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 752, 753, 1, 0, 0, 0, 753, 763, 5, 116, 0, 0, 754, 760, 10, 7, 0, 0, 755, 761, 3, 116, 58, 0, 756, 757, 5, 10, 0, 0, 757, 761, 3, 118, 59, 0, 758, 759, 5, 10, 0, 0, 759, 761, 5, 200, 0, 0, 760, 755, 1, 0, 0, 0, 760, 756, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 763, 1, 0, 0, 0, 762, 671, 1, 0, 0, 0, 762, 678, 1, 0, 0, 0, 762, 685, 1, 0, 0, 0, 762, 713, 1, 0, 0, 0, 762, 716, 1, 0, 0, 0, 762, 719, 1, 0, 0, 0, 762, 722, 1, 0, 0, 0, 762, 731, 1, 0, 0, 0, 762, 737, 1, 0, 0, 0, 762, 742, 1, 0, 0, 0, 762, 745, 1, 0, 0, 0, 762, 748, 1, 0, 0, 0, 762, 754, 1, 0, 0, 0, 763, 766, 1, 0, 0, 0, 764, 762, 1, 0, 0, 0, 764, 765, 1, 0, 0, 0, 765, 75, 1, 0, 0, 0, 766, 764, 1, 0, 0, 0, 767, 772, 3, 78, 39, 0, 768, 769, 5, 206, 0, 0, 769, 771, 3, 78, 39, 0, 770, 768, 1, 0, 0, 0, 771, 774, 1, 0, 0, 0, 772, 770, 1, 0, 0, 0, 772, 773, 1, 0, 0, 0, 773, 77, 1, 0, 0, 0, 774, 772, 1, 0, 0, 0, 775, 778, 3, 80, 40, 0, 776, 778, 3, 74, 37, 0, 777, 775, 1, 0, 0, 0, 777, 776, 1, 0, 0, 0, 778, 79, 1, 0, 0, 0, 779, 780, 5, 220, 0, 0, 780, 785, 3, 118, 59, 0, 781, 782, 5, 206, 0, 0, 782, 784, 3, 118, 59, 0, 783, 781, 1, 0, 0, 0, 784, 787, 1, 0, 0, 0, 785, 783, 1, 0, 0, 0, 785, 786, 1, 0, 0, 0, 786, 788, 1, 0, 0, 0, 787, 785, 1, 0, 0, 0, 788, 789, 5, 236, 0, 0, 789, 799, 1, 0, 0, 0, 790, 795, 3, 118, 59, 0, 791, 792, 5, 206, 0, 0, 792, 794, 3, 118, 59, 0, 793, 791, 1, 0, 0, 0, 794, 797, 1, 0, 0, 0, 795, 793, 1, 0, 0, 0, 795, 796, 1, 0, 0, 0, 796, 799, 1, 0, 0, 0, 797, 795, 1, 0, 0, 0, 798, 779, 1, 0, 0, 0, 798, 790, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0, 800, 801, 5, 201, 0, 0, 801, 802, 3, 74, 37, 0, 802, 81, 1, 0, 0, 0, 803, 804, 5, 222, 0, 0, 804, 808, 3, 118, 59, 0, 805, 807, 3, 84, 42, 0, 806, 805, 1, 0, 0, 0, 807, 810, 1, 0, 0, 0, 808, 806, 1, 0, 0, 0, 808, 809, 1, 0, 0, 0, 809, 811, 1, 0, 0, 0, 810, 808, 1, 0, 0, 0, 811, 812, 5, 238, 0, 0, 812, 813, 5, 214, 0, 0, 813, 832, 1, 0, 0, 0, 814, 815, 5, 222, 0, 0, 815, 819, 3, 118, 59, 0, 816, 818, 3, 84, 42, 0, 817, 816, 1, 0, 0, 0, 818, 821, 1, 0, 0, 0, 819, 817, 1, 0, 0, 0, 819, 820, 1, 0, 0, 0, 820, 822, 1, 0, 0, 0, 821, 819, 1, 0, 0, 0, 822, 824, 5, 214, 0, 0, 823, 825, 3, 82, 41, 0, 824, 823, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 827, 5, 222, 0, 0, 827, 828, 5, 238, 0, 0, 828, 829, 3, 118, 59, 0, 829, 830, 5, 214, 0, 0, 830, 832, 1, 0, 0, 0, 831, 803, 1, 0, 0, 0, 831, 814, 1, 0, 0, 0, 832, 83, 1, 0, 0, 0, 833, 834, 3, 118, 59, 0, 834, 835, 5, 212, 0, 0, 835, 836, 5, 200, 0, 0, 836, 845, 1, 0, 0, 0, 837, 838, 3, 118, 59, 0, 838, 839, 5, 212, 0, 0, 839, 840, 5, 218, 0, 0, 840, 841, 3, 74, 37, 0, 841, 842, 5, 234, 0, 0, 842, 845, 1, 0, 0, 0, 843, 845, 3, 118, 59, 0, 844, 833, 1, 0, 0, 0, 844, 837, 1, 0, 0, 0, 844, 843, 1, 0, 0, 0, 845, 85, 1, 0, 0, 0, 846, 851, 3, 88, 44, 0, 847, 848, 5, 206, 0, 0, 848, 850, 3, 88, 44, 0, 849, 847, 1, 0, 0, 0, 850, 853, 1, 0, 0, 0, 851, 849, 1, 0, 0, 0, 851, 852, 1, 0, 0, 0, 852, 87, 1, 0, 0, 0, 853, 851, 1, 0, 0, 0, 854, 855, 3, 118, 59, 0, 855, 856, 5, 10, 0, 0, 856, 857, 5, 220, 0, 0, 857, 858, 3, 2, 1, 0, 858, 859, 5, 236, 0, 0, 859, 865, 1, 0, 0, 0, 860, 861, 3, 74, 37, 0, 861, 862, 5, 10, 0, 0, 862, 863, 3, 118, 59, 0, 863, 865, 1, 0, 0, 0, 864, 854, 1, 0, 0, 0, 864, 860, 1, 0, 0, 0, 865, 89, 1, 0, 0, 0, 866, 874, 3, 122, 61, 0, 867, 868, 3, 98, 49, 0, 868, 869, 5, 210, 0, 0, 869, 871, 1, 0, 0, 0, 870, 867, 1, 0, 0, 0, 870, 871, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 874, 3, 92, 46, 0, 873, 866, 1, 0, 0, 0, 873, 870, 1, 0, 0, 0, 874, 91, 1, 0, 0, 0, 875, 880, 3, 118, 59, 0, 876, 877, 5, 210, 0, 0, 877, 879, 3, 118, 59, 0, 878, 876, 1, 0, 0, 0, 879, 882, 1, 0, 0, 0, 880, 878, 1, 0, 0, 0, 880, 881, 1, 0, 0, 0, 881, 93, 1, 0, 0, 0, 882, 880, 1, 0, 0, 0, 883, 884, 6, 47, -1, 0, 884, 893, 3, 98, 49, 0, 885, 893, 3, 96, 48, 0, 886, 887, 5, 220, 0, 0, 887, 888, 3, 2, 1, 0, 888, 889, 5, 236, 0, 0, 889, 893, 1, 0, 0, 0, 890, 893, 3, 82, 41, 0, 891, 893, 3, 122, 61, 0, 892, 883, 1, 0, 0, 0, 892, 885, 1, 0, 0, 0, 892, 886, 1, 0, 0, 0, 892, 890, 1, 0, 0, 0, 892, 891, 1, 0, 0, 0, 893, 902, 1, 0, 0, 0, 894, 898, 10, 3, 0, 0, 895, 899, 3, 116, 58, 0, 896, 897, 5, 10, 0, 0, 897, 899, 3, 118, 59, 0, 898, 895, 1, 0, 0, 0, 898, 896, 1, 0, 0, 0, 899, 901, 1, 0, 0, 0, 900, 894, 1, 0, 0, 0, 901, 904, 1, 0, 0, 0, 902, 900, 1, 0, 0, 0, 902, 903, 1, 0, 0, 0, 903, 95, 1, 0, 0, 0, 904, 902, 1, 0, 0, 0, 905, 906, 3, 118, 59, 0, 906, 908, 5, 220, 0, 0, 907, 909, 3, 100, 50, 0, 908, 907, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 5, 236, 0, 0, 911, 97, 1, 0, 0, 0, 912, 913, 3, 102, 51, 0, 913, 914, 5, 210, 0, 0, 914, 916, 1, 0, 0, 0, 915, 912, 1, 0, 0, 0, 915, 916, 1, 0, 0, 0, 916, 917, 1, 0, 0, 0, 917, 918, 3, 118, 59, 0, 918, 99, 1, 0, 0, 0, 919, 924, 3, 74, 37, 0, 920, 921, 5, 206, 0, 0, 921, 923, 3, 74, 37, 0, 922, 920, 1, 0, 0, 0, 923, 926, 1, 0, 0, 0, 924, 922, 1, 0, 0, 0, 924, 925, 1, 0, 0, 0, 925, 101, 1, 0, 0, 0, 926, 924, 1, 0, 0, 0, 927, 928, 3, 118, 59, 0, 928, 103, 1, 0, 0, 0, 929, 938, 5, 196, 0, 0, 930, 931, 5, 210, 0, 0, 931, 938, 7, 11, 0, 0, 932, 933, 5, 198, 0, 0, 933, 935, 5, 210, 0, 0, 934, 936, 7, 11, 0, 0, 935, 934, 1, 0, 0, 0, 935, 936, 1, 0, 0, 0, 936, 938, 1, 0, 0, 0, 937, 929, 1, 0, 0, 0, 937, 930, 1, 0, 0, 0, 937, 932, 1, 0, 0, 0, 938, 105, 1, 0, 0, 0, 939, 941, 7, 12, 0, 0, 940, 939, 1, 0, 0, 0, 940, 941, 1, 0, 0, 0, 941, 948, 1, 0, 0, 0, 942, 949, 3, 104, 52, 0, 943, 949, 5, 197, 0, 0, 944, 949, 5, 198, 0, 0, 945, 949, 5, 199, 0, 0, 946, 949, 5, 82, 0, 0, 947, 949, 5, 113, 0, 0, 948, 942, 1, 0, 0, 0, 948, 943, 1, 0, 0, 0, 948, 944, 1, 0, 0, 0, 948, 945, 1, 0, 0, 0, 948, 946, 1, 0, 0, 0, 948, 947, 1, 0, 0, 0, 949, 107, 1, 0, 0, 0, 950, 954, 3, 106, 53, 0, 951, 954, 5, 200, 0, 0, 952, 954, 5, 116, 0, 0, 953, 950, 1, 0, 0, 0, 953, 951, 1, 0, 0, 0, 953, 952, 1, 0, 0, 0, 954, 109, 1, 0, 0, 0, 955, 956, 7, 13, 0, 0, 956, 111, 1, 0, 0, 0, 957, 958, 7, 14, 0, 0, 958, 113, 1, 0, 0, 0, 959, 960, 7, 15, 0, 0, 960, 115, 1, 0, 0, 0, 961, 964, 5, 195, 0, 0, 962, 964, 3, 114, 57, 0, 963, 961, 1, 0, 0, 0, 963, 962, 1, 0, 0, 0, 964, 117, 1, 0, 0, 0, 965, 969, 5, 195, 0, 0, 966, 969, 3, 110, 55, 0, 967, 969, 3, 112, 56, 0, 968, 965, 1, 0, 0, 0, 968, 966, 1, 0, 0, 0, 968, 967, 1, 0, 0, 0, 969, 119, 1, 0, 0, 0, 970, 971, 5, 200, 0, 0, 971, 972, 5, 212, 0, 0, 972, 973, 3, 106, 53, 0, 973, 121, 1, 0, 0, 0, 974, 975, 5, 218, 0, 0, 975, 976, 3, 118, 59, 0, 976, 977, 5, 234, 0, 0, 977, 123, 1, 0, 0, 0, 120, 127, 137, 146, 149, 153, 156, 160, 163, 166, 169, 172, 176, 180, 183, 186, 189, 193, 196, 205, 211, 232, 249, 266, 272, 278, 289, 291, 302, 305, 311, 319, 325, 327, 331, 336, 339, 342, 346, 350, 353, 355, 358, 362, 366, 369, 371, 373, 378, 389, 395, 402, 407, 411, 415, 421, 423, 430, 438, 441, 444, 463, 477, 493, 505, 517, 525, 529, 536, 542, 551, 555, 586, 603, 615, 625, 628, 632, 635, 648, 665, 669, 675, 682, 694, 698, 701, 710, 724, 751, 760, 762, 764, 772, 777, 785, 795, 798, 808, 819, 824, 831, 844, 851, 864, 870, 873, 880, 892, 898, 902, 908, 915, 924, 935, 937, 940, 948, 953, 963, 968]
\ No newline at end of file
+[4, 1, 242, 972, 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, 1, 0, 1, 0, 1, 0, 3, 0, 128, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 136, 8, 1, 10, 1, 12, 1, 139, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 147, 8, 2, 1, 3, 3, 3, 150, 8, 3, 1, 3, 1, 3, 3, 3, 154, 8, 3, 1, 3, 3, 3, 157, 8, 3, 1, 3, 1, 3, 3, 3, 161, 8, 3, 1, 3, 3, 3, 164, 8, 3, 1, 3, 3, 3, 167, 8, 3, 1, 3, 3, 3, 170, 8, 3, 1, 3, 3, 3, 173, 8, 3, 1, 3, 1, 3, 3, 3, 177, 8, 3, 1, 3, 1, 3, 3, 3, 181, 8, 3, 1, 3, 3, 3, 184, 8, 3, 1, 3, 3, 3, 187, 8, 3, 1, 3, 3, 3, 190, 8, 3, 1, 3, 1, 3, 3, 3, 194, 8, 3, 1, 3, 3, 3, 197, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 206, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 3, 7, 212, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 5, 8, 231, 8, 8, 10, 8, 12, 8, 234, 9, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 250, 8, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 267, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 273, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 279, 8, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 290, 8, 15, 3, 15, 292, 8, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 3, 18, 303, 8, 18, 1, 18, 3, 18, 306, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 312, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 320, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 326, 8, 18, 10, 18, 12, 18, 329, 9, 18, 1, 19, 3, 19, 332, 8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 337, 8, 19, 1, 19, 3, 19, 340, 8, 19, 1, 19, 3, 19, 343, 8, 19, 1, 19, 1, 19, 3, 19, 347, 8, 19, 1, 19, 1, 19, 3, 19, 351, 8, 19, 1, 19, 3, 19, 354, 8, 19, 3, 19, 356, 8, 19, 1, 19, 3, 19, 359, 8, 19, 1, 19, 1, 19, 3, 19, 363, 8, 19, 1, 19, 1, 19, 3, 19, 367, 8, 19, 1, 19, 3, 19, 370, 8, 19, 3, 19, 372, 8, 19, 3, 19, 374, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 379, 8, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 390, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 396, 8, 22, 1, 23, 1, 23, 1, 23, 5, 23, 401, 8, 23, 10, 23, 12, 23, 404, 9, 23, 1, 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, 25, 1, 25, 1, 25, 1, 25, 3, 25, 422, 8, 25, 3, 25, 424, 8, 25, 1, 26, 1, 26, 1, 26, 5, 26, 429, 8, 26, 10, 26, 12, 26, 432, 9, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 3, 28, 439, 8, 28, 1, 28, 3, 28, 442, 8, 28, 1, 28, 3, 28, 445, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 464, 8, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 478, 8, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 492, 8, 35, 10, 35, 12, 35, 495, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 504, 8, 35, 10, 35, 12, 35, 507, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 516, 8, 35, 10, 35, 12, 35, 519, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 3, 35, 526, 8, 35, 1, 35, 1, 35, 3, 35, 530, 8, 35, 1, 36, 1, 36, 1, 36, 5, 36, 535, 8, 36, 10, 36, 12, 36, 538, 9, 36, 1, 37, 1, 37, 1, 37, 3, 37, 543, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 550, 8, 37, 11, 37, 12, 37, 551, 1, 37, 1, 37, 3, 37, 556, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 580, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 597, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 609, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 619, 8, 37, 1, 37, 3, 37, 622, 8, 37, 1, 37, 1, 37, 3, 37, 626, 8, 37, 1, 37, 3, 37, 629, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 642, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 659, 8, 37, 1, 37, 1, 37, 3, 37, 663, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 669, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 676, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 688, 8, 37, 1, 37, 1, 37, 3, 37, 692, 8, 37, 1, 37, 3, 37, 695, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 704, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 718, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 745, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 754, 8, 37, 5, 37, 756, 8, 37, 10, 37, 12, 37, 759, 9, 37, 1, 38, 1, 38, 1, 38, 5, 38, 764, 8, 38, 10, 38, 12, 38, 767, 9, 38, 1, 39, 1, 39, 3, 39, 771, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 777, 8, 40, 10, 40, 12, 40, 780, 9, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 787, 8, 40, 10, 40, 12, 40, 790, 9, 40, 3, 40, 792, 8, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 5, 41, 800, 8, 41, 10, 41, 12, 41, 803, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 811, 8, 41, 10, 41, 12, 41, 814, 9, 41, 1, 41, 1, 41, 3, 41, 818, 8, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 825, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 838, 8, 42, 1, 43, 1, 43, 1, 43, 5, 43, 843, 8, 43, 10, 43, 12, 43, 846, 9, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 858, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 3, 45, 864, 8, 45, 1, 45, 3, 45, 867, 8, 45, 1, 46, 1, 46, 1, 46, 5, 46, 872, 8, 46, 10, 46, 12, 46, 875, 9, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 886, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 892, 8, 47, 5, 47, 894, 8, 47, 10, 47, 12, 47, 897, 9, 47, 1, 48, 1, 48, 1, 48, 3, 48, 902, 8, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 3, 49, 909, 8, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 5, 50, 916, 8, 50, 10, 50, 12, 50, 919, 9, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 929, 8, 52, 3, 52, 931, 8, 52, 1, 53, 3, 53, 934, 8, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 942, 8, 53, 1, 54, 1, 54, 1, 54, 3, 54, 947, 8, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 3, 58, 957, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 962, 8, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 0, 3, 36, 74, 94, 62, 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, 0, 16, 2, 0, 32, 32, 141, 141, 2, 0, 84, 84, 96, 96, 3, 0, 4, 4, 8, 8, 12, 12, 4, 0, 4, 4, 7, 8, 12, 12, 147, 147, 2, 0, 96, 96, 140, 140, 2, 0, 4, 4, 8, 8, 2, 0, 11, 11, 42, 43, 2, 0, 62, 62, 93, 93, 2, 0, 133, 133, 143, 143, 3, 0, 17, 17, 95, 95, 170, 170, 2, 0, 79, 79, 98, 98, 1, 0, 197, 198, 2, 0, 208, 208, 228, 228, 8, 0, 37, 37, 76, 76, 108, 108, 110, 110, 132, 132, 145, 145, 185, 185, 190, 190, 13, 0, 2, 24, 26, 36, 38, 75, 77, 81, 83, 107, 109, 109, 111, 112, 114, 115, 117, 130, 133, 144, 146, 184, 186, 189, 191, 192, 4, 0, 36, 36, 62, 62, 77, 77, 91, 91, 1099, 0, 127, 1, 0, 0, 0, 2, 131, 1, 0, 0, 0, 4, 146, 1, 0, 0, 0, 6, 149, 1, 0, 0, 0, 8, 198, 1, 0, 0, 0, 10, 201, 1, 0, 0, 0, 12, 207, 1, 0, 0, 0, 14, 211, 1, 0, 0, 0, 16, 217, 1, 0, 0, 0, 18, 235, 1, 0, 0, 0, 20, 238, 1, 0, 0, 0, 22, 241, 1, 0, 0, 0, 24, 251, 1, 0, 0, 0, 26, 254, 1, 0, 0, 0, 28, 258, 1, 0, 0, 0, 30, 291, 1, 0, 0, 0, 32, 293, 1, 0, 0, 0, 34, 296, 1, 0, 0, 0, 36, 311, 1, 0, 0, 0, 38, 373, 1, 0, 0, 0, 40, 378, 1, 0, 0, 0, 42, 389, 1, 0, 0, 0, 44, 391, 1, 0, 0, 0, 46, 397, 1, 0, 0, 0, 48, 405, 1, 0, 0, 0, 50, 423, 1, 0, 0, 0, 52, 425, 1, 0, 0, 0, 54, 433, 1, 0, 0, 0, 56, 438, 1, 0, 0, 0, 58, 446, 1, 0, 0, 0, 60, 450, 1, 0, 0, 0, 62, 454, 1, 0, 0, 0, 64, 463, 1, 0, 0, 0, 66, 477, 1, 0, 0, 0, 68, 479, 1, 0, 0, 0, 70, 529, 1, 0, 0, 0, 72, 531, 1, 0, 0, 0, 74, 662, 1, 0, 0, 0, 76, 760, 1, 0, 0, 0, 78, 770, 1, 0, 0, 0, 80, 791, 1, 0, 0, 0, 82, 824, 1, 0, 0, 0, 84, 837, 1, 0, 0, 0, 86, 839, 1, 0, 0, 0, 88, 857, 1, 0, 0, 0, 90, 866, 1, 0, 0, 0, 92, 868, 1, 0, 0, 0, 94, 885, 1, 0, 0, 0, 96, 898, 1, 0, 0, 0, 98, 908, 1, 0, 0, 0, 100, 912, 1, 0, 0, 0, 102, 920, 1, 0, 0, 0, 104, 930, 1, 0, 0, 0, 106, 933, 1, 0, 0, 0, 108, 946, 1, 0, 0, 0, 110, 948, 1, 0, 0, 0, 112, 950, 1, 0, 0, 0, 114, 952, 1, 0, 0, 0, 116, 956, 1, 0, 0, 0, 118, 961, 1, 0, 0, 0, 120, 963, 1, 0, 0, 0, 122, 967, 1, 0, 0, 0, 124, 128, 3, 2, 1, 0, 125, 128, 3, 6, 3, 0, 126, 128, 3, 82, 41, 0, 127, 124, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 130, 5, 0, 0, 1, 130, 1, 1, 0, 0, 0, 131, 137, 3, 4, 2, 0, 132, 133, 5, 176, 0, 0, 133, 134, 5, 4, 0, 0, 134, 136, 3, 4, 2, 0, 135, 132, 1, 0, 0, 0, 136, 139, 1, 0, 0, 0, 137, 135, 1, 0, 0, 0, 137, 138, 1, 0, 0, 0, 138, 3, 1, 0, 0, 0, 139, 137, 1, 0, 0, 0, 140, 147, 3, 6, 3, 0, 141, 142, 5, 220, 0, 0, 142, 143, 3, 2, 1, 0, 143, 144, 5, 236, 0, 0, 144, 147, 1, 0, 0, 0, 145, 147, 3, 122, 61, 0, 146, 140, 1, 0, 0, 0, 146, 141, 1, 0, 0, 0, 146, 145, 1, 0, 0, 0, 147, 5, 1, 0, 0, 0, 148, 150, 3, 8, 4, 0, 149, 148, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 153, 5, 146, 0, 0, 152, 154, 5, 49, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 156, 1, 0, 0, 0, 155, 157, 3, 10, 5, 0, 156, 155, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 160, 3, 72, 36, 0, 159, 161, 3, 12, 6, 0, 160, 159, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 163, 1, 0, 0, 0, 162, 164, 3, 14, 7, 0, 163, 162, 1, 0, 0, 0, 163, 164, 1, 0, 0, 0, 164, 166, 1, 0, 0, 0, 165, 167, 3, 18, 9, 0, 166, 165, 1, 0, 0, 0, 166, 167, 1, 0, 0, 0, 167, 169, 1, 0, 0, 0, 168, 170, 3, 20, 10, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 172, 1, 0, 0, 0, 171, 173, 3, 22, 11, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 175, 5, 189, 0, 0, 175, 177, 7, 0, 0, 0, 176, 174, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 180, 1, 0, 0, 0, 178, 179, 5, 189, 0, 0, 179, 181, 5, 169, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 183, 1, 0, 0, 0, 182, 184, 3, 24, 12, 0, 183, 182, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 187, 3, 16, 8, 0, 186, 185, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 190, 3, 26, 13, 0, 189, 188, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 194, 3, 30, 15, 0, 192, 194, 3, 32, 16, 0, 193, 191, 1, 0, 0, 0, 193, 192, 1, 0, 0, 0, 193, 194, 1, 0, 0, 0, 194, 196, 1, 0, 0, 0, 195, 197, 3, 34, 17, 0, 196, 195, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 7, 1, 0, 0, 0, 198, 199, 5, 189, 0, 0, 199, 200, 3, 86, 43, 0, 200, 9, 1, 0, 0, 0, 201, 202, 5, 168, 0, 0, 202, 205, 5, 198, 0, 0, 203, 204, 5, 189, 0, 0, 204, 206, 5, 164, 0, 0, 205, 203, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 11, 1, 0, 0, 0, 207, 208, 5, 68, 0, 0, 208, 209, 3, 36, 18, 0, 209, 13, 1, 0, 0, 0, 210, 212, 7, 1, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 5, 9, 0, 0, 214, 215, 5, 90, 0, 0, 215, 216, 3, 72, 36, 0, 216, 15, 1, 0, 0, 0, 217, 218, 5, 188, 0, 0, 218, 219, 3, 118, 59, 0, 219, 220, 5, 10, 0, 0, 220, 221, 5, 220, 0, 0, 221, 222, 3, 56, 28, 0, 222, 232, 5, 236, 0, 0, 223, 224, 5, 206, 0, 0, 224, 225, 3, 118, 59, 0, 225, 226, 5, 10, 0, 0, 226, 227, 5, 220, 0, 0, 227, 228, 3, 56, 28, 0, 228, 229, 5, 236, 0, 0, 229, 231, 1, 0, 0, 0, 230, 223, 1, 0, 0, 0, 231, 234, 1, 0, 0, 0, 232, 230, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 17, 1, 0, 0, 0, 234, 232, 1, 0, 0, 0, 235, 236, 5, 129, 0, 0, 236, 237, 3, 74, 37, 0, 237, 19, 1, 0, 0, 0, 238, 239, 5, 187, 0, 0, 239, 240, 3, 74, 37, 0, 240, 21, 1, 0, 0, 0, 241, 242, 5, 73, 0, 0, 242, 249, 5, 18, 0, 0, 243, 244, 7, 0, 0, 0, 244, 245, 5, 220, 0, 0, 245, 246, 3, 72, 36, 0, 246, 247, 5, 236, 0, 0, 247, 250, 1, 0, 0, 0, 248, 250, 3, 72, 36, 0, 249, 243, 1, 0, 0, 0, 249, 248, 1, 0, 0, 0, 250, 23, 1, 0, 0, 0, 251, 252, 5, 74, 0, 0, 252, 253, 3, 74, 37, 0, 253, 25, 1, 0, 0, 0, 254, 255, 5, 122, 0, 0, 255, 256, 5, 18, 0, 0, 256, 257, 3, 46, 23, 0, 257, 27, 1, 0, 0, 0, 258, 259, 5, 122, 0, 0, 259, 260, 5, 18, 0, 0, 260, 261, 3, 72, 36, 0, 261, 29, 1, 0, 0, 0, 262, 263, 5, 99, 0, 0, 263, 266, 3, 74, 37, 0, 264, 265, 5, 206, 0, 0, 265, 267, 3, 74, 37, 0, 266, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 272, 1, 0, 0, 0, 268, 269, 5, 189, 0, 0, 269, 273, 5, 164, 0, 0, 270, 271, 5, 18, 0, 0, 271, 273, 3, 72, 36, 0, 272, 268, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 292, 1, 0, 0, 0, 274, 275, 5, 99, 0, 0, 275, 278, 3, 74, 37, 0, 276, 277, 5, 189, 0, 0, 277, 279, 5, 164, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 5, 118, 0, 0, 281, 282, 3, 74, 37, 0, 282, 292, 1, 0, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 3, 74, 37, 0, 285, 286, 5, 118, 0, 0, 286, 289, 3, 74, 37, 0, 287, 288, 5, 18, 0, 0, 288, 290, 3, 72, 36, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 292, 1, 0, 0, 0, 291, 262, 1, 0, 0, 0, 291, 274, 1, 0, 0, 0, 291, 283, 1, 0, 0, 0, 292, 31, 1, 0, 0, 0, 293, 294, 5, 118, 0, 0, 294, 295, 3, 74, 37, 0, 295, 33, 1, 0, 0, 0, 296, 297, 5, 150, 0, 0, 297, 298, 3, 52, 26, 0, 298, 35, 1, 0, 0, 0, 299, 300, 6, 18, -1, 0, 300, 302, 3, 94, 47, 0, 301, 303, 5, 61, 0, 0, 302, 301, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 305, 1, 0, 0, 0, 304, 306, 3, 44, 22, 0, 305, 304, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 312, 1, 0, 0, 0, 307, 308, 5, 220, 0, 0, 308, 309, 3, 36, 18, 0, 309, 310, 5, 236, 0, 0, 310, 312, 1, 0, 0, 0, 311, 299, 1, 0, 0, 0, 311, 307, 1, 0, 0, 0, 312, 327, 1, 0, 0, 0, 313, 314, 10, 3, 0, 0, 314, 315, 3, 40, 20, 0, 315, 316, 3, 36, 18, 4, 316, 326, 1, 0, 0, 0, 317, 319, 10, 4, 0, 0, 318, 320, 3, 38, 19, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 90, 0, 0, 322, 323, 3, 36, 18, 0, 323, 324, 3, 42, 21, 0, 324, 326, 1, 0, 0, 0, 325, 313, 1, 0, 0, 0, 325, 317, 1, 0, 0, 0, 326, 329, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 37, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 330, 332, 7, 2, 0, 0, 331, 330, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 340, 5, 84, 0, 0, 334, 336, 5, 84, 0, 0, 335, 337, 7, 2, 0, 0, 336, 335, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 340, 1, 0, 0, 0, 338, 340, 7, 2, 0, 0, 339, 331, 1, 0, 0, 0, 339, 334, 1, 0, 0, 0, 339, 338, 1, 0, 0, 0, 340, 374, 1, 0, 0, 0, 341, 343, 7, 3, 0, 0, 342, 341, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 344, 1, 0, 0, 0, 344, 346, 7, 4, 0, 0, 345, 347, 5, 123, 0, 0, 346, 345, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 347, 356, 1, 0, 0, 0, 348, 350, 7, 4, 0, 0, 349, 351, 5, 123, 0, 0, 350, 349, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 353, 1, 0, 0, 0, 352, 354, 7, 3, 0, 0, 353, 352, 1, 0, 0, 0, 353, 354, 1, 0, 0, 0, 354, 356, 1, 0, 0, 0, 355, 342, 1, 0, 0, 0, 355, 348, 1, 0, 0, 0, 356, 374, 1, 0, 0, 0, 357, 359, 7, 5, 0, 0, 358, 357, 1, 0, 0, 0, 358, 359, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 362, 5, 69, 0, 0, 361, 363, 5, 123, 0, 0, 362, 361, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 372, 1, 0, 0, 0, 364, 366, 5, 69, 0, 0, 365, 367, 5, 123, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 369, 1, 0, 0, 0, 368, 370, 7, 5, 0, 0, 369, 368, 1, 0, 0, 0, 369, 370, 1, 0, 0, 0, 370, 372, 1, 0, 0, 0, 371, 358, 1, 0, 0, 0, 371, 364, 1, 0, 0, 0, 372, 374, 1, 0, 0, 0, 373, 339, 1, 0, 0, 0, 373, 355, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 374, 39, 1, 0, 0, 0, 375, 376, 5, 31, 0, 0, 376, 379, 5, 90, 0, 0, 377, 379, 5, 206, 0, 0, 378, 375, 1, 0, 0, 0, 378, 377, 1, 0, 0, 0, 379, 41, 1, 0, 0, 0, 380, 381, 5, 119, 0, 0, 381, 390, 3, 72, 36, 0, 382, 383, 5, 179, 0, 0, 383, 384, 5, 220, 0, 0, 384, 385, 3, 72, 36, 0, 385, 386, 5, 236, 0, 0, 386, 390, 1, 0, 0, 0, 387, 388, 5, 179, 0, 0, 388, 390, 3, 72, 36, 0, 389, 380, 1, 0, 0, 0, 389, 382, 1, 0, 0, 0, 389, 387, 1, 0, 0, 0, 390, 43, 1, 0, 0, 0, 391, 392, 5, 144, 0, 0, 392, 395, 3, 50, 25, 0, 393, 394, 5, 118, 0, 0, 394, 396, 3, 50, 25, 0, 395, 393, 1, 0, 0, 0, 395, 396, 1, 0, 0, 0, 396, 45, 1, 0, 0, 0, 397, 402, 3, 48, 24, 0, 398, 399, 5, 206, 0, 0, 399, 401, 3, 48, 24, 0, 400, 398, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 47, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 405, 407, 3, 74, 37, 0, 406, 408, 7, 6, 0, 0, 407, 406, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 411, 1, 0, 0, 0, 409, 410, 5, 117, 0, 0, 410, 412, 7, 7, 0, 0, 411, 409, 1, 0, 0, 0, 411, 412, 1, 0, 0, 0, 412, 415, 1, 0, 0, 0, 413, 414, 5, 26, 0, 0, 414, 416, 5, 200, 0, 0, 415, 413, 1, 0, 0, 0, 415, 416, 1, 0, 0, 0, 416, 49, 1, 0, 0, 0, 417, 424, 3, 122, 61, 0, 418, 421, 3, 106, 53, 0, 419, 420, 5, 238, 0, 0, 420, 422, 3, 106, 53, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 417, 1, 0, 0, 0, 423, 418, 1, 0, 0, 0, 424, 51, 1, 0, 0, 0, 425, 430, 3, 54, 27, 0, 426, 427, 5, 206, 0, 0, 427, 429, 3, 54, 27, 0, 428, 426, 1, 0, 0, 0, 429, 432, 1, 0, 0, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 53, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 433, 434, 3, 118, 59, 0, 434, 435, 5, 212, 0, 0, 435, 436, 3, 108, 54, 0, 436, 55, 1, 0, 0, 0, 437, 439, 3, 58, 29, 0, 438, 437, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 441, 1, 0, 0, 0, 440, 442, 3, 60, 30, 0, 441, 440, 1, 0, 0, 0, 441, 442, 1, 0, 0, 0, 442, 444, 1, 0, 0, 0, 443, 445, 3, 62, 31, 0, 444, 443, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, 57, 1, 0, 0, 0, 446, 447, 5, 126, 0, 0, 447, 448, 5, 18, 0, 0, 448, 449, 3, 72, 36, 0, 449, 59, 1, 0, 0, 0, 450, 451, 5, 122, 0, 0, 451, 452, 5, 18, 0, 0, 452, 453, 3, 46, 23, 0, 453, 61, 1, 0, 0, 0, 454, 455, 7, 8, 0, 0, 455, 456, 3, 64, 32, 0, 456, 63, 1, 0, 0, 0, 457, 464, 3, 66, 33, 0, 458, 459, 5, 16, 0, 0, 459, 460, 3, 66, 33, 0, 460, 461, 5, 6, 0, 0, 461, 462, 3, 66, 33, 0, 462, 464, 1, 0, 0, 0, 463, 457, 1, 0, 0, 0, 463, 458, 1, 0, 0, 0, 464, 65, 1, 0, 0, 0, 465, 466, 5, 33, 0, 0, 466, 478, 5, 142, 0, 0, 467, 468, 5, 175, 0, 0, 468, 478, 5, 128, 0, 0, 469, 470, 5, 175, 0, 0, 470, 478, 5, 64, 0, 0, 471, 472, 3, 106, 53, 0, 472, 473, 5, 128, 0, 0, 473, 478, 1, 0, 0, 0, 474, 475, 3, 106, 53, 0, 475, 476, 5, 64, 0, 0, 476, 478, 1, 0, 0, 0, 477, 465, 1, 0, 0, 0, 477, 467, 1, 0, 0, 0, 477, 469, 1, 0, 0, 0, 477, 471, 1, 0, 0, 0, 477, 474, 1, 0, 0, 0, 478, 67, 1, 0, 0, 0, 479, 480, 3, 74, 37, 0, 480, 481, 5, 0, 0, 1, 481, 69, 1, 0, 0, 0, 482, 530, 3, 118, 59, 0, 483, 484, 3, 118, 59, 0, 484, 485, 5, 220, 0, 0, 485, 486, 3, 118, 59, 0, 486, 493, 3, 70, 35, 0, 487, 488, 5, 206, 0, 0, 488, 489, 3, 118, 59, 0, 489, 490, 3, 70, 35, 0, 490, 492, 1, 0, 0, 0, 491, 487, 1, 0, 0, 0, 492, 495, 1, 0, 0, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 496, 1, 0, 0, 0, 495, 493, 1, 0, 0, 0, 496, 497, 5, 236, 0, 0, 497, 530, 1, 0, 0, 0, 498, 499, 3, 118, 59, 0, 499, 500, 5, 220, 0, 0, 500, 505, 3, 120, 60, 0, 501, 502, 5, 206, 0, 0, 502, 504, 3, 120, 60, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 508, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 509, 5, 236, 0, 0, 509, 530, 1, 0, 0, 0, 510, 511, 3, 118, 59, 0, 511, 512, 5, 220, 0, 0, 512, 517, 3, 70, 35, 0, 513, 514, 5, 206, 0, 0, 514, 516, 3, 70, 35, 0, 515, 513, 1, 0, 0, 0, 516, 519, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 518, 1, 0, 0, 0, 518, 520, 1, 0, 0, 0, 519, 517, 1, 0, 0, 0, 520, 521, 5, 236, 0, 0, 521, 530, 1, 0, 0, 0, 522, 523, 3, 118, 59, 0, 523, 525, 5, 220, 0, 0, 524, 526, 3, 72, 36, 0, 525, 524, 1, 0, 0, 0, 525, 526, 1, 0, 0, 0, 526, 527, 1, 0, 0, 0, 527, 528, 5, 236, 0, 0, 528, 530, 1, 0, 0, 0, 529, 482, 1, 0, 0, 0, 529, 483, 1, 0, 0, 0, 529, 498, 1, 0, 0, 0, 529, 510, 1, 0, 0, 0, 529, 522, 1, 0, 0, 0, 530, 71, 1, 0, 0, 0, 531, 536, 3, 74, 37, 0, 532, 533, 5, 206, 0, 0, 533, 535, 3, 74, 37, 0, 534, 532, 1, 0, 0, 0, 535, 538, 1, 0, 0, 0, 536, 534, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 537, 73, 1, 0, 0, 0, 538, 536, 1, 0, 0, 0, 539, 540, 6, 37, -1, 0, 540, 542, 5, 19, 0, 0, 541, 543, 3, 74, 37, 0, 542, 541, 1, 0, 0, 0, 542, 543, 1, 0, 0, 0, 543, 549, 1, 0, 0, 0, 544, 545, 5, 186, 0, 0, 545, 546, 3, 74, 37, 0, 546, 547, 5, 163, 0, 0, 547, 548, 3, 74, 37, 0, 548, 550, 1, 0, 0, 0, 549, 544, 1, 0, 0, 0, 550, 551, 1, 0, 0, 0, 551, 549, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 555, 1, 0, 0, 0, 553, 554, 5, 52, 0, 0, 554, 556, 3, 74, 37, 0, 555, 553, 1, 0, 0, 0, 555, 556, 1, 0, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 5, 53, 0, 0, 558, 663, 1, 0, 0, 0, 559, 560, 5, 20, 0, 0, 560, 561, 5, 220, 0, 0, 561, 562, 3, 74, 37, 0, 562, 563, 5, 10, 0, 0, 563, 564, 3, 70, 35, 0, 564, 565, 5, 236, 0, 0, 565, 663, 1, 0, 0, 0, 566, 567, 5, 36, 0, 0, 567, 663, 5, 200, 0, 0, 568, 569, 5, 86, 0, 0, 569, 570, 3, 74, 37, 0, 570, 571, 3, 110, 55, 0, 571, 663, 1, 0, 0, 0, 572, 573, 5, 155, 0, 0, 573, 574, 5, 220, 0, 0, 574, 575, 3, 74, 37, 0, 575, 576, 5, 68, 0, 0, 576, 579, 3, 74, 37, 0, 577, 578, 5, 65, 0, 0, 578, 580, 3, 74, 37, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 582, 5, 236, 0, 0, 582, 663, 1, 0, 0, 0, 583, 584, 5, 166, 0, 0, 584, 663, 5, 200, 0, 0, 585, 586, 5, 171, 0, 0, 586, 587, 5, 220, 0, 0, 587, 588, 7, 9, 0, 0, 588, 589, 5, 200, 0, 0, 589, 590, 5, 68, 0, 0, 590, 591, 3, 74, 37, 0, 591, 592, 5, 236, 0, 0, 592, 663, 1, 0, 0, 0, 593, 594, 3, 118, 59, 0, 594, 596, 5, 220, 0, 0, 595, 597, 3, 72, 36, 0, 596, 595, 1, 0, 0, 0, 596, 597, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 599, 5, 236, 0, 0, 599, 600, 1, 0, 0, 0, 600, 601, 5, 125, 0, 0, 601, 602, 5, 220, 0, 0, 602, 603, 3, 56, 28, 0, 603, 604, 5, 236, 0, 0, 604, 663, 1, 0, 0, 0, 605, 606, 3, 118, 59, 0, 606, 608, 5, 220, 0, 0, 607, 609, 3, 72, 36, 0, 608, 607, 1, 0, 0, 0, 608, 609, 1, 0, 0, 0, 609, 610, 1, 0, 0, 0, 610, 611, 5, 236, 0, 0, 611, 612, 1, 0, 0, 0, 612, 613, 5, 125, 0, 0, 613, 614, 3, 118, 59, 0, 614, 663, 1, 0, 0, 0, 615, 621, 3, 118, 59, 0, 616, 618, 5, 220, 0, 0, 617, 619, 3, 72, 36, 0, 618, 617, 1, 0, 0, 0, 618, 619, 1, 0, 0, 0, 619, 620, 1, 0, 0, 0, 620, 622, 5, 236, 0, 0, 621, 616, 1, 0, 0, 0, 621, 622, 1, 0, 0, 0, 622, 623, 1, 0, 0, 0, 623, 625, 5, 220, 0, 0, 624, 626, 5, 49, 0, 0, 625, 624, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 628, 1, 0, 0, 0, 627, 629, 3, 76, 38, 0, 628, 627, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 631, 5, 236, 0, 0, 631, 663, 1, 0, 0, 0, 632, 663, 3, 82, 41, 0, 633, 663, 3, 108, 54, 0, 634, 635, 5, 208, 0, 0, 635, 663, 3, 74, 37, 18, 636, 637, 5, 115, 0, 0, 637, 663, 3, 74, 37, 12, 638, 639, 3, 98, 49, 0, 639, 640, 5, 210, 0, 0, 640, 642, 1, 0, 0, 0, 641, 638, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 663, 5, 202, 0, 0, 644, 645, 5, 220, 0, 0, 645, 646, 3, 2, 1, 0, 646, 647, 5, 236, 0, 0, 647, 663, 1, 0, 0, 0, 648, 649, 5, 220, 0, 0, 649, 650, 3, 74, 37, 0, 650, 651, 5, 236, 0, 0, 651, 663, 1, 0, 0, 0, 652, 653, 5, 220, 0, 0, 653, 654, 3, 72, 36, 0, 654, 655, 5, 236, 0, 0, 655, 663, 1, 0, 0, 0, 656, 658, 5, 219, 0, 0, 657, 659, 3, 72, 36, 0, 658, 657, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 660, 1, 0, 0, 0, 660, 663, 5, 235, 0, 0, 661, 663, 3, 90, 45, 0, 662, 539, 1, 0, 0, 0, 662, 559, 1, 0, 0, 0, 662, 566, 1, 0, 0, 0, 662, 568, 1, 0, 0, 0, 662, 572, 1, 0, 0, 0, 662, 583, 1, 0, 0, 0, 662, 585, 1, 0, 0, 0, 662, 593, 1, 0, 0, 0, 662, 605, 1, 0, 0, 0, 662, 615, 1, 0, 0, 0, 662, 632, 1, 0, 0, 0, 662, 633, 1, 0, 0, 0, 662, 634, 1, 0, 0, 0, 662, 636, 1, 0, 0, 0, 662, 641, 1, 0, 0, 0, 662, 644, 1, 0, 0, 0, 662, 648, 1, 0, 0, 0, 662, 652, 1, 0, 0, 0, 662, 656, 1, 0, 0, 0, 662, 661, 1, 0, 0, 0, 663, 757, 1, 0, 0, 0, 664, 668, 10, 17, 0, 0, 665, 669, 5, 202, 0, 0, 666, 669, 5, 238, 0, 0, 667, 669, 5, 227, 0, 0, 668, 665, 1, 0, 0, 0, 668, 666, 1, 0, 0, 0, 668, 667, 1, 0, 0, 0, 669, 670, 1, 0, 0, 0, 670, 756, 3, 74, 37, 18, 671, 675, 10, 16, 0, 0, 672, 676, 5, 228, 0, 0, 673, 676, 5, 208, 0, 0, 674, 676, 5, 207, 0, 0, 675, 672, 1, 0, 0, 0, 675, 673, 1, 0, 0, 0, 675, 674, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 756, 3, 74, 37, 17, 678, 703, 10, 15, 0, 0, 679, 704, 5, 211, 0, 0, 680, 704, 5, 212, 0, 0, 681, 704, 5, 223, 0, 0, 682, 704, 5, 221, 0, 0, 683, 704, 5, 222, 0, 0, 684, 704, 5, 213, 0, 0, 685, 704, 5, 214, 0, 0, 686, 688, 5, 115, 0, 0, 687, 686, 1, 0, 0, 0, 687, 688, 1, 0, 0, 0, 688, 689, 1, 0, 0, 0, 689, 691, 5, 80, 0, 0, 690, 692, 5, 25, 0, 0, 691, 690, 1, 0, 0, 0, 691, 692, 1, 0, 0, 0, 692, 704, 1, 0, 0, 0, 693, 695, 5, 115, 0, 0, 694, 693, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 696, 1, 0, 0, 0, 696, 704, 7, 10, 0, 0, 697, 704, 5, 232, 0, 0, 698, 704, 5, 233, 0, 0, 699, 704, 5, 225, 0, 0, 700, 704, 5, 216, 0, 0, 701, 704, 5, 217, 0, 0, 702, 704, 5, 224, 0, 0, 703, 679, 1, 0, 0, 0, 703, 680, 1, 0, 0, 0, 703, 681, 1, 0, 0, 0, 703, 682, 1, 0, 0, 0, 703, 683, 1, 0, 0, 0, 703, 684, 1, 0, 0, 0, 703, 685, 1, 0, 0, 0, 703, 687, 1, 0, 0, 0, 703, 694, 1, 0, 0, 0, 703, 697, 1, 0, 0, 0, 703, 698, 1, 0, 0, 0, 703, 699, 1, 0, 0, 0, 703, 700, 1, 0, 0, 0, 703, 701, 1, 0, 0, 0, 703, 702, 1, 0, 0, 0, 704, 705, 1, 0, 0, 0, 705, 756, 3, 74, 37, 16, 706, 707, 10, 13, 0, 0, 707, 708, 5, 226, 0, 0, 708, 756, 3, 74, 37, 14, 709, 710, 10, 11, 0, 0, 710, 711, 5, 6, 0, 0, 711, 756, 3, 74, 37, 12, 712, 713, 10, 10, 0, 0, 713, 714, 5, 121, 0, 0, 714, 756, 3, 74, 37, 11, 715, 717, 10, 9, 0, 0, 716, 718, 5, 115, 0, 0, 717, 716, 1, 0, 0, 0, 717, 718, 1, 0, 0, 0, 718, 719, 1, 0, 0, 0, 719, 720, 5, 16, 0, 0, 720, 721, 3, 74, 37, 0, 721, 722, 5, 6, 0, 0, 722, 723, 3, 74, 37, 10, 723, 756, 1, 0, 0, 0, 724, 725, 10, 8, 0, 0, 725, 726, 5, 229, 0, 0, 726, 727, 3, 74, 37, 0, 727, 728, 5, 205, 0, 0, 728, 729, 3, 74, 37, 8, 729, 756, 1, 0, 0, 0, 730, 731, 10, 21, 0, 0, 731, 732, 5, 219, 0, 0, 732, 733, 3, 74, 37, 0, 733, 734, 5, 235, 0, 0, 734, 756, 1, 0, 0, 0, 735, 736, 10, 20, 0, 0, 736, 737, 5, 210, 0, 0, 737, 756, 5, 198, 0, 0, 738, 739, 10, 19, 0, 0, 739, 740, 5, 210, 0, 0, 740, 756, 3, 118, 59, 0, 741, 742, 10, 14, 0, 0, 742, 744, 5, 88, 0, 0, 743, 745, 5, 115, 0, 0, 744, 743, 1, 0, 0, 0, 744, 745, 1, 0, 0, 0, 745, 746, 1, 0, 0, 0, 746, 756, 5, 116, 0, 0, 747, 753, 10, 7, 0, 0, 748, 754, 3, 116, 58, 0, 749, 750, 5, 10, 0, 0, 750, 754, 3, 118, 59, 0, 751, 752, 5, 10, 0, 0, 752, 754, 5, 200, 0, 0, 753, 748, 1, 0, 0, 0, 753, 749, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 754, 756, 1, 0, 0, 0, 755, 664, 1, 0, 0, 0, 755, 671, 1, 0, 0, 0, 755, 678, 1, 0, 0, 0, 755, 706, 1, 0, 0, 0, 755, 709, 1, 0, 0, 0, 755, 712, 1, 0, 0, 0, 755, 715, 1, 0, 0, 0, 755, 724, 1, 0, 0, 0, 755, 730, 1, 0, 0, 0, 755, 735, 1, 0, 0, 0, 755, 738, 1, 0, 0, 0, 755, 741, 1, 0, 0, 0, 755, 747, 1, 0, 0, 0, 756, 759, 1, 0, 0, 0, 757, 755, 1, 0, 0, 0, 757, 758, 1, 0, 0, 0, 758, 75, 1, 0, 0, 0, 759, 757, 1, 0, 0, 0, 760, 765, 3, 78, 39, 0, 761, 762, 5, 206, 0, 0, 762, 764, 3, 78, 39, 0, 763, 761, 1, 0, 0, 0, 764, 767, 1, 0, 0, 0, 765, 763, 1, 0, 0, 0, 765, 766, 1, 0, 0, 0, 766, 77, 1, 0, 0, 0, 767, 765, 1, 0, 0, 0, 768, 771, 3, 80, 40, 0, 769, 771, 3, 74, 37, 0, 770, 768, 1, 0, 0, 0, 770, 769, 1, 0, 0, 0, 771, 79, 1, 0, 0, 0, 772, 773, 5, 220, 0, 0, 773, 778, 3, 118, 59, 0, 774, 775, 5, 206, 0, 0, 775, 777, 3, 118, 59, 0, 776, 774, 1, 0, 0, 0, 777, 780, 1, 0, 0, 0, 778, 776, 1, 0, 0, 0, 778, 779, 1, 0, 0, 0, 779, 781, 1, 0, 0, 0, 780, 778, 1, 0, 0, 0, 781, 782, 5, 236, 0, 0, 782, 792, 1, 0, 0, 0, 783, 788, 3, 118, 59, 0, 784, 785, 5, 206, 0, 0, 785, 787, 3, 118, 59, 0, 786, 784, 1, 0, 0, 0, 787, 790, 1, 0, 0, 0, 788, 786, 1, 0, 0, 0, 788, 789, 1, 0, 0, 0, 789, 792, 1, 0, 0, 0, 790, 788, 1, 0, 0, 0, 791, 772, 1, 0, 0, 0, 791, 783, 1, 0, 0, 0, 792, 793, 1, 0, 0, 0, 793, 794, 5, 201, 0, 0, 794, 795, 3, 74, 37, 0, 795, 81, 1, 0, 0, 0, 796, 797, 5, 222, 0, 0, 797, 801, 3, 118, 59, 0, 798, 800, 3, 84, 42, 0, 799, 798, 1, 0, 0, 0, 800, 803, 1, 0, 0, 0, 801, 799, 1, 0, 0, 0, 801, 802, 1, 0, 0, 0, 802, 804, 1, 0, 0, 0, 803, 801, 1, 0, 0, 0, 804, 805, 5, 238, 0, 0, 805, 806, 5, 214, 0, 0, 806, 825, 1, 0, 0, 0, 807, 808, 5, 222, 0, 0, 808, 812, 3, 118, 59, 0, 809, 811, 3, 84, 42, 0, 810, 809, 1, 0, 0, 0, 811, 814, 1, 0, 0, 0, 812, 810, 1, 0, 0, 0, 812, 813, 1, 0, 0, 0, 813, 815, 1, 0, 0, 0, 814, 812, 1, 0, 0, 0, 815, 817, 5, 214, 0, 0, 816, 818, 3, 82, 41, 0, 817, 816, 1, 0, 0, 0, 817, 818, 1, 0, 0, 0, 818, 819, 1, 0, 0, 0, 819, 820, 5, 222, 0, 0, 820, 821, 5, 238, 0, 0, 821, 822, 3, 118, 59, 0, 822, 823, 5, 214, 0, 0, 823, 825, 1, 0, 0, 0, 824, 796, 1, 0, 0, 0, 824, 807, 1, 0, 0, 0, 825, 83, 1, 0, 0, 0, 826, 827, 3, 118, 59, 0, 827, 828, 5, 212, 0, 0, 828, 829, 5, 200, 0, 0, 829, 838, 1, 0, 0, 0, 830, 831, 3, 118, 59, 0, 831, 832, 5, 212, 0, 0, 832, 833, 5, 218, 0, 0, 833, 834, 3, 74, 37, 0, 834, 835, 5, 234, 0, 0, 835, 838, 1, 0, 0, 0, 836, 838, 3, 118, 59, 0, 837, 826, 1, 0, 0, 0, 837, 830, 1, 0, 0, 0, 837, 836, 1, 0, 0, 0, 838, 85, 1, 0, 0, 0, 839, 844, 3, 88, 44, 0, 840, 841, 5, 206, 0, 0, 841, 843, 3, 88, 44, 0, 842, 840, 1, 0, 0, 0, 843, 846, 1, 0, 0, 0, 844, 842, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 87, 1, 0, 0, 0, 846, 844, 1, 0, 0, 0, 847, 848, 3, 118, 59, 0, 848, 849, 5, 10, 0, 0, 849, 850, 5, 220, 0, 0, 850, 851, 3, 2, 1, 0, 851, 852, 5, 236, 0, 0, 852, 858, 1, 0, 0, 0, 853, 854, 3, 74, 37, 0, 854, 855, 5, 10, 0, 0, 855, 856, 3, 118, 59, 0, 856, 858, 1, 0, 0, 0, 857, 847, 1, 0, 0, 0, 857, 853, 1, 0, 0, 0, 858, 89, 1, 0, 0, 0, 859, 867, 3, 122, 61, 0, 860, 861, 3, 98, 49, 0, 861, 862, 5, 210, 0, 0, 862, 864, 1, 0, 0, 0, 863, 860, 1, 0, 0, 0, 863, 864, 1, 0, 0, 0, 864, 865, 1, 0, 0, 0, 865, 867, 3, 92, 46, 0, 866, 859, 1, 0, 0, 0, 866, 863, 1, 0, 0, 0, 867, 91, 1, 0, 0, 0, 868, 873, 3, 118, 59, 0, 869, 870, 5, 210, 0, 0, 870, 872, 3, 118, 59, 0, 871, 869, 1, 0, 0, 0, 872, 875, 1, 0, 0, 0, 873, 871, 1, 0, 0, 0, 873, 874, 1, 0, 0, 0, 874, 93, 1, 0, 0, 0, 875, 873, 1, 0, 0, 0, 876, 877, 6, 47, -1, 0, 877, 886, 3, 98, 49, 0, 878, 886, 3, 96, 48, 0, 879, 880, 5, 220, 0, 0, 880, 881, 3, 2, 1, 0, 881, 882, 5, 236, 0, 0, 882, 886, 1, 0, 0, 0, 883, 886, 3, 82, 41, 0, 884, 886, 3, 122, 61, 0, 885, 876, 1, 0, 0, 0, 885, 878, 1, 0, 0, 0, 885, 879, 1, 0, 0, 0, 885, 883, 1, 0, 0, 0, 885, 884, 1, 0, 0, 0, 886, 895, 1, 0, 0, 0, 887, 891, 10, 3, 0, 0, 888, 892, 3, 116, 58, 0, 889, 890, 5, 10, 0, 0, 890, 892, 3, 118, 59, 0, 891, 888, 1, 0, 0, 0, 891, 889, 1, 0, 0, 0, 892, 894, 1, 0, 0, 0, 893, 887, 1, 0, 0, 0, 894, 897, 1, 0, 0, 0, 895, 893, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 95, 1, 0, 0, 0, 897, 895, 1, 0, 0, 0, 898, 899, 3, 118, 59, 0, 899, 901, 5, 220, 0, 0, 900, 902, 3, 100, 50, 0, 901, 900, 1, 0, 0, 0, 901, 902, 1, 0, 0, 0, 902, 903, 1, 0, 0, 0, 903, 904, 5, 236, 0, 0, 904, 97, 1, 0, 0, 0, 905, 906, 3, 102, 51, 0, 906, 907, 5, 210, 0, 0, 907, 909, 1, 0, 0, 0, 908, 905, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 911, 3, 118, 59, 0, 911, 99, 1, 0, 0, 0, 912, 917, 3, 74, 37, 0, 913, 914, 5, 206, 0, 0, 914, 916, 3, 74, 37, 0, 915, 913, 1, 0, 0, 0, 916, 919, 1, 0, 0, 0, 917, 915, 1, 0, 0, 0, 917, 918, 1, 0, 0, 0, 918, 101, 1, 0, 0, 0, 919, 917, 1, 0, 0, 0, 920, 921, 3, 118, 59, 0, 921, 103, 1, 0, 0, 0, 922, 931, 5, 196, 0, 0, 923, 924, 5, 210, 0, 0, 924, 931, 7, 11, 0, 0, 925, 926, 5, 198, 0, 0, 926, 928, 5, 210, 0, 0, 927, 929, 7, 11, 0, 0, 928, 927, 1, 0, 0, 0, 928, 929, 1, 0, 0, 0, 929, 931, 1, 0, 0, 0, 930, 922, 1, 0, 0, 0, 930, 923, 1, 0, 0, 0, 930, 925, 1, 0, 0, 0, 931, 105, 1, 0, 0, 0, 932, 934, 7, 12, 0, 0, 933, 932, 1, 0, 0, 0, 933, 934, 1, 0, 0, 0, 934, 941, 1, 0, 0, 0, 935, 942, 3, 104, 52, 0, 936, 942, 5, 197, 0, 0, 937, 942, 5, 198, 0, 0, 938, 942, 5, 199, 0, 0, 939, 942, 5, 82, 0, 0, 940, 942, 5, 113, 0, 0, 941, 935, 1, 0, 0, 0, 941, 936, 1, 0, 0, 0, 941, 937, 1, 0, 0, 0, 941, 938, 1, 0, 0, 0, 941, 939, 1, 0, 0, 0, 941, 940, 1, 0, 0, 0, 942, 107, 1, 0, 0, 0, 943, 947, 3, 106, 53, 0, 944, 947, 5, 200, 0, 0, 945, 947, 5, 116, 0, 0, 946, 943, 1, 0, 0, 0, 946, 944, 1, 0, 0, 0, 946, 945, 1, 0, 0, 0, 947, 109, 1, 0, 0, 0, 948, 949, 7, 13, 0, 0, 949, 111, 1, 0, 0, 0, 950, 951, 7, 14, 0, 0, 951, 113, 1, 0, 0, 0, 952, 953, 7, 15, 0, 0, 953, 115, 1, 0, 0, 0, 954, 957, 5, 195, 0, 0, 955, 957, 3, 114, 57, 0, 956, 954, 1, 0, 0, 0, 956, 955, 1, 0, 0, 0, 957, 117, 1, 0, 0, 0, 958, 962, 5, 195, 0, 0, 959, 962, 3, 110, 55, 0, 960, 962, 3, 112, 56, 0, 961, 958, 1, 0, 0, 0, 961, 959, 1, 0, 0, 0, 961, 960, 1, 0, 0, 0, 962, 119, 1, 0, 0, 0, 963, 964, 5, 200, 0, 0, 964, 965, 5, 212, 0, 0, 965, 966, 3, 106, 53, 0, 966, 121, 1, 0, 0, 0, 967, 968, 5, 218, 0, 0, 968, 969, 3, 118, 59, 0, 969, 970, 5, 234, 0, 0, 970, 123, 1, 0, 0, 0, 120, 127, 137, 146, 149, 153, 156, 160, 163, 166, 169, 172, 176, 180, 183, 186, 189, 193, 196, 205, 211, 232, 249, 266, 272, 278, 289, 291, 302, 305, 311, 319, 325, 327, 331, 336, 339, 342, 346, 350, 353, 355, 358, 362, 366, 369, 371, 373, 378, 389, 395, 402, 407, 411, 415, 421, 423, 430, 438, 441, 444, 463, 477, 493, 505, 517, 525, 529, 536, 542, 551, 555, 579, 596, 608, 618, 621, 625, 628, 641, 658, 662, 668, 675, 687, 691, 694, 703, 717, 744, 753, 755, 757, 765, 770, 778, 788, 791, 801, 812, 817, 824, 837, 844, 857, 863, 866, 873, 885, 891, 895, 901, 908, 917, 928, 930, 933, 941, 946, 956, 961]
\ No newline at end of file
diff --git a/posthog/hogql/grammar/HogQLParser.py b/posthog/hogql/grammar/HogQLParser.py
index 6bf1053a93059..dff73f2d50927 100644
--- a/posthog/hogql/grammar/HogQLParser.py
+++ b/posthog/hogql/grammar/HogQLParser.py
@@ -10,7 +10,7 @@
def serializedATN():
return [
- 4,1,242,979,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,242,972,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,
@@ -57,344 +57,342 @@ def serializedATN():
36,5,36,535,8,36,10,36,12,36,538,9,36,1,37,1,37,1,37,3,37,543,8,
37,1,37,1,37,1,37,1,37,1,37,4,37,550,8,37,11,37,12,37,551,1,37,1,
37,3,37,556,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,587,8,37,1,37,1,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,604,
- 8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,616,
- 8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,626,8,37,1,37,
- 3,37,629,8,37,1,37,1,37,3,37,633,8,37,1,37,3,37,636,8,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,649,8,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
- 37,1,37,3,37,666,8,37,1,37,1,37,3,37,670,8,37,1,37,1,37,1,37,1,37,
- 3,37,676,8,37,1,37,1,37,1,37,1,37,1,37,3,37,683,8,37,1,37,1,37,1,
- 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,695,8,37,1,37,1,37,3,
- 37,699,8,37,1,37,3,37,702,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 3,37,711,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,3,37,725,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
+ 37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,
+ 37,580,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,3,37,597,8,37,1,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,1,37,1,37,3,37,609,8,37,1,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,1,37,3,37,619,8,37,1,37,3,37,622,8,37,1,37,1,37,3,37,626,
+ 8,37,1,37,3,37,629,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
+ 1,37,1,37,1,37,3,37,642,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
+ 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,659,8,37,1,37,1,37,
+ 3,37,663,8,37,1,37,1,37,1,37,1,37,3,37,669,8,37,1,37,1,37,1,37,1,
+ 37,1,37,3,37,676,8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,
+ 37,1,37,3,37,688,8,37,1,37,1,37,3,37,692,8,37,1,37,3,37,695,8,37,
+ 1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,704,8,37,1,37,1,37,1,37,
+ 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,718,8,37,1,37,
1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,1,37,1,37,1,37,3,37,752,8,37,1,37,1,37,1,37,1,37,1,37,1,37,
- 1,37,3,37,761,8,37,5,37,763,8,37,10,37,12,37,766,9,37,1,38,1,38,
- 1,38,5,38,771,8,38,10,38,12,38,774,9,38,1,39,1,39,3,39,778,8,39,
- 1,40,1,40,1,40,1,40,5,40,784,8,40,10,40,12,40,787,9,40,1,40,1,40,
- 1,40,1,40,1,40,5,40,794,8,40,10,40,12,40,797,9,40,3,40,799,8,40,
- 1,40,1,40,1,40,1,41,1,41,1,41,5,41,807,8,41,10,41,12,41,810,9,41,
- 1,41,1,41,1,41,1,41,1,41,1,41,5,41,818,8,41,10,41,12,41,821,9,41,
- 1,41,1,41,3,41,825,8,41,1,41,1,41,1,41,1,41,1,41,3,41,832,8,41,1,
- 42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,3,42,845,8,
- 42,1,43,1,43,1,43,5,43,850,8,43,10,43,12,43,853,9,43,1,44,1,44,1,
- 44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,3,44,865,8,44,1,45,1,45,1,
- 45,1,45,3,45,871,8,45,1,45,3,45,874,8,45,1,46,1,46,1,46,5,46,879,
- 8,46,10,46,12,46,882,9,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,
- 1,47,3,47,893,8,47,1,47,1,47,1,47,1,47,3,47,899,8,47,5,47,901,8,
- 47,10,47,12,47,904,9,47,1,48,1,48,1,48,3,48,909,8,48,1,48,1,48,1,
- 49,1,49,1,49,3,49,916,8,49,1,49,1,49,1,50,1,50,1,50,5,50,923,8,50,
- 10,50,12,50,926,9,50,1,51,1,51,1,52,1,52,1,52,1,52,1,52,1,52,3,52,
- 936,8,52,3,52,938,8,52,1,53,3,53,941,8,53,1,53,1,53,1,53,1,53,1,
- 53,1,53,3,53,949,8,53,1,54,1,54,1,54,3,54,954,8,54,1,55,1,55,1,56,
- 1,56,1,57,1,57,1,58,1,58,3,58,964,8,58,1,59,1,59,1,59,3,59,969,8,
- 59,1,60,1,60,1,60,1,60,1,61,1,61,1,61,1,61,1,61,0,3,36,74,94,62,
- 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,0,
- 16,2,0,32,32,141,141,2,0,84,84,96,96,3,0,4,4,8,8,12,12,4,0,4,4,7,
- 8,12,12,147,147,2,0,96,96,140,140,2,0,4,4,8,8,2,0,11,11,42,43,2,
- 0,62,62,93,93,2,0,133,133,143,143,3,0,17,17,95,95,170,170,2,0,79,
- 79,98,98,1,0,197,198,2,0,208,208,228,228,8,0,37,37,76,76,108,108,
- 110,110,132,132,145,145,185,185,190,190,13,0,2,24,26,36,38,75,77,
- 81,83,107,109,109,111,112,114,115,117,130,133,144,146,184,186,189,
- 191,192,4,0,36,36,62,62,77,77,91,91,1107,0,127,1,0,0,0,2,131,1,0,
- 0,0,4,146,1,0,0,0,6,149,1,0,0,0,8,198,1,0,0,0,10,201,1,0,0,0,12,
- 207,1,0,0,0,14,211,1,0,0,0,16,217,1,0,0,0,18,235,1,0,0,0,20,238,
- 1,0,0,0,22,241,1,0,0,0,24,251,1,0,0,0,26,254,1,0,0,0,28,258,1,0,
- 0,0,30,291,1,0,0,0,32,293,1,0,0,0,34,296,1,0,0,0,36,311,1,0,0,0,
- 38,373,1,0,0,0,40,378,1,0,0,0,42,389,1,0,0,0,44,391,1,0,0,0,46,397,
- 1,0,0,0,48,405,1,0,0,0,50,423,1,0,0,0,52,425,1,0,0,0,54,433,1,0,
- 0,0,56,438,1,0,0,0,58,446,1,0,0,0,60,450,1,0,0,0,62,454,1,0,0,0,
- 64,463,1,0,0,0,66,477,1,0,0,0,68,479,1,0,0,0,70,529,1,0,0,0,72,531,
- 1,0,0,0,74,669,1,0,0,0,76,767,1,0,0,0,78,777,1,0,0,0,80,798,1,0,
- 0,0,82,831,1,0,0,0,84,844,1,0,0,0,86,846,1,0,0,0,88,864,1,0,0,0,
- 90,873,1,0,0,0,92,875,1,0,0,0,94,892,1,0,0,0,96,905,1,0,0,0,98,915,
- 1,0,0,0,100,919,1,0,0,0,102,927,1,0,0,0,104,937,1,0,0,0,106,940,
- 1,0,0,0,108,953,1,0,0,0,110,955,1,0,0,0,112,957,1,0,0,0,114,959,
- 1,0,0,0,116,963,1,0,0,0,118,968,1,0,0,0,120,970,1,0,0,0,122,974,
- 1,0,0,0,124,128,3,2,1,0,125,128,3,6,3,0,126,128,3,82,41,0,127,124,
- 1,0,0,0,127,125,1,0,0,0,127,126,1,0,0,0,128,129,1,0,0,0,129,130,
- 5,0,0,1,130,1,1,0,0,0,131,137,3,4,2,0,132,133,5,176,0,0,133,134,
- 5,4,0,0,134,136,3,4,2,0,135,132,1,0,0,0,136,139,1,0,0,0,137,135,
- 1,0,0,0,137,138,1,0,0,0,138,3,1,0,0,0,139,137,1,0,0,0,140,147,3,
- 6,3,0,141,142,5,220,0,0,142,143,3,2,1,0,143,144,5,236,0,0,144,147,
- 1,0,0,0,145,147,3,122,61,0,146,140,1,0,0,0,146,141,1,0,0,0,146,145,
- 1,0,0,0,147,5,1,0,0,0,148,150,3,8,4,0,149,148,1,0,0,0,149,150,1,
- 0,0,0,150,151,1,0,0,0,151,153,5,146,0,0,152,154,5,49,0,0,153,152,
- 1,0,0,0,153,154,1,0,0,0,154,156,1,0,0,0,155,157,3,10,5,0,156,155,
- 1,0,0,0,156,157,1,0,0,0,157,158,1,0,0,0,158,160,3,72,36,0,159,161,
- 3,12,6,0,160,159,1,0,0,0,160,161,1,0,0,0,161,163,1,0,0,0,162,164,
- 3,14,7,0,163,162,1,0,0,0,163,164,1,0,0,0,164,166,1,0,0,0,165,167,
- 3,18,9,0,166,165,1,0,0,0,166,167,1,0,0,0,167,169,1,0,0,0,168,170,
- 3,20,10,0,169,168,1,0,0,0,169,170,1,0,0,0,170,172,1,0,0,0,171,173,
- 3,22,11,0,172,171,1,0,0,0,172,173,1,0,0,0,173,176,1,0,0,0,174,175,
- 5,189,0,0,175,177,7,0,0,0,176,174,1,0,0,0,176,177,1,0,0,0,177,180,
- 1,0,0,0,178,179,5,189,0,0,179,181,5,169,0,0,180,178,1,0,0,0,180,
- 181,1,0,0,0,181,183,1,0,0,0,182,184,3,24,12,0,183,182,1,0,0,0,183,
- 184,1,0,0,0,184,186,1,0,0,0,185,187,3,16,8,0,186,185,1,0,0,0,186,
- 187,1,0,0,0,187,189,1,0,0,0,188,190,3,26,13,0,189,188,1,0,0,0,189,
- 190,1,0,0,0,190,193,1,0,0,0,191,194,3,30,15,0,192,194,3,32,16,0,
- 193,191,1,0,0,0,193,192,1,0,0,0,193,194,1,0,0,0,194,196,1,0,0,0,
- 195,197,3,34,17,0,196,195,1,0,0,0,196,197,1,0,0,0,197,7,1,0,0,0,
- 198,199,5,189,0,0,199,200,3,86,43,0,200,9,1,0,0,0,201,202,5,168,
- 0,0,202,205,5,198,0,0,203,204,5,189,0,0,204,206,5,164,0,0,205,203,
- 1,0,0,0,205,206,1,0,0,0,206,11,1,0,0,0,207,208,5,68,0,0,208,209,
- 3,36,18,0,209,13,1,0,0,0,210,212,7,1,0,0,211,210,1,0,0,0,211,212,
- 1,0,0,0,212,213,1,0,0,0,213,214,5,9,0,0,214,215,5,90,0,0,215,216,
- 3,72,36,0,216,15,1,0,0,0,217,218,5,188,0,0,218,219,3,118,59,0,219,
- 220,5,10,0,0,220,221,5,220,0,0,221,222,3,56,28,0,222,232,5,236,0,
- 0,223,224,5,206,0,0,224,225,3,118,59,0,225,226,5,10,0,0,226,227,
- 5,220,0,0,227,228,3,56,28,0,228,229,5,236,0,0,229,231,1,0,0,0,230,
- 223,1,0,0,0,231,234,1,0,0,0,232,230,1,0,0,0,232,233,1,0,0,0,233,
- 17,1,0,0,0,234,232,1,0,0,0,235,236,5,129,0,0,236,237,3,74,37,0,237,
- 19,1,0,0,0,238,239,5,187,0,0,239,240,3,74,37,0,240,21,1,0,0,0,241,
- 242,5,73,0,0,242,249,5,18,0,0,243,244,7,0,0,0,244,245,5,220,0,0,
- 245,246,3,72,36,0,246,247,5,236,0,0,247,250,1,0,0,0,248,250,3,72,
- 36,0,249,243,1,0,0,0,249,248,1,0,0,0,250,23,1,0,0,0,251,252,5,74,
- 0,0,252,253,3,74,37,0,253,25,1,0,0,0,254,255,5,122,0,0,255,256,5,
- 18,0,0,256,257,3,46,23,0,257,27,1,0,0,0,258,259,5,122,0,0,259,260,
- 5,18,0,0,260,261,3,72,36,0,261,29,1,0,0,0,262,263,5,99,0,0,263,266,
- 3,74,37,0,264,265,5,206,0,0,265,267,3,74,37,0,266,264,1,0,0,0,266,
- 267,1,0,0,0,267,272,1,0,0,0,268,269,5,189,0,0,269,273,5,164,0,0,
- 270,271,5,18,0,0,271,273,3,72,36,0,272,268,1,0,0,0,272,270,1,0,0,
- 0,272,273,1,0,0,0,273,292,1,0,0,0,274,275,5,99,0,0,275,278,3,74,
- 37,0,276,277,5,189,0,0,277,279,5,164,0,0,278,276,1,0,0,0,278,279,
- 1,0,0,0,279,280,1,0,0,0,280,281,5,118,0,0,281,282,3,74,37,0,282,
- 292,1,0,0,0,283,284,5,99,0,0,284,285,3,74,37,0,285,286,5,118,0,0,
- 286,289,3,74,37,0,287,288,5,18,0,0,288,290,3,72,36,0,289,287,1,0,
- 0,0,289,290,1,0,0,0,290,292,1,0,0,0,291,262,1,0,0,0,291,274,1,0,
- 0,0,291,283,1,0,0,0,292,31,1,0,0,0,293,294,5,118,0,0,294,295,3,74,
- 37,0,295,33,1,0,0,0,296,297,5,150,0,0,297,298,3,52,26,0,298,35,1,
- 0,0,0,299,300,6,18,-1,0,300,302,3,94,47,0,301,303,5,61,0,0,302,301,
- 1,0,0,0,302,303,1,0,0,0,303,305,1,0,0,0,304,306,3,44,22,0,305,304,
- 1,0,0,0,305,306,1,0,0,0,306,312,1,0,0,0,307,308,5,220,0,0,308,309,
- 3,36,18,0,309,310,5,236,0,0,310,312,1,0,0,0,311,299,1,0,0,0,311,
- 307,1,0,0,0,312,327,1,0,0,0,313,314,10,3,0,0,314,315,3,40,20,0,315,
- 316,3,36,18,4,316,326,1,0,0,0,317,319,10,4,0,0,318,320,3,38,19,0,
- 319,318,1,0,0,0,319,320,1,0,0,0,320,321,1,0,0,0,321,322,5,90,0,0,
- 322,323,3,36,18,0,323,324,3,42,21,0,324,326,1,0,0,0,325,313,1,0,
- 0,0,325,317,1,0,0,0,326,329,1,0,0,0,327,325,1,0,0,0,327,328,1,0,
- 0,0,328,37,1,0,0,0,329,327,1,0,0,0,330,332,7,2,0,0,331,330,1,0,0,
- 0,331,332,1,0,0,0,332,333,1,0,0,0,333,340,5,84,0,0,334,336,5,84,
- 0,0,335,337,7,2,0,0,336,335,1,0,0,0,336,337,1,0,0,0,337,340,1,0,
- 0,0,338,340,7,2,0,0,339,331,1,0,0,0,339,334,1,0,0,0,339,338,1,0,
- 0,0,340,374,1,0,0,0,341,343,7,3,0,0,342,341,1,0,0,0,342,343,1,0,
- 0,0,343,344,1,0,0,0,344,346,7,4,0,0,345,347,5,123,0,0,346,345,1,
- 0,0,0,346,347,1,0,0,0,347,356,1,0,0,0,348,350,7,4,0,0,349,351,5,
- 123,0,0,350,349,1,0,0,0,350,351,1,0,0,0,351,353,1,0,0,0,352,354,
- 7,3,0,0,353,352,1,0,0,0,353,354,1,0,0,0,354,356,1,0,0,0,355,342,
- 1,0,0,0,355,348,1,0,0,0,356,374,1,0,0,0,357,359,7,5,0,0,358,357,
- 1,0,0,0,358,359,1,0,0,0,359,360,1,0,0,0,360,362,5,69,0,0,361,363,
- 5,123,0,0,362,361,1,0,0,0,362,363,1,0,0,0,363,372,1,0,0,0,364,366,
- 5,69,0,0,365,367,5,123,0,0,366,365,1,0,0,0,366,367,1,0,0,0,367,369,
- 1,0,0,0,368,370,7,5,0,0,369,368,1,0,0,0,369,370,1,0,0,0,370,372,
- 1,0,0,0,371,358,1,0,0,0,371,364,1,0,0,0,372,374,1,0,0,0,373,339,
- 1,0,0,0,373,355,1,0,0,0,373,371,1,0,0,0,374,39,1,0,0,0,375,376,5,
- 31,0,0,376,379,5,90,0,0,377,379,5,206,0,0,378,375,1,0,0,0,378,377,
- 1,0,0,0,379,41,1,0,0,0,380,381,5,119,0,0,381,390,3,72,36,0,382,383,
- 5,179,0,0,383,384,5,220,0,0,384,385,3,72,36,0,385,386,5,236,0,0,
- 386,390,1,0,0,0,387,388,5,179,0,0,388,390,3,72,36,0,389,380,1,0,
- 0,0,389,382,1,0,0,0,389,387,1,0,0,0,390,43,1,0,0,0,391,392,5,144,
- 0,0,392,395,3,50,25,0,393,394,5,118,0,0,394,396,3,50,25,0,395,393,
- 1,0,0,0,395,396,1,0,0,0,396,45,1,0,0,0,397,402,3,48,24,0,398,399,
- 5,206,0,0,399,401,3,48,24,0,400,398,1,0,0,0,401,404,1,0,0,0,402,
- 400,1,0,0,0,402,403,1,0,0,0,403,47,1,0,0,0,404,402,1,0,0,0,405,407,
- 3,74,37,0,406,408,7,6,0,0,407,406,1,0,0,0,407,408,1,0,0,0,408,411,
- 1,0,0,0,409,410,5,117,0,0,410,412,7,7,0,0,411,409,1,0,0,0,411,412,
- 1,0,0,0,412,415,1,0,0,0,413,414,5,26,0,0,414,416,5,200,0,0,415,413,
- 1,0,0,0,415,416,1,0,0,0,416,49,1,0,0,0,417,424,3,122,61,0,418,421,
- 3,106,53,0,419,420,5,238,0,0,420,422,3,106,53,0,421,419,1,0,0,0,
- 421,422,1,0,0,0,422,424,1,0,0,0,423,417,1,0,0,0,423,418,1,0,0,0,
- 424,51,1,0,0,0,425,430,3,54,27,0,426,427,5,206,0,0,427,429,3,54,
- 27,0,428,426,1,0,0,0,429,432,1,0,0,0,430,428,1,0,0,0,430,431,1,0,
- 0,0,431,53,1,0,0,0,432,430,1,0,0,0,433,434,3,118,59,0,434,435,5,
- 212,0,0,435,436,3,108,54,0,436,55,1,0,0,0,437,439,3,58,29,0,438,
- 437,1,0,0,0,438,439,1,0,0,0,439,441,1,0,0,0,440,442,3,60,30,0,441,
- 440,1,0,0,0,441,442,1,0,0,0,442,444,1,0,0,0,443,445,3,62,31,0,444,
- 443,1,0,0,0,444,445,1,0,0,0,445,57,1,0,0,0,446,447,5,126,0,0,447,
- 448,5,18,0,0,448,449,3,72,36,0,449,59,1,0,0,0,450,451,5,122,0,0,
- 451,452,5,18,0,0,452,453,3,46,23,0,453,61,1,0,0,0,454,455,7,8,0,
- 0,455,456,3,64,32,0,456,63,1,0,0,0,457,464,3,66,33,0,458,459,5,16,
- 0,0,459,460,3,66,33,0,460,461,5,6,0,0,461,462,3,66,33,0,462,464,
- 1,0,0,0,463,457,1,0,0,0,463,458,1,0,0,0,464,65,1,0,0,0,465,466,5,
- 33,0,0,466,478,5,142,0,0,467,468,5,175,0,0,468,478,5,128,0,0,469,
- 470,5,175,0,0,470,478,5,64,0,0,471,472,3,106,53,0,472,473,5,128,
- 0,0,473,478,1,0,0,0,474,475,3,106,53,0,475,476,5,64,0,0,476,478,
- 1,0,0,0,477,465,1,0,0,0,477,467,1,0,0,0,477,469,1,0,0,0,477,471,
- 1,0,0,0,477,474,1,0,0,0,478,67,1,0,0,0,479,480,3,74,37,0,480,481,
- 5,0,0,1,481,69,1,0,0,0,482,530,3,118,59,0,483,484,3,118,59,0,484,
- 485,5,220,0,0,485,486,3,118,59,0,486,493,3,70,35,0,487,488,5,206,
- 0,0,488,489,3,118,59,0,489,490,3,70,35,0,490,492,1,0,0,0,491,487,
- 1,0,0,0,492,495,1,0,0,0,493,491,1,0,0,0,493,494,1,0,0,0,494,496,
- 1,0,0,0,495,493,1,0,0,0,496,497,5,236,0,0,497,530,1,0,0,0,498,499,
- 3,118,59,0,499,500,5,220,0,0,500,505,3,120,60,0,501,502,5,206,0,
- 0,502,504,3,120,60,0,503,501,1,0,0,0,504,507,1,0,0,0,505,503,1,0,
- 0,0,505,506,1,0,0,0,506,508,1,0,0,0,507,505,1,0,0,0,508,509,5,236,
- 0,0,509,530,1,0,0,0,510,511,3,118,59,0,511,512,5,220,0,0,512,517,
- 3,70,35,0,513,514,5,206,0,0,514,516,3,70,35,0,515,513,1,0,0,0,516,
- 519,1,0,0,0,517,515,1,0,0,0,517,518,1,0,0,0,518,520,1,0,0,0,519,
- 517,1,0,0,0,520,521,5,236,0,0,521,530,1,0,0,0,522,523,3,118,59,0,
- 523,525,5,220,0,0,524,526,3,72,36,0,525,524,1,0,0,0,525,526,1,0,
- 0,0,526,527,1,0,0,0,527,528,5,236,0,0,528,530,1,0,0,0,529,482,1,
- 0,0,0,529,483,1,0,0,0,529,498,1,0,0,0,529,510,1,0,0,0,529,522,1,
- 0,0,0,530,71,1,0,0,0,531,536,3,74,37,0,532,533,5,206,0,0,533,535,
- 3,74,37,0,534,532,1,0,0,0,535,538,1,0,0,0,536,534,1,0,0,0,536,537,
- 1,0,0,0,537,73,1,0,0,0,538,536,1,0,0,0,539,540,6,37,-1,0,540,542,
- 5,19,0,0,541,543,3,74,37,0,542,541,1,0,0,0,542,543,1,0,0,0,543,549,
- 1,0,0,0,544,545,5,186,0,0,545,546,3,74,37,0,546,547,5,163,0,0,547,
- 548,3,74,37,0,548,550,1,0,0,0,549,544,1,0,0,0,550,551,1,0,0,0,551,
- 549,1,0,0,0,551,552,1,0,0,0,552,555,1,0,0,0,553,554,5,52,0,0,554,
- 556,3,74,37,0,555,553,1,0,0,0,555,556,1,0,0,0,556,557,1,0,0,0,557,
- 558,5,53,0,0,558,670,1,0,0,0,559,560,5,20,0,0,560,561,5,220,0,0,
- 561,562,3,74,37,0,562,563,5,10,0,0,563,564,3,70,35,0,564,565,5,236,
- 0,0,565,670,1,0,0,0,566,567,5,36,0,0,567,670,5,200,0,0,568,569,5,
- 59,0,0,569,570,5,220,0,0,570,571,3,110,55,0,571,572,5,68,0,0,572,
- 573,3,74,37,0,573,574,5,236,0,0,574,670,1,0,0,0,575,576,5,86,0,0,
- 576,577,3,74,37,0,577,578,3,110,55,0,578,670,1,0,0,0,579,580,5,155,
- 0,0,580,581,5,220,0,0,581,582,3,74,37,0,582,583,5,68,0,0,583,586,
- 3,74,37,0,584,585,5,65,0,0,585,587,3,74,37,0,586,584,1,0,0,0,586,
- 587,1,0,0,0,587,588,1,0,0,0,588,589,5,236,0,0,589,670,1,0,0,0,590,
- 591,5,166,0,0,591,670,5,200,0,0,592,593,5,171,0,0,593,594,5,220,
- 0,0,594,595,7,9,0,0,595,596,5,200,0,0,596,597,5,68,0,0,597,598,3,
- 74,37,0,598,599,5,236,0,0,599,670,1,0,0,0,600,601,3,118,59,0,601,
- 603,5,220,0,0,602,604,3,72,36,0,603,602,1,0,0,0,603,604,1,0,0,0,
- 604,605,1,0,0,0,605,606,5,236,0,0,606,607,1,0,0,0,607,608,5,125,
- 0,0,608,609,5,220,0,0,609,610,3,56,28,0,610,611,5,236,0,0,611,670,
- 1,0,0,0,612,613,3,118,59,0,613,615,5,220,0,0,614,616,3,72,36,0,615,
- 614,1,0,0,0,615,616,1,0,0,0,616,617,1,0,0,0,617,618,5,236,0,0,618,
- 619,1,0,0,0,619,620,5,125,0,0,620,621,3,118,59,0,621,670,1,0,0,0,
- 622,628,3,118,59,0,623,625,5,220,0,0,624,626,3,72,36,0,625,624,1,
- 0,0,0,625,626,1,0,0,0,626,627,1,0,0,0,627,629,5,236,0,0,628,623,
- 1,0,0,0,628,629,1,0,0,0,629,630,1,0,0,0,630,632,5,220,0,0,631,633,
- 5,49,0,0,632,631,1,0,0,0,632,633,1,0,0,0,633,635,1,0,0,0,634,636,
- 3,76,38,0,635,634,1,0,0,0,635,636,1,0,0,0,636,637,1,0,0,0,637,638,
- 5,236,0,0,638,670,1,0,0,0,639,670,3,82,41,0,640,670,3,108,54,0,641,
- 642,5,208,0,0,642,670,3,74,37,18,643,644,5,115,0,0,644,670,3,74,
- 37,12,645,646,3,98,49,0,646,647,5,210,0,0,647,649,1,0,0,0,648,645,
- 1,0,0,0,648,649,1,0,0,0,649,650,1,0,0,0,650,670,5,202,0,0,651,652,
- 5,220,0,0,652,653,3,2,1,0,653,654,5,236,0,0,654,670,1,0,0,0,655,
- 656,5,220,0,0,656,657,3,74,37,0,657,658,5,236,0,0,658,670,1,0,0,
- 0,659,660,5,220,0,0,660,661,3,72,36,0,661,662,5,236,0,0,662,670,
- 1,0,0,0,663,665,5,219,0,0,664,666,3,72,36,0,665,664,1,0,0,0,665,
- 666,1,0,0,0,666,667,1,0,0,0,667,670,5,235,0,0,668,670,3,90,45,0,
- 669,539,1,0,0,0,669,559,1,0,0,0,669,566,1,0,0,0,669,568,1,0,0,0,
- 669,575,1,0,0,0,669,579,1,0,0,0,669,590,1,0,0,0,669,592,1,0,0,0,
- 669,600,1,0,0,0,669,612,1,0,0,0,669,622,1,0,0,0,669,639,1,0,0,0,
- 669,640,1,0,0,0,669,641,1,0,0,0,669,643,1,0,0,0,669,648,1,0,0,0,
- 669,651,1,0,0,0,669,655,1,0,0,0,669,659,1,0,0,0,669,663,1,0,0,0,
- 669,668,1,0,0,0,670,764,1,0,0,0,671,675,10,17,0,0,672,676,5,202,
- 0,0,673,676,5,238,0,0,674,676,5,227,0,0,675,672,1,0,0,0,675,673,
- 1,0,0,0,675,674,1,0,0,0,676,677,1,0,0,0,677,763,3,74,37,18,678,682,
- 10,16,0,0,679,683,5,228,0,0,680,683,5,208,0,0,681,683,5,207,0,0,
- 682,679,1,0,0,0,682,680,1,0,0,0,682,681,1,0,0,0,683,684,1,0,0,0,
- 684,763,3,74,37,17,685,710,10,15,0,0,686,711,5,211,0,0,687,711,5,
- 212,0,0,688,711,5,223,0,0,689,711,5,221,0,0,690,711,5,222,0,0,691,
- 711,5,213,0,0,692,711,5,214,0,0,693,695,5,115,0,0,694,693,1,0,0,
- 0,694,695,1,0,0,0,695,696,1,0,0,0,696,698,5,80,0,0,697,699,5,25,
- 0,0,698,697,1,0,0,0,698,699,1,0,0,0,699,711,1,0,0,0,700,702,5,115,
- 0,0,701,700,1,0,0,0,701,702,1,0,0,0,702,703,1,0,0,0,703,711,7,10,
- 0,0,704,711,5,232,0,0,705,711,5,233,0,0,706,711,5,225,0,0,707,711,
- 5,216,0,0,708,711,5,217,0,0,709,711,5,224,0,0,710,686,1,0,0,0,710,
- 687,1,0,0,0,710,688,1,0,0,0,710,689,1,0,0,0,710,690,1,0,0,0,710,
- 691,1,0,0,0,710,692,1,0,0,0,710,694,1,0,0,0,710,701,1,0,0,0,710,
- 704,1,0,0,0,710,705,1,0,0,0,710,706,1,0,0,0,710,707,1,0,0,0,710,
- 708,1,0,0,0,710,709,1,0,0,0,711,712,1,0,0,0,712,763,3,74,37,16,713,
- 714,10,13,0,0,714,715,5,226,0,0,715,763,3,74,37,14,716,717,10,11,
- 0,0,717,718,5,6,0,0,718,763,3,74,37,12,719,720,10,10,0,0,720,721,
- 5,121,0,0,721,763,3,74,37,11,722,724,10,9,0,0,723,725,5,115,0,0,
- 724,723,1,0,0,0,724,725,1,0,0,0,725,726,1,0,0,0,726,727,5,16,0,0,
- 727,728,3,74,37,0,728,729,5,6,0,0,729,730,3,74,37,10,730,763,1,0,
- 0,0,731,732,10,8,0,0,732,733,5,229,0,0,733,734,3,74,37,0,734,735,
- 5,205,0,0,735,736,3,74,37,8,736,763,1,0,0,0,737,738,10,21,0,0,738,
- 739,5,219,0,0,739,740,3,74,37,0,740,741,5,235,0,0,741,763,1,0,0,
- 0,742,743,10,20,0,0,743,744,5,210,0,0,744,763,5,198,0,0,745,746,
- 10,19,0,0,746,747,5,210,0,0,747,763,3,118,59,0,748,749,10,14,0,0,
- 749,751,5,88,0,0,750,752,5,115,0,0,751,750,1,0,0,0,751,752,1,0,0,
- 0,752,753,1,0,0,0,753,763,5,116,0,0,754,760,10,7,0,0,755,761,3,116,
- 58,0,756,757,5,10,0,0,757,761,3,118,59,0,758,759,5,10,0,0,759,761,
- 5,200,0,0,760,755,1,0,0,0,760,756,1,0,0,0,760,758,1,0,0,0,761,763,
- 1,0,0,0,762,671,1,0,0,0,762,678,1,0,0,0,762,685,1,0,0,0,762,713,
- 1,0,0,0,762,716,1,0,0,0,762,719,1,0,0,0,762,722,1,0,0,0,762,731,
- 1,0,0,0,762,737,1,0,0,0,762,742,1,0,0,0,762,745,1,0,0,0,762,748,
- 1,0,0,0,762,754,1,0,0,0,763,766,1,0,0,0,764,762,1,0,0,0,764,765,
- 1,0,0,0,765,75,1,0,0,0,766,764,1,0,0,0,767,772,3,78,39,0,768,769,
- 5,206,0,0,769,771,3,78,39,0,770,768,1,0,0,0,771,774,1,0,0,0,772,
- 770,1,0,0,0,772,773,1,0,0,0,773,77,1,0,0,0,774,772,1,0,0,0,775,778,
- 3,80,40,0,776,778,3,74,37,0,777,775,1,0,0,0,777,776,1,0,0,0,778,
- 79,1,0,0,0,779,780,5,220,0,0,780,785,3,118,59,0,781,782,5,206,0,
- 0,782,784,3,118,59,0,783,781,1,0,0,0,784,787,1,0,0,0,785,783,1,0,
- 0,0,785,786,1,0,0,0,786,788,1,0,0,0,787,785,1,0,0,0,788,789,5,236,
- 0,0,789,799,1,0,0,0,790,795,3,118,59,0,791,792,5,206,0,0,792,794,
- 3,118,59,0,793,791,1,0,0,0,794,797,1,0,0,0,795,793,1,0,0,0,795,796,
- 1,0,0,0,796,799,1,0,0,0,797,795,1,0,0,0,798,779,1,0,0,0,798,790,
- 1,0,0,0,799,800,1,0,0,0,800,801,5,201,0,0,801,802,3,74,37,0,802,
- 81,1,0,0,0,803,804,5,222,0,0,804,808,3,118,59,0,805,807,3,84,42,
- 0,806,805,1,0,0,0,807,810,1,0,0,0,808,806,1,0,0,0,808,809,1,0,0,
- 0,809,811,1,0,0,0,810,808,1,0,0,0,811,812,5,238,0,0,812,813,5,214,
- 0,0,813,832,1,0,0,0,814,815,5,222,0,0,815,819,3,118,59,0,816,818,
- 3,84,42,0,817,816,1,0,0,0,818,821,1,0,0,0,819,817,1,0,0,0,819,820,
- 1,0,0,0,820,822,1,0,0,0,821,819,1,0,0,0,822,824,5,214,0,0,823,825,
- 3,82,41,0,824,823,1,0,0,0,824,825,1,0,0,0,825,826,1,0,0,0,826,827,
- 5,222,0,0,827,828,5,238,0,0,828,829,3,118,59,0,829,830,5,214,0,0,
- 830,832,1,0,0,0,831,803,1,0,0,0,831,814,1,0,0,0,832,83,1,0,0,0,833,
- 834,3,118,59,0,834,835,5,212,0,0,835,836,5,200,0,0,836,845,1,0,0,
- 0,837,838,3,118,59,0,838,839,5,212,0,0,839,840,5,218,0,0,840,841,
- 3,74,37,0,841,842,5,234,0,0,842,845,1,0,0,0,843,845,3,118,59,0,844,
- 833,1,0,0,0,844,837,1,0,0,0,844,843,1,0,0,0,845,85,1,0,0,0,846,851,
- 3,88,44,0,847,848,5,206,0,0,848,850,3,88,44,0,849,847,1,0,0,0,850,
- 853,1,0,0,0,851,849,1,0,0,0,851,852,1,0,0,0,852,87,1,0,0,0,853,851,
- 1,0,0,0,854,855,3,118,59,0,855,856,5,10,0,0,856,857,5,220,0,0,857,
- 858,3,2,1,0,858,859,5,236,0,0,859,865,1,0,0,0,860,861,3,74,37,0,
- 861,862,5,10,0,0,862,863,3,118,59,0,863,865,1,0,0,0,864,854,1,0,
- 0,0,864,860,1,0,0,0,865,89,1,0,0,0,866,874,3,122,61,0,867,868,3,
- 98,49,0,868,869,5,210,0,0,869,871,1,0,0,0,870,867,1,0,0,0,870,871,
- 1,0,0,0,871,872,1,0,0,0,872,874,3,92,46,0,873,866,1,0,0,0,873,870,
- 1,0,0,0,874,91,1,0,0,0,875,880,3,118,59,0,876,877,5,210,0,0,877,
- 879,3,118,59,0,878,876,1,0,0,0,879,882,1,0,0,0,880,878,1,0,0,0,880,
- 881,1,0,0,0,881,93,1,0,0,0,882,880,1,0,0,0,883,884,6,47,-1,0,884,
- 893,3,98,49,0,885,893,3,96,48,0,886,887,5,220,0,0,887,888,3,2,1,
- 0,888,889,5,236,0,0,889,893,1,0,0,0,890,893,3,82,41,0,891,893,3,
- 122,61,0,892,883,1,0,0,0,892,885,1,0,0,0,892,886,1,0,0,0,892,890,
- 1,0,0,0,892,891,1,0,0,0,893,902,1,0,0,0,894,898,10,3,0,0,895,899,
- 3,116,58,0,896,897,5,10,0,0,897,899,3,118,59,0,898,895,1,0,0,0,898,
- 896,1,0,0,0,899,901,1,0,0,0,900,894,1,0,0,0,901,904,1,0,0,0,902,
- 900,1,0,0,0,902,903,1,0,0,0,903,95,1,0,0,0,904,902,1,0,0,0,905,906,
- 3,118,59,0,906,908,5,220,0,0,907,909,3,100,50,0,908,907,1,0,0,0,
- 908,909,1,0,0,0,909,910,1,0,0,0,910,911,5,236,0,0,911,97,1,0,0,0,
- 912,913,3,102,51,0,913,914,5,210,0,0,914,916,1,0,0,0,915,912,1,0,
- 0,0,915,916,1,0,0,0,916,917,1,0,0,0,917,918,3,118,59,0,918,99,1,
- 0,0,0,919,924,3,74,37,0,920,921,5,206,0,0,921,923,3,74,37,0,922,
- 920,1,0,0,0,923,926,1,0,0,0,924,922,1,0,0,0,924,925,1,0,0,0,925,
- 101,1,0,0,0,926,924,1,0,0,0,927,928,3,118,59,0,928,103,1,0,0,0,929,
- 938,5,196,0,0,930,931,5,210,0,0,931,938,7,11,0,0,932,933,5,198,0,
- 0,933,935,5,210,0,0,934,936,7,11,0,0,935,934,1,0,0,0,935,936,1,0,
- 0,0,936,938,1,0,0,0,937,929,1,0,0,0,937,930,1,0,0,0,937,932,1,0,
- 0,0,938,105,1,0,0,0,939,941,7,12,0,0,940,939,1,0,0,0,940,941,1,0,
- 0,0,941,948,1,0,0,0,942,949,3,104,52,0,943,949,5,197,0,0,944,949,
- 5,198,0,0,945,949,5,199,0,0,946,949,5,82,0,0,947,949,5,113,0,0,948,
- 942,1,0,0,0,948,943,1,0,0,0,948,944,1,0,0,0,948,945,1,0,0,0,948,
- 946,1,0,0,0,948,947,1,0,0,0,949,107,1,0,0,0,950,954,3,106,53,0,951,
- 954,5,200,0,0,952,954,5,116,0,0,953,950,1,0,0,0,953,951,1,0,0,0,
- 953,952,1,0,0,0,954,109,1,0,0,0,955,956,7,13,0,0,956,111,1,0,0,0,
- 957,958,7,14,0,0,958,113,1,0,0,0,959,960,7,15,0,0,960,115,1,0,0,
- 0,961,964,5,195,0,0,962,964,3,114,57,0,963,961,1,0,0,0,963,962,1,
- 0,0,0,964,117,1,0,0,0,965,969,5,195,0,0,966,969,3,110,55,0,967,969,
- 3,112,56,0,968,965,1,0,0,0,968,966,1,0,0,0,968,967,1,0,0,0,969,119,
- 1,0,0,0,970,971,5,200,0,0,971,972,5,212,0,0,972,973,3,106,53,0,973,
- 121,1,0,0,0,974,975,5,218,0,0,975,976,3,118,59,0,976,977,5,234,0,
- 0,977,123,1,0,0,0,120,127,137,146,149,153,156,160,163,166,169,172,
- 176,180,183,186,189,193,196,205,211,232,249,266,272,278,289,291,
- 302,305,311,319,325,327,331,336,339,342,346,350,353,355,358,362,
- 366,369,371,373,378,389,395,402,407,411,415,421,423,430,438,441,
- 444,463,477,493,505,517,525,529,536,542,551,555,586,603,615,625,
- 628,632,635,648,665,669,675,682,694,698,701,710,724,751,760,762,
- 764,772,777,785,795,798,808,819,824,831,844,851,864,870,873,880,
- 892,898,902,908,915,924,935,937,940,948,953,963,968
+ 1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,745,
+ 8,37,1,37,1,37,1,37,1,37,1,37,1,37,1,37,3,37,754,8,37,5,37,756,8,
+ 37,10,37,12,37,759,9,37,1,38,1,38,1,38,5,38,764,8,38,10,38,12,38,
+ 767,9,38,1,39,1,39,3,39,771,8,39,1,40,1,40,1,40,1,40,5,40,777,8,
+ 40,10,40,12,40,780,9,40,1,40,1,40,1,40,1,40,1,40,5,40,787,8,40,10,
+ 40,12,40,790,9,40,3,40,792,8,40,1,40,1,40,1,40,1,41,1,41,1,41,5,
+ 41,800,8,41,10,41,12,41,803,9,41,1,41,1,41,1,41,1,41,1,41,1,41,5,
+ 41,811,8,41,10,41,12,41,814,9,41,1,41,1,41,3,41,818,8,41,1,41,1,
+ 41,1,41,1,41,1,41,3,41,825,8,41,1,42,1,42,1,42,1,42,1,42,1,42,1,
+ 42,1,42,1,42,1,42,1,42,3,42,838,8,42,1,43,1,43,1,43,5,43,843,8,43,
+ 10,43,12,43,846,9,43,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,
+ 1,44,3,44,858,8,44,1,45,1,45,1,45,1,45,3,45,864,8,45,1,45,3,45,867,
+ 8,45,1,46,1,46,1,46,5,46,872,8,46,10,46,12,46,875,9,46,1,47,1,47,
+ 1,47,1,47,1,47,1,47,1,47,1,47,1,47,3,47,886,8,47,1,47,1,47,1,47,
+ 1,47,3,47,892,8,47,5,47,894,8,47,10,47,12,47,897,9,47,1,48,1,48,
+ 1,48,3,48,902,8,48,1,48,1,48,1,49,1,49,1,49,3,49,909,8,49,1,49,1,
+ 49,1,50,1,50,1,50,5,50,916,8,50,10,50,12,50,919,9,50,1,51,1,51,1,
+ 52,1,52,1,52,1,52,1,52,1,52,3,52,929,8,52,3,52,931,8,52,1,53,3,53,
+ 934,8,53,1,53,1,53,1,53,1,53,1,53,1,53,3,53,942,8,53,1,54,1,54,1,
+ 54,3,54,947,8,54,1,55,1,55,1,56,1,56,1,57,1,57,1,58,1,58,3,58,957,
+ 8,58,1,59,1,59,1,59,3,59,962,8,59,1,60,1,60,1,60,1,60,1,61,1,61,
+ 1,61,1,61,1,61,0,3,36,74,94,62,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,0,16,2,0,32,32,141,141,2,0,84,84,96,
+ 96,3,0,4,4,8,8,12,12,4,0,4,4,7,8,12,12,147,147,2,0,96,96,140,140,
+ 2,0,4,4,8,8,2,0,11,11,42,43,2,0,62,62,93,93,2,0,133,133,143,143,
+ 3,0,17,17,95,95,170,170,2,0,79,79,98,98,1,0,197,198,2,0,208,208,
+ 228,228,8,0,37,37,76,76,108,108,110,110,132,132,145,145,185,185,
+ 190,190,13,0,2,24,26,36,38,75,77,81,83,107,109,109,111,112,114,115,
+ 117,130,133,144,146,184,186,189,191,192,4,0,36,36,62,62,77,77,91,
+ 91,1099,0,127,1,0,0,0,2,131,1,0,0,0,4,146,1,0,0,0,6,149,1,0,0,0,
+ 8,198,1,0,0,0,10,201,1,0,0,0,12,207,1,0,0,0,14,211,1,0,0,0,16,217,
+ 1,0,0,0,18,235,1,0,0,0,20,238,1,0,0,0,22,241,1,0,0,0,24,251,1,0,
+ 0,0,26,254,1,0,0,0,28,258,1,0,0,0,30,291,1,0,0,0,32,293,1,0,0,0,
+ 34,296,1,0,0,0,36,311,1,0,0,0,38,373,1,0,0,0,40,378,1,0,0,0,42,389,
+ 1,0,0,0,44,391,1,0,0,0,46,397,1,0,0,0,48,405,1,0,0,0,50,423,1,0,
+ 0,0,52,425,1,0,0,0,54,433,1,0,0,0,56,438,1,0,0,0,58,446,1,0,0,0,
+ 60,450,1,0,0,0,62,454,1,0,0,0,64,463,1,0,0,0,66,477,1,0,0,0,68,479,
+ 1,0,0,0,70,529,1,0,0,0,72,531,1,0,0,0,74,662,1,0,0,0,76,760,1,0,
+ 0,0,78,770,1,0,0,0,80,791,1,0,0,0,82,824,1,0,0,0,84,837,1,0,0,0,
+ 86,839,1,0,0,0,88,857,1,0,0,0,90,866,1,0,0,0,92,868,1,0,0,0,94,885,
+ 1,0,0,0,96,898,1,0,0,0,98,908,1,0,0,0,100,912,1,0,0,0,102,920,1,
+ 0,0,0,104,930,1,0,0,0,106,933,1,0,0,0,108,946,1,0,0,0,110,948,1,
+ 0,0,0,112,950,1,0,0,0,114,952,1,0,0,0,116,956,1,0,0,0,118,961,1,
+ 0,0,0,120,963,1,0,0,0,122,967,1,0,0,0,124,128,3,2,1,0,125,128,3,
+ 6,3,0,126,128,3,82,41,0,127,124,1,0,0,0,127,125,1,0,0,0,127,126,
+ 1,0,0,0,128,129,1,0,0,0,129,130,5,0,0,1,130,1,1,0,0,0,131,137,3,
+ 4,2,0,132,133,5,176,0,0,133,134,5,4,0,0,134,136,3,4,2,0,135,132,
+ 1,0,0,0,136,139,1,0,0,0,137,135,1,0,0,0,137,138,1,0,0,0,138,3,1,
+ 0,0,0,139,137,1,0,0,0,140,147,3,6,3,0,141,142,5,220,0,0,142,143,
+ 3,2,1,0,143,144,5,236,0,0,144,147,1,0,0,0,145,147,3,122,61,0,146,
+ 140,1,0,0,0,146,141,1,0,0,0,146,145,1,0,0,0,147,5,1,0,0,0,148,150,
+ 3,8,4,0,149,148,1,0,0,0,149,150,1,0,0,0,150,151,1,0,0,0,151,153,
+ 5,146,0,0,152,154,5,49,0,0,153,152,1,0,0,0,153,154,1,0,0,0,154,156,
+ 1,0,0,0,155,157,3,10,5,0,156,155,1,0,0,0,156,157,1,0,0,0,157,158,
+ 1,0,0,0,158,160,3,72,36,0,159,161,3,12,6,0,160,159,1,0,0,0,160,161,
+ 1,0,0,0,161,163,1,0,0,0,162,164,3,14,7,0,163,162,1,0,0,0,163,164,
+ 1,0,0,0,164,166,1,0,0,0,165,167,3,18,9,0,166,165,1,0,0,0,166,167,
+ 1,0,0,0,167,169,1,0,0,0,168,170,3,20,10,0,169,168,1,0,0,0,169,170,
+ 1,0,0,0,170,172,1,0,0,0,171,173,3,22,11,0,172,171,1,0,0,0,172,173,
+ 1,0,0,0,173,176,1,0,0,0,174,175,5,189,0,0,175,177,7,0,0,0,176,174,
+ 1,0,0,0,176,177,1,0,0,0,177,180,1,0,0,0,178,179,5,189,0,0,179,181,
+ 5,169,0,0,180,178,1,0,0,0,180,181,1,0,0,0,181,183,1,0,0,0,182,184,
+ 3,24,12,0,183,182,1,0,0,0,183,184,1,0,0,0,184,186,1,0,0,0,185,187,
+ 3,16,8,0,186,185,1,0,0,0,186,187,1,0,0,0,187,189,1,0,0,0,188,190,
+ 3,26,13,0,189,188,1,0,0,0,189,190,1,0,0,0,190,193,1,0,0,0,191,194,
+ 3,30,15,0,192,194,3,32,16,0,193,191,1,0,0,0,193,192,1,0,0,0,193,
+ 194,1,0,0,0,194,196,1,0,0,0,195,197,3,34,17,0,196,195,1,0,0,0,196,
+ 197,1,0,0,0,197,7,1,0,0,0,198,199,5,189,0,0,199,200,3,86,43,0,200,
+ 9,1,0,0,0,201,202,5,168,0,0,202,205,5,198,0,0,203,204,5,189,0,0,
+ 204,206,5,164,0,0,205,203,1,0,0,0,205,206,1,0,0,0,206,11,1,0,0,0,
+ 207,208,5,68,0,0,208,209,3,36,18,0,209,13,1,0,0,0,210,212,7,1,0,
+ 0,211,210,1,0,0,0,211,212,1,0,0,0,212,213,1,0,0,0,213,214,5,9,0,
+ 0,214,215,5,90,0,0,215,216,3,72,36,0,216,15,1,0,0,0,217,218,5,188,
+ 0,0,218,219,3,118,59,0,219,220,5,10,0,0,220,221,5,220,0,0,221,222,
+ 3,56,28,0,222,232,5,236,0,0,223,224,5,206,0,0,224,225,3,118,59,0,
+ 225,226,5,10,0,0,226,227,5,220,0,0,227,228,3,56,28,0,228,229,5,236,
+ 0,0,229,231,1,0,0,0,230,223,1,0,0,0,231,234,1,0,0,0,232,230,1,0,
+ 0,0,232,233,1,0,0,0,233,17,1,0,0,0,234,232,1,0,0,0,235,236,5,129,
+ 0,0,236,237,3,74,37,0,237,19,1,0,0,0,238,239,5,187,0,0,239,240,3,
+ 74,37,0,240,21,1,0,0,0,241,242,5,73,0,0,242,249,5,18,0,0,243,244,
+ 7,0,0,0,244,245,5,220,0,0,245,246,3,72,36,0,246,247,5,236,0,0,247,
+ 250,1,0,0,0,248,250,3,72,36,0,249,243,1,0,0,0,249,248,1,0,0,0,250,
+ 23,1,0,0,0,251,252,5,74,0,0,252,253,3,74,37,0,253,25,1,0,0,0,254,
+ 255,5,122,0,0,255,256,5,18,0,0,256,257,3,46,23,0,257,27,1,0,0,0,
+ 258,259,5,122,0,0,259,260,5,18,0,0,260,261,3,72,36,0,261,29,1,0,
+ 0,0,262,263,5,99,0,0,263,266,3,74,37,0,264,265,5,206,0,0,265,267,
+ 3,74,37,0,266,264,1,0,0,0,266,267,1,0,0,0,267,272,1,0,0,0,268,269,
+ 5,189,0,0,269,273,5,164,0,0,270,271,5,18,0,0,271,273,3,72,36,0,272,
+ 268,1,0,0,0,272,270,1,0,0,0,272,273,1,0,0,0,273,292,1,0,0,0,274,
+ 275,5,99,0,0,275,278,3,74,37,0,276,277,5,189,0,0,277,279,5,164,0,
+ 0,278,276,1,0,0,0,278,279,1,0,0,0,279,280,1,0,0,0,280,281,5,118,
+ 0,0,281,282,3,74,37,0,282,292,1,0,0,0,283,284,5,99,0,0,284,285,3,
+ 74,37,0,285,286,5,118,0,0,286,289,3,74,37,0,287,288,5,18,0,0,288,
+ 290,3,72,36,0,289,287,1,0,0,0,289,290,1,0,0,0,290,292,1,0,0,0,291,
+ 262,1,0,0,0,291,274,1,0,0,0,291,283,1,0,0,0,292,31,1,0,0,0,293,294,
+ 5,118,0,0,294,295,3,74,37,0,295,33,1,0,0,0,296,297,5,150,0,0,297,
+ 298,3,52,26,0,298,35,1,0,0,0,299,300,6,18,-1,0,300,302,3,94,47,0,
+ 301,303,5,61,0,0,302,301,1,0,0,0,302,303,1,0,0,0,303,305,1,0,0,0,
+ 304,306,3,44,22,0,305,304,1,0,0,0,305,306,1,0,0,0,306,312,1,0,0,
+ 0,307,308,5,220,0,0,308,309,3,36,18,0,309,310,5,236,0,0,310,312,
+ 1,0,0,0,311,299,1,0,0,0,311,307,1,0,0,0,312,327,1,0,0,0,313,314,
+ 10,3,0,0,314,315,3,40,20,0,315,316,3,36,18,4,316,326,1,0,0,0,317,
+ 319,10,4,0,0,318,320,3,38,19,0,319,318,1,0,0,0,319,320,1,0,0,0,320,
+ 321,1,0,0,0,321,322,5,90,0,0,322,323,3,36,18,0,323,324,3,42,21,0,
+ 324,326,1,0,0,0,325,313,1,0,0,0,325,317,1,0,0,0,326,329,1,0,0,0,
+ 327,325,1,0,0,0,327,328,1,0,0,0,328,37,1,0,0,0,329,327,1,0,0,0,330,
+ 332,7,2,0,0,331,330,1,0,0,0,331,332,1,0,0,0,332,333,1,0,0,0,333,
+ 340,5,84,0,0,334,336,5,84,0,0,335,337,7,2,0,0,336,335,1,0,0,0,336,
+ 337,1,0,0,0,337,340,1,0,0,0,338,340,7,2,0,0,339,331,1,0,0,0,339,
+ 334,1,0,0,0,339,338,1,0,0,0,340,374,1,0,0,0,341,343,7,3,0,0,342,
+ 341,1,0,0,0,342,343,1,0,0,0,343,344,1,0,0,0,344,346,7,4,0,0,345,
+ 347,5,123,0,0,346,345,1,0,0,0,346,347,1,0,0,0,347,356,1,0,0,0,348,
+ 350,7,4,0,0,349,351,5,123,0,0,350,349,1,0,0,0,350,351,1,0,0,0,351,
+ 353,1,0,0,0,352,354,7,3,0,0,353,352,1,0,0,0,353,354,1,0,0,0,354,
+ 356,1,0,0,0,355,342,1,0,0,0,355,348,1,0,0,0,356,374,1,0,0,0,357,
+ 359,7,5,0,0,358,357,1,0,0,0,358,359,1,0,0,0,359,360,1,0,0,0,360,
+ 362,5,69,0,0,361,363,5,123,0,0,362,361,1,0,0,0,362,363,1,0,0,0,363,
+ 372,1,0,0,0,364,366,5,69,0,0,365,367,5,123,0,0,366,365,1,0,0,0,366,
+ 367,1,0,0,0,367,369,1,0,0,0,368,370,7,5,0,0,369,368,1,0,0,0,369,
+ 370,1,0,0,0,370,372,1,0,0,0,371,358,1,0,0,0,371,364,1,0,0,0,372,
+ 374,1,0,0,0,373,339,1,0,0,0,373,355,1,0,0,0,373,371,1,0,0,0,374,
+ 39,1,0,0,0,375,376,5,31,0,0,376,379,5,90,0,0,377,379,5,206,0,0,378,
+ 375,1,0,0,0,378,377,1,0,0,0,379,41,1,0,0,0,380,381,5,119,0,0,381,
+ 390,3,72,36,0,382,383,5,179,0,0,383,384,5,220,0,0,384,385,3,72,36,
+ 0,385,386,5,236,0,0,386,390,1,0,0,0,387,388,5,179,0,0,388,390,3,
+ 72,36,0,389,380,1,0,0,0,389,382,1,0,0,0,389,387,1,0,0,0,390,43,1,
+ 0,0,0,391,392,5,144,0,0,392,395,3,50,25,0,393,394,5,118,0,0,394,
+ 396,3,50,25,0,395,393,1,0,0,0,395,396,1,0,0,0,396,45,1,0,0,0,397,
+ 402,3,48,24,0,398,399,5,206,0,0,399,401,3,48,24,0,400,398,1,0,0,
+ 0,401,404,1,0,0,0,402,400,1,0,0,0,402,403,1,0,0,0,403,47,1,0,0,0,
+ 404,402,1,0,0,0,405,407,3,74,37,0,406,408,7,6,0,0,407,406,1,0,0,
+ 0,407,408,1,0,0,0,408,411,1,0,0,0,409,410,5,117,0,0,410,412,7,7,
+ 0,0,411,409,1,0,0,0,411,412,1,0,0,0,412,415,1,0,0,0,413,414,5,26,
+ 0,0,414,416,5,200,0,0,415,413,1,0,0,0,415,416,1,0,0,0,416,49,1,0,
+ 0,0,417,424,3,122,61,0,418,421,3,106,53,0,419,420,5,238,0,0,420,
+ 422,3,106,53,0,421,419,1,0,0,0,421,422,1,0,0,0,422,424,1,0,0,0,423,
+ 417,1,0,0,0,423,418,1,0,0,0,424,51,1,0,0,0,425,430,3,54,27,0,426,
+ 427,5,206,0,0,427,429,3,54,27,0,428,426,1,0,0,0,429,432,1,0,0,0,
+ 430,428,1,0,0,0,430,431,1,0,0,0,431,53,1,0,0,0,432,430,1,0,0,0,433,
+ 434,3,118,59,0,434,435,5,212,0,0,435,436,3,108,54,0,436,55,1,0,0,
+ 0,437,439,3,58,29,0,438,437,1,0,0,0,438,439,1,0,0,0,439,441,1,0,
+ 0,0,440,442,3,60,30,0,441,440,1,0,0,0,441,442,1,0,0,0,442,444,1,
+ 0,0,0,443,445,3,62,31,0,444,443,1,0,0,0,444,445,1,0,0,0,445,57,1,
+ 0,0,0,446,447,5,126,0,0,447,448,5,18,0,0,448,449,3,72,36,0,449,59,
+ 1,0,0,0,450,451,5,122,0,0,451,452,5,18,0,0,452,453,3,46,23,0,453,
+ 61,1,0,0,0,454,455,7,8,0,0,455,456,3,64,32,0,456,63,1,0,0,0,457,
+ 464,3,66,33,0,458,459,5,16,0,0,459,460,3,66,33,0,460,461,5,6,0,0,
+ 461,462,3,66,33,0,462,464,1,0,0,0,463,457,1,0,0,0,463,458,1,0,0,
+ 0,464,65,1,0,0,0,465,466,5,33,0,0,466,478,5,142,0,0,467,468,5,175,
+ 0,0,468,478,5,128,0,0,469,470,5,175,0,0,470,478,5,64,0,0,471,472,
+ 3,106,53,0,472,473,5,128,0,0,473,478,1,0,0,0,474,475,3,106,53,0,
+ 475,476,5,64,0,0,476,478,1,0,0,0,477,465,1,0,0,0,477,467,1,0,0,0,
+ 477,469,1,0,0,0,477,471,1,0,0,0,477,474,1,0,0,0,478,67,1,0,0,0,479,
+ 480,3,74,37,0,480,481,5,0,0,1,481,69,1,0,0,0,482,530,3,118,59,0,
+ 483,484,3,118,59,0,484,485,5,220,0,0,485,486,3,118,59,0,486,493,
+ 3,70,35,0,487,488,5,206,0,0,488,489,3,118,59,0,489,490,3,70,35,0,
+ 490,492,1,0,0,0,491,487,1,0,0,0,492,495,1,0,0,0,493,491,1,0,0,0,
+ 493,494,1,0,0,0,494,496,1,0,0,0,495,493,1,0,0,0,496,497,5,236,0,
+ 0,497,530,1,0,0,0,498,499,3,118,59,0,499,500,5,220,0,0,500,505,3,
+ 120,60,0,501,502,5,206,0,0,502,504,3,120,60,0,503,501,1,0,0,0,504,
+ 507,1,0,0,0,505,503,1,0,0,0,505,506,1,0,0,0,506,508,1,0,0,0,507,
+ 505,1,0,0,0,508,509,5,236,0,0,509,530,1,0,0,0,510,511,3,118,59,0,
+ 511,512,5,220,0,0,512,517,3,70,35,0,513,514,5,206,0,0,514,516,3,
+ 70,35,0,515,513,1,0,0,0,516,519,1,0,0,0,517,515,1,0,0,0,517,518,
+ 1,0,0,0,518,520,1,0,0,0,519,517,1,0,0,0,520,521,5,236,0,0,521,530,
+ 1,0,0,0,522,523,3,118,59,0,523,525,5,220,0,0,524,526,3,72,36,0,525,
+ 524,1,0,0,0,525,526,1,0,0,0,526,527,1,0,0,0,527,528,5,236,0,0,528,
+ 530,1,0,0,0,529,482,1,0,0,0,529,483,1,0,0,0,529,498,1,0,0,0,529,
+ 510,1,0,0,0,529,522,1,0,0,0,530,71,1,0,0,0,531,536,3,74,37,0,532,
+ 533,5,206,0,0,533,535,3,74,37,0,534,532,1,0,0,0,535,538,1,0,0,0,
+ 536,534,1,0,0,0,536,537,1,0,0,0,537,73,1,0,0,0,538,536,1,0,0,0,539,
+ 540,6,37,-1,0,540,542,5,19,0,0,541,543,3,74,37,0,542,541,1,0,0,0,
+ 542,543,1,0,0,0,543,549,1,0,0,0,544,545,5,186,0,0,545,546,3,74,37,
+ 0,546,547,5,163,0,0,547,548,3,74,37,0,548,550,1,0,0,0,549,544,1,
+ 0,0,0,550,551,1,0,0,0,551,549,1,0,0,0,551,552,1,0,0,0,552,555,1,
+ 0,0,0,553,554,5,52,0,0,554,556,3,74,37,0,555,553,1,0,0,0,555,556,
+ 1,0,0,0,556,557,1,0,0,0,557,558,5,53,0,0,558,663,1,0,0,0,559,560,
+ 5,20,0,0,560,561,5,220,0,0,561,562,3,74,37,0,562,563,5,10,0,0,563,
+ 564,3,70,35,0,564,565,5,236,0,0,565,663,1,0,0,0,566,567,5,36,0,0,
+ 567,663,5,200,0,0,568,569,5,86,0,0,569,570,3,74,37,0,570,571,3,110,
+ 55,0,571,663,1,0,0,0,572,573,5,155,0,0,573,574,5,220,0,0,574,575,
+ 3,74,37,0,575,576,5,68,0,0,576,579,3,74,37,0,577,578,5,65,0,0,578,
+ 580,3,74,37,0,579,577,1,0,0,0,579,580,1,0,0,0,580,581,1,0,0,0,581,
+ 582,5,236,0,0,582,663,1,0,0,0,583,584,5,166,0,0,584,663,5,200,0,
+ 0,585,586,5,171,0,0,586,587,5,220,0,0,587,588,7,9,0,0,588,589,5,
+ 200,0,0,589,590,5,68,0,0,590,591,3,74,37,0,591,592,5,236,0,0,592,
+ 663,1,0,0,0,593,594,3,118,59,0,594,596,5,220,0,0,595,597,3,72,36,
+ 0,596,595,1,0,0,0,596,597,1,0,0,0,597,598,1,0,0,0,598,599,5,236,
+ 0,0,599,600,1,0,0,0,600,601,5,125,0,0,601,602,5,220,0,0,602,603,
+ 3,56,28,0,603,604,5,236,0,0,604,663,1,0,0,0,605,606,3,118,59,0,606,
+ 608,5,220,0,0,607,609,3,72,36,0,608,607,1,0,0,0,608,609,1,0,0,0,
+ 609,610,1,0,0,0,610,611,5,236,0,0,611,612,1,0,0,0,612,613,5,125,
+ 0,0,613,614,3,118,59,0,614,663,1,0,0,0,615,621,3,118,59,0,616,618,
+ 5,220,0,0,617,619,3,72,36,0,618,617,1,0,0,0,618,619,1,0,0,0,619,
+ 620,1,0,0,0,620,622,5,236,0,0,621,616,1,0,0,0,621,622,1,0,0,0,622,
+ 623,1,0,0,0,623,625,5,220,0,0,624,626,5,49,0,0,625,624,1,0,0,0,625,
+ 626,1,0,0,0,626,628,1,0,0,0,627,629,3,76,38,0,628,627,1,0,0,0,628,
+ 629,1,0,0,0,629,630,1,0,0,0,630,631,5,236,0,0,631,663,1,0,0,0,632,
+ 663,3,82,41,0,633,663,3,108,54,0,634,635,5,208,0,0,635,663,3,74,
+ 37,18,636,637,5,115,0,0,637,663,3,74,37,12,638,639,3,98,49,0,639,
+ 640,5,210,0,0,640,642,1,0,0,0,641,638,1,0,0,0,641,642,1,0,0,0,642,
+ 643,1,0,0,0,643,663,5,202,0,0,644,645,5,220,0,0,645,646,3,2,1,0,
+ 646,647,5,236,0,0,647,663,1,0,0,0,648,649,5,220,0,0,649,650,3,74,
+ 37,0,650,651,5,236,0,0,651,663,1,0,0,0,652,653,5,220,0,0,653,654,
+ 3,72,36,0,654,655,5,236,0,0,655,663,1,0,0,0,656,658,5,219,0,0,657,
+ 659,3,72,36,0,658,657,1,0,0,0,658,659,1,0,0,0,659,660,1,0,0,0,660,
+ 663,5,235,0,0,661,663,3,90,45,0,662,539,1,0,0,0,662,559,1,0,0,0,
+ 662,566,1,0,0,0,662,568,1,0,0,0,662,572,1,0,0,0,662,583,1,0,0,0,
+ 662,585,1,0,0,0,662,593,1,0,0,0,662,605,1,0,0,0,662,615,1,0,0,0,
+ 662,632,1,0,0,0,662,633,1,0,0,0,662,634,1,0,0,0,662,636,1,0,0,0,
+ 662,641,1,0,0,0,662,644,1,0,0,0,662,648,1,0,0,0,662,652,1,0,0,0,
+ 662,656,1,0,0,0,662,661,1,0,0,0,663,757,1,0,0,0,664,668,10,17,0,
+ 0,665,669,5,202,0,0,666,669,5,238,0,0,667,669,5,227,0,0,668,665,
+ 1,0,0,0,668,666,1,0,0,0,668,667,1,0,0,0,669,670,1,0,0,0,670,756,
+ 3,74,37,18,671,675,10,16,0,0,672,676,5,228,0,0,673,676,5,208,0,0,
+ 674,676,5,207,0,0,675,672,1,0,0,0,675,673,1,0,0,0,675,674,1,0,0,
+ 0,676,677,1,0,0,0,677,756,3,74,37,17,678,703,10,15,0,0,679,704,5,
+ 211,0,0,680,704,5,212,0,0,681,704,5,223,0,0,682,704,5,221,0,0,683,
+ 704,5,222,0,0,684,704,5,213,0,0,685,704,5,214,0,0,686,688,5,115,
+ 0,0,687,686,1,0,0,0,687,688,1,0,0,0,688,689,1,0,0,0,689,691,5,80,
+ 0,0,690,692,5,25,0,0,691,690,1,0,0,0,691,692,1,0,0,0,692,704,1,0,
+ 0,0,693,695,5,115,0,0,694,693,1,0,0,0,694,695,1,0,0,0,695,696,1,
+ 0,0,0,696,704,7,10,0,0,697,704,5,232,0,0,698,704,5,233,0,0,699,704,
+ 5,225,0,0,700,704,5,216,0,0,701,704,5,217,0,0,702,704,5,224,0,0,
+ 703,679,1,0,0,0,703,680,1,0,0,0,703,681,1,0,0,0,703,682,1,0,0,0,
+ 703,683,1,0,0,0,703,684,1,0,0,0,703,685,1,0,0,0,703,687,1,0,0,0,
+ 703,694,1,0,0,0,703,697,1,0,0,0,703,698,1,0,0,0,703,699,1,0,0,0,
+ 703,700,1,0,0,0,703,701,1,0,0,0,703,702,1,0,0,0,704,705,1,0,0,0,
+ 705,756,3,74,37,16,706,707,10,13,0,0,707,708,5,226,0,0,708,756,3,
+ 74,37,14,709,710,10,11,0,0,710,711,5,6,0,0,711,756,3,74,37,12,712,
+ 713,10,10,0,0,713,714,5,121,0,0,714,756,3,74,37,11,715,717,10,9,
+ 0,0,716,718,5,115,0,0,717,716,1,0,0,0,717,718,1,0,0,0,718,719,1,
+ 0,0,0,719,720,5,16,0,0,720,721,3,74,37,0,721,722,5,6,0,0,722,723,
+ 3,74,37,10,723,756,1,0,0,0,724,725,10,8,0,0,725,726,5,229,0,0,726,
+ 727,3,74,37,0,727,728,5,205,0,0,728,729,3,74,37,8,729,756,1,0,0,
+ 0,730,731,10,21,0,0,731,732,5,219,0,0,732,733,3,74,37,0,733,734,
+ 5,235,0,0,734,756,1,0,0,0,735,736,10,20,0,0,736,737,5,210,0,0,737,
+ 756,5,198,0,0,738,739,10,19,0,0,739,740,5,210,0,0,740,756,3,118,
+ 59,0,741,742,10,14,0,0,742,744,5,88,0,0,743,745,5,115,0,0,744,743,
+ 1,0,0,0,744,745,1,0,0,0,745,746,1,0,0,0,746,756,5,116,0,0,747,753,
+ 10,7,0,0,748,754,3,116,58,0,749,750,5,10,0,0,750,754,3,118,59,0,
+ 751,752,5,10,0,0,752,754,5,200,0,0,753,748,1,0,0,0,753,749,1,0,0,
+ 0,753,751,1,0,0,0,754,756,1,0,0,0,755,664,1,0,0,0,755,671,1,0,0,
+ 0,755,678,1,0,0,0,755,706,1,0,0,0,755,709,1,0,0,0,755,712,1,0,0,
+ 0,755,715,1,0,0,0,755,724,1,0,0,0,755,730,1,0,0,0,755,735,1,0,0,
+ 0,755,738,1,0,0,0,755,741,1,0,0,0,755,747,1,0,0,0,756,759,1,0,0,
+ 0,757,755,1,0,0,0,757,758,1,0,0,0,758,75,1,0,0,0,759,757,1,0,0,0,
+ 760,765,3,78,39,0,761,762,5,206,0,0,762,764,3,78,39,0,763,761,1,
+ 0,0,0,764,767,1,0,0,0,765,763,1,0,0,0,765,766,1,0,0,0,766,77,1,0,
+ 0,0,767,765,1,0,0,0,768,771,3,80,40,0,769,771,3,74,37,0,770,768,
+ 1,0,0,0,770,769,1,0,0,0,771,79,1,0,0,0,772,773,5,220,0,0,773,778,
+ 3,118,59,0,774,775,5,206,0,0,775,777,3,118,59,0,776,774,1,0,0,0,
+ 777,780,1,0,0,0,778,776,1,0,0,0,778,779,1,0,0,0,779,781,1,0,0,0,
+ 780,778,1,0,0,0,781,782,5,236,0,0,782,792,1,0,0,0,783,788,3,118,
+ 59,0,784,785,5,206,0,0,785,787,3,118,59,0,786,784,1,0,0,0,787,790,
+ 1,0,0,0,788,786,1,0,0,0,788,789,1,0,0,0,789,792,1,0,0,0,790,788,
+ 1,0,0,0,791,772,1,0,0,0,791,783,1,0,0,0,792,793,1,0,0,0,793,794,
+ 5,201,0,0,794,795,3,74,37,0,795,81,1,0,0,0,796,797,5,222,0,0,797,
+ 801,3,118,59,0,798,800,3,84,42,0,799,798,1,0,0,0,800,803,1,0,0,0,
+ 801,799,1,0,0,0,801,802,1,0,0,0,802,804,1,0,0,0,803,801,1,0,0,0,
+ 804,805,5,238,0,0,805,806,5,214,0,0,806,825,1,0,0,0,807,808,5,222,
+ 0,0,808,812,3,118,59,0,809,811,3,84,42,0,810,809,1,0,0,0,811,814,
+ 1,0,0,0,812,810,1,0,0,0,812,813,1,0,0,0,813,815,1,0,0,0,814,812,
+ 1,0,0,0,815,817,5,214,0,0,816,818,3,82,41,0,817,816,1,0,0,0,817,
+ 818,1,0,0,0,818,819,1,0,0,0,819,820,5,222,0,0,820,821,5,238,0,0,
+ 821,822,3,118,59,0,822,823,5,214,0,0,823,825,1,0,0,0,824,796,1,0,
+ 0,0,824,807,1,0,0,0,825,83,1,0,0,0,826,827,3,118,59,0,827,828,5,
+ 212,0,0,828,829,5,200,0,0,829,838,1,0,0,0,830,831,3,118,59,0,831,
+ 832,5,212,0,0,832,833,5,218,0,0,833,834,3,74,37,0,834,835,5,234,
+ 0,0,835,838,1,0,0,0,836,838,3,118,59,0,837,826,1,0,0,0,837,830,1,
+ 0,0,0,837,836,1,0,0,0,838,85,1,0,0,0,839,844,3,88,44,0,840,841,5,
+ 206,0,0,841,843,3,88,44,0,842,840,1,0,0,0,843,846,1,0,0,0,844,842,
+ 1,0,0,0,844,845,1,0,0,0,845,87,1,0,0,0,846,844,1,0,0,0,847,848,3,
+ 118,59,0,848,849,5,10,0,0,849,850,5,220,0,0,850,851,3,2,1,0,851,
+ 852,5,236,0,0,852,858,1,0,0,0,853,854,3,74,37,0,854,855,5,10,0,0,
+ 855,856,3,118,59,0,856,858,1,0,0,0,857,847,1,0,0,0,857,853,1,0,0,
+ 0,858,89,1,0,0,0,859,867,3,122,61,0,860,861,3,98,49,0,861,862,5,
+ 210,0,0,862,864,1,0,0,0,863,860,1,0,0,0,863,864,1,0,0,0,864,865,
+ 1,0,0,0,865,867,3,92,46,0,866,859,1,0,0,0,866,863,1,0,0,0,867,91,
+ 1,0,0,0,868,873,3,118,59,0,869,870,5,210,0,0,870,872,3,118,59,0,
+ 871,869,1,0,0,0,872,875,1,0,0,0,873,871,1,0,0,0,873,874,1,0,0,0,
+ 874,93,1,0,0,0,875,873,1,0,0,0,876,877,6,47,-1,0,877,886,3,98,49,
+ 0,878,886,3,96,48,0,879,880,5,220,0,0,880,881,3,2,1,0,881,882,5,
+ 236,0,0,882,886,1,0,0,0,883,886,3,82,41,0,884,886,3,122,61,0,885,
+ 876,1,0,0,0,885,878,1,0,0,0,885,879,1,0,0,0,885,883,1,0,0,0,885,
+ 884,1,0,0,0,886,895,1,0,0,0,887,891,10,3,0,0,888,892,3,116,58,0,
+ 889,890,5,10,0,0,890,892,3,118,59,0,891,888,1,0,0,0,891,889,1,0,
+ 0,0,892,894,1,0,0,0,893,887,1,0,0,0,894,897,1,0,0,0,895,893,1,0,
+ 0,0,895,896,1,0,0,0,896,95,1,0,0,0,897,895,1,0,0,0,898,899,3,118,
+ 59,0,899,901,5,220,0,0,900,902,3,100,50,0,901,900,1,0,0,0,901,902,
+ 1,0,0,0,902,903,1,0,0,0,903,904,5,236,0,0,904,97,1,0,0,0,905,906,
+ 3,102,51,0,906,907,5,210,0,0,907,909,1,0,0,0,908,905,1,0,0,0,908,
+ 909,1,0,0,0,909,910,1,0,0,0,910,911,3,118,59,0,911,99,1,0,0,0,912,
+ 917,3,74,37,0,913,914,5,206,0,0,914,916,3,74,37,0,915,913,1,0,0,
+ 0,916,919,1,0,0,0,917,915,1,0,0,0,917,918,1,0,0,0,918,101,1,0,0,
+ 0,919,917,1,0,0,0,920,921,3,118,59,0,921,103,1,0,0,0,922,931,5,196,
+ 0,0,923,924,5,210,0,0,924,931,7,11,0,0,925,926,5,198,0,0,926,928,
+ 5,210,0,0,927,929,7,11,0,0,928,927,1,0,0,0,928,929,1,0,0,0,929,931,
+ 1,0,0,0,930,922,1,0,0,0,930,923,1,0,0,0,930,925,1,0,0,0,931,105,
+ 1,0,0,0,932,934,7,12,0,0,933,932,1,0,0,0,933,934,1,0,0,0,934,941,
+ 1,0,0,0,935,942,3,104,52,0,936,942,5,197,0,0,937,942,5,198,0,0,938,
+ 942,5,199,0,0,939,942,5,82,0,0,940,942,5,113,0,0,941,935,1,0,0,0,
+ 941,936,1,0,0,0,941,937,1,0,0,0,941,938,1,0,0,0,941,939,1,0,0,0,
+ 941,940,1,0,0,0,942,107,1,0,0,0,943,947,3,106,53,0,944,947,5,200,
+ 0,0,945,947,5,116,0,0,946,943,1,0,0,0,946,944,1,0,0,0,946,945,1,
+ 0,0,0,947,109,1,0,0,0,948,949,7,13,0,0,949,111,1,0,0,0,950,951,7,
+ 14,0,0,951,113,1,0,0,0,952,953,7,15,0,0,953,115,1,0,0,0,954,957,
+ 5,195,0,0,955,957,3,114,57,0,956,954,1,0,0,0,956,955,1,0,0,0,957,
+ 117,1,0,0,0,958,962,5,195,0,0,959,962,3,110,55,0,960,962,3,112,56,
+ 0,961,958,1,0,0,0,961,959,1,0,0,0,961,960,1,0,0,0,962,119,1,0,0,
+ 0,963,964,5,200,0,0,964,965,5,212,0,0,965,966,3,106,53,0,966,121,
+ 1,0,0,0,967,968,5,218,0,0,968,969,3,118,59,0,969,970,5,234,0,0,970,
+ 123,1,0,0,0,120,127,137,146,149,153,156,160,163,166,169,172,176,
+ 180,183,186,189,193,196,205,211,232,249,266,272,278,289,291,302,
+ 305,311,319,325,327,331,336,339,342,346,350,353,355,358,362,366,
+ 369,371,373,378,389,395,402,407,411,415,421,423,430,438,441,444,
+ 463,477,493,505,517,525,529,536,542,551,555,579,596,608,618,621,
+ 625,628,641,658,662,668,675,687,691,694,703,717,744,753,755,757,
+ 765,770,778,788,791,801,812,817,824,837,844,857,863,866,873,885,
+ 891,895,901,908,917,928,930,933,941,946,956,961
]
class HogQLParser ( Parser ):
@@ -4150,34 +4148,6 @@ def accept(self, visitor:ParseTreeVisitor):
return visitor.visitChildren(self)
- class ColumnExprExtractContext(ColumnExprContext):
-
- def __init__(self, parser, ctx:ParserRuleContext): # actually a HogQLParser.ColumnExprContext
- super().__init__(parser)
- self.copyFrom(ctx)
-
- def EXTRACT(self):
- return self.getToken(HogQLParser.EXTRACT, 0)
- def LPAREN(self):
- return self.getToken(HogQLParser.LPAREN, 0)
- def interval(self):
- return self.getTypedRuleContext(HogQLParser.IntervalContext,0)
-
- def FROM(self):
- return self.getToken(HogQLParser.FROM, 0)
- def columnExpr(self):
- return self.getTypedRuleContext(HogQLParser.ColumnExprContext,0)
-
- def RPAREN(self):
- return self.getToken(HogQLParser.RPAREN, 0)
-
- def accept(self, visitor:ParseTreeVisitor):
- if hasattr( visitor, "visitColumnExprExtract" ):
- return visitor.visitColumnExprExtract(self)
- else:
- return visitor.visitChildren(self)
-
-
class ColumnExprNegateContext(ColumnExprContext):
def __init__(self, parser, ctx:ParserRuleContext): # actually a HogQLParser.ColumnExprContext
@@ -4970,7 +4940,7 @@ def columnExpr(self, _p:int=0):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 669
+ self.state = 662
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,80,self._ctx)
if la_ == 1:
@@ -5049,317 +5019,299 @@ def columnExpr(self, _p:int=0):
pass
elif la_ == 4:
- localctx = HogQLParser.ColumnExprExtractContext(self, localctx)
+ localctx = HogQLParser.ColumnExprIntervalContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
self.state = 568
- self.match(HogQLParser.EXTRACT)
+ self.match(HogQLParser.INTERVAL)
self.state = 569
- self.match(HogQLParser.LPAREN)
+ self.columnExpr(0)
self.state = 570
self.interval()
- self.state = 571
- self.match(HogQLParser.FROM)
- self.state = 572
- self.columnExpr(0)
- self.state = 573
- self.match(HogQLParser.RPAREN)
pass
elif la_ == 5:
- localctx = HogQLParser.ColumnExprIntervalContext(self, localctx)
- self._ctx = localctx
- _prevctx = localctx
- self.state = 575
- self.match(HogQLParser.INTERVAL)
- self.state = 576
- self.columnExpr(0)
- self.state = 577
- self.interval()
- pass
-
- elif la_ == 6:
localctx = HogQLParser.ColumnExprSubstringContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 579
+ self.state = 572
self.match(HogQLParser.SUBSTRING)
- self.state = 580
+ self.state = 573
self.match(HogQLParser.LPAREN)
- self.state = 581
+ self.state = 574
self.columnExpr(0)
- self.state = 582
+ self.state = 575
self.match(HogQLParser.FROM)
- self.state = 583
+ self.state = 576
self.columnExpr(0)
- self.state = 586
+ self.state = 579
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==65:
- self.state = 584
+ self.state = 577
self.match(HogQLParser.FOR)
- self.state = 585
+ self.state = 578
self.columnExpr(0)
- self.state = 588
+ self.state = 581
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 7:
+ elif la_ == 6:
localctx = HogQLParser.ColumnExprTimestampContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 590
+ self.state = 583
self.match(HogQLParser.TIMESTAMP)
- self.state = 591
+ self.state = 584
self.match(HogQLParser.STRING_LITERAL)
pass
- elif la_ == 8:
+ elif la_ == 7:
localctx = HogQLParser.ColumnExprTrimContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 592
+ self.state = 585
self.match(HogQLParser.TRIM)
- self.state = 593
+ self.state = 586
self.match(HogQLParser.LPAREN)
- self.state = 594
+ self.state = 587
_la = self._input.LA(1)
if not(_la==17 or _la==95 or _la==170):
self._errHandler.recoverInline(self)
else:
self._errHandler.reportMatch(self)
self.consume()
- self.state = 595
+ self.state = 588
self.match(HogQLParser.STRING_LITERAL)
- self.state = 596
+ self.state = 589
self.match(HogQLParser.FROM)
- self.state = 597
+ self.state = 590
self.columnExpr(0)
- self.state = 598
+ self.state = 591
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 9:
+ elif la_ == 8:
localctx = HogQLParser.ColumnExprWinFunctionContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 600
+ self.state = 593
self.identifier()
- self.state = 601
+ self.state = 594
self.match(HogQLParser.LPAREN)
- self.state = 603
+ self.state = 596
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -1) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or ((((_la - 192)) & ~0x3f) == 0 and ((1 << (_la - 192)) & 70263309817) != 0):
- self.state = 602
+ self.state = 595
self.columnExprList()
- self.state = 605
+ self.state = 598
self.match(HogQLParser.RPAREN)
- self.state = 607
+ self.state = 600
self.match(HogQLParser.OVER)
- self.state = 608
+ self.state = 601
self.match(HogQLParser.LPAREN)
- self.state = 609
+ self.state = 602
self.windowExpr()
- self.state = 610
+ self.state = 603
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 10:
+ elif la_ == 9:
localctx = HogQLParser.ColumnExprWinFunctionTargetContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 612
+ self.state = 605
self.identifier()
- self.state = 613
+ self.state = 606
self.match(HogQLParser.LPAREN)
- self.state = 615
+ self.state = 608
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -1) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or ((((_la - 192)) & ~0x3f) == 0 and ((1 << (_la - 192)) & 70263309817) != 0):
- self.state = 614
+ self.state = 607
self.columnExprList()
- self.state = 617
+ self.state = 610
self.match(HogQLParser.RPAREN)
- self.state = 619
+ self.state = 612
self.match(HogQLParser.OVER)
- self.state = 620
+ self.state = 613
self.identifier()
pass
- elif la_ == 11:
+ elif la_ == 10:
localctx = HogQLParser.ColumnExprFunctionContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 622
+ self.state = 615
self.identifier()
- self.state = 628
+ self.state = 621
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,75,self._ctx)
if la_ == 1:
- self.state = 623
+ self.state = 616
self.match(HogQLParser.LPAREN)
- self.state = 625
+ self.state = 618
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -1) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or ((((_la - 192)) & ~0x3f) == 0 and ((1 << (_la - 192)) & 70263309817) != 0):
- self.state = 624
+ self.state = 617
self.columnExprList()
- self.state = 627
+ self.state = 620
self.match(HogQLParser.RPAREN)
- self.state = 630
+ self.state = 623
self.match(HogQLParser.LPAREN)
- self.state = 632
+ self.state = 625
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,76,self._ctx)
if la_ == 1:
- self.state = 631
+ self.state = 624
self.match(HogQLParser.DISTINCT)
- self.state = 635
+ self.state = 628
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -1) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or ((((_la - 192)) & ~0x3f) == 0 and ((1 << (_la - 192)) & 70263309817) != 0):
- self.state = 634
+ self.state = 627
self.columnArgList()
- self.state = 637
+ self.state = 630
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 12:
+ elif la_ == 11:
localctx = HogQLParser.ColumnExprTagElementContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 639
+ self.state = 632
self.hogqlxTagElement()
pass
- elif la_ == 13:
+ elif la_ == 12:
localctx = HogQLParser.ColumnExprLiteralContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 640
+ self.state = 633
self.literal()
pass
- elif la_ == 14:
+ elif la_ == 13:
localctx = HogQLParser.ColumnExprNegateContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 641
+ self.state = 634
self.match(HogQLParser.DASH)
- self.state = 642
+ self.state = 635
self.columnExpr(18)
pass
- elif la_ == 15:
+ elif la_ == 14:
localctx = HogQLParser.ColumnExprNotContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 643
+ self.state = 636
self.match(HogQLParser.NOT)
- self.state = 644
+ self.state = 637
self.columnExpr(12)
pass
- elif la_ == 16:
+ elif la_ == 15:
localctx = HogQLParser.ColumnExprAsteriskContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 648
+ self.state = 641
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -5066549581053953) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or _la==192 or _la==195:
- self.state = 645
+ self.state = 638
self.tableIdentifier()
- self.state = 646
+ self.state = 639
self.match(HogQLParser.DOT)
- self.state = 650
+ self.state = 643
self.match(HogQLParser.ASTERISK)
pass
- elif la_ == 17:
+ elif la_ == 16:
localctx = HogQLParser.ColumnExprSubqueryContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 651
+ self.state = 644
self.match(HogQLParser.LPAREN)
- self.state = 652
+ self.state = 645
self.selectUnionStmt()
- self.state = 653
+ self.state = 646
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 18:
+ elif la_ == 17:
localctx = HogQLParser.ColumnExprParensContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 655
+ self.state = 648
self.match(HogQLParser.LPAREN)
- self.state = 656
+ self.state = 649
self.columnExpr(0)
- self.state = 657
+ self.state = 650
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 19:
+ elif la_ == 18:
localctx = HogQLParser.ColumnExprTupleContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 659
+ self.state = 652
self.match(HogQLParser.LPAREN)
- self.state = 660
+ self.state = 653
self.columnExprList()
- self.state = 661
+ self.state = 654
self.match(HogQLParser.RPAREN)
pass
- elif la_ == 20:
+ elif la_ == 19:
localctx = HogQLParser.ColumnExprArrayContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 663
+ self.state = 656
self.match(HogQLParser.LBRACKET)
- self.state = 665
+ self.state = 658
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -1) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or ((((_la - 192)) & ~0x3f) == 0 and ((1 << (_la - 192)) & 70263309817) != 0):
- self.state = 664
+ self.state = 657
self.columnExprList()
- self.state = 667
+ self.state = 660
self.match(HogQLParser.RBRACKET)
pass
- elif la_ == 21:
+ elif la_ == 20:
localctx = HogQLParser.ColumnExprIdentifierContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 668
+ self.state = 661
self.columnIdentifier()
pass
self._ctx.stop = self._input.LT(-1)
- self.state = 764
+ self.state = 757
self._errHandler.sync(self)
_alt = self._interp.adaptivePredict(self._input,91,self._ctx)
while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER:
@@ -5367,36 +5319,36 @@ def columnExpr(self, _p:int=0):
if self._parseListeners is not None:
self.triggerExitRuleEvent()
_prevctx = localctx
- self.state = 762
+ self.state = 755
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,90,self._ctx)
if la_ == 1:
localctx = HogQLParser.ColumnExprPrecedence1Context(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
localctx.left = _prevctx
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 671
+ self.state = 664
if not self.precpred(self._ctx, 17):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 17)")
- self.state = 675
+ self.state = 668
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [202]:
- self.state = 672
+ self.state = 665
localctx.operator = self.match(HogQLParser.ASTERISK)
pass
elif token in [238]:
- self.state = 673
+ self.state = 666
localctx.operator = self.match(HogQLParser.SLASH)
pass
elif token in [227]:
- self.state = 674
+ self.state = 667
localctx.operator = self.match(HogQLParser.PERCENT)
pass
else:
raise NoViableAltException(self)
- self.state = 677
+ self.state = 670
localctx.right = self.columnExpr(18)
pass
@@ -5404,29 +5356,29 @@ def columnExpr(self, _p:int=0):
localctx = HogQLParser.ColumnExprPrecedence2Context(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
localctx.left = _prevctx
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 678
+ self.state = 671
if not self.precpred(self._ctx, 16):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 16)")
- self.state = 682
+ self.state = 675
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [228]:
- self.state = 679
+ self.state = 672
localctx.operator = self.match(HogQLParser.PLUS)
pass
elif token in [208]:
- self.state = 680
+ self.state = 673
localctx.operator = self.match(HogQLParser.DASH)
pass
elif token in [207]:
- self.state = 681
+ self.state = 674
localctx.operator = self.match(HogQLParser.CONCAT)
pass
else:
raise NoViableAltException(self)
- self.state = 684
+ self.state = 677
localctx.right = self.columnExpr(17)
pass
@@ -5434,79 +5386,79 @@ def columnExpr(self, _p:int=0):
localctx = HogQLParser.ColumnExprPrecedence3Context(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
localctx.left = _prevctx
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 685
+ self.state = 678
if not self.precpred(self._ctx, 15):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 15)")
- self.state = 710
+ self.state = 703
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,86,self._ctx)
if la_ == 1:
- self.state = 686
+ self.state = 679
localctx.operator = self.match(HogQLParser.EQ_DOUBLE)
pass
elif la_ == 2:
- self.state = 687
+ self.state = 680
localctx.operator = self.match(HogQLParser.EQ_SINGLE)
pass
elif la_ == 3:
- self.state = 688
+ self.state = 681
localctx.operator = self.match(HogQLParser.NOT_EQ)
pass
elif la_ == 4:
- self.state = 689
+ self.state = 682
localctx.operator = self.match(HogQLParser.LT_EQ)
pass
elif la_ == 5:
- self.state = 690
+ self.state = 683
localctx.operator = self.match(HogQLParser.LT)
pass
elif la_ == 6:
- self.state = 691
+ self.state = 684
localctx.operator = self.match(HogQLParser.GT_EQ)
pass
elif la_ == 7:
- self.state = 692
+ self.state = 685
localctx.operator = self.match(HogQLParser.GT)
pass
elif la_ == 8:
- self.state = 694
+ self.state = 687
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==115:
- self.state = 693
+ self.state = 686
localctx.operator = self.match(HogQLParser.NOT)
- self.state = 696
+ self.state = 689
self.match(HogQLParser.IN)
- self.state = 698
+ self.state = 691
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==25:
- self.state = 697
+ self.state = 690
self.match(HogQLParser.COHORT)
pass
elif la_ == 9:
- self.state = 701
+ self.state = 694
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==115:
- self.state = 700
+ self.state = 693
localctx.operator = self.match(HogQLParser.NOT)
- self.state = 703
+ self.state = 696
_la = self._input.LA(1)
if not(_la==79 or _la==98):
self._errHandler.recoverInline(self)
@@ -5516,209 +5468,209 @@ def columnExpr(self, _p:int=0):
pass
elif la_ == 10:
- self.state = 704
+ self.state = 697
localctx.operator = self.match(HogQLParser.REGEX_SINGLE)
pass
elif la_ == 11:
- self.state = 705
+ self.state = 698
localctx.operator = self.match(HogQLParser.REGEX_DOUBLE)
pass
elif la_ == 12:
- self.state = 706
+ self.state = 699
localctx.operator = self.match(HogQLParser.NOT_REGEX)
pass
elif la_ == 13:
- self.state = 707
+ self.state = 700
localctx.operator = self.match(HogQLParser.IREGEX_SINGLE)
pass
elif la_ == 14:
- self.state = 708
+ self.state = 701
localctx.operator = self.match(HogQLParser.IREGEX_DOUBLE)
pass
elif la_ == 15:
- self.state = 709
+ self.state = 702
localctx.operator = self.match(HogQLParser.NOT_IREGEX)
pass
- self.state = 712
+ self.state = 705
localctx.right = self.columnExpr(16)
pass
elif la_ == 4:
localctx = HogQLParser.ColumnExprNullishContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 713
+ self.state = 706
if not self.precpred(self._ctx, 13):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 13)")
- self.state = 714
+ self.state = 707
self.match(HogQLParser.NULLISH)
- self.state = 715
+ self.state = 708
self.columnExpr(14)
pass
elif la_ == 5:
localctx = HogQLParser.ColumnExprAndContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 716
+ self.state = 709
if not self.precpred(self._ctx, 11):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 11)")
- self.state = 717
+ self.state = 710
self.match(HogQLParser.AND)
- self.state = 718
+ self.state = 711
self.columnExpr(12)
pass
elif la_ == 6:
localctx = HogQLParser.ColumnExprOrContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 719
+ self.state = 712
if not self.precpred(self._ctx, 10):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 10)")
- self.state = 720
+ self.state = 713
self.match(HogQLParser.OR)
- self.state = 721
+ self.state = 714
self.columnExpr(11)
pass
elif la_ == 7:
localctx = HogQLParser.ColumnExprBetweenContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 722
+ self.state = 715
if not self.precpred(self._ctx, 9):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 9)")
- self.state = 724
+ self.state = 717
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==115:
- self.state = 723
+ self.state = 716
self.match(HogQLParser.NOT)
- self.state = 726
+ self.state = 719
self.match(HogQLParser.BETWEEN)
- self.state = 727
+ self.state = 720
self.columnExpr(0)
- self.state = 728
+ self.state = 721
self.match(HogQLParser.AND)
- self.state = 729
+ self.state = 722
self.columnExpr(10)
pass
elif la_ == 8:
localctx = HogQLParser.ColumnExprTernaryOpContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 731
+ self.state = 724
if not self.precpred(self._ctx, 8):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 8)")
- self.state = 732
+ self.state = 725
self.match(HogQLParser.QUERY)
- self.state = 733
+ self.state = 726
self.columnExpr(0)
- self.state = 734
+ self.state = 727
self.match(HogQLParser.COLON)
- self.state = 735
+ self.state = 728
self.columnExpr(8)
pass
elif la_ == 9:
localctx = HogQLParser.ColumnExprArrayAccessContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 737
+ self.state = 730
if not self.precpred(self._ctx, 21):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 21)")
- self.state = 738
+ self.state = 731
self.match(HogQLParser.LBRACKET)
- self.state = 739
+ self.state = 732
self.columnExpr(0)
- self.state = 740
+ self.state = 733
self.match(HogQLParser.RBRACKET)
pass
elif la_ == 10:
localctx = HogQLParser.ColumnExprTupleAccessContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 742
+ self.state = 735
if not self.precpred(self._ctx, 20):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 20)")
- self.state = 743
+ self.state = 736
self.match(HogQLParser.DOT)
- self.state = 744
+ self.state = 737
self.match(HogQLParser.DECIMAL_LITERAL)
pass
elif la_ == 11:
localctx = HogQLParser.ColumnExprPropertyAccessContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 745
+ self.state = 738
if not self.precpred(self._ctx, 19):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 19)")
- self.state = 746
+ self.state = 739
self.match(HogQLParser.DOT)
- self.state = 747
+ self.state = 740
self.identifier()
pass
elif la_ == 12:
localctx = HogQLParser.ColumnExprIsNullContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 748
+ self.state = 741
if not self.precpred(self._ctx, 14):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 14)")
- self.state = 749
+ self.state = 742
self.match(HogQLParser.IS)
- self.state = 751
+ self.state = 744
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==115:
- self.state = 750
+ self.state = 743
self.match(HogQLParser.NOT)
- self.state = 753
+ self.state = 746
self.match(HogQLParser.NULL_SQL)
pass
elif la_ == 13:
localctx = HogQLParser.ColumnExprAliasContext(self, HogQLParser.ColumnExprContext(self, _parentctx, _parentState))
self.pushNewRecursionContext(localctx, _startState, self.RULE_columnExpr)
- self.state = 754
+ self.state = 747
if not self.precpred(self._ctx, 7):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 7)")
- self.state = 760
+ self.state = 753
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,89,self._ctx)
if la_ == 1:
- self.state = 755
+ self.state = 748
self.alias()
pass
elif la_ == 2:
- self.state = 756
+ self.state = 749
self.match(HogQLParser.AS)
- self.state = 757
+ self.state = 750
self.identifier()
pass
elif la_ == 3:
- self.state = 758
+ self.state = 751
self.match(HogQLParser.AS)
- self.state = 759
+ self.state = 752
self.match(HogQLParser.STRING_LITERAL)
pass
@@ -5726,7 +5678,7 @@ def columnExpr(self, _p:int=0):
pass
- self.state = 766
+ self.state = 759
self._errHandler.sync(self)
_alt = self._interp.adaptivePredict(self._input,91,self._ctx)
@@ -5778,17 +5730,17 @@ def columnArgList(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 767
+ self.state = 760
self.columnArgExpr()
- self.state = 772
+ self.state = 765
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==206:
- self.state = 768
+ self.state = 761
self.match(HogQLParser.COMMA)
- self.state = 769
+ self.state = 762
self.columnArgExpr()
- self.state = 774
+ self.state = 767
self._errHandler.sync(self)
_la = self._input.LA(1)
@@ -5833,18 +5785,18 @@ def columnArgExpr(self):
localctx = HogQLParser.ColumnArgExprContext(self, self._ctx, self.state)
self.enterRule(localctx, 78, self.RULE_columnArgExpr)
try:
- self.state = 777
+ self.state = 770
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,93,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
- self.state = 775
+ self.state = 768
self.columnLambdaExpr()
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
- self.state = 776
+ self.state = 769
self.columnExpr(0)
pass
@@ -5910,41 +5862,41 @@ def columnLambdaExpr(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 798
+ self.state = 791
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [220]:
- self.state = 779
+ self.state = 772
self.match(HogQLParser.LPAREN)
- self.state = 780
+ self.state = 773
self.identifier()
- self.state = 785
+ self.state = 778
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==206:
- self.state = 781
+ self.state = 774
self.match(HogQLParser.COMMA)
- self.state = 782
+ self.state = 775
self.identifier()
- self.state = 787
+ self.state = 780
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 788
+ self.state = 781
self.match(HogQLParser.RPAREN)
pass
elif token in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195]:
- self.state = 790
+ self.state = 783
self.identifier()
- self.state = 795
+ self.state = 788
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==206:
- self.state = 791
+ self.state = 784
self.match(HogQLParser.COMMA)
- self.state = 792
+ self.state = 785
self.identifier()
- self.state = 797
+ self.state = 790
self._errHandler.sync(self)
_la = self._input.LA(1)
@@ -5952,9 +5904,9 @@ def columnLambdaExpr(self):
else:
raise NoViableAltException(self)
- self.state = 800
+ self.state = 793
self.match(HogQLParser.ARROW)
- self.state = 801
+ self.state = 794
self.columnExpr(0)
except RecognitionException as re:
localctx.exception = re
@@ -6059,66 +6011,66 @@ def hogqlxTagElement(self):
self.enterRule(localctx, 82, self.RULE_hogqlxTagElement)
self._la = 0 # Token type
try:
- self.state = 831
+ self.state = 824
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,100,self._ctx)
if la_ == 1:
localctx = HogQLParser.HogqlxTagElementClosedContext(self, localctx)
self.enterOuterAlt(localctx, 1)
- self.state = 803
+ self.state = 796
self.match(HogQLParser.LT)
- self.state = 804
+ self.state = 797
self.identifier()
- self.state = 808
+ self.state = 801
self._errHandler.sync(self)
_la = self._input.LA(1)
while (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -5066549581053953) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or _la==192 or _la==195:
- self.state = 805
+ self.state = 798
self.hogqlxTagAttribute()
- self.state = 810
+ self.state = 803
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 811
+ self.state = 804
self.match(HogQLParser.SLASH)
- self.state = 812
+ self.state = 805
self.match(HogQLParser.GT)
pass
elif la_ == 2:
localctx = HogQLParser.HogqlxTagElementNestedContext(self, localctx)
self.enterOuterAlt(localctx, 2)
- self.state = 814
+ self.state = 807
self.match(HogQLParser.LT)
- self.state = 815
+ self.state = 808
self.identifier()
- self.state = 819
+ self.state = 812
self._errHandler.sync(self)
_la = self._input.LA(1)
while (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -5066549581053953) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or _la==192 or _la==195:
- self.state = 816
+ self.state = 809
self.hogqlxTagAttribute()
- self.state = 821
+ self.state = 814
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 822
+ self.state = 815
self.match(HogQLParser.GT)
- self.state = 824
+ self.state = 817
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,99,self._ctx)
if la_ == 1:
- self.state = 823
+ self.state = 816
self.hogqlxTagElement()
- self.state = 826
+ self.state = 819
self.match(HogQLParser.LT)
- self.state = 827
+ self.state = 820
self.match(HogQLParser.SLASH)
- self.state = 828
+ self.state = 821
self.identifier()
- self.state = 829
+ self.state = 822
self.match(HogQLParser.GT)
pass
@@ -6176,36 +6128,36 @@ def hogqlxTagAttribute(self):
localctx = HogQLParser.HogqlxTagAttributeContext(self, self._ctx, self.state)
self.enterRule(localctx, 84, self.RULE_hogqlxTagAttribute)
try:
- self.state = 844
+ self.state = 837
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,101,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
- self.state = 833
+ self.state = 826
self.identifier()
- self.state = 834
+ self.state = 827
self.match(HogQLParser.EQ_SINGLE)
- self.state = 835
+ self.state = 828
self.match(HogQLParser.STRING_LITERAL)
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
- self.state = 837
+ self.state = 830
self.identifier()
- self.state = 838
+ self.state = 831
self.match(HogQLParser.EQ_SINGLE)
- self.state = 839
+ self.state = 832
self.match(HogQLParser.LBRACE)
- self.state = 840
+ self.state = 833
self.columnExpr(0)
- self.state = 841
+ self.state = 834
self.match(HogQLParser.RBRACE)
pass
elif la_ == 3:
self.enterOuterAlt(localctx, 3)
- self.state = 843
+ self.state = 836
self.identifier()
pass
@@ -6258,17 +6210,17 @@ def withExprList(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 846
+ self.state = 839
self.withExpr()
- self.state = 851
+ self.state = 844
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==206:
- self.state = 847
+ self.state = 840
self.match(HogQLParser.COMMA)
- self.state = 848
+ self.state = 841
self.withExpr()
- self.state = 853
+ self.state = 846
self._errHandler.sync(self)
_la = self._input.LA(1)
@@ -6352,32 +6304,32 @@ def withExpr(self):
localctx = HogQLParser.WithExprContext(self, self._ctx, self.state)
self.enterRule(localctx, 88, self.RULE_withExpr)
try:
- self.state = 864
+ self.state = 857
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,103,self._ctx)
if la_ == 1:
localctx = HogQLParser.WithExprSubqueryContext(self, localctx)
self.enterOuterAlt(localctx, 1)
- self.state = 854
+ self.state = 847
self.identifier()
- self.state = 855
+ self.state = 848
self.match(HogQLParser.AS)
- self.state = 856
+ self.state = 849
self.match(HogQLParser.LPAREN)
- self.state = 857
+ self.state = 850
self.selectUnionStmt()
- self.state = 858
+ self.state = 851
self.match(HogQLParser.RPAREN)
pass
elif la_ == 2:
localctx = HogQLParser.WithExprColumnContext(self, localctx)
self.enterOuterAlt(localctx, 2)
- self.state = 860
+ self.state = 853
self.columnExpr(0)
- self.state = 861
+ self.state = 854
self.match(HogQLParser.AS)
- self.state = 862
+ self.state = 855
self.identifier()
pass
@@ -6430,27 +6382,27 @@ def columnIdentifier(self):
localctx = HogQLParser.ColumnIdentifierContext(self, self._ctx, self.state)
self.enterRule(localctx, 90, self.RULE_columnIdentifier)
try:
- self.state = 873
+ self.state = 866
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [218]:
self.enterOuterAlt(localctx, 1)
- self.state = 866
+ self.state = 859
self.placeholder()
pass
elif token in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195]:
self.enterOuterAlt(localctx, 2)
- self.state = 870
+ self.state = 863
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,104,self._ctx)
if la_ == 1:
- self.state = 867
+ self.state = 860
self.tableIdentifier()
- self.state = 868
+ self.state = 861
self.match(HogQLParser.DOT)
- self.state = 872
+ self.state = 865
self.nestedIdentifier()
pass
else:
@@ -6503,18 +6455,18 @@ def nestedIdentifier(self):
self.enterRule(localctx, 92, self.RULE_nestedIdentifier)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 875
+ self.state = 868
self.identifier()
- self.state = 880
+ self.state = 873
self._errHandler.sync(self)
_alt = self._interp.adaptivePredict(self._input,106,self._ctx)
while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER:
if _alt==1:
- self.state = 876
+ self.state = 869
self.match(HogQLParser.DOT)
- self.state = 877
+ self.state = 870
self.identifier()
- self.state = 882
+ self.state = 875
self._errHandler.sync(self)
_alt = self._interp.adaptivePredict(self._input,106,self._ctx)
@@ -6667,7 +6619,7 @@ def tableExpr(self, _p:int=0):
self.enterRecursionRule(localctx, 94, self.RULE_tableExpr, _p)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 892
+ self.state = 885
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,107,self._ctx)
if la_ == 1:
@@ -6675,7 +6627,7 @@ def tableExpr(self, _p:int=0):
self._ctx = localctx
_prevctx = localctx
- self.state = 884
+ self.state = 877
self.tableIdentifier()
pass
@@ -6683,7 +6635,7 @@ def tableExpr(self, _p:int=0):
localctx = HogQLParser.TableExprFunctionContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 885
+ self.state = 878
self.tableFunctionExpr()
pass
@@ -6691,11 +6643,11 @@ def tableExpr(self, _p:int=0):
localctx = HogQLParser.TableExprSubqueryContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 886
+ self.state = 879
self.match(HogQLParser.LPAREN)
- self.state = 887
+ self.state = 880
self.selectUnionStmt()
- self.state = 888
+ self.state = 881
self.match(HogQLParser.RPAREN)
pass
@@ -6703,7 +6655,7 @@ def tableExpr(self, _p:int=0):
localctx = HogQLParser.TableExprTagContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 890
+ self.state = 883
self.hogqlxTagElement()
pass
@@ -6711,13 +6663,13 @@ def tableExpr(self, _p:int=0):
localctx = HogQLParser.TableExprPlaceholderContext(self, localctx)
self._ctx = localctx
_prevctx = localctx
- self.state = 891
+ self.state = 884
self.placeholder()
pass
self._ctx.stop = self._input.LT(-1)
- self.state = 902
+ self.state = 895
self._errHandler.sync(self)
_alt = self._interp.adaptivePredict(self._input,109,self._ctx)
while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER:
@@ -6727,27 +6679,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 = 894
+ self.state = 887
if not self.precpred(self._ctx, 3):
from antlr4.error.Errors import FailedPredicateException
raise FailedPredicateException(self, "self.precpred(self._ctx, 3)")
- self.state = 898
+ self.state = 891
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [36, 62, 77, 91, 195]:
- self.state = 895
+ self.state = 888
self.alias()
pass
elif token in [10]:
- self.state = 896
+ self.state = 889
self.match(HogQLParser.AS)
- self.state = 897
+ self.state = 890
self.identifier()
pass
else:
raise NoViableAltException(self)
- self.state = 904
+ self.state = 897
self._errHandler.sync(self)
_alt = self._interp.adaptivePredict(self._input,109,self._ctx)
@@ -6800,19 +6752,19 @@ def tableFunctionExpr(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 905
+ self.state = 898
self.identifier()
- self.state = 906
+ self.state = 899
self.match(HogQLParser.LPAREN)
- self.state = 908
+ self.state = 901
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & -33554436) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -1) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & -9) != 0) or ((((_la - 192)) & ~0x3f) == 0 and ((1 << (_la - 192)) & 70263309817) != 0):
- self.state = 907
+ self.state = 900
self.tableArgList()
- self.state = 910
+ self.state = 903
self.match(HogQLParser.RPAREN)
except RecognitionException as re:
localctx.exception = re
@@ -6859,17 +6811,17 @@ def tableIdentifier(self):
self.enterRule(localctx, 98, self.RULE_tableIdentifier)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 915
+ self.state = 908
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,111,self._ctx)
if la_ == 1:
- self.state = 912
+ self.state = 905
self.databaseIdentifier()
- self.state = 913
+ self.state = 906
self.match(HogQLParser.DOT)
- self.state = 917
+ self.state = 910
self.identifier()
except RecognitionException as re:
localctx.exception = re
@@ -6919,17 +6871,17 @@ def tableArgList(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 919
+ self.state = 912
self.columnExpr(0)
- self.state = 924
+ self.state = 917
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==206:
- self.state = 920
+ self.state = 913
self.match(HogQLParser.COMMA)
- self.state = 921
+ self.state = 914
self.columnExpr(0)
- self.state = 926
+ self.state = 919
self._errHandler.sync(self)
_la = self._input.LA(1)
@@ -6971,7 +6923,7 @@ def databaseIdentifier(self):
self.enterRule(localctx, 102, self.RULE_databaseIdentifier)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 927
+ self.state = 920
self.identifier()
except RecognitionException as re:
localctx.exception = re
@@ -7022,19 +6974,19 @@ def floatingLiteral(self):
self.enterRule(localctx, 104, self.RULE_floatingLiteral)
self._la = 0 # Token type
try:
- self.state = 937
+ self.state = 930
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [196]:
self.enterOuterAlt(localctx, 1)
- self.state = 929
+ self.state = 922
self.match(HogQLParser.FLOATING_LITERAL)
pass
elif token in [210]:
self.enterOuterAlt(localctx, 2)
- self.state = 930
+ self.state = 923
self.match(HogQLParser.DOT)
- self.state = 931
+ self.state = 924
_la = self._input.LA(1)
if not(_la==197 or _la==198):
self._errHandler.recoverInline(self)
@@ -7044,15 +6996,15 @@ def floatingLiteral(self):
pass
elif token in [198]:
self.enterOuterAlt(localctx, 3)
- self.state = 932
+ self.state = 925
self.match(HogQLParser.DECIMAL_LITERAL)
- self.state = 933
+ self.state = 926
self.match(HogQLParser.DOT)
- self.state = 935
+ self.state = 928
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,113,self._ctx)
if la_ == 1:
- self.state = 934
+ self.state = 927
_la = self._input.LA(1)
if not(_la==197 or _la==198):
self._errHandler.recoverInline(self)
@@ -7125,11 +7077,11 @@ def numberLiteral(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 940
+ self.state = 933
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==208 or _la==228:
- self.state = 939
+ self.state = 932
_la = self._input.LA(1)
if not(_la==208 or _la==228):
self._errHandler.recoverInline(self)
@@ -7138,36 +7090,36 @@ def numberLiteral(self):
self.consume()
- self.state = 948
+ self.state = 941
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,116,self._ctx)
if la_ == 1:
- self.state = 942
+ self.state = 935
self.floatingLiteral()
pass
elif la_ == 2:
- self.state = 943
+ self.state = 936
self.match(HogQLParser.OCTAL_LITERAL)
pass
elif la_ == 3:
- self.state = 944
+ self.state = 937
self.match(HogQLParser.DECIMAL_LITERAL)
pass
elif la_ == 4:
- self.state = 945
+ self.state = 938
self.match(HogQLParser.HEXADECIMAL_LITERAL)
pass
elif la_ == 5:
- self.state = 946
+ self.state = 939
self.match(HogQLParser.INF)
pass
elif la_ == 6:
- self.state = 947
+ self.state = 940
self.match(HogQLParser.NAN_SQL)
pass
@@ -7215,22 +7167,22 @@ def literal(self):
localctx = HogQLParser.LiteralContext(self, self._ctx, self.state)
self.enterRule(localctx, 108, self.RULE_literal)
try:
- self.state = 953
+ self.state = 946
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [82, 113, 196, 197, 198, 199, 208, 210, 228]:
self.enterOuterAlt(localctx, 1)
- self.state = 950
+ self.state = 943
self.numberLiteral()
pass
elif token in [200]:
self.enterOuterAlt(localctx, 2)
- self.state = 951
+ self.state = 944
self.match(HogQLParser.STRING_LITERAL)
pass
elif token in [116]:
self.enterOuterAlt(localctx, 3)
- self.state = 952
+ self.state = 945
self.match(HogQLParser.NULL_SQL)
pass
else:
@@ -7295,7 +7247,7 @@ def interval(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 955
+ self.state = 948
_la = self._input.LA(1)
if not(_la==37 or ((((_la - 76)) & ~0x3f) == 0 and ((1 << (_la - 76)) & 72057615512764417) != 0) or ((((_la - 145)) & ~0x3f) == 0 and ((1 << (_la - 145)) & 36283883716609) != 0)):
self._errHandler.recoverInline(self)
@@ -7871,7 +7823,7 @@ def keyword(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 957
+ self.state = 950
_la = self._input.LA(1)
if not(((((_la - 2)) & ~0x3f) == 0 and ((1 << (_la - 2)) & -34368126977) != 0) or ((((_la - 66)) & ~0x3f) == 0 and ((1 << (_la - 66)) & -1288627627820033) != 0) or ((((_la - 130)) & ~0x3f) == 0 and ((1 << (_la - 130)) & 8034421735228932089) != 0)):
self._errHandler.recoverInline(self)
@@ -7925,7 +7877,7 @@ def keywordForAlias(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 959
+ self.state = 952
_la = self._input.LA(1)
if not(((((_la - 36)) & ~0x3f) == 0 and ((1 << (_la - 36)) & 36030996109328385) != 0)):
self._errHandler.recoverInline(self)
@@ -7972,17 +7924,17 @@ def alias(self):
localctx = HogQLParser.AliasContext(self, self._ctx, self.state)
self.enterRule(localctx, 116, self.RULE_alias)
try:
- self.state = 963
+ self.state = 956
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [195]:
self.enterOuterAlt(localctx, 1)
- self.state = 961
+ self.state = 954
self.match(HogQLParser.IDENTIFIER)
pass
elif token in [36, 62, 77, 91]:
self.enterOuterAlt(localctx, 2)
- self.state = 962
+ self.state = 955
self.keywordForAlias()
pass
else:
@@ -8032,22 +7984,22 @@ def identifier(self):
localctx = HogQLParser.IdentifierContext(self, self._ctx, self.state)
self.enterRule(localctx, 118, self.RULE_identifier)
try:
- self.state = 968
+ self.state = 961
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [195]:
self.enterOuterAlt(localctx, 1)
- self.state = 965
+ self.state = 958
self.match(HogQLParser.IDENTIFIER)
pass
elif token in [37, 76, 108, 110, 132, 145, 185, 190]:
self.enterOuterAlt(localctx, 2)
- self.state = 966
+ self.state = 959
self.interval()
pass
elif token in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 109, 111, 112, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 186, 187, 188, 189, 191, 192]:
self.enterOuterAlt(localctx, 3)
- self.state = 967
+ self.state = 960
self.keyword()
pass
else:
@@ -8097,11 +8049,11 @@ def enumValue(self):
self.enterRule(localctx, 120, self.RULE_enumValue)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 970
+ self.state = 963
self.match(HogQLParser.STRING_LITERAL)
- self.state = 971
+ self.state = 964
self.match(HogQLParser.EQ_SINGLE)
- self.state = 972
+ self.state = 965
self.numberLiteral()
except RecognitionException as re:
localctx.exception = re
@@ -8147,11 +8099,11 @@ def placeholder(self):
self.enterRule(localctx, 122, self.RULE_placeholder)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 974
+ self.state = 967
self.match(HogQLParser.LBRACE)
- self.state = 975
+ self.state = 968
self.identifier()
- self.state = 976
+ self.state = 969
self.match(HogQLParser.RBRACE)
except RecognitionException as re:
localctx.exception = re
diff --git a/posthog/hogql/grammar/HogQLParserVisitor.py b/posthog/hogql/grammar/HogQLParserVisitor.py
index 389da7e99385c..66a36b5bdb4e9 100644
--- a/posthog/hogql/grammar/HogQLParserVisitor.py
+++ b/posthog/hogql/grammar/HogQLParserVisitor.py
@@ -254,11 +254,6 @@ def visitColumnExprAlias(self, ctx:HogQLParser.ColumnExprAliasContext):
return self.visitChildren(ctx)
- # Visit a parse tree produced by HogQLParser#ColumnExprExtract.
- def visitColumnExprExtract(self, ctx:HogQLParser.ColumnExprExtractContext):
- return self.visitChildren(ctx)
-
-
# Visit a parse tree produced by HogQLParser#ColumnExprNegate.
def visitColumnExprNegate(self, ctx:HogQLParser.ColumnExprNegateContext):
return self.visitChildren(ctx)
diff --git a/posthog/hogql/modifiers.py b/posthog/hogql/modifiers.py
index 3c6fa11a9fc3b..8452016dc1411 100644
--- a/posthog/hogql/modifiers.py
+++ b/posthog/hogql/modifiers.py
@@ -1,7 +1,12 @@
from typing import Optional, TYPE_CHECKING
-from posthog.schema import HogQLQueryModifiers, InCohortVia, MaterializationMode, PersonsArgMaxVersion
-from posthog.utils import PersonOnEventsMode
+from posthog.schema import (
+ HogQLQueryModifiers,
+ InCohortVia,
+ MaterializationMode,
+ PersonsArgMaxVersion,
+ PersonsOnEventsMode,
+)
if TYPE_CHECKING:
from posthog.models import Team
@@ -16,7 +21,10 @@ def create_default_modifiers_for_team(
modifiers = modifiers.model_copy()
if modifiers.personsOnEventsMode is None:
- modifiers.personsOnEventsMode = team.person_on_events_mode or PersonOnEventsMode.DISABLED
+ if team.person_on_events_v3_querying_enabled:
+ modifiers.personsOnEventsMode = PersonsOnEventsMode.v3_enabled
+ else:
+ modifiers.personsOnEventsMode = team.person_on_events_mode
if modifiers.personsArgMaxVersion is None:
modifiers.personsArgMaxVersion = PersonsArgMaxVersion.auto
diff --git a/posthog/hogql/parser.py b/posthog/hogql/parser.py
index 399f6953698cd..07fa55228d671 100644
--- a/posthog/hogql/parser.py
+++ b/posthog/hogql/parser.py
@@ -499,9 +499,6 @@ def visitColumnExprAlias(self, ctx: HogQLParser.ColumnExprAliasContext):
return ast.Alias(expr=expr, alias=alias)
- def visitColumnExprExtract(self, ctx: HogQLParser.ColumnExprExtractContext):
- raise NotImplementedException(f"Unsupported node: ColumnExprExtract")
-
def visitColumnExprNegate(self, ctx: HogQLParser.ColumnExprNegateContext):
return ast.ArithmeticOperation(
op=ast.ArithmeticOperationOp.Sub,
diff --git a/posthog/hogql/printer.py b/posthog/hogql/printer.py
index db6523cfa4078..98d3bdc4bc8a5 100644
--- a/posthog/hogql/printer.py
+++ b/posthog/hogql/printer.py
@@ -822,11 +822,21 @@ def visit_call(self, node: ast.Call):
break # Found an overload matching the first function org
if func_meta.tz_aware:
- if (relevant_clickhouse_name == "now64" and len(node.args) == 0) or (
- relevant_clickhouse_name == "parseDateTime64BestEffortOrNull" and len(node.args) == 1
+ has_tz_override = len(node.args) == func_meta.max_args
+
+ if not has_tz_override:
+ args.append(self.visit(ast.Constant(value=self._get_timezone())))
+
+ if (
+ relevant_clickhouse_name == "now64"
+ and (len(node.args) == 0 or (has_tz_override and len(node.args) == 1))
+ ) or (
+ relevant_clickhouse_name == "parseDateTime64BestEffortOrNull"
+ and (len(node.args) == 1 or (has_tz_override and len(node.args) == 2))
):
- args.append("6") # These two CH functions require the precision argument before timezone
- args.append(self.visit(ast.Constant(value=self._get_timezone())))
+ # These two CH functions require a precision argument before timezone
+ args = args[:-1] + ["6"] + args[-1:]
+
if node.name == "toStartOfWeek" and len(node.args) == 1:
# If week mode hasn't been specified, use the project's default.
# For Monday-based weeks mode 3 is used (which is ISO 8601), for Sunday-based mode 0 (CH default)
diff --git a/posthog/hogql/test/_test_parser.py b/posthog/hogql/test/_test_parser.py
index 5a4c45b533647..61c90d031ffc3 100644
--- a/posthog/hogql/test/_test_parser.py
+++ b/posthog/hogql/test/_test_parser.py
@@ -1594,4 +1594,17 @@ def test_visit_hogqlx_tag_source(self):
],
)
+ def test_select_extract_as_function(self):
+ node = self._select("select extract('string', 'other string') from events")
+
+ assert node == ast.SelectQuery(
+ select=[
+ ast.Call(
+ name="extract",
+ args=[ast.Constant(value="string"), ast.Constant(value="other string")],
+ )
+ ],
+ select_from=ast.JoinExpr(table=ast.Field(chain=["events"])),
+ )
+
return TestParser
diff --git a/posthog/hogql/test/test_modifiers.py b/posthog/hogql/test/test_modifiers.py
index b2b0ef1e40630..a33d57575e2f4 100644
--- a/posthog/hogql/test/test_modifiers.py
+++ b/posthog/hogql/test/test_modifiers.py
@@ -7,7 +7,11 @@
class TestModifiers(BaseTest):
- @override_settings(PERSON_ON_EVENTS_OVERRIDE=False, PERSON_ON_EVENTS_V2_OVERRIDE=False)
+ @override_settings(
+ PERSON_ON_EVENTS_OVERRIDE=False,
+ PERSON_ON_EVENTS_V2_OVERRIDE=False,
+ PERSON_ON_EVENTS_V3_OVERRIDE=False,
+ )
def test_create_default_modifiers_for_team_init(self):
assert self.team.person_on_events_mode == "disabled"
modifiers = create_default_modifiers_for_team(self.team)
@@ -23,6 +27,9 @@ def test_create_default_modifiers_for_team_init(self):
)
assert modifiers.personsOnEventsMode == PersonsOnEventsMode.v2_enabled
+ with override_settings(PERSON_ON_EVENTS_V3_OVERRIDE=True):
+ assert create_default_modifiers_for_team(self.team).personsOnEventsMode == PersonsOnEventsMode.v3_enabled
+
def test_modifiers_persons_on_events_mode_v1_enabled(self):
query = "SELECT event, person_id FROM events"
diff --git a/posthog/hogql/test/test_printer.py b/posthog/hogql/test/test_printer.py
index 9bbf4c40aff98..1f3b2db78e7ed 100644
--- a/posthog/hogql/test/test_printer.py
+++ b/posthog/hogql/test/test_printer.py
@@ -1524,3 +1524,37 @@ def test_lookup_organic_medium_type(self):
),
printed,
)
+
+ def test_override_timezone(self):
+ context = HogQLContext(
+ team_id=self.team.pk,
+ enable_select_queries=True,
+ database=Database(None, WeekStartDay.SUNDAY),
+ )
+ context.database.events.fields["test_date"] = DateDatabaseField(name="test_date") # type: ignore
+
+ self.assertEqual(
+ self._select(
+ """
+ SELECT
+ toDateTime(timestamp),
+ toDateTime(timestamp, 'US/Pacific'),
+ now(),
+ now('US/Pacific')
+ FROM events
+ """,
+ context,
+ ),
+ f"SELECT toDateTime(toTimeZone(events.timestamp, %(hogql_val_0)s), %(hogql_val_1)s), toDateTime(toTimeZone(events.timestamp, %(hogql_val_2)s), %(hogql_val_3)s), now64(6, %(hogql_val_4)s), now64(6, %(hogql_val_5)s) FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000",
+ )
+ self.assertEqual(
+ context.values,
+ {
+ "hogql_val_0": "UTC",
+ "hogql_val_1": "UTC",
+ "hogql_val_2": "UTC",
+ "hogql_val_3": "US/Pacific",
+ "hogql_val_4": "UTC",
+ "hogql_val_5": "US/Pacific",
+ },
+ )
diff --git a/posthog/hogql_queries/hogql_query_runner.py b/posthog/hogql_queries/hogql_query_runner.py
index acc404ac9519a..7f30ae435803c 100644
--- a/posthog/hogql_queries/hogql_query_runner.py
+++ b/posthog/hogql_queries/hogql_query_runner.py
@@ -45,7 +45,7 @@ def to_actors_query(self) -> ast.SelectQuery:
def calculate(self) -> HogQLQueryResponse:
query = self.to_query()
paginator = None
- if not query.limit:
+ if isinstance(query, ast.SelectQuery) and not query.limit:
paginator = HogQLHasMorePaginator.from_limit_context(limit_context=self.limit_context)
func = cast(
Callable[..., HogQLQueryResponse],
diff --git a/posthog/hogql_queries/insights/trends/breakdown.py b/posthog/hogql_queries/insights/trends/breakdown.py
index bde2cd807b6a7..1cae30854e5d1 100644
--- a/posthog/hogql_queries/insights/trends/breakdown.py
+++ b/posthog/hogql_queries/insights/trends/breakdown.py
@@ -150,10 +150,14 @@ def events_where_filter(self) -> ast.Expr | None:
left=transform_func, op=ast.CompareOperationOp.Eq, right=ast.Constant(value=value)
)
)
+ elif value == BREAKDOWN_NULL_STRING_LABEL:
+ compare_ops.append(
+ ast.CompareOperation(left=left, op=ast.CompareOperationOp.Eq, right=ast.Constant(value=None))
+ )
+ compare_ops.append(
+ ast.CompareOperation(left=left, op=ast.CompareOperationOp.Eq, right=ast.Constant(value=""))
+ )
else:
- if value == BREAKDOWN_NULL_STRING_LABEL:
- value = None
-
compare_ops.append(
ast.CompareOperation(left=left, op=ast.CompareOperationOp.Eq, right=ast.Constant(value=value))
)
@@ -172,21 +176,17 @@ def _get_breakdown_transform_func(self) -> ast.Call:
return self._get_breakdown_values_transform(ast.Field(chain=self._properties_chain))
def _get_breakdown_values_transform(self, node: ast.Expr) -> ast.Call:
- breakdown_values = self._breakdown_values_ast
- return ast.Call(
- name="transform",
- args=[
- ast.Call(
- name="ifNull",
- args=[
- hogql_to_string(node),
- ast.Constant(value=BREAKDOWN_NULL_STRING_LABEL),
- ],
- ),
- breakdown_values,
- breakdown_values,
- ast.Constant(value=BREAKDOWN_OTHER_STRING_LABEL),
- ],
+ return cast(
+ ast.Call,
+ parse_expr(
+ "transform(ifNull(nullIf(toString({node}), ''), {nil}), {values}, {values}, {other})",
+ placeholders={
+ "node": node,
+ "values": self._breakdown_values_ast,
+ "nil": ast.Constant(value=BREAKDOWN_NULL_STRING_LABEL),
+ "other": ast.Constant(value=BREAKDOWN_OTHER_STRING_LABEL),
+ },
+ ),
)
@cached_property
diff --git a/posthog/hogql_queries/insights/trends/display.py b/posthog/hogql_queries/insights/trends/display.py
index c5823a22a5877..8747544f7241c 100644
--- a/posthog/hogql_queries/insights/trends/display.py
+++ b/posthog/hogql_queries/insights/trends/display.py
@@ -86,4 +86,5 @@ def _get_cumulative_query(self, inner_query: ast.SelectQuery, breakdown_enabled:
),
],
select_from=ast.JoinExpr(table=inner_query),
+ order_by=[ast.OrderExpr(expr=ast.Field(chain=["day_start"]), order="ASC")],
)
diff --git a/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends.ambr b/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends.ambr
index e2ec22fb9fb1c..3d37d683cc26c 100644
--- a/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends.ambr
+++ b/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends.ambr
@@ -231,7 +231,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(e__group_0.properties___industry), '$$_posthog_breakdown_null_$$'), ['finance', 'technology'], ['finance', 'technology'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__group_0.properties___industry), ''), '$$_posthog_breakdown_null_$$'), ['finance', 'technology'], ['finance', 'technology'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT JOIN
(SELECT argMax(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(groups.group_properties, 'industry'), ''), 'null'), '^"|"$', ''), groups._timestamp) AS properties___industry,
@@ -331,7 +331,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(e__group_0.properties___industry), '$$_posthog_breakdown_null_$$'), ['finance'], ['finance'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__group_0.properties___industry), ''), '$$_posthog_breakdown_null_$$'), ['finance'], ['finance'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT JOIN
(SELECT argMax(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(groups.group_properties, 'industry'), ''), 'null'), '^"|"$', ''), groups._timestamp) AS properties___industry,
@@ -392,7 +392,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['second url'], ['second url'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['second url'], ['second url'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-22 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-05 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$browser'), ''), 'null'), '^"|"$', ''), 'Firefox'), 0), ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', ''), 'Windows'), 0)), ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', ''), 'Mac'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', '')), 'second url'), 0))
GROUP BY day_start,
@@ -445,9 +445,9 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$'], ['$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$'], ['$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-22 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-05 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), and(ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$browser'), ''), 'null'), '^"|"$', ''), 'Firefox'), 0), ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', ''), 'Windows'), 0)), ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', ''), 'Mac'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', ''))))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-22 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-05 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), and(ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$browser'), ''), 'null'), '^"|"$', ''), 'Firefox'), 0), ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', ''), 'Windows'), 0)), ifNull(equals(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', ''), 'Mac'), 0), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$current_url'), ''), 'null'), '^"|"$', '')), ''), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -494,7 +494,7 @@
CROSS JOIN
(SELECT toTimeZone(e.timestamp, 'UTC') AS timestamp,
e__pdi.person_id AS actor_id,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['val', 'bor'], ['val', 'bor'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['val', 'bor'], ['val', 'bor'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -552,7 +552,7 @@
CROSS JOIN
(SELECT toTimeZone(e.timestamp, 'UTC') AS timestamp,
e__pdi.person_id AS actor_id,
- transform(ifNull(toString(nullIf(nullIf(e.mat_key, ''), 'null')), '$$_posthog_breakdown_null_$$'), ['val', 'bor'], ['val', 'bor'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(nullIf(nullIf(e.mat_key, ''), 'null')), ''), '$$_posthog_breakdown_null_$$'), ['val', 'bor'], ['val', 'bor'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -668,7 +668,7 @@
CROSS JOIN
(SELECT toTimeZone(e.timestamp, 'UTC') AS timestamp,
e__pdi.person_id AS actor_id,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['val'], ['val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['val'], ['val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -757,7 +757,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['uh', 'oh'], ['uh', 'oh'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['uh', 'oh'], ['uh', 'oh'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT JOIN
(SELECT argMax(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(groups.group_properties, 'industry'), ''), 'null'), '^"|"$', ''), groups._timestamp) AS properties___industry,
@@ -840,7 +840,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT ifNull(nullIf(e__override.override_person_id, '00000000-0000-0000-0000-000000000000'), e.person_id)) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['uh', 'oh'], ['uh', 'oh'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'key'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['uh', 'oh'], ['uh', 'oh'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT OUTER JOIN
(SELECT argMax(person_overrides.override_person_id, person_overrides.version) AS override_person_id,
@@ -907,7 +907,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e__pdi.person_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['other_value', '$$_posthog_breakdown_null_$$', 'value'], ['other_value', '$$_posthog_breakdown_null_$$', 'value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['other_value', '$$_posthog_breakdown_null_$$', 'value'], ['other_value', '$$_posthog_breakdown_null_$$', 'value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1.0
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -916,7 +916,7 @@
WHERE equals(person_distinct_id2.team_id, 2)
GROUP BY person_distinct_id2.distinct_id
HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0)))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -967,7 +967,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e__pdi.person_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['other_value', '$$_posthog_breakdown_null_$$', 'value'], ['other_value', '$$_posthog_breakdown_null_$$', 'value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['other_value', '$$_posthog_breakdown_null_$$', 'value'], ['other_value', '$$_posthog_breakdown_null_$$', 'value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1.0
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -976,7 +976,7 @@
WHERE equals(person_distinct_id2.team_id, 2)
GROUP BY person_distinct_id2.distinct_id
HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0)))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -1322,7 +1322,7 @@
CROSS JOIN
(SELECT toTimeZone(e.timestamp, 'UTC') AS timestamp,
e__pdi.person_id AS actor_id,
- transform(ifNull(toString(e__pdi__person.`properties___$some_prop`), '$$_posthog_breakdown_null_$$'), ['some_val2', 'some_val'], ['some_val2', 'some_val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__pdi__person.`properties___$some_prop`), ''), '$$_posthog_breakdown_null_$$'), ['some_val2', 'some_val'], ['some_val2', 'some_val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -1416,7 +1416,7 @@
CROSS JOIN
(SELECT toTimeZone(e.timestamp, 'UTC') AS timestamp,
ifNull(nullIf(e__override.override_person_id, '00000000-0000-0000-0000-000000000000'), e.person_id) AS actor_id,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.person_properties, '$some_prop'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['some_val2', 'some_val'], ['some_val2', 'some_val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.person_properties, '$some_prop'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['some_val2', 'some_val'], ['some_val2', 'some_val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT OUTER JOIN
(SELECT argMax(person_overrides.override_person_id, person_overrides.version) AS override_person_id,
@@ -1538,7 +1538,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -1552,7 +1552,7 @@
FROM cohortpeople
WHERE and(equals(cohortpeople.team_id, 2), equals(cohortpeople.cohort_id, 2))
GROUP BY cohortpeople.person_id, cohortpeople.cohort_id, cohortpeople.version
- HAVING ifNull(greater(sum(cohortpeople.sign), 0), 0))), 0)), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
+ HAVING ifNull(greater(sum(cohortpeople.sign), 0), 0))), 0)), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -1634,7 +1634,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT OUTER JOIN
(SELECT argMax(person_overrides.override_person_id, person_overrides.version) AS override_person_id,
@@ -1647,7 +1647,7 @@
FROM cohortpeople
WHERE and(equals(cohortpeople.team_id, 2), equals(cohortpeople.cohort_id, 2))
GROUP BY cohortpeople.person_id, cohortpeople.cohort_id, cohortpeople.version
- HAVING ifNull(greater(sum(cohortpeople.sign), 0), 0))), 0)), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
+ HAVING ifNull(greater(sum(cohortpeople.sign), 0), 0))), 0)), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -2267,7 +2267,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e__pdi.person_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['Mac'], ['Mac'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['Mac'], ['Mac'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -2458,7 +2458,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e__pdi.person_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'America/Phoenix')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['Mac'], ['Mac'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['Mac'], ['Mac'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -2649,7 +2649,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e__pdi.person_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'Asia/Tokyo')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['Mac'], ['Mac'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$os'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['Mac'], ['Mac'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -3062,7 +3062,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(e__pdi__person.properties___email), '$$_posthog_breakdown_null_$$'), ['test2@posthog.com', 'test@gmail.com', 'test5@posthog.com', 'test4@posthog.com', 'test3@posthog.com'], ['test2@posthog.com', 'test@gmail.com', 'test5@posthog.com', 'test4@posthog.com', 'test3@posthog.com'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__pdi__person.properties___email), ''), '$$_posthog_breakdown_null_$$'), ['test2@posthog.com', 'test@gmail.com', 'test5@posthog.com', 'test4@posthog.com', 'test3@posthog.com'], ['test2@posthog.com', 'test@gmail.com', 'test5@posthog.com', 'test4@posthog.com', 'test3@posthog.com'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS e__pdi___person_id,
@@ -3155,7 +3155,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.uuid) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(e__pdi__person.properties___email), '$$_posthog_breakdown_null_$$'), ['test2@posthog.com'], ['test2@posthog.com'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__pdi__person.properties___email), ''), '$$_posthog_breakdown_null_$$'), ['test2@posthog.com'], ['test2@posthog.com'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS e__pdi___person_id,
@@ -3316,7 +3316,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e.distinct_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(e__pdi__person.`properties___$some_prop`), '$$_posthog_breakdown_null_$$'), ['some_val', '$$_posthog_breakdown_null_$$'], ['some_val', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__pdi__person.`properties___$some_prop`), ''), '$$_posthog_breakdown_null_$$'), ['some_val', '$$_posthog_breakdown_null_$$'], ['some_val', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS e__pdi___person_id,
@@ -3336,7 +3336,7 @@
WHERE equals(person.team_id, 2)
GROUP BY person.id
HAVING ifNull(equals(argMax(person.is_deleted, person.version), 0), 0))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__pdi__person ON equals(e__pdi.e__pdi___person_id, e__pdi__person.id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-24 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-31 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(e__pdi__person.`properties___$some_prop`), 'some_val'), 0), isNull(toString(e__pdi__person.`properties___$some_prop`))))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-24 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-31 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(e__pdi__person.`properties___$some_prop`), 'some_val'), 0), isNull(toString(e__pdi__person.`properties___$some_prop`)), ifNull(equals(toString(e__pdi__person.`properties___$some_prop`), ''), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -3465,9 +3465,9 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e.distinct_id) AS total,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_prop'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$'], ['$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_prop'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$'], ['$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-24 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-31 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_prop'), ''), 'null'), '^"|"$', ''))))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-24 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-31 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_prop'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_prop'), ''), 'null'), '^"|"$', '')), ''), 0)))
GROUP BY day_start,
breakdown_value)
GROUP BY day_start,
@@ -3575,7 +3575,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT e__pdi.person_id) AS total,
min(toStartOfDay(toTimeZone(e.timestamp, 'UTC'))) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -3584,12 +3584,13 @@
WHERE equals(person_distinct_id2.team_id, 2)
GROUP BY person_distinct_id2.distinct_id
HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
GROUP BY e__pdi.person_id,
breakdown_value)
GROUP BY day_start,
breakdown_value
- ORDER BY day_start ASC, breakdown_value ASC))
+ ORDER BY day_start ASC, breakdown_value ASC)
+ ORDER BY day_start ASC)
GROUP BY breakdown_value
ORDER BY sum(count) DESC, breakdown_value ASC
LIMIT 10000 SETTINGS readonly=2,
@@ -3640,7 +3641,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(DISTINCT ifNull(nullIf(e__override.override_person_id, '00000000-0000-0000-0000-000000000000'), e.person_id)) AS total,
min(toStartOfDay(toTimeZone(e.timestamp, 'UTC'))) AS day_start,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], ['$$_posthog_breakdown_null_$$', 'value', 'other_value'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
LEFT OUTER JOIN
(SELECT argMax(person_overrides.override_person_id, person_overrides.version) AS override_person_id,
@@ -3648,12 +3649,13 @@
FROM person_overrides
WHERE equals(person_overrides.team_id, 2)
GROUP BY person_overrides.old_person_id) AS e__override ON equals(e.person_id, e__override.old_person_id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'other_value'), 0)))
GROUP BY ifNull(nullIf(e__override.override_person_id, '00000000-0000-0000-0000-000000000000'), e.person_id),
breakdown_value)
GROUP BY day_start,
breakdown_value
- ORDER BY day_start ASC, breakdown_value ASC))
+ ORDER BY day_start ASC, breakdown_value ASC)
+ ORDER BY day_start ASC)
GROUP BY breakdown_value
ORDER BY sum(count) DESC, breakdown_value ASC
LIMIT 10000 SETTINGS readonly=2,
@@ -3686,7 +3688,7 @@
breakdown_value AS breakdown_value
FROM
(SELECT any(e__session.duration) AS session_duration,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['value2', 'value1', '$$_posthog_breakdown_null_$$'], ['value2', 'value1', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['value2', 'value1', '$$_posthog_breakdown_null_$$'], ['value2', 'value1', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT events.`$session_id` AS id,
@@ -3694,7 +3696,7 @@
FROM events
WHERE and(equals(events.team_id, 2), greaterOrEquals(toTimeZone(events.timestamp, 'UTC'), toStartOfWeek(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')), 0)), lessOrEquals(toTimeZone(events.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), ifNull(notEquals(id, ''), 1))
GROUP BY id) AS e__session ON equals(e.`$session_id`, e__session.id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfWeek(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')), 0)), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value2'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value1'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')))))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfWeek(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')), 0)), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value2'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value1'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0)))
GROUP BY e__session.id,
breakdown_value)
GROUP BY breakdown_value
@@ -3728,7 +3730,7 @@
breakdown_value AS breakdown_value
FROM
(SELECT any(e__session.duration) AS session_duration,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['value2', 'value1', '$$_posthog_breakdown_null_$$'], ['value2', 'value1', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['value2', 'value1', '$$_posthog_breakdown_null_$$'], ['value2', 'value1', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT events.`$session_id` AS id,
@@ -3736,7 +3738,7 @@
FROM events
WHERE and(equals(events.team_id, 2), greaterOrEquals(toTimeZone(events.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(events.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), ifNull(notEquals(id, ''), 1))
GROUP BY id) AS e__session ON equals(e.`$session_id`, e__session.id)
- WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value2'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value1'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')))))
+ WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value2'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), 'value1'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), 0)))
GROUP BY e__session.id,
breakdown_value)
GROUP BY breakdown_value
@@ -3888,7 +3890,7 @@
breakdown_value AS breakdown_value
FROM
(SELECT count(e.uuid) AS total,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['red', 'blue', '$$_posthog_breakdown_null_$$'], ['red', 'blue', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['red', 'blue', '$$_posthog_breakdown_null_$$'], ['red', 'blue', '$$_posthog_breakdown_null_$$'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1.0
INNER JOIN
(SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id,
@@ -3897,7 +3899,7 @@
WHERE equals(person_distinct_id2.team_id, 2)
GROUP BY person_distinct_id2.distinct_id
HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id)
- WHERE and(equals(e.team_id, 2), and(equals(e.event, 'viewed video'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), 'red'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), 'blue'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', ''))))), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), minus(assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-01 00:00:00', 6, 'UTC')), toIntervalDay(0))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-07 23:59:59', 6, 'UTC'))))
+ WHERE and(equals(e.team_id, 2), and(equals(e.event, 'viewed video'), or(ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), 'red'), 0), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), 'blue'), 0), isNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', ''))), ifNull(equals(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, 'color'), ''), 'null'), '^"|"$', '')), ''), 0))), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), minus(assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-01 00:00:00', 6, 'UTC')), toIntervalDay(0))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-07 23:59:59', 6, 'UTC'))))
GROUP BY e__pdi.person_id,
breakdown_value)
GROUP BY breakdown_value)
@@ -4036,7 +4038,8 @@
WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-30 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-06 23:59:59', 6, 'UTC'))), equals(e.event, 'viewed video'), ifNull(notEquals(nullIf(nullIf(e.`$group_0`, ''), 'null'), ''), 1), notEquals(e.`$group_0`, ''))
GROUP BY e.`$group_0`)
GROUP BY day_start
- ORDER BY day_start ASC))
+ ORDER BY day_start ASC)
+ ORDER BY day_start ASC)
ORDER BY sum(count) DESC
LIMIT 10000 SETTINGS readonly=2,
max_execution_time=60,
@@ -4066,7 +4069,8 @@
WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'))
GROUP BY day_start)
GROUP BY day_start
- ORDER BY day_start ASC))
+ ORDER BY day_start ASC)
+ ORDER BY day_start ASC)
ORDER BY sum(count) DESC
LIMIT 10000 SETTINGS readonly=2,
max_execution_time=60,
@@ -4103,7 +4107,8 @@
WHERE and(equals(e.team_id, 2), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2019-12-28 00:00:00', 6, 'UTC')))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2020-01-04 23:59:59', 6, 'UTC'))), equals(e.event, 'sign up'))
GROUP BY e__pdi.person_id)
GROUP BY day_start
- ORDER BY day_start ASC))
+ ORDER BY day_start ASC)
+ ORDER BY day_start ASC)
ORDER BY sum(count) DESC
LIMIT 10000 SETTINGS readonly=2,
max_execution_time=60,
@@ -4153,7 +4158,7 @@
breakdown_value AS breakdown_value
FROM
(SELECT any(e__session.duration) AS session_duration,
- transform(ifNull(toString(e__pdi__person.`properties___$some_prop`), '$$_posthog_breakdown_null_$$'), ['some_val', 'another_val'], ['some_val', 'another_val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e__pdi__person.`properties___$some_prop`), ''), '$$_posthog_breakdown_null_$$'), ['some_val', 'another_val'], ['some_val', 'another_val'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM events AS e SAMPLE 1
INNER JOIN
(SELECT events.`$session_id` AS id,
@@ -4375,7 +4380,7 @@
breakdown_value AS breakdown_value
FROM
(SELECT any(e__session.duration) AS session_duration,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['value2', 'value1'], ['value2', 'value1'], '$$_posthog_breakdown_other_$$') AS breakdown_value,
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['value2', 'value1'], ['value2', 'value1'], '$$_posthog_breakdown_other_$$') AS breakdown_value,
toStartOfWeek(toTimeZone(e.timestamp, 'UTC'), 0) AS day_start
FROM events AS e SAMPLE 1
INNER JOIN
@@ -4448,7 +4453,7 @@
breakdown_value AS breakdown_value
FROM
(SELECT any(e__session.duration) AS session_duration,
- transform(ifNull(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), '$$_posthog_breakdown_null_$$'), ['value2', 'value1'], ['value2', 'value1'], '$$_posthog_breakdown_other_$$') AS breakdown_value,
+ transform(ifNull(nullIf(toString(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(e.properties, '$some_property'), ''), 'null'), '^"|"$', '')), ''), '$$_posthog_breakdown_null_$$'), ['value2', 'value1'], ['value2', 'value1'], '$$_posthog_breakdown_other_$$') AS breakdown_value,
toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start
FROM events AS e SAMPLE 1
INNER JOIN
diff --git a/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends_data_warehouse_query.ambr b/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends_data_warehouse_query.ambr
index bd7142030fe3a..68ff0e1542b02 100644
--- a/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends_data_warehouse_query.ambr
+++ b/posthog/hogql_queries/insights/trends/test/__snapshots__/test_trends_data_warehouse_query.ambr
@@ -37,7 +37,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.id) AS total,
toStartOfDay(toTimeZone(e.created, 'UTC')) AS day_start,
- transform(ifNull(toString(e.prop_1), '$$_posthog_breakdown_null_$$'), ['d', 'c', 'b', 'a'], ['d', 'c', 'b', 'a'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e.prop_1), ''), '$$_posthog_breakdown_null_$$'), ['d', 'c', 'b', 'a'], ['d', 'c', 'b', 'a'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.hogql.datawarehouse.trendquery/*.parquet', 'object_storage_root_user', 'object_storage_root_password', 'Parquet', 'id String, prop_1 String, prop_2 String, created DateTime64(3, \'UTC\')') AS e
WHERE and(ifNull(greaterOrEquals(toTimeZone(e.created, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2023-01-01 00:00:00', 6, 'UTC')))), 0), ifNull(lessOrEquals(toTimeZone(e.created, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2023-01-07 23:59:59', 6, 'UTC'))), 0), or(ifNull(equals(toString(e.prop_1), 'd'), 0), ifNull(equals(toString(e.prop_1), 'c'), 0), ifNull(equals(toString(e.prop_1), 'b'), 0), ifNull(equals(toString(e.prop_1), 'a'), 0)))
GROUP BY day_start,
@@ -90,7 +90,7 @@
ORDER BY sec.breakdown_value ASC, day_start ASC
UNION ALL SELECT count(e.id) AS total,
toStartOfDay(toTimeZone(e.created, 'UTC')) AS day_start,
- transform(ifNull(toString(e.prop_1), '$$_posthog_breakdown_null_$$'), ['a'], ['a'], '$$_posthog_breakdown_other_$$') AS breakdown_value
+ transform(ifNull(nullIf(toString(e.prop_1), ''), '$$_posthog_breakdown_null_$$'), ['a'], ['a'], '$$_posthog_breakdown_other_$$') AS breakdown_value
FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.hogql.datawarehouse.trendquery/*.parquet', 'object_storage_root_user', 'object_storage_root_password', 'Parquet', 'id String, prop_1 String, prop_2 String, created DateTime64(3, \'UTC\')') AS e
WHERE and(ifNull(greaterOrEquals(toTimeZone(e.created, 'UTC'), toStartOfDay(assumeNotNull(parseDateTime64BestEffortOrNull('2023-01-01 00:00:00', 6, 'UTC')))), 0), ifNull(lessOrEquals(toTimeZone(e.created, 'UTC'), assumeNotNull(parseDateTime64BestEffortOrNull('2023-01-07 23:59:59', 6, 'UTC'))), 0), equals(e.prop_1, 'a'), ifNull(equals(toString(e.prop_1), 'a'), 0))
GROUP BY day_start,
diff --git a/posthog/hogql_queries/insights/trends/test/test_trends.py b/posthog/hogql_queries/insights/trends/test/test_trends.py
index 9e885fbadcc1d..1ef5c15c59b4a 100644
--- a/posthog/hogql_queries/insights/trends/test/test_trends.py
+++ b/posthog/hogql_queries/insights/trends/test/test_trends.py
@@ -22,7 +22,7 @@
from posthog.hogql_queries.insights.trends.trends_query_runner import TrendsQueryRunner
from posthog.hogql_queries.legacy_compatibility.filter_to_query import (
clean_entity_properties,
- clean_properties,
+ clean_global_properties,
)
from posthog.models import (
Action,
@@ -118,7 +118,7 @@ def _props(dict: Dict):
"values": [{"type": "AND", "values": [props]}],
}
- return PropertyGroupFilter(**clean_properties(raw_properties))
+ return PropertyGroupFilter(**clean_global_properties(raw_properties))
def convert_filter_to_trends_query(filter: Filter) -> TrendsQuery:
diff --git a/posthog/hogql_queries/legacy_compatibility/clean_properties.py b/posthog/hogql_queries/legacy_compatibility/clean_properties.py
new file mode 100644
index 0000000000000..27e400d8c99e3
--- /dev/null
+++ b/posthog/hogql_queries/legacy_compatibility/clean_properties.py
@@ -0,0 +1,133 @@
+def clean_global_properties(properties: dict | list[dict] | None):
+ if properties is None or len(properties) == 0:
+ # empty properties
+ return None
+ elif is_old_style_properties(properties):
+ # old style properties
+ properties = transform_old_style_properties(properties)
+ properties = {
+ "type": "AND",
+ "values": [{"type": "AND", "values": properties}],
+ }
+ return clean_property_group_filter(properties)
+ elif isinstance(properties, list):
+ # list of property filters
+ properties = {
+ "type": "AND",
+ "values": [{"type": "AND", "values": properties}],
+ }
+ return clean_property_group_filter(properties)
+ elif (
+ isinstance(properties, dict)
+ and properties.get("type") in ["AND", "OR"]
+ and not any(property.get("type") in ["AND", "OR"] for property in properties["values"])
+ ):
+ # property group filter value
+ properties = {
+ "type": "AND",
+ "values": [properties],
+ }
+ return clean_property_group_filter(properties)
+ else:
+ # property group filter
+ return clean_property_group_filter(properties)
+
+
+def clean_entity_properties(properties: list[dict] | dict | None):
+ if properties is None or len(properties) == 0:
+ # empty properties
+ return None
+ elif is_old_style_properties(properties):
+ # old style properties
+ return transform_old_style_properties(properties)
+ elif isinstance(properties, list):
+ # list of property filters
+ return list(map(clean_property, properties))
+ elif (
+ isinstance(properties, dict)
+ and properties.get("type") in ["AND", "OR"]
+ and not any(property.get("type") in ["AND", "OR"] for property in properties["values"])
+ ):
+ # property group filter value
+ return list(map(clean_property, properties["values"]))
+ else:
+ raise ValueError("Unexpected format of entity properties.")
+
+
+def clean_property_group_filter(properties: dict):
+ properties["values"] = clean_property_group_filter_values(properties["values"])
+ return properties
+
+
+def clean_property_group_filter_values(properties: list[dict]):
+ return [clean_property_group_filter_value(property) for property in properties]
+
+
+def clean_property_group_filter_value(property: dict):
+ if property.get("type") in ["AND", "OR"]:
+ # property group filter value
+ property["values"] = clean_property_group_filter_values(property["values"])
+ return property
+ else:
+ # property filter
+ return clean_property(property)
+
+
+def clean_property(property: dict):
+ cleaned_property = {**property}
+
+ # fix type typo
+ if cleaned_property.get("type") == "events":
+ cleaned_property["type"] = "event"
+
+ # fix value key typo
+ if cleaned_property.get("values") is not None and cleaned_property.get("value") is None:
+ cleaned_property["value"] = cleaned_property.pop("values")
+
+ # convert precalculated and static cohorts to cohorts
+ if cleaned_property.get("type") in ("precalculated-cohort", "static-cohort"):
+ cleaned_property["type"] = "cohort"
+
+ # fix invalid property key for cohorts
+ if cleaned_property.get("type") == "cohort" and cleaned_property.get("key") != "id":
+ cleaned_property["key"] = "id"
+
+ # set a default operator for properties that support it, but don't have an operator set
+ if is_property_with_operator(cleaned_property) and cleaned_property.get("operator") is None:
+ cleaned_property["operator"] = "exact"
+
+ # remove the operator for properties that don't support it, but have it set
+ if not is_property_with_operator(cleaned_property) and cleaned_property.get("operator") is not None:
+ del cleaned_property["operator"]
+
+ # remove none from values
+ if isinstance(cleaned_property.get("value"), list):
+ cleaned_property["value"] = list(filter(lambda x: x is not None, cleaned_property.get("value"))) # type: ignore
+
+ # remove keys without concrete value
+ cleaned_property = {key: value for key, value in cleaned_property.items() if value is not None}
+
+ return cleaned_property
+
+
+def is_property_with_operator(property: dict):
+ return property.get("type") not in ("cohort", "hogql")
+
+
+# old style dict properties e.g. {"utm_medium__icontains": "email"}
+def is_old_style_properties(properties):
+ return isinstance(properties, dict) and len(properties) == 1 and properties.get("type") not in ("AND", "OR")
+
+
+def transform_old_style_properties(properties):
+ key = list(properties.keys())[0]
+ value = list(properties.values())[0]
+ key_split = key.split("__")
+ return [
+ {
+ "key": key_split[0],
+ "value": value,
+ "operator": key_split[1] if len(key_split) > 1 else "exact",
+ "type": "event",
+ }
+ ]
diff --git a/posthog/hogql_queries/legacy_compatibility/filter_to_query.py b/posthog/hogql_queries/legacy_compatibility/filter_to_query.py
index 2b8f59f88a421..199294a3a5969 100644
--- a/posthog/hogql_queries/legacy_compatibility/filter_to_query.py
+++ b/posthog/hogql_queries/legacy_compatibility/filter_to_query.py
@@ -2,6 +2,7 @@
from enum import Enum
import json
from typing import List, Dict, Literal
+from posthog.hogql_queries.legacy_compatibility.clean_properties import clean_entity_properties, clean_global_properties
from posthog.models.entity.entity import Entity as LegacyEntity
from posthog.schema import (
ActionsNode,
@@ -18,7 +19,6 @@
LifecycleQuery,
PathsFilter,
PathsQuery,
- PropertyGroupFilter,
RetentionFilter,
RetentionQuery,
StickinessFilter,
@@ -45,88 +45,6 @@ class MathAvailability(str, Enum):
]
-def is_property_with_operator(property: Dict):
- return property.get("type") not in ("cohort", "hogql")
-
-
-def clean_property(property: Dict):
- cleaned_property = {**property}
-
- # fix type typo
- if cleaned_property.get("type") == "events":
- cleaned_property["type"] = "event"
-
- # fix value key typo
- if cleaned_property.get("values") is not None and cleaned_property.get("value") is None:
- cleaned_property["value"] = cleaned_property.pop("values")
-
- # convert precalculated and static cohorts to cohorts
- if cleaned_property.get("type") in ("precalculated-cohort", "static-cohort"):
- cleaned_property["type"] = "cohort"
-
- # fix invalid property key for cohorts
- if cleaned_property.get("type") == "cohort" and cleaned_property.get("key") != "id":
- cleaned_property["key"] = "id"
-
- # set a default operator for properties that support it, but don't have an operator set
- if is_property_with_operator(cleaned_property) and cleaned_property.get("operator") is None:
- cleaned_property["operator"] = "exact"
-
- # remove the operator for properties that don't support it, but have it set
- if not is_property_with_operator(cleaned_property) and cleaned_property.get("operator") is not None:
- del cleaned_property["operator"]
-
- # remove none from values
- if isinstance(cleaned_property.get("value"), List):
- cleaned_property["value"] = list(filter(lambda x: x is not None, cleaned_property.get("value")))
-
- # remove keys without concrete value
- cleaned_property = {key: value for key, value in cleaned_property.items() if value is not None}
-
- return cleaned_property
-
-
-# old style dict properties
-def is_old_style_properties(properties):
- return isinstance(properties, Dict) and len(properties) == 1 and properties.get("type") not in ("AND", "OR")
-
-
-def transform_old_style_properties(properties):
- key = list(properties.keys())[0]
- value = list(properties.values())[0]
- key_split = key.split("__")
- return [
- {
- "key": key_split[0],
- "value": value,
- "operator": key_split[1] if len(key_split) > 1 else "exact",
- "type": "event",
- }
- ]
-
-
-def clean_entity_properties(properties: List[Dict] | None):
- if properties is None:
- return None
- elif is_old_style_properties(properties):
- return transform_old_style_properties(properties)
- else:
- return list(map(clean_property, properties))
-
-
-def clean_property_group_filter_value(value: Dict):
- if value.get("type") in ("AND", "OR"):
- value["values"] = map(clean_property_group_filter_value, value.get("values"))
- return value
- else:
- return clean_property(value)
-
-
-def clean_properties(properties: Dict):
- properties["values"] = map(clean_property_group_filter_value, properties.get("values"))
- return properties
-
-
def clean_display(display: str):
if display not in ChartDisplayType.__members__:
return None
@@ -299,29 +217,13 @@ def _sampling_factor(filter: Dict):
return {"samplingFactor": filter.get("sampling_factor")}
-def _filter_test_accounts(filter: Dict):
- return {"filterTestAccounts": filter.get("filter_test_accounts")}
-
-
def _properties(filter: Dict):
raw_properties = filter.get("properties", None)
- if raw_properties is None or len(raw_properties) == 0:
- return {}
- elif isinstance(raw_properties, list):
- raw_properties = {
- "type": "AND",
- "values": [{"type": "AND", "values": raw_properties}],
- }
- return {"properties": PropertyGroupFilter(**clean_properties(raw_properties))}
- elif is_old_style_properties(raw_properties):
- raw_properties = transform_old_style_properties(raw_properties)
- raw_properties = {
- "type": "AND",
- "values": [{"type": "AND", "values": raw_properties}],
- }
- return {"properties": PropertyGroupFilter(**clean_properties(raw_properties))}
- else:
- return {"properties": PropertyGroupFilter(**clean_properties(raw_properties))}
+ return {"properties": clean_global_properties(raw_properties)}
+
+
+def _filter_test_accounts(filter: Dict):
+ return {"filterTestAccounts": filter.get("filter_test_accounts")}
def _breakdown_filter(_filter: Dict):
diff --git a/posthog/hogql_queries/legacy_compatibility/test/test_clean_properties.py b/posthog/hogql_queries/legacy_compatibility/test/test_clean_properties.py
new file mode 100644
index 0000000000000..e3e5fd91acd7b
--- /dev/null
+++ b/posthog/hogql_queries/legacy_compatibility/test/test_clean_properties.py
@@ -0,0 +1,149 @@
+from posthog.hogql_queries.legacy_compatibility.clean_properties import clean_entity_properties, clean_global_properties
+from posthog.test.base import BaseTest
+
+
+class TestCleanGlobalProperties(BaseTest):
+ def test_handles_empty_properties(self):
+ properties: dict = {}
+
+ result = clean_global_properties(properties)
+
+ self.assertEqual(result, None)
+
+ def test_handles_old_style_properties(self):
+ properties = {"utm_medium__icontains": "email"}
+
+ result = clean_global_properties(properties)
+
+ self.assertEqual(
+ result,
+ {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": [{"key": "utm_medium", "operator": "icontains", "type": "event", "value": "email"}],
+ }
+ ],
+ },
+ )
+
+ def test_handles_property_filter_lists(self):
+ properties = [{"key": "id", "type": "cohort", "value": 636, "operator": None}]
+
+ result = clean_global_properties(properties)
+
+ self.assertEqual(
+ result,
+ {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": [{"key": "id", "type": "cohort", "value": 636}],
+ }
+ ],
+ },
+ )
+
+ def test_handles_property_group_filters(self):
+ properties = {
+ "type": "AND",
+ "values": [{"type": "AND", "values": [{"key": "id", "type": "cohort", "value": 850, "operator": None}]}],
+ }
+
+ result = clean_global_properties(properties)
+
+ self.assertEqual(
+ result,
+ {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": [{"key": "id", "type": "cohort", "value": 850}],
+ }
+ ],
+ },
+ )
+
+ def test_handles_property_group_filters_values(self):
+ properties = {
+ "type": "AND",
+ "values": [{"key": "id", "type": "cohort", "value": 850, "operator": None}],
+ }
+
+ result = clean_global_properties(properties)
+
+ self.assertEqual(
+ result,
+ {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": [{"key": "id", "type": "cohort", "value": 850}],
+ }
+ ],
+ },
+ )
+
+
+class TestCleanEntityProperties(BaseTest):
+ def test_handles_empty_properties(self):
+ properties: dict = {}
+
+ result = clean_entity_properties(properties)
+
+ self.assertEqual(result, None)
+
+ def test_handles_old_style_properties(self):
+ properties = {"utm_medium__icontains": "email"}
+
+ result = clean_entity_properties(properties)
+
+ self.assertEqual(
+ result,
+ [{"key": "utm_medium", "operator": "icontains", "type": "event", "value": "email"}],
+ )
+
+ def test_handles_property_filter_lists(self):
+ properties = [
+ {"key": "$current_url", type: "event", "value": "https://hedgebox.net/signup/", "operator": "exact"},
+ ]
+
+ result = clean_entity_properties(properties)
+
+ self.assertEqual(
+ result,
+ [
+ {"key": "$current_url", type: "event", "value": "https://hedgebox.net/signup/", "operator": "exact"},
+ ],
+ )
+
+ def test_handles_property_group_values(self):
+ properties = {
+ "type": "AND",
+ "values": [
+ {
+ "key": "$current_url",
+ "operator": "exact",
+ "type": "event",
+ "value": "https://hedgebox.net/signup/",
+ },
+ ],
+ }
+
+ result = clean_entity_properties(properties)
+
+ self.assertEqual(
+ result,
+ [
+ {
+ "key": "$current_url",
+ "operator": "exact",
+ "type": "event",
+ "value": "https://hedgebox.net/signup/",
+ },
+ ],
+ )
diff --git a/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py b/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py
index 9421ac41be854..9abc0f3506b8c 100644
--- a/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py
+++ b/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py
@@ -1167,7 +1167,7 @@ def test_series_properties(self):
self.assertEqual(
query.series,
[
- EventsNode(event="$pageview", name="$pageview", properties=[]),
+ EventsNode(event="$pageview", name="$pageview", properties=None),
EventsNode(
event="$pageview",
name="$pageview",
diff --git a/posthog/migrations/0399_batchexportrun_records_total_count.py b/posthog/migrations/0399_batchexportrun_records_total_count.py
new file mode 100644
index 0000000000000..b9301a92b4110
--- /dev/null
+++ b/posthog/migrations/0399_batchexportrun_records_total_count.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.1.13 on 2024-03-25 14:13
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("posthog", "0398_alter_externaldatasource_source_type"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="batchexportrun",
+ name="records_total_count",
+ field=models.IntegerField(
+ help_text="The total count of records that should be exported in this BatchExportRun.", null=True
+ ),
+ ),
+ ]
diff --git a/posthog/models/team/team.py b/posthog/models/team/team.py
index 66b4a3ed51415..afceba0ffd728 100644
--- a/posthog/models/team/team.py
+++ b/posthog/models/team/team.py
@@ -357,6 +357,25 @@ def _person_on_events_v2_querying_enabled(self) -> bool:
return get_instance_setting("PERSON_ON_EVENTS_V2_ENABLED")
+ @property
+ def person_on_events_v3_querying_enabled(self) -> bool:
+ if settings.PERSON_ON_EVENTS_V3_OVERRIDE is not None:
+ return settings.PERSON_ON_EVENTS_V3_OVERRIDE
+
+ return posthoganalytics.feature_enabled(
+ "persons-on-events-v3-reads-enabled",
+ str(self.uuid),
+ groups={"organization": str(self.organization_id)},
+ group_properties={
+ "organization": {
+ "id": str(self.organization_id),
+ "created_at": self.organization.created_at,
+ }
+ },
+ only_evaluate_locally=True,
+ send_feature_flag_events=False,
+ )
+
@property
def strict_caching_enabled(self) -> bool:
enabled_teams = get_list(get_instance_setting("STRICT_CACHING_TEAMS"))
diff --git a/posthog/settings/__init__.py b/posthog/settings/__init__.py
index 455b7e8dc34a1..dd72e63bcc92a 100644
--- a/posthog/settings/__init__.py
+++ b/posthog/settings/__init__.py
@@ -96,6 +96,7 @@
# Only written in specific scripts - do not use outside of them.
PERSON_ON_EVENTS_V2_OVERRIDE = get_from_env("PERSON_ON_EVENTS_V2_OVERRIDE", optional=True, type_cast=str_to_bool)
+PERSON_ON_EVENTS_V3_OVERRIDE = get_from_env("PERSON_ON_EVENTS_V3_OVERRIDE", optional=True, type_cast=str_to_bool)
# Wether to use insight queries converted to HogQL.
HOGQL_INSIGHTS_OVERRIDE = get_from_env("HOGQL_INSIGHTS_OVERRIDE", optional=True, type_cast=str_to_bool)
diff --git a/posthog/temporal/batch_exports/__init__.py b/posthog/temporal/batch_exports/__init__.py
index 8debe181fb82f..33c1b200e6a97 100644
--- a/posthog/temporal/batch_exports/__init__.py
+++ b/posthog/temporal/batch_exports/__init__.py
@@ -5,9 +5,9 @@
)
from posthog.temporal.batch_exports.batch_exports import (
create_batch_export_backfill_model,
- create_export_run,
+ finish_batch_export_run,
+ start_batch_export_run,
update_batch_export_backfill_model_status,
- update_export_run_status,
)
from posthog.temporal.batch_exports.bigquery_batch_export import (
BigQueryBatchExportWorkflow,
@@ -59,9 +59,10 @@
ACTIVITIES = [
backfill_schedule,
create_batch_export_backfill_model,
- create_export_run,
+ start_batch_export_run,
create_table,
drop_table,
+ finish_batch_export_run,
get_schedule_frequency,
insert_into_bigquery_activity,
insert_into_http_activity,
@@ -73,7 +74,6 @@
optimize_person_distinct_id_overrides,
submit_mutation,
update_batch_export_backfill_model_status,
- update_export_run_status,
wait_for_mutation,
wait_for_table,
]
diff --git a/posthog/temporal/batch_exports/batch_exports.py b/posthog/temporal/batch_exports/batch_exports.py
index 88cf9e32f274f..0e12fc14635b4 100644
--- a/posthog/temporal/batch_exports/batch_exports.py
+++ b/posthog/temporal/batch_exports/batch_exports.py
@@ -23,7 +23,7 @@
get_export_finished_metric,
get_export_started_metric,
)
-from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.common.clickhouse import ClickHouseClient, get_client
from posthog.temporal.common.logger import bind_temporal_worker_logger
SELECT_QUERY_TEMPLATE = Template(
@@ -282,36 +282,74 @@ def get_data_interval(interval: str, data_interval_end: str | None) -> tuple[dt.
@dataclasses.dataclass
-class CreateBatchExportRunInputs:
- """Inputs to the create_export_run activity.
+class StartBatchExportRunInputs:
+ """Inputs to the 'start_batch_export_run' activity.
Attributes:
team_id: The id of the team the BatchExportRun belongs to.
batch_export_id: The id of the BatchExport this BatchExportRun belongs to.
data_interval_start: Start of this BatchExportRun's data interval.
data_interval_end: End of this BatchExportRun's data interval.
+ exclude_events: Optionally, any event names that should be excluded.
+ include_events: Optionally, the event names that should only be included in the export.
"""
team_id: int
batch_export_id: str
data_interval_start: str
data_interval_end: str
- status: str = BatchExportRun.Status.STARTING
+ exclude_events: list[str] | None = None
+ include_events: list[str] | None = None
+
+
+RecordsTotalCount = int
+BatchExportRunId = str
@activity.defn
-async def create_export_run(inputs: CreateBatchExportRunInputs) -> str:
- """Activity that creates an BatchExportRun.
+async def start_batch_export_run(inputs: StartBatchExportRunInputs) -> tuple[BatchExportRunId, RecordsTotalCount]:
+ """Activity that creates an BatchExportRun and returns the count of records to export.
Intended to be used in all export workflows, usually at the start, to create a model
instance to represent them in our database.
+
+ Upon seeing a count of 0 records to export, batch export workflows should finish early
+ (i.e. without running the insert activity), as there will be nothing to export.
"""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id)
logger.info(
- "Creating batch export for range %s - %s",
+ "Starting batch export for range %s - %s",
inputs.data_interval_start,
inputs.data_interval_end,
)
+
+ async with get_client(team_id=inputs.team_id) as client:
+ if not await client.is_alive():
+ raise ConnectionError("Cannot establish connection to ClickHouse")
+
+ count = await get_rows_count(
+ client=client,
+ team_id=inputs.team_id,
+ interval_start=inputs.data_interval_start,
+ interval_end=inputs.data_interval_end,
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
+ )
+
+ if count > 0:
+ logger.info(
+ "Batch export for range %s - %s will export %s rows",
+ inputs.data_interval_start,
+ inputs.data_interval_end,
+ count,
+ )
+ else:
+ logger.info(
+ "Batch export for range %s - %s has no rows to export",
+ inputs.data_interval_start,
+ inputs.data_interval_end,
+ )
+
# 'sync_to_async' type hints are fixed in asgiref>=3.4.1
# But one of our dependencies is pinned to asgiref==3.3.2.
# Remove these comments once we upgrade.
@@ -319,33 +357,51 @@ async def create_export_run(inputs: CreateBatchExportRunInputs) -> str:
batch_export_id=uuid.UUID(inputs.batch_export_id),
data_interval_start=inputs.data_interval_start,
data_interval_end=inputs.data_interval_end,
- status=inputs.status,
+ status=BatchExportRun.Status.STARTING,
+ records_total_count=count,
)
- return str(run.id)
+ return str(run.id), count
@dataclasses.dataclass
-class UpdateBatchExportRunStatusInputs:
- """Inputs to the update_export_run_status activity."""
+class FinishBatchExportRunInputs:
+ """Inputs to the 'finish_batch_export_run' activity.
+
+ Attributes:
+ id: The id of the batch export run. This should be a valid UUID string.
+ team_id: The team id of the batch export.
+ status: The status this batch export is finishing with.
+ latest_error: The latest error message captured, if any.
+ records_completed: Number of records successfully exported.
+ records_total_count: Total count of records this run noted.
+ """
id: str
- status: str
team_id: int
+ status: str
latest_error: str | None = None
- records_completed: int = 0
+ records_completed: int | None = None
+ records_total_count: int | None = None
@activity.defn
-async def update_export_run_status(inputs: UpdateBatchExportRunStatusInputs) -> None:
- """Activity that updates the status of an BatchExportRun."""
+async def finish_batch_export_run(inputs: FinishBatchExportRunInputs) -> None:
+ """Activity that finishes a BatchExportRun.
+
+ Finishing means a final update to the status of the BatchExportRun model.
+ """
logger = await bind_temporal_worker_logger(team_id=inputs.team_id)
+ update_params = {
+ key: value
+ for key, value in dataclasses.asdict(inputs).items()
+ if key not in ("id", "team_id") and value is not None
+ }
batch_export_run = await sync_to_async(update_batch_export_run)(
run_id=uuid.UUID(inputs.id),
- status=inputs.status,
- latest_error=inputs.latest_error,
- records_completed=inputs.records_completed,
+ finished_at=dt.datetime.now(),
+ **update_params,
)
if batch_export_run.status in (BatchExportRun.Status.FAILED, BatchExportRun.Status.FAILED_RETRYABLE):
@@ -428,11 +484,15 @@ async def update_batch_export_backfill_model_status(inputs: UpdateBatchExportBac
)
+RecordsCompleted = int
+BatchExportActivity = collections.abc.Callable[..., collections.abc.Awaitable[RecordsCompleted]]
+
+
async def execute_batch_export_insert_activity(
- activity,
+ activity: BatchExportActivity,
inputs,
non_retryable_error_types: list[str],
- update_inputs: UpdateBatchExportRunStatusInputs,
+ finish_inputs: FinishBatchExportRunInputs,
start_to_close_timeout_seconds: int = 3600,
heartbeat_timeout_seconds: int | None = 120,
maximum_attempts: int = 10,
@@ -449,7 +509,7 @@ async def execute_batch_export_insert_activity(
activity: The 'insert_into_*' activity function to execute.
inputs: The inputs to the activity.
non_retryable_error_types: A list of errors to not retry on when executing the activity.
- update_inputs: Inputs to the update_export_run_status to run at the end.
+ finish_inputs: Inputs to the 'finish_batch_export_run' to run at the end.
start_to_close_timeout: A timeout for the 'insert_into_*' activity function.
maximum_attempts: Maximum number of retries for the 'insert_into_*' activity function.
Assuming the error that triggered the retry is not in non_retryable_error_types.
@@ -472,30 +532,30 @@ async def execute_batch_export_insert_activity(
heartbeat_timeout=dt.timedelta(seconds=heartbeat_timeout_seconds) if heartbeat_timeout_seconds else None,
retry_policy=retry_policy,
)
- update_inputs.records_completed = records_completed
+ finish_inputs.records_completed = records_completed
except exceptions.ActivityError as e:
if isinstance(e.cause, exceptions.CancelledError):
- update_inputs.status = BatchExportRun.Status.CANCELLED
+ finish_inputs.status = BatchExportRun.Status.CANCELLED
elif isinstance(e.cause, exceptions.ApplicationError) and e.cause.type not in non_retryable_error_types:
- update_inputs.status = BatchExportRun.Status.FAILED_RETRYABLE
+ finish_inputs.status = BatchExportRun.Status.FAILED_RETRYABLE
else:
- update_inputs.status = BatchExportRun.Status.FAILED
+ finish_inputs.status = BatchExportRun.Status.FAILED
- update_inputs.latest_error = str(e.cause)
+ finish_inputs.latest_error = str(e.cause)
raise
except Exception:
- update_inputs.status = BatchExportRun.Status.FAILED
- update_inputs.latest_error = "An unexpected error has ocurred"
+ finish_inputs.status = BatchExportRun.Status.FAILED
+ finish_inputs.latest_error = "An unexpected error has ocurred"
raise
finally:
- get_export_finished_metric(status=update_inputs.status.lower()).add(1)
+ get_export_finished_metric(status=finish_inputs.status.lower()).add(1)
await workflow.execute_activity(
- update_export_run_status,
- update_inputs,
+ finish_batch_export_run,
+ finish_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
diff --git a/posthog/temporal/batch_exports/bigquery_batch_export.py b/posthog/temporal/batch_exports/bigquery_batch_export.py
index b754a7add16b4..f9ddd29bd528f 100644
--- a/posthog/temporal/batch_exports/bigquery_batch_export.py
+++ b/posthog/temporal/batch_exports/bigquery_batch_export.py
@@ -12,17 +12,22 @@
from temporalio.common import RetryPolicy
from posthog.batch_exports.models import BatchExportRun
-from posthog.batch_exports.service import BatchExportField, BatchExportSchema, BigQueryBatchExportInputs
+from posthog.batch_exports.service import (
+ BatchExportField,
+ BatchExportSchema,
+ BigQueryBatchExportInputs,
+)
from posthog.temporal.batch_exports.base import PostHogWorkflow
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
+ FinishBatchExportRunInputs,
+ RecordsCompleted,
+ StartBatchExportRunInputs,
default_fields,
execute_batch_export_insert_activity,
+ finish_batch_export_run,
get_data_interval,
- get_rows_count,
iter_records,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.metrics import (
get_bytes_exported_metric,
@@ -146,6 +151,7 @@ class BigQueryInsertInputs:
include_events: list[str] | None = None
use_json_type: bool = False
batch_export_schema: BatchExportSchema | None = None
+ run_id: str | None = None
@contextlib.contextmanager
@@ -195,13 +201,16 @@ def bigquery_default_fields() -> list[BatchExportField]:
@activity.defn
-async def insert_into_bigquery_activity(inputs: BigQueryInsertInputs) -> int:
+async def insert_into_bigquery_activity(inputs: BigQueryInsertInputs) -> RecordsCompleted:
"""Activity streams data from ClickHouse to BigQuery."""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id, destination="BigQuery")
logger.info(
- "Exporting batch %s - %s",
+ "Batch exporting range %s - %s to BigQuery: %s.%s.%s",
inputs.data_interval_start,
inputs.data_interval_end,
+ inputs.project_id,
+ inputs.dataset_id,
+ inputs.table_id,
)
should_resume, details = await should_resume_from_activity_heartbeat(activity, BigQueryHeartbeatDetails, logger)
@@ -217,25 +226,6 @@ async def insert_into_bigquery_activity(inputs: BigQueryInsertInputs) -> int:
if not await client.is_alive():
raise ConnectionError("Cannot establish connection to ClickHouse")
- count = await get_rows_count(
- client=client,
- team_id=inputs.team_id,
- interval_start=data_interval_start,
- interval_end=inputs.data_interval_end,
- exclude_events=inputs.exclude_events,
- include_events=inputs.include_events,
- )
-
- if count == 0:
- logger.info(
- "Nothing to export in batch %s - %s",
- inputs.data_interval_start,
- inputs.data_interval_end,
- )
- return 0
-
- logger.info("BatchExporting %s rows", count)
-
if inputs.batch_export_schema is None:
fields = bigquery_default_fields()
query_parameters = None
@@ -380,15 +370,17 @@ async def run(self, inputs: BigQueryBatchExportInputs):
"""Workflow implementation to export data to BigQuery."""
data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end)
- create_export_run_inputs = CreateBatchExportRunInputs(
+ start_batch_export_run_inputs = StartBatchExportRunInputs(
team_id=inputs.team_id,
batch_export_id=inputs.batch_export_id,
data_interval_start=data_interval_start.isoformat(),
data_interval_end=data_interval_end.isoformat(),
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
)
- run_id = await workflow.execute_activity(
- create_export_run,
- create_export_run_inputs,
+ run_id, records_total_count = await workflow.execute_activity(
+ start_batch_export_run,
+ start_batch_export_run_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
@@ -398,10 +390,30 @@ async def run(self, inputs: BigQueryBatchExportInputs):
),
)
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=run_id, status=BatchExportRun.Status.COMPLETED, team_id=inputs.team_id
)
+ finish_inputs = FinishBatchExportRunInputs(
+ id=run_id,
+ status=BatchExportRun.Status.COMPLETED,
+ team_id=inputs.team_id,
+ )
+
+ if records_total_count == 0:
+ await workflow.execute_activity(
+ finish_batch_export_run,
+ finish_inputs,
+ start_to_close_timeout=dt.timedelta(minutes=5),
+ retry_policy=RetryPolicy(
+ initial_interval=dt.timedelta(seconds=10),
+ maximum_interval=dt.timedelta(seconds=60),
+ maximum_attempts=0,
+ non_retryable_error_types=["NotNullViolation", "IntegrityError"],
+ ),
+ )
+ return
+
insert_inputs = BigQueryInsertInputs(
team_id=inputs.team_id,
table_id=inputs.table_id,
@@ -417,6 +429,7 @@ async def run(self, inputs: BigQueryBatchExportInputs):
include_events=inputs.include_events,
use_json_type=inputs.use_json_type,
batch_export_schema=inputs.batch_export_schema,
+ run_id=run_id,
)
await execute_batch_export_insert_activity(
@@ -430,5 +443,5 @@ async def run(self, inputs: BigQueryBatchExportInputs):
# Usually means the dataset or project doesn't exist.
"NotFound",
],
- update_inputs=update_inputs,
+ finish_inputs=finish_inputs,
)
diff --git a/posthog/temporal/batch_exports/http_batch_export.py b/posthog/temporal/batch_exports/http_batch_export.py
index 2866d50c99876..993806c004c5e 100644
--- a/posthog/temporal/batch_exports/http_batch_export.py
+++ b/posthog/temporal/batch_exports/http_batch_export.py
@@ -9,17 +9,22 @@
from temporalio import activity, workflow
from temporalio.common import RetryPolicy
-from posthog.batch_exports.service import BatchExportField, BatchExportSchema, HttpBatchExportInputs
+from posthog.batch_exports.service import (
+ BatchExportField,
+ BatchExportSchema,
+ HttpBatchExportInputs,
+)
from posthog.models import BatchExportRun
from posthog.temporal.batch_exports.base import PostHogWorkflow
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
+ FinishBatchExportRunInputs,
+ RecordsCompleted,
+ StartBatchExportRunInputs,
execute_batch_export_insert_activity,
+ finish_batch_export_run,
get_data_interval,
- get_rows_count,
iter_records,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.metrics import (
get_bytes_exported_metric,
@@ -99,6 +104,7 @@ class HttpInsertInputs:
data_interval_end: str
exclude_events: list[str] | None = None
include_events: list[str] | None = None
+ run_id: str | None = None
batch_export_schema: BatchExportSchema | None = None
@@ -154,38 +160,20 @@ async def post_json_file_to_url(url, batch_file, session: aiohttp.ClientSession)
@activity.defn
-async def insert_into_http_activity(inputs: HttpInsertInputs) -> int:
+async def insert_into_http_activity(inputs: HttpInsertInputs) -> RecordsCompleted:
"""Activity streams data from ClickHouse to an HTTP Endpoint."""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id, destination="HTTP")
logger.info(
- "Exporting batch %s - %s",
+ "Batch exporting range %s - %s to HTTP endpoint: %s",
inputs.data_interval_start,
inputs.data_interval_end,
+ inputs.url,
)
async with get_client(team_id=inputs.team_id) as client:
if not await client.is_alive():
raise ConnectionError("Cannot establish connection to ClickHouse")
- count = await get_rows_count(
- client=client,
- team_id=inputs.team_id,
- interval_start=inputs.data_interval_start,
- interval_end=inputs.data_interval_end,
- exclude_events=inputs.exclude_events,
- include_events=inputs.include_events,
- )
-
- if count == 0:
- logger.info(
- "Nothing to export in batch %s - %s",
- inputs.data_interval_start,
- inputs.data_interval_end,
- )
- return 0
-
- logger.info("BatchExporting %s rows", count)
-
if inputs.batch_export_schema is not None:
raise NotImplementedError("Batch export schema is not supported for HTTP export")
@@ -329,15 +317,17 @@ async def run(self, inputs: HttpBatchExportInputs):
"""Workflow implementation to export data to an HTTP Endpoint."""
data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end)
- create_export_run_inputs = CreateBatchExportRunInputs(
+ start_batch_export_run_inputs = StartBatchExportRunInputs(
team_id=inputs.team_id,
batch_export_id=inputs.batch_export_id,
data_interval_start=data_interval_start.isoformat(),
data_interval_end=data_interval_end.isoformat(),
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
)
- run_id = await workflow.execute_activity(
- create_export_run,
- create_export_run_inputs,
+ run_id, records_total_count = await workflow.execute_activity(
+ start_batch_export_run,
+ start_batch_export_run_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
@@ -347,12 +337,26 @@ async def run(self, inputs: HttpBatchExportInputs):
),
)
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=run_id,
status=BatchExportRun.Status.COMPLETED,
team_id=inputs.team_id,
)
+ if records_total_count == 0:
+ await workflow.execute_activity(
+ finish_batch_export_run,
+ finish_inputs,
+ start_to_close_timeout=dt.timedelta(minutes=5),
+ retry_policy=RetryPolicy(
+ initial_interval=dt.timedelta(seconds=10),
+ maximum_interval=dt.timedelta(seconds=60),
+ maximum_attempts=0,
+ non_retryable_error_types=["NotNullViolation", "IntegrityError"],
+ ),
+ )
+ return
+
insert_inputs = HttpInsertInputs(
team_id=inputs.team_id,
url=inputs.url,
@@ -362,6 +366,7 @@ async def run(self, inputs: HttpBatchExportInputs):
exclude_events=inputs.exclude_events,
include_events=inputs.include_events,
batch_export_schema=inputs.batch_export_schema,
+ run_id=run_id,
)
await execute_batch_export_insert_activity(
@@ -370,7 +375,7 @@ async def run(self, inputs: HttpBatchExportInputs):
non_retryable_error_types=[
"NonRetryableResponseError",
],
- update_inputs=update_inputs,
+ finish_inputs=finish_inputs,
# Disable heartbeat timeout until we add heartbeat support.
heartbeat_timeout_seconds=None,
)
diff --git a/posthog/temporal/batch_exports/postgres_batch_export.py b/posthog/temporal/batch_exports/postgres_batch_export.py
index 98969ee78de79..54b3f316393c2 100644
--- a/posthog/temporal/batch_exports/postgres_batch_export.py
+++ b/posthog/temporal/batch_exports/postgres_batch_export.py
@@ -14,17 +14,22 @@
from temporalio.common import RetryPolicy
from posthog.batch_exports.models import BatchExportRun
-from posthog.batch_exports.service import BatchExportField, BatchExportSchema, PostgresBatchExportInputs
+from posthog.batch_exports.service import (
+ BatchExportField,
+ BatchExportSchema,
+ PostgresBatchExportInputs,
+)
from posthog.temporal.batch_exports.base import PostHogWorkflow
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
+ FinishBatchExportRunInputs,
+ RecordsCompleted,
+ StartBatchExportRunInputs,
default_fields,
execute_batch_export_insert_activity,
+ finish_batch_export_run,
get_data_interval,
- get_rows_count,
iter_records,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.metrics import (
get_bytes_exported_metric,
@@ -33,7 +38,7 @@
from posthog.temporal.batch_exports.temporary_file import (
BatchExportTemporaryFile,
)
-from posthog.temporal.batch_exports.utils import peek_first_and_rewind
+from posthog.temporal.batch_exports.utils import peek_first_and_rewind, try_set_batch_export_run_to_running
from posthog.temporal.common.clickhouse import get_client
from posthog.temporal.common.logger import bind_temporal_worker_logger
@@ -233,41 +238,28 @@ class PostgresInsertInputs:
exclude_events: list[str] | None = None
include_events: list[str] | None = None
batch_export_schema: BatchExportSchema | None = None
+ run_id: str | None = None
@activity.defn
-async def insert_into_postgres_activity(inputs: PostgresInsertInputs) -> int:
+async def insert_into_postgres_activity(inputs: PostgresInsertInputs) -> RecordsCompleted:
"""Activity streams data from ClickHouse to Postgres."""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id, destination="PostgreSQL")
logger.info(
- "Exporting batch %s - %s",
+ "Batch exporting range %s - %s to PostgreSQL: %s.%s.%s",
inputs.data_interval_start,
inputs.data_interval_end,
+ inputs.database,
+ inputs.schema,
+ inputs.table_name,
)
+ await try_set_batch_export_run_to_running(run_id=inputs.run_id, logger=logger)
+
async with get_client(team_id=inputs.team_id) as client:
if not await client.is_alive():
raise ConnectionError("Cannot establish connection to ClickHouse")
- count = await get_rows_count(
- client=client,
- team_id=inputs.team_id,
- interval_start=inputs.data_interval_start,
- interval_end=inputs.data_interval_end,
- exclude_events=inputs.exclude_events,
- include_events=inputs.include_events,
- )
-
- if count == 0:
- logger.info(
- "Nothing to export in batch %s - %s",
- inputs.data_interval_start,
- inputs.data_interval_end,
- )
- return 0
-
- logger.info("BatchExporting %s rows", count)
-
if inputs.batch_export_schema is None:
fields = postgres_default_fields()
query_parameters = None
@@ -385,15 +377,17 @@ async def run(self, inputs: PostgresBatchExportInputs):
"""Workflow implementation to export data to Postgres."""
data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end)
- create_export_run_inputs = CreateBatchExportRunInputs(
+ start_batch_export_run_inputs = StartBatchExportRunInputs(
team_id=inputs.team_id,
batch_export_id=inputs.batch_export_id,
data_interval_start=data_interval_start.isoformat(),
data_interval_end=data_interval_end.isoformat(),
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
)
- run_id = await workflow.execute_activity(
- create_export_run,
- create_export_run_inputs,
+ run_id, records_total_count = await workflow.execute_activity(
+ start_batch_export_run,
+ start_batch_export_run_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
@@ -403,12 +397,26 @@ async def run(self, inputs: PostgresBatchExportInputs):
),
)
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=run_id,
status=BatchExportRun.Status.COMPLETED,
team_id=inputs.team_id,
)
+ if records_total_count == 0:
+ await workflow.execute_activity(
+ finish_batch_export_run,
+ finish_inputs,
+ start_to_close_timeout=dt.timedelta(minutes=5),
+ retry_policy=RetryPolicy(
+ initial_interval=dt.timedelta(seconds=10),
+ maximum_interval=dt.timedelta(seconds=60),
+ maximum_attempts=0,
+ non_retryable_error_types=["NotNullViolation", "IntegrityError"],
+ ),
+ )
+ return
+
insert_inputs = PostgresInsertInputs(
team_id=inputs.team_id,
user=inputs.user,
@@ -424,6 +432,7 @@ async def run(self, inputs: PostgresBatchExportInputs):
exclude_events=inputs.exclude_events,
include_events=inputs.include_events,
batch_export_schema=inputs.batch_export_schema,
+ run_id=run_id,
)
await execute_batch_export_insert_activity(
@@ -438,7 +447,7 @@ async def run(self, inputs: PostgresBatchExportInputs):
# Missing permissions to, e.g., insert into table.
"InsufficientPrivilege",
],
- update_inputs=update_inputs,
+ finish_inputs=finish_inputs,
# Disable heartbeat timeout until we add heartbeat support.
heartbeat_timeout_seconds=None,
)
diff --git a/posthog/temporal/batch_exports/redshift_batch_export.py b/posthog/temporal/batch_exports/redshift_batch_export.py
index bc1549cef838f..a71f292fcf30a 100644
--- a/posthog/temporal/batch_exports/redshift_batch_export.py
+++ b/posthog/temporal/batch_exports/redshift_batch_export.py
@@ -16,14 +16,15 @@
from posthog.batch_exports.service import BatchExportField, RedshiftBatchExportInputs
from posthog.temporal.batch_exports.base import PostHogWorkflow
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
+ FinishBatchExportRunInputs,
+ RecordsCompleted,
+ StartBatchExportRunInputs,
default_fields,
execute_batch_export_insert_activity,
+ finish_batch_export_run,
get_data_interval,
- get_rows_count,
iter_records,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.metrics import get_rows_exported_metric
from posthog.temporal.batch_exports.postgres_batch_export import (
@@ -271,7 +272,7 @@ class RedshiftInsertInputs(PostgresInsertInputs):
@activity.defn
-async def insert_into_redshift_activity(inputs: RedshiftInsertInputs) -> int:
+async def insert_into_redshift_activity(inputs: RedshiftInsertInputs) -> RecordsCompleted:
"""Activity to insert data from ClickHouse to Redshift.
This activity executes the following steps:
@@ -289,34 +290,18 @@ async def insert_into_redshift_activity(inputs: RedshiftInsertInputs) -> int:
"""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id, destination="Redshift")
logger.info(
- "Exporting batch %s - %s",
+ "Batch exporting range %s - %s to Redshift: %s.%s.%s",
inputs.data_interval_start,
inputs.data_interval_end,
+ inputs.database,
+ inputs.schema,
+ inputs.table_name,
)
async with get_client(team_id=inputs.team_id) as client:
if not await client.is_alive():
raise ConnectionError("Cannot establish connection to ClickHouse")
- count = await get_rows_count(
- client=client,
- team_id=inputs.team_id,
- interval_start=inputs.data_interval_start,
- interval_end=inputs.data_interval_end,
- exclude_events=inputs.exclude_events,
- include_events=inputs.include_events,
- )
-
- if count == 0:
- logger.info(
- "Nothing to export in batch %s - %s",
- inputs.data_interval_start,
- inputs.data_interval_end,
- )
- return 0
-
- logger.info("BatchExporting %s rows", count)
-
if inputs.batch_export_schema is None:
fields = redshift_default_fields()
query_parameters = None
@@ -421,15 +406,17 @@ async def run(self, inputs: RedshiftBatchExportInputs):
"""Workflow implementation to export data to Redshift."""
data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end)
- create_export_run_inputs = CreateBatchExportRunInputs(
+ start_batch_export_run_inputs = StartBatchExportRunInputs(
team_id=inputs.team_id,
batch_export_id=inputs.batch_export_id,
data_interval_start=data_interval_start.isoformat(),
data_interval_end=data_interval_end.isoformat(),
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
)
- run_id = await workflow.execute_activity(
- create_export_run,
- create_export_run_inputs,
+ run_id, records_total_count = await workflow.execute_activity(
+ start_batch_export_run,
+ start_batch_export_run_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
@@ -439,12 +426,26 @@ async def run(self, inputs: RedshiftBatchExportInputs):
),
)
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=run_id,
status=BatchExportRun.Status.COMPLETED,
team_id=inputs.team_id,
)
+ if records_total_count == 0:
+ await workflow.execute_activity(
+ finish_batch_export_run,
+ finish_inputs,
+ start_to_close_timeout=dt.timedelta(minutes=5),
+ retry_policy=RetryPolicy(
+ initial_interval=dt.timedelta(seconds=10),
+ maximum_interval=dt.timedelta(seconds=60),
+ maximum_attempts=0,
+ non_retryable_error_types=["NotNullViolation", "IntegrityError"],
+ ),
+ )
+ return
+
insert_inputs = RedshiftInsertInputs(
team_id=inputs.team_id,
user=inputs.user,
@@ -461,6 +462,7 @@ async def run(self, inputs: RedshiftBatchExportInputs):
include_events=inputs.include_events,
properties_data_type=inputs.properties_data_type,
batch_export_schema=inputs.batch_export_schema,
+ run_id=run_id,
)
await execute_batch_export_insert_activity(
@@ -475,7 +477,7 @@ async def run(self, inputs: RedshiftBatchExportInputs):
# Missing permissions to, e.g., insert into table.
"InsufficientPrivilege",
],
- update_inputs=update_inputs,
+ finish_inputs=finish_inputs,
# Disable heartbeat timeout until we add heartbeat support.
heartbeat_timeout_seconds=None,
)
diff --git a/posthog/temporal/batch_exports/s3_batch_export.py b/posthog/temporal/batch_exports/s3_batch_export.py
index e83fe3f12915d..a6420e95cb8b1 100644
--- a/posthog/temporal/batch_exports/s3_batch_export.py
+++ b/posthog/temporal/batch_exports/s3_batch_export.py
@@ -16,17 +16,22 @@
from temporalio.common import RetryPolicy
from posthog.batch_exports.models import BatchExportRun
-from posthog.batch_exports.service import BatchExportField, BatchExportSchema, S3BatchExportInputs
+from posthog.batch_exports.service import (
+ BatchExportField,
+ BatchExportSchema,
+ S3BatchExportInputs,
+)
from posthog.temporal.batch_exports.base import PostHogWorkflow
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
+ FinishBatchExportRunInputs,
+ RecordsCompleted,
+ StartBatchExportRunInputs,
default_fields,
execute_batch_export_insert_activity,
+ finish_batch_export_run,
get_data_interval,
- get_rows_count,
iter_records,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.metrics import (
get_bytes_exported_metric,
@@ -40,7 +45,7 @@
ParquetBatchExportWriter,
UnsupportedFileFormatError,
)
-from posthog.temporal.batch_exports.utils import peek_first_and_rewind
+from posthog.temporal.batch_exports.utils import peek_first_and_rewind, try_set_batch_export_run_to_running
from posthog.temporal.common.clickhouse import get_client
from posthog.temporal.common.logger import bind_temporal_worker_logger
@@ -336,6 +341,7 @@ class S3InsertInputs:
endpoint_url: str | None = None
# TODO: In Python 3.11, this could be a enum.StrEnum.
file_format: str = "JSONLines"
+ run_id: str | None = None
async def initialize_and_resume_multipart_upload(inputs: S3InsertInputs) -> tuple[S3MultiPartUpload, str]:
@@ -413,7 +419,7 @@ def s3_default_fields() -> list[BatchExportField]:
@activity.defn
-async def insert_into_s3_activity(inputs: S3InsertInputs) -> int:
+async def insert_into_s3_activity(inputs: S3InsertInputs) -> RecordsCompleted:
"""Activity to batch export data from PostHog's ClickHouse to S3.
It currently only creates a single file per run, and uploads as a multipart upload.
@@ -425,34 +431,18 @@ async def insert_into_s3_activity(inputs: S3InsertInputs) -> int:
"""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id, destination="S3")
logger.info(
- "Exporting batch %s - %s",
+ "Batch exporting range %s - %s to S3: %s",
inputs.data_interval_start,
inputs.data_interval_end,
+ get_s3_key(inputs),
)
+ await try_set_batch_export_run_to_running(run_id=inputs.run_id, logger=logger)
+
async with get_client(team_id=inputs.team_id) as client:
if not await client.is_alive():
raise ConnectionError("Cannot establish connection to ClickHouse")
- count = await get_rows_count(
- client=client,
- team_id=inputs.team_id,
- interval_start=inputs.data_interval_start,
- interval_end=inputs.data_interval_end,
- exclude_events=inputs.exclude_events,
- include_events=inputs.include_events,
- )
-
- if count == 0:
- logger.info(
- "Nothing to export in batch %s - %s",
- inputs.data_interval_start,
- inputs.data_interval_end,
- )
- return 0
-
- logger.info("BatchExporting %s rows to S3", count)
-
s3_upload, interval_start = await initialize_and_resume_multipart_upload(inputs)
if inputs.batch_export_schema is None:
@@ -654,15 +644,17 @@ async def run(self, inputs: S3BatchExportInputs):
"""Workflow implementation to export data to S3 bucket."""
data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end)
- create_export_run_inputs = CreateBatchExportRunInputs(
+ start_batch_export_run_inputs = StartBatchExportRunInputs(
team_id=inputs.team_id,
batch_export_id=inputs.batch_export_id,
data_interval_start=data_interval_start.isoformat(),
data_interval_end=data_interval_end.isoformat(),
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
)
- run_id = await workflow.execute_activity(
- create_export_run,
- create_export_run_inputs,
+ run_id, records_total_count = await workflow.execute_activity(
+ start_batch_export_run,
+ start_batch_export_run_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
@@ -672,12 +664,26 @@ async def run(self, inputs: S3BatchExportInputs):
),
)
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=run_id,
status=BatchExportRun.Status.COMPLETED,
team_id=inputs.team_id,
)
+ if records_total_count == 0:
+ await workflow.execute_activity(
+ finish_batch_export_run,
+ finish_inputs,
+ start_to_close_timeout=dt.timedelta(minutes=5),
+ retry_policy=RetryPolicy(
+ initial_interval=dt.timedelta(seconds=10),
+ maximum_interval=dt.timedelta(seconds=60),
+ maximum_attempts=0,
+ non_retryable_error_types=["NotNullViolation", "IntegrityError"],
+ ),
+ )
+ return
+
insert_inputs = S3InsertInputs(
bucket_name=inputs.bucket_name,
region=inputs.region,
@@ -695,6 +701,7 @@ async def run(self, inputs: S3BatchExportInputs):
kms_key_id=inputs.kms_key_id,
batch_export_schema=inputs.batch_export_schema,
file_format=inputs.file_format,
+ run_id=run_id,
)
await execute_batch_export_insert_activity(
@@ -708,5 +715,5 @@ async def run(self, inputs: S3BatchExportInputs):
# An S3 bucket doesn't exist.
"NoSuchBucket",
],
- update_inputs=update_inputs,
+ finish_inputs=finish_inputs,
)
diff --git a/posthog/temporal/batch_exports/snowflake_batch_export.py b/posthog/temporal/batch_exports/snowflake_batch_export.py
index 9053f3e1006ad..19b090340a9c9 100644
--- a/posthog/temporal/batch_exports/snowflake_batch_export.py
+++ b/posthog/temporal/batch_exports/snowflake_batch_export.py
@@ -15,17 +15,22 @@
from temporalio.common import RetryPolicy
from posthog.batch_exports.models import BatchExportRun
-from posthog.batch_exports.service import BatchExportField, BatchExportSchema, SnowflakeBatchExportInputs
+from posthog.batch_exports.service import (
+ BatchExportField,
+ BatchExportSchema,
+ SnowflakeBatchExportInputs,
+)
from posthog.temporal.batch_exports.base import PostHogWorkflow
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
+ FinishBatchExportRunInputs,
+ RecordsCompleted,
+ StartBatchExportRunInputs,
default_fields,
execute_batch_export_insert_activity,
+ finish_batch_export_run,
get_data_interval,
- get_rows_count,
iter_records,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.metrics import (
get_bytes_exported_metric,
@@ -110,6 +115,7 @@ class SnowflakeInsertInputs:
exclude_events: list[str] | None = None
include_events: list[str] | None = None
batch_export_schema: BatchExportSchema | None = None
+ run_id: str | None = None
def use_namespace(connection: SnowflakeConnection, database: str, schema: str) -> None:
@@ -390,16 +396,19 @@ async def copy_loaded_files_to_snowflake_table(
@activity.defn
-async def insert_into_snowflake_activity(inputs: SnowflakeInsertInputs) -> int:
+async def insert_into_snowflake_activity(inputs: SnowflakeInsertInputs) -> RecordsCompleted:
"""Activity streams data from ClickHouse to Snowflake.
TODO: We're using JSON here, it's not the most efficient way to do this.
"""
logger = await bind_temporal_worker_logger(team_id=inputs.team_id, destination="Snowflake")
logger.info(
- "Exporting batch %s - %s",
+ "Batch exporting range %s - %s to Snowflake: %s.%s.%s",
inputs.data_interval_start,
inputs.data_interval_end,
+ inputs.database,
+ inputs.schema,
+ inputs.table_name,
)
should_resume, details = await should_resume_from_activity_heartbeat(activity, SnowflakeHeartbeatDetails, logger)
@@ -417,25 +426,6 @@ async def insert_into_snowflake_activity(inputs: SnowflakeInsertInputs) -> int:
if not await client.is_alive():
raise ConnectionError("Cannot establish connection to ClickHouse")
- count = await get_rows_count(
- client=client,
- team_id=inputs.team_id,
- interval_start=data_interval_start,
- interval_end=inputs.data_interval_end,
- exclude_events=inputs.exclude_events,
- include_events=inputs.include_events,
- )
-
- if count == 0:
- logger.info(
- "Nothing to export in batch %s - %s",
- inputs.data_interval_start,
- inputs.data_interval_end,
- )
- return 0
-
- logger.info("BatchExporting %s rows", count)
-
rows_exported = get_rows_exported_metric()
bytes_exported = get_bytes_exported_metric()
@@ -469,7 +459,7 @@ async def flush_to_snowflake(
record_iterator = iter_records(
client=client,
team_id=inputs.team_id,
- interval_start=inputs.data_interval_start,
+ interval_start=data_interval_start,
interval_end=inputs.data_interval_end,
exclude_events=inputs.exclude_events,
include_events=inputs.include_events,
@@ -579,15 +569,17 @@ async def run(self, inputs: SnowflakeBatchExportInputs):
"""Workflow implementation to export data to Snowflake table."""
data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end)
- create_export_run_inputs = CreateBatchExportRunInputs(
+ start_batch_export_run_inputs = StartBatchExportRunInputs(
team_id=inputs.team_id,
batch_export_id=inputs.batch_export_id,
data_interval_start=data_interval_start.isoformat(),
data_interval_end=data_interval_end.isoformat(),
+ exclude_events=inputs.exclude_events,
+ include_events=inputs.include_events,
)
- run_id = await workflow.execute_activity(
- create_export_run,
- create_export_run_inputs,
+ run_id, records_total_count = await workflow.execute_activity(
+ start_batch_export_run,
+ start_batch_export_run_inputs,
start_to_close_timeout=dt.timedelta(minutes=5),
retry_policy=RetryPolicy(
initial_interval=dt.timedelta(seconds=10),
@@ -597,12 +589,26 @@ async def run(self, inputs: SnowflakeBatchExportInputs):
),
)
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=run_id,
status=BatchExportRun.Status.COMPLETED,
team_id=inputs.team_id,
)
+ if records_total_count == 0:
+ await workflow.execute_activity(
+ finish_batch_export_run,
+ finish_inputs,
+ start_to_close_timeout=dt.timedelta(minutes=5),
+ retry_policy=RetryPolicy(
+ initial_interval=dt.timedelta(seconds=10),
+ maximum_interval=dt.timedelta(seconds=60),
+ maximum_attempts=0,
+ non_retryable_error_types=["NotNullViolation", "IntegrityError"],
+ ),
+ )
+ return
+
insert_inputs = SnowflakeInsertInputs(
team_id=inputs.team_id,
user=inputs.user,
@@ -618,6 +624,7 @@ async def run(self, inputs: SnowflakeBatchExportInputs):
exclude_events=inputs.exclude_events,
include_events=inputs.include_events,
batch_export_schema=inputs.batch_export_schema,
+ run_id=run_id,
)
await execute_batch_export_insert_activity(
@@ -632,5 +639,5 @@ async def run(self, inputs: SnowflakeBatchExportInputs):
# Raised by Snowflake with an incorrect account name.
"ForbiddenError",
],
- update_inputs=update_inputs,
+ finish_inputs=finish_inputs,
)
diff --git a/posthog/temporal/batch_exports/temporary_file.py b/posthog/temporal/batch_exports/temporary_file.py
index f955f45553727..46cfb26b418ca 100644
--- a/posthog/temporal/batch_exports/temporary_file.py
+++ b/posthog/temporal/batch_exports/temporary_file.py
@@ -1,4 +1,5 @@
"""This module contains a temporary file to stage data in batch exports."""
+
import abc
import collections.abc
import contextlib
@@ -14,8 +15,25 @@
import pyarrow.parquet as pq
+def replace_broken_unicode(obj):
+ if isinstance(obj, str):
+ return obj.encode("utf-8", "replace").decode("utf-8")
+ elif isinstance(obj, list):
+ return [replace_broken_unicode(item) for item in obj]
+ elif isinstance(obj, dict):
+ return {replace_broken_unicode(key): replace_broken_unicode(value) for key, value in obj.items()}
+ else:
+ return obj
+
+
def json_dumps_bytes(d) -> bytes:
- return orjson.dumps(d, default=str)
+ try:
+ return orjson.dumps(d, default=str)
+ except orjson.JSONEncodeError:
+ # orjson is very strict about invalid unicode. This slow path protects us against
+ # things we've observed in practice, like single surrogate codes, e.g. "\ud83d"
+ cleaned_d = replace_broken_unicode(d)
+ return orjson.dumps(cleaned_d, default=str)
class BatchExportTemporaryFile:
@@ -131,7 +149,13 @@ def write_record_as_bytes(self, record: bytes):
def write_records_to_jsonl(self, records):
"""Write records to a temporary file as JSONL."""
if len(records) == 1:
- jsonl_dump = orjson.dumps(records[0], option=orjson.OPT_APPEND_NEWLINE, default=str)
+ try:
+ jsonl_dump = orjson.dumps(records[0], option=orjson.OPT_APPEND_NEWLINE, default=str)
+ except orjson.JSONEncodeError:
+ # orjson is very strict about invalid unicode. This slow path protects us against
+ # things we've observed in practice, like single surrogate codes, e.g. "\ud83d"
+ cleaned_record = replace_broken_unicode(records[0])
+ jsonl_dump = orjson.dumps(cleaned_record, option=orjson.OPT_APPEND_NEWLINE, default=str)
else:
jsonl_dump = b"\n".join(map(json_dumps_bytes, records))
@@ -405,7 +429,13 @@ def __init__(
def write(self, content: bytes) -> int:
"""Write a single row of JSONL."""
- n = self.batch_export_file.write(orjson.dumps(content, default=str) + b"\n")
+ try:
+ n = self.batch_export_file.write(orjson.dumps(content, default=str) + b"\n")
+ except orjson.JSONEncodeError:
+ # orjson is very strict about invalid unicode. This slow path protects us against
+ # things we've observed in practice, like single surrogate codes, e.g. "\ud83d"
+ cleaned_content = replace_broken_unicode(content)
+ n = self.batch_export_file.write(orjson.dumps(cleaned_content, default=str) + b"\n")
return n
def _write_record_batch(self, record_batch: pa.RecordBatch) -> None:
diff --git a/posthog/temporal/batch_exports/utils.py b/posthog/temporal/batch_exports/utils.py
index bdb2b9001feed..9cd68c60e8b94 100644
--- a/posthog/temporal/batch_exports/utils.py
+++ b/posthog/temporal/batch_exports/utils.py
@@ -1,5 +1,10 @@
+import asyncio
import collections.abc
import typing
+import uuid
+
+from posthog.batch_exports.models import BatchExportRun
+from posthog.batch_exports.service import update_batch_export_run
T = typing.TypeVar("T")
@@ -24,3 +29,33 @@ def rewind_gen() -> collections.abc.Generator[T, None, None]:
yield i
return (first, rewind_gen())
+
+
+async def try_set_batch_export_run_to_running(run_id: str | None, logger, timeout: float = 10.0) -> None:
+ """Try to set a batch export run to 'RUNNING' status, but do nothing if we fail or if 'run_id' is 'None'.
+
+ This is intended to be used within a batch export's 'insert_*' activity. These activities cannot afford
+ to fail if our database is experiencing issues, as we should strive to not let issues in our infrastructure
+ propagate to users. So, we do a best effort update and swallow the exception if we fail.
+
+ Even if we fail to update the status here, the 'finish_batch_export_run' activity at the end of each batch
+ export will retry indefinitely and wait for postgres to recover, eventually making a final update with
+ the status. This means that, worse case, the batch export status won't be displayed as 'RUNNING' while running.
+ """
+ if run_id is None:
+ return
+
+ try:
+ await asyncio.wait_for(
+ asyncio.to_thread(
+ update_batch_export_run,
+ uuid.UUID(run_id),
+ status=BatchExportRun.Status.RUNNING,
+ ),
+ timeout=timeout,
+ )
+ except Exception as e:
+ logger.warn(
+ "Unexpected error trying to set batch export to 'RUNNING' status. Run will continue but displayed status may not be accurate until run finishes",
+ exc_info=e,
+ )
diff --git a/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py
index b2c46f6344dbc..3652c1caf19aa 100644
--- a/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py
+++ b/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py
@@ -21,9 +21,9 @@
from posthog.batch_exports.service import BatchExportSchema, BigQueryBatchExportInputs
from posthog.temporal.batch_exports.batch_exports import (
- create_export_run,
+ finish_batch_export_run,
iter_records,
- update_export_run_status,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.bigquery_batch_export import (
BigQueryBatchExportWorkflow,
@@ -33,6 +33,7 @@
insert_into_bigquery_activity,
)
from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.tests.batch_exports.utils import mocked_start_batch_export_run
from posthog.temporal.tests.utils.events import generate_test_events_in_clickhouse
from posthog.temporal.tests.utils.models import (
acreate_batch_export,
@@ -433,9 +434,9 @@ async def test_bigquery_export_workflow(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[BigQueryBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_bigquery_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -454,6 +455,7 @@ async def test_bigquery_export_workflow(
run = runs[0]
assert run.status == "Completed"
assert run.records_completed == 100
+ assert run.records_total_count == 100
ingested_timestamp = frozen_time().replace(tzinfo=dt.timezone.utc)
assert_clickhouse_records_in_bigquery(
@@ -495,9 +497,9 @@ async def insert_into_bigquery_activity_mocked(_: BigQueryInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[BigQueryBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_bigquery_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -546,9 +548,9 @@ class RefreshError(Exception):
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[BigQueryBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_bigquery_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -567,7 +569,8 @@ class RefreshError(Exception):
run = runs[0]
assert run.status == "Failed"
assert run.latest_error == "RefreshError: A useful error message"
- assert run.records_completed == 0
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_bigquery_export_workflow_handles_cancellation(ateam, bigquery_batch_export, interval):
@@ -595,9 +598,9 @@ async def never_finish_activity(_: BigQueryInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[BigQueryBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
never_finish_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
diff --git a/posthog/temporal/tests/batch_exports/test_http_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_http_batch_export_workflow.py
index 6267577472125..451e3e03c4484 100644
--- a/posthog/temporal/tests/batch_exports/test_http_batch_export_workflow.py
+++ b/posthog/temporal/tests/batch_exports/test_http_batch_export_workflow.py
@@ -16,9 +16,9 @@
from temporalio.worker import UnsandboxedWorkflowRunner, Worker
from posthog.temporal.batch_exports.batch_exports import (
- create_export_run,
+ finish_batch_export_run,
iter_records,
- update_export_run_status,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.http_batch_export import (
HeartbeatDetails,
@@ -31,6 +31,7 @@
insert_into_http_activity,
)
from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.tests.batch_exports.utils import mocked_start_batch_export_run
from posthog.temporal.tests.utils.events import generate_test_events_in_clickhouse
from posthog.temporal.tests.utils.models import (
acreate_batch_export,
@@ -345,9 +346,9 @@ async def test_http_export_workflow(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[HttpBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_http_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -405,9 +406,9 @@ async def insert_into_http_activity_mocked(_: HttpInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[HttpBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_http_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -426,7 +427,8 @@ async def insert_into_http_activity_mocked(_: HttpInsertInputs) -> str:
run = runs[0]
assert run.status == "FailedRetryable"
assert run.latest_error == "ValueError: A useful error message"
- assert run.records_completed == 0
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_http_export_workflow_handles_insert_activity_non_retryable_errors(ateam, http_batch_export, interval):
@@ -455,9 +457,9 @@ class NonRetryableResponseError(Exception):
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[HttpBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_http_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -476,6 +478,8 @@ class NonRetryableResponseError(Exception):
run = runs[0]
assert run.status == "Failed"
assert run.latest_error == "NonRetryableResponseError: A useful error message"
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_http_export_workflow_handles_cancellation(ateam, http_batch_export, interval):
@@ -503,9 +507,9 @@ async def never_finish_activity(_: HttpInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[HttpBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
never_finish_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
diff --git a/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py
index c486cc2747fcc..d63e04a7812d7 100644
--- a/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py
+++ b/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py
@@ -1,8 +1,8 @@
import asyncio
import datetime as dt
import json
+import uuid
from random import randint
-from uuid import uuid4
import psycopg
import pytest
@@ -18,9 +18,9 @@
from posthog.batch_exports.service import BatchExportSchema
from posthog.temporal.batch_exports.batch_exports import (
- create_export_run,
+ finish_batch_export_run,
iter_records,
- update_export_run_status,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.postgres_batch_export import (
PostgresBatchExportInputs,
@@ -30,6 +30,7 @@
postgres_default_fields,
)
from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.tests.batch_exports.utils import mocked_start_batch_export_run
from posthog.temporal.tests.utils.events import generate_test_events_in_clickhouse
from posthog.temporal.tests.utils.models import (
acreate_batch_export,
@@ -348,7 +349,7 @@ async def test_postgres_export_workflow(
event_name=event_name,
)
- workflow_id = str(uuid4())
+ workflow_id = str(uuid.uuid4())
inputs = PostgresBatchExportInputs(
team_id=ateam.pk,
batch_export_id=str(postgres_batch_export.id),
@@ -364,9 +365,9 @@ async def test_postgres_export_workflow(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[PostgresBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_postgres_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -386,6 +387,7 @@ async def test_postgres_export_workflow(
run = runs[0]
assert run.status == "Completed"
assert run.records_completed == 100
+ assert run.records_total_count == 100
await assert_clickhouse_records_in_postgres(
postgres_connection=postgres_connection,
@@ -404,7 +406,7 @@ async def test_postgres_export_workflow_handles_insert_activity_errors(ateam, po
"""Test that Postgres Export Workflow can gracefully handle errors when inserting Postgres data."""
data_interval_end = dt.datetime.fromisoformat("2023-04-25T14:30:00.000000+00:00")
- workflow_id = str(uuid4())
+ workflow_id = str(uuid.uuid4())
inputs = PostgresBatchExportInputs(
team_id=ateam.pk,
batch_export_id=str(postgres_batch_export.id),
@@ -423,9 +425,9 @@ async def insert_into_postgres_activity_mocked(_: PostgresInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[PostgresBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_postgres_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -444,6 +446,8 @@ async def insert_into_postgres_activity_mocked(_: PostgresInsertInputs) -> str:
run = runs[0]
assert run.status == "FailedRetryable"
assert run.latest_error == "ValueError: A useful error message"
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_postgres_export_workflow_handles_insert_activity_non_retryable_errors(
@@ -452,7 +456,7 @@ async def test_postgres_export_workflow_handles_insert_activity_non_retryable_er
"""Test that Postgres Export Workflow can gracefully handle non-retryable errors when inserting Postgres data."""
data_interval_end = dt.datetime.fromisoformat("2023-04-25T14:30:00.000000+00:00")
- workflow_id = str(uuid4())
+ workflow_id = str(uuid.uuid4())
inputs = PostgresBatchExportInputs(
team_id=ateam.pk,
batch_export_id=str(postgres_batch_export.id),
@@ -474,9 +478,9 @@ class InsufficientPrivilege(Exception):
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[PostgresBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_postgres_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -495,14 +499,15 @@ class InsufficientPrivilege(Exception):
run = runs[0]
assert run.status == "Failed"
assert run.latest_error == "InsufficientPrivilege: A useful error message"
- assert run.records_completed == 0
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_postgres_export_workflow_handles_cancellation(ateam, postgres_batch_export, interval):
"""Test that Postgres Export Workflow can gracefully handle cancellations when inserting Postgres data."""
data_interval_end = dt.datetime.fromisoformat("2023-04-25T14:30:00.000000+00:00")
- workflow_id = str(uuid4())
+ workflow_id = str(uuid.uuid4())
inputs = PostgresBatchExportInputs(
team_id=ateam.pk,
batch_export_id=str(postgres_batch_export.id),
@@ -523,9 +528,9 @@ async def never_finish_activity(_: PostgresInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[PostgresBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
never_finish_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -548,3 +553,5 @@ async def never_finish_activity(_: PostgresInsertInputs) -> str:
run = runs[0]
assert run.status == "Cancelled"
assert run.latest_error == "Cancelled"
+ assert run.records_completed is None
+ assert run.records_total_count == 1
diff --git a/posthog/temporal/tests/batch_exports/test_redshift_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_redshift_batch_export_workflow.py
index 173bed3a69bb3..eb454a7be3a4a 100644
--- a/posthog/temporal/tests/batch_exports/test_redshift_batch_export_workflow.py
+++ b/posthog/temporal/tests/batch_exports/test_redshift_batch_export_workflow.py
@@ -20,9 +20,9 @@
from posthog.batch_exports.service import BatchExportSchema
from posthog.temporal.batch_exports.batch_exports import (
- create_export_run,
+ finish_batch_export_run,
iter_records,
- update_export_run_status,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.redshift_batch_export import (
RedshiftBatchExportInputs,
@@ -33,6 +33,7 @@
remove_escaped_whitespace_recursive,
)
from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.tests.batch_exports.utils import mocked_start_batch_export_run
from posthog.temporal.tests.utils.events import generate_test_events_in_clickhouse
from posthog.temporal.tests.utils.models import (
acreate_batch_export,
@@ -412,9 +413,9 @@ async def test_redshift_export_workflow(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[RedshiftBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_redshift_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -488,9 +489,9 @@ async def insert_into_redshift_activity_mocked(_: RedshiftInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[RedshiftBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_redshift_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -509,6 +510,8 @@ async def insert_into_redshift_activity_mocked(_: RedshiftInsertInputs) -> str:
run = runs[0]
assert run.status == "FailedRetryable"
assert run.latest_error == "ValueError: A useful error message"
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_redshift_export_workflow_handles_insert_activity_non_retryable_errors(
@@ -539,9 +542,9 @@ class InsufficientPrivilege(Exception):
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[RedshiftBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_redshift_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -560,4 +563,5 @@ class InsufficientPrivilege(Exception):
run = runs[0]
assert run.status == "Failed"
assert run.latest_error == "InsufficientPrivilege: A useful error message"
- assert run.records_completed == 0
+ assert run.records_completed is None
+ assert run.records_total_count == 1
diff --git a/posthog/temporal/tests/batch_exports/test_run_updates.py b/posthog/temporal/tests/batch_exports/test_run_updates.py
index fc03d26cbda0a..7269b3455d8f1 100644
--- a/posthog/temporal/tests/batch_exports/test_run_updates.py
+++ b/posthog/temporal/tests/batch_exports/test_run_updates.py
@@ -11,10 +11,10 @@
Team,
)
from posthog.temporal.batch_exports.batch_exports import (
- CreateBatchExportRunInputs,
- UpdateBatchExportRunStatusInputs,
- create_export_run,
- update_export_run_status,
+ FinishBatchExportRunInputs,
+ StartBatchExportRunInputs,
+ finish_batch_export_run,
+ start_batch_export_run,
)
@@ -74,58 +74,64 @@ def batch_export(destination, team):
@pytest.mark.django_db(transaction=True)
@pytest.mark.asyncio
-async def test_create_export_run(activity_environment, team, batch_export):
- """Test the create_export_run activity.
+async def test_start_batch_export_run(activity_environment, team, batch_export):
+ """Test the 'start_batch_export_run' activity.
- We check if an BatchExportRun is created after the activity runs.
+ We check if a 'BatchExportRun' is created after the activity runs.
"""
start = dt.datetime(2023, 4, 24, tzinfo=dt.timezone.utc)
end = dt.datetime(2023, 4, 25, tzinfo=dt.timezone.utc)
- inputs = CreateBatchExportRunInputs(
+ inputs = StartBatchExportRunInputs(
team_id=team.id,
batch_export_id=str(batch_export.id),
data_interval_start=start.isoformat(),
data_interval_end=end.isoformat(),
)
- run_id = await activity_environment.run(create_export_run, inputs)
+ run_id, records_total_count = await activity_environment.run(start_batch_export_run, inputs)
runs = BatchExportRun.objects.filter(id=run_id)
assert await sync_to_async(runs.exists)() # type:ignore
run = await sync_to_async(runs.first)() # type:ignore
+ assert run is not None
assert run.data_interval_start == start
assert run.data_interval_end == end
+ assert run.records_total_count == records_total_count
@pytest.mark.django_db(transaction=True)
@pytest.mark.asyncio
-async def test_update_export_run_status(activity_environment, team, batch_export):
+async def test_finish_batch_export_run(activity_environment, team, batch_export):
"""Test the export_run_status activity."""
start = dt.datetime(2023, 4, 24, tzinfo=dt.timezone.utc)
end = dt.datetime(2023, 4, 25, tzinfo=dt.timezone.utc)
- inputs = CreateBatchExportRunInputs(
+ inputs = StartBatchExportRunInputs(
team_id=team.id,
batch_export_id=str(batch_export.id),
data_interval_start=start.isoformat(),
data_interval_end=end.isoformat(),
)
- run_id = await activity_environment.run(create_export_run, inputs)
+ run_id, records_total_count = await activity_environment.run(start_batch_export_run, inputs)
runs = BatchExportRun.objects.filter(id=run_id)
run = await sync_to_async(runs.first)() # type:ignore
+ assert run is not None
assert run.status == "Starting"
+ assert run.records_total_count == records_total_count
- update_inputs = UpdateBatchExportRunStatusInputs(
+ finish_inputs = FinishBatchExportRunInputs(
id=str(run_id),
status="Completed",
team_id=inputs.team_id,
)
- await activity_environment.run(update_export_run_status, update_inputs)
+ await activity_environment.run(finish_batch_export_run, finish_inputs)
runs = BatchExportRun.objects.filter(id=run_id)
run = await sync_to_async(runs.first)() # type:ignore
+ assert run is not None
assert run.status == "Completed"
+ assert run.records_total_count == records_total_count
diff --git a/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py
index e6583d049e2a8..a58fb54d67901 100644
--- a/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py
+++ b/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py
@@ -24,9 +24,9 @@
from posthog.batch_exports.service import BatchExportSchema
from posthog.temporal.batch_exports.batch_exports import (
- create_export_run,
+ finish_batch_export_run,
iter_records,
- update_export_run_status,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.s3_batch_export import (
FILE_FORMAT_EXTENSIONS,
@@ -39,6 +39,7 @@
s3_default_fields,
)
from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.tests.batch_exports.utils import mocked_start_batch_export_run
from posthog.temporal.tests.utils.events import (
generate_test_events_in_clickhouse,
)
@@ -411,9 +412,9 @@ async def test_insert_into_s3_activity_puts_data_into_s3(
with override_settings(
BATCH_EXPORT_S3_UPLOAD_CHUNK_SIZE_BYTES=5 * 1024**2
): # 5MB, the minimum for Multipart uploads
- records_total = await activity_environment.run(insert_into_s3_activity, insert_inputs)
+ records_exported = await activity_environment.run(insert_into_s3_activity, insert_inputs)
- assert records_total == 10005
+ assert records_exported == 10005
await assert_clickhouse_records_in_s3(
s3_compatible_client=minio_client,
@@ -550,9 +551,9 @@ async def test_s3_export_workflow_with_minio_bucket(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_s3_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -690,9 +691,9 @@ async def test_s3_export_workflow_with_s3_bucket(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_s3_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -774,9 +775,9 @@ async def test_s3_export_workflow_with_minio_bucket_and_a_lot_of_data(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_s3_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -849,9 +850,9 @@ async def test_s3_export_workflow_defaults_to_timestamp_on_null_inserted_at(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_s3_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -870,6 +871,7 @@ async def test_s3_export_workflow_defaults_to_timestamp_on_null_inserted_at(
run = runs[0]
assert run.status == "Completed"
assert run.records_completed == 100
+ assert run.records_total_count == 100
await assert_clickhouse_records_in_s3(
s3_compatible_client=minio_client,
@@ -934,9 +936,9 @@ async def test_s3_export_workflow_with_minio_bucket_and_custom_key_prefix(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_s3_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -955,6 +957,7 @@ async def test_s3_export_workflow_with_minio_bucket_and_custom_key_prefix(
run = runs[0]
assert run.status == "Completed"
assert run.records_completed == 100
+ assert run.records_total_count == 100
expected_key_prefix = s3_key_prefix.format(
table="events",
@@ -1009,9 +1012,9 @@ async def insert_into_s3_activity_mocked(_: S3InsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_s3_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -1030,7 +1033,8 @@ async def insert_into_s3_activity_mocked(_: S3InsertInputs) -> str:
run = runs[0]
assert run.status == "FailedRetryable"
assert run.latest_error == "ValueError: A useful error message"
- assert run.records_completed == 0
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_s3_export_workflow_handles_insert_activity_non_retryable_errors(ateam, s3_batch_export, interval):
@@ -1062,9 +1066,9 @@ class ParamValidationError(Exception):
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_s3_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -1114,9 +1118,9 @@ async def never_finish_activity(_: S3InsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[S3BatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
never_finish_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -1142,11 +1146,7 @@ async def never_finish_activity(_: S3InsertInputs) -> str:
# We don't care about these for the next test, just need something to be defined.
-base_inputs = {
- "bucket_name": "test",
- "region": "test",
- "team_id": 1,
-}
+base_inputs = {"bucket_name": "test", "region": "test", "team_id": 1}
@pytest.mark.parametrize(
diff --git a/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py
index f8c12a3d1369f..fffbb50534530 100644
--- a/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py
+++ b/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py
@@ -26,9 +26,9 @@
from posthog.batch_exports.service import BatchExportSchema
from posthog.temporal.batch_exports.batch_exports import (
- create_export_run,
+ finish_batch_export_run,
iter_records,
- update_export_run_status,
+ start_batch_export_run,
)
from posthog.temporal.batch_exports.snowflake_batch_export import (
SnowflakeBatchExportInputs,
@@ -39,6 +39,7 @@
snowflake_default_fields,
)
from posthog.temporal.common.clickhouse import ClickHouseClient
+from posthog.temporal.tests.batch_exports.utils import mocked_start_batch_export_run
from posthog.temporal.tests.utils.events import generate_test_events_in_clickhouse
from posthog.temporal.tests.utils.models import (
acreate_batch_export,
@@ -407,9 +408,9 @@ async def test_snowflake_export_workflow_exports_events(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -475,9 +476,9 @@ async def test_snowflake_export_workflow_without_events(ateam, snowflake_batch_e
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -558,9 +559,9 @@ async def test_snowflake_export_workflow_raises_error_on_put_fail(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -624,9 +625,9 @@ async def test_snowflake_export_workflow_raises_error_on_copy_fail(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -675,9 +676,9 @@ async def insert_into_snowflake_activity_mocked(_: SnowflakeInsertInputs) -> str
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_snowflake_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -696,7 +697,8 @@ async def insert_into_snowflake_activity_mocked(_: SnowflakeInsertInputs) -> str
run = runs[0]
assert run.status == "FailedRetryable"
assert run.latest_error == "ValueError: A useful error message"
- assert run.records_completed == 0
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_snowflake_export_workflow_handles_insert_activity_non_retryable_errors(ateam, snowflake_batch_export):
@@ -722,9 +724,9 @@ class ForbiddenError(Exception):
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
insert_into_snowflake_activity_mocked,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -743,6 +745,8 @@ class ForbiddenError(Exception):
run = runs[0]
assert run.status == "Failed"
assert run.latest_error == "ForbiddenError: A useful error message"
+ assert run.records_completed is None
+ assert run.records_total_count == 1
async def test_snowflake_export_workflow_handles_cancellation_mocked(ateam, snowflake_batch_export):
@@ -770,9 +774,9 @@ async def never_finish_activity(_: SnowflakeInsertInputs) -> str:
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ mocked_start_batch_export_run,
never_finish_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -1087,9 +1091,9 @@ async def test_snowflake_export_workflow(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -1172,9 +1176,9 @@ async def test_snowflake_export_workflow_with_many_files(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
@@ -1242,9 +1246,9 @@ async def test_snowflake_export_workflow_handles_cancellation(
task_queue=settings.TEMPORAL_TASK_QUEUE,
workflows=[SnowflakeBatchExportWorkflow],
activities=[
- create_export_run,
+ start_batch_export_run,
insert_into_snowflake_activity,
- update_export_run_status,
+ finish_batch_export_run,
],
workflow_runner=UnsandboxedWorkflowRunner(),
):
diff --git a/posthog/temporal/tests/batch_exports/test_temporary_file.py b/posthog/temporal/tests/batch_exports/test_temporary_file.py
index 4fd7e69c0c12f..8995486ec90e4 100644
--- a/posthog/temporal/tests/batch_exports/test_temporary_file.py
+++ b/posthog/temporal/tests/batch_exports/test_temporary_file.py
@@ -88,6 +88,15 @@ def test_batch_export_temporary_file_write_records_to_jsonl(records):
assert be_file.records_since_last_reset == 0
+def test_batch_export_temporary_file_write_records_to_jsonl_invalid_unicode():
+ with BatchExportTemporaryFile() as be_file:
+ be_file.write_records_to_jsonl(["hello\ud83dworld"])
+
+ be_file.seek(0)
+ # Invalid single surrogate is replaced with a question mark.
+ assert json.loads(be_file.readlines()[0]) == "hello?world"
+
+
@pytest.mark.parametrize(
"records",
TEST_RECORDS,
diff --git a/posthog/temporal/tests/batch_exports/utils.py b/posthog/temporal/tests/batch_exports/utils.py
new file mode 100644
index 0000000000000..7c7140983bc7f
--- /dev/null
+++ b/posthog/temporal/tests/batch_exports/utils.py
@@ -0,0 +1,22 @@
+import uuid
+
+from asgiref.sync import sync_to_async
+from temporalio import activity
+
+from posthog.batch_exports.models import BatchExportRun
+from posthog.batch_exports.service import create_batch_export_run
+from posthog.temporal.batch_exports.batch_exports import StartBatchExportRunInputs
+
+
+@activity.defn(name="start_batch_export_run")
+async def mocked_start_batch_export_run(inputs: StartBatchExportRunInputs) -> tuple[str, int]:
+ """Create a run and return some count >0 to avoid early return."""
+ run = await sync_to_async(create_batch_export_run)(
+ batch_export_id=uuid.UUID(inputs.batch_export_id),
+ data_interval_start=inputs.data_interval_start,
+ data_interval_end=inputs.data_interval_end,
+ status=BatchExportRun.Status.STARTING,
+ records_total_count=1,
+ )
+
+ return str(run.id), 1
diff --git a/requirements.in b/requirements.in
index 800abfa76f036..e108c9bc6e8c2 100644
--- a/requirements.in
+++ b/requirements.in
@@ -101,5 +101,5 @@ phonenumberslite==8.13.6
openai==1.10.0
tiktoken==0.6.0
nh3==0.2.14
-hogql-parser==1.0.3
+hogql-parser==1.0.4
urllib3[secure,socks]==1.26.18
diff --git a/requirements.txt b/requirements.txt
index a08984a29ff22..9d40bf3f4bc26 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -291,7 +291,7 @@ h11==0.13.0
# wsproto
hexbytes==1.0.0
# via dlt
-hogql-parser==1.0.3
+hogql-parser==1.0.4
# via -r requirements.in
httpcore==1.0.2
# via httpx