From aa7fcf5622802119d9b0dd2cd31c3a096e5b4c06 Mon Sep 17 00:00:00 2001 From: bom-d-van Date: Wed, 29 Jun 2022 09:00:52 +0200 Subject: [PATCH] trie: supporting nested value list queries Value list (i.e. curl braces) in go-carbon queries is a tricky business. filepath.Glob, trigram, and trie index all have to work around the issue one way or the other. Currently, all the three query paths depends on `*CarbonserverListener.expandGlobBraces` to to perform the expansion. However, it currently does not support nested value lists like `{a,b,c,x.{a,b,c}}`. Unlike filepath.Glob and trigram, trie index does not need full expansion, it only needs expansion if a query contains nested values that are hierarchical (i.e. containing a dir node, another i.e., a dot). This is also partially due to the current implementation of how trie index handles hierarchical queries. To be more specific, trieIndex.query does not support queries like x.y.z.{a,nested.subquery}`, therefore, a query like that would be expanded by `*CarbonserverListener.expandGlobBraces` as `x.y.z.a` and `x.y.z.nested.subquery`. However, the current implementation does not support nested value lists like `x.y.z.{a,nested.subquery.{a,b,c}}`. This patch introduces a more through and proper (TM) value list query parser and rewriter for supporting all expansion cases (hopefully). Like most of the other improvements, only the trie index is supported for now. Unlike `*CarbonserverListener.expandGlobBraces`, *CarbonserverListener.expandGlobBracesForTrieIndex would only expand value list that contains dir/hierarchical nodes. For example, `x.y.z.{a,b,nested.subquery.{a,b,c}}` is rewritten as `x.y.z.{a,b}` and `x.y.z.nested.subquery.{a,b,c}`, because trie index can handle non-hierarchical value lists natively. We should also try to introduce a new expand function that can do full expansion to replace `*CarbonserverListener.expandGlobBraces`. --- carbonserver/carbonserver.go | 6 + carbonserver/trie.go | 13 +- carbonserver/trie_value_list.go | 524 +++++++++++ carbonserver/trie_value_list_test.go | 1287 ++++++++++++++++++++++++++ 4 files changed, 1827 insertions(+), 3 deletions(-) create mode 100644 carbonserver/trie_value_list.go create mode 100644 carbonserver/trie_value_list_test.go diff --git a/carbonserver/carbonserver.go b/carbonserver/carbonserver.go index 465a3d9a1..e729f5ea6 100644 --- a/carbonserver/carbonserver.go +++ b/carbonserver/carbonserver.go @@ -1407,6 +1407,12 @@ func (listener *CarbonserverListener) expandGlobs(ctx context.Context, query str } // TODO(dgryski): add tests +// +// TODO(xhu): doesn't support nested braces like {a,b,c,x.{a,b,c}}, should +// migrate to use the parser and rewriter in trie_value_list.go. however, +// unlike trie index which supports partial/non-nested value list, +// filepath.Glob and trigram index doesn't support brace queries at all, so full +// expansion are needed. func (listener *CarbonserverListener) expandGlobBraces(globs []string) ([]string, error) { for { bracematch := false diff --git a/carbonserver/trie.go b/carbonserver/trie.go index bc3694e65..9b64e8d86 100644 --- a/carbonserver/trie.go +++ b/carbonserver/trie.go @@ -1490,7 +1490,7 @@ func (ti *trieIndex) countNodes() (count, files, dirs, onec, onefc, onedc int, c } func (listener *CarbonserverListener) expandGlobsTrie(query string) ([]string, []bool, error) { - query = strings.ReplaceAll(query, ".", "/") + // query = strings.ReplaceAll(query, ".", "/") globs := []string{query} var slashInBraces, inAlter bool @@ -1500,17 +1500,24 @@ func (listener *CarbonserverListener) expandGlobsTrie(query string) ([]string, [ inAlter = true case c == '}': inAlter = false - case inAlter && c == '/': + case inAlter && c == '.': slashInBraces = true } } // for complex queries like {a.b.c,x}.o.p.q, fall back to simple expansion if slashInBraces { var err error - globs, err = listener.expandGlobBraces(globs) + globs, err = listener.expandGlobBracesForTrieIndex(query) if err != nil { return nil, nil, err } + + // TODO: slow? maybe we should make listener.expandGlobBracesForTrieIndex handles / natively? + for i := 0; i < len(globs); i++ { + globs[i] = strings.ReplaceAll(globs[i], ".", "/") + } + } else { + globs[0] = strings.ReplaceAll(globs[0], ".", "/") } var fidx = listener.CurrentFileIndex() diff --git a/carbonserver/trie_value_list.go b/carbonserver/trie_value_list.go new file mode 100644 index 000000000..1f37d4479 --- /dev/null +++ b/carbonserver/trie_value_list.go @@ -0,0 +1,524 @@ +package carbonserver + +import ( + "errors" + "fmt" + "strings" +) + +// value list query parser and rewriter + +func (listener *CarbonserverListener) expandGlobBracesForTrieIndex(query string) ([]string, error) { + vlq, err := parseValueLists(query) + if err != nil { + return nil, err + } + + // TODO: test max glob failing logics + + // glob expansion limit is a good thing because it's trival for user or + // tool to craft a query like {a,b,c,d}{a,b,c,d}{a,b,c,d} + // {a,b,c,d}... and it can trigger oom in go-carbon because of the + // exponential expansion result. + limit := listener.maxGlobs + subvlqs, err := vlq.expandBySubquery(limit) + if err != nil && (!errors.Is(err, errMaxGlobsExhausted) || listener.failOnMaxGlobs) { + return nil, err + } + + var subqueries []string + for _, svlq := range subvlqs { + subqueries = append(subqueries, svlq.String()) + } + + return subqueries, nil +} + +type vlQueryNode interface { + vlQueryNode() + clone() vlQueryNode +} + +type vlQuery []vlQueryNode + +func (vlQuery) vlQueryNode() {} + +func (vlq *vlQuery) clone() vlQueryNode { + var vlqc vlQuery + for _, item := range *vlq { + vlqc = append(vlqc, item.clone()) + } + return &vlqc +} + +// TODO: could just be new type to vlQuery? +type vlQueryList []vlQueryNode + +func (vlQueryList) vlQueryNode() {} + +func (vlql *vlQueryList) clone() vlQueryNode { + var vlqlc vlQueryList + for _, item := range *vlql { + vlqlc = append(vlqlc, item.clone()) + } + return &vlqlc +} + +type vlQueryLiteral string + +func (vlQueryLiteral) vlQueryNode() {} + +func (vlql vlQueryLiteral) clone() vlQueryNode { + return vlql +} + +func (vlq *vlQuery) String() string { + var qstr string + for _, nx := range *vlq { + switch n := nx.(type) { + case *vlQuery: + qstr += n.String() + case *vlQueryLiteral: + qstr += string(*n) + case vlQueryLiteral: + qstr += string(n) + case *vlQueryList: + var items []string + for _, item := range *n { + items = append(items, (&vlQuery{item}).String()) + } + qstr += fmt.Sprintf("{%s}", strings.Join(items, ",")) + default: + panic(fmt.Sprintf("unknown vlQueryNodeType %T", n)) + } + } + + return qstr +} + +// var errValueQueryListTooBig = errors.New("value list too big, please break down or rewrite the query") + +// TODO: rate limit +func (vlq *vlQuery) expandBySubquery(limit int) ([]*vlQuery, error) { + if limit <= 0 { + return nil, errMaxGlobsExhausted + } + + // flatten top sub queries + for { + var hasSubquery bool + var newNodes = make([]vlQueryNode, 0, len(*vlq)) + for _, x := range *vlq { + if node, ok := x.(*vlQuery); ok { + newNodes = append(newNodes, *node...) + hasSubquery = true + } else { + newNodes = append(newNodes, x) + } + } + + if !hasSubquery { + break + } + + *vlq = newNodes + } + + for i, n := range *vlq { + node, ok := n.(*vlQueryList) + if !ok { + continue + } + + var listsNext = [][]*vlQueryList{{node}} + var lindices = [][][]int{{{i}}} + var depth int + for len(listsNext[depth]) > 0 { + depth++ + listsNext = append(listsNext, nil) + lindices = append(lindices, nil) + + for lindex, list := range listsNext[depth-1] { + var newList = [][]vlQueryNode{{}} + var indices = []int{0} + for j, item := range *list { + switch inode := item.(type) { + case *vlQuery: + newList = append(newList, []vlQueryNode{item}) + indices = append(indices, j) + case vlQueryLiteral: + if strings.Contains(string(inode), ".") { + newList = append(newList, []vlQueryNode{item}) + indices = append(indices, j) + } else { + newList[0] = append(newList[0], item) + } + case *vlQueryList: + // trying to de-value-list items as deep as possible + var sublists = []*vlQueryList{inode} + for len(sublists) > 0 { + var newSubLists []*vlQueryList + for _, sl := range sublists { + for _, sitem := range *sl { + switch itemn := sitem.(type) { + case *vlQueryList: + newSubLists = append(newSubLists, itemn) + case vlQueryLiteral: + if strings.Contains(string(itemn), ".") { + newList = append(newList, []vlQueryNode{sitem}) + indices = append(indices, j) + } else { + newList[0] = append(newList[0], sitem) + } + default: + newList[0] = append(newList[0], sitem) + } + } + } + sublists = newSubLists + } + default: + newList[0] = append(newList[0], item) + } + } + + // no split needed, skips + if len(newList) == 1 { + continue + } + + var newQueries []*vlQuery + if len(newList[0]) > 0 { + newq := vlq.clone().(*vlQuery) + indices := lindices[depth-1][lindex] + if len(newList[0]) == 1 { + newq.replaceNodeAt(indices, newList[0][0]) + } else { + newq.replaceNodeAt(indices, (*vlQueryList)(&newList[0])) + } + expandedSubqueries, err := newq.expandBySubquery(limit - len(newQueries)) + newQueries = append(newQueries, expandedSubqueries...) + if err != nil { + return newQueries, err + } + } + for i, newl := range newList { + if i == 0 { + continue + } + + newq := vlq.clone().(*vlQuery) + indices := lindices[depth-1][lindex] + newq.replaceNodeAt(indices, newl[0]) + expandedSubqueries, err := newq.expandBySubquery(limit - len(newQueries)) + newQueries = append(newQueries, expandedSubqueries...) + if err != nil { + return newQueries, err + } + } + + return newQueries, nil + } + } + } + + return []*vlQuery{vlq}, nil +} + +func (q *vlQuery) replaceNodeAt(indices []int, newItems vlQueryNode) error { + var idxp int + var node vlQueryNode = q + for idxp < len(indices) { + switch x := node.(type) { + case *vlQuery: + if idxp == len(indices)-1 { + (*x)[indices[idxp]] = newItems + return nil + } + + node = (*x)[indices[idxp]] + case *vlQueryList: + if idxp == len(indices)-1 { + (*x)[indices[idxp]] = newItems + return nil + } + + node = (*x)[indices[idxp]] + default: + return fmt.Errorf("can't index non-indexable node: %T", node) + } + + idxp++ + } + + return fmt.Errorf("failed to replace the node") +} + +type vlQueryParserStackEntry struct { + start int + node vlQueryNode +} + +type vlQueryParserStack []*vlQueryParserStackEntry + +func (s *vlQueryParserStack) pop() *vlQueryParserStackEntry { + if len(*s) == 0 { + return nil + } + e := (*s)[len(*s)-1] + *s = (*s)[:len(*s)-1] + return e +} + +func (s *vlQueryParserStack) last() *vlQueryParserStackEntry { + if len(*s) == 0 { + return nil + } + e := (*s)[len(*s)-1] + return e +} +func (s *vlQueryParserStack) push(entry *vlQueryParserStackEntry) { + *s = append(*s, entry) +} +func (s *vlQueryParserStack) depth() int { return len(*s) } + +func parseValueLists(query string) (*vlQuery, error) { + var nodes vlQuery + var stack = vlQueryParserStack(make([]*vlQueryParserStackEntry, 0, 8)) + + for cur, c := range query { + // if *qvlDebug { + // log.Printf("%s @ %d: stack = %+v\n", query[:cur+1], cur, stack) + // pretty.Println(stack) + // } + + switch c { + case '{': + curEntry := stack.last() + if curEntry == nil { + stack.push(&vlQueryParserStackEntry{start: cur, node: &vlQueryList{}}) + continue + } + + switch node := curEntry.node.(type) { + case *vlQuery: + subl := &vlQueryList{} + *node = append(*node, subl) + stack.push(&vlQueryParserStackEntry{start: cur, node: subl}) + case *vlQueryList: + subl := &vlQueryList{} + + if len(*node) == 0 || (cur > 1 && query[cur-1] == ',') { + *node = append(*node, subl) + } else { + if len(*node) > 0 { + switch sibling := (*node)[len(*node)-1].(type) { + case *vlQuery: + *sibling = append(*sibling, subl) + stack.push(&vlQueryParserStackEntry{start: cur, node: sibling}) + case *vlQueryList: + subq := &vlQuery{sibling, subl} + (*node)[len(*node)-1] = subq + stack.push(&vlQueryParserStackEntry{start: cur, node: subq}) + } + } else { + subq := &vlQuery{node, subl} + curEntry.node = subq + } + } + + stack.push(&vlQueryParserStackEntry{start: cur, node: subl}) + case vlQueryLiteral: + literal := vlQueryLiteral(query[curEntry.start:cur]) + + if stack.depth() == 1 { + nodes = append(nodes, literal) + stack.pop() + + stack.push(&vlQueryParserStackEntry{start: cur, node: &vlQueryList{}}) + } else if stack.depth() > 1 { + subl := &vlQueryList{} + + switch parent := stack[stack.depth()-2].node.(type) { + case *vlQuery: + *parent = append(*parent, literal, subl) + stack.pop() + case *vlQueryList: + subq := &vlQuery{literal, subl} + curEntry.node = subq + *parent = append(*parent, subq) + } + + stack.push(&vlQueryParserStackEntry{start: cur, node: subl}) + } + case nil: + // TODO: impossible? + stack.push(&vlQueryParserStackEntry{start: cur, node: &vlQueryList{}}) + } + case ',': + curEntry := stack.last() + + // TODO: should check if its outside of value list? + if curEntry == nil { + // TODO: should return error instead? + stack.push(&vlQueryParserStackEntry{start: cur, node: vlQueryLiteral("")}) + + continue + } + + switch node := curEntry.node.(type) { + case *vlQuery: + stack.pop() + case *vlQueryList: + // empty string literal, do nothing + // stack = append(stack, &entry{start: cur, node: &vlQueryLiteral("")}) + + // for supporting empty value item like '{,}' + if len(*node) == 0 || (cur > 1 && query[cur-1] == ',') { + *node = append(*node, vlQueryLiteral("")) + } + case vlQueryLiteral: + if stack.depth() == 1 { + // most likely due to cases like ",,," + continue + } + + literal := vlQueryLiteral(query[curEntry.start:cur]) + stack.pop() + parentEntry := stack.last() + + switch parent := parentEntry.node.(type) { + case *vlQueryList: + *parent = append(*parent, literal) + case *vlQuery: + *parent = append(*parent, literal) + stack.pop() + + // TODO: should check if parent of parent not a value list? + default: + // return + } + } + case '}': + // TODO: supporting empty value item like '{,}' + + curEntry := stack.last() + if curEntry == nil { + // TODO: return error + return nil, errors.New("query has an unpaired closing curly bracket") + } + + switch node := curEntry.node.(type) { + case *vlQuery: + stack.pop() + + parentEntry := stack.pop() + if parentEntry == nil { + return nil, errors.New("found vlQuery outside of value list") + } + + if stack.depth() == 0 { + nodes = append(nodes, parentEntry.node) + } + case *vlQueryList: + // empty string literal, do nothing + if cur > 0 && query[cur-1] == ',' { + *node = append(*node, vlQueryLiteral("")) + } + + stack.pop() + if stack.depth() == 0 { + nodes = append(nodes, node) + } + case vlQueryLiteral: + literal := vlQueryLiteral(query[curEntry.start:cur]) + stack.pop() + + parentEntry := stack.last() + if parentEntry == nil { + return nil, errors.New("query has an unpaired closing curly bracket") + } + + switch parent := parentEntry.node.(type) { + case *vlQuery: + stack.pop() + *parent = append(*parent, literal) + + grandParentEntry := stack.pop() + if grandParentEntry == nil { + return nil, errors.New("found vlQuery outside of value list") + } + + if stack.depth() == 0 { + nodes = append(nodes, grandParentEntry.node) + } + case *vlQueryList: + *parent = append(*parent, literal) + + stack.pop() + if stack.depth() == 0 { + nodes = append(nodes, parent) + } + + // TODO: should check if parent of parent not a value list? + default: + // TODO: error? + } + } + + // TODO: handling spaces? + default: + if stack.depth() == 0 { + stack.push(&vlQueryParserStackEntry{start: cur, node: vlQueryLiteral("")}) + continue + } + + lastEntry := stack.last() + + switch node := lastEntry.node.(type) { + case *vlQuery: + stack.push(&vlQueryParserStackEntry{start: cur, node: vlQueryLiteral("")}) + case *vlQueryList: + if len(*node) == 0 { + // stack.push(&vlQueryParserStackEntry{start: cur, node: vlQueryLiteral("")}) + } else if sublist, ok := (*node)[len(*node)-1].(*vlQueryList); ok { + var delimited bool + if cur > 0 && query[cur-1] == ',' { + delimited = true + } + + if !delimited { + subq := &vlQuery{sublist} + (*node)[len(*node)-1] = subq + stack.push(&vlQueryParserStackEntry{start: cur, node: subq}) + } + } + + stack.push(&vlQueryParserStackEntry{start: cur, node: vlQueryLiteral("")}) + } + } + } + + // if *qvlDebug { + // log.Printf("end: stack = %+v\n", stack) + // pretty.Println(stack) + // } + + if stack.last() != nil { + curEntry := stack.pop() + switch curEntry.node.(type) { + case vlQueryLiteral: + nodes = append(nodes, vlQueryLiteral(query[curEntry.start:])) + case *vlQueryList: + return nil, errors.New("query has an unpaired opening curly bracket") + default: + nodes = append(nodes, curEntry.node) + } + } + + if stack.depth() > 0 { + return nil, errors.New("query has an unpaired opening curly bracket") + } + + return &nodes, nil +} diff --git a/carbonserver/trie_value_list_test.go b/carbonserver/trie_value_list_test.go new file mode 100644 index 000000000..03b8e33e0 --- /dev/null +++ b/carbonserver/trie_value_list_test.go @@ -0,0 +1,1287 @@ +package carbonserver + +import ( + "errors" + "regexp" + "runtime/debug" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func FuzzValueListParsingRoundTrip(f *testing.F) { + f.Add(`{`) + f.Add(`}`) + f.Add(`,`) + f.Add(`.`) + f.Add(`{xyz,abc}`) + f.Add(`{xyz.abc}.abc`) + f.Add(`test.{abc,xyz}.abc`) + f.Fuzz(func(t *testing.T, query string) { + defer func() { + if x := recover(); x != nil { + t.Errorf("panics catched (%s): %s\n%s", query, x, debug.Stack()) + } + }() + + vlq, err := parseValueLists(query) + if err != nil { + return + } + if vlqs := vlq.String(); vlqs != query { + t.Errorf("round trip parsing and encoding failed for query: %s (got: %s)", query, vlqs) + } + }) +} + +func TestValueListQueryStringer(t *testing.T) { + query := &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral("abc.xyz"), + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral("abc.xyz"), + }, + &vlQuery{ // for encoding + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + // &vlQueryList{ + // vlQueryLiteral("test"), + // vlQueryLiteral("abc"), + // }, + }, + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("test"), + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + }, + }, + vlQueryLiteral(".suffix"), + }, + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + }, + }, + }, + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral(".suffix"), + }, + }, + }, + }, + }, + vlQueryLiteral(".test."), + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral(".suffix"), + }, + }, + }, + }, + } + if got, want := query.String(), `test.{test,abc,abc.xyz,{test,abc,abc.xyz},sub.{test,abc},sub.{test,{{test,abc}}}.suffix,{{{{test,abc}}}},{{{{test,abc}.suffix}}}}.test.{{{{test,abc}.suffix}}}`; got != want { + t.Errorf("recording failed:\nquery.String() = %s\nwant %s", got, want) + } +} + +// var qvlDebug = flag.Bool("qvlDebug", false, "print parseValueLists debug info") + +func TestValueListQueryParser(t *testing.T) { + // test.{abc,xyz}.abc + // {{{test,abc},xyz.abc},xyz.abc}.abc + // {,test,abc}.test + // prefix.{,test,abc}test + // {test.abc.xyz} + // {test} + + for _, tcase := range []struct { + query string + output *vlQuery + err error + }{ + // overly_suspicious_testcase -- start + // + // probably controversal to support queries like this, + // but in trie-indexing, it shouldn't reach value list parser. + { + query: `,`, + output: &vlQuery{vlQueryLiteral(",")}, + }, + { + query: `,,,,`, + output: &vlQuery{vlQueryLiteral(",,,,")}, + }, + { + query: `{`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `{{{`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `}`, + err: errors.New("query has an unpaired closing curly bracket"), + }, + { + query: `}}}`, + err: errors.New("query has an unpaired closing curly bracket"), + }, + { + query: `.`, + output: &vlQuery{vlQueryLiteral(".")}, + }, + { + query: `0}`, + err: errors.New("query has an unpaired closing curly bracket"), + // output: &vlQuery{vlQueryLiteral(".")}, + }, + { + query: `{{}0{`, + err: errors.New("query has an unpaired opening curly bracket"), + // output: &vlQuery{vlQueryLiteral(".")}, + }, + { + query: `{0{}0}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + vlQueryLiteral("0"), + &vlQueryList{}, + vlQueryLiteral("0"), + }, + }, + }, + }, + { + query: `{0{}0{}}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + vlQueryLiteral("0"), + &vlQueryList{}, + vlQueryLiteral("0"), + &vlQueryList{}, + }, + }, + }, + }, + { + query: `{{}{}}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + }, + }, + }, + }, + { + query: `{{},{}}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{}, + &vlQueryList{}, + }, + }, + }, + { + query: `{}{}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + }, + }, + { + query: `{}.{}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{}, + vlQueryLiteral("."), + &vlQueryList{}, + }, + }, + { + query: `{{}{}0}`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + vlQueryLiteral("0"), + }, + }, + }, + }, + { + query: `{,}`, + output: &vlQuery{ + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral(""), + }, + }, + }, + { + query: `{0{,}`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `{0{,z}`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `{0{,}}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + vlQueryLiteral("0"), + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral(""), + }, + }, + }, + }, + }, + { + query: `{0{,z}}`, + // err: errors.New("query has an unpaired closing curly bracket"), + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + vlQueryLiteral("0"), + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral("z"), + }, + }, + }, + }, + }, + { + query: `{{}{{}}`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `{{}{{}}}`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{ + &vlQueryList{}, + }, + }, + }, + }, + }, + { + query: `{{}{{}}.xyz}.xyz`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{ + &vlQueryList{}, + }, + vlQueryLiteral(".xyz"), + }, + }, + vlQueryLiteral(".xyz"), + }, + }, + { + query: `{{}{{},}{}`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `{{}{{},}{}}`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{ + &vlQueryList{}, + vlQueryLiteral(""), + }, + &vlQueryList{}, + }, + }, + }, + }, + { + query: `{{}{{}{},}{}}`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + }, + vlQueryLiteral(""), + }, + &vlQueryList{}, + }, + }, + }, + }, + { + query: `{{}{{}test{},}{{}{},{}{{}{},{{{}{}{}{},{}{}}}}},test}.test`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + vlQueryLiteral("test"), + &vlQueryList{}, + }, + vlQueryLiteral(""), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + }, + &vlQuery{ + &vlQueryList{}, + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + }, + &vlQueryList{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + &vlQueryList{}, + &vlQueryList{}, + }, + &vlQuery{ + &vlQueryList{}, + &vlQueryList{}, + }, + }, + }, + }, + }, + }, + }, + vlQueryLiteral("test"), + }, + vlQueryLiteral(".test"), + }, + }, + { + query: `{{xyz,abc.xdb}{{xyz,abc,xyz.abc}test{abc.abc,xyz},}{{xyz,abc.xyz}{abc,xyz},{abc,xyz.abc}{{abc.xyz,abc}{abc.xyz},{{{abc.xyz}{abc.xyz,abc,xyz}{abc,xyz,abc.xyz}{abc,xyz,abc},{abc,xyz}{abc,xyz,abc}}}}},test}.test`, + output: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xdb"), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral("test"), + &vlQueryList{ + vlQueryLiteral("abc.abc"), + vlQueryLiteral("xyz"), + }, + }, + vlQueryLiteral(""), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + }, + }, + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc.xyz"), + vlQueryLiteral("abc"), + }, + &vlQueryList{ + vlQueryLiteral("abc.xyz"), + }, + }, + &vlQueryList{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc.xyz"), + }, + &vlQueryList{ + vlQueryLiteral("abc.xyz"), + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + }, + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + vlQueryLiteral("abc"), + }, + }, + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + }, + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + vlQueryLiteral("abc"), + }, + }, + }, + }, + }, + }, + }, + }, + vlQueryLiteral("test"), + }, + vlQueryLiteral(".test"), + }, + }, + // overly_suspicious_testcase -- end + + { + query: `test.{abc,xyz}.abc`, + output: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `test.{abc,xyz,石墨}.abc`, + output: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz"), + vlQueryLiteral("石墨"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `test.{abc,{xyz}}.abc`, + output: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + }, + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `test.{abc,{xyz,abc},abc}.abc`, + output: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("abc"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `prefix.{,test,abc}test`, + output: &vlQuery{ + vlQueryLiteral("prefix."), + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("test"), + }, + }, + { + query: `prefix.{,test,{abc}.abc}test`, + output: &vlQuery{ + vlQueryLiteral("prefix."), + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral("test"), + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc"), + }, + vlQueryLiteral(".abc"), + }, + }, + vlQueryLiteral("test"), + }, + }, + { + query: `prefix.{,test,{abc}.abc,xyz}test`, + output: &vlQuery{ + vlQueryLiteral("prefix."), + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral("test"), + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc"), + }, + vlQueryLiteral(".abc"), + }, + vlQueryLiteral("xyz"), + }, + vlQueryLiteral("test"), + }, + }, + { + query: `prefix.{,test,{{abc}.abc,xyz}test`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `prefix.{,test,{abc}.abc}},xyz}test`, + err: errors.New("query has an unpaired closing curly bracket"), + }, + { + query: `{{{test,abc},xyz.abc},xyz.abc}.abc`, + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `{{{test,abc},xyz.abc},xyz.abc}.abc.{{{test,abc},xyz.abc},xyz.abc}.abc`, + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral(".abc."), + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `{test,,test}.abc`, + output: &vlQuery{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral(""), + vlQueryLiteral("test"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `}{test,,test}.abc`, + err: errors.New("query has an unpaired closing curly bracket"), + }, + { + query: `{{test,,test}.abc`, + err: errors.New("query has an unpaired opening curly bracket"), + }, + { + query: `{test,abc,}.abc`, + output: &vlQuery{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral(""), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `{,,}.abc`, + output: &vlQuery{ + &vlQueryList{ + vlQueryLiteral(""), + vlQueryLiteral(""), + vlQueryLiteral(""), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `{{{test,abc},xyz.abc},xyz.abc}.abc`, + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `{{{test,abc},xyz.abc},xyz.abc{xyz,obj}}.abc`, + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + &vlQuery{ + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("obj"), + }, + }, + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `{{{test,abc},xyz.abc},xyz.abc{xyz,obj},xxx}.abc`, + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + &vlQuery{ + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("obj"), + }, + }, + vlQueryLiteral("xxx"), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: `a.b.c.{{eu-central1-a,eu-central2a,eu-west1-a,as-southeast1-a,as-east1-a,eu-west2-a,eu-west6a},by_az.{eu-central1-a,eu-central2a,eu-west1-a,as-southeast1-a,as-east1-a,eu-west2-a,eu-west6a}}.d.e.f.*.g.sum`, + output: &vlQuery{ + vlQueryLiteral("a.b.c."), + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("eu-central1-a"), + vlQueryLiteral("eu-central2a"), + vlQueryLiteral("eu-west1-a"), + vlQueryLiteral("as-southeast1-a"), + vlQueryLiteral("as-east1-a"), + vlQueryLiteral("eu-west2-a"), + vlQueryLiteral("eu-west6a"), + }, + &vlQuery{ + vlQueryLiteral("by_az."), + &vlQueryList{ + vlQueryLiteral("eu-central1-a"), + vlQueryLiteral("eu-central2a"), + vlQueryLiteral("eu-west1-a"), + vlQueryLiteral("as-southeast1-a"), + vlQueryLiteral("as-east1-a"), + vlQueryLiteral("eu-west2-a"), + vlQueryLiteral("eu-west6a"), + }, + }, + }, + vlQueryLiteral(".d.e.f.*.g.sum"), + }, + }, + { + query: `{{{test,abc},xyz.abc},,xyz.abc{xyz,obj},,xxx,}.abc`, + output: &vlQuery{ + &vlQueryList{ + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + }, + vlQueryLiteral("xyz.abc"), + }, + vlQueryLiteral(""), + &vlQuery{ + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("obj"), + }, + }, + vlQueryLiteral(""), + vlQueryLiteral("xxx"), + vlQueryLiteral(""), + }, + vlQueryLiteral(".abc"), + }, + }, + { + query: "test.{foo1,foo2,sub.{foo1,foo2.xyz{abc,xyz.abc,{xyz,abc.xyz}}}}.test.{foo1,foo2,sub.{foo1,foo2.xyz{abc,xyz.abc,{xyz,abc.xyz}}}}", + output: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("foo1"), + &vlQuery{ + vlQueryLiteral("foo2.xyz"), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + }, + }, + }, + }, + }, + vlQueryLiteral(".test."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("foo1"), + &vlQuery{ + vlQueryLiteral("foo2.xyz"), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + }, + }, + }, + }, + }, + }, + }, + } { + t.Run(tcase.query, func(t *testing.T) { + t.Logf("case: TestValueListQueryParser/'^%s$'", regexp.QuoteMeta(tcase.query)) + + vlq, err := parseValueLists(tcase.query) + if (err != nil || tcase.err != nil) && ((err == nil) || (tcase.err == nil) || (err.Error() != tcase.err.Error())) { + t.Errorf("err = %s; want %s", err, tcase.err) + } + + // log.Printf("query = %+v\n", tcase.query) + // log.Printf("%#v\n", vlq) + // pretty.Printf("%# v\n", vlq) + + if diff := cmp.Diff(vlq, tcase.output); diff != "" { + t.Errorf("diff: %s", diff) + } + + if vlq != nil { + if got, want := vlq.String(), tcase.query; got != want { + t.Errorf("vlq.String() = %s; want %s", got, want) + } + } + }) + } + + // query := + // vlq, err := parseValueLists(query) + // log.Printf("query = %+v\n", query) + // log.Printf("err = %+v\n", err) + // pretty.Println(vlq) + + // query := `{{{test,abc},xyz.abc},xyz.abc}.abc` + // vlq, err := parseValueLists(query) + // log.Printf("query = %+v\n", query) + // log.Printf("err = %+v\n", err) + // pretty.Println(vlq) +} + +func TestValueListQueryRewrite(t *testing.T) { + for _, tcase := range []struct { + name string + query *vlQuery + output []string + }{ + { + name: "test.{test,abc,abc.xyz}{test,abc,abc.xyz}.test", + query: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral("abc.xyz"), + }, + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral("abc.xyz"), + }, + vlQueryLiteral(".test"), + }, + output: []string{ + "test.{test,abc}{test,abc}.test", + "test.{test,abc}abc.xyz.test", + "test.abc.xyz{test,abc}.test", + "test.abc.xyzabc.xyz.test", + }, + }, + { + name: "test.{test,abc,abc.xyz,{test1,abc1,abc1.xyz1}}.test", + query: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral("abc.xyz"), + &vlQueryList{ + vlQueryLiteral("test1"), + vlQueryLiteral("abc1"), + vlQueryLiteral("abc1.xyz1"), + }, + }, + vlQueryLiteral(".test"), + }, + output: []string{ + "test.{test,abc,test1,abc1}.test", + "test.abc.xyz.test", + "test.abc1.xyz1.test", + }, + }, + { + name: "test.{test,abc,abc.xyz,{sub.{test1,abc1,abc1.xyz1}}}.test", + query: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("test"), + vlQueryLiteral("abc"), + vlQueryLiteral("abc.xyz"), + &vlQueryList{ + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("test1"), + vlQueryLiteral("abc1"), + vlQueryLiteral("abc1.xyz1"), // incorrect + }, + }, + }, + }, + vlQueryLiteral(".test"), + }, + output: []string{ + "test.{test,abc}.test", + "test.sub.{test1,abc1}.test", + "test.sub.abc1.xyz1.test", + "test.abc.xyz.test", + }, + }, + { + name: "test.{foo1,foo2,sub.{foo1,foo2}}.test", + query: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + }, + }, + }, + vlQueryLiteral(".test"), + }, + output: []string{ + "test.{foo1,foo2}.test", + "test.sub.{foo1,foo2}.test", + }, + }, + { + name: "test.{foo1,foo2,sub.{foo1,foo2.xyz{abc,xyz.abc,{xyz,abc.xyz}}}}.test", + query: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("foo1"), + &vlQuery{ + vlQueryLiteral("foo2.xyz"), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + }, + }, + }, + }, + }, + vlQueryLiteral(".test"), + }, + output: []string{ + "test.{foo1,foo2}.test", + "test.sub.foo1.test", + "test.sub.foo2.xyz{abc,xyz}.test", + "test.sub.foo2.xyzxyz.abc.test", + "test.sub.foo2.xyzabc.xyz.test", + }, + }, + { + name: `a.b.c.{{eu-central1-a,eu-central2a,eu-west1-a,as-southeast1-a,as-east1-a,eu-west2-a,eu-west6a},by_az.{eu-central1-a,eu-central2a,eu-west1-a,as-southeast1-a,as-east1-a,eu-west2-a,eu-west6a}}.d.e.f.*.g.sum`, + query: &vlQuery{ + vlQueryLiteral("a.b.c."), + &vlQueryList{ + &vlQueryList{ + vlQueryLiteral("eu-central1-a"), + vlQueryLiteral("eu-central2a"), + vlQueryLiteral("eu-west1-a"), + vlQueryLiteral("as-southeast1-a"), + vlQueryLiteral("as-east1-a"), + vlQueryLiteral("eu-west2-a"), + vlQueryLiteral("eu-west6a"), + }, + &vlQuery{ + vlQueryLiteral("by_az."), + &vlQueryList{ + vlQueryLiteral("eu-central1-a"), + vlQueryLiteral("eu-central2a"), + vlQueryLiteral("eu-west1-a"), + vlQueryLiteral("as-southeast1-a"), + vlQueryLiteral("as-east1-a"), + vlQueryLiteral("eu-west2-a"), + vlQueryLiteral("eu-west6a"), + }, + }, + }, + vlQueryLiteral(".d.e.f.*.g.sum"), + }, + output: []string{ + "a.b.c.{eu-central1-a,eu-central2a,eu-west1-a,as-southeast1-a,as-east1-a,eu-west2-a,eu-west6a}.d.e.f.*.g.sum", + "a.b.c.by_az.{eu-central1-a,eu-central2a,eu-west1-a,as-southeast1-a,as-east1-a,eu-west2-a,eu-west6a}.d.e.f.*.g.sum", + }, + }, + { + name: "test.{foo1,foo2,sub.{foo1,foo2.xyz{abc,xyz.abc,{xyz,abc.xyz}}}}.test.{foo1,foo2,sub.{foo1,foo2.xyz{abc,xyz.abc,{xyz,abc.xyz}}}}", + query: &vlQuery{ + vlQueryLiteral("test."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("foo1"), + &vlQuery{ + vlQueryLiteral("foo2.xyz"), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + }, + }, + }, + }, + }, + vlQueryLiteral(".test."), + &vlQueryList{ + vlQueryLiteral("foo1"), + vlQueryLiteral("foo2"), + &vlQuery{ + vlQueryLiteral("sub."), + &vlQueryList{ + vlQueryLiteral("foo1"), + &vlQuery{ + vlQueryLiteral("foo2.xyz"), + &vlQueryList{ + vlQueryLiteral("abc"), + vlQueryLiteral("xyz.abc"), + &vlQueryList{ + vlQueryLiteral("xyz"), + vlQueryLiteral("abc.xyz"), + }, + }, + }, + }, + }, + }, + }, + output: []string{ + "test.{foo1,foo2}.test.{foo1,foo2}", + "test.{foo1,foo2}.test.sub.foo1", + "test.{foo1,foo2}.test.sub.foo2.xyz{abc,xyz}", + "test.{foo1,foo2}.test.sub.foo2.xyzxyz.abc", + "test.{foo1,foo2}.test.sub.foo2.xyzabc.xyz", + + "test.sub.foo1.test.{foo1,foo2}", + "test.sub.foo1.test.sub.foo1", + "test.sub.foo1.test.sub.foo2.xyz{abc,xyz}", + "test.sub.foo1.test.sub.foo2.xyzxyz.abc", + "test.sub.foo1.test.sub.foo2.xyzabc.xyz", + + "test.sub.foo2.xyz{abc,xyz}.test.{foo1,foo2}", + "test.sub.foo2.xyz{abc,xyz}.test.sub.foo1", + "test.sub.foo2.xyz{abc,xyz}.test.sub.foo2.xyz{abc,xyz}", + "test.sub.foo2.xyz{abc,xyz}.test.sub.foo2.xyzxyz.abc", + "test.sub.foo2.xyz{abc,xyz}.test.sub.foo2.xyzabc.xyz", + + "test.sub.foo2.xyzxyz.abc.test.{foo1,foo2}", + "test.sub.foo2.xyzxyz.abc.test.sub.foo1", + "test.sub.foo2.xyzxyz.abc.test.sub.foo2.xyz{abc,xyz}", + "test.sub.foo2.xyzxyz.abc.test.sub.foo2.xyzxyz.abc", + "test.sub.foo2.xyzxyz.abc.test.sub.foo2.xyzabc.xyz", + + "test.sub.foo2.xyzabc.xyz.test.{foo1,foo2}", + "test.sub.foo2.xyzabc.xyz.test.sub.foo1", + "test.sub.foo2.xyzabc.xyz.test.sub.foo2.xyz{abc,xyz}", + "test.sub.foo2.xyzabc.xyz.test.sub.foo2.xyzxyz.abc", + "test.sub.foo2.xyzabc.xyz.test.sub.foo2.xyzabc.xyz", + }, + }, + { + name: `{{xyz0,abc0.xdb}{{xyz1,abc1,xyz1.abc}test2{abc.abc3,xyz3},}{{xyz4,abc.xyz4}{abc5,xyz5},{abc6,xyz.abc6}{{abc.xyz7,abc7}{abc.xyz8},{{{abc.xyz9}{abc.xyz10,abc10,xyz10}{abc11,xyz11,abc.xyz11}{abc12,xyz12,abc12},{abc13,xyz13}{abc14,xyz14,abc14}}}}},test15}.test16.{abc17,xyz17,abc18.{xyz19,abc19}}`, + query: &vlQuery{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("xyz0"), + vlQueryLiteral("abc0.xdb"), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("xyz1"), + vlQueryLiteral("abc1"), + vlQueryLiteral("xyz1.abc"), + }, + vlQueryLiteral("test2"), + &vlQueryList{ + vlQueryLiteral("abc.abc3"), + vlQueryLiteral("xyz3"), + }, + }, + vlQueryLiteral(""), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("xyz4"), + vlQueryLiteral("abc.xyz4"), + }, + &vlQueryList{ + vlQueryLiteral("abc5"), + vlQueryLiteral("xyz5"), + }, + }, + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc6"), + vlQueryLiteral("xyz.abc6"), + }, + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc.xyz7"), + vlQueryLiteral("abc7"), + }, + &vlQueryList{ + vlQueryLiteral("abc.xyz8"), + }, + }, + &vlQueryList{ + &vlQueryList{ + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc.xyz9"), + }, + &vlQueryList{ + vlQueryLiteral("abc.xyz10"), + vlQueryLiteral("abc10"), + vlQueryLiteral("xyz10"), + }, + &vlQueryList{ + vlQueryLiteral("abc11"), + vlQueryLiteral("xyz11"), + vlQueryLiteral("abc.xyz11"), + }, + &vlQueryList{ + vlQueryLiteral("abc12"), + vlQueryLiteral("xyz12"), + vlQueryLiteral("abc12"), + }, + }, + &vlQuery{ + &vlQueryList{ + vlQueryLiteral("abc13"), + vlQueryLiteral("xyz13"), + }, + &vlQueryList{ + vlQueryLiteral("abc14"), + vlQueryLiteral("xyz14"), + vlQueryLiteral("abc14"), + }, + }, + }, + }, + }, + }, + }, + }, + vlQueryLiteral("test15"), + }, + vlQueryLiteral(".test16."), + &vlQueryList{ + vlQueryLiteral("abc17"), + vlQueryLiteral("xyz17"), + &vlQuery{ + vlQueryLiteral("abc18."), + &vlQueryList{ + vlQueryLiteral("xyz19"), + vlQueryLiteral("abc19"), + }, + }, + }, + }, + output: vlqRewriteVeryBigOutput0, + }, + } { + t.Run(tcase.name, func(t *testing.T) { + t.Logf("case: TestValueListQueryRewrite/'^%s$'", regexp.QuoteMeta(tcase.name)) + + // log.Printf("tcase.query.String() = %+v\n", tcase.query.String()) + + newQueries, err := tcase.query.expandBySubquery(65536) + if err != nil { + t.Error(err) + } + + var result []string + for _, q := range newQueries { + result = append(result, q.String()) + } + // pretty.Println(result) + + if diff := cmp.Diff(result, tcase.output); diff != "" { + t.Errorf("diff: %s", diff) + } + }) + } +} + +var vlqRewriteVeryBigOutput0 = []string{"test15.test16.{abc17,xyz17}", "test15.test16.abc18.{xyz19,abc19}", "xyz0xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "xyz0xyz1.abctest2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdbxyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdbabc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbabc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbabc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbabc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbabc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdbabc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbabc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbabc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbabc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdb{xyz1,abc1}test2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2xyz3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc.xyz4{abc5,xyz5}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc.xyz4{abc5,xyz5}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9{abc10,xyz10}abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10{abc11,xyz11}{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz9abc.xyz10abc.xyz11{abc12,xyz12,abc12}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6{abc13,xyz13}{abc14,xyz14,abc14}.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc7abc.xyz8.test16.abc18.{xyz19,abc19}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.{abc17,xyz17}", "abc0.xdbxyz1.abctest2abc.abc3xyz.abc6abc.xyz7abc.xyz8.test16.abc18.{xyz19,abc19}"}