@sqg/sqg 0.19.1 → 0.21.0

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/dist/sqg.mjs CHANGED
@@ -221,6 +221,7 @@ SQL Annotation Syntax:
221
221
  -- QUERY <name> [:one] [:pluck] Select query (returns rows)
222
222
  -- EXEC <name> [:batch] Execute statement (INSERT/UPDATE/DELETE)
223
223
  -- BASELINE <name> Schema created outside SQG (runs before migrations, not tracked)
224
+ -- BASELINE <name> :source=<src> Schema of a 'type: postgres' source (applied to a managed testcontainer, attached into DuckDB)
224
225
  -- MIGRATE <name> Schema migration (runs in source order; name is any identifier, e.g. "1" or "add_email")
225
226
  -- TESTDATA <name> Test data setup (not generated)
226
227
  -- TABLE <name> :appender Table for bulk insert appender (DuckDB, PostgreSQL)
@@ -229,11 +230,19 @@ SQL Annotation Syntax:
229
230
  \${varName} Reference a variable in SQL
230
231
 
231
232
  Modifiers:
232
- :one Return single row (or null) instead of array
233
- :pluck Return single column value (requires exactly 1 column)
234
- :all Return all rows (default)
235
- :batch Generate a JDBC batch method for an EXEC (Java only)
236
- :appender Generate bulk insert appender for TABLE annotation
233
+ :one Return single row (or null) instead of array
234
+ :pluck Return single column value (requires exactly 1 column)
235
+ :all Return all rows (default)
236
+ :batch Generate a JDBC batch method for an EXEC (Java only)
237
+ :appender Generate bulk insert appender for TABLE annotation
238
+ :source=Name Mark a BASELINE block as the schema of a postgres source (Name)
239
+ :result=Name Name (and share) the row type (Java only). Annotate ONE query
240
+ with :result=Name — every other query in the same file with the
241
+ same column shape automatically gets the same name; you do NOT
242
+ need to repeat the modifier on each query.
243
+ Without :result=, each query keeps its own per-query row type.
244
+ Exception: SELECT * matching a -- TABLE schema (same columns,
245
+ same order) auto-uses the table's row type with no annotation.
237
246
 
238
247
  Example:
239
248
  -- MIGRATE 1
@@ -724,7 +733,7 @@ const parser = LRParser.deserialize({
724
733
  maxTerm: 34,
725
734
  skippedNodes: [0],
726
735
  repeatNodeCount: 6,
727
- tokenData: "$KR~RqOX#YXY'wYZ(iZ]#Y]^$W^p#Ypq'wqr#Yrs(}st#Ytu6^uw#Ywx9[xz#Yz{%_{}#Y}!OKi!O!P#Y!P!Q#2P!Q![$A]![!]$Bu!]!_#Y!_!`$Eu!`!b#Y!b!c$Fu!c!}$A]!}#R#Y#R#S$A]#S#T#Y#T#o$A]#o;'S#Y;'S;=`'q<%lO#YU#_]_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YS$ZTOz$Wz{$j{;'S$W;'S;=`%X<%lO$WS$mVOz$Wz{$j{!P$W!P!Q%S!Q;'S$W;'S;=`%X<%lO$WS%XOnSS%[P;=`<%l$WU%d__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!P#Y!P!Q&c!Q;'S#Y;'S;=`'q<%lO#YU&jVnS_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'UV_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'nP;=`<%l'PU'tP;=`<%l#Y~'|Xj~OX$WXY'wYp$Wpq'wqz$Wz{$j{;'S$W;'S;=`%X<%lO$W~(nTk~Oz$Wz{$j{;'S$W;'S;=`%X<%lO$WU)Sb_QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U*_ZOY*[YZ$WZr*[rs+Qsz*[z{+f{#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U+VT]QOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU+i]OY*[YZ$WZr*[rs+Qsz*[z{+f{!P*[!P!Q,b!Q#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U,gWnSOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-SWOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-qO]QQ-tTOY-PYZ-PZ;'S-P;'S;=`.T<%lO-PQ.WP;=`<%l-PU.^VOY*[YZ*[Zz*[z{+f{;'S*[;'S;=`.s<%lO*[U.vP;=`<%l*[U/Q]]Q_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU0Od_QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{!P(}!P!Q1^!Q#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U1e_nS_QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ2i__QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ3oV]Q_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ4Z[_QOX2dXY-PYZ-PZ]2d]^-P^p2dpq-Pqt2dtu-Pu;'S2d;'S;=`5P<%lO2dQ5SP;=`<%l2dU5[^_QOX(}XY*[YZ*[Z](}]^*[^p(}pq*[qt(}tu*[uz(}z{/y{;'S(};'S;=`6W<%lO(}U6ZP;=`<%l(}U6cV_QOz$Wz{$j{#o$W#o#p6x#p;'S$W;'S;=`%X<%lO$WU6{]Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o;'S$W;'S;=`%X<%lO$WU7w_Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o#q$W#q#r8v#r;'S$W;'S;=`%X<%lO$WU8{TaQOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU9ab_QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[U:lZOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU;dT^QOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU;v]OY:iYZ$WZw:iwx;_xz:iz{;s{!P:i!P!Q<o!Q#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU<tWnSOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q=aWOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>OO^QQ>RXOY=^YZ=^Zw=^wx>nx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>sW^QOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q?`P;=`<%l=^U?fZOY:iYZ:iZw:iwx@Xxz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU@^Z^QOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iUASP;=`<%l:iUA^]^Q_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YUB[d_QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{!P9[!P!QCj!Q#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UCq_nS_QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQDu__QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQE{V^Q_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQFg`_QOXDpXY=^YZ=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxGix#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQGp_^Q_QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQHrP;=`<%lDpUHzb_QOX9[XY:iYZ:iZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxJSxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UJZb^Q_QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UKfP;=`<%l9[VKn__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{}#Y}!OLm!O;'S#Y;'S;=`'q<%lO#YVLthQR_QOXN`XY!&|YZ$WZ]N`]^! c^pN`pq!&|qtN`tu! cuzN`z{!#q{!dN`!d!e!=`!e!gN`!g!h!Ft!h!oN`!o!p!Ja!p!sN`!s!t#!`!t!vN`!v!w#'U!w;'SN`;'S;=`!&v<%lON`VNg^QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{;'SN`;'S;=`!&v<%lON`V! hVQROY! cYZ$WZz! cz{! }{;'S! c;'S;=`!#k<%lO! cV!!SXQROY! cYZ$WZz! cz{! }{!P! c!P!Q!!o!Q;'S! c;'S;=`!#k<%lO! cV!!vSnSQROY!#SZ;'S!#S;'S;=`!#e<%lO!#SR!#XSQROY!#SZ;'S!#S;'S;=`!#e<%lO!#SR!#hP;=`<%l!#SV!#nP;=`<%l! cV!#x`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!PN`!P!Q!$z!Q;'SN`;'S;=`!&v<%lON`V!%TZnSQR_QOX!%vXY!#SZ]!%v]^!#S^p!%vpq!#Sqt!%vtu!#Su;'S!%v;'S;=`!&p<%lO!%vR!%}ZQR_QOX!%vXY!#SZ]!%v]^!#S^p!%vpq!#Sqt!%vtu!#Su;'S!%v;'S;=`!&p<%lO!%vR!&sP;=`<%l!%vV!&yP;=`<%lN`V!'RdQROX! cXY!&|YZ$WZp! cpq!&|qz! cz{! }{!d! c!d!e!(a!e!g! c!g!h!.l!h!o! c!o!p!0p!p!s! c!s!t!4W!t!v! c!v!w!6|!w;'S! c;'S;=`!#k<%lO! cV!(fXQROY! cYZ$WZz! cz{! }{!c! c!c!d!)R!d;'S! c;'S;=`!#k<%lO! cV!)WXQROY! cYZ$WZz! cz{! }{!u! c!u!v!)s!v;'S! c;'S;=`!#k<%lO! cV!)xXQROY! cYZ$WZz! cz{! }{!g! c!g!h!*e!h;'S! c;'S;=`!#k<%lO! cV!*jXQROY! cYZ$WZz! cz{! }{!n! c!n!o!+V!o;'S! c;'S;=`!#k<%lO! cV!+[XQROY! cYZ$WZz! cz{! }{!k! c!k!l!+w!l;'S! c;'S;=`!#k<%lO! cV!+|XQROY! cYZ$WZz! cz{! }{!p! c!p!q!,i!q;'S! c;'S;=`!#k<%lO! cV!,nXQROY! cYZ$WZz! cz{! }{!g! c!g!h!-Z!h;'S! c;'S;=`!#k<%lO! cV!-`YQROX! cXY!.OYZ$WZp! cpq!.Oqz! cz{! }{;'S! c;'S;=`!#k<%lO! cV!.VVYRQROY! cYZ$WZz! cz{! }{;'S! c;'S;=`!#k<%lO! cV!.qXQROY! cYZ$WZz! cz{! }{!z! c!z!{!/^!{;'S! c;'S;=`!#k<%lO! cV!/cXQROY! cYZ$WZz! cz{! }{!g! c!g!h!0O!h;'S! c;'S;=`!#k<%lO! cV!0TXQROY! cYZ$WZz! cz{! }{!e! c!e!f!-Z!f;'S! c;'S;=`!#k<%lO! cV!0uXQROY! cYZ$WZz! cz{! }{!k! c!k!l!1b!l;'S! c;'S;=`!#k<%lO! cV!1gXQROY! cYZ$WZz! cz{! }{!i! c!i!j!2S!j;'S! c;'S;=`!#k<%lO! cV!2XXQROY! cYZ$WZz! cz{! }{!t! c!t!u!2t!u;'S! c;'S;=`!#k<%lO! cV!2yXQROY! cYZ$WZz! cz{! }{!c! c!c!d!3f!d;'S! c;'S;=`!#k<%lO! cV!3kXQROY! cYZ$WZz! cz{! }{!v! c!v!w!,i!w;'S! c;'S;=`!#k<%lO! cV!4]XQROY! cYZ$WZz! cz{! }{!w! c!w!x!4x!x;'S! c;'S;=`!#k<%lO! cV!4}XQROY! cYZ$WZz! cz{! }{!g! c!g!h!5j!h;'S! c;'S;=`!#k<%lO! cV!5oXQROY! cYZ$WZz! cz{! }{!t! c!t!u!6[!u;'S! c;'S;=`!#k<%lO! cV!6aXQROY! cYZ$WZz! cz{! }{!{! c!{!|!-Z!|;'S! c;'S;=`!#k<%lO! cV!7RZQROY! cYZ$WZz! cz{! }{!c! c!c!d!7t!d!g! c!g!h!9W!h;'S! c;'S;=`!#k<%lO! cV!7yXQROY! cYZ$WZz! cz{! }{!d! c!d!e!8f!e;'S! c;'S;=`!#k<%lO! cV!8kXQROY! cYZ$WZz! cz{! }{!n! c!n!o!,i!o;'S! c;'S;=`!#k<%lO! cV!9]XQROY! cYZ$WZz! cz{! }{!u! c!u!v!9x!v;'S! c;'S;=`!#k<%lO! cV!9}XQROY! cYZ$WZz! cz{! }{!v! c!v!w!:j!w;'S! c;'S;=`!#k<%lO! cV!:oXQROY! cYZ$WZz! cz{! }{!f! c!f!g!;[!g;'S! c;'S;=`!#k<%lO! cV!;aXQROY! cYZ$WZz! cz{! }{!c! c!c!d!;|!d;'S! c;'S;=`!#k<%lO! cV!<RXQROY! cYZ$WZz! cz{! }{!v! c!v!w!<n!w;'S! c;'S;=`!#k<%lO! cV!<sXQROY! cYZ$WZz! cz{! }{!c! c!c!d!-Z!d;'S! c;'S;=`!#k<%lO! cV!=g`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d!>i!d;'SN`;'S;=`!&v<%lON`V!>p`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!uN`!u!v!?r!v;'SN`;'S;=`!&v<%lON`V!?y`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h!@{!h;'SN`;'S;=`!&v<%lON`V!AS`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!nN`!n!o!BU!o;'SN`;'S;=`!&v<%lON`V!B]`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!kN`!k!l!C_!l;'SN`;'S;=`!&v<%lON`V!Cf`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!pN`!p!q!Dh!q;'SN`;'S;=`!&v<%lON`V!Do`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h!Eq!h;'SN`;'S;=`!&v<%lON`V!Ex^QR_QOXN`XY!.OYZ$WZ]N`]^! c^pN`pq!.OqtN`tu! cuzN`z{!#q{;'SN`;'S;=`!&v<%lON`V!F{`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!zN`!z!{!G}!{;'SN`;'S;=`!&v<%lON`V!HU`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h!IW!h;'SN`;'S;=`!&v<%lON`V!I_`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!eN`!e!f!Eq!f;'SN`;'S;=`!&v<%lON`V!Jh`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!kN`!k!l!Kj!l;'SN`;'S;=`!&v<%lON`V!Kq`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!iN`!i!j!Ls!j;'SN`;'S;=`!&v<%lON`V!Lz`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!tN`!t!u!M|!u;'SN`;'S;=`!&v<%lON`V!NT`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d# V!d;'SN`;'S;=`!&v<%lON`V# ^`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!vN`!v!w!Dh!w;'SN`;'S;=`!&v<%lON`V#!g`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!wN`!w!x##i!x;'SN`;'S;=`!&v<%lON`V##p`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h#$r!h;'SN`;'S;=`!&v<%lON`V#$y`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!tN`!t!u#%{!u;'SN`;'S;=`!&v<%lON`V#&S`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!{N`!{!|!Eq!|;'SN`;'S;=`!&v<%lON`V#']bQR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d#(e!d!gN`!g!h#*w!h;'SN`;'S;=`!&v<%lON`V#(l`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!dN`!d!e#)n!e;'SN`;'S;=`!&v<%lON`V#)u`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!nN`!n!o!Dh!o;'SN`;'S;=`!&v<%lON`V#+O`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!uN`!u!v#,Q!v;'SN`;'S;=`!&v<%lON`V#,X`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!vN`!v!w#-Z!w;'SN`;'S;=`!&v<%lON`V#-b`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!fN`!f!g#.d!g;'SN`;'S;=`!&v<%lON`V#.k`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d#/m!d;'SN`;'S;=`!&v<%lON`V#/t`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!vN`!v!w#0v!w;'SN`;'S;=`!&v<%lON`V#0}`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d!Eq!d;'SN`;'S;=`!&v<%lON`V#2U]_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{#2}{;'S#Y;'S;=`'q<%lO#YV#3Sj_QOX#4tXY#8uYZ#8uZ]#4t]^#5r^p#4tpq#8uqt#4ttu#5ruz#4tz{#6{{!P#4t!P!Q#Js!Q!d#4t!d!e$ p!e!g#4t!g!h$*_!h!o#4t!o!p$-k!p!s#4t!s!t$3P!t!v#4t!v!w$7a!w;'S#4t;'S;=`#8o<%lO#4tV#4y]_QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{;'S#4t;'S;=`#8o<%lO#4tV#5uTOz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#6XVOz#5rz{#6U{!P#5r!P!Q#6n!Q;'S#5r;'S;=`#6u<%lO#5rV#6uORRnSV#6xP;=`<%l#5rV#7Q__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!P#4t!P!Q#8P!Q;'S#4t;'S;=`#8o<%lO#4tV#8YVRRnS_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PV#8rP;=`<%l#4tV#8xdOX#5rXY#8uYZ#8uZp#5rpq#8uqz#5rz{#6U{!d#5r!d!e#:W!e!g#5r!g!h#?o!h!o#5r!o!p#AZ!p!s#5r!s!t#Cw!t!v#5r!v!w#E{!w;'S#5r;'S;=`#6u<%lO#5rV#:ZVOz#5rz{#6U{!c#5r!c!d#:p!d;'S#5r;'S;=`#6u<%lO#5rV#:sVOz#5rz{#6U{!u#5r!u!v#;Y!v;'S#5r;'S;=`#6u<%lO#5rV#;]VOz#5rz{#6U{!g#5r!g!h#;r!h;'S#5r;'S;=`#6u<%lO#5rV#;uVOz#5rz{#6U{!n#5r!n!o#<[!o;'S#5r;'S;=`#6u<%lO#5rV#<_VOz#5rz{#6U{!k#5r!k!l#<t!l;'S#5r;'S;=`#6u<%lO#5rV#<wVOz#5rz{#6U{!p#5r!p!q#=^!q;'S#5r;'S;=`#6u<%lO#5rV#=aVOz#5rz{#6U{!g#5r!g!h#=v!h;'S#5r;'S;=`#6u<%lO#5rV#=yYOX#5rXY#>iYZ#?ZZp#5rpq#>iqz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#>nXUROX#5rXY#>iYp#5rpq#>iqz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#?`TUROz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#?rVOz#5rz{#6U{!z#5r!z!{#@X!{;'S#5r;'S;=`#6u<%lO#5rV#@[VOz#5rz{#6U{!g#5r!g!h#@q!h;'S#5r;'S;=`#6u<%lO#5rV#@tVOz#5rz{#6U{!e#5r!e!f#=v!f;'S#5r;'S;=`#6u<%lO#5rV#A^VOz#5rz{#6U{!k#5r!k!l#As!l;'S#5r;'S;=`#6u<%lO#5rV#AvVOz#5rz{#6U{!i#5r!i!j#B]!j;'S#5r;'S;=`#6u<%lO#5rV#B`VOz#5rz{#6U{!t#5r!t!u#Bu!u;'S#5r;'S;=`#6u<%lO#5rV#BxVOz#5rz{#6U{!c#5r!c!d#C_!d;'S#5r;'S;=`#6u<%lO#5rV#CbVOz#5rz{#6U{!v#5r!v!w#=^!w;'S#5r;'S;=`#6u<%lO#5rV#CzVOz#5rz{#6U{!w#5r!w!x#Da!x;'S#5r;'S;=`#6u<%lO#5rV#DdVOz#5rz{#6U{!g#5r!g!h#Dy!h;'S#5r;'S;=`#6u<%lO#5rV#D|VOz#5rz{#6U{!t#5r!t!u#Ec!u;'S#5r;'S;=`#6u<%lO#5rV#EfVOz#5rz{#6U{!{#5r!{!|#=v!|;'S#5r;'S;=`#6u<%lO#5rV#FOXOz#5rz{#6U{!c#5r!c!d#Fk!d!g#5r!g!h#Gm!h;'S#5r;'S;=`#6u<%lO#5rV#FnVOz#5rz{#6U{!d#5r!d!e#GT!e;'S#5r;'S;=`#6u<%lO#5rV#GWVOz#5rz{#6U{!n#5r!n!o#=^!o;'S#5r;'S;=`#6u<%lO#5rV#GpVOz#5rz{#6U{!u#5r!u!v#HV!v;'S#5r;'S;=`#6u<%lO#5rV#HYVOz#5rz{#6U{!v#5r!v!w#Ho!w;'S#5r;'S;=`#6u<%lO#5rV#HrVOz#5rz{#6U{!f#5r!f!g#IX!g;'S#5r;'S;=`#6u<%lO#5rV#I[VOz#5rz{#6U{!c#5r!c!d#Iq!d;'S#5r;'S;=`#6u<%lO#5rV#ItVOz#5rz{#6U{!v#5r!v!w#JZ!w;'S#5r;'S;=`#6u<%lO#5rV#J^VOz#5rz{#6U{!c#5r!c!d#=v!d;'S#5r;'S;=`#6u<%lO#5rV#Jz]nS_QOX#KsXZ#LqZ]#Ks]^#Lq^p#Kspq#Lqqt#Kstu#Lquz#Ksz{#Mx{;'S#Ks;'S;=`$ j<%lO#KsR#Kx]_QOX#KsXZ#LqZ]#Ks]^#Lq^p#Kspq#Lqqt#Kstu#Lquz#Ksz{#Mx{;'S#Ks;'S;=`$ j<%lO#KsR#LtTOz#Lqz{#MT{;'S#Lq;'S;=`#Mr<%lO#LqR#MWVOz#Lqz{#MT{!P#Lq!P!Q#Mm!Q;'S#Lq;'S;=`#Mr<%lO#LqR#MrORRR#MuP;=`<%l#LqR#M}__QOX#KsXZ#LqZ]#Ks]^#Lq^p#Kspq#Lqqt#Kstu#Lquz#Ksz{#Mx{!P#Ks!P!Q#N|!Q;'S#Ks;'S;=`$ j<%lO#KsR$ TVRR_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PR$ mP;=`<%l#KsV$ u__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$!t!d;'S#4t;'S;=`#8o<%lO#4tV$!y__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!u#4t!u!v$#x!v;'S#4t;'S;=`#8o<%lO#4tV$#}__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$$|!h;'S#4t;'S;=`#8o<%lO#4tV$%R__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!n#4t!n!o$&Q!o;'S#4t;'S;=`#8o<%lO#4tV$&V__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!k#4t!k!l$'U!l;'S#4t;'S;=`#8o<%lO#4tV$'Z__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!p#4t!p!q$(Y!q;'S#4t;'S;=`#8o<%lO#4tV$(___QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$)^!h;'S#4t;'S;=`#8o<%lO#4tV$)c^_QOX#4tXY#>iYZ#?ZZ]#4t]^#5r^p#4tpq#>iqt#4ttu#5ruz#4tz{#6{{;'S#4t;'S;=`#8o<%lO#4tV$*d__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!z#4t!z!{$+c!{;'S#4t;'S;=`#8o<%lO#4tV$+h__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$,g!h;'S#4t;'S;=`#8o<%lO#4tV$,l__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!e#4t!e!f$)^!f;'S#4t;'S;=`#8o<%lO#4tV$-p__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!k#4t!k!l$.o!l;'S#4t;'S;=`#8o<%lO#4tV$.t__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!i#4t!i!j$/s!j;'S#4t;'S;=`#8o<%lO#4tV$/x__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!t#4t!t!u$0w!u;'S#4t;'S;=`#8o<%lO#4tV$0|__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$1{!d;'S#4t;'S;=`#8o<%lO#4tV$2Q__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!v#4t!v!w$(Y!w;'S#4t;'S;=`#8o<%lO#4tV$3U__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!w#4t!w!x$4T!x;'S#4t;'S;=`#8o<%lO#4tV$4Y__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$5X!h;'S#4t;'S;=`#8o<%lO#4tV$5^__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!t#4t!t!u$6]!u;'S#4t;'S;=`#8o<%lO#4tV$6b__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!{#4t!{!|$)^!|;'S#4t;'S;=`#8o<%lO#4tV$7fa_QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$8k!d!g#4t!g!h$:s!h;'S#4t;'S;=`#8o<%lO#4tV$8p__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!d#4t!d!e$9o!e;'S#4t;'S;=`#8o<%lO#4tV$9t__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!n#4t!n!o$(Y!o;'S#4t;'S;=`#8o<%lO#4tV$:x__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!u#4t!u!v$;w!v;'S#4t;'S;=`#8o<%lO#4tV$;|__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!v#4t!v!w$<{!w;'S#4t;'S;=`#8o<%lO#4tV$=Q__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!f#4t!f!g$>P!g;'S#4t;'S;=`#8o<%lO#4tV$>U__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$?T!d;'S#4t;'S;=`#8o<%lO#4tV$?Y__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!v#4t!v!w$@X!w;'S#4t;'S;=`#8o<%lO#4tV$@^__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$)^!d;'S#4t;'S;=`#8o<%lO#4tV$AdeVP_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$A]![!c#Y!c!}$A]!}#R#Y#R#S$A]#S#T#Y#T#o$A]#o;'S#Y;'S;=`'q<%lO#Y~$Bze_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$D]![!c#Y!c!}$D]!}#R#Y#R#S$D]#S#T#Y#T#o$D]#o;'S#Y;'S;=`'q<%lO#Y~$DdeW~_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$D]![!c#Y!c!}$D]!}#R#Y#R#S$D]#S#T#Y#T#o$D]#o;'S#Y;'S;=`'q<%lO#YV$E|]qP_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU$Fz__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#g#Y#g#h$Gy#h;'S#Y;'S;=`'q<%lO#YU$HO__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#X#Y#X#Y$H}#Y;'S#Y;'S;=`'q<%lO#YU$IS__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#h#Y#h#i$JR#i;'S#Y;'S;=`'q<%lO#YU$JY]pQ_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#Y",
736
+ tokenData: "$NX~RqOX#YXY'wYZ(iZ]#Y]^$W^p#Ypq'wqr#Yrs(}st#Ytu6^uw#Ywx9[xz#Yz{%_{}#Y}!OKi!O!P#Y!P!Q#2P!Q![$A]![!]$Bu!]!_#Y!_!`$H{!`!b#Y!b!c$I{!c!}$A]!}#R#Y#R#S$A]#S#T#Y#T#o$A]#o;'S#Y;'S;=`'q<%lO#YU#_]_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YS$ZTOz$Wz{$j{;'S$W;'S;=`%X<%lO$WS$mVOz$Wz{$j{!P$W!P!Q%S!Q;'S$W;'S;=`%X<%lO$WS%XOnSS%[P;=`<%l$WU%d__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!P#Y!P!Q&c!Q;'S#Y;'S;=`'q<%lO#YU&jVnS_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'UV_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ'nP;=`<%l'PU'tP;=`<%l#Y~'|Xj~OX$WXY'wYp$Wpq'wqz$Wz{$j{;'S$W;'S;=`%X<%lO$W~(nTk~Oz$Wz{$j{;'S$W;'S;=`%X<%lO$WU)Sb_QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U*_ZOY*[YZ$WZr*[rs+Qsz*[z{+f{#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U+VT]QOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU+i]OY*[YZ$WZr*[rs+Qsz*[z{+f{!P*[!P!Q,b!Q#O*[#O#P.Z#P;'S*[;'S;=`.s<%lO*[U,gWnSOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-SWOY-PZr-Prs-ls#O-P#O#P-q#P;'S-P;'S;=`.T<%lO-PQ-qO]QQ-tTOY-PYZ-PZ;'S-P;'S;=`.T<%lO-PQ.WP;=`<%l-PU.^VOY*[YZ*[Zz*[z{+f{;'S*[;'S;=`.s<%lO*[U.vP;=`<%l*[U/Q]]Q_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU0Od_QOX(}XY*[YZ$WZ](}]^*[^p(}pq*[qr(}rs.yst(}tu*[uz(}z{/y{!P(}!P!Q1^!Q#O(}#O#P5V#P;'S(};'S;=`6W<%lO(}U1e_nS_QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ2i__QOX2dXY-PZ]2d]^-P^p2dpq-Pqr2drs3hst2dtu-Pu#O2d#O#P4U#P;'S2d;'S;=`5P<%lO2dQ3oV]Q_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQ4Z[_QOX2dXY-PYZ-PZ]2d]^-P^p2dpq-Pqt2dtu-Pu;'S2d;'S;=`5P<%lO2dQ5SP;=`<%l2dU5[^_QOX(}XY*[YZ*[Z](}]^*[^p(}pq*[qt(}tu*[uz(}z{/y{;'S(};'S;=`6W<%lO(}U6ZP;=`<%l(}U6cV_QOz$Wz{$j{#o$W#o#p6x#p;'S$W;'S;=`%X<%lO$WU6{]Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o;'S$W;'S;=`%X<%lO$WU7w_Oz$Wz{$j{!Q$W!Q![7t![!c$W!c!}7t!}#R$W#R#S7t#S#T$W#T#o7t#o#q$W#q#r8v#r;'S$W;'S;=`%X<%lO$WU8{TaQOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU9ab_QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[U:lZOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU;dT^QOz$Wz{$j{;'S$W;'S;=`%X<%lO$WU;v]OY:iYZ$WZw:iwx;_xz:iz{;s{!P:i!P!Q<o!Q#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU<tWnSOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q=aWOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>OO^QQ>RXOY=^YZ=^Zw=^wx>nx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q>sW^QOY=^Zw=^wx=yx#O=^#O#P>O#P;'S=^;'S;=`?]<%lO=^Q?`P;=`<%l=^U?fZOY:iYZ:iZw:iwx@Xxz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iU@^Z^QOY:iYZ$WZw:iwx;_xz:iz{;s{#O:i#O#P?c#P;'S:i;'S;=`AP<%lO:iUASP;=`<%l:iUA^]^Q_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YUB[d_QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{!P9[!P!QCj!Q#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UCq_nS_QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQDu__QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQE{V^Q_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PQFg`_QOXDpXY=^YZ=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxGix#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQGp_^Q_QOXDpXY=^Z]Dp]^=^^pDppq=^qtDptu=^uwDpwxEtx#ODp#O#PFb#P;'SDp;'S;=`Ho<%lODpQHrP;=`<%lDpUHzb_QOX9[XY:iYZ:iZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxJSxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UJZb^Q_QOX9[XY:iYZ$WZ]9[]^:i^p9[pq:iqt9[tu:iuw9[wxAVxz9[z{BV{#O9[#O#PHu#P;'S9[;'S;=`Kc<%lO9[UKfP;=`<%l9[VKn__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{}#Y}!OLm!O;'S#Y;'S;=`'q<%lO#YVLthQR_QOXN`XY!&|YZ$WZ]N`]^! c^pN`pq!&|qtN`tu! cuzN`z{!#q{!dN`!d!e!=`!e!gN`!g!h!Ft!h!oN`!o!p!Ja!p!sN`!s!t#!`!t!vN`!v!w#'U!w;'SN`;'S;=`!&v<%lON`VNg^QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{;'SN`;'S;=`!&v<%lON`V! hVQROY! cYZ$WZz! cz{! }{;'S! c;'S;=`!#k<%lO! cV!!SXQROY! cYZ$WZz! cz{! }{!P! c!P!Q!!o!Q;'S! c;'S;=`!#k<%lO! cV!!vSnSQROY!#SZ;'S!#S;'S;=`!#e<%lO!#SR!#XSQROY!#SZ;'S!#S;'S;=`!#e<%lO!#SR!#hP;=`<%l!#SV!#nP;=`<%l! cV!#x`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!PN`!P!Q!$z!Q;'SN`;'S;=`!&v<%lON`V!%TZnSQR_QOX!%vXY!#SZ]!%v]^!#S^p!%vpq!#Sqt!%vtu!#Su;'S!%v;'S;=`!&p<%lO!%vR!%}ZQR_QOX!%vXY!#SZ]!%v]^!#S^p!%vpq!#Sqt!%vtu!#Su;'S!%v;'S;=`!&p<%lO!%vR!&sP;=`<%l!%vV!&yP;=`<%lN`V!'RdQROX! cXY!&|YZ$WZp! cpq!&|qz! cz{! }{!d! c!d!e!(a!e!g! c!g!h!.l!h!o! c!o!p!0p!p!s! c!s!t!4W!t!v! c!v!w!6|!w;'S! c;'S;=`!#k<%lO! cV!(fXQROY! cYZ$WZz! cz{! }{!c! c!c!d!)R!d;'S! c;'S;=`!#k<%lO! cV!)WXQROY! cYZ$WZz! cz{! }{!u! c!u!v!)s!v;'S! c;'S;=`!#k<%lO! cV!)xXQROY! cYZ$WZz! cz{! }{!g! c!g!h!*e!h;'S! c;'S;=`!#k<%lO! cV!*jXQROY! cYZ$WZz! cz{! }{!n! c!n!o!+V!o;'S! c;'S;=`!#k<%lO! cV!+[XQROY! cYZ$WZz! cz{! }{!k! c!k!l!+w!l;'S! c;'S;=`!#k<%lO! cV!+|XQROY! cYZ$WZz! cz{! }{!p! c!p!q!,i!q;'S! c;'S;=`!#k<%lO! cV!,nXQROY! cYZ$WZz! cz{! }{!g! c!g!h!-Z!h;'S! c;'S;=`!#k<%lO! cV!-`YQROX! cXY!.OYZ$WZp! cpq!.Oqz! cz{! }{;'S! c;'S;=`!#k<%lO! cV!.VVYRQROY! cYZ$WZz! cz{! }{;'S! c;'S;=`!#k<%lO! cV!.qXQROY! cYZ$WZz! cz{! }{!z! c!z!{!/^!{;'S! c;'S;=`!#k<%lO! cV!/cXQROY! cYZ$WZz! cz{! }{!g! c!g!h!0O!h;'S! c;'S;=`!#k<%lO! cV!0TXQROY! cYZ$WZz! cz{! }{!e! c!e!f!-Z!f;'S! c;'S;=`!#k<%lO! cV!0uXQROY! cYZ$WZz! cz{! }{!k! c!k!l!1b!l;'S! c;'S;=`!#k<%lO! cV!1gXQROY! cYZ$WZz! cz{! }{!i! c!i!j!2S!j;'S! c;'S;=`!#k<%lO! cV!2XXQROY! cYZ$WZz! cz{! }{!t! c!t!u!2t!u;'S! c;'S;=`!#k<%lO! cV!2yXQROY! cYZ$WZz! cz{! }{!c! c!c!d!3f!d;'S! c;'S;=`!#k<%lO! cV!3kXQROY! cYZ$WZz! cz{! }{!v! c!v!w!,i!w;'S! c;'S;=`!#k<%lO! cV!4]XQROY! cYZ$WZz! cz{! }{!w! c!w!x!4x!x;'S! c;'S;=`!#k<%lO! cV!4}XQROY! cYZ$WZz! cz{! }{!g! c!g!h!5j!h;'S! c;'S;=`!#k<%lO! cV!5oXQROY! cYZ$WZz! cz{! }{!t! c!t!u!6[!u;'S! c;'S;=`!#k<%lO! cV!6aXQROY! cYZ$WZz! cz{! }{!{! c!{!|!-Z!|;'S! c;'S;=`!#k<%lO! cV!7RZQROY! cYZ$WZz! cz{! }{!c! c!c!d!7t!d!g! c!g!h!9W!h;'S! c;'S;=`!#k<%lO! cV!7yXQROY! cYZ$WZz! cz{! }{!d! c!d!e!8f!e;'S! c;'S;=`!#k<%lO! cV!8kXQROY! cYZ$WZz! cz{! }{!n! c!n!o!,i!o;'S! c;'S;=`!#k<%lO! cV!9]XQROY! cYZ$WZz! cz{! }{!u! c!u!v!9x!v;'S! c;'S;=`!#k<%lO! cV!9}XQROY! cYZ$WZz! cz{! }{!v! c!v!w!:j!w;'S! c;'S;=`!#k<%lO! cV!:oXQROY! cYZ$WZz! cz{! }{!f! c!f!g!;[!g;'S! c;'S;=`!#k<%lO! cV!;aXQROY! cYZ$WZz! cz{! }{!c! c!c!d!;|!d;'S! c;'S;=`!#k<%lO! cV!<RXQROY! cYZ$WZz! cz{! }{!v! c!v!w!<n!w;'S! c;'S;=`!#k<%lO! cV!<sXQROY! cYZ$WZz! cz{! }{!c! c!c!d!-Z!d;'S! c;'S;=`!#k<%lO! cV!=g`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d!>i!d;'SN`;'S;=`!&v<%lON`V!>p`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!uN`!u!v!?r!v;'SN`;'S;=`!&v<%lON`V!?y`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h!@{!h;'SN`;'S;=`!&v<%lON`V!AS`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!nN`!n!o!BU!o;'SN`;'S;=`!&v<%lON`V!B]`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!kN`!k!l!C_!l;'SN`;'S;=`!&v<%lON`V!Cf`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!pN`!p!q!Dh!q;'SN`;'S;=`!&v<%lON`V!Do`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h!Eq!h;'SN`;'S;=`!&v<%lON`V!Ex^QR_QOXN`XY!.OYZ$WZ]N`]^! c^pN`pq!.OqtN`tu! cuzN`z{!#q{;'SN`;'S;=`!&v<%lON`V!F{`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!zN`!z!{!G}!{;'SN`;'S;=`!&v<%lON`V!HU`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h!IW!h;'SN`;'S;=`!&v<%lON`V!I_`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!eN`!e!f!Eq!f;'SN`;'S;=`!&v<%lON`V!Jh`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!kN`!k!l!Kj!l;'SN`;'S;=`!&v<%lON`V!Kq`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!iN`!i!j!Ls!j;'SN`;'S;=`!&v<%lON`V!Lz`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!tN`!t!u!M|!u;'SN`;'S;=`!&v<%lON`V!NT`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d# V!d;'SN`;'S;=`!&v<%lON`V# ^`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!vN`!v!w!Dh!w;'SN`;'S;=`!&v<%lON`V#!g`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!wN`!w!x##i!x;'SN`;'S;=`!&v<%lON`V##p`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!gN`!g!h#$r!h;'SN`;'S;=`!&v<%lON`V#$y`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!tN`!t!u#%{!u;'SN`;'S;=`!&v<%lON`V#&S`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!{N`!{!|!Eq!|;'SN`;'S;=`!&v<%lON`V#']bQR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d#(e!d!gN`!g!h#*w!h;'SN`;'S;=`!&v<%lON`V#(l`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!dN`!d!e#)n!e;'SN`;'S;=`!&v<%lON`V#)u`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!nN`!n!o!Dh!o;'SN`;'S;=`!&v<%lON`V#+O`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!uN`!u!v#,Q!v;'SN`;'S;=`!&v<%lON`V#,X`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!vN`!v!w#-Z!w;'SN`;'S;=`!&v<%lON`V#-b`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!fN`!f!g#.d!g;'SN`;'S;=`!&v<%lON`V#.k`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d#/m!d;'SN`;'S;=`!&v<%lON`V#/t`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!vN`!v!w#0v!w;'SN`;'S;=`!&v<%lON`V#0}`QR_QOXN`XY! cYZ$WZ]N`]^! c^pN`pq! cqtN`tu! cuzN`z{!#q{!cN`!c!d!Eq!d;'SN`;'S;=`!&v<%lON`V#2U]_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{#2}{;'S#Y;'S;=`'q<%lO#YV#3Sj_QOX#4tXY#8uYZ#8uZ]#4t]^#5r^p#4tpq#8uqt#4ttu#5ruz#4tz{#6{{!P#4t!P!Q#Js!Q!d#4t!d!e$ p!e!g#4t!g!h$*_!h!o#4t!o!p$-k!p!s#4t!s!t$3P!t!v#4t!v!w$7a!w;'S#4t;'S;=`#8o<%lO#4tV#4y]_QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{;'S#4t;'S;=`#8o<%lO#4tV#5uTOz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#6XVOz#5rz{#6U{!P#5r!P!Q#6n!Q;'S#5r;'S;=`#6u<%lO#5rV#6uORRnSV#6xP;=`<%l#5rV#7Q__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!P#4t!P!Q#8P!Q;'S#4t;'S;=`#8o<%lO#4tV#8YVRRnS_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PV#8rP;=`<%l#4tV#8xdOX#5rXY#8uYZ#8uZp#5rpq#8uqz#5rz{#6U{!d#5r!d!e#:W!e!g#5r!g!h#?o!h!o#5r!o!p#AZ!p!s#5r!s!t#Cw!t!v#5r!v!w#E{!w;'S#5r;'S;=`#6u<%lO#5rV#:ZVOz#5rz{#6U{!c#5r!c!d#:p!d;'S#5r;'S;=`#6u<%lO#5rV#:sVOz#5rz{#6U{!u#5r!u!v#;Y!v;'S#5r;'S;=`#6u<%lO#5rV#;]VOz#5rz{#6U{!g#5r!g!h#;r!h;'S#5r;'S;=`#6u<%lO#5rV#;uVOz#5rz{#6U{!n#5r!n!o#<[!o;'S#5r;'S;=`#6u<%lO#5rV#<_VOz#5rz{#6U{!k#5r!k!l#<t!l;'S#5r;'S;=`#6u<%lO#5rV#<wVOz#5rz{#6U{!p#5r!p!q#=^!q;'S#5r;'S;=`#6u<%lO#5rV#=aVOz#5rz{#6U{!g#5r!g!h#=v!h;'S#5r;'S;=`#6u<%lO#5rV#=yYOX#5rXY#>iYZ#?ZZp#5rpq#>iqz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#>nXUROX#5rXY#>iYp#5rpq#>iqz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#?`TUROz#5rz{#6U{;'S#5r;'S;=`#6u<%lO#5rV#?rVOz#5rz{#6U{!z#5r!z!{#@X!{;'S#5r;'S;=`#6u<%lO#5rV#@[VOz#5rz{#6U{!g#5r!g!h#@q!h;'S#5r;'S;=`#6u<%lO#5rV#@tVOz#5rz{#6U{!e#5r!e!f#=v!f;'S#5r;'S;=`#6u<%lO#5rV#A^VOz#5rz{#6U{!k#5r!k!l#As!l;'S#5r;'S;=`#6u<%lO#5rV#AvVOz#5rz{#6U{!i#5r!i!j#B]!j;'S#5r;'S;=`#6u<%lO#5rV#B`VOz#5rz{#6U{!t#5r!t!u#Bu!u;'S#5r;'S;=`#6u<%lO#5rV#BxVOz#5rz{#6U{!c#5r!c!d#C_!d;'S#5r;'S;=`#6u<%lO#5rV#CbVOz#5rz{#6U{!v#5r!v!w#=^!w;'S#5r;'S;=`#6u<%lO#5rV#CzVOz#5rz{#6U{!w#5r!w!x#Da!x;'S#5r;'S;=`#6u<%lO#5rV#DdVOz#5rz{#6U{!g#5r!g!h#Dy!h;'S#5r;'S;=`#6u<%lO#5rV#D|VOz#5rz{#6U{!t#5r!t!u#Ec!u;'S#5r;'S;=`#6u<%lO#5rV#EfVOz#5rz{#6U{!{#5r!{!|#=v!|;'S#5r;'S;=`#6u<%lO#5rV#FOXOz#5rz{#6U{!c#5r!c!d#Fk!d!g#5r!g!h#Gm!h;'S#5r;'S;=`#6u<%lO#5rV#FnVOz#5rz{#6U{!d#5r!d!e#GT!e;'S#5r;'S;=`#6u<%lO#5rV#GWVOz#5rz{#6U{!n#5r!n!o#=^!o;'S#5r;'S;=`#6u<%lO#5rV#GpVOz#5rz{#6U{!u#5r!u!v#HV!v;'S#5r;'S;=`#6u<%lO#5rV#HYVOz#5rz{#6U{!v#5r!v!w#Ho!w;'S#5r;'S;=`#6u<%lO#5rV#HrVOz#5rz{#6U{!f#5r!f!g#IX!g;'S#5r;'S;=`#6u<%lO#5rV#I[VOz#5rz{#6U{!c#5r!c!d#Iq!d;'S#5r;'S;=`#6u<%lO#5rV#ItVOz#5rz{#6U{!v#5r!v!w#JZ!w;'S#5r;'S;=`#6u<%lO#5rV#J^VOz#5rz{#6U{!c#5r!c!d#=v!d;'S#5r;'S;=`#6u<%lO#5rV#Jz]nS_QOX#KsXZ#LqZ]#Ks]^#Lq^p#Kspq#Lqqt#Kstu#Lquz#Ksz{#Mx{;'S#Ks;'S;=`$ j<%lO#KsR#Kx]_QOX#KsXZ#LqZ]#Ks]^#Lq^p#Kspq#Lqqt#Kstu#Lquz#Ksz{#Mx{;'S#Ks;'S;=`$ j<%lO#KsR#LtTOz#Lqz{#MT{;'S#Lq;'S;=`#Mr<%lO#LqR#MWVOz#Lqz{#MT{!P#Lq!P!Q#Mm!Q;'S#Lq;'S;=`#Mr<%lO#LqR#MrORRR#MuP;=`<%l#LqR#M}__QOX#KsXZ#LqZ]#Ks]^#Lq^p#Kspq#Lqqt#Kstu#Lquz#Ksz{#Mx{!P#Ks!P!Q#N|!Q;'S#Ks;'S;=`$ j<%lO#KsR$ TVRR_QOX'PZ]'P^p'Pqt'Pu;'S'P;'S;=`'k<%lO'PR$ mP;=`<%l#KsV$ u__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$!t!d;'S#4t;'S;=`#8o<%lO#4tV$!y__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!u#4t!u!v$#x!v;'S#4t;'S;=`#8o<%lO#4tV$#}__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$$|!h;'S#4t;'S;=`#8o<%lO#4tV$%R__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!n#4t!n!o$&Q!o;'S#4t;'S;=`#8o<%lO#4tV$&V__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!k#4t!k!l$'U!l;'S#4t;'S;=`#8o<%lO#4tV$'Z__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!p#4t!p!q$(Y!q;'S#4t;'S;=`#8o<%lO#4tV$(___QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$)^!h;'S#4t;'S;=`#8o<%lO#4tV$)c^_QOX#4tXY#>iYZ#?ZZ]#4t]^#5r^p#4tpq#>iqt#4ttu#5ruz#4tz{#6{{;'S#4t;'S;=`#8o<%lO#4tV$*d__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!z#4t!z!{$+c!{;'S#4t;'S;=`#8o<%lO#4tV$+h__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$,g!h;'S#4t;'S;=`#8o<%lO#4tV$,l__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!e#4t!e!f$)^!f;'S#4t;'S;=`#8o<%lO#4tV$-p__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!k#4t!k!l$.o!l;'S#4t;'S;=`#8o<%lO#4tV$.t__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!i#4t!i!j$/s!j;'S#4t;'S;=`#8o<%lO#4tV$/x__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!t#4t!t!u$0w!u;'S#4t;'S;=`#8o<%lO#4tV$0|__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$1{!d;'S#4t;'S;=`#8o<%lO#4tV$2Q__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!v#4t!v!w$(Y!w;'S#4t;'S;=`#8o<%lO#4tV$3U__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!w#4t!w!x$4T!x;'S#4t;'S;=`#8o<%lO#4tV$4Y__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!g#4t!g!h$5X!h;'S#4t;'S;=`#8o<%lO#4tV$5^__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!t#4t!t!u$6]!u;'S#4t;'S;=`#8o<%lO#4tV$6b__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!{#4t!{!|$)^!|;'S#4t;'S;=`#8o<%lO#4tV$7fa_QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$8k!d!g#4t!g!h$:s!h;'S#4t;'S;=`#8o<%lO#4tV$8p__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!d#4t!d!e$9o!e;'S#4t;'S;=`#8o<%lO#4tV$9t__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!n#4t!n!o$(Y!o;'S#4t;'S;=`#8o<%lO#4tV$:x__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!u#4t!u!v$;w!v;'S#4t;'S;=`#8o<%lO#4tV$;|__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!v#4t!v!w$<{!w;'S#4t;'S;=`#8o<%lO#4tV$=Q__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!f#4t!f!g$>P!g;'S#4t;'S;=`#8o<%lO#4tV$>U__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$?T!d;'S#4t;'S;=`#8o<%lO#4tV$?Y__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!v#4t!v!w$@X!w;'S#4t;'S;=`#8o<%lO#4tV$@^__QOX#4tXZ#5rZ]#4t]^#5r^p#4tpq#5rqt#4ttu#5ruz#4tz{#6{{!c#4t!c!d$)^!d;'S#4t;'S;=`#8o<%lO#4tV$AdeVP_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$A]![!c#Y!c!}$A]!}#R#Y#R#S$A]#S#T#Y#T#o$A]#o;'S#Y;'S;=`'q<%lO#Y~$Bze_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$D]![!c#Y!c!}$D]!}#R#Y#R#S$D]#S#T#Y#T#o$D]#o;'S#Y;'S;=`'q<%lO#Y~$DdgW~_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$D]![!_#Y!_!`$E{!`!c#Y!c!}$D]!}#R#Y#R#S$D]#S#T#Y#T#o$D]#o;'S#Y;'S;=`'q<%lO#Y~$FQe_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$Gc![!c#Y!c!}$Gc!}#R#Y#R#S$Gc#S#T#Y#T#o$Gc#o;'S#Y;'S;=`'q<%lO#Y~$GjeW~_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{!Q#Y!Q![$Gc![!c#Y!c!}$Gc!}#R#Y#R#S$Gc#S#T#Y#T#o$Gc#o;'S#Y;'S;=`'q<%lO#YV$IS]qP_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#YU$JQ__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#g#Y#g#h$KP#h;'S#Y;'S;=`'q<%lO#YU$KU__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#X#Y#X#Y$LT#Y;'S#Y;'S;=`'q<%lO#YU$LY__QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{#h#Y#h#i$MX#i;'S#Y;'S;=`'q<%lO#YU$M`]pQ_QOX#YXZ$WZ]#Y]^$W^p#Ypq$Wqt#Ytu$Wuz#Yz{%_{;'S#Y;'S;=`'q<%lO#Y",
728
737
  tokenizers: [
729
738
  0,
730
739
  1,
@@ -774,6 +783,17 @@ var SQLQuery = class {
774
783
  allColumns;
775
784
  /** Database-reported parameter types (variable name → SQL type), set by database adapters */
776
785
  parameterTypes;
786
+ /** Explicit row-type name from `:result=Name` modifier, when present. */
787
+ resultTypeOverride;
788
+ /**
789
+ * Name of the postgres `source` this block targets, from a `:source=name`
790
+ * modifier on a BASELINE block. Such blocks define the schema of an external
791
+ * postgres source and run natively against that source's container during
792
+ * generation (not against the DuckDB introspection connection).
793
+ */
794
+ sourceTarget;
795
+ /** Final row-type identifier assigned by assignResultTypeNames (after introspection). */
796
+ resultTypeName;
777
797
  constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, isBatch, variables, config, line) {
778
798
  this.filename = filename;
779
799
  this.id = id;
@@ -887,6 +907,9 @@ function parseSQLQueries(filePath, extraVariables) {
887
907
  const isOne = modifiers.includes(":one");
888
908
  const isPluck = modifiers.includes(":pluck");
889
909
  const isBatch = modifiers.includes(":batch");
910
+ const resultTypeOverride = modifiers.find((m) => m.startsWith(":result="))?.slice(8);
911
+ const sourceTarget = modifiers.find((m) => m.startsWith(":source="))?.slice(8);
912
+ if (sourceTarget && queryType !== "BASELINE") throw SqgError.inQuery(`The ':source=' modifier is only valid on BASELINE blocks, not ${queryType}`, "SQL_PARSE_ERROR", name, filePath, { suggestion: "Move the schema for a postgres source into a '-- BASELINE <name> :source=<source>' block" });
890
913
  let configStr = getStr("Config", true);
891
914
  if (configStr?.endsWith("*/")) configStr = configStr.slice(0, -2);
892
915
  let config = null;
@@ -1041,6 +1064,8 @@ function parseSQLQueries(filePath, extraVariables) {
1041
1064
  config
1042
1065
  });
1043
1066
  const query = new SQLQuery(filePath, name, sqlContentStr, sql.toSqlWithAnonymousPlaceholders(), sql.toSqlWithNamedPlaceholders(), sql.toSqlWithPositionalPlaceholders(), queryType, isOne, isPluck, isBatch, variables, config, annotationLine);
1067
+ query.resultTypeOverride = resultTypeOverride;
1068
+ query.sourceTarget = sourceTarget;
1044
1069
  checkDuplicate(queryType, name);
1045
1070
  queries.push(query);
1046
1071
  consola.debug(`Added query: ${name} (${queryType})`);
@@ -1057,7 +1082,7 @@ function parseSQLQueries(filePath, extraVariables) {
1057
1082
  //#endregion
1058
1083
  //#region src/db/types.ts
1059
1084
  async function initializeDatabase(queries, execQueries, reporter) {
1060
- const baselineQueries = queries.filter((q) => q.isBaseline);
1085
+ const baselineQueries = queries.filter((q) => q.isBaseline && !q.sourceTarget);
1061
1086
  for (const query of baselineQueries) try {
1062
1087
  await execQueries(query);
1063
1088
  } catch (error) {
@@ -1113,9 +1138,17 @@ function convertType(type) {
1113
1138
  const duckdb = new class {
1114
1139
  db;
1115
1140
  connection;
1116
- async initializeDatabase(queries, reporter) {
1141
+ async initializeDatabase(queries, reporter, options) {
1117
1142
  this.db = await DuckDBInstance.create(":memory:");
1118
1143
  this.connection = await this.db.connect();
1144
+ for (const attachment of options?.attachments ?? []) {
1145
+ const sql = `ATTACH '${attachment.connectionUri}' AS ${attachment.alias} (TYPE postgres)`;
1146
+ try {
1147
+ await this.connection.run(sql);
1148
+ } catch (e) {
1149
+ throw new DatabaseError(`Failed to attach source '${attachment.alias}': ${e.message}`, "duckdb", "Check that the postgres source container started and is reachable.");
1150
+ }
1151
+ }
1119
1152
  await initializeDatabase(queries, async (query) => {
1120
1153
  try {
1121
1154
  await this.connection.run(query.rawQuery);
@@ -1325,6 +1358,7 @@ const postgres = new class {
1325
1358
  mode;
1326
1359
  dynamicTypeCache = /* @__PURE__ */ new Map();
1327
1360
  enumTypeCache = /* @__PURE__ */ new Map();
1361
+ tableOidCache = /* @__PURE__ */ new Map();
1328
1362
  async startContainer(reporter) {
1329
1363
  reporter?.onContainerStarting?.();
1330
1364
  const container = await new PostgreSqlContainer("postgres:16-alpine").withDatabase("sqg-db").withUsername("sqg").withPassword("secret").start();
@@ -1375,10 +1409,17 @@ const postgres = new class {
1375
1409
  if (enumType) return enumType;
1376
1410
  return this.getTypeName(dataTypeID);
1377
1411
  }
1412
+ async resolveTableOids(db, oids) {
1413
+ const missing = oids.filter((oid) => !this.tableOidCache.has(oid));
1414
+ if (missing.length === 0) return;
1415
+ const res = await db.query("SELECT oid::int AS oid, relname FROM pg_class WHERE oid = ANY($1)", [missing]);
1416
+ for (const row of res.rows) this.tableOidCache.set(Number(row.oid), row.relname);
1417
+ }
1378
1418
  async initializeDatabase(queries, reporter) {
1379
1419
  const externalUrl = process.env.SQG_POSTGRES_URL;
1380
1420
  this.dynamicTypeCache = /* @__PURE__ */ new Map();
1381
1421
  this.enumTypeCache = /* @__PURE__ */ new Map();
1422
+ this.tableOidCache = /* @__PURE__ */ new Map();
1382
1423
  if (externalUrl) this.mode = new ExternalDbMode(externalUrl);
1383
1424
  else {
1384
1425
  const { connectionUri, container } = await this.startContainer(reporter);
@@ -1444,11 +1485,18 @@ const postgres = new class {
1444
1485
  });
1445
1486
  consola.debug("Columns:", columnNames);
1446
1487
  consola.debug("Types:", columnTypes.map((t) => t.toString()));
1447
- query.columns = columnNames.map((name, index) => ({
1448
- name,
1449
- type: columnTypes[index],
1450
- nullable: true
1451
- }));
1488
+ const tableOids = Array.from(new Set(result.fields.map((f) => f.tableID).filter((oid) => oid && oid > 0)));
1489
+ await this.resolveTableOids(db, tableOids);
1490
+ query.columns = columnNames.map((name, index) => {
1491
+ const field = result.fields[index];
1492
+ const sourceTable = field.tableID && field.tableID > 0 ? this.tableOidCache.get(field.tableID) : void 0;
1493
+ return {
1494
+ name,
1495
+ type: columnTypes[index],
1496
+ nullable: true,
1497
+ sourceTable
1498
+ };
1499
+ });
1452
1500
  }
1453
1501
  if (query.isQuery) {
1454
1502
  if (query.isOne) return result.rows[0] || null;
@@ -1486,6 +1534,7 @@ const postgres = new class {
1486
1534
  await this.mode.close(this.db);
1487
1535
  this.dynamicTypeCache = /* @__PURE__ */ new Map();
1488
1536
  this.enumTypeCache = /* @__PURE__ */ new Map();
1537
+ this.tableOidCache = /* @__PURE__ */ new Map();
1489
1538
  }
1490
1539
  }();
1491
1540
  //#endregion
@@ -1596,7 +1645,8 @@ const sqlite = new class {
1596
1645
  return {
1597
1646
  name: col.name,
1598
1647
  type: col.type || probed.type || "unknown",
1599
- nullable: col.table ? colInfo?.pk === 0 && colInfo?.notnull === 0 : probed.nullable
1648
+ nullable: col.table ? colInfo?.pk === 0 && colInfo?.notnull === 0 : probed.nullable,
1649
+ sourceTable: col.table ?? void 0
1600
1650
  };
1601
1651
  });
1602
1652
  }
@@ -1666,13 +1716,13 @@ var TypeMapper = class {
1666
1716
  * @param path - Optional prefix path for nested type references
1667
1717
  * @returns Generated type declaration code, or empty string for primitive types
1668
1718
  */
1669
- getDeclarations(column, path = "") {
1670
- if (column.type instanceof StructType) return this.generateStructDeclaration(column, path);
1719
+ getDeclarations(column, path = "", nameOverride) {
1720
+ if (column.type instanceof StructType) return this.generateStructDeclaration(column, path, nameOverride);
1671
1721
  if (column.type instanceof ListType) return this.getDeclarations({
1672
1722
  name: column.name,
1673
1723
  type: column.type.baseType,
1674
1724
  nullable: true
1675
- }, path);
1725
+ }, path, nameOverride);
1676
1726
  return "";
1677
1727
  }
1678
1728
  };
@@ -1829,9 +1879,9 @@ var JavaTypeMapper = class JavaTypeMapper extends TypeMapper {
1829
1879
  formatStructTypeName(fieldName) {
1830
1880
  return `${pascalCase(fieldName)}Result`;
1831
1881
  }
1832
- generateStructDeclaration(column, path = "") {
1882
+ generateStructDeclaration(column, path = "", nameOverride) {
1833
1883
  if (!(column.type instanceof StructType)) throw new Error(`Expected StructType ${column}`);
1834
- const structName = this.formatStructTypeName(column.name);
1884
+ const structName = nameOverride ?? this.formatStructTypeName(column.name);
1835
1885
  const newPath = `${path}${structName}.`;
1836
1886
  const children = column.type.fields.map((field) => {
1837
1887
  return this.getDeclarations({
@@ -2025,7 +2075,7 @@ var TypeScriptTypeMapper = class extends TypeMapper {
2025
2075
  formatMapTypeName(fieldName) {
2026
2076
  return "Map";
2027
2077
  }
2028
- generateStructDeclaration(column) {
2078
+ generateStructDeclaration(column, _path, _nameOverride) {
2029
2079
  if (!(column.type instanceof StructType)) throw new Error("Expected StructType");
2030
2080
  return `interface ${this.formatStructTypeName(column.name)} {\n entries: {\n${column.type.fields.map((field) => {
2031
2081
  const fieldType = this.getTypeName({
@@ -2160,7 +2210,7 @@ var PythonTypeMapper = class PythonTypeMapper extends TypeMapper {
2160
2210
  formatMapTypeName(_fieldName) {
2161
2211
  return "dict";
2162
2212
  }
2163
- generateStructDeclaration(column, path = "") {
2213
+ generateStructDeclaration(column, path = "", _nameOverride) {
2164
2214
  if (!(column.type instanceof StructType)) throw new Error(`Expected StructType ${column}`);
2165
2215
  const structName = this.formatStructTypeName(column.name);
2166
2216
  const newPath = `${path}${structName}.`;
@@ -2231,7 +2281,7 @@ var BaseGenerator = class {
2231
2281
  ...query.columns[0],
2232
2282
  name: query.id
2233
2283
  });
2234
- return this.getClassName(`${query.id}_Result`);
2284
+ return this.getClassName(query.resultTypeName ?? `${query.id}_Result`);
2235
2285
  }
2236
2286
  getStatement(q) {
2237
2287
  return q.queryAnonymous;
@@ -2241,6 +2291,8 @@ var BaseGenerator = class {
2241
2291
  //#region src/generators/java-generator.ts
2242
2292
  var JavaGenerator = class extends BaseGenerator {
2243
2293
  engine;
2294
+ /** Query ids that should emit their row-type record declaration (set per render). */
2295
+ declareTypeOwners = /* @__PURE__ */ new Set();
2244
2296
  constructor(template, engine = "duckdb") {
2245
2297
  super(template, new JavaTypeMapper());
2246
2298
  this.template = template;
@@ -2291,7 +2343,21 @@ var JavaGenerator = class extends BaseGenerator {
2291
2343
  if (readExpr !== null) return readExpr;
2292
2344
  return this.typeMapper.parseValue(column, `rs.getObject(${idx})`, path);
2293
2345
  }
2294
- async beforeGenerate(_projectDir, _gen, _queries, _tables) {
2346
+ async beforeGenerate(_projectDir, _gen, queries, tables) {
2347
+ this.declareTypeOwners = /* @__PURE__ */ new Set();
2348
+ const seenRowTypes = /* @__PURE__ */ new Set();
2349
+ const tableRowTypes = new Set(this.supportsAppenders(this.engine) ? tables.filter((t) => t.hasAppender).map((t) => this.getClassName(`${t.id}_row`)) : []);
2350
+ for (const q of queries) {
2351
+ if (q.skipGenerateFunction) continue;
2352
+ if (!q.isQuery || q.isPluck) continue;
2353
+ if (q.columns.length === 0) continue;
2354
+ const rowTypeName = this.rowType(q);
2355
+ if (tableRowTypes.has(rowTypeName)) continue;
2356
+ if (seenRowTypes.has(rowTypeName)) continue;
2357
+ seenRowTypes.add(rowTypeName);
2358
+ this.declareTypeOwners.add(q.id);
2359
+ }
2360
+ Handlebars.registerHelper("shouldDeclareType", (queryHelper) => this.declareTypeOwners.has(queryHelper.id));
2295
2361
  Handlebars.registerHelper("isDuckDB", () => this.engine === "duckdb");
2296
2362
  Handlebars.registerHelper("isPostgres", () => this.engine === "postgres");
2297
2363
  Handlebars.registerHelper("pgBulkType", (column) => {
@@ -2314,7 +2380,9 @@ var JavaGenerator = class extends BaseGenerator {
2314
2380
  ...query.columns[0],
2315
2381
  name: query.id
2316
2382
  }, " ");
2317
- return queryHelper.typeMapper.getDeclarations(query.allColumns);
2383
+ if (!this.declareTypeOwners.has(query.id)) return "";
2384
+ const structName = this.rowType(query);
2385
+ return queryHelper.typeMapper.getDeclarations(query.allColumns, "", structName);
2318
2386
  });
2319
2387
  Handlebars.registerHelper("appenderType", (column) => {
2320
2388
  return this.typeMapper.getUnboxedTypeName(column);
@@ -2538,13 +2606,25 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
2538
2606
  async beforeGenerate(projectDir, gen, queries, tables) {
2539
2607
  const q = queries.filter((q) => q.isQuery && q.isOne || q.isMigrate);
2540
2608
  const name = `${gen.name}-jdbc`;
2541
- writeGeneratedFile(projectDir, {
2609
+ await writeGeneratedFile(projectDir, {
2542
2610
  name,
2543
2611
  generator: "java/duckdb/jdbc",
2544
2612
  output: gen.output,
2545
2613
  config: gen.config,
2546
2614
  projectName: gen.projectName
2547
2615
  }, this.javaGenerator, name, q, tables, "duckdb");
2616
+ const owners = /* @__PURE__ */ new Set();
2617
+ const seen = /* @__PURE__ */ new Set();
2618
+ for (const q of queries) {
2619
+ if (q.skipGenerateFunction) continue;
2620
+ if (!q.isQuery || q.isOne) continue;
2621
+ if (q.columns.length === 0) continue;
2622
+ const rowTypeName = this.rowType(q);
2623
+ if (seen.has(rowTypeName)) continue;
2624
+ seen.add(rowTypeName);
2625
+ owners.add(q.id);
2626
+ }
2627
+ Handlebars.registerHelper("shouldDeclareType", (queryHelper) => owners.has(queryHelper.id));
2548
2628
  }
2549
2629
  isCompatibleWith(engine) {
2550
2630
  return engine === "duckdb";
@@ -2606,7 +2686,7 @@ var JavaDuckDBArrowGenerator = class extends BaseGenerator {
2606
2686
  }
2607
2687
  rowType(query) {
2608
2688
  if (query.isOne) return this.javaGenerator.rowType(query);
2609
- return this.getClassName(`${query.id}_Result`);
2689
+ return this.getClassName(query.resultTypeName ?? `${query.id}_Result`);
2610
2690
  }
2611
2691
  };
2612
2692
  //#endregion
@@ -2666,6 +2746,19 @@ var PythonGenerator = class extends BaseGenerator {
2666
2746
  if (value.includes("\n") || value.includes("'") || value.includes("\"")) return `"""\\\n${value}"""`;
2667
2747
  return `"${value}"`;
2668
2748
  });
2749
+ Handlebars.registerHelper("sqlExpr", (queryHelper) => {
2750
+ const parts = queryHelper.sqlQueryParts;
2751
+ if (!parts.some((p) => typeof p !== "string" && p.name.startsWith("sources_"))) {
2752
+ const value = queryHelper.sqlQuery;
2753
+ if (value.includes("\n") || value.includes("'") || value.includes("\"")) return `"""\\\n${value}"""`;
2754
+ return `"${value}"`;
2755
+ }
2756
+ let out = "f\"\"\"";
2757
+ for (const part of parts) if (typeof part === "string") out += part.replace(/\\/g, "\\\\").replace(/\{/g, "{{").replace(/\}/g, "}}");
2758
+ else if (part.name.startsWith("sources_")) out += ` '{${part.name}}'`;
2759
+ else out += "?";
2760
+ return `${out}"""`;
2761
+ });
2669
2762
  Handlebars.registerHelper("pyType", (column) => {
2670
2763
  return this.getPyType(column);
2671
2764
  });
@@ -2790,6 +2883,7 @@ var TsGenerator = class extends BaseGenerator {
2790
2883
  async beforeGenerate(_projectDir, gen, _queries, _tables) {
2791
2884
  if (this.typeMapper instanceof TypeScriptTypeMapper) this.typeMapper.safeIntegers = !!gen.config?.safeIntegers;
2792
2885
  Handlebars.registerHelper("quote", (value) => this.quote(value));
2886
+ Handlebars.registerHelper("sqlExpr", (queryHelper) => this.sqlExpr(queryHelper));
2793
2887
  Handlebars.registerHelper("appendMethod", (column) => {
2794
2888
  if (column.type instanceof ListType) return "List";
2795
2889
  const typeStr = column.type?.toString().toUpperCase() || "";
@@ -2942,6 +3036,22 @@ var TsGenerator = class extends BaseGenerator {
2942
3036
  quote(value) {
2943
3037
  return value.includes("\n") || value.includes("'") ? `\`${value}\`` : `'${value}'`;
2944
3038
  }
3039
+ /**
3040
+ * Build the SQL expression for a query. Without file `sources`, this is the
3041
+ * plain quoted SQL string (unchanged). When a `${sources_x}` reference is
3042
+ * present it is interpolated into a template literal as a runtime argument
3043
+ * (the value is supplied by the caller, not bound), mirroring the Java
3044
+ * generator — `ATTACH '` + arg + `'` style.
3045
+ */
3046
+ sqlExpr(queryHelper) {
3047
+ const parts = queryHelper.sqlQueryParts;
3048
+ if (!parts.some((p) => typeof p !== "string" && p.name.startsWith("sources_"))) return this.quote(queryHelper.sqlQuery);
3049
+ let out = "`";
3050
+ for (const part of parts) if (typeof part === "string") out += part.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
3051
+ else if (part.name.startsWith("sources_")) out += ` '\${${part.name}}'`;
3052
+ else out += "?";
3053
+ return `${out}\``;
3054
+ }
2945
3055
  };
2946
3056
  //#endregion
2947
3057
  //#region src/generators/typescript-duckdb-generator.ts
@@ -3048,6 +3158,57 @@ function getGenerator(generator) {
3048
3158
  }
3049
3159
  }
3050
3160
  //#endregion
3161
+ //#region src/sources.ts
3162
+ /**
3163
+ * For each `type: postgres` source: start a throwaway Postgres testcontainer,
3164
+ * run the source's schema (the BASELINE blocks tagged `:source=<name>`) natively
3165
+ * against it so introspection sees true Postgres types, and return the connection
3166
+ * info to ATTACH into DuckDB.
3167
+ *
3168
+ * The synthesized ATTACH (done by the DuckDB adapter) and these schema blocks are
3169
+ * not emitted into generated code — at runtime the application attaches the real
3170
+ * production database under the same alias.
3171
+ */
3172
+ async function preparePostgresSources(sources, queries, reporter) {
3173
+ const containers = [];
3174
+ const attachments = [];
3175
+ const teardown = async () => {
3176
+ for (const container of containers) try {
3177
+ await container.stop();
3178
+ } catch {}
3179
+ };
3180
+ try {
3181
+ for (const source of sources) {
3182
+ reporter?.onContainerStarting?.();
3183
+ const container = await new PostgreSqlContainer(source.image).withDatabase("sqg-db").withUsername("sqg").withPassword("secret").start();
3184
+ containers.push(container);
3185
+ const connectionUri = container.getConnectionUri();
3186
+ reporter?.onContainerStarted?.(connectionUri);
3187
+ const schemaBlocks = queries.filter((q) => q.isBaseline && q.sourceTarget === source.name);
3188
+ const client = new Client({ connectionString: connectionUri });
3189
+ await client.connect();
3190
+ try {
3191
+ for (const block of schemaBlocks) await client.query(block.rawQuery);
3192
+ } catch (e) {
3193
+ throw new DatabaseError(`Failed to apply schema for postgres source '${source.name}': ${e.message}`, "postgres", `Check that the BASELINE blocks tagged ':source=${source.name}' are valid PostgreSQL.`);
3194
+ } finally {
3195
+ await client.end();
3196
+ }
3197
+ attachments.push({
3198
+ alias: source.name,
3199
+ connectionUri
3200
+ });
3201
+ }
3202
+ } catch (e) {
3203
+ await teardown();
3204
+ throw e;
3205
+ }
3206
+ return {
3207
+ attachments,
3208
+ teardown
3209
+ };
3210
+ }
3211
+ //#endregion
3051
3212
  //#region src/sqltool.ts
3052
3213
  const GENERATED_FILE_COMMENT = "This file is generated by SQG (https://sqg.dev). Do not edit manually.";
3053
3214
  const configSchema = z.object({ result: z.record(z.string(), z.string()).optional() });
@@ -3224,18 +3385,23 @@ var TableHelper = class {
3224
3385
  return this.generator.typeMapper;
3225
3386
  }
3226
3387
  };
3227
- function generateSourceFile(name, queries, tables, templatePath, generator, engine, projectName, config) {
3388
+ function generateSourceFile(name, queries, tables, templatePath, generator, engine, projectName, config, postgresSourceNames = []) {
3228
3389
  const templateSrc = readFileSync(templatePath, "utf-8");
3229
3390
  const template = Handlebars.compile(templateSrc);
3230
3391
  Handlebars.registerHelper("mapType", (column) => generator.mapType(column));
3231
3392
  Handlebars.registerHelper("plusOne", (value) => value + 1);
3232
3393
  const migrations = queries.filter((q) => q.isMigrate).map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q)));
3233
3394
  const tableHelpers = generator.supportsAppenders(engine) ? tables.filter((t) => !t.skipGenerateFunction).map((t) => new TableHelper(t, generator)) : [];
3395
+ const attachers = engine === "duckdb" ? postgresSourceNames.map((sourceName) => ({
3396
+ alias: sourceName,
3397
+ functionName: generator.getFunctionName(`attach_${sourceName}`)
3398
+ })) : [];
3234
3399
  return template({
3235
3400
  generatedComment: GENERATED_FILE_COMMENT,
3236
3401
  migrations,
3237
3402
  queries: queries.map((q) => new SqlQueryHelper(q, generator, generator.getStatement(q))),
3238
3403
  tables: tableHelpers,
3404
+ attachers,
3239
3405
  className: generator.getClassName(name),
3240
3406
  projectName,
3241
3407
  config
@@ -3263,9 +3429,11 @@ const ProjectSchema = z.object({
3263
3429
  })).min(1, "At least one generator is required").describe("Code generators to run")
3264
3430
  })).min(1, "At least one SQL configuration is required").describe("SQL file configurations"),
3265
3431
  sources: z.array(z.object({
3266
- path: z.string().describe("Path to source file (supports $HOME)"),
3267
- name: z.string().optional().describe("Variable name override")
3268
- })).optional().describe("External source files to include as variables")
3432
+ type: z.enum(["file", "postgres"]).optional().describe("Source type: 'file' (default) or 'postgres'"),
3433
+ path: z.string().optional().describe("Path to source file for file sources (supports $HOME)"),
3434
+ name: z.string().optional().describe("Variable name (file sources) or DuckDB attach alias (postgres sources)"),
3435
+ image: z.string().optional().describe("Docker image for postgres sources (default: postgres:16-alpine)")
3436
+ }).refine((s) => s.type === "postgres" ? !!s.name : !!s.path, { message: "file sources require 'path'; postgres sources require 'name'" })).optional().describe("External sources: files inlined as variables, or postgres databases attached for introspection")
3269
3437
  });
3270
3438
  var ExtraVariable = class {
3271
3439
  constructor(name, value) {
@@ -3274,7 +3442,7 @@ var ExtraVariable = class {
3274
3442
  }
3275
3443
  };
3276
3444
  function createExtraVariables(sources, suppressLogging = false) {
3277
- return sources.map((source) => {
3445
+ return sources.filter((source) => source.type !== "postgres").map((source) => {
3278
3446
  const path = source.path;
3279
3447
  const resolvedPath = path.replace("$HOME", homedir());
3280
3448
  const varName = `sources_${(source.name ?? basename(path, extname(resolvedPath))).replace(/\s+/g, "_")}`;
@@ -3282,6 +3450,13 @@ function createExtraVariables(sources, suppressLogging = false) {
3282
3450
  return new ExtraVariable(varName, `'${resolvedPath}'`);
3283
3451
  });
3284
3452
  }
3453
+ /** Postgres sources resolved from the project config (with image defaulted). */
3454
+ function getPostgresSources(sources) {
3455
+ return sources.filter((source) => source.type === "postgres").map((source) => ({
3456
+ name: source.name,
3457
+ image: source.image ?? "postgres:16-alpine"
3458
+ }));
3459
+ }
3285
3460
  function buildProjectFromCliOptions(options) {
3286
3461
  if (!isValidGenerator(options.generator)) {
3287
3462
  const similar = findSimilarGenerators(options.generator);
@@ -3358,6 +3533,106 @@ function getOutputPath(projectDir, sqlFileName, gen, generator) {
3358
3533
  mkdirSync(dirname(outputPath), { recursive: true });
3359
3534
  return outputPath;
3360
3535
  }
3536
+ function assignResultTypeNames(queries, tables, projectDir = process.cwd()) {
3537
+ const hints = [];
3538
+ const tablesByName = /* @__PURE__ */ new Map();
3539
+ for (const t of tables) tablesByName.set(t.tableName, t);
3540
+ const groups = /* @__PURE__ */ new Map();
3541
+ const eligible = queries.filter((q) => q.isQuery && !q.isPluck && !q.skipGenerateFunction && q.columns.length > 0);
3542
+ for (const q of eligible) {
3543
+ const cols = effectiveColumns(q);
3544
+ const key = JSON.stringify(cols.map((c) => ({
3545
+ n: c.name,
3546
+ t: c.type.toString(),
3547
+ nu: c.nullable,
3548
+ s: c.sourceTable ?? null
3549
+ })));
3550
+ let g = groups.get(key);
3551
+ if (!g) {
3552
+ g = { queries: [] };
3553
+ groups.set(key, g);
3554
+ }
3555
+ g.queries.push(q);
3556
+ }
3557
+ const recordShape = (cols) => JSON.stringify(cols.map((c) => ({
3558
+ n: c.name,
3559
+ t: c.type.toString(),
3560
+ nu: c.nullable
3561
+ })));
3562
+ const claims = /* @__PURE__ */ new Map();
3563
+ for (const t of tables) {
3564
+ if (!t.hasAppender) continue;
3565
+ const cols = t.columns.filter((c) => !c.generated);
3566
+ claims.set(pascalCase(`${t.id}_row`), {
3567
+ shape: recordShape(cols),
3568
+ offenderId: t.id,
3569
+ source: `TABLE ${t.tableName}`
3570
+ });
3571
+ }
3572
+ const claim = (name, shape, representative, source) => {
3573
+ const canonical = pascalCase(name);
3574
+ const existing = claims.get(canonical);
3575
+ if (existing && existing.shape !== shape) throw SqgError.inQuery(`Result type '${name}' would be emitted with two incompatible shapes: ${source} ('${representative.id}') vs ${existing.source} ('${existing.offenderId}')`, "VALIDATION_ERROR", representative.id, representative.filename, { suggestion: "Use a different `:result=` name for one of the queries, or change the queries so their result columns match" });
3576
+ if (!existing) claims.set(canonical, {
3577
+ shape,
3578
+ offenderId: representative.id,
3579
+ source
3580
+ });
3581
+ };
3582
+ for (const group of groups.values()) {
3583
+ const overrides = group.queries.map((q) => q.resultTypeOverride).filter((v) => !!v);
3584
+ const uniqueOverrides = new Set(overrides);
3585
+ if (uniqueOverrides.size > 1) {
3586
+ const offenders = group.queries.filter((q) => q.resultTypeOverride);
3587
+ throw SqgError.inQuery(`Conflicting ':result=' names for queries with identical result shapes: ${offenders.map((q) => `'${q.id}' uses '${q.resultTypeOverride}'`).join(", ")}`, "VALIDATION_ERROR", offenders[0].id, offenders[0].filename, { suggestion: "Pick a single name for this row type or change the queries so their shapes differ" });
3588
+ }
3589
+ const shape = recordShape(effectiveColumns(group.queries[0]));
3590
+ if (uniqueOverrides.size === 1) {
3591
+ const resolved = [...uniqueOverrides][0];
3592
+ claim(resolved, shape, group.queries.find((q) => q.resultTypeOverride === resolved), `:result=${resolved}`);
3593
+ for (const q of group.queries) q.resultTypeName = resolved;
3594
+ continue;
3595
+ }
3596
+ const fullMatch = tryFullTableMatch(group.queries[0], tablesByName);
3597
+ if (fullMatch) {
3598
+ claim(fullMatch, shape, group.queries[0], "full-table match");
3599
+ for (const q of group.queries) q.resultTypeName = fullMatch;
3600
+ continue;
3601
+ }
3602
+ if (group.queries.length >= 2) {
3603
+ const list = group.queries.map((q) => `'${q.id}' (${displayPath(q.filename, projectDir)}:${q.line})`).join(", ");
3604
+ hints.push({
3605
+ queryIds: group.queries.map((q) => q.id),
3606
+ message: `${group.queries.length} queries return the same row shape: ${list}. Add \`:result=Name\` to any one of them to share a single row type.`
3607
+ });
3608
+ }
3609
+ }
3610
+ return hints;
3611
+ }
3612
+ /** Show paths relative to the project root when it's inside the tree; otherwise fall back to absolute. */
3613
+ function displayPath(fullPath, projectDir) {
3614
+ const rel = relative(projectDir, fullPath);
3615
+ return rel && !rel.startsWith("..") ? rel : fullPath;
3616
+ }
3617
+ /** Resolve config-overridden column info, mirroring what validateQueries does for allColumns. */
3618
+ function effectiveColumns(query) {
3619
+ return query.columns.map((col) => query.config?.getColumnInfo(col.name) ?? col);
3620
+ }
3621
+ function tryFullTableMatch(query, tablesByName) {
3622
+ const cols = effectiveColumns(query);
3623
+ const firstSource = cols[0]?.sourceTable;
3624
+ if (!firstSource) return void 0;
3625
+ if (!cols.every((c) => c.sourceTable === firstSource)) return void 0;
3626
+ const table = tablesByName.get(firstSource);
3627
+ if (!table) return void 0;
3628
+ if (table.columns.some((c) => c.generated)) return void 0;
3629
+ if (table.columns.length !== cols.length) return void 0;
3630
+ for (let i = 0; i < cols.length; i++) {
3631
+ if (cols[i].name !== table.columns[i].name) return void 0;
3632
+ if (cols[i].type.toString() !== table.columns[i].type.toString()) return void 0;
3633
+ }
3634
+ return `${table.id}_row`;
3635
+ }
3361
3636
  function validateQueries(queries) {
3362
3637
  for (const query of queries) {
3363
3638
  if (query.isQuery && query.isPluck && query.columns.length !== 1) throw SqgError.inQuery(`':pluck' modifier requires exactly 1 column, but query has ${query.columns.length} columns`, "VALIDATION_ERROR", query.id, query.filename, { suggestion: query.columns.length === 0 ? "Ensure the query returns at least one column" : `Remove ':pluck' or select only one column. Current columns: ${query.columns.map((c) => c.name).join(", ")}` });
@@ -3373,14 +3648,14 @@ function validateQueries(queries) {
3373
3648
  };
3374
3649
  }
3375
3650
  }
3376
- async function writeGeneratedFile(projectDir, gen, generator, file, queries, tables, engine, writeToStdout = false) {
3651
+ async function writeGeneratedFile(projectDir, gen, generator, file, queries, tables, engine, writeToStdout = false, postgresSourceNames = []) {
3377
3652
  await generator.beforeGenerate(projectDir, gen, queries, tables);
3378
3653
  const templatePath = join(dirname(new URL(import.meta.url).pathname), gen.template ?? generator.template);
3379
3654
  const name = gen.name ?? basename(file, extname(file));
3380
3655
  const sourceFile = generateSourceFile(name, queries, tables, templatePath, generator, engine, gen.projectName ?? name, {
3381
3656
  migrations: true,
3382
3657
  ...gen.config
3383
- });
3658
+ }, postgresSourceNames);
3384
3659
  if (writeToStdout) {
3385
3660
  process.stdout.write(sourceFile);
3386
3661
  if (!sourceFile.endsWith("\n")) process.stdout.write("\n");
@@ -3481,6 +3756,11 @@ async function processProjectFromConfig(project, projectDir, writeToStdout = fal
3481
3756
  const results = [];
3482
3757
  try {
3483
3758
  const extraVariables = createExtraVariables(project.sources ?? [], writeToStdout);
3759
+ const pgSources = getPostgresSources(project.sources ?? []);
3760
+ const pgSourceNames = new Set(pgSources.map((s) => s.name));
3761
+ if (pgSources.length > 0) {
3762
+ if (!project.sql.some((sql) => sql.gen.some((gen) => getGeneratorEngine(gen.generator) === "duckdb"))) throw new SqgError("Postgres sources require a DuckDB generator (they are attached into DuckDB for introspection)", "CONFIG_VALIDATION_ERROR", "Add a 'typescript/duckdb' or 'java/duckdb' generator, or remove the postgres sources");
3763
+ }
3484
3764
  const files = [];
3485
3765
  for (const sql of project.sql) {
3486
3766
  const gensByEngine = /* @__PURE__ */ new Map();
@@ -3498,6 +3778,7 @@ async function processProjectFromConfig(project, projectDir, writeToStdout = fal
3498
3778
  const parseResult = parseSQLQueries(fullPath, extraVariables);
3499
3779
  queries = parseResult.queries;
3500
3780
  tables = parseResult.tables;
3781
+ for (const q of queries) if (q.sourceTarget && !pgSourceNames.has(q.sourceTarget)) throw SqgError.inQuery(`BASELINE block targets unknown postgres source '${q.sourceTarget}'`, "CONFIG_VALIDATION_ERROR", q.id, sqlFile, { suggestion: `Declare a source with 'type: postgres, name: ${q.sourceTarget}' in sqg.yaml` });
3501
3782
  } catch (e) {
3502
3783
  if (e instanceof SqgError) throw e;
3503
3784
  throw SqgError.inFile(`Failed to parse SQL file: ${e.message}`, "SQL_PARSE_ERROR", sqlFile, { suggestion: "Check SQL syntax and annotation format" });
@@ -3506,15 +3787,25 @@ async function processProjectFromConfig(project, projectDir, writeToStdout = fal
3506
3787
  const executableQueries = queries.filter((q) => !q.skipGenerateFunction);
3507
3788
  const reporterAny = reporter;
3508
3789
  if (reporterAny?.setQueryTotal) reporterAny.setQueryTotal(executableQueries.length);
3790
+ let preparedSources;
3509
3791
  try {
3510
3792
  const dbEngine = getDatabaseEngine(engine);
3793
+ let attachments;
3794
+ if (engine === "duckdb" && pgSources.length > 0) {
3795
+ ui?.startPhase("Starting postgres source containers...");
3796
+ preparedSources = await preparePostgresSources(pgSources, queries, reporter);
3797
+ attachments = preparedSources.attachments;
3798
+ }
3511
3799
  ui?.startPhase(`Initializing ${engine} database...`);
3512
- await dbEngine.initializeDatabase(queries, reporter);
3800
+ await dbEngine.initializeDatabase(queries, reporter, { attachments });
3513
3801
  ui?.startPhase(`Introspecting ${executableQueries.length} queries...`);
3514
3802
  await dbEngine.executeQueries(queries, reporter);
3515
3803
  if (tables.length > 0) await dbEngine.introspectTables(tables, reporter);
3516
3804
  ui?.succeedPhase(`Introspected ${executableQueries.length} queries`);
3517
3805
  validateQueries(queries);
3806
+ const hints = assignResultTypeNames(queries, tables, projectDir);
3807
+ for (const hint of hints) if (ui) ui.hint(hint.message);
3808
+ else consola.info(hint.message);
3518
3809
  await dbEngine.close();
3519
3810
  } catch (e) {
3520
3811
  ui?.failPhase(`Failed to process ${sqlFile}`);
@@ -3523,6 +3814,8 @@ async function processProjectFromConfig(project, projectDir, writeToStdout = fal
3523
3814
  file: sqlFile,
3524
3815
  engine
3525
3816
  });
3817
+ } finally {
3818
+ if (preparedSources) await preparedSources.teardown();
3526
3819
  }
3527
3820
  ui?.startPhase("Generating code...");
3528
3821
  const genStart = performance.now();
@@ -3531,7 +3824,7 @@ async function processProjectFromConfig(project, projectDir, writeToStdout = fal
3531
3824
  const outputPath = await writeGeneratedFile(projectDir, {
3532
3825
  ...gen,
3533
3826
  projectName: project.name
3534
- }, generator, sqlFile, queries, tables, engine, writeToStdout);
3827
+ }, generator, sqlFile, queries, tables, engine, writeToStdout, pgSources.map((s) => s.name));
3535
3828
  if (outputPath !== null) {
3536
3829
  files.push(outputPath);
3537
3830
  results.push({
@@ -3565,7 +3858,7 @@ async function processProject(projectPath, ui) {
3565
3858
  //#region src/mcp-server.ts
3566
3859
  const server = new Server({
3567
3860
  name: "sqg-mcp",
3568
- version: process.env.npm_package_version ?? "0.19.1"
3861
+ version: process.env.npm_package_version ?? "0.21.0"
3569
3862
  }, { capabilities: {
3570
3863
  tools: {},
3571
3864
  resources: {}
@@ -3987,6 +4280,12 @@ var UI = class {
3987
4280
  this.log("");
3988
4281
  this.log(` ${pc.green("done")} ${pc.dim(`in ${formatMs(totalMs)}`)}`);
3989
4282
  }
4283
+ /** Display an info-level hint (e.g. "these queries could share a row type") */
4284
+ hint(message) {
4285
+ if (this.silent) return;
4286
+ this.stopSpinner();
4287
+ this.log(` ${pc.cyan(pc.bold("hint"))} ${message}`);
4288
+ }
3990
4289
  /** Display a formatted error */
3991
4290
  error(err) {
3992
4291
  if (this.silent) return;
@@ -4030,7 +4329,7 @@ function formatMs(ms) {
4030
4329
  }
4031
4330
  //#endregion
4032
4331
  //#region src/sqg.ts
4033
- const version = process.env.npm_package_version ?? "0.19.1";
4332
+ const version = process.env.npm_package_version ?? "0.21.0";
4034
4333
  updateNotifier({ pkg: {
4035
4334
  name: "@sqg/sqg",
4036
4335
  version