@graphenedata/cli 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.ts +6 -1
- package/dist/cli/cli.js +155 -143
- package/dist/docs/agent-instructions.md +18 -0
- package/dist/docs/graphene.md +310 -182
- package/dist/ui/app.css +8 -10
- package/dist/ui/internal/NavSidebar.svelte +24 -8
- package/dist/ui/internal/NavSidebarHMR.svelte +8 -0
- package/dist/ui/internal/queryEngine.ts +4 -2
- package/dist/ui/web.js +1 -1
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -58,12 +58,12 @@ function walkExpression(root, fn, parent = null) {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
async function pollFor(fn, timeoutMs,
|
|
61
|
+
async function pollFor(fn, timeoutMs, interval2) {
|
|
62
62
|
let end = Date.now() + timeoutMs;
|
|
63
63
|
while (Date.now() < end) {
|
|
64
64
|
let res = fn();
|
|
65
65
|
if (res) return res;
|
|
66
|
-
await new Promise((r) => setTimeout(r,
|
|
66
|
+
await new Promise((r) => setTimeout(r, interval2));
|
|
67
67
|
}
|
|
68
68
|
return null;
|
|
69
69
|
}
|
|
@@ -175,21 +175,18 @@ var init_config = __esm({
|
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
// ../lang/functionDefs.ts
|
|
178
|
-
import { DUCKDB_DIALECT_FUNCTIONS, GlobalNameSpace, DialectNameSpace, getDialect } from "@graphenedata/malloy";
|
|
178
|
+
import { DUCKDB_DIALECT_FUNCTIONS, GlobalNameSpace, DialectNameSpace, getDialect, registerDialect, StandardSQLDialect, expandBlueprintMap } from "@graphenedata/malloy";
|
|
179
179
|
function findOverloads(name, dialect) {
|
|
180
180
|
if (!dialectNamespaces.has(dialect)) {
|
|
181
|
-
|
|
182
|
-
dialectNamespaces.set(dialect, new DialectNameSpace(d));
|
|
181
|
+
dialectNamespaces.set(dialect, new DialectNameSpace(getDialect(dialect)));
|
|
183
182
|
}
|
|
184
183
|
let res = dialectNamespaces.get(dialect).getEntry(name) || globalNamespace.getEntry(name);
|
|
185
184
|
return res?.entry ? res.entry.overloads : [];
|
|
186
185
|
}
|
|
187
|
-
var globalNamespace, dialectNamespaces
|
|
186
|
+
var BIGQUERY_DIALECT_FUNCTIONS, BigQueryDialect, globalNamespace, dialectNamespaces;
|
|
188
187
|
var init_functionDefs = __esm({
|
|
189
188
|
"../lang/functionDefs.ts"() {
|
|
190
189
|
"use strict";
|
|
191
|
-
globalNamespace = new GlobalNameSpace();
|
|
192
|
-
dialectNamespaces = /* @__PURE__ */ new Map();
|
|
193
190
|
Object.assign(DUCKDB_DIALECT_FUNCTIONS, {
|
|
194
191
|
"count_if": {
|
|
195
192
|
takes: { "value": "boolean" },
|
|
@@ -243,7 +240,11 @@ var init_functionDefs = __esm({
|
|
|
243
240
|
}
|
|
244
241
|
});
|
|
245
242
|
BIGQUERY_DIALECT_FUNCTIONS = {
|
|
246
|
-
"
|
|
243
|
+
"countif": {
|
|
244
|
+
takes: { "value": "boolean" },
|
|
245
|
+
returns: { measure: "number" },
|
|
246
|
+
impl: { function: "COUNTIF" }
|
|
247
|
+
},
|
|
247
248
|
"if": { ...DUCKDB_DIALECT_FUNCTIONS["if"] },
|
|
248
249
|
"safe_divide": {
|
|
249
250
|
takes: { "numerator": "number", "denominator": "number" },
|
|
@@ -315,6 +316,18 @@ var init_functionDefs = __esm({
|
|
|
315
316
|
}
|
|
316
317
|
}
|
|
317
318
|
};
|
|
319
|
+
BigQueryDialect = class extends StandardSQLDialect {
|
|
320
|
+
constructor() {
|
|
321
|
+
super();
|
|
322
|
+
this.name = "bigquery";
|
|
323
|
+
}
|
|
324
|
+
getDialectFunctions() {
|
|
325
|
+
return expandBlueprintMap(BIGQUERY_DIALECT_FUNCTIONS);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
registerDialect(new BigQueryDialect());
|
|
329
|
+
globalNamespace = new GlobalNameSpace();
|
|
330
|
+
dialectNamespaces = /* @__PURE__ */ new Map();
|
|
318
331
|
}
|
|
319
332
|
});
|
|
320
333
|
|
|
@@ -469,29 +482,6 @@ function parseTemporalLiteral(value, expected) {
|
|
|
469
482
|
}
|
|
470
483
|
return null;
|
|
471
484
|
}
|
|
472
|
-
function parseTemporal(node) {
|
|
473
|
-
if (node.node !== "stringLiteral") return null;
|
|
474
|
-
let rawValue = typeof node.literal === "string" ? node.literal.trim() : "";
|
|
475
|
-
if (!rawValue) return null;
|
|
476
|
-
let parsedDate = parseTemporalLiteral(rawValue, "date");
|
|
477
|
-
if (parsedDate) {
|
|
478
|
-
let typeDef = { type: parsedDate.type, timeframe: parsedDate.timeframe };
|
|
479
|
-
Object.assign(node, { node: "timeLiteral", literal: parsedDate.literal, type: parsedDate.type, typeDef });
|
|
480
|
-
return parsedDate.timeframe;
|
|
481
|
-
}
|
|
482
|
-
let parsedTimestamp = parseTemporalLiteral(rawValue, "timestamp");
|
|
483
|
-
if (parsedTimestamp) {
|
|
484
|
-
let typeDef = { type: parsedTimestamp.type, timeframe: parsedTimestamp.timeframe };
|
|
485
|
-
Object.assign(node, { node: "timeLiteral", literal: parsedTimestamp.literal, type: parsedTimestamp.type, typeDef });
|
|
486
|
-
return parsedTimestamp.timeframe;
|
|
487
|
-
}
|
|
488
|
-
let interval = parseIntervalLiteral(rawValue);
|
|
489
|
-
if (interval) {
|
|
490
|
-
Object.assign(node, { node: "numberLiteral", literal: interval.quantity.toString(), type: "interval", intervalUnit: interval.unit });
|
|
491
|
-
return interval.unit;
|
|
492
|
-
}
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
485
|
function parseIntervalLiteral(value) {
|
|
496
486
|
let raw = (value ?? "").trim().toLowerCase().replace(/\s+/g, " ");
|
|
497
487
|
if (!raw) return null;
|
|
@@ -503,6 +493,9 @@ function parseIntervalLiteral(value) {
|
|
|
503
493
|
if (!unit) return null;
|
|
504
494
|
return { quantity, unit };
|
|
505
495
|
}
|
|
496
|
+
function parseIntervalUnit(value) {
|
|
497
|
+
return INTERVAL_UNITS[value.toLowerCase()] || null;
|
|
498
|
+
}
|
|
506
499
|
function buildResult(year, month, day, hour, minute, second, timeframe, expected) {
|
|
507
500
|
if (expected === "date") {
|
|
508
501
|
return { literal: `${pad(year)}-${pad(month)}-${pad(day)}`, timeframe, type: "date" };
|
|
@@ -519,8 +512,8 @@ function inRange(value, min, max) {
|
|
|
519
512
|
function isValidDate(year, month, day) {
|
|
520
513
|
if (!inRange(month, 1, 12)) return false;
|
|
521
514
|
if (!inRange(day, 1, 31)) return false;
|
|
522
|
-
let
|
|
523
|
-
return
|
|
515
|
+
let date2 = new Date(Date.UTC(year, month - 1, day));
|
|
516
|
+
return date2.getUTCFullYear() === year && date2.getUTCMonth() === month - 1 && date2.getUTCDate() === day;
|
|
524
517
|
}
|
|
525
518
|
function pad(value) {
|
|
526
519
|
return value.toString().padStart(2, "0");
|
|
@@ -708,9 +701,11 @@ function findTables(fi) {
|
|
|
708
701
|
let nodes = tn.getChildren("TableStatement").concat(tn.getChildren("ViewStatement"));
|
|
709
702
|
for (let syntaxNode of nodes) {
|
|
710
703
|
let name = txt(syntaxNode.getChild("Ref"));
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
704
|
+
let existing = Object.values(FILE_MAP).find((f) => {
|
|
705
|
+
if (f.path.endsWith(".md") && f.path != fi.path) return;
|
|
706
|
+
return f.tables.find((t) => t.name == name);
|
|
707
|
+
});
|
|
708
|
+
if (existing) diag(syntaxNode.getChild("Ref"), `Table "${name}" is already defined`);
|
|
714
709
|
let table2 = makeTable(name, syntaxNode.getChild("QueryStatement") ? "query_source" : "table");
|
|
715
710
|
table2.metadata = extractLeadingMetadata(syntaxNode);
|
|
716
711
|
syntaxNode.getChildren("ColumnDef").forEach((cn) => addColumnField(table2, cn));
|
|
@@ -939,6 +934,40 @@ function analyzeExpression(expr, scope) {
|
|
|
939
934
|
if (!isExtractUnit(units)) return diag(expr, "Not a valid unit to extract", errExpr2);
|
|
940
935
|
return { node: "extract", type: "number", units, e, isAgg: false };
|
|
941
936
|
}
|
|
937
|
+
case "CastExpression":
|
|
938
|
+
case "TypeCastExpression": {
|
|
939
|
+
let innerExpr = expr.getChild("Expression") || expr.firstChild;
|
|
940
|
+
let e = analyzeExpression(innerExpr, scope);
|
|
941
|
+
let targetTypeStr = txt(expr.getChild("CastType"));
|
|
942
|
+
let type = convertDataType(targetTypeStr);
|
|
943
|
+
if (!type) return diag(expr.getChild("CastType"), `Unsupported cast type: ${targetTypeStr}`, errExpr2);
|
|
944
|
+
return { node: "cast", safe: false, e, dstSQLType: targetTypeStr.toUpperCase(), type, isAgg: e.isAgg };
|
|
945
|
+
}
|
|
946
|
+
case "IntervalExpression": {
|
|
947
|
+
let stringNode = expr.getChild("String");
|
|
948
|
+
if (stringNode) {
|
|
949
|
+
let parsed = parseIntervalLiteral(txt(stringNode).slice(1, -1));
|
|
950
|
+
if (!parsed) return diag(stringNode, "Could not parse interval literal", errExpr2);
|
|
951
|
+
return { node: "numberLiteral", literal: parsed.quantity.toString(), type: "interval", intervalUnit: parsed.unit, isAgg: false };
|
|
952
|
+
} else {
|
|
953
|
+
let numNode = expr.getChild("Number");
|
|
954
|
+
let unitNode = expr.getChild("IntervalUnit");
|
|
955
|
+
let quantity = Number(txt(numNode));
|
|
956
|
+
let unitStr = txt(unitNode).toLowerCase();
|
|
957
|
+
let unit = parseIntervalUnit(unitStr);
|
|
958
|
+
if (!unit) return diag(unitNode, `Invalid interval unit: "${unitStr}"`, errExpr2);
|
|
959
|
+
return { node: "numberLiteral", literal: quantity.toString(), type: "interval", intervalUnit: unit, isAgg: false };
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
case "DateExpression":
|
|
963
|
+
case "TimestampExpression": {
|
|
964
|
+
let expectedType = expr.name === "DateExpression" ? "date" : "timestamp";
|
|
965
|
+
let stringNode = expr.getChild("String");
|
|
966
|
+
let parsed = parseTemporalLiteral(txt(stringNode).slice(1, -1), expectedType);
|
|
967
|
+
if (!parsed) return diag(stringNode, `Could not parse ${expectedType}`, errExpr2);
|
|
968
|
+
let typeDef = { type: parsed.type, timeframe: parsed.timeframe };
|
|
969
|
+
return { node: "timeLiteral", literal: parsed.literal, type: parsed.type, typeDef, isAgg: false };
|
|
970
|
+
}
|
|
942
971
|
case "FunctionCall":
|
|
943
972
|
return analyzeFunctionCall(expr, scope);
|
|
944
973
|
case "Parenthetical":
|
|
@@ -1031,29 +1060,23 @@ function analyzeExpression(expr, scope) {
|
|
|
1031
1060
|
}
|
|
1032
1061
|
function analyzeTimeExpression(op, left2, right2, node) {
|
|
1033
1062
|
if (left2.type !== "date" && left2.type !== "timestamp") return diag(node, "Expected left side to be a date or timestamp", errExpr2);
|
|
1034
|
-
let units = left2.type === "timestamp" ? "second" : "day";
|
|
1035
|
-
if (right2.node == "stringLiteral") {
|
|
1036
|
-
units = parseTemporal(right2);
|
|
1037
|
-
if (right2.node == "stringLiteral") {
|
|
1038
|
-
return diag(node, "Could not parse interval", errExpr2);
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
1063
|
if (right2.type == "date" || right2.type == "timestamp") {
|
|
1042
1064
|
if (op !== "-") return diag(node, "Only subtraction between dates is supported", errExpr2);
|
|
1043
1065
|
if (right2.type !== left2.type) return diag(node, `Expected right side to be a ${left2.type}`, errExpr2);
|
|
1066
|
+
let units = left2.type === "timestamp" ? "second" : "day";
|
|
1044
1067
|
return { node: "timeDiff", kids: { left: left2, right: right2 }, units, type: "interval", isAgg: false };
|
|
1045
1068
|
}
|
|
1046
1069
|
if (right2.type == "interval") {
|
|
1047
1070
|
let typeDef = { type: left2.type };
|
|
1071
|
+
let units = right2.intervalUnit;
|
|
1072
|
+
if (!units) return diag(node, "Interval must have a unit", errExpr2);
|
|
1048
1073
|
return { node: "delta", kids: { base: left2, delta: right2 }, op, units, type: left2.type, typeDef, isAgg: false };
|
|
1049
1074
|
}
|
|
1050
|
-
return diag(node, "Expected right side to be a date or interval", errExpr2);
|
|
1075
|
+
return diag(node, "Expected right side to be a date, timestamp, or interval", errExpr2);
|
|
1051
1076
|
}
|
|
1052
1077
|
function ensureSameType(left2, leftNode, right2, rightNode) {
|
|
1053
1078
|
if (left2.type === "error" || right2.type === "error") return;
|
|
1054
1079
|
if (left2.node === "parameter" || right2.node === "parameter") return;
|
|
1055
|
-
if (isTemporalType(left2.type)) checkTypes(right2, [left2.type], rightNode);
|
|
1056
|
-
if (isTemporalType(right2.type)) checkTypes(left2, [right2.type], leftNode);
|
|
1057
1080
|
if (left2.type !== right2.type) diag(rightNode, `Expected ${left2.type}, got ${right2.type}`);
|
|
1058
1081
|
}
|
|
1059
1082
|
function checkTypes(expr, expected, node) {
|
|
@@ -1061,17 +1084,7 @@ function checkTypes(expr, expected, node) {
|
|
|
1061
1084
|
if (expr.node === "parameter") return;
|
|
1062
1085
|
if (expected.includes(expr.type)) return;
|
|
1063
1086
|
if (expected.includes("generic")) return;
|
|
1064
|
-
|
|
1065
|
-
if (expr.node == "stringLiteral" && dt) {
|
|
1066
|
-
let parsed = parseTemporalLiteral(expr.literal, dt);
|
|
1067
|
-
if (!parsed) return diag(node, `Could not parse ${dt} literal: "${expr.literal}"`, void 0);
|
|
1068
|
-
let typeDef = { type: parsed.type, timeframe: parsed.timeframe };
|
|
1069
|
-
Object.assign(expr, { node: "timeLiteral", literal: parsed?.literal, type: parsed?.type, typeDef });
|
|
1070
|
-
} else if (expr.node == "stringLiteral" && expected.includes("interval")) {
|
|
1071
|
-
let parsed = parseIntervalLiteral(expr.literal);
|
|
1072
|
-
if (!parsed) return diag(node, `Could not parse interval literal: "${expr.literal}"`, void 0);
|
|
1073
|
-
return Object.assign(expr, { node: "numberLiteral", literal: parsed.quantity.toString(), type: "interval", intervalUnit: parsed.unit });
|
|
1074
|
-
} else diag(node, `Expected types: ${expected.join(", ")}`);
|
|
1087
|
+
diag(node, `Expected types: ${expected.join(", ")}`);
|
|
1075
1088
|
}
|
|
1076
1089
|
function lookupField(expr, scope) {
|
|
1077
1090
|
let pathNodes = expr.getChildren("Identifier");
|
|
@@ -1168,6 +1181,8 @@ function convertDataType(dataType) {
|
|
|
1168
1181
|
return "string";
|
|
1169
1182
|
case "INTEGER":
|
|
1170
1183
|
return "number";
|
|
1184
|
+
case "NUMERIC":
|
|
1185
|
+
return "number";
|
|
1171
1186
|
case "FLOAT":
|
|
1172
1187
|
return "number";
|
|
1173
1188
|
case "FLOAT64":
|
|
@@ -1227,40 +1242,43 @@ var init_analyze = __esm({
|
|
|
1227
1242
|
});
|
|
1228
1243
|
|
|
1229
1244
|
// ../lang/parser.terms.js
|
|
1230
|
-
var table, primary_key, join, as, on, or, and, like, not, _in, from, inner, left, right, full, cross, select, where, group, by, order, asc, desc, limit, offset, is, _null, exists, _true, _false;
|
|
1245
|
+
var table, date, timestamp, interval, primary_key, join, as, on, or, and, like, not, _in, from, inner, left, right, full, cross, select, where, group, by, order, asc, desc, limit, offset, is, _null, exists, _true, _false;
|
|
1231
1246
|
var init_parser_terms = __esm({
|
|
1232
1247
|
"../lang/parser.terms.js"() {
|
|
1233
1248
|
"use strict";
|
|
1234
|
-
table =
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1249
|
+
table = 5;
|
|
1250
|
+
date = 10;
|
|
1251
|
+
timestamp = 12;
|
|
1252
|
+
interval = 14;
|
|
1253
|
+
primary_key = 17;
|
|
1254
|
+
join = 21;
|
|
1255
|
+
as = 27;
|
|
1256
|
+
on = 30;
|
|
1257
|
+
or = 39;
|
|
1258
|
+
and = 43;
|
|
1259
|
+
like = 52;
|
|
1260
|
+
not = 54;
|
|
1261
|
+
_in = 64;
|
|
1262
|
+
from = 69;
|
|
1263
|
+
inner = 75;
|
|
1264
|
+
left = 77;
|
|
1265
|
+
right = 79;
|
|
1266
|
+
full = 81;
|
|
1267
|
+
cross = 83;
|
|
1268
|
+
select = 86;
|
|
1269
|
+
where = 93;
|
|
1270
|
+
group = 96;
|
|
1271
|
+
by = 98;
|
|
1272
|
+
order = 104;
|
|
1273
|
+
asc = 108;
|
|
1274
|
+
desc = 110;
|
|
1275
|
+
limit = 113;
|
|
1276
|
+
offset = 115;
|
|
1277
|
+
is = 118;
|
|
1278
|
+
_null = 120;
|
|
1279
|
+
exists = 138;
|
|
1280
|
+
_true = 142;
|
|
1281
|
+
_false = 144;
|
|
1264
1282
|
}
|
|
1265
1283
|
});
|
|
1266
1284
|
|
|
@@ -1304,7 +1322,10 @@ var init_tokens = __esm({
|
|
|
1304
1322
|
offset,
|
|
1305
1323
|
table,
|
|
1306
1324
|
exists,
|
|
1307
|
-
primary_key
|
|
1325
|
+
primary_key,
|
|
1326
|
+
interval,
|
|
1327
|
+
date,
|
|
1328
|
+
timestamp
|
|
1308
1329
|
};
|
|
1309
1330
|
}
|
|
1310
1331
|
});
|
|
@@ -1316,24 +1337,24 @@ var init_parser = __esm({
|
|
|
1316
1337
|
"../lang/parser.js"() {
|
|
1317
1338
|
"use strict";
|
|
1318
1339
|
init_tokens();
|
|
1319
|
-
spec_Identifier = { __proto__: null, table:
|
|
1340
|
+
spec_Identifier = { __proto__: null, table: 10, date: 20, timestamp: 24, interval: 28, primary_key: 34, join: 42, one: 46, many: 50, as: 54, on: 60, or: 78, and: 86, like: 104, not: 108, in: 128, from: 138, inner: 150, left: 154, right: 158, full: 162, cross: 166, select: 172, distinct: 176, where: 186, group: 192, by: 196, having: 202, order: 208, asc: 216, desc: 220, limit: 226, offset: 230, is: 236, null: 240, case: 250, when: 256, then: 260, else: 266, end: 270, exists: 276, true: 284, false: 288, count: 298, extract: 304, cast: 312, extend: 338 };
|
|
1320
1341
|
parser = LRParser.deserialize({
|
|
1321
1342
|
version: 14,
|
|
1322
|
-
states: "
|
|
1323
|
-
stateData: "!
|
|
1324
|
-
goto: "
|
|
1325
|
-
nodeNames: "\u26A0
|
|
1326
|
-
maxTerm:
|
|
1343
|
+
states: "JfQYQPOOOOQO'#C_'#C_OOQO'#Dr'#DrOwQPO'#DqOOQO'#ET'#ETO#aQPO'#ESOOQO'#E['#E[OOQO'#E_'#E_O#hQPO'#E^OOQO'#Ed'#EdOOQO'#Eg'#EgO#hQPO'#EfOOQO'#Ep'#EpO#mQPO'#EoOOQO'#GQ'#GQO$ZQPO'#DpO$hQPO'#C^OOQO'#Fz'#FzO$hQPO'#FyO$mQPO'#F|QYQPOOQ%bQPO'#F|O%gQPO'#EZO%gQPO'#EcO)^QPO'#CbO)hQPO'#CbO)mQPO'#DtO#rQPO'#DvO*zQPO'#DuOOQO'#Gb'#GbO,mQPO,5:]O-aQPO'#CbO.sQPO'#CbOOQO'#Ce'#CeOOQO'#Cg'#CgOOQO'#Ci'#CiO0]QPO'#EXOOQO'#Dc'#DcO1VQPO'#DvOOQO'#EV'#EVOOQO'#EY'#EYOOQO'#EX'#EXO1pQPO,5:nO!PQPO,5:nOOQO'#Ew'#EwOOQO'#Ez'#EzOOQO'#E|'#E|O2eQPO'#E{OOQO'#FZ'#FZO2lQPO'#FYOOQO'#F_'#F_OOQO'#Fa'#FaOOQO'#F^'#F^OOQO'#Fc'#FcOOQO'#Gf'#GfOOQO'#Ff'#FfO2qQPO'#FeOOQO'#Ge'#GeOOQO'#Fi'#FiOOQO'#Fm'#FmO2vQPO'#FoO3OQPO'#FqO3TQPO'#FrOOQO'#Gd'#GdOOQO'#Gg'#GgOOQO'#G`'#G`O%gQPO'#EyO3YQPO'#FhO3_QPO'#FlOOQO'#Ea'#EaO!PQPO,5:xO3dQPO,5;QO3lQPO,5;ZOOQO-E:O-E:OO4aQPO,58xO4iQPO,5<eOOQO,5<h,5<hOOQO-E9z-E9zO4nQPO,5:uO5bQPO,5:}OOQO,5<i,5<iO6UQPO,58|OOQO-E9{-E9{OOQO'#Cv'#CvOOQO'#Cx'#CxOOQO,5:`,5:`O:PQPO,5:`O:UQPO,5:bOOQO,5:a,5:aO:PQPO,5:aOOQO'#Cp'#CpOOQO'#Dx'#DxOOQO'#Dz'#DzOOQO'#D|'#D|OOQO'#EO'#EOOOQO'#EQ'#EQOwQPO'#DwO:ZQPO'#DwOOQO'#GR'#GRO:`QPO1G/wO;SQPO,5<OOOQO,5:t,5:tOOQO'#DS'#DSO;ZQPO,59pOOQO'#DW'#DWOOQO'#Da'#DaOOQO'#DY'#DYO;iQPO,5:WOOQO'#De'#DeOOQO'#Dh'#DhOOQO'#Dm'#DmO;qQPO,5:WOOQO'#Eu'#EuO;vQPO,5;`O%gQPO,59qO%gQPO,59qO%gQPO,59qO%gQPO,59qO%gQPO,59qOOQO,5:s,5:sO:PQPO,5:sO<OQPO,5<`O<VQPO1G0YO<yQPO1G0YO<yQPO1G0YO=nQPO,5;gOOQO'#FP'#FPOOQO'#GU'#GUO=uQPO,5;gO%gQPO'#FOO#rQPO,5;tO>QQPO,5<POOQO,5<Z,5<ZO>_QPO,5<ZOOQO,5<],5<]OOQO,5<^,5<^O>dQPO,5;eOBUQPO,5<SO%gQPO,5<WOB^QPO1G0dOCRQPO'#EiOC|QPO1G0lOOQO'#Er'#ErODqQPO1G0uODvQPO1G.dOFTQPO1G2OOFYQPO1G2PPGgQPO'#F}OOQO1G/z1G/zOOQO1G/|1G/|OOQO1G/{1G/{OGlQPO,5:cOwQPO,5:cOOQO-E:P-E:POHsQPO1G1jOOQO1G1j1G1jOOQO'#DQ'#DQOOQO1G/[1G/[OOQO,59t,59tOH}QPO1G/rO1VQPO1G/rOOQO1G0z1G0zO;yQPO1G0zOLqQPO1G/]OLxQPO1G/]O!!kQPO1G/]O!!uQPO1G/]O!#PQPO1G/]OOQO1G0_1G0_OOQO1G1z1G1zOOQO,5<n,5<nO!&qQPO7+%tOOQO-E:Q-E:QO!'eQPO7+%tO=uQPO1G1ROOQO-E:S-E:SOOQO'#FU'#FUOOQO'#FW'#FWOOQO1G1R1G1RO={QPO1G1RO%gQPO'#FTO!(YQPO,5;jO!(aQPO1G1`O!(fQPO1G1kOOQO1G1k1G1kO!(mQPO1G1kO%gQPO1G1kOOQO'#Fp'#FpOOQO1G1u1G1uOOQO'#Fk'#FkO!(rQPO1G1nO.{QPO1G1rO!(wQPO7+&OO!)kQPO7+&OOOQO'#Ek'#EkOOQO'#Em'#EmOOQO,5;T,5;TO!+QQPO7+&WO!+[QPO7+&WOOQO7+&a7+&aO!,|QPO'#CbO!-^QPO'#CoO$hQPO'#CnO!.pQPO'#C}OOQO'#G_'#G_OOQO'#G^'#G^O!.zQPO'#GOO!0_QPO7+$OO!0fQPO'#C}O#rQPO7+'jO!+cQPO'#CbOOQO'#Gi'#GiO!0kQPO'#GVO!2OQPO7+'kOOQO'#Cy'#CyO%gQPO1G/}O!2VQPO1G/}O!3^QPO7+'UO!3fQPO7+'UOOQO7+'U7+'UO1VQPO7+%^O!3mQPO'#DoO!3wQPO7+%^OOQO7+&f7+&fP!PQPO'#GSO!3|QPO<<I`OOQO7+&m7+&mO={QPO7+&mO!4pQPO,5;oOOQO'#FR'#FRO%gQPO1G1UOOQO7+&z7+&zOOQO7+'V7+'VO!4wQPO7+'VO%gQPO7+'YO;ZQPO7+'^O!5OQPO<<IjOOQO,5<o,5<oO!5rQPO<<IrOOQO-E:R-E:ROOQO'#Cd'#CdO!6jQPO,58}OOQO'#Cr'#CrOOQO'#Ct'#CtOOQO,59Z,59ZO!8QQPO,59YO;ZQPO,59jO;iQPO,5<aO!8YQPO,5<aO;vQPO,5<bO%gQPO,59mO%gQPO,59mO%gQPO,59mO%gQPO,59mO%gQPO,59mO:PQPO,59iOOQO,5<j,5<jOOQO-E9|-E9|OOQO<<Gj<<GjO%gQPO,59iO!8_QPO<<KUOOQO,5<q,5<qOOQO-E:T-E:TOOQO<<KV<<KVO!8dQPO7+%iO%gQPO7+%iOOQO-E9}-E9}O!9jQPO<<JpOOQO<<Jp<<JpO!9qQPO,5<kO!9{QPO<<HxO!:QQPO,5:ZO!:YQPO,5:ZOOQO<<Hx<<HxOOQO<<JX<<JXO!:aQPO7+&pOOQO<<Jq<<JqO!:nQPO<<JtO!:uQPO<<JxP3dQPO'#GTOOQO'#Cl'#ClOOQO'#Ck'#CkOOQO1G.i1G.iO$hQPO1G.tO:PQPO1G.tOOQO1G/U1G/UO!:zQPO1G1{O1VQPO1G1{OOQO1G1|1G1|O;yQPO1G1|O!<^QPO1G/XO!<eQPO1G/XO!=vQPO1G/XO!>QQPO1G/XO!>[QPO1G/XOOQO1G/T1G/TO!?lQPO1G/TOOQOAN@pAN@pO!@xQPO<<ITP%gQPO'#GPOOQOAN@[AN@[OOQOAN>dAN>dO!BOQPO1G/uOOQOAN@`AN@`OOQOAN@dAN@dO!BVQPO'#C{OOQO7+$`7+$`O!8TQPO7+$`O1VQPO7+'gO!B[QPO7+'gOOQO7+'h7+'hO$hQPO,59gO$hQPO<<GzO!BaQPO<<KROOQO<<KR<<KROOQO1G/R1G/ROOQOAN=fAN=fOOQOAN@mAN@m",
|
|
1344
|
+
stateData: "!Bm~O$|OS$}OS~OTPO!gQO!xSO#PUO#SVO#XXO#[YO#e[O$oaO~OShO%PkO~OSoOYqO[rO^sO!WuO!Y}O!Z}O!]xO#^!WO#l|O#q!OO$O!QO$P!WO$S!SO$U!TO$Z!XO$^![O$b!]O$g!aO%PvO~O!zwO~P!PO#U!gO~O#^!jO~O!gQO!xSO#PUO#SVO#XXO#[YO#e[O~O$z!dX%[!dX%V!dX~P#rOShO~O%[!nOT$pX!g$pX!x$pX#P$pX#S$pX#X$pX#[$pX#e$pX$o$pX$z$pX~O%[!nO~OSoOYqO[rO^sO!WuO!Y}O!Z}O#^!WO#l|O#q!OO$O!QO$P!WO$S!SO$U!TO$Z!XO$^![O$b!]O$g!aO%PvO~O%O!rOSUXeUXkUX!gUX!mUX!oUX!qUX!sUX!uUX!xUX#PUX#SUX#XUX#[UX#eUX$zUX%[UX%VUXpUXYUX[UX^UX!WUX!YUX!ZUX#^UX#lUX#qUX$OUX$PUX$SUX$UUX$ZUX$^UX$bUX$gUX%TUX~O%PUXnUX~P&tOS!sO~OS!vOk!uOe!hX!g!hX!m!hX!o!hX!q!hX!s!hX!u!hX!x!hX#P!hX#S!hX#X!hX#[!hX#e!hX$z!hX%[!hX%V!hXn!hX~OS!vOk!uOe!iX!g!iX!m!iX!o!iX!q!iX!s!iX!u!iX!x!iX#P!iX#S!iX#X!iX#[!iX#e!iX$z!iX%[!iX%V!iXn!iX~Oe!|O!m!}O!o#OO!q#PO!s#QO!u#RO~O!g!ea!x!ea#P!ea#S!ea#X!ea#[!ea#e!ea$z!ea%[!ea%V!ea~P,XO%P#WOsUXwUX{UX}UX!OUX!PUX!QUX!RUX!SUX!UUX!]UX!^UX!_UX!bUX#jUX#tUX#vUX#{UX#yUX~P&tOS!sO!]#XO~Ok!uOp#^Os#ZOw#YO{#[O}#^O!O#^O!P#^O!Q#^O!R#^O!S#^O!U#]O!WuO!Y#`O!Z#`O!]#aO!^#aO!_#aO!b#bO#j#dO~OS!vO!g!{X!x!{X#P!{X#S!{X#X!{X#[!{X#e!{X$z!{X%T!{X%[!{X%V!{X~P.{O!gQO!xSO#PUO#SVO#XXO#[YO#e[O~P%gO%T#nO!g!va!x!va#P!va#S!va#X!va#[!va#e!va$z!va%[!va%V!va~O#t#rO~P%gO%P#vO~O%P#wO~O#^#yO$P#xO~O$P#zO~O$P#{O~O%P#}O~O%P$OO~OS$QO#^$QO~O#g$SO!g#ca!x#ca#P#ca#S#ca#X#ca#[#ca#e#ca$z#ca%[#ca%V#ca~Ok!uO%P$UO~O%P$WO~O!g!}a!x!}a#P!}a#S!}a#X!}a#[!}a#e!}a$z!}a%[!}a%V!}a~P/OO!g#Va!x#Va#P#Va#S#Va#X#Va#[#Va#e#Va$z#Va%[#Va%V#Va~P/OO%O!rOSUaeUakUa!gUa!mUa!oUa!qUa!sUa!uUa!xUa#PUa#SUa#XUa#[Ua#eUa$zUa%[UapUasUawUa{Ua}Ua!OUa!PUa!QUa!RUa!SUa!UUa!WUa!YUa!ZUa!]Ua!^Ua!_Ua!bUa#jUa%TUa%PUa%VUa#tUanUa#vUa#{Ua#yUaYUa[Ua^Ua#^Ua#lUa#qUa$OUa$PUa$SUa$UUa$ZUa$^Ua$bUa$gUa~OS!vO~O%V$ZO~Oe!|O~O!g!ei!x!ei#P!ei#S!ei#X!ei#[!ei#e!ei$z!ei%[!ei%V!ei~P,XO%V$aO~P%gOS$bOYqO[rO^sO~O!U#]O!b#bO~O%P$fO~O!WuO#l|O~O%V$oO~P/OO!g!vi!x!vi#P!vi#S!vi#X!vi#[!vi#e!vi$z!vi%[!vi%V!vi~P!PO%T$qO!g!vi!x!vi#P!vi#S!vi#X!vi#[!vi#e!vi$z!vi%[!vi%V!vi~O#t#rO~P/OO#t#rO#y$vO#{$wO~O!]%PO!zwO%V%OO~P%gOS%RO~Os#ZOS#mak#map#maw#ma{#ma}#ma!O#ma!P#ma!Q#ma!R#ma!S#ma!U#ma!W#ma!Y#ma!Z#ma!]#ma!^#ma!_#ma!b#ma!g#ma!x#ma#P#ma#S#ma#X#ma#[#ma#e#ma#j#ma$z#ma%T#ma%[#ma%V#ma#t#ma#v#ma#{#mae#ma!m#ma!o#ma!q#ma!s#ma!u#ma#y#maY#ma[#ma^#ma#^#ma#l#ma#q#ma$O#ma$P#ma$S#ma$U#ma$Z#ma$^#ma$b#ma$g#ma~OS%TO$P%TO~O%T%WO!g#Qi!x#Qi#P#Qi#S#Qi#X#Qi#[#Qi#e#Qi$z#Qi%[#Qi%V#Qi~O#`%YO#b%ZO!g#]X!x#]X#P#]X#S#]X#X#]X#[#]X#e#]X$z#]X%T#]X%[#]X%V#]X~O%T%]O!g#Yi!x#Yi#P#Yi#S#Yi#X#Yi#[#Yi#e#Yi$z#Yi%[#Yi%V#Yi~O#^%_O~OS%`OYqO[rO^sOe!|O!WuO!Y}O!Z}O#^!WO#l|O#q!OO$O!QO$P!WO$S!SO$U!TO$Z!XO$^![O$b!]O$g!aO~O%P%iO~OS%jOYqO[rO^sOe!|O!WuO!Y}O!Z}O#^!WO#l|O#q!OO$O!QO$P!WO$S!SO$U!TO$Z!XO$^![O$b!]O$g!aO~O%O!rO~On%nOe!ka!g!ka!m!ka!o!ka!q!ka!s!ka!u!ka!x!ka#P!ka#S!ka#X!ka#[!ka#e!ka$z!ka%[!ka%V!ka~O%T%rO%V%sO~P/OO%P%tO~Op#^Os#ZO}#^O!O#^O!P#^O!Q#^O!R#^O!S#^O!U#]O!WuO!Y#`O!Z#`O!]#aO!^#aO!_#aO!b#bO#j#dOSyikyiwyi!gyi!xyi#Pyi#Syi#Xyi#[yi#eyi$zyi%Tyi%[yi%Vyi#tyi#vyi#{yieyi!myi!oyi!qyi!syi!uyi#yyiYyi[yi^yi#^yi#lyi#qyi$Oyi$Pyi$Syi$Uyi$Zyi$^yi$byi$gyi~O{#[O~PISO{yi~PISOs#ZO!]#aO!^#aO!_#aOSyikyipyiwyi{yi}yi!Oyi!Pyi!Qyi!Ryi!Syi!Uyi!Wyi!byi!gyi!xyi#Pyi#Syi#Xyi#[yi#eyi#jyi$zyi%Tyi%[yi%Vyi#tyi#vyi#{yieyi!myi!oyi!qyi!syi!uyi#yyiYyi[yi^yi#^yi#lyi#qyi$Oyi$Pyi$Syi$Uyi$Zyi$^yi$byi$gyi~O!Y#`O!Z#`O~PMPO!Yyi!Zyi~PMPOs#ZOSyikyipyiwyi{yi}yi!Oyi!Pyi!Qyi!Ryi!Syi!Uyi!Wyi!Yyi!Zyi!]yi!^yi!_yi!byi!gyi!xyi#Pyi#Syi#Xyi#[yi#eyi#jyi$zyi%Tyi%[yi%Vyi#tyi#vyi#{yieyi!myi!oyi!qyi!syi!uyi#yyiYyi[yi^yi#^yi#lyi#qyi$Oyi$Pyi$Syi$Uyi$Zyi$^yi$byi$gyi~O!g!vq!x!vq#P!vq#S!vq#X!vq#[!vq#e!vq$z!vq%[!vq%V!vq~P!PO%T%yO!g!vq!x!vq#P!vq#S!vq#X!vq#[!vq#e!vq$z!vq%[!vq%V!vq~O#v%}O~P/OO%V&PO~O%V&QO~P/OO%V&QO~O!gQO~O!g#Qq!x#Qq#P#Qq#S#Qq#X#Qq#[#Qq#e#Qq$z#Qq%[#Qq%V#Qq~P!PO%T&UO!g#Qq!x#Qq#P#Qq#S#Qq#X#Qq#[#Qq#e#Qq$z#Qq%[#Qq%V#Qq~O!g#Yq!x#Yq#P#Yq#S#Yq#X#Yq#[#Yq#e#Yq$z#Yq%[#Yq%V#Yq~OS$QO#^$QO~P!*`O%T&WO~P!*`O%O!rO%P#WOkUXpUXsUXwUX{UX}UX!OUX!PUX!QUX!RUX!SUX!UUX!WUX!YUX!ZUX!]UX!^UX!_UX!bUX#jUX$klX~OS&YOYqO[rO^sO~P!+cOg&[Oi&]O~Op#^Ow#YO{#[O}#^O!O#^O!P#^O!Q#^O!R#^O!S#^O!U#]O!WuO!Y#`O!Z#`O!]#aO!^#aO!_#aO!b#bO#j#dO~Ok!uOs&`O~P!-fO%T&jOS$rXY$rX[$rX^$rXe$rX!W$rX!Y$rX!Z$rX#^$rX#l$rX#q$rX$O$rX$P$rX$S$rX$U$rX$Z$rX$^$rX$b$rX$g$rX%V$rX~O%V&lO~PDvO$k&mO~O%T&oOS$yXY$yX[$yX^$yXe$yX!W$yX!Y$yX!Z$yX#^$yX#l$yX#q$yX$O$yX$P$yX$S$yX$U$yX$Z$yX$^$yX$b$yX$g$yX%V$yX~O%V&qO~PFYOn%nOe!ki!g!ki!m!ki!o!ki!q!ki!s!ki!u!ki!x!ki#P!ki#S!ki#X!ki#[!ki#e!ki$z!ki%[!ki%V!ki~O%T&uO%V&vO~O%V&vO~P%gO%T&zO%V!cX~P/OO%V&{O~O!g!vy!x!vy#P!vy#S!vy#X!vy#[!vy#e!vy$z!vy%[!vy%V!vy~P!PO#{#wa~P/OO%V'OO~P/OO!g#Qy!x#Qy#P#Qy#S#Qy#X#Qy#[#Qy#e#Qy$z#Qy%[#Qy%V#Qy~P!POS$QO#^$QO!g#Yy!x#Yy#P#Yy#S#Yy#X#Yy#[#Yy#e#Yy$z#Yy%[#Yy%V#Yy~Oa'SOSVaYVa[Va^VaeVa!WVa!YVa!ZVa#^Va#lVa#qVa$OVa$PVa$SVa$UVa$ZVa$^Va$bVa$gVa%TVa%VVa~Ok!uOn%nO~O%P'ZO~O%V'eO~Oe!kq!g!kq!m!kq!o!kq!q!kq!s!kq!u!kq!x!kq#P!kq#S!kq#X!kq#[!kq#e!kq$z!kq%[!kq%V!kq~P/OO%V'hO~P%gO%T$sa%V$sa~P/OO%V'iO~O%T'jO%V!ca~O%V!ca~P%gO#t#rq#y#rq#{#rq~P/OO%V'kO~P/OO%V'lO~O%P'pO~Op#^Os#ZO}#^O!O#^O!P#^O!Q#^O!R#^O!S#^O!U#]O!WuO!Y#`O!Z#`O!]#aO!^#aO!_#aO!b#bO#j#dOkuiwui~O{#[O~P!;PO{ui~P!;POs#ZO!]#aO!^#aO!_#aOkuipuiwui{ui}ui!Oui!Pui!Qui!Rui!Sui!Uui!Wui!bui#jui~O!Y#`O!Z#`O~P!<lO!Yui!Zui~P!<lOs#ZOkuipuiwui{ui}ui!Oui!Pui!Qui!Rui!Sui!Uui!Wui!Yui!Zui!]ui!^ui!_ui!bui#jui~OSqiYqi[qi^qieqi#^qi#lqi#qqi$Oqi$Pqi$Sqi$Uqi$Zqi$^qi$bqi$gqi%Tqi%Vqi~P/OOe!ky!g!ky!m!ky!o!ky!q!ky!s!ky!u!ky!x!ky#P!ky#S!ky#X!ky#[!ky#e!ky$z!ky%[!ky%V!ky~P/OO%V!ci~P%gOp'sO~O%V'vO~O%V'yO~O$}!Zs$k!]!^~",
|
|
1345
|
+
goto: "! V%^PP%_%cPP%g'Q'U'XP(eP)qP*}+QP+T+]+cP+pP+pP+sP,Y,xP-UP+T-[P-b-[-kP.S.S/SP/mPPPPPP0YP0wP2nPP3]PPP.S3|P4o4{5g5tP6U6U6Z7`7dP7dP7dP7dP7dP5g7hP7uP7{8^5g8iP5g8vP9TP5g9ZP5g9hP9uP9}P9}P5g:QP:_P.S:bP:}P<_=c<_>gP?k?qP?wP?z@QP@UP<_@`PPAdBhPBhPAdClClDpP<_EtPFx<_F{P<_HP<_<_P6`-[-[P%_%_HSPHWH^IqIwJRJbJhJvJ|KWPPPPPPK^KbKhPMrPM{<_Cl.SP! RTcOdT`OdUjR#S$^#S!ZTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pQ!l`Q!mbQ&_%bS'm'V'tR'w'sT%e$U%gR&Z%`#S!_Tfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pU$b#Z&T&`R&Y%`#S!`Tfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pU$b#Z&T&`R&Y%`#S!^Tfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pU$b#Z&T&`R&Y%`R'U&ZR'T&ZS%e$U%gT%k$W%mX%b$U$W%g%mS#Sn#VQ$^#TX%a$U$W%g%mR&^%aQ!xjQ!{lQ#ltQ$V!lQ&T%VQ&i%cR'W&_Q!wjQ!zlQ#ktQ$Y!xQ$[!{Q$n#lW%h$U$W%g%mQ'c&iR'o'WQ%o$]Q&s%pQ'V&_R't'oQ'n'VR'x'tX%d$U$W%g%mQ$c#ZQ'Q&TR'X&`t#ft!p!q#m#q$`${$}%V%u%|&R&r&w&}'P'd'fR&d%c!{!cTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$f$q$z%Q%W%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'px#gt!p!q#m#q$`$i${$}%V%u%|&R&r&w&}'P'^'d'fR&e%c|#ht!p!q#m#q$`$i$j${$}%V%u%|&R&r&w&}'P'^'_'d'fR&f%c!O#^t!p!q#m#q$`$i$j${$}%V%c%u%|&R&r&w&}'P'^'_'d'fT$d#_&a#S}Tfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p|#_t!p!q#m#q$`$i$j${$}%V%u%|&R&r&w&}'P'^'_'d'fQ$h#eQ&a%cR']&c!Q#it!p!q#m#q$`$i$j$k${$}%V%u%|&R&r&w&}'P'^'_'`'d'fR&g%c!U#jt!p!q#m#q$`$i$j$k$l${$}%V%u%|&R&r&w&}'P'^'_'`'a'd'fR&h%c|#ct!p!q#m#q$`$i$j${$}%V%u%|&R&r&w&}'P'^'_'d'fQ$e#_Q&b%cR'Y&aQ%v$fQ&x%tQ'q'ZR'u'pSeOdS!ykvQ$|#vQ%v$fQ&n%iQ&x%tQ'q'ZR'u'pg^O_dkv#v$f%i%t'Z'pfRO_dkv#v$f%i%t'Z'pR&S%UVmR#S$^UlR#S$^!{!bTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$f$q$z%Q%W%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pT#Un#VT#Tn#VgTO_dkv#v$f%i%t'Z'pQ{TR%Q#wQzTQ#p{Q$P!h]$p#n$q%W%x%y&UcyT{!h#n$q%W%x%y&UgfO_dkv#v$f%i%t'Z'pgWO_dkv#v$f%i%t'Z'pQ!hWR!iZggO_dkv#v$f%i%t'Z'pgZO_dkv#v$f%i%t'Z'pQ$R!iV&V%]&W'RR%[$Qg]O_dkv#v$f%i%t'Z'pR$T!j|#et!p!q#m#q$`$i$j${$}%V%u%|&R&r&w&}'P'^'_'d'fR&c%c#S!VTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pQ$g#eQ%w$hQ'[&cR'r']#T!aTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!dTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!PTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pX#s!P#q#t$tX#u!P#q#t$tR&O${Q$y#tR%{$tT$z#t$tQ$x#tS%z$t$yR&|%{#T!RTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!WTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!UTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!ZTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!YTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'p#T!eTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pR%U#}#T!fTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$U$W$f$q$z%Q%W%g%m%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pR%S#yTbOdQdOR!od#SiR`bfgv!P!d#S#W#f#g#h#i#j#u#w$O$U$W$^$f$z%Q%b%g%m%o%r%t&O&S&d&e&f&g&h&m&s&u&z'V'Z'g'j'p's'tbpT{!h#n$q%W%x%y&UT!tipQ%g$UR&k%gQ%q$`S&t%q&yR&y%ud_Odkv#v$f%i%t'Z'pR!k_Q#VnR$_#VQ#ozU$r#o$s%XQ$s#pR%X$PQ%^$RR&X%^Q#t!PQ$t#qT$u#t$tQ%m$WR&p%mT%f$U%gX%c$U$W%g%mbtT{!h#n$q%W%x%y&UQ!pfQ!qgQ#mvQ#q!PQ#|!dQ$`#WQ$i#fQ$j#gQ$k#hQ$l#iQ$m#jQ${#uQ$}#wQ%V$OW%u$f%t'Z'pQ%|$zQ&R%QQ&r%oY&w%r&u&z'g'jQ&}&OQ'P&SQ'^&dQ'_&eQ'`&fQ'a&gQ'b&hQ'd&mR'f&sQnRQ$]#SR%p$^!z!cTfgv{!P!d!h#W#f#g#h#i#j#n#u#w$O$f$q$z%Q%W%o%r%t%x%y&O&S&U&d&e&f&g&h&m&s&u&z'Z'g'j'pX%d$U$W%g%mT%l$W%m",
|
|
1346
|
+
nodeNames: "\u26A0 Program TableStatement Kw Identifier table Ref ColumnDef DataType Kw date Kw timestamp Kw interval PrimaryKey Kw primary_key JoinDef JoinType Kw join Kw one Kw many Kw as Alias Kw on BinaryExpression = ComputedDef TypeCastExpression :: CastType BinaryExpression Kw or TypeCastExpression BinaryExpression Kw and ComparisonOp != <> < > <= >= Kw like Kw not AddOp + - MulOp * / % InExpression Kw in InValueList QueryStatement FromClause Kw from TableName Subquery SubqueryExpression JoinClause Kw inner Kw left Kw right Kw full Kw cross SelectClause Kw select Kw distinct SelectItem Wildcard WhereClause Kw where GroupByClause Kw group Kw by HavingClause Kw having OrderByClause Kw order OrderItem Number Kw asc Kw desc LimitClause Kw limit Kw offset NullTestExpression Kw is Kw null UnaryExpression UnaryOperator CaseExpression Kw case WhenClause Kw when Kw then ElseClause Kw else Kw end ExistsExpression Kw exists String Boolean Kw true Kw false Null FunctionCall Count Kw count ExtractExpression Kw extract ExtractUnit CastExpression Kw cast IntervalExpression IntervalUnit DateExpression TimestampExpression Param Parenthetical InExpression NullTestExpression : ViewStatement ExtendStatement Kw extend",
|
|
1347
|
+
maxTerm: 197,
|
|
1327
1348
|
nodeProps: [
|
|
1328
|
-
["group", -
|
|
1349
|
+
["group", -16, 6, 106, 121, 123, 136, 139, 140, 145, 146, 147, 150, 154, 157, 159, 160, 161, "Expression Expression", -11, 31, 34, 37, 40, 41, 62, 72, 116, 162, 163, 164, "Expression", -2, 70, 71, "TablePrimary"]
|
|
1329
1350
|
],
|
|
1330
|
-
skippedNodes: [0
|
|
1351
|
+
skippedNodes: [0],
|
|
1331
1352
|
repeatNodeCount: 10,
|
|
1332
|
-
tokenData: "*
|
|
1353
|
+
tokenData: "*w~RoX^#Spq#Sqr#wrs$Stu$quv%cwx%hxy&Qyz&Vz{&[{|&a|}&f}!O&k!O!P'[!P!Q'a!Q![(p![!])Z!]!^)h!^!_)m!_!`*S!`!a*X!c!}*f#T#o*f#y#z#S$f$g#S#BY#BZ#S$IS$I_#S$I|$JO#S$JT$JU#S$KV$KW#S&FU&FV#S~#XY$|~X^#Spq#S#y#z#S$f$g#S#BY#BZ#S$IS$I_#S$I|$JO#S$JT$JU#S$KV$KW#S&FU&FV#S~#zP!_!`#}~$SO}~~$VTOr$Srs$fs;'S$S;'S;=`$k<%lO$S~$kO$P~~$nP;=`<%l$S~$tS!Q![%Q!c!}%Q#R#S%Q#T#o%Q~%VS$g~!Q![%Q!c!}%Q#R#S%Q#T#o%Q~%hO!_~~%kTOw%hwx$fx;'S%h;'S;=`%z<%lO%h~%}P;=`<%l%h~&VO%P~~&[O%V~~&aO!]~~&fO!Y~~&kO%T~~&pP!Z~}!O&s~&xS$}~OY&sZ;'S&s;'S;=`'U<%lO&s~'XP;=`<%l&s~'aO%O~~'fP!^~z{'i~'lTOz'iz{'{{;'S'i;'S;=`(j<%lO'i~(OVOz'iz{'{{!P'i!P!Q(e!Q;'S'i;'S;=`(j<%lO'i~(jO$}~~(mP;=`<%l'i~(uQ#^~!O!P({!Q![(p~)OP!Q![)R~)WP#^~!Q![)R~)`P$k~![!])c~)hOs~~)mO%[~~)rQ!P~!_!`)x!`!a)}~)}O!R~~*SO!O~~*XOp~~*^P!Q~!_!`*a~*fO!S~~*kSS~!Q![*f!c!}*f#R#S*f#T#o*f",
|
|
1333
1354
|
tokenizers: [0],
|
|
1334
|
-
topRules: { "Program": [0,
|
|
1335
|
-
specialized: [{ term:
|
|
1336
|
-
tokenPrec:
|
|
1355
|
+
topRules: { "Program": [0, 1] },
|
|
1356
|
+
specialized: [{ term: 4, get: (value, stack) => specializeIdentifier(value, stack) << 1, external: specializeIdentifier }, { term: 4, get: (value) => spec_Identifier[value] || -1 }],
|
|
1357
|
+
tokenPrec: 3656
|
|
1337
1358
|
});
|
|
1338
1359
|
}
|
|
1339
1360
|
});
|
|
@@ -1544,7 +1565,7 @@ var init_snowflake = __esm({
|
|
|
1544
1565
|
});
|
|
1545
1566
|
|
|
1546
1567
|
// ../lang/core.ts
|
|
1547
|
-
import {
|
|
1568
|
+
import { QueryModel } from "@graphenedata/malloy";
|
|
1548
1569
|
import { readFile } from "node:fs/promises";
|
|
1549
1570
|
import { glob } from "glob";
|
|
1550
1571
|
import path2 from "node:path";
|
|
@@ -1624,7 +1645,6 @@ function toSql(query, params = {}) {
|
|
|
1624
1645
|
});
|
|
1625
1646
|
return qm.compileQuery(query).sql;
|
|
1626
1647
|
}
|
|
1627
|
-
var BigQueryDialect;
|
|
1628
1648
|
var init_core = __esm({
|
|
1629
1649
|
"../lang/core.ts"() {
|
|
1630
1650
|
"use strict";
|
|
@@ -1632,20 +1652,10 @@ var init_core = __esm({
|
|
|
1632
1652
|
init_params();
|
|
1633
1653
|
init_util();
|
|
1634
1654
|
init_config();
|
|
1635
|
-
init_functionDefs();
|
|
1636
1655
|
init_parser();
|
|
1637
1656
|
init_markdown();
|
|
1638
1657
|
init_snowflake();
|
|
1639
|
-
|
|
1640
|
-
constructor() {
|
|
1641
|
-
super();
|
|
1642
|
-
this.name = "bigquery";
|
|
1643
|
-
}
|
|
1644
|
-
getDialectFunctions() {
|
|
1645
|
-
return expandBlueprintMap(BIGQUERY_DIALECT_FUNCTIONS);
|
|
1646
|
-
}
|
|
1647
|
-
};
|
|
1648
|
-
registerDialect(new BigQueryDialect());
|
|
1658
|
+
init_functionDefs();
|
|
1649
1659
|
}
|
|
1650
1660
|
});
|
|
1651
1661
|
|
|
@@ -2087,7 +2097,7 @@ async function startLoopback() {
|
|
|
2087
2097
|
await new Promise((r) => server.listen(0, "127.0.0.1", () => r()));
|
|
2088
2098
|
let addr = server.address();
|
|
2089
2099
|
if (!addr || typeof addr !== "object") throw new Error("Couldnt start oauth callback server");
|
|
2090
|
-
let redirectBase = `http://
|
|
2100
|
+
let redirectBase = `http://127.0.0.1:${addr.port}`;
|
|
2091
2101
|
let waitForCode = new Promise((resolve) => {
|
|
2092
2102
|
server.on("request", (req, res) => {
|
|
2093
2103
|
let url = new URL(req.url || "/", redirectBase);
|
|
@@ -2183,7 +2193,7 @@ var init_auth = __esm({
|
|
|
2183
2193
|
"auth.ts"() {
|
|
2184
2194
|
"use strict";
|
|
2185
2195
|
init_config();
|
|
2186
|
-
AUTH_CLIENT_ID = "connected-app-test-
|
|
2196
|
+
AUTH_CLIENT_ID = "connected-app-test-75eae3e8-efa1-454d-8ad0-66288c750872";
|
|
2187
2197
|
AUTH_SCOPES = "offline_access";
|
|
2188
2198
|
cfgDir = process.env.XDG_CONFIG_HOME || path5.join(os2.homedir(), ".config");
|
|
2189
2199
|
credsPath = path5.join(cfgDir, "graphene", "credentials.json");
|
|
@@ -2197,8 +2207,8 @@ __export(bigQuery_exports, {
|
|
|
2197
2207
|
});
|
|
2198
2208
|
import { BigQuery, BigQueryDate, BigQueryTimestamp } from "@google-cloud/bigquery";
|
|
2199
2209
|
import { readFileSync as readFileSync3 } from "fs";
|
|
2200
|
-
function
|
|
2201
|
-
|
|
2210
|
+
function validateBigQueryIdent(ident) {
|
|
2211
|
+
if (!/^[\w.-]+$/.test(ident)) throw new Error(`Invalid BigQuery identifier: ${ident}`);
|
|
2202
2212
|
}
|
|
2203
2213
|
var BigQueryConnection;
|
|
2204
2214
|
var init_bigQuery = __esm({
|
|
@@ -2225,8 +2235,8 @@ var init_bigQuery = __esm({
|
|
|
2225
2235
|
this.client = new BigQuery({ ...options, userAgent: "Graphene" });
|
|
2226
2236
|
this.defaultNamespace = config.namespace;
|
|
2227
2237
|
}
|
|
2228
|
-
async runQuery(sql) {
|
|
2229
|
-
let [job] = await this.client.createQueryJob({ query: sql, useLegacySql: false });
|
|
2238
|
+
async runQuery(sql, params) {
|
|
2239
|
+
let [job] = await this.client.createQueryJob({ query: sql, useLegacySql: false, params });
|
|
2230
2240
|
let [rows] = await job.getQueryResults({ maxResults: 1e4 });
|
|
2231
2241
|
let metadata = job.metadata || (await job.getMetadata())[0];
|
|
2232
2242
|
let totalRows = Number(metadata?.statistics?.query?.totalRows ?? rows.length);
|
|
@@ -2244,6 +2254,7 @@ var init_bigQuery = __esm({
|
|
|
2244
2254
|
}
|
|
2245
2255
|
async listTables(dataset) {
|
|
2246
2256
|
if (!dataset) throw new Error("BigQuery requires a dataset");
|
|
2257
|
+
validateBigQueryIdent(dataset);
|
|
2247
2258
|
let res = await this.runQuery(`select table_schema as table_schema, table_name as table_name
|
|
2248
2259
|
from \`${dataset}.INFORMATION_SCHEMA.TABLES\`
|
|
2249
2260
|
where table_type in ('BASE TABLE', 'VIEW') order by table_name`);
|
|
@@ -2253,13 +2264,14 @@ var init_bigQuery = __esm({
|
|
|
2253
2264
|
let parts = target.split(".");
|
|
2254
2265
|
let table2 = parts.pop() || "";
|
|
2255
2266
|
let dataset = parts.join(".");
|
|
2267
|
+
validateBigQueryIdent(dataset);
|
|
2256
2268
|
let sql = `
|
|
2257
2269
|
select column_name as column_name, data_type as data_type, ordinal_position as ordinal_position
|
|
2258
2270
|
from \`${dataset}.INFORMATION_SCHEMA.COLUMNS\`
|
|
2259
|
-
where lower(table_name) = lower(
|
|
2271
|
+
where lower(table_name) = lower(@table)
|
|
2260
2272
|
order by ordinal_position
|
|
2261
2273
|
`.trim();
|
|
2262
|
-
let res = await this.runQuery(sql);
|
|
2274
|
+
let res = await this.runQuery(sql, { table: table2 });
|
|
2263
2275
|
return res.rows.map((row) => {
|
|
2264
2276
|
return { name: String(row["column_name"]), dataType: String(row["data_type"]) };
|
|
2265
2277
|
});
|
|
@@ -2276,9 +2288,6 @@ __export(duckdb_exports, {
|
|
|
2276
2288
|
import { promises as fs5 } from "fs";
|
|
2277
2289
|
import path6 from "path";
|
|
2278
2290
|
import { DuckDBTimestampValue, DuckDBInstance, DuckDBDateValue } from "@duckdb/node-api";
|
|
2279
|
-
function sqlStringLiteral2(value) {
|
|
2280
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
2281
|
-
}
|
|
2282
2291
|
var DuckDBConnection;
|
|
2283
2292
|
var init_duckdb = __esm({
|
|
2284
2293
|
"connections/duckdb.ts"() {
|
|
@@ -2306,9 +2315,9 @@ var init_duckdb = __esm({
|
|
|
2306
2315
|
await this.connection.run(`attach '${escapedPath}' as graphene_cli (READ_ONLY);`);
|
|
2307
2316
|
await this.connection.run("use graphene_cli;");
|
|
2308
2317
|
}
|
|
2309
|
-
async runQuery(sql) {
|
|
2318
|
+
async runQuery(sql, params) {
|
|
2310
2319
|
await this.ready;
|
|
2311
|
-
let reader = await this.connection.runAndReadAll(sql);
|
|
2320
|
+
let reader = params ? await this.connection.runAndReadAll(sql, params) : await this.connection.runAndReadAll(sql);
|
|
2312
2321
|
let rows = reader.getRowObjects().map((record) => {
|
|
2313
2322
|
let out = {};
|
|
2314
2323
|
for (let [k, v] of Object.entries(record)) {
|
|
@@ -2340,14 +2349,15 @@ var init_duckdb = __esm({
|
|
|
2340
2349
|
let parts = target.split(".");
|
|
2341
2350
|
let table2 = parts.pop() || "";
|
|
2342
2351
|
let schema = parts[0];
|
|
2343
|
-
let schemaFilter = schema ?
|
|
2352
|
+
let schemaFilter = schema ? "lower(table_schema) = lower($2)" : "table_schema not in ('information_schema', 'pg_catalog')";
|
|
2344
2353
|
let sql = `
|
|
2345
2354
|
select column_name as column_name, data_type as data_type, ordinal_position as ordinal_position
|
|
2346
2355
|
from information_schema.columns
|
|
2347
|
-
where lower(table_name) = lower($
|
|
2356
|
+
where lower(table_name) = lower($1) and ${schemaFilter}
|
|
2348
2357
|
order by ordinal_position
|
|
2349
2358
|
`.trim();
|
|
2350
|
-
let
|
|
2359
|
+
let params = schema ? [table2, schema] : [table2];
|
|
2360
|
+
let res = await this.runQuery(sql, params);
|
|
2351
2361
|
return res.rows.map((row) => {
|
|
2352
2362
|
return { name: String(row["column_name"]), dataType: String(row["data_type"]) };
|
|
2353
2363
|
});
|
|
@@ -2367,9 +2377,6 @@ function snowflakeIdent(value) {
|
|
|
2367
2377
|
if (!value) throw new Error("Snowflake identifiers cannot be empty");
|
|
2368
2378
|
return `"${value.replace(/"/g, '""')}"`;
|
|
2369
2379
|
}
|
|
2370
|
-
function sqlStringLiteral3(value) {
|
|
2371
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
2372
|
-
}
|
|
2373
2380
|
var SnowflakeConnection;
|
|
2374
2381
|
var init_snowflake2 = __esm({
|
|
2375
2382
|
"connections/snowflake.ts"() {
|
|
@@ -2403,12 +2410,13 @@ var init_snowflake2 = __esm({
|
|
|
2403
2410
|
this.connection.connect((err, conn) => err ? reject(err) : resolve(conn));
|
|
2404
2411
|
});
|
|
2405
2412
|
}
|
|
2406
|
-
async runQuery(sql) {
|
|
2413
|
+
async runQuery(sql, params) {
|
|
2407
2414
|
await this.ready;
|
|
2408
2415
|
return await new Promise((resolve, reject) => {
|
|
2409
2416
|
let rows = [];
|
|
2410
2417
|
this.connection.execute({
|
|
2411
2418
|
sqlText: sql,
|
|
2419
|
+
binds: params,
|
|
2412
2420
|
streamResult: true,
|
|
2413
2421
|
complete: (error, statement) => {
|
|
2414
2422
|
if (error) {
|
|
@@ -2441,9 +2449,9 @@ var init_snowflake2 = __esm({
|
|
|
2441
2449
|
let res = await this.runQuery(`
|
|
2442
2450
|
select table_schema as "table_schema", table_name as "table_name"
|
|
2443
2451
|
from ${snowflakeIdent(database)}.INFORMATION_SCHEMA.TABLES
|
|
2444
|
-
where table_type in ('BASE TABLE', 'VIEW') and table_schema =
|
|
2452
|
+
where table_type in ('BASE TABLE', 'VIEW') and table_schema = ?
|
|
2445
2453
|
order by table_name
|
|
2446
|
-
|
|
2454
|
+
`, [schema]);
|
|
2447
2455
|
return res.rows.map((row) => `${row["table_schema"]}.${row["table_name"]}`);
|
|
2448
2456
|
}
|
|
2449
2457
|
async describeTable(target) {
|
|
@@ -2454,9 +2462,9 @@ var init_snowflake2 = __esm({
|
|
|
2454
2462
|
let res = await this.runQuery(`
|
|
2455
2463
|
select column_name as "column_name", data_type as "data_type", ordinal_position as ordinal_position
|
|
2456
2464
|
from ${snowflakeIdent(database)}.INFORMATION_SCHEMA.COLUMNS
|
|
2457
|
-
where upper(table_schema) = upper(
|
|
2465
|
+
where upper(table_schema) = upper(?) and upper(table_name) = upper(?)
|
|
2458
2466
|
order by ordinal_position
|
|
2459
|
-
|
|
2467
|
+
`, [schema, table2]);
|
|
2460
2468
|
return res.rows.map((row) => {
|
|
2461
2469
|
return { name: String(row["column_name"]).toLowerCase(), dataType: String(row["data_type"]) };
|
|
2462
2470
|
});
|
|
@@ -2480,17 +2488,17 @@ async function getConnection() {
|
|
|
2480
2488
|
throw new Error(`Unsupported dialect: ${config.dialect}`);
|
|
2481
2489
|
}
|
|
2482
2490
|
}
|
|
2483
|
-
async function runQuery(sql) {
|
|
2491
|
+
async function runQuery(sql, params) {
|
|
2484
2492
|
if (config.host) {
|
|
2485
2493
|
let resp = await authenticatedFetch("/_api/query", {
|
|
2486
2494
|
method: "POST",
|
|
2487
2495
|
headers: { "Content-Type": "application/json" },
|
|
2488
|
-
body: JSON.stringify({ sql })
|
|
2496
|
+
body: JSON.stringify({ sql, params })
|
|
2489
2497
|
});
|
|
2490
2498
|
return await resp.json();
|
|
2491
2499
|
}
|
|
2492
2500
|
let conn = await getConnection();
|
|
2493
|
-
return await conn.runQuery(sql);
|
|
2501
|
+
return await conn.runQuery(sql, params);
|
|
2494
2502
|
}
|
|
2495
2503
|
var init_connections = __esm({
|
|
2496
2504
|
"connections/index.ts"() {
|
|
@@ -2829,10 +2837,14 @@ init_auth();
|
|
|
2829
2837
|
import { Command } from "commander";
|
|
2830
2838
|
import fs8 from "fs-extra";
|
|
2831
2839
|
import path9 from "path";
|
|
2840
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2832
2841
|
import dotenv from "dotenv";
|
|
2833
2842
|
dotenv.config({ quiet: true });
|
|
2834
2843
|
var program = new Command();
|
|
2835
|
-
|
|
2844
|
+
var __dirname = path9.dirname(fileURLToPath3(import.meta.url));
|
|
2845
|
+
var pkgPath = fs8.existsSync(path9.join(__dirname, "package.json")) ? path9.join(__dirname, "package.json") : path9.join(__dirname, "../../package.json");
|
|
2846
|
+
var pkg = fs8.readJsonSync(pkgPath);
|
|
2847
|
+
program.name("graphene").description("Graphene CLI").version(pkg.version, "-v, --version");
|
|
2836
2848
|
program.hook("preAction", async () => {
|
|
2837
2849
|
if (process.env.CLI_DELAY) {
|
|
2838
2850
|
await new Promise((r) => setTimeout(r, 1e3));
|