From 6902110134de2324d4bf1033258f7bc67be8fc5a Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Fri, 26 Nov 2021 11:26:55 +0100 Subject: [PATCH] internal/core/export: fix let exporting This is a hacky fix that relies on the original let AST expression to be present in the ADT. In practice this will almost certainly always be the case, though. As part of this, the name uniquer has been fixed to remember the random number. The exporter methods were defined on the value, instead of the pointer type, so the random generator was created on each instance. The first few numbers are now fixed, to have more sane numbers in the majority of cases. This algorithm has the additional property that if an expression refers to a let that is not exported, the expression will be inlined. This does not give the correct result if this expression itself contains references, but that is a general problem with the current exporter. NOTE: the filepath substitution is incorrect in value mode. The original was incorrect as well, however, as the alias also was inserted in the wrong scope. In practice this only matters for the already broken `eval`. In export it would always generate an error anyway. Unique name generator comment moved to where it applies. Fixes #1116 Signed-off-by: Marcel van Lohuizen Change-Id: I31c05485a5af4d9b423c71bd4e51fc05b5d4a5d7 Signed-off-by: Marcel van Lohuizen --- internal/core/export/adt.go | 46 +-- internal/core/export/export.go | 114 +++++- internal/core/export/expr.go | 11 +- internal/core/export/testdata/alias.txtar | 14 +- internal/core/export/testdata/let.txtar | 445 +++++++++++++++++++++- internal/core/export/value.go | 7 + internal/filetypes/types.go | 4 +- 7 files changed, 550 insertions(+), 91 deletions(-) diff --git a/internal/core/export/adt.go b/internal/core/export/adt.go index 4cbb49fc13d..9691763f2b5 100644 --- a/internal/core/export/adt.go +++ b/internal/core/export/adt.go @@ -179,51 +179,7 @@ func (e *exporter) adt(expr adt.Expr, conjuncts []adt.Conjunct) ast.Expr { return ident case *adt.LetReference: - // TODO: Handle references that went out of scope. In case of aliases - // this means they may need to be reproduced locally. Most of these - // issues can be avoided by either fully expanding a configuration - // (export) or not at all (def). - // - i := len(e.stack) - 1 - int(x.UpCount) - 1 - if i < 0 { - i = 0 - } - f := &(e.stack[i]) - let := f.let[x.X] - if let == nil { - if f.let == nil { - f.let = map[adt.Expr]*ast.LetClause{} - } - label := e.uniqueLetIdent(x.Label, x.X) - - name := label.IdentString(e.ctx) - - // A let may be added multiple times to the same scope as a result - // of how merging works. If that happens here it must be one - // originating from the same expression, and it is safe to drop. - for _, elt := range f.scope.Elts { - if a, ok := elt.(*ast.LetClause); ok { - if a.Ident.Name == name { - let = a - break - } - } - } - - if let == nil { - let = &ast.LetClause{ - Ident: e.ident(label), - Expr: e.expr(x.X), - } - f.scope.Elts = append(f.scope.Elts, let) - } - - f.let[x.X] = let - } - ident := ast.NewIdent(let.Ident.Name) - ident.Node = let - ident.Scope = f.scope - return ident + return e.resolveLet(x) case *adt.SelectorExpr: return &ast.SelectorExpr{ diff --git a/internal/core/export/export.go b/internal/core/export/export.go index 6c88b5bf440..c98f4d72aee 100644 --- a/internal/core/export/export.go +++ b/internal/core/export/export.go @@ -217,7 +217,7 @@ type exporter struct { index adt.StringIndexer rand *rand.Rand - // For resolving up references. + // For resolving references. stack []frame inDefinition int // for close() wrapping. @@ -231,6 +231,7 @@ type exporter struct { usedFeature map[adt.Feature]adt.Expr labelAlias map[adt.Expr]adt.Feature valueAlias map[*ast.Alias]*ast.Alias + letAlias map[*ast.LetClause]*ast.LetClause usedHidden map[string]bool } @@ -307,15 +308,76 @@ func setFieldAlias(f *ast.Field, name string) { } } -// uniqueLetIdent returns a name for a let identifier that uniquely identifies -// the given expression. If the preferred name is already taken, a new globally -// unique name of the form base_X ... base_XXXXXXXXXXXXXX is generated. -// -// It prefers short extensions over large ones, while ensuring the likelihood of -// fast termination is high. There are at least two digits to make it visually -// clearer this concerns a generated number. -// -func (e exporter) uniqueLetIdent(f adt.Feature, x adt.Expr) adt.Feature { +func (e *exporter) markLets(n ast.Node) { + switch v := n.(type) { + case *ast.StructLit: + e.markLetDecls(v.Elts) + case *ast.File: + e.markLetDecls(v.Decls) + } +} + +func (e *exporter) markLetDecls(decls []ast.Decl) { + for _, d := range decls { + if let, ok := d.(*ast.LetClause); ok { + e.markLetAlias(let) + } + } +} + +// markLetAlias inserts an uninitialized let clause into the current scope. +// It gets initialized upon first usage. +func (e *exporter) markLetAlias(x *ast.LetClause) { + // The created let clause is initialized upon first usage, and removed + // later if never referenced. + let := &ast.LetClause{} + + if e.letAlias == nil { + e.letAlias = make(map[*ast.LetClause]*ast.LetClause) + } + e.letAlias[x] = let + + scope := e.top().scope + scope.Elts = append(scope.Elts, let) +} + +// In value mode, lets are only used if there wasn't an error. +func filterUnusedLets(s *ast.StructLit) { + k := 0 + for i, d := range s.Elts { + if let, ok := d.(*ast.LetClause); ok && let.Expr == nil { + continue + } + s.Elts[k] = s.Elts[i] + k++ + } + s.Elts = s.Elts[:k] +} + +// resolveLet actually parses the let expression. +// If there was no recorded let expression, it expands the expression in place. +func (e *exporter) resolveLet(x *adt.LetReference) ast.Expr { + letClause, _ := x.Src.Node.(*ast.LetClause) + let := e.letAlias[letClause] + + switch { + case let == nil: + return e.expr(x.X) + + case let.Expr == nil: + label := e.uniqueLetIdent(x.Label, x.X) + + let.Ident = e.ident(label) + let.Expr = e.expr(x.X) + } + + ident := ast.NewIdent(let.Ident.Name) + ident.Node = let + // TODO: set scope? + return ident +} + +func (e *exporter) uniqueLetIdent(f adt.Feature, x adt.Expr) adt.Feature { if e.usedFeature[f] == x { return f } @@ -325,7 +387,7 @@ func (e exporter) uniqueLetIdent(f adt.Feature, x adt.Expr) adt.Feature { return f } -func (e exporter) uniqueAlias(name string) string { +func (e *exporter) uniqueAlias(name string) string { f := adt.MakeIdentLabel(e.ctx, name, "") if _, ok := e.usedFeature[f]; !ok { @@ -337,29 +399,46 @@ func (e exporter) uniqueAlias(name string) string { return name } -func (e exporter) uniqueFeature(base string) (f adt.Feature, name string) { +// uniqueFeature returns a name for an identifier that uniquely identifies +// the given expression. If the preferred name is already taken, a new globally +// unique name of the form base_X ... base_XXXXXXXXXXXXXX is generated. +// +// It prefers short extensions over large ones, while ensuring the likelihood of +// fast termination is high. There are at least two digits to make it visually +// clearer this concerns a generated number. +// +func (e *exporter) uniqueFeature(base string) (f adt.Feature, name string) { if e.rand == nil { e.rand = rand.New(rand.NewSource(808)) } + // Try the first few numbers in sequence. + for i := 1; i < 5; i++ { + name := fmt.Sprintf("%s_%01X", base, i) + f := adt.MakeIdentLabel(e.ctx, name, "") + if _, ok := e.usedFeature[f]; !ok { + e.usedFeature[f] = nil + return f, name + } + } + const mask = 0xff_ffff_ffff_ffff // max bits; stay clear of int64 overflow const shift = 4 // rate of growth + digits := 1 for n := int64(0x10); ; n = int64(mask&((n< 0 + for _, c := range a { e.top().upCount = c.up x := c.c.Expr() @@ -133,8 +138,6 @@ func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct, } } - s := x.top().scope - for _, a := range e.attrs { s.Elts = append(s.Elts, a) } @@ -184,7 +187,7 @@ func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct, } else { x = e.embed[0] } - if len(e.attrs) == 0 { + if len(e.attrs) == 0 && !hasAlias { return x } if st, ok := x.(*ast.StructLit); ok { diff --git a/internal/core/export/testdata/alias.txtar b/internal/core/export/testdata/alias.txtar index fb688e68051..1098d246cc9 100644 --- a/internal/core/export/testdata/alias.txtar +++ b/internal/core/export/testdata/alias.txtar @@ -67,12 +67,12 @@ fieldAlias: { } cross: { baz: 3 - X_85="d-2": { + X_2="d-2": { E=[D="cue"]: { C="foo\(baz)": { name: "xx" foo: C.name - bar: X_85 + bar: X_2 baz: D qux: E } @@ -84,8 +84,8 @@ valueAlias: { merge: { // Merge fields, rename alias to avoid conflict. // TODO: merged values can still be simplified. - value: X_BA={ - #value: X_BA.b & X_BA.b + value: X_3={ + #value: X_3.b & X_3.b b: 2 v: { X: 3 @@ -95,8 +95,8 @@ valueAlias: { selfRef: { struct: { a: { - b: X_57C8={ - #foo: X_57C8.b + b: X_4={ + #foo: X_4.b b: 2 } } @@ -110,7 +110,7 @@ valueAlias: { // an issue exclusive to value aliases, and falls within the // range of what is acceptable for now. // TODO: solve this issue. - a: X_35B7E=or(X_35B7E) + a: X_8=or(X_8) } pattern: { // this triggers the verbatim "adt" path. Note that there diff --git a/internal/core/export/testdata/let.txtar b/internal/core/export/testdata/let.txtar index 65b1e39c7b1..c581f766b21 100644 --- a/internal/core/export/testdata/let.txtar +++ b/internal/core/export/testdata/let.txtar @@ -31,8 +31,73 @@ for cfg in cfgs { } } +-- for.cue -- +comprehension: { + for cfg in [{a: "one"}] { + let filepath = "kind-\(cfg.name)" + "\(filepath)": { + patches: cfg + } + } +} + +-- scope.cue -- +scoped: { + _args: required: 1 + direct: { + let Args = _args + a: Args.required + } + embed1: { + let Args = _args + a: {Args.required} + } + embed2: { + let Args = _args + a: {{Args.required}} + } + list: { + let Args = _args + a: [Args.required] + } + listStruct: { + let Args = _args + a: [{a: Args.required}] + } + listEmbed: { + let Args = _args + a: [{Args.required}] + } +} + + +-- incomplete.cue -- +incomplete: a: { + x: "a \(run.a) z" + run: { + a: string + } +} +incomplete: b: { + let A = run.a + x: "a \(A) z" + run: { + a: string + } +} +incomplete: c: { + let A = run.a + x: "a \(A) z" + run: { + a: "foo" + } +} + -- out/definition -- +let X = 1 + 1 +let Y = x +let Y_1 = x { cfgs: [ for crd in ["one", "two"] { metadata: { @@ -48,12 +113,72 @@ for cfg in cfgs { } } } -let X = 1 + 1 #Foo: X x: "foo" -let Y = x -let Y_1 = x +comprehension: { + for cfg in [{ + a: "one" + }] { + let filepath_1 = "kind-\(cfg.name)" + "\(filepath_1)": { + patches: cfg + } + } +} +scoped: { + _args: { + required: 1 + } + direct: { + let Args = _args + a: Args.required + } + embed1: { + let Args_1 = _args + a: Args_1.required + } + embed2: { + let Args_2 = _args + a: Args_2.required + } + list: { + let Args_3 = _args + a: [Args_3.required] + } + listStruct: { + let Args_4 = _args + a: [{ + a: Args_4.required + }] + } + listEmbed: { + let Args_8 = _args + a: [Args_8.required] + } +} y: Y & Y_1 +incomplete: { + a: { + x: "a \(run.a) z" + run: { + a: string + } + } + b: { + let A = run.a + x: "a \(A) z" + run: { + a: string + } + } + c: { + let A_1 = run.a + x: "a \(A_1) z" + run: { + a: "foo" + } + } +} -- out/doc -- [] [#Foo] @@ -66,6 +191,39 @@ y: Y & Y_1 [cfgs 1] [cfgs 1 metadata] [cfgs 1 metadata name] +[comprehension] +[scoped] +[scoped _args] +[scoped _args required] +[scoped direct] +[scoped direct a] +[scoped embed1] +[scoped embed1 a] +[scoped embed2] +[scoped embed2 a] +[scoped list] +[scoped list a] +[scoped list a 0] +[scoped listStruct] +[scoped listStruct a] +[scoped listStruct a 0] +[scoped listStruct a 0 a] +[scoped listEmbed] +[scoped listEmbed a] +[scoped listEmbed a 0] +[incomplete] +[incomplete a] +[incomplete a x] +[incomplete a run] +[incomplete a run a] +[incomplete b] +[incomplete b x] +[incomplete b run] +[incomplete b run a] +[incomplete c] +[incomplete c x] +[incomplete c run] +[incomplete c run a] [files] -- out/value -- == Simplified @@ -80,17 +238,69 @@ y: Y & Y_1 name: "two" } }] - let filepath = "kind-\(cfg.name)" + comprehension: { + for cfg in [{ + a: "one" + }] { + let filepath_1 = "kind-\(cfg.name)" + "\(filepath_1)": { + patches: cfg + } + } + } + scoped: { + direct: { + a: 1 + } + embed1: { + a: 1 + } + embed2: { + a: 1 + } + list: { + a: [1] + } + listStruct: { + a: [{ + a: 1 + }] + } + listEmbed: { + a: [1] + } + } files: { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } & { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } y: "foo" + incomplete: { + a: { + x: "a \(run.a) z" + run: { + a: string + } + } + b: { + let A = run.a + x: "a \(A) z" + run: { + a: string + } + } + c: { + x: "a foo z" + run: { + a: "foo" + } + } + } } == Raw { @@ -105,17 +315,72 @@ y: Y & Y_1 name: "two" } }] - let filepath = "kind-\(cfg.name)" + comprehension: { + for cfg in [{ + a: "one" + }] { + let filepath_1 = "kind-\(cfg.name)" + "\(filepath_1)": { + patches: cfg + } + } + } + scoped: { + _args: { + required: 1 + } + direct: { + a: 1 + } + embed1: { + a: 1 + } + embed2: { + a: 1 + } + list: { + a: [1] + } + listStruct: { + a: [{ + a: 1 + }] + } + listEmbed: { + a: [1] + } + } files: { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } & { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } y: "foo" + incomplete: { + a: { + x: "a \(run.a) z" + run: { + a: string + } + } + b: { + let A = run.a + x: "a \(A) z" + run: { + a: string + } + } + c: { + x: "a foo z" + run: { + a: "foo" + } + } + } } == Final { @@ -129,8 +394,51 @@ y: Y & Y_1 name: "two" } }] + comprehension: _|_ // invalid interpolation: invalid interpolation: comprehension: undefined field: name + scoped: { + direct: { + a: 1 + } + embed1: { + a: 1 + } + embed2: { + a: 1 + } + list: { + a: [1] + } + listStruct: { + a: [{ + a: 1 + }] + } + listEmbed: { + a: [1] + } + } files: _|_ // invalid interpolation: invalid interpolation: files: undefined field: name (and 3 more errors) y: "foo" + incomplete: { + a: { + x: _|_ // invalid interpolation: incomplete.a.x: non-concrete value string (type string) + run: { + a: string + } + } + b: { + x: _|_ // invalid interpolation: incomplete.b.x: non-concrete value string (type string) + run: { + a: string + } + } + c: { + x: "a foo z" + run: { + a: "foo" + } + } + } } == All { @@ -145,17 +453,72 @@ y: Y & Y_1 name: "two" } }] - let filepath = "kind-\(cfg.name)" + comprehension: { + for cfg in [{ + a: "one" + }] { + let filepath_1 = "kind-\(cfg.name)" + "\(filepath_1)": { + patches: cfg + } + } + } + scoped: { + _args: { + required: 1 + } + direct: { + a: 1 + } + embed1: { + a: 1 + } + embed2: { + a: 1 + } + list: { + a: [1] + } + listStruct: { + a: [{ + a: 1 + }] + } + listEmbed: { + a: [1] + } + } files: { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } & { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } y: "foo" + incomplete: { + a: { + x: "a \(run.a) z" + run: { + a: string + } + } + b: { + let A = run.a + x: "a \(A) z" + run: { + a: string + } + } + c: { + x: "a foo z" + run: { + a: "foo" + } + } + } } == Eval { @@ -170,15 +533,67 @@ y: Y & Y_1 name: "two" } }] - let filepath = "kind-\(cfg.name)" + comprehension: { + for cfg in [{ + a: "one" + }] { + let filepath_1 = "kind-\(cfg.name)" + "\(filepath_1)": { + patches: cfg + } + } + } + scoped: { + direct: { + a: 1 + } + embed1: { + a: 1 + } + embed2: { + a: 1 + } + list: { + a: [1] + } + listStruct: { + a: [{ + a: 1 + }] + } + listEmbed: { + a: [1] + } + } files: { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } & { - "\(filepath)": { + "\("kind-\(cfg.name)")": { patches: cfg } } y: "foo" + incomplete: { + a: { + x: "a \(run.a) z" + run: { + a: string + } + } + b: { + let A = run.a + x: "a \(A) z" + run: { + a: string + } + } + c: { + x: "a foo z" + run: { + a: "foo" + } + } + } } diff --git a/internal/core/export/value.go b/internal/core/export/value.go index 9018af8e874..a5efc7f2e74 100644 --- a/internal/core/export/value.go +++ b/internal/core/export/value.go @@ -349,6 +349,13 @@ func (e *exporter) structComposite(v *adt.Vertex, attrs []*ast.Attribute) ast.Ex e.popFrame(saved) }() + for _, c := range v.Conjuncts { + e.markLets(c.Expr().Source()) + } + if len(s.Elts) > 0 { + defer filterUnusedLets(s) + } + showRegular := false switch x := v.BaseValue.(type) { case *adt.StructMarker: diff --git a/internal/filetypes/types.go b/internal/filetypes/types.go index 2093cd0cd8a..b4cd55aeec2 100644 --- a/internal/filetypes/types.go +++ b/internal/filetypes/types.go @@ -41,5 +41,5 @@ func cuegenMake(name string, x interface{}) cue.Value { return v } -// Data size: 1713 bytes. -var cuegenInstanceData = []byte("\x01\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xacX\u074f\u0736\x11\x97\xce.P\x11i\u07da\xb7\x02c\x19\b\u0483\xabE\x1e\x8c\x18\v\x1c\f'\xb6\v\xbf4E\x91>\x05\xc1\x81+\x8dv\xd9H\xa4JR\xc9\x1dr\xfb\xd06M\xfbW{\x8b!\xa9o\xdd\xd9\xd7\xfa^nw~\x9c\xe1\xccp>\xf7W\xa7\u007f\x9f\xc5g\xa7\xffD\xf1\xe9\x1fQ\xf4\xf9\xe9\xef\x0f\xe2\xf8#!\x8d\xe52\u01d7\xdcr\xa2\xc7\x0f\xe2\x87\u007fV\xca\xc6gQ\xfc\xf0O\xdc\x1e\u23e2\xf8\x17\xafE\x85&>\xfd\x1cE\xd1oO\xff:\x8b\xe3_\u007f\xf3m\xdebV\x8a*p\xfe\x1c\u0167\x9f\xa2\xe8\xd3\xd3?\x1f\xc4\xf1/\a\xfaOQ|\x16?\xfc#\xaf\x91\x04=tD\x16E\xd1\u06cf3\xd2$\x8e\xcf\xe28\xb1\xd7\r\x9a,o1~\xfb\xf1o\x1a\x9e\u007f\xc7\xf7\b\xbbVT\x05c\x9b\r\xbc\x00\xba\x1fr\xa55\x9aF\xc9\u0080U\xc0\xe1\x0f\xca\x1f\xca\b\xce\xd8c\xfa\xb7\x85\x1fYB\xd7K^\xe3\x16\u009f\xb1Z\xc8=KP\xe6\xaa\x10r\xdf\x03\x8f_\x05\nK\x84\xb4\xa8\x1b\x8d\x96[\xa1\xe4\xf3-<~3\xa1\xb0\xa4T\xba~\u07b3\x12\xf7k\xa5k\x96X\xbe7\xcf\xdd\xc5\xc97\xfe\xa6o\xb7\xfd\x95GvtF\xbc\u0112\xb7\x95\x05a\xc0\x1e\x10HEh\r\x16P*\r\xc6\x16B\x02\x97\x05}R\xad\xcd\xe0\xeb\x03\x82Ak\x85\xdc\x1b(\xb0AY\x90\x14%\a\xeeZ\x15du\x10\xbc\x05g?|2u\xc0y\xfa\xfb\x14n:m\x8e#\u007f\xbe\x91\xa5\x82\x02K!\xd1\xc0A\xfd\x00\u070b\x15\x06\x9c\x9b\xb0p\n\xf5n\xc1\"\xb8\x98\x18\x9d\xb5\xee\x1bK\nn\xf9\xe0\x95s\xab[\x84\x1b(ye\x90%\x1aK\xd4(s4\xdb%\x98_\xe7\x95\aV8\x9dj\x82\xa0A\xb0X7\x15\xb7h\x80kt\x0f \xe95\xac\x82\x1dB+E)\x90\xde\x05\xb8u\xc1\xa0\x95\xb2\xa0J\xb0\aaHH\xaed)\xf6\xad\xbf!c\xee\x02\xf7^B6\xad\xf5q:D\r}\x1b\xe5\xc5y\x9a\xb7H\x11sI\xf4,\xcbX\x92\x1cY\x92Th\xe1\n.\xfc\xf1\xb1;f\xaf\x96L\xfc2\aI\xd2(\x86\xae\xd8p\xb5\t\xaa\xe4-E-\xa5\x9a\xc9L~\xc0\x9a\ae\x88\x17\xaf,J\xe3C\u009dN\xb3\xbf\x1a%\xd3\xf0m\x96\xc3d\ro\xad\xea\xcd9z\x96k^W\xf7e\xb9\x1f\u01d1\xf2>\xc1+\x8a\xaew:\xdcYp\x8b\xc7/?[\xf3y\xf0\xea\xf9\xaa\xcf\xe7\xe0\xdc\u75df\xbd\xc3\xeb\x94\u03c3\u03cf,Qmc\xbb\xc0\xf1Z={\xfa\xe1\xd5z\xf6\xf4\xbez\xe1\xf7T\t\xfe\xf7p\xbe\xfc\xe2\u01477\xe3\x8b\x17\xef0\xa3\x14\x94\xf6c;\n,\xff/3\x9e~\xfe\xe5\xb3\x0f\x9e\x9aN\xea=\xf3\xb3\xebu\xaf\xba4\x85\x9a7\u01b7\x95!u\xa9\x90\x85\xc2\xe8\xa1FSA\xb4\x82\xea\xe0,\xc3\xd3t\xdco/Y\x92\u0498\xd0\x13\xa9\xf3\x12\x81\r\x85`\xa0\x13\xa1\x03\xaa\x80\xf4@EHU\fLSD\u078a\x84\xe21H#\x02\xebK\xc4\n`\xaf\xec\x14\xb0xe\t\u062b\xc1:\a\xec\x15\x91\x1b\xad\xac\x1a\xeb\xeb\bN\x12^\xd9\x0e\xed%M\xd1\xddH\xe7\x01e\t5\x97\xaf^~\xb5\x052\xc4\xe0\u07de8R\x9au\f=\xd3N\xc8f\a\x9b\r\xec\x84\xe4\xfa\xba\xd9\xf5CC7*\x81\x90\x85\xc8}\u007f\xf2\x0fH\xd1\xc0\xadkr\x1a\x1b\x8d\x06%\r.\xc0\xe9i\xf7\x9a\xd7\x19\xeb\a\xad-<\xbaHS/R\xc2t\u0102\x02-\xeaz4\x91\xe4\xa8-\x17\xb2\x93\x03\xe6\xa0\u06aa\xa0>8\x99K6\x1bx\xad4t\xc3\xec\x13p\xb5\xa2\xe6\u05f3\x93\xc0\xa9'\x9b\\\x8b\x9d\xd7\xcfG\xf0\x13\xf8\xe1 \xf2\x03\bk\xb0*]\x0f\xe5\x92Xs%\xbfGm}\xf3\xe5\xf0\xe5_^\x05\x8e\x8c\u0366\xc3~\xe0s3\xe18h\x03\xbdt\xc3\xe9dx\uc1b0\xd9\u0216\x96J\xf9h\xf6#\xa7\xe7J\xfd\xc5ix\x0ez+\x9f]\xb9\xaak\x1a\xd4*!\u0453\xadZ\xe6\x15\x01.\xa3\xbc\x18\x9f\xcc^z/\x99Rx\xafys\x98\xa0\x8e\xe2\xc1\x82\xef'P\xc1\xf7\x1d`\xf9\f\xb1A\xa0\xab\x17?\xb2q5s\xc5\u0301d\xe5\x02\r\xa6\a\xb8Z\xc5+\u007f\x80Rl\x81\xbb\fu\xb0\v\xfe\x05\xee3\xc8\x1d\xe83dqhH5:\u84a5\xd9\xd1l\xecfv\x14\xf6\x80\x9a\x1c\xdd\xe5BH\x17\xe8D<\x015\xc1Y\xd2\xec\xb6p>\xbd\xc5\xff\xa5]\xa6\xa5l9\\\xa4t?\xdc\xc0\x1a\u38cb\xbbY\x1d9X\xb9j`\xda?\x98\xd3cx4/v\xc1\xe3\u0277r\xed\x17n\f\x06\xd26q\x9bqI\x1f\x99IRqw\u035e\x9c\x1ez#\xb1~\x10\xa9\xdd>\x16\xe4\xd2\xc8\xe6\xf1\x05\xbb\x9b\xe6V.\x9cLj!:\xc7\u0674\x104\x1cx\x1fq\xaaA\xc9\x1bq\x8b\xac\x80\xbe\x87 _\x1f\\\x83\xee\u05fb\u0428\xa9@\xf3\xaa\xf2`\x06o,\x14\n\rHeA\u023cj\v\xf4\u06e5\xd25\xbcy\x991w\xce)\xe4v[\xda\xe2/\xfa\x05\xb7\xaf_N{j\u0517k\xd5\x05z-\x83+\xe0\x06R7\x03\xb9O]u\x99\xad]\xf31k\xba\xbc\xcdg\x97\xe9\xaa8G\xa7K\xe3\xa7\x13\xf8w\xf0\u025c\u0092\xd9J9\x977].\xe7\xe8t\xa5\x9c\xa1G\xaa\xf3\xb2\x9bZ\xc7C\xd4\xc2_\xc1G\x8b\xfb\u05ad\x1a\xe4/\n\xf8\xf0\x00\xde\xd7\xe4u*\xdc\xfe\xbf\xcb\xdd\xd9\nO:/|\xbe\xee\xeb;\xb5\x99\xf9q\xdd\u007f\xeb~\x1b\xec\x99\xf4\x1c\x939\x1bF\xb6=\xba\x18B\xa8\xfb9a\xcc<\xeeK\xb4B\xec\xe7~yt\x11\xda\xd8T\xdbN\xad\xc9\xef\x17\xbd]\xe3\xdf-V\rX\xf5K\xaf\u05d1M\xa7\xea\xbeGvI0X0t\xc8a\t\x9ae\x8bO\x12\xb8\xe9\xdem\xbc\x02tz\x8c'\xffA\xf8\xd0>\xa7\u039d\xa8Ai\xe8%O;\xf2\xaa>\xfd\xc1\xa1\u7b1e\x1bt\x18\xb7\x9aw\x1c\xb5\xaa\xbe\xeb\xee\xe1\u0a25\xcfr\xec\xbd\u0180\x89\xf4[f\x82\xd1\v\xccm\xa1F\u007f\x97\x98q\xcf^\x932\xb4\xbc\x99\xf2\vC\x8fl\xda'\xeeQ\xab\xdd2\xe5\x9b\xe0\xf4\x96yW\xbb\u0541w\xf6\xaf\xf7\xe6Zu\xd6<\x9a\x8e,\x8a\xfe\x1b\x00\x00\xff\xff\x8e\xf7,\xe9\xbe\x16\x00\x00") +// Data size: 1708 bytes. +var cuegenInstanceData = []byte("\x01\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4X\xddo\xe4\xb6\x11\x97|W\xa0R\xd3>\xe6\xad\xc0\x9c\xae\bR\xe3*#\x1f@\x81\x05\x8cC\u047b+\xee\xa5)\x8a\xf4)\b\f\xae4\xdae#\x91*I%6\xe2}h\x9b\xa6\xfd\xab\xb3\u0150\x94(je\xfb\f\xa4\xa8_\xbc;?\xcepf8\x9f\xfb\xf3\xe3\xbf\xcf\u04b3\xe3\u007f\x92\xf4\xf8\x8f$\xf9\xed\xf1\xefO\xd2\xf4=.\xb4a\xa2\xc2W\xcc0\xa2\xa7O\u04a7\u007f\x96\u04a4gI\xfa\xf4O\xcc\xec\xd3\xf7\x92\xf4'ox\x8b:=~\x9f$\xc9/\x8f\xff:K\xd3_|\xf1e5`\xd9\xf0\xd6s~\x9f\xa4\xc7\xef\x92\xe4\xc3\xe3?\x9f\xa4\xe9O\x03\xfd\xbb$=K\x9f\xfe\x91uH\x82\x9eZb\x9e$\xc9\x0f\xef\xff\x8a4I\u04f34\xcd\xccM\x8f\xba\xac\x06L\u007fx\xffg=\xab\xbeb;\x84\xed\xc0\xdb:\xcf/.\xe0w@\xf7C%\x95B\xddKQk0\x12\x18\xfcA\xbaC%\xc1e\xfe\x9c\xfem\xe0\xdb<\xa3\xeb\x05\xebp\x03\xfeO\x1b\xc5\xc5.\xcfPT\xb2\xe6b7\x01\xcf_{J\x9eqaP\xf5\n\r3\\\x8a\x97\x1bx\xfe6\xa2\xe4Y#U\xf7rb%\xee7Ruyf\xd8N\xbf\xb4\x17g_\xb8\x9b\xbe\xdcLW\x1e\xf2\x835\xe2\x156lh\rp\rf\x8f@*\u00a0\xb1\x86F*\u0426\xe6\x02\x98\xa8\xe9\x93\x1cL\t\x9f\xef\x114\x1a\xc3\xc5NC\x8d=\x8a\x9a\xa4H\x11\xb8;Y\x93\xd5^\xf0\x06\xac\xfd\xf0A\xec\x80\xf3\xe27\x05\u070e\xda\x1cf\xfe|+\x1a\t56\\\xa0\x86\xbd\xfc\x06\x98\x13\xcb5X7am\x15\x9a\u0702\xb5w11Zk\xed\xb7<\xab\x99a\xc1+\xe7F\r\b\xb7\u0430Vc\x9e)lP\xa1\xa8PoN\xc1\xea\xa6j\x1d\xb0\xc2iU\xe3\xe4y:\xb1\x95\xb2\xcd3\xd9\xd3w\xd6:\x16G\xab\xa4\xd0F1.L8\xf7\x15b\xef\xfd\xa27\x9e\xc6E%\xbb\xbeEc\xc3\xc2\u04fa^*3j\xe0h\xda(d\u0768\x94\xa3\u0572\xd2\xc1DGc\xc6(\xbe\x1d\x8c3\xc0\u049c{\xe9]4=\x1e=\x9c\xd3\xc1>r\xcd\x1b\xeb\v\x03\xb2G\u015c%\xeet\x99_\\\x10\xeb\xe7{\xd4\b\x06\xbb\xbee\x0650\x85\xf6\x01\x04\xbd\x86\x91\xb0E\x18\x04o8\u04bb\x0036\x18\x94\x94\x06d\x03f\xcf5\t\xa9\xa4h\xf8np7\x94\xb9\xbd\xc0\xbe\x17\x17\xfd`\\\x9c\xb6h\xe0\x1a.\xed\xe7\u023a\xc5#d\x91\x99K\xf0\x90gY\x88?++d\xd8yQ\rH\xb1wE\xf4\xb2,G\x86\x10C\xd7y`\xd0^@5P\xd4R\xaa\xe9RW{\xec\x98\x17A\xbcxmPh\x17\x12\xf6tQ\xfeUKQ\xf8o\x8b\x1c&\x1d\xd8`\xe4\xa4\xc4\xc1\xb1\u0730\xae},\xcb\xe38\x0e\x94\xf7\x19^St\xcd\x1c~\xf5\u045a\u02fdS\xcfW]\xbe\x04\x1fp\xb9\xf5\xc6\xfd>\xbf\xfa\xe8\x01\xafS>\a\x9f\x1f\xf2L\x0e\xbd\x89\x02\xe7\xea\xe3\x1f\u01ce\xb9V\x1f?V+\xfc\x9a\xea@\xd0\xe9\x93\xff\xb5o\x1f\x0e\xe7\xabO\x1e0\xa2\xe1\x94\xf2s+jl\xe6F|\xfa\xff\xcf\u026bO\x1f\x99\x95c\x87{=&'t\xac\u05ee\x99\x84\x84\xa5\xf2\xe5\u02e1\x83zEe\xd0p\xaa~\x8b\xbc.\x8ay\x97\xbd\u02b3\x82\x86\x83\x89H\xfd\x96\byH\xff@'\xc2\b\xb4\x1e\x99\x80\x96\x90\xb6\x0eL1\"\xeeD|\xc9\b\u0488\x90O\x85a\x050\xd7&\x06\f^\x1b\x02v2Xg\x81\x9d$r\xaf\xa4\x91s}-\xc1J\xc2k3\xa2\x93\xa4\x18\xdd\xcet\x0eh\x9eQK\xf9\xec\xd5g\x1b C4\xfe\xed\x85%\x15\xe5\xc801m\xb9\xe8\xb7pq\x01[.\x98\xba\xe9\xb7\u04e80\x0eH\xc0E\xcd+\u05d5\xdc\x03R40c[\x9b\xc2^\xa1FA\xe3\n0z\u069db]\x99O\xe3\xd5\x06\x9e]\x16\x85\x13) \x1e\xac\xa0F\x83\xaa\x9b\xcd!\x15*\u00f8\x18\xe5\x80\xde\u02e1\xad\xa9\xfbE\xd3\xc8\xc5\x05\xbc\x91\n\xc6\x11\xf6\x05\xd8\x1a\u0471\x9b\xc5I`\u0509u\xa5\xf8\xd6\xe9\xe7\"\xf8\x05|\xb3\xe7\xd5\x1e\xb8\xd1\xd86\xb6s2A\xac\x95\x14_\xa32\xae\xe52\xf8\xfd_^{\x8e2_\u0304\u04d8g'\xc1y\xd0zzcG\xd2hd\x1cG\xaf\u0160V4R\xbahv\x83\xa6\xe3*\xdc\u0145\u007f\x0ez+\x97]\x95\xec:\x1a\xcfZ.\u0411\x8d<\xcd+\x02lF91.\x99\x9d\xf4I2\xa5\xf0N\xb1~\x1f\xa1\x96\xe2\xc0\x9a\xed\"\xa8f\xbb\x110l\x81\x18/\xd0\u058bo\xf3y\xed\xb1\xa5\u01c2d\xe5\t\xeaM\xf7p\xbb\x8a\xb7\xee\x00\xa5\xd8\tn3\xd4\xc26\xf8Op\x97A\xf6\xc0\x94!'\x87B\xaa\xd1A\x9b,\xfd\x96&b;\xa9#7{T\xe4\xe81\x17|\xba\xc0(\xe2\x05\xc8\b\u03f3~\xbb\x81\xf3\xf8\x16\xf7W\x8c\x99V\xe4\xa7#EA\xf7\xc3-\xac1>\xbb\xbc\x9f\u0552\xbd\x95\xab\x06\x16\u04c3Y=\u00a39\xb1'<\x8e|'\xd7\xee\u010d\xde@\xda!\xee2.\x9b\"3\xcbZf\xaf\u0651\xd3}W$\xd6\x1fE\uae05y\xb94\xa89\xfc\x84\xdd\xcep+\x17F3\x95\x8f\xcey6\x9d\b\n\a\xdeE\x9c\xecQ\xb0\x9e\xdf!\u02e3\xef \xc8\xd5\a\u06e0\xa7\xa5\xce7j*\u042cm\x1dX\xc2[\x03\xb5D\rB\x1a\xe0\xa2j\x87\x1a\xddN)U\ao_\x95\xb9=g\x15\xb2\x1b-\xed\xee\x97\xd3Z;\xd5/\xab=5\uaaf5\xea\x02\x93\x96\xde\x15p\v\x85\x9d~\uc9f1\xba,\x96\xad\xe5@\x16\xafl\xcbI'^\x10\x97h\xbc*~\x18\xc1\xbf\x86\x0f\x96\x94<[,\x92Ky\xf1J\xb9D\xe3Er\x81\x1e\xa8\u038bqZ\x9d\x0fQ'\xfe\xf2>:\xb9o\u076a \xff\xa4\x80\x87\ap\xbe&\xafS\xe1v\xffm\xee.\x16w\xd2\xf9\xc4\xe7\ubfbeW\x9b\x85\x1f\xd7\xfd\xb7\xee\xb7`O\xd4stim\x98\xd9\xf6\xec2\x84\xd0\xf8#\u009cy\u0797hu\xd8-\xfd\xf2\xec\u04b7\xb1X\xdbQ\xad\xe8W\x8b\u026e\xf9\xaf\x15\xab\x06\xac\xfae\xd2\xeb\x90\xc7S\xf5\xd4#\xc7$\b\x16\x84\x0e\x19\x96\x9fE\xb6\xb8$\x81\xdb\xf1\xdd\xe6\v\u00e8\xc7|O\b\xc2C\xfb\x8c\x9d\x1b\xa9Ai\xe8$\xc7\x1dyU\x9f\xe9`\xe89\xab\xe7\x82\x0e\xf3V\xf3\xc0Q#\xbb\xfb\xee\x0e\ag-}\x91c\xef4\x06D\xd2\xef\x98\tf/\xb0\xb4\x85\x1a\xfd}b\xe6={MJhy\v\xe5O\f=\xe4q\x9fxD\xad\xb6\u02d4k\x82\xf1-\u02eev\xa7\x03\xef\xed_\xef\u0335\xea\xace4\x1d\xf2$\xf9o\x00\x00\x00\xff\xff\x85i\xbeS\xb4\x16\x00\x00")