diff --git a/.gitignore b/.gitignore index ae5de48..e6e8d8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -gron +/gron *.tgz *.zip *.swp diff --git a/flake.nix b/flake.nix index 5c9e157..4c4014f 100644 --- a/flake.nix +++ b/flake.nix @@ -67,10 +67,10 @@ settings.formatter = { prettier = { excludes = [ - "testdata/large-line.json" - "testdata/long-stream.json" - "testdata/scalar-stream.json" - "testdata/stream.json" + "internal/gron/testdata/large-line.json" + "internal/gron/testdata/long-stream.json" + "internal/gron/testdata/scalar-stream.json" + "internal/gron/testdata/stream.json" ]; }; }; @@ -84,7 +84,11 @@ treefmt.enable = true; typos = { enable = true; - excludes = [ "ADVANCED.mkd" "testdata/.*" "ungron_test.go" ]; + excludes = [ + "ADVANCED.mkd" + "internal/gron/testdata/.*" + "internal/gron/ungron_test.go" + ]; }; }; }; diff --git a/go.mod b/go.mod index 203762e..2c7b279 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,10 @@ require ( github.com/mattn/go-colorable v0.1.13 github.com/nwidger/jsoncolor v0.3.2 github.com/pkg/errors v0.9.1 + gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/mattn/go-isatty v0.0.19 // indirect golang.org/x/sys v0.10.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d3fbe99..5615de9 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/gron/decoder.go b/internal/gron/decoder.go new file mode 100644 index 0000000..ec51383 --- /dev/null +++ b/internal/gron/decoder.go @@ -0,0 +1,26 @@ +package gron + +import ( + "encoding/json" + "gopkg.in/yaml.v3" + "io" +) + +// an ActionFn represents a main action of the program, it accepts +// an input, output and a bitfield of options; returning an exit +// code and any error that occurred +type ActionFn func(io.Reader, io.Writer, int) (int, error) + +type Decoder interface { + Decode(interface{}) error +} + +func MakeDecoder(r io.Reader, optYAML int) Decoder { + if optYAML > 0 { + return yaml.NewDecoder(r) + } else { + d := json.NewDecoder(r) + d.UseNumber() + return d + } +} diff --git a/internal/gron/gron.go b/internal/gron/gron.go new file mode 100644 index 0000000..c9c205c --- /dev/null +++ b/internal/gron/gron.go @@ -0,0 +1,169 @@ +package gron + +import ( + "bufio" + "bytes" + "fmt" + "io" + "sort" + + "github.com/fatih/color" +) + +// Exit codes +const ( + exitOK = iota + exitOpenFile + exitReadInput + exitFormStatements + exitFetchURL + exitParseStatements + exitJSONEncode +) + +// Option bitfields +const ( + optMonochrome = 1 << iota + optNoSort + optJSON + optYAML +) + +// Output colors +var ( + strColor = color.New(color.FgYellow) + braceColor = color.New(color.FgMagenta) + bareColor = color.New(color.FgBlue, color.Bold) + numColor = color.New(color.FgRed) + boolColor = color.New(color.FgCyan) +) + +// Gron is the default action. Given JSON as the input it returns a list +// of assignment statements. Possible options are optNoSort and optMonochrome +func Gron(r io.Reader, w io.Writer, opts int) (int, error) { + var err error + + var conv StatementConv + if opts&optMonochrome > 0 { + conv = StatementToString + } else { + conv = StatementToColorString + } + + ss, err := StatementsFromJSON(MakeDecoder(r, opts&optYAML), Statement{{"json", TypBare}}) + if err != nil { + goto out + } + + // Go's maps do not have well-defined ordering, but we want a consistent + // output for a given input, so we must sort the statements + if opts&optNoSort == 0 { + sort.Sort(ss) + } + + for _, s := range ss { + if opts&optJSON > 0 { + s, err = s.Jsonify() + if err != nil { + goto out + } + } + fmt.Fprintln(w, conv(s)) + } + +out: + if err != nil { + return exitFormStatements, fmt.Errorf("failed to form statements: %s", err) + } + return exitOK, nil +} + +// GronStream is like the gron action, but it treats the input as one +// JSON object per line. There's a bit of code duplication from the +// gron action, but it'd be fairly messy to combine the two actions +func GronStream(r io.Reader, w io.Writer, opts int) (int, error) { + var err error + errstr := "failed to form statements" + var i int + var sc *bufio.Scanner + var buf []byte + + var conv func(s Statement) string + if opts&optMonochrome > 0 { + conv = StatementToString + } else { + conv = StatementToColorString + } + + // Helper function to make the prefix statements for each line + makePrefix := func(index int) Statement { + return Statement{ + {"json", TypBare}, + {"[", TypLBrace}, + {fmt.Sprintf("%d", index), TypNumericKey}, + {"]", TypRBrace}, + } + } + + // The first line of output needs to establish that the top-level + // thing is actually an array... + top := Statement{ + {"json", TypBare}, + {"=", TypEquals}, + {"[]", TypEmptyArray}, + {";", TypSemi}, + } + + if opts&optJSON > 0 { + top, err = top.Jsonify() + if err != nil { + goto out + } + } + + fmt.Fprintln(w, conv(top)) + + // Read the input line by line + sc = bufio.NewScanner(r) + buf = make([]byte, 0, 64*1024) + sc.Buffer(buf, 1024*1024) + i = 0 + for sc.Scan() { + + line := bytes.NewBuffer(sc.Bytes()) + + var ss Statements + ss, err = StatementsFromJSON(MakeDecoder(line, opts&optYAML), makePrefix(i)) + i++ + if err != nil { + goto out + } + + // Go's maps do not have well-defined ordering, but we want a consistent + // output for a given input, so we must sort the statements + if opts&optNoSort == 0 { + sort.Sort(ss) + } + + for _, s := range ss { + if opts&optJSON > 0 { + s, err = s.Jsonify() + if err != nil { + goto out + } + + } + fmt.Fprintln(w, conv(s)) + } + } + if err = sc.Err(); err != nil { + errstr = "error reading multiline input: %s" + } + +out: + if err != nil { + return exitFormStatements, fmt.Errorf(errstr+": %s", err) + } + return exitOK, nil + +} diff --git a/main_test.go b/internal/gron/gron_test.go similarity index 94% rename from main_test.go rename to internal/gron/gron_test.go index 44fe0e9..a5c829e 100644 --- a/main_test.go +++ b/internal/gron/gron_test.go @@ -1,4 +1,4 @@ -package main +package gron import ( "bytes" @@ -32,7 +32,7 @@ func TestGron(t *testing.T) { } out := &bytes.Buffer{} - code, err := gron(in, out, optMonochrome) + code, err := Gron(in, out, optMonochrome) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -71,7 +71,7 @@ func TestGronStream(t *testing.T) { } out := &bytes.Buffer{} - code, err := gronStream(in, out, optMonochrome) + code, err := GronStream(in, out, optMonochrome) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -109,7 +109,7 @@ func TestLargeGronStream(t *testing.T) { } out := &bytes.Buffer{} - code, err := gronStream(in, out, optMonochrome) + code, err := GronStream(in, out, optMonochrome) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -159,7 +159,7 @@ func TestUngron(t *testing.T) { } out := &bytes.Buffer{} - code, err := ungron(in, out, optMonochrome) + code, err := Ungron(in, out, optMonochrome) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -206,7 +206,7 @@ func TestGronJ(t *testing.T) { } out := &bytes.Buffer{} - code, err := gron(in, out, optMonochrome|optJSON) + code, err := Gron(in, out, optMonochrome|optJSON) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -245,7 +245,7 @@ func TestGronStreamJ(t *testing.T) { } out := &bytes.Buffer{} - code, err := gronStream(in, out, optMonochrome|optJSON) + code, err := GronStream(in, out, optMonochrome|optJSON) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -292,7 +292,7 @@ func TestUngronJ(t *testing.T) { } out := &bytes.Buffer{} - code, err := ungron(in, out, optMonochrome|optJSON) + code, err := Ungron(in, out, optMonochrome|optJSON) if code != exitOK { t.Errorf("want exitOK; have %d", code) @@ -329,7 +329,7 @@ func BenchmarkBigJSON(b *testing.B) { b.Fatalf("failed to rewind input: %s", err) } - _, err := gron(in, out, optMonochrome|optNoSort) + _, err := Gron(in, out, optMonochrome|optNoSort) if err != nil { b.Fatalf("failed to gron: %s", err) } diff --git a/identifier.go b/internal/gron/identifier.go similarity index 99% rename from identifier.go rename to internal/gron/identifier.go index 02345e5..6e4e3d4 100644 --- a/identifier.go +++ b/internal/gron/identifier.go @@ -1,4 +1,4 @@ -package main +package gron import "unicode" diff --git a/identifier_test.go b/internal/gron/identifier_test.go similarity index 99% rename from identifier_test.go rename to internal/gron/identifier_test.go index 82df524..504c12a 100644 --- a/identifier_test.go +++ b/internal/gron/identifier_test.go @@ -1,4 +1,4 @@ -package main +package gron import "testing" diff --git a/statements.go b/internal/gron/statements.go similarity index 64% rename from statements.go rename to internal/gron/statements.go index 653ef52..74a11d1 100644 --- a/statements.go +++ b/internal/gron/statements.go @@ -1,4 +1,4 @@ -package main +package gron import ( "encoding/json" @@ -10,19 +10,19 @@ import ( "github.com/pkg/errors" ) -// A statement is a slice of tokens representing an assignment statement. -// An assignment statement is something like: +// A Statement is a slice of tokens representing an assignment Statement. +// An assignment Statement is something like: // // json.city = "Leeds"; // // Where 'json', '.', 'city', '=', '"Leeds"' and ';' are discrete tokens. // Statements are stored as tokens to make sorting more efficient, and so // that the same type can easily be used when gronning and ungronning. -type statement []token +type Statement []Token // String returns the string form of a statement rather than the // underlying slice of tokens -func (s statement) String() string { +func (s Statement) String() string { out := make([]string, 0, len(s)+2) for _, t := range s { out = append(out, t.format()) @@ -31,7 +31,7 @@ func (s statement) String() string { } // colorString returns the string form of a statement with ASCII color codes -func (s statement) colorString() string { +func (s Statement) colorString() string { out := make([]string, 0, len(s)+2) for _, t := range s { out = append(out, t.formatColor()) @@ -39,148 +39,148 @@ func (s statement) colorString() string { return strings.Join(out, "") } -// a statementconv converts a statement to string -type statementconv func(s statement) string +// a StatementConv converts a statement to string +type StatementConv func(s Statement) string // statementconv variant of statement.String -func statementToString(s statement) string { +func StatementToString(s Statement) string { return s.String() } // statementconv variant of statement.colorString -func statementToColorString(s statement) string { +func StatementToColorString(s Statement) string { return s.colorString() } // withBare returns a copy of a statement with a new bare // word token appended to it -func (s statement) withBare(k string) statement { - new := make(statement, len(s), len(s)+2) +func (s Statement) withBare(k string) Statement { + new := make(Statement, len(s), len(s)+2) copy(new, s) return append( new, - token{".", typDot}, - token{k, typBare}, + Token{".", TypDot}, + Token{k, TypBare}, ) } -// jsonify converts an assignment statement to a JSON representation -func (s statement) jsonify() (statement, error) { +// Jsonify converts an assignment statement to a JSON representation +func (s Statement) Jsonify() (Statement, error) { // If m is the number of keys occurring in the left hand side // of s, then len(s) is in between 2*m+4 and 3*m+4. The resultant // statement j (carrying the JSON representation) is always 2*m+5 // long. So len(s)+1 ≥ 2*m+5 = len(j). Therefore an initaial // allocation of j with capacity len(s)+1 will allow us to carry // through without reallocation. - j := make(statement, 0, len(s)+1) - if len(s) < 4 || s[0].typ != typBare || s[len(s)-3].typ != typEquals || - s[len(s)-1].typ != typSemi { + j := make(Statement, 0, len(s)+1) + if len(s) < 4 || s[0].Typ != TypBare || s[len(s)-3].Typ != TypEquals || + s[len(s)-1].Typ != TypSemi { return nil, errors.New("non-assignment statement") } - j = append(j, token{"[", typLBrace}) - j = append(j, token{"[", typLBrace}) + j = append(j, Token{"[", TypLBrace}) + j = append(j, Token{"[", TypLBrace}) for _, t := range s[1 : len(s)-3] { - switch t.typ { - case typNumericKey, typQuotedKey: + switch t.Typ { + case TypNumericKey, TypQuotedKey: j = append(j, t) - j = append(j, token{",", typComma}) - case typBare: - j = append(j, token{quoteString(t.text), typQuotedKey}) - j = append(j, token{",", typComma}) + j = append(j, Token{",", TypComma}) + case TypBare: + j = append(j, Token{quoteString(t.Text), TypQuotedKey}) + j = append(j, Token{",", TypComma}) } } - if j[len(j)-1].typ == typComma { + if j[len(j)-1].Typ == TypComma { j = j[:len(j)-1] } - j = append(j, token{"]", typLBrace}) - j = append(j, token{",", typComma}) + j = append(j, Token{"]", TypLBrace}) + j = append(j, Token{",", TypComma}) j = append(j, s[len(s)-2]) - j = append(j, token{"]", typLBrace}) + j = append(j, Token{"]", TypLBrace}) return j, nil } // withQuotedKey returns a copy of a statement with a new // quoted key token appended to it -func (s statement) withQuotedKey(k string) statement { - new := make(statement, len(s), len(s)+3) +func (s Statement) withQuotedKey(k string) Statement { + new := make(Statement, len(s), len(s)+3) copy(new, s) return append( new, - token{"[", typLBrace}, - token{quoteString(k), typQuotedKey}, - token{"]", typRBrace}, + Token{"[", TypLBrace}, + Token{quoteString(k), TypQuotedKey}, + Token{"]", TypRBrace}, ) } // withNumericKey returns a copy of a statement with a new // numeric key token appended to it -func (s statement) withNumericKey(k int) statement { - new := make(statement, len(s), len(s)+3) +func (s Statement) withNumericKey(k int) Statement { + new := make(Statement, len(s), len(s)+3) copy(new, s) return append( new, - token{"[", typLBrace}, - token{strconv.Itoa(k), typNumericKey}, - token{"]", typRBrace}, + Token{"[", TypLBrace}, + Token{strconv.Itoa(k), TypNumericKey}, + Token{"]", TypRBrace}, ) } -// statements is a list of assignment statements. +// Statements is a list of assignment Statements. // E.g statement: json.foo = "bar"; -type statements []statement +type Statements []Statement -// addWithValue takes a statement representing a path, copies it, +// AddWithValue takes a statement representing a path, copies it, // adds a value token to the end of the statement and appends // the new statement to the list of statements -func (ss *statements) addWithValue(path statement, value token) { - s := make(statement, len(path), len(path)+3) +func (ss *Statements) AddWithValue(path Statement, value Token) { + s := make(Statement, len(path), len(path)+3) copy(s, path) - s = append(s, token{"=", typEquals}, value, token{";", typSemi}) + s = append(s, Token{"=", TypEquals}, value, Token{";", TypSemi}) *ss = append(*ss, s) } -// add appends a new complete statement to list of statements -func (ss *statements) add(s statement) { +// Add appends a new complete statement to list of statements +func (ss *Statements) Add(s Statement) { *ss = append(*ss, s) } // Len returns the number of statements for sort.Sort -func (ss statements) Len() int { +func (ss Statements) Len() int { return len(ss) } // Swap swaps two statements for sort.Sort -func (ss statements) Swap(i, j int) { +func (ss Statements) Swap(i, j int) { ss[i], ss[j] = ss[j], ss[i] } -// a statementmaker is a function that makes a statement +// a StatementMaker is a function that makes a statement // from string -type statementmaker func(str string) (statement, error) +type StatementMaker func(str string) (Statement, error) -// statementFromString takes statement string, lexes it and returns +// StatementFromString takes statement string, lexes it and returns // the corresponding statement -func statementFromString(str string) statement { +func StatementFromString(str string) Statement { l := newLexer(str) s := l.lex() return s } // statementmaker variant of statementFromString -func statementFromStringMaker(str string) (statement, error) { - return statementFromString(str), nil +func StatementFromStringMaker(str string) (Statement, error) { + return StatementFromString(str), nil } // statementFromJson returns statement encoded by // JSON specification -func statementFromJSONSpec(str string) (statement, error) { +func StatementFromJSONSpec(str string) (Statement, error) { var a []interface{} var ok bool var v interface{} - var s statement - var t tokenTyp + var s Statement + var t TokenTyp var nstr string var nbuf []byte @@ -200,58 +200,58 @@ func statementFromJSONSpec(str string) (statement, error) { // We'll append one initial token, then 3 tokens for each element of a, // then 3 closing tokens, that's altogether 3*len(a)+4. - s = make(statement, 0, 3*len(a)+4) - s = append(s, token{"json", typBare}) + s = make(Statement, 0, 3*len(a)+4) + s = append(s, Token{"json", TypBare}) for _, e := range a { - s = append(s, token{"[", typLBrace}) + s = append(s, Token{"[", TypLBrace}) switch e := e.(type) { case string: - s = append(s, token{quoteString(e), typQuotedKey}) + s = append(s, Token{quoteString(e), TypQuotedKey}) case float64: nbuf, err = json.Marshal(e) if err != nil { return nil, errors.Wrap(err, "JSON internal error") } nstr = fmt.Sprintf("%s", nbuf) - s = append(s, token{nstr, typNumericKey}) + s = append(s, Token{nstr, TypNumericKey}) default: ok = false goto out } - s = append(s, token{"]", typRBrace}) + s = append(s, Token{"]", TypRBrace}) } - s = append(s, token{"=", typEquals}) + s = append(s, Token{"=", TypEquals}) switch v := v.(type) { case bool: if v { - t = typTrue + t = TypTrue } else { - t = typFalse + t = TypFalse } case float64: - t = typNumber + t = TypNumber case string: - t = typString + t = TypString case []interface{}: ok = (len(v) == 0) if !ok { goto out } - t = typEmptyArray + t = TypEmptyArray case map[string]interface{}: ok = (len(v) == 0) if !ok { goto out } - t = typEmptyObject + t = TypEmptyObject default: ok = (v == nil) if !ok { goto out } - t = typNull + t = TypNull } nbuf, err = json.Marshal(v) @@ -259,9 +259,9 @@ func statementFromJSONSpec(str string) (statement, error) { return nil, errors.Wrap(err, "JSON internal error") } nstr = fmt.Sprintf("%s", nbuf) - s = append(s, token{nstr, t}) + s = append(s, Token{nstr, t}) - s = append(s, token{";", typSemi}) + s = append(s, Token{";", TypSemi}) out: if !ok { @@ -271,7 +271,7 @@ out: } // ungron turns statements into a proper datastructure -func (ss statements) toInterface() (interface{}, error) { +func (ss Statements) ToInterface() (interface{}, error) { // Get all the individually parsed statements var parsed []interface{} @@ -308,7 +308,7 @@ func (ss statements) toInterface() (interface{}, error) { // Less compares two statements for sort.Sort // Implements a natural sort to keep array indexes in order -func (ss statements) Less(a, b int) bool { +func (ss Statements) Less(a, b int) bool { // ss[a] and ss[b] are both slices of tokens. The first // thing we need to do is find the first token (if any) @@ -344,36 +344,36 @@ func (ss statements) Less(a, b int) bool { tb := ss[b][diffIndex] // An equals always comes first - if ta.typ == typEquals { + if ta.Typ == TypEquals { return true } - if tb.typ == typEquals { + if tb.Typ == TypEquals { return false } // If both tokens are numeric keys do an integer comparison - if ta.typ == typNumericKey && tb.typ == typNumericKey { - ia, _ := strconv.Atoi(ta.text) - ib, _ := strconv.Atoi(tb.text) + if ta.Typ == TypNumericKey && tb.Typ == TypNumericKey { + ia, _ := strconv.Atoi(ta.Text) + ib, _ := strconv.Atoi(tb.Text) return ia < ib } // If neither token is a number, just do a string comparison - if ta.typ != typNumber || tb.typ != typNumber { - return ta.text < tb.text + if ta.Typ != TypNumber || tb.Typ != TypNumber { + return ta.Text < tb.Text } // We have two numbers to compare so turn them into json.Number // for comparison - na, _ := json.Number(ta.text).Float64() - nb, _ := json.Number(tb.text).Float64() + na, _ := json.Number(ta.Text).Float64() + nb, _ := json.Number(tb.Text).Float64() return na < nb } // Contains searches the statements for a given statement // Mostly to make testing things easier -func (ss statements) Contains(search statement) bool { +func (ss Statements) Contains(search Statement) bool { for _, i := range ss { if reflect.DeepEqual(i, search) { return true @@ -382,25 +382,25 @@ func (ss statements) Contains(search statement) bool { return false } -// statementsFromJSON takes an io.Reader containing JSON +// StatementsFromJSON takes an io.Reader containing JSON // and returns statements or an error on failure -func statementsFromJSON(r decoder, prefix statement) (statements, error) { +func StatementsFromJSON(r Decoder, prefix Statement) (Statements, error) { var top interface{} err := r.Decode(&top) if err != nil { return nil, err } - ss := make(statements, 0, 32) + ss := make(Statements, 0, 32) ss.fill(prefix, top) return ss, nil } // fill takes a prefix statement and some value and recursively fills // the statement list using that value -func (ss *statements) fill(prefix statement, v interface{}) { +func (ss *Statements) fill(prefix Statement, v interface{}) { // Add a statement for the current prefix and value - ss.addWithValue(prefix, valueTokenFromInterface(v)) + ss.AddWithValue(prefix, valueTokenFromInterface(v)) // Recurse into objects and arrays switch vv := v.(type) { diff --git a/statements_test.go b/internal/gron/statements_test.go similarity index 87% rename from statements_test.go rename to internal/gron/statements_test.go index 61fb8c2..8cf8c3d 100644 --- a/statements_test.go +++ b/internal/gron/statements_test.go @@ -1,4 +1,4 @@ -package main +package gron import ( "bytes" @@ -8,10 +8,10 @@ import ( "testing" ) -func statementsFromStringSlice(strs []string) statements { - ss := make(statements, len(strs)) +func statementsFromStringSlice(strs []string) Statements { + ss := make(Statements, len(strs)) for i, str := range strs { - ss[i] = statementFromString(str) + ss[i] = StatementFromString(str) } return ss } @@ -33,7 +33,7 @@ func TestStatementsSimple(t *testing.T) { "": 2 }`) - ss, err := statementsFromJSON(makeDecoder(bytes.NewReader(j), 0), statement{{"json", typBare}}) + ss, err := StatementsFromJSON(MakeDecoder(bytes.NewReader(j), 0), Statement{{"json", TypBare}}) if err != nil { t.Errorf("Want nil error from makeStatementsFromJSON() but got %s", err) @@ -83,7 +83,7 @@ x: | y: "z" id: 66912849`) - ss, err := statementsFromJSON(makeDecoder(bytes.NewReader(j), optYAML), statement{{"yaml", typBare}}) + ss, err := StatementsFromJSON(MakeDecoder(bytes.NewReader(j), optYAML), Statement{{"yaml", TypBare}}) if err != nil { t.Errorf("Want nil error from makeStatementsFromJSON() but got %s", err) @@ -179,8 +179,8 @@ func BenchmarkFill(b *testing.B) { } for i := 0; i < b.N; i++ { - ss := make(statements, 0) - ss.fill(statement{{"json", typBare}}, top) + ss := make(Statements, 0) + ss.fill(Statement{{"json", TypBare}}, top) } } @@ -206,7 +206,7 @@ func TestUngronStatementsSimple(t *testing.T) { }, } - have, err := in.toInterface() + have, err := in.ToInterface() if err != nil { t.Fatalf("want nil error but have: %s", err) @@ -222,14 +222,14 @@ func TestUngronStatementsSimple(t *testing.T) { } func TestUngronStatementsInvalid(t *testing.T) { - cases := []statements{ + cases := []Statements{ statementsFromStringSlice([]string{``}), statementsFromStringSlice([]string{`this isn't a statement at all`}), statementsFromStringSlice([]string{`json[0] = 1;`, `json.bar = 1;`}), } for _, c := range cases { - _, err := c.toInterface() + _, err := c.ToInterface() if err == nil { t.Errorf("want non-nil error; have nil") } @@ -237,13 +237,13 @@ func TestUngronStatementsInvalid(t *testing.T) { } func TestStatement(t *testing.T) { - s := statement{ - token{"json", typBare}, - token{".", typDot}, - token{"foo", typBare}, - token{"=", typEquals}, - token{"2", typNumber}, - token{";", typSemi}, + s := Statement{ + Token{"json", TypBare}, + Token{".", TypDot}, + Token{"foo", TypBare}, + Token{"=", TypEquals}, + Token{"2", TypNumber}, + Token{";", TypSemi}, } have := s.String() diff --git a/testdata/big.json b/internal/gron/testdata/big.json similarity index 100% rename from testdata/big.json rename to internal/gron/testdata/big.json diff --git a/testdata/duplicate-numeric.gron b/internal/gron/testdata/duplicate-numeric.gron similarity index 100% rename from testdata/duplicate-numeric.gron rename to internal/gron/testdata/duplicate-numeric.gron diff --git a/testdata/duplicate-numeric.json b/internal/gron/testdata/duplicate-numeric.json similarity index 100% rename from testdata/duplicate-numeric.json rename to internal/gron/testdata/duplicate-numeric.json diff --git a/testdata/github.gron b/internal/gron/testdata/github.gron similarity index 100% rename from testdata/github.gron rename to internal/gron/testdata/github.gron diff --git a/testdata/github.jgron b/internal/gron/testdata/github.jgron similarity index 100% rename from testdata/github.jgron rename to internal/gron/testdata/github.jgron diff --git a/testdata/github.json b/internal/gron/testdata/github.json similarity index 100% rename from testdata/github.json rename to internal/gron/testdata/github.json diff --git a/testdata/grep-separators.gron b/internal/gron/testdata/grep-separators.gron similarity index 100% rename from testdata/grep-separators.gron rename to internal/gron/testdata/grep-separators.gron diff --git a/testdata/grep-separators.json b/internal/gron/testdata/grep-separators.json similarity index 100% rename from testdata/grep-separators.json rename to internal/gron/testdata/grep-separators.json diff --git a/testdata/invalid-type-mismatch.gron b/internal/gron/testdata/invalid-type-mismatch.gron similarity index 100% rename from testdata/invalid-type-mismatch.gron rename to internal/gron/testdata/invalid-type-mismatch.gron diff --git a/testdata/invalid-value.gron b/internal/gron/testdata/invalid-value.gron similarity index 100% rename from testdata/invalid-value.gron rename to internal/gron/testdata/invalid-value.gron diff --git a/testdata/large-line.gron b/internal/gron/testdata/large-line.gron similarity index 100% rename from testdata/large-line.gron rename to internal/gron/testdata/large-line.gron diff --git a/testdata/large-line.json b/internal/gron/testdata/large-line.json similarity index 99% rename from testdata/large-line.json rename to internal/gron/testdata/large-line.json index 918478e..559793b 100644 --- a/testdata/large-line.json +++ b/internal/gron/testdata/large-line.json @@ -1 +1,3 @@ -{"blob":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} +{ + "blob": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +} diff --git a/testdata/long-stream.gron b/internal/gron/testdata/long-stream.gron similarity index 100% rename from testdata/long-stream.gron rename to internal/gron/testdata/long-stream.gron diff --git a/internal/gron/testdata/long-stream.json b/internal/gron/testdata/long-stream.json new file mode 100644 index 0000000..a1aaee1 --- /dev/null +++ b/internal/gron/testdata/long-stream.json @@ -0,0 +1,2304 @@ +{ + "details": [ + { + "_id": "5ae0aa34b3f979b9b85509e0", + "index": 0, + "guid": "164542db-58d9-4d63-aacd-fbf3a7739474", + "isActive": true, + "balance": "$2,644.04", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "blue", + "name": { "first": "Tracy", "last": "Scott" }, + "company": "QUOTEZART", + "email": "tracy.scott@quotezart.io", + "phone": "+1 (998) 407-3468", + "address": "324 Cornelia Street, Echo, Indiana, 8046", + "about": "Nostrud magna ullamco id amet et incididunt officia dolor cillum do. Excepteur amet aliquip non veniam amet est nisi incididunt enim aliqua ad occaecat exercitation. Duis cupidatat ea voluptate consequat anim irure incididunt consequat consectetur amet. Enim exercitation ea eiusmod aliqua occaecat proident proident occaecat incididunt fugiat sint. Eu velit incididunt dolore voluptate in deserunt mollit officia.", + "registered": "Saturday, October 7, 2017 2:37 PM", + "latitude": "-19.206275", + "longitude": "-57.387994", + "tags": [ + "quis", + "elit", + "minim", + "quis", + "ut", + "quis", + "et", + "laboris", + "et", + "quis" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Gwendolyn Barnett" }, + { "id": 1, "name": "Hill Patrick" }, + { "id": 2, "name": "Corinne Pearson" }, + { "id": 3, "name": "Nona Walters" }, + { "id": 4, "name": "Beach Hart" }, + { "id": 5, "name": "Figueroa Russell" }, + { "id": 6, "name": "Eve Cobb" }, + { "id": 7, "name": "Sanchez Bradshaw" }, + { "id": 8, "name": "Irma Turner" }, + { "id": 9, "name": "Keisha Walls" } + ], + "greeting": "Hello, Tracy! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa342f534020c0f882a2", + "index": 1, + "guid": "e3ceb40a-9dbd-4769-96cd-283c227952d4", + "isActive": true, + "balance": "$2,449.54", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { "first": "Nora", "last": "Gates" }, + "company": "ENTALITY", + "email": "nora.gates@entality.name", + "phone": "+1 (845) 592-3644", + "address": "904 Randolph Street, Cowiche, District Of Columbia, 6897", + "about": "Duis in mollit ex consectetur laboris commodo ad laboris do officia. Proident aute officia aliquip mollit incididunt amet est deserunt. Sunt magna ea sit reprehenderit. Enim et non excepteur dolor proident quis dolor ea. Non dolore tempor esse aliqua ipsum cupidatat quis cupidatat sint veniam pariatur.", + "registered": "Wednesday, September 3, 2014 5:55 PM", + "latitude": "-17.863169", + "longitude": "175.110579", + "tags": [ + "sunt", + "ut", + "sint", + "labore", + "adipisicing", + "velit", + "esse", + "consectetur", + "enim", + "ad" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Meagan Daugherty" }, + { "id": 1, "name": "Morin Delacruz" }, + { "id": 2, "name": "Robin Blanchard" }, + { "id": 3, "name": "Georgia Mays" }, + { "id": 4, "name": "Cheri Soto" }, + { "id": 5, "name": "Hobbs Lucas" }, + { "id": 6, "name": "Maritza Garza" }, + { "id": 7, "name": "Kathy Whitney" }, + { "id": 8, "name": "Burch Cortez" }, + { "id": 9, "name": "Jenny Campos" } + ], + "greeting": "Hello, Nora! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34866f48fd0a12505e", + "index": 2, + "guid": "ddcd3d1e-8706-48bf-9dea-554b69706120", + "isActive": false, + "balance": "$3,999.63", + "picture": "http://placehold.it/32x32", + "age": 20, + "eyeColor": "green", + "name": { "first": "Beatrice", "last": "Foley" }, + "company": "KANGLE", + "email": "beatrice.foley@kangle.biz", + "phone": "+1 (832) 487-2607", + "address": "813 Garden Place, Hackneyville, Kentucky, 4301", + "about": "Minim dolor eiusmod ipsum laborum proident. Ad cillum ullamco cupidatat dolor proident irure veniam proident nostrud. Enim non cillum nostrud tempor dolor id dolore laboris mollit non adipisicing. In dolore amet dolor incididunt non dolor magna pariatur anim exercitation eiusmod reprehenderit. Ex elit aute eiusmod ullamco amet consequat nostrud est. Ullamco cupidatat adipisicing amet commodo non ipsum aliqua esse excepteur reprehenderit irure quis consectetur enim. Eu aliqua occaecat do amet exercitation ad fugiat.", + "registered": "Thursday, August 27, 2015 6:31 PM", + "latitude": "-20.102055", + "longitude": "-159.81829", + "tags": [ + "reprehenderit", + "et", + "magna", + "aliquip", + "sit", + "pariatur", + "amet", + "labore", + "Lorem", + "aute" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Lawrence Ratliff" }, + { "id": 1, "name": "Debbie Kent" }, + { "id": 2, "name": "Lynda Morse" }, + { "id": 3, "name": "Wiley Stephenson" }, + { "id": 4, "name": "Mclaughlin Hines" }, + { "id": 5, "name": "Erin Ashley" }, + { "id": 6, "name": "Boyer Dotson" }, + { "id": 7, "name": "Decker Rollins" }, + { "id": 8, "name": "Eddie Lane" }, + { "id": 9, "name": "Cecile Lindsey" } + ], + "greeting": "Hello, Beatrice! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34dc3fbdc4ed72a342", + "index": 3, + "guid": "5dbc0677-c792-420e-b31e-2ba3e520b9bf", + "isActive": false, + "balance": "$1,227.64", + "picture": "http://placehold.it/32x32", + "age": 20, + "eyeColor": "brown", + "name": { "first": "Sherrie", "last": "Brock" }, + "company": "NAVIR", + "email": "sherrie.brock@navir.us", + "phone": "+1 (886) 472-3610", + "address": "916 Oakland Place, Rodman, Louisiana, 8864", + "about": "Eiusmod est minim ullamco minim tempor sunt. Do aliquip tempor et nisi aute do ullamco. Sint non mollit fugiat Lorem laboris pariatur et commodo labore et tempor. Non officia tempor cupidatat aute deserunt ea ut laboris consequat magna.", + "registered": "Saturday, November 12, 2016 3:31 AM", + "latitude": "54.818965", + "longitude": "117.261723", + "tags": [ + "veniam", + "voluptate", + "esse", + "amet", + "deserunt", + "aute", + "elit", + "anim", + "est", + "excepteur" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Sofia Ray" }, + { "id": 1, "name": "Ronda Bates" }, + { "id": 2, "name": "Robert Blankenship" }, + { "id": 3, "name": "Bowers Potts" }, + { "id": 4, "name": "Holcomb Nieves" }, + { "id": 5, "name": "Marquita Glover" }, + { "id": 6, "name": "Manuela Rocha" }, + { "id": 7, "name": "Carey Fitzpatrick" }, + { "id": 8, "name": "Joann Singleton" }, + { "id": 9, "name": "Vincent Johns" } + ], + "greeting": "Hello, Sherrie! You have 8 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa348f55f735b48cfa46", + "index": 4, + "guid": "a1944b22-c22f-49a3-8ac4-45153a3d1de4", + "isActive": true, + "balance": "$2,403.86", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "brown", + "name": { "first": "Stuart", "last": "Mendoza" }, + "company": "SNOWPOKE", + "email": "stuart.mendoza@snowpoke.biz", + "phone": "+1 (940) 532-2198", + "address": "806 High Street, Dunnavant, Idaho, 5507", + "about": "Aute adipisicing deserunt et elit consequat deserunt amet amet officia aliqua in. Et qui minim ea sit exercitation aliquip do laborum consectetur voluptate eiusmod irure. Exercitation reprehenderit eiusmod proident fugiat laborum in aliqua laboris commodo sint et. Amet qui labore culpa excepteur magna voluptate anim mollit eiusmod. Officia mollit eu et laborum reprehenderit ullamco. Proident incididunt incididunt cillum laborum officia veniam aute voluptate officia irure elit.", + "registered": "Wednesday, November 12, 2014 9:10 AM", + "latitude": "-4.553307", + "longitude": "-92.981375", + "tags": [ + "voluptate", + "fugiat", + "non", + "fugiat", + "cupidatat", + "deserunt", + "occaecat", + "dolor", + "aute", + "fugiat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Valeria Burgess" }, + { "id": 1, "name": "Cleveland Noel" }, + { "id": 2, "name": "Arline Oneill" }, + { "id": 3, "name": "Tasha Johnston" }, + { "id": 4, "name": "Graciela Mosley" }, + { "id": 5, "name": "Bartlett Gonzales" }, + { "id": 6, "name": "Darla Bond" }, + { "id": 7, "name": "Gail Hatfield" }, + { "id": 8, "name": "Cecilia Clay" }, + { "id": 9, "name": "Keri May" } + ], + "greeting": "Hello, Stuart! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa342f229045f41285f7", + "index": 5, + "guid": "a087b56e-cd7c-4832-9c07-ec80217d5355", + "isActive": false, + "balance": "$3,736.67", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "blue", + "name": { "first": "Marjorie", "last": "Cunningham" }, + "company": "IMMUNICS", + "email": "marjorie.cunningham@immunics.com", + "phone": "+1 (807) 427-2665", + "address": "649 Whitty Lane, Thatcher, Michigan, 9747", + "about": "Aliquip quis proident consequat magna id ullamco nulla culpa laborum. Quis laborum laborum adipisicing duis duis eu sint exercitation deserunt cillum ea. Incididunt laborum magna Lorem quis officia sint cillum commodo laboris exercitation proident proident. Sit sunt nostrud sint duis. Cillum minim cupidatat sunt ipsum eiusmod ipsum fugiat fugiat culpa consequat. Esse irure consectetur ad officia Lorem eu culpa est ad deserunt velit amet exercitation aute.", + "registered": "Tuesday, October 7, 2014 5:24 PM", + "latitude": "6.552001", + "longitude": "-139.202433", + "tags": [ + "ipsum", + "est", + "officia", + "eiusmod", + "ea", + "fugiat", + "quis", + "voluptate", + "proident", + "dolor" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Glenna Beck" }, + { "id": 1, "name": "Castaneda Spears" }, + { "id": 2, "name": "Justice Michael" }, + { "id": 3, "name": "Shelton Parsons" }, + { "id": 4, "name": "Robertson Good" }, + { "id": 5, "name": "Sheena Burch" }, + { "id": 6, "name": "Tessa Miranda" }, + { "id": 7, "name": "Perkins Barker" }, + { "id": 8, "name": "Maribel Lester" }, + { "id": 9, "name": "Hodge Cabrera" } + ], + "greeting": "Hello, Marjorie! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa3482a305f0781a3aba", + "index": 6, + "guid": "ccfdf87d-b381-4b64-b517-cd60a8fc9f04", + "isActive": false, + "balance": "$2,116.04", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "green", + "name": { "first": "Yvonne", "last": "Duffy" }, + "company": "KENEGY", + "email": "yvonne.duffy@kenegy.co.uk", + "phone": "+1 (956) 575-2780", + "address": "742 Bergen Court, Mahtowa, Alaska, 4598", + "about": "Anim nulla est eu laborum proident et. Sunt anim dolore voluptate non laboris sint mollit laborum exercitation enim aliqua exercitation. Veniam consectetur excepteur esse nostrud cupidatat aute nulla aute ad id mollit. Enim exercitation labore culpa voluptate in ea nulla nulla ex. Id tempor nisi ad proident dolore est cillum eiusmod dolor veniam consectetur labore. Mollit velit cupidatat est mollit adipisicing est exercitation. Veniam aliqua reprehenderit ea tempor.", + "registered": "Monday, December 8, 2014 2:57 AM", + "latitude": "23.863564", + "longitude": "150.896594", + "tags": [ + "voluptate", + "ex", + "consequat", + "in", + "sit", + "nulla", + "commodo", + "adipisicing", + "nulla", + "commodo" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Clemons Snyder" }, + { "id": 1, "name": "Bernard Navarro" }, + { "id": 2, "name": "Burton Burnett" }, + { "id": 3, "name": "Suzette Callahan" }, + { "id": 4, "name": "William Hill" }, + { "id": 5, "name": "Mays Larsen" }, + { "id": 6, "name": "Joanna Graham" }, + { "id": 7, "name": "Fowler Berry" }, + { "id": 8, "name": "Lacey Hayden" }, + { "id": 9, "name": "Shauna Frederick" } + ], + "greeting": "Hello, Yvonne! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa349dcd18765c1626dc", + "index": 7, + "guid": "425bc7f1-467f-4ed6-be2c-ccbcd9555674", + "isActive": false, + "balance": "$3,403.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "blue", + "name": { "first": "Dana", "last": "Reed" }, + "company": "NETPLAX", + "email": "dana.reed@netplax.ca", + "phone": "+1 (988) 463-2342", + "address": "980 Central Avenue, Strykersville, Maryland, 873", + "about": "Sunt nisi duis dolor cupidatat magna quis. Pariatur eu id commodo ea eiusmod dolore cillum veniam voluptate. Anim ex occaecat sit ipsum proident tempor quis ipsum laborum ad. Minim ut quis enim incididunt aliqua tempor. Ullamco exercitation consectetur quis fugiat cupidatat esse est consequat ad aliqua duis ea consectetur consequat. Id ea commodo minim aute.", + "registered": "Sunday, March 22, 2015 7:03 PM", + "latitude": "61.534583", + "longitude": "123.100188", + "tags": [ + "non", + "elit", + "Lorem", + "commodo", + "enim", + "dolor", + "sint", + "qui", + "aliqua", + "cupidatat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Chan Keller" }, + { "id": 1, "name": "Mary Dyer" }, + { "id": 2, "name": "Genevieve Whitfield" }, + { "id": 3, "name": "Meyers York" }, + { "id": 4, "name": "James Carr" }, + { "id": 5, "name": "Rollins Frazier" }, + { "id": 6, "name": "Aurora Nguyen" }, + { "id": 7, "name": "Shawn Jacobs" }, + { "id": 8, "name": "Reba Mcfarland" }, + { "id": 9, "name": "Paige Pitts" } + ], + "greeting": "Hello, Dana! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34d760d6da02fde756", + "index": 8, + "guid": "be208b32-be08-4c6d-86ea-da589d1ec977", + "isActive": false, + "balance": "$1,012.38", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "brown", + "name": { "first": "Schmidt", "last": "Sweeney" }, + "company": "PROWASTE", + "email": "schmidt.sweeney@prowaste.info", + "phone": "+1 (994) 493-3642", + "address": "245 Veterans Avenue, Catherine, Arkansas, 1444", + "about": "Voluptate ut deserunt nostrud nulla anim fugiat occaecat fugiat nisi anim commodo minim consequat. Tempor velit amet cillum aliquip nisi ut. Eu sunt excepteur amet dolor excepteur laborum. Enim minim elit irure proident pariatur ex nulla aute sunt.", + "registered": "Wednesday, April 6, 2016 12:10 PM", + "latitude": "22.555683", + "longitude": "63.232647", + "tags": [ + "aute", + "deserunt", + "ad", + "sint", + "quis", + "tempor", + "sunt", + "consectetur", + "labore", + "Lorem" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Browning House" }, + { "id": 1, "name": "Beverly Hoover" }, + { "id": 2, "name": "Mitchell Figueroa" }, + { "id": 3, "name": "Blackburn Camacho" }, + { "id": 4, "name": "Leila Doyle" }, + { "id": 5, "name": "Lee Montoya" }, + { "id": 6, "name": "Beck Velasquez" }, + { "id": 7, "name": "Charlotte Bird" }, + { "id": 8, "name": "Lillie Velez" }, + { "id": 9, "name": "Williamson Elliott" } + ], + "greeting": "Hello, Schmidt! You have 6 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34a2574825a9fad671", + "index": 9, + "guid": "b3a104cf-4361-421c-9e13-91ae146e517d", + "isActive": true, + "balance": "$1,454.62", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "blue", + "name": { "first": "Davenport", "last": "Marquez" }, + "company": "MUSANPOLY", + "email": "davenport.marquez@musanpoly.me", + "phone": "+1 (843) 438-2469", + "address": "109 Victor Road, Fruitdale, American Samoa, 8856", + "about": "Culpa aliquip Lorem elit laborum aliquip laboris dolore non ea. Est occaecat do minim pariatur pariatur mollit velit laborum eu consectetur qui eiusmod. Consectetur nostrud occaecat dolore sunt mollit. Anim excepteur et nulla consequat laborum dolor Lorem ad.", + "registered": "Sunday, February 16, 2014 11:28 PM", + "latitude": "5.32883", + "longitude": "-128.790048", + "tags": [ + "veniam", + "cillum", + "non", + "qui", + "ullamco", + "quis", + "consequat", + "incididunt", + "laborum", + "deserunt" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Beard Gomez" }, + { "id": 1, "name": "Elaine Lamb" }, + { "id": 2, "name": "Gallegos Merritt" }, + { "id": 3, "name": "Margarita Shepherd" }, + { "id": 4, "name": "Mia Griffin" }, + { "id": 5, "name": "Deena Foreman" }, + { "id": 6, "name": "Muriel Howe" }, + { "id": 7, "name": "Wilder Chang" }, + { "id": 8, "name": "Pearlie Ford" }, + { "id": 9, "name": "Tabatha Mathews" } + ], + "greeting": "Hello, Davenport! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34ce8ffcd27683f469", + "index": 10, + "guid": "d6d9c317-c71c-48ff-a522-905d54cef18b", + "isActive": true, + "balance": "$2,197.16", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": { "first": "Julianne", "last": "Miles" }, + "company": "EXIAND", + "email": "julianne.miles@exiand.org", + "phone": "+1 (981) 429-3214", + "address": "560 Louis Place, Sperryville, Vermont, 7450", + "about": "Aute irure Lorem laborum cillum Lorem ad dolore proident tempor in non. Excepteur fugiat amet proident ut exercitation adipisicing cupidatat esse. Occaecat cillum labore dolore cupidatat consectetur est exercitation mollit dolor dolore.", + "registered": "Wednesday, June 14, 2017 11:19 AM", + "latitude": "-32.254528", + "longitude": "-97.815247", + "tags": [ + "consectetur", + "cupidatat", + "est", + "esse", + "anim", + "et", + "tempor", + "et", + "ex", + "fugiat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Trevino Nash" }, + { "id": 1, "name": "Mills Conley" }, + { "id": 2, "name": "Deirdre Cruz" }, + { "id": 3, "name": "Marsh Webster" }, + { "id": 4, "name": "Frye Johnson" }, + { "id": 5, "name": "Jeanine Craft" }, + { "id": 6, "name": "Fern Richmond" }, + { "id": 7, "name": "Janelle Ramsey" }, + { "id": 8, "name": "Kirby Valentine" }, + { "id": 9, "name": "Lessie Acevedo" } + ], + "greeting": "Hello, Julianne! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34d5b29d6058c2450f", + "index": 11, + "guid": "925f4c31-5a6b-4cf2-b90d-fb0ee37680a6", + "isActive": false, + "balance": "$1,111.42", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "blue", + "name": { "first": "Elva", "last": "Woods" }, + "company": "MAXIMIND", + "email": "elva.woods@maximind.tv", + "phone": "+1 (883) 569-3812", + "address": "540 Trucklemans Lane, Stollings, Oregon, 2549", + "about": "Consequat ut deserunt in esse do nisi. Aliquip laboris ex nulla excepteur occaecat et nulla. Incididunt enim irure officia ex aute nulla est consectetur aute eiusmod. Ea ipsum magna nisi quis ex labore qui occaecat eu aute culpa adipisicing aute cupidatat. Consequat mollit dolore ex deserunt. Deserunt do eiusmod Lorem anim laborum dolor esse aute laboris dolor officia esse officia. Cupidatat consectetur veniam ipsum et mollit cupidatat ullamco et non officia exercitation nisi ea.", + "registered": "Saturday, July 25, 2015 1:20 PM", + "latitude": "-14.967803", + "longitude": "160.339242", + "tags": [ + "incididunt", + "nulla", + "aliquip", + "et", + "quis", + "voluptate", + "aliqua", + "qui", + "in", + "ea" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Compton Holt" }, + { "id": 1, "name": "Christy Padilla" }, + { "id": 2, "name": "Roy Boyer" }, + { "id": 3, "name": "Celina Wright" }, + { "id": 4, "name": "Patton Fowler" }, + { "id": 5, "name": "Juanita Blair" }, + { "id": 6, "name": "Thornton Townsend" }, + { "id": 7, "name": "Mcintyre William" }, + { "id": 8, "name": "Lorena Mckee" }, + { "id": 9, "name": "Alisha Mullen" } + ], + "greeting": "Hello, Elva! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34040ef52f7d92ee6a", + "index": 12, + "guid": "9ccba22d-2de3-4784-b291-93a18c017a82", + "isActive": false, + "balance": "$1,147.66", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { "first": "Lizzie", "last": "Melton" }, + "company": "FUTURITY", + "email": "lizzie.melton@futurity.io", + "phone": "+1 (875) 595-2680", + "address": "584 Indiana Place, Blue, New Jersey, 420", + "about": "Culpa culpa irure duis fugiat magna cillum ut aliqua incididunt. Deserunt nostrud cillum duis reprehenderit ad duis voluptate dolore. Elit officia ullamco minim nisi officia eu eu Lorem sint. Est aute quis occaecat sunt. Excepteur minim commodo exercitation consectetur eiusmod aute elit proident nulla enim ullamco enim. Tempor labore duis ex cupidatat et.", + "registered": "Friday, October 17, 2014 2:39 PM", + "latitude": "-52.473183", + "longitude": "111.529289", + "tags": [ + "enim", + "ut", + "ullamco", + "tempor", + "commodo", + "esse", + "nisi", + "eiusmod", + "exercitation", + "sit" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Sasha Porter" }, + { "id": 1, "name": "Pittman Wilkerson" }, + { "id": 2, "name": "Lloyd Carter" }, + { "id": 3, "name": "Mathews Armstrong" }, + { "id": 4, "name": "Geraldine Harrison" }, + { "id": 5, "name": "Margo Giles" }, + { "id": 6, "name": "Ewing Pollard" }, + { "id": 7, "name": "Esperanza Simon" }, + { "id": 8, "name": "Christa Wiggins" }, + { "id": 9, "name": "Lorraine Wilkinson" } + ], + "greeting": "Hello, Lizzie! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa3468cb0abe9cf31577", + "index": 13, + "guid": "3a1566ab-fb93-417b-8c4f-ead8269d6cc8", + "isActive": false, + "balance": "$1,824.72", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "blue", + "name": { "first": "Ford", "last": "Randolph" }, + "company": "INSECTUS", + "email": "ford.randolph@insectus.name", + "phone": "+1 (982) 589-2146", + "address": "231 Centre Street, Coalmont, Washington, 5554", + "about": "Commodo consequat occaecat ad ea ut id reprehenderit laborum elit ullamco magna. Non aliquip nisi fugiat anim veniam consequat eu qui esse sint magna. Cupidatat officia sunt mollit irure sit nulla excepteur dolor nulla. Fugiat elit deserunt mollit est fugiat laborum magna sint ullamco et in. Commodo voluptate aliqua sit dolore ut excepteur laborum qui dolore.", + "registered": "Friday, February 28, 2014 9:04 PM", + "latitude": "-85.796706", + "longitude": "82.662603", + "tags": [ + "amet", + "exercitation", + "proident", + "do", + "incididunt", + "nisi", + "sunt", + "ullamco", + "commodo", + "reprehenderit" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Delaney Knowles" }, + { "id": 1, "name": "Simone Nichols" }, + { "id": 2, "name": "Tate Brewer" }, + { "id": 3, "name": "Madeline Paul" }, + { "id": 4, "name": "Jeanette Roberson" }, + { "id": 5, "name": "Sallie Holden" }, + { "id": 6, "name": "Clements Hinton" }, + { "id": 7, "name": "Lourdes Tyler" }, + { "id": 8, "name": "Aline Davidson" }, + { "id": 9, "name": "Tia Collier" } + ], + "greeting": "Hello, Ford! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34d4c1ab9766cdd713", + "index": 14, + "guid": "0665f792-8282-4efd-b409-9c791ecb1091", + "isActive": true, + "balance": "$2,174.56", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "brown", + "name": { "first": "Grace", "last": "Fuentes" }, + "company": "ZINCA", + "email": "grace.fuentes@zinca.biz", + "phone": "+1 (802) 553-2237", + "address": "166 Sackman Street, Brownsville, Utah, 7296", + "about": "Lorem incididunt deserunt dolor nulla. Minim sit eu do commodo. Sint aliqua et exercitation duis Lorem laborum irure enim quis pariatur laboris incididunt veniam magna. Ea labore eiusmod incididunt fugiat. Sunt cillum nisi culpa Lorem aliqua nostrud quis dolore incididunt nostrud amet anim cupidatat. Ex pariatur enim esse sunt eiusmod. Aliquip consectetur reprehenderit nisi labore eu nostrud sint consectetur.", + "registered": "Friday, December 18, 2015 11:18 PM", + "latitude": "-66.13255", + "longitude": "179.72211", + "tags": [ + "ea", + "sunt", + "elit", + "Lorem", + "nisi", + "aute", + "do", + "fugiat", + "in", + "fugiat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Dixon Fletcher" }, + { "id": 1, "name": "Lambert Ingram" }, + { "id": 2, "name": "Mendez Pate" }, + { "id": 3, "name": "Ray Ward" }, + { "id": 4, "name": "Heidi Cardenas" }, + { "id": 5, "name": "Barton Meyer" }, + { "id": 6, "name": "Velma Park" }, + { "id": 7, "name": "Patricia Lynch" }, + { "id": 8, "name": "Eugenia Grant" }, + { "id": 9, "name": "York Sloan" } + ], + "greeting": "Hello, Grace! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa343b56f5acad827190", + "index": 15, + "guid": "4c8eb809-8024-490f-b95a-0cace6949320", + "isActive": true, + "balance": "$2,489.41", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { "first": "Laurel", "last": "Contreras" }, + "company": "DOGNOSIS", + "email": "laurel.contreras@dognosis.us", + "phone": "+1 (917) 546-3266", + "address": "147 Strong Place, Hayes, New Mexico, 2530", + "about": "Cupidatat nisi quis irure nostrud labore eu et voluptate. Nisi eiusmod enim dolor cillum. Ea dolor et ea adipisicing minim pariatur ea ad minim ad eu amet ea.", + "registered": "Saturday, December 24, 2016 9:20 AM", + "latitude": "-54.412123", + "longitude": "-169.324571", + "tags": [ + "reprehenderit", + "quis", + "irure", + "dolor", + "do", + "adipisicing", + "veniam", + "in", + "aliqua", + "ipsum" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Laurie Becker" }, + { "id": 1, "name": "Butler Coffey" }, + { "id": 2, "name": "Ruthie Benjamin" }, + { "id": 3, "name": "Jean Lee" }, + { "id": 4, "name": "Lowe Warren" }, + { "id": 5, "name": "Zelma Hudson" }, + { "id": 6, "name": "Wiggins Schwartz" }, + { "id": 7, "name": "Brewer Goodman" }, + { "id": 8, "name": "Melanie Haney" }, + { "id": 9, "name": "Alyson Brooks" } + ], + "greeting": "Hello, Laurel! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa3405bf5c4f96c29069", + "index": 16, + "guid": "e218adf6-22b7-4e1e-a6f4-31234460fd8e", + "isActive": true, + "balance": "$1,324.19", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "green", + "name": { "first": "Ginger", "last": "Pennington" }, + "company": "CYTREX", + "email": "ginger.pennington@cytrex.biz", + "phone": "+1 (827) 512-3179", + "address": "726 Lake Street, Shindler, Nevada, 4750", + "about": "Deserunt elit et labore minim officia cupidatat exercitation esse adipisicing enim amet culpa in adipisicing. Amet eiusmod velit amet laboris deserunt minim. Anim duis deserunt proident ex consequat incididunt commodo sint excepteur Lorem proident esse duis. Ad adipisicing veniam anim Lorem sit eu laboris ex nostrud qui nostrud ipsum. Labore exercitation excepteur voluptate aliqua labore anim id fugiat.", + "registered": "Saturday, December 9, 2017 10:11 AM", + "latitude": "14.567831", + "longitude": "66.731219", + "tags": [ + "incididunt", + "dolor", + "commodo", + "eiusmod", + "est", + "est", + "sint", + "ad", + "ut", + "minim" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Iva Guerrero" }, + { "id": 1, "name": "Cathleen Young" }, + { "id": 2, "name": "Welch Pierce" }, + { "id": 3, "name": "Tyson Raymond" }, + { "id": 4, "name": "Josefa Crawford" }, + { "id": 5, "name": "Cross Burks" }, + { "id": 6, "name": "Crosby Brady" }, + { "id": 7, "name": "Barry Guthrie" }, + { "id": 8, "name": "Margret Duran" }, + { "id": 9, "name": "Reilly Patton" } + ], + "greeting": "Hello, Ginger! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa343537eccc1ace3207", + "index": 17, + "guid": "7e65b665-28a9-4499-81c0-c1d9042bebdf", + "isActive": false, + "balance": "$3,776.91", + "picture": "http://placehold.it/32x32", + "age": 36, + "eyeColor": "green", + "name": { "first": "Mckenzie", "last": "Chan" }, + "company": "ENDIPIN", + "email": "mckenzie.chan@endipin.com", + "phone": "+1 (824) 566-2134", + "address": "448 Terrace Place, Cetronia, Puerto Rico, 9914", + "about": "Deserunt elit nostrud cupidatat labore deserunt cupidatat ea cupidatat consectetur. Labore est velit duis voluptate occaecat quis veniam nostrud incididunt proident minim elit. Nulla velit elit tempor occaecat cillum adipisicing exercitation exercitation id incididunt officia ipsum fugiat sunt. Aliqua pariatur reprehenderit in aliqua esse do quis aliquip. Proident exercitation ullamco nisi id minim id cillum eiusmod mollit ea Lorem. Laborum sit exercitation exercitation Lorem eiusmod ad laborum nisi ex id non.", + "registered": "Friday, June 23, 2017 11:32 AM", + "latitude": "-13.394667", + "longitude": "-158.627154", + "tags": [ + "ut", + "quis", + "laboris", + "ea", + "esse", + "non", + "do", + "irure", + "ea", + "excepteur" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Woodward Little" }, + { "id": 1, "name": "Patty Gamble" }, + { "id": 2, "name": "Erickson Macias" }, + { "id": 3, "name": "Tanya Pace" }, + { "id": 4, "name": "Hunt Tate" }, + { "id": 5, "name": "Maricela Crane" }, + { "id": 6, "name": "Hanson Rodriguez" }, + { "id": 7, "name": "Goodman Austin" }, + { "id": 8, "name": "Short Donovan" }, + { "id": 9, "name": "Blanche England" } + ], + "greeting": "Hello, Mckenzie! You have 8 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa34290ac8fa63a12eac", + "index": 18, + "guid": "547f7c12-6dc2-46bd-ba15-29730366275d", + "isActive": true, + "balance": "$2,585.89", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "green", + "name": { "first": "Frazier", "last": "Pickett" }, + "company": "GRUPOLI", + "email": "frazier.pickett@grupoli.co.uk", + "phone": "+1 (897) 581-2849", + "address": "678 Newton Street, Chelsea, Ohio, 490", + "about": "Ex non cupidatat non cupidatat enim sint occaecat ut incididunt irure nulla. Ex id culpa voluptate id do id exercitation sit mollit esse id excepteur eu duis. Minim est veniam laboris irure ut minim consectetur fugiat enim ullamco minim. Sint mollit ullamco dolore consequat ipsum eu cillum. Et consectetur elit est sit aliquip et non occaecat.", + "registered": "Wednesday, March 29, 2017 7:15 PM", + "latitude": "1.80887", + "longitude": "28.819849", + "tags": [ + "tempor", + "veniam", + "elit", + "mollit", + "aliquip", + "magna", + "laboris", + "labore", + "anim", + "proident" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Mcconnell Mccall" }, + { "id": 1, "name": "Harper Fields" }, + { "id": 2, "name": "Kathryn Schultz" }, + { "id": 3, "name": "Campos Hensley" }, + { "id": 4, "name": "Landry Owen" }, + { "id": 5, "name": "Perez Greer" }, + { "id": 6, "name": "Maldonado Bartlett" }, + { "id": 7, "name": "Hendrix Stein" }, + { "id": 8, "name": "Delgado Wade" }, + { "id": 9, "name": "Rene Wallace" } + ], + "greeting": "Hello, Frazier! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34e17d55284d96d1f5", + "index": 19, + "guid": "c7255282-e5a6-4b8b-af24-3b637fd9b044", + "isActive": false, + "balance": "$1,869.10", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "blue", + "name": { "first": "Ochoa", "last": "Madden" }, + "company": "INSURITY", + "email": "ochoa.madden@insurity.ca", + "phone": "+1 (934) 422-2951", + "address": "422 Emerald Street, Sugartown, North Carolina, 2526", + "about": "Dolor est aliquip pariatur sunt irure deserunt pariatur excepteur do do. Nisi nostrud esse ullamco duis fugiat aliquip cillum. Sint pariatur occaecat ex id aliqua.", + "registered": "Friday, February 2, 2018 8:53 PM", + "latitude": "-67.260494", + "longitude": "76.369882", + "tags": [ + "aute", + "minim", + "commodo", + "non", + "ex", + "qui", + "ut", + "veniam", + "commodo", + "aliquip" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Lilia Schroeder" }, + { "id": 1, "name": "Amber Meyers" }, + { "id": 2, "name": "Janette Richards" }, + { "id": 3, "name": "Lucinda Key" }, + { "id": 4, "name": "Kristine Freeman" }, + { "id": 5, "name": "Tillman Horne" }, + { "id": 6, "name": "Cervantes Rosario" }, + { "id": 7, "name": "Kerr Mcdonald" }, + { "id": 8, "name": "Dionne Hancock" }, + { "id": 9, "name": "Huber Hester" } + ], + "greeting": "Hello, Ochoa! You have 6 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa3473ba36f5b47cb4fe", + "index": 20, + "guid": "9019a995-b226-4d0e-8dbc-c6dc102d3bcc", + "isActive": true, + "balance": "$1,109.74", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "green", + "name": { "first": "Janie", "last": "Hendricks" }, + "company": "TELEQUIET", + "email": "janie.hendricks@telequiet.info", + "phone": "+1 (830) 552-3242", + "address": "302 Dunham Place, Cataract, South Dakota, 2071", + "about": "Ea et eiusmod adipisicing labore minim. Veniam nostrud non esse non adipisicing aliquip exercitation incididunt laboris velit occaecat Lorem nisi. Veniam adipisicing veniam magna nulla qui in irure culpa. Sint est aute anim sit magna velit nulla labore eu. Mollit duis amet ea culpa amet exercitation officia. Exercitation pariatur deserunt consequat magna enim occaecat mollit sunt incididunt. Fugiat id non veniam elit in ipsum duis exercitation Lorem non culpa in occaecat.", + "registered": "Monday, February 29, 2016 4:08 PM", + "latitude": "52.718238", + "longitude": "-107.958872", + "tags": [ + "nulla", + "aliquip", + "aliquip", + "reprehenderit", + "laboris", + "non", + "exercitation", + "anim", + "nisi", + "eiusmod" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Diann Robertson" }, + { "id": 1, "name": "Forbes Molina" }, + { "id": 2, "name": "Phelps Medina" }, + { "id": 3, "name": "Billie James" }, + { "id": 4, "name": "Addie Roach" }, + { "id": 5, "name": "Vickie Petersen" }, + { "id": 6, "name": "Navarro Sanford" }, + { "id": 7, "name": "Mclean Sampson" }, + { "id": 8, "name": "Barlow Bolton" }, + { "id": 9, "name": "Nicholson Zamora" } + ], + "greeting": "Hello, Janie! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa3485ccf4bd0ca5238a", + "index": 21, + "guid": "ca0b5dc7-21a3-4edb-849e-1d6d81c57f8a", + "isActive": false, + "balance": "$3,102.46", + "picture": "http://placehold.it/32x32", + "age": 28, + "eyeColor": "blue", + "name": { "first": "Good", "last": "Hays" }, + "company": "GYNKO", + "email": "good.hays@gynko.me", + "phone": "+1 (936) 448-2745", + "address": "538 Lott Place, Rivera, Pennsylvania, 7526", + "about": "Aliqua veniam aliqua adipisicing aliquip sit aute commodo. Fugiat ut esse laboris duis nisi ipsum ea dolor labore sit pariatur laborum officia. Ipsum ad do tempor nostrud in irure enim ad amet ex id. Nostrud dolore voluptate nulla cupidatat laboris minim.", + "registered": "Friday, December 9, 2016 10:14 AM", + "latitude": "-26.185693", + "longitude": "68.079701", + "tags": [ + "laborum", + "dolor", + "cillum", + "dolor", + "duis", + "in", + "veniam", + "enim", + "aliquip", + "incididunt" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Erika Dalton" }, + { "id": 1, "name": "Josie Cole" }, + { "id": 2, "name": "Katelyn Dominguez" }, + { "id": 3, "name": "Jasmine Mathis" }, + { "id": 4, "name": "Phoebe Reynolds" }, + { "id": 5, "name": "Bishop Barr" }, + { "id": 6, "name": "Morton Flynn" }, + { "id": 7, "name": "Brock Berger" }, + { "id": 8, "name": "Dominique Obrien" }, + { "id": 9, "name": "Ayers Garrison" } + ], + "greeting": "Hello, Good! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa348b68911a5e827ca8", + "index": 22, + "guid": "e0df62b2-c28f-40bb-a00e-f95a667b3fa0", + "isActive": true, + "balance": "$3,544.61", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "brown", + "name": { "first": "Golden", "last": "Reid" }, + "company": "KIDGREASE", + "email": "golden.reid@kidgrease.org", + "phone": "+1 (882) 440-2209", + "address": "952 Holly Street, Monument, Minnesota, 7297", + "about": "Exercitation esse ullamco do ullamco aliquip eiusmod adipisicing proident. Labore do cupidatat in irure proident. Mollit velit fugiat voluptate aliqua qui voluptate laboris aliqua minim laborum sunt amet. Consequat magna duis commodo ea cupidatat ea culpa eiusmod ut cillum ut eu velit aute. Laboris amet ea irure fugiat nisi amet commodo labore officia excepteur dolor tempor mollit magna. Non consequat dolor reprehenderit ullamco dolor tempor quis voluptate magna ad reprehenderit adipisicing incididunt. Velit laboris elit esse nulla quis.", + "registered": "Monday, February 24, 2014 11:59 AM", + "latitude": "30.725621", + "longitude": "-158.551407", + "tags": [ + "sit", + "pariatur", + "nulla", + "quis", + "nisi", + "ea", + "qui", + "deserunt", + "officia", + "aliquip" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Bradshaw Gilmore" }, + { "id": 1, "name": "Pugh Munoz" }, + { "id": 2, "name": "Nunez Hawkins" }, + { "id": 3, "name": "Julia Washington" }, + { "id": 4, "name": "Rivers Webb" }, + { "id": 5, "name": "Tara Summers" }, + { "id": 6, "name": "Cheryl Odonnell" }, + { "id": 7, "name": "Theresa Williamson" }, + { "id": 8, "name": "Lesley Duke" }, + { "id": 9, "name": "Snyder Bush" } + ], + "greeting": "Hello, Golden! You have 6 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34fc10000370445e6f", + "index": 23, + "guid": "22bcb41a-1eb7-458b-80e7-7428f316d8f9", + "isActive": false, + "balance": "$1,233.98", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "green", + "name": { "first": "Green", "last": "Mcknight" }, + "company": "BESTO", + "email": "green.mcknight@besto.tv", + "phone": "+1 (817) 590-3548", + "address": "672 Montauk Court, Grahamtown, Florida, 6020", + "about": "Non commodo non nisi cillum fugiat. Quis ad fugiat eu ad consequat veniam adipisicing dolor. Non aliqua nulla Lorem id culpa anim veniam. Aliqua ea et eiusmod minim ut. Id ullamco qui sit aute reprehenderit nulla fugiat velit magna nisi eiusmod sit minim.", + "registered": "Saturday, February 10, 2018 8:53 AM", + "latitude": "52.299418", + "longitude": "21.885332", + "tags": [ + "incididunt", + "quis", + "ea", + "cupidatat", + "quis", + "irure", + "qui", + "tempor", + "voluptate", + "et" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Mercedes Lowe" }, + { "id": 1, "name": "Chen Perry" }, + { "id": 2, "name": "Maxine Price" }, + { "id": 3, "name": "Bryant Koch" }, + { "id": 4, "name": "Benita Adams" }, + { "id": 5, "name": "Clara Winters" }, + { "id": 6, "name": "Alta Cantu" }, + { "id": 7, "name": "Freida Petty" }, + { "id": 8, "name": "Kimberly Bender" }, + { "id": 9, "name": "Mccormick Roberts" } + ], + "greeting": "Hello, Green! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa3489c9bb951ae47da8", + "index": 24, + "guid": "22a0295f-7b80-4f06-9fc3-be1cdc79bdfb", + "isActive": false, + "balance": "$2,006.10", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "brown", + "name": { "first": "Hilda", "last": "Finch" }, + "company": "CODAX", + "email": "hilda.finch@codax.io", + "phone": "+1 (827) 575-2563", + "address": "395 Seaview Avenue, Hemlock, Connecticut, 5299", + "about": "Quis ex cillum ipsum id. Lorem ea velit minim ipsum ipsum irure excepteur nisi culpa officia dolore aliqua dolor deserunt. Et esse aliquip ex enim nisi excepteur mollit tempor non tempor in eu.", + "registered": "Tuesday, October 24, 2017 6:47 PM", + "latitude": "-50.758977", + "longitude": "-133.236945", + "tags": [ + "et", + "cillum", + "elit", + "aliquip", + "amet", + "quis", + "enim", + "dolor", + "eiusmod", + "adipisicing" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Erma Robbins" }, + { "id": 1, "name": "Gwen Evans" }, + { "id": 2, "name": "Connie Cummings" }, + { "id": 3, "name": "Bonnie Valenzuela" }, + { "id": 4, "name": "Martin Bradford" }, + { "id": 5, "name": "Mcmahon Long" }, + { "id": 6, "name": "Trisha Vaughan" }, + { "id": 7, "name": "Allison West" }, + { "id": 8, "name": "Chapman Olsen" }, + { "id": 9, "name": "Minerva Reeves" } + ], + "greeting": "Hello, Hilda! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa340fc9dc39242531ff", + "index": 25, + "guid": "3d78eba2-0b29-46e1-8119-b2b170f4be97", + "isActive": true, + "balance": "$2,534.73", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "blue", + "name": { "first": "Cora", "last": "Franco" }, + "company": "ENTHAZE", + "email": "cora.franco@enthaze.name", + "phone": "+1 (916) 530-2675", + "address": "217 Beaver Street, Bergoo, Montana, 7013", + "about": "Amet anim ipsum velit anim magna incididunt proident excepteur laborum ut voluptate voluptate ex cillum. Labore ea amet eu exercitation excepteur magna ex cupidatat laborum. Nisi ipsum id ex reprehenderit eu enim reprehenderit adipisicing. Ullamco eu sint anim et aute. Laborum sit duis quis sit non duis. Enim minim irure laboris veniam incididunt sint cupidatat.", + "registered": "Thursday, July 16, 2015 4:42 PM", + "latitude": "-26.445079", + "longitude": "77.502053", + "tags": [ + "id", + "culpa", + "consequat", + "deserunt", + "velit", + "sint", + "dolor", + "ad", + "nulla", + "do" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Barnett Jacobson" }, + { "id": 1, "name": "Lynn Mcpherson" }, + { "id": 2, "name": "Beverley Phelps" }, + { "id": 3, "name": "Aguilar Valdez" }, + { "id": 4, "name": "Sweeney Sandoval" }, + { "id": 5, "name": "Potts Allison" }, + { "id": 6, "name": "Chavez Norman" }, + { "id": 7, "name": "Katherine Torres" }, + { "id": 8, "name": "Kelli Russo" }, + { "id": 9, "name": "Joni Rojas" } + ], + "greeting": "Hello, Cora! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa34a34dd832ac2eda38", + "index": 26, + "guid": "3ac7f2d1-cbc7-404b-915b-9984bc0947bb", + "isActive": true, + "balance": "$3,667.55", + "picture": "http://placehold.it/32x32", + "age": 29, + "eyeColor": "green", + "name": { "first": "Faye", "last": "Guzman" }, + "company": "CIPROMOX", + "email": "faye.guzman@cipromox.biz", + "phone": "+1 (912) 528-3635", + "address": "633 Livonia Avenue, Gracey, Mississippi, 9805", + "about": "Id ea duis velit enim qui esse non sunt. Est ad laboris proident et consequat exercitation. Aliquip do exercitation ea officia mollit dolore. Sit ullamco anim anim minim cillum pariatur officia. Exercitation velit ullamco ullamco sint amet voluptate commodo nulla ipsum qui. Elit cillum mollit ut nulla aute aliquip anim consequat ipsum Lorem sunt nisi nisi est.", + "registered": "Thursday, February 4, 2016 12:04 AM", + "latitude": "-23.278189", + "longitude": "-136.239491", + "tags": [ + "culpa", + "consequat", + "Lorem", + "eiusmod", + "deserunt", + "officia", + "elit", + "cillum", + "aliquip", + "ex" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Cassandra Forbes" }, + { "id": 1, "name": "Poole Mueller" }, + { "id": 2, "name": "Danielle Espinoza" }, + { "id": 3, "name": "Gentry Leach" }, + { "id": 4, "name": "Allen Berg" }, + { "id": 5, "name": "Rhea Fitzgerald" }, + { "id": 6, "name": "Blair Arnold" }, + { "id": 7, "name": "Felicia Fulton" }, + { "id": 8, "name": "Karla Rodgers" }, + { "id": 9, "name": "Alyssa Mcfadden" } + ], + "greeting": "Hello, Faye! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34e0f6838816113db8", + "index": 27, + "guid": "ca5a4646-8edc-4443-91cf-c5dc73927e7a", + "isActive": false, + "balance": "$3,344.58", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "brown", + "name": { "first": "Ryan", "last": "Mcintyre" }, + "company": "STOCKPOST", + "email": "ryan.mcintyre@stockpost.us", + "phone": "+1 (872) 474-3518", + "address": "272 Barwell Terrace, Tedrow, Hawaii, 5053", + "about": "Incididunt incididunt commodo nulla eiusmod ullamco velit ipsum ad minim non magna culpa laborum. Exercitation ipsum culpa sint in ipsum qui exercitation eiusmod nulla ex. Magna ex eu officia magna esse. Irure dolore anim aute anim tempor nulla adipisicing culpa culpa voluptate ullamco commodo. Adipisicing pariatur excepteur ad reprehenderit reprehenderit dolor magna velit est. Fugiat laboris laborum in et consectetur laborum elit adipisicing.", + "registered": "Saturday, April 11, 2015 11:23 PM", + "latitude": "76.874677", + "longitude": "94.777546", + "tags": [ + "id", + "veniam", + "ad", + "do", + "commodo", + "amet", + "tempor", + "sunt", + "ullamco", + "laborum" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Vera Olson" }, + { "id": 1, "name": "West Daniel" }, + { "id": 2, "name": "Socorro Manning" }, + { "id": 3, "name": "Louise Haynes" }, + { "id": 4, "name": "Lela Mann" }, + { "id": 5, "name": "Spence Lyons" }, + { "id": 6, "name": "Wynn Gillespie" }, + { "id": 7, "name": "Lynch Jones" }, + { "id": 8, "name": "Patrica Carlson" }, + { "id": 9, "name": "Marietta Hickman" } + ], + "greeting": "Hello, Ryan! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa344299323300eee507", + "index": 28, + "guid": "58a7ace0-c6be-4581-bee8-74a5d60398f7", + "isActive": false, + "balance": "$3,743.38", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "blue", + "name": { "first": "Mcgowan", "last": "Mcgowan" }, + "company": "QUINTITY", + "email": "mcgowan.mcgowan@quintity.biz", + "phone": "+1 (881) 485-2266", + "address": "822 Ridge Court, Somerset, Rhode Island, 458", + "about": "Laboris in velit voluptate amet cupidatat sit. Ea culpa cupidatat in dolor aute ex dolor ut dolore aliqua aliquip cillum. Ipsum laboris sint dolor esse deserunt amet exercitation sunt mollit.", + "registered": "Tuesday, June 28, 2016 6:36 AM", + "latitude": "-25.599677", + "longitude": "84.225442", + "tags": [ + "nostrud", + "consectetur", + "labore", + "ex", + "anim", + "fugiat", + "nostrud", + "sunt", + "deserunt", + "in" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Steele Riggs" }, + { "id": 1, "name": "Carmella Moran" }, + { "id": 2, "name": "Allyson Blake" }, + { "id": 3, "name": "Carol Cooke" }, + { "id": 4, "name": "Heath Knight" }, + { "id": 5, "name": "Ware Oconnor" }, + { "id": 6, "name": "Osborne Jackson" }, + { "id": 7, "name": "Lilian Burns" }, + { "id": 8, "name": "Mallory Chen" }, + { "id": 9, "name": "Liza Nunez" } + ], + "greeting": "Hello, Mcgowan! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34ad8457b4672e26a6", + "index": 29, + "guid": "af06ab7e-2514-4610-805b-9ef1ab10d1b6", + "isActive": false, + "balance": "$2,641.66", + "picture": "http://placehold.it/32x32", + "age": 40, + "eyeColor": "green", + "name": { "first": "Cathryn", "last": "Norris" }, + "company": "CUIZINE", + "email": "cathryn.norris@cuizine.com", + "phone": "+1 (886) 433-3723", + "address": "631 Hinsdale Street, Edmund, Texas, 818", + "about": "Enim consectetur eu nulla aliqua enim deserunt veniam deserunt. Commodo dolor anim aliqua anim cupidatat incididunt ex. Consequat qui ex dolor do do ullamco officia laboris ipsum. Sit sunt officia dolore ut dolore veniam dolor Lorem dolor do et qui velit pariatur. Nisi eiusmod ut do duis Lorem cillum do cillum amet dolore. Qui esse officia veniam incididunt consectetur id nostrud deserunt dolor adipisicing ipsum aliquip occaecat. Cillum aliquip sint eu minim aliquip nostrud eiusmod ullamco esse mollit sit amet amet ipsum.", + "registered": "Wednesday, July 5, 2017 9:58 PM", + "latitude": "-54.903831", + "longitude": "-75.383676", + "tags": [ + "non", + "minim", + "fugiat", + "sint", + "deserunt", + "quis", + "fugiat", + "do", + "deserunt", + "occaecat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Hale Wiley" }, + { "id": 1, "name": "Clarice Holcomb" }, + { "id": 2, "name": "Arlene Rowland" }, + { "id": 3, "name": "Mckee Craig" }, + { "id": 4, "name": "Leann Mullins" }, + { "id": 5, "name": "Lydia Carpenter" }, + { "id": 6, "name": "Franklin Bishop" }, + { "id": 7, "name": "Meadows Rice" }, + { "id": 8, "name": "Lee Bullock" }, + { "id": 9, "name": "Moon Vance" } + ], + "greeting": "Hello, Cathryn! You have 8 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa3438902775803a72d7", + "index": 30, + "guid": "0433ad5c-c75b-4e57-b81b-d6f7b4c6ce23", + "isActive": true, + "balance": "$1,413.96", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "green", + "name": { "first": "Gladys", "last": "Luna" }, + "company": "VORTEXACO", + "email": "gladys.luna@vortexaco.co.uk", + "phone": "+1 (841) 419-2692", + "address": "710 Grove Place, Gouglersville, North Dakota, 7911", + "about": "Adipisicing excepteur incididunt eu ullamco in tempor. Fugiat aute ex veniam culpa labore quis anim magna. Aliqua exercitation culpa cupidatat do ullamco nostrud id. Dolore nisi laborum ullamco fugiat eiusmod laboris exercitation dolore magna id ipsum. Non velit commodo amet fugiat esse cillum tempor ex esse et aliquip ipsum nostrud. Consectetur adipisicing nisi voluptate exercitation amet. Incididunt fugiat dolore elit consequat laboris sunt culpa quis ullamco occaecat consequat enim.", + "registered": "Thursday, February 25, 2016 1:35 AM", + "latitude": "-17.405117", + "longitude": "-94.797563", + "tags": [ + "ullamco", + "cupidatat", + "consectetur", + "sit", + "sit", + "incididunt", + "voluptate", + "eu", + "occaecat", + "commodo" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Jill Black" }, + { "id": 1, "name": "Myra Wilcox" }, + { "id": 2, "name": "Rojas Mcintosh" }, + { "id": 3, "name": "Duffy Tyson" }, + { "id": 4, "name": "Nettie Payne" }, + { "id": 5, "name": "Pam Avery" }, + { "id": 6, "name": "Guerrero Drake" }, + { "id": 7, "name": "Dunlap Fuller" }, + { "id": 8, "name": "Mercer Hopper" }, + { "id": 9, "name": "Mayra Ramos" } + ], + "greeting": "Hello, Gladys! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34fab19bc37260045d", + "index": 31, + "guid": "fbd1f589-514f-4124-a008-6fafdfceebca", + "isActive": false, + "balance": "$2,778.78", + "picture": "http://placehold.it/32x32", + "age": 29, + "eyeColor": "blue", + "name": { "first": "Mildred", "last": "Farrell" }, + "company": "GLEAMINK", + "email": "mildred.farrell@gleamink.ca", + "phone": "+1 (979) 492-2298", + "address": "285 Lewis Avenue, Toftrees, West Virginia, 2663", + "about": "Lorem ut incididunt Lorem commodo ipsum nisi sunt consequat officia sit nulla labore nostrud labore. Culpa cupidatat id proident nostrud dolor officia ullamco non veniam. Laborum exercitation amet amet sint. Excepteur excepteur dolor irure laborum. Commodo ut minim incididunt tempor officia consequat occaecat.", + "registered": "Monday, July 11, 2016 4:58 PM", + "latitude": "-22.275242", + "longitude": "138.432225", + "tags": [ + "dolor", + "officia", + "dolor", + "sit", + "est", + "ea", + "enim", + "eiusmod", + "magna", + "incididunt" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Rodgers Thornton" }, + { "id": 1, "name": "Samantha Stanley" }, + { "id": 2, "name": "Lelia Bowen" }, + { "id": 3, "name": "Herminia Hutchinson" }, + { "id": 4, "name": "Wright Holloway" }, + { "id": 5, "name": "Ava Vinson" }, + { "id": 6, "name": "Francine Schmidt" }, + { "id": 7, "name": "Frederick Bowman" }, + { "id": 8, "name": "Daniel Brown" }, + { "id": 9, "name": "Renee Gill" } + ], + "greeting": "Hello, Mildred! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34a398b521eb072327", + "index": 32, + "guid": "045c43e8-f6f2-4490-8d26-3fb124098c34", + "isActive": false, + "balance": "$3,371.61", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "blue", + "name": { "first": "Angelina", "last": "Hahn" }, + "company": "QUANTALIA", + "email": "angelina.hahn@quantalia.info", + "phone": "+1 (813) 431-3542", + "address": "894 Louisa Street, Cochranville, Maine, 2019", + "about": "Tempor Lorem labore et officia id. Laboris aliqua Lorem do aliquip dolore officia quis Lorem quis et qui voluptate sunt. Id Lorem voluptate elit ea dolor occaecat magna occaecat et ad sint. Cillum mollit incididunt nisi reprehenderit Lorem duis reprehenderit minim voluptate exercitation incididunt est nisi esse.", + "registered": "Monday, December 12, 2016 7:40 AM", + "latitude": "28.524161", + "longitude": "97.447644", + "tags": [ + "pariatur", + "incididunt", + "est", + "ut", + "pariatur", + "laboris", + "duis", + "nulla", + "eu", + "fugiat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Sylvia Bradley" }, + { "id": 1, "name": "Jamie Wells" }, + { "id": 2, "name": "Jodie Mccormick" }, + { "id": 3, "name": "Calderon Hansen" }, + { "id": 4, "name": "Fuentes Walton" }, + { "id": 5, "name": "Lacy Goff" }, + { "id": 6, "name": "Marguerite Cantrell" }, + { "id": 7, "name": "Goldie Best" }, + { "id": 8, "name": "Melva Ware" }, + { "id": 9, "name": "Lina Stuart" } + ], + "greeting": "Hello, Angelina! You have 6 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa3415690121e1d31dc8", + "index": 33, + "guid": "1c4d9d82-a2ed-4137-bbb2-1e31c25c3845", + "isActive": true, + "balance": "$1,955.48", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "green", + "name": { "first": "Rosanna", "last": "Morgan" }, + "company": "AQUOAVO", + "email": "rosanna.morgan@aquoavo.me", + "phone": "+1 (972) 555-2633", + "address": "125 Downing Street, Lutsen, Missouri, 7484", + "about": "Officia officia magna exercitation do culpa nostrud anim minim reprehenderit velit exercitation exercitation excepteur. Cillum est occaecat id nisi. Ipsum dolor quis incididunt non anim. Officia in esse nulla do commodo eu non commodo consequat. Et proident et id officia fugiat consectetur do non. Est ea eu velit fugiat ea nostrud id consequat cillum sit consectetur. Proident ut Lorem incididunt Lorem aliqua mollit Lorem dolore esse mollit elit eu.", + "registered": "Saturday, November 11, 2017 6:19 AM", + "latitude": "-26.09161", + "longitude": "-142.715019", + "tags": [ + "veniam", + "exercitation", + "proident", + "minim", + "aliquip", + "labore", + "sint", + "quis", + "laboris", + "ut" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Durham Mayo" }, + { "id": 1, "name": "Puckett Clayton" }, + { "id": 2, "name": "Guzman Franks" }, + { "id": 3, "name": "Marion Riddle" }, + { "id": 4, "name": "Bowman Clemons" }, + { "id": 5, "name": "Church Dudley" }, + { "id": 6, "name": "Adeline Gross" }, + { "id": 7, "name": "Wolf Boyle" }, + { "id": 8, "name": "Maggie Fry" }, + { "id": 9, "name": "Molly Willis" } + ], + "greeting": "Hello, Rosanna! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa3473b934c37662ee87", + "index": 34, + "guid": "9e975a37-6c04-4476-8af8-a8da71f95bce", + "isActive": false, + "balance": "$2,374.83", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { "first": "Alexis", "last": "Stephens" }, + "company": "VIDTO", + "email": "alexis.stephens@vidto.org", + "phone": "+1 (823) 415-2326", + "address": "129 Cove Lane, Loretto, Federated States Of Micronesia, 4132", + "about": "Ipsum laboris elit irure sunt velit minim et aliquip qui labore. Cupidatat pariatur cupidatat labore dolore ullamco nisi ipsum aute. Aute fugiat pariatur cupidatat fugiat irure do proident voluptate pariatur duis quis sit est. Ex ipsum ea ipsum nulla nostrud ad veniam sunt cupidatat aliquip occaecat elit est voluptate. Nostrud non enim quis consequat cupidatat voluptate occaecat veniam ad sunt sint Lorem tempor minim.", + "registered": "Tuesday, February 9, 2016 6:58 AM", + "latitude": "30.265793", + "longitude": "133.438276", + "tags": [ + "veniam", + "eiusmod", + "Lorem", + "officia", + "consequat", + "dolor", + "tempor", + "sunt", + "ex", + "sit" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Fanny Atkinson" }, + { "id": 1, "name": "Maryanne Conrad" }, + { "id": 2, "name": "Catalina Harmon" }, + { "id": 3, "name": "Cooke Rowe" }, + { "id": 4, "name": "Angie Mcgee" }, + { "id": 5, "name": "Stokes Gibson" }, + { "id": 6, "name": "Jones Vega" }, + { "id": 7, "name": "Leah Butler" }, + { "id": 8, "name": "Taylor Peters" }, + { "id": 9, "name": "Cochran Neal" } + ], + "greeting": "Hello, Alexis! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa34629b7e6a2d9be431", + "index": 35, + "guid": "3c9958e7-c013-4af9-8fcd-b6956105558b", + "isActive": false, + "balance": "$3,908.65", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "green", + "name": { "first": "Aguirre", "last": "Mckinney" }, + "company": "NETPLODE", + "email": "aguirre.mckinney@netplode.tv", + "phone": "+1 (894) 423-3860", + "address": "403 Glendale Court, Wildwood, Massachusetts, 8080", + "about": "Aliqua elit sunt anim magna aliquip ullamco non incididunt. Proident irure Lorem excepteur aliqua deserunt nisi in ea reprehenderit. Ad laboris aute cillum ut exercitation culpa dolor.", + "registered": "Wednesday, May 7, 2014 2:56 PM", + "latitude": "-76.365309", + "longitude": "-157.854137", + "tags": [ + "proident", + "deserunt", + "est", + "sint", + "sint", + "magna", + "aliquip", + "in", + "commodo", + "velit" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Dorsey Cote" }, + { "id": 1, "name": "Levy Castro" }, + { "id": 2, "name": "Anne Love" }, + { "id": 3, "name": "Neva Suarez" }, + { "id": 4, "name": "Tammie Gallagher" }, + { "id": 5, "name": "Kristi Parker" }, + { "id": 6, "name": "Waller Miller" }, + { "id": 7, "name": "Nadia Wood" }, + { "id": 8, "name": "Powell Lott" }, + { "id": 9, "name": "Chris Hoffman" } + ], + "greeting": "Hello, Aguirre! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa3426ab5d444b6a10f9", + "index": 36, + "guid": "8b4fdf0f-9db7-41d4-b39d-139cd785d7b5", + "isActive": true, + "balance": "$2,280.91", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "green", + "name": { "first": "Richards", "last": "Snow" }, + "company": "BLURRYBUS", + "email": "richards.snow@blurrybus.io", + "phone": "+1 (905) 463-2264", + "address": "494 Brightwater Court, Marenisco, Colorado, 1830", + "about": "Mollit duis nisi eu aliquip tempor irure laborum ad minim aliqua. Ullamco voluptate enim adipisicing consectetur adipisicing occaecat tempor voluptate dolor incididunt tempor fugiat. Adipisicing cupidatat esse ex commodo nostrud officia cupidatat ullamco magna proident incididunt. Adipisicing sint Lorem qui duis laborum non consequat minim incididunt sint quis in voluptate. Minim ea ex ex cupidatat consectetur aliqua proident exercitation cupidatat duis sint ut. Magna enim eu aute aliquip est minim nulla mollit. Occaecat magna ad nisi eiusmod aliqua deserunt consectetur exercitation adipisicing commodo voluptate.", + "registered": "Thursday, October 13, 2016 7:34 PM", + "latitude": "-84.839295", + "longitude": "-173.645597", + "tags": [ + "ut", + "veniam", + "ullamco", + "culpa", + "exercitation", + "fugiat", + "quis", + "consequat", + "amet", + "nostrud" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Lakeisha Banks" }, + { "id": 1, "name": "Anderson Wooten" }, + { "id": 2, "name": "Marie Hopkins" }, + { "id": 3, "name": "Parks Jensen" }, + { "id": 4, "name": "Wendi Page" }, + { "id": 5, "name": "Hart Andrews" }, + { "id": 6, "name": "Margery Irwin" }, + { "id": 7, "name": "Harrison Kirby" }, + { "id": 8, "name": "Ivy Santiago" }, + { "id": 9, "name": "Tamra Witt" } + ], + "greeting": "Hello, Richards! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa345399675c8e97e073", + "index": 37, + "guid": "8c6ce068-927a-4c5a-ba09-bc264d9fd709", + "isActive": true, + "balance": "$2,124.25", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "brown", + "name": { "first": "Penny", "last": "Swanson" }, + "company": "PLAYCE", + "email": "penny.swanson@playce.name", + "phone": "+1 (874) 539-3904", + "address": "797 Pershing Loop, Gorst, New York, 2236", + "about": "Cillum ad irure consequat do cillum culpa aliquip exercitation est cupidatat ex do consectetur aute. Enim proident ea velit dolore ex ea tempor elit consequat laboris. Laborum velit eu minim irure nostrud cupidatat mollit minim nostrud. Tempor ea laboris nostrud tempor veniam. Cillum ex in cupidatat ut laboris. Fugiat nisi in quis velit eu fugiat veniam aliquip aliqua anim est.", + "registered": "Tuesday, September 13, 2016 10:26 AM", + "latitude": "46.06826", + "longitude": "-179.707892", + "tags": [ + "ea", + "proident", + "ea", + "culpa", + "consequat", + "incididunt", + "incididunt", + "non", + "ea", + "duis" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Webster Alford" }, + { "id": 1, "name": "Stacey Boyd" }, + { "id": 2, "name": "Nellie Delgado" }, + { "id": 3, "name": "Baker Slater" }, + { "id": 4, "name": "Moody Underwood" }, + { "id": 5, "name": "Rosales Buck" }, + { "id": 6, "name": "Hess Todd" }, + { "id": 7, "name": "Lane Farley" }, + { "id": 8, "name": "Smith Sears" }, + { "id": 9, "name": "Newman Caldwell" } + ], + "greeting": "Hello, Penny! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa344f3de72033606554", + "index": 38, + "guid": "78c70b05-ba42-4c24-a841-3cb06a29112c", + "isActive": false, + "balance": "$2,845.79", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { "first": "Christi", "last": "French" }, + "company": "SKYPLEX", + "email": "christi.french@skyplex.biz", + "phone": "+1 (831) 500-2423", + "address": "381 Colby Court, Haena, Marshall Islands, 839", + "about": "Consectetur magna in fugiat quis aute anim elit officia ex sint exercitation. Sunt exercitation pariatur enim laborum mollit labore. Minim enim pariatur enim ex ipsum eiusmod est quis irure.", + "registered": "Wednesday, August 17, 2016 9:32 PM", + "latitude": "-70.652626", + "longitude": "-160.945222", + "tags": [ + "dolor", + "reprehenderit", + "nulla", + "laborum", + "esse", + "est", + "nostrud", + "velit", + "cupidatat", + "id" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Haley Mcneil" }, + { "id": 1, "name": "Bernadine Bean" }, + { "id": 2, "name": "Agnes Kirk" }, + { "id": 3, "name": "Margie Aguirre" }, + { "id": 4, "name": "Mitzi Harper" }, + { "id": 5, "name": "Hatfield Marks" }, + { "id": 6, "name": "Rachael Harris" }, + { "id": 7, "name": "Serena Sykes" }, + { "id": 8, "name": "Davis Cline" }, + { "id": 9, "name": "Blanca Cameron" } + ], + "greeting": "Hello, Christi! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa346c214ead2d9abdf1", + "index": 39, + "guid": "eae6507c-4bae-4729-9212-aa5a8c48006b", + "isActive": false, + "balance": "$3,360.83", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { "first": "Kidd", "last": "Stark" }, + "company": "CENTREXIN", + "email": "kidd.stark@centrexin.us", + "phone": "+1 (832) 581-2526", + "address": "759 Blake Court, Turpin, Oklahoma, 7285", + "about": "Dolore dolor labore ut aliquip ad enim do enim do. Fugiat voluptate culpa qui ut officia consequat ipsum laboris ullamco exercitation voluptate consectetur proident minim. Laboris nisi amet quis aliquip adipisicing eiusmod pariatur in ut quis.", + "registered": "Saturday, April 30, 2016 2:38 AM", + "latitude": "-66.122491", + "longitude": "178.936101", + "tags": [ + "pariatur", + "duis", + "qui", + "qui", + "deserunt", + "minim", + "in", + "aliqua", + "voluptate", + "laboris" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Petty Ferrell" }, + { "id": 1, "name": "Jacqueline Reilly" }, + { "id": 2, "name": "Robles Frye" }, + { "id": 3, "name": "Woods Weeks" }, + { "id": 4, "name": "Louisa Levine" }, + { "id": 5, "name": "Hardin Farmer" }, + { "id": 6, "name": "Roach Glass" }, + { "id": 7, "name": "Jacobs Faulkner" }, + { "id": 8, "name": "Oconnor Hurley" }, + { "id": 9, "name": "Loretta Patel" } + ], + "greeting": "Hello, Kidd! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa348ff4bb496eae2130", + "index": 40, + "guid": "77f38c4e-206a-41ad-b8ec-8c124da29d71", + "isActive": true, + "balance": "$1,227.03", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": { "first": "Angelita", "last": "Mills" }, + "company": "CABLAM", + "email": "angelita.mills@cablam.biz", + "phone": "+1 (977) 596-3341", + "address": "240 Court Street, Collins, South Carolina, 3358", + "about": "Quis velit labore adipisicing amet excepteur. Exercitation enim adipisicing adipisicing ut nostrud cillum. Est anim duis duis voluptate Lorem occaecat. Ut commodo laborum reprehenderit aliqua dolor eiusmod cupidatat duis. Deserunt et mollit velit excepteur qui non deserunt esse ut tempor ut voluptate. Sit culpa sit officia Lorem nisi ad nulla amet ipsum elit dolore. Mollit amet id Lorem magna esse consequat duis irure ad veniam ea duis.", + "registered": "Saturday, October 11, 2014 3:14 PM", + "latitude": "47.351007", + "longitude": "105.90419", + "tags": [ + "sunt", + "non", + "voluptate", + "consectetur", + "ut", + "est", + "laborum", + "ad", + "cupidatat", + "esse" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Langley Powers" }, + { "id": 1, "name": "Carson Woodard" }, + { "id": 2, "name": "Peterson Pugh" }, + { "id": 3, "name": "Lorie Perez" }, + { "id": 4, "name": "Case Parks" }, + { "id": 5, "name": "Elizabeth Boone" }, + { "id": 6, "name": "Marian Maddox" }, + { "id": 7, "name": "Mara Sargent" }, + { "id": 8, "name": "Gilliam Garner" }, + { "id": 9, "name": "Weeks Ross" } + ], + "greeting": "Hello, Angelita! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34e7a9b39ca8267980", + "index": 41, + "guid": "2a508c71-aa4d-4f9e-a96d-3f6495bf102c", + "isActive": true, + "balance": "$2,610.88", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "green", + "name": { "first": "Kirk", "last": "Conner" }, + "company": "ECRATER", + "email": "kirk.conner@ecrater.com", + "phone": "+1 (876) 408-2160", + "address": "984 Erasmus Street, Ronco, Tennessee, 2168", + "about": "Nisi sint velit reprehenderit ex anim in veniam elit laborum aliquip. Sit exercitation mollit magna veniam officia minim ipsum labore dolore nulla. Dolor ad adipisicing magna amet aliquip. Amet elit aliqua dolore dolore mollit ex veniam sit aliquip proident pariatur duis aliqua do. Eu et id aute in eu qui minim sunt ullamco quis ea ipsum. Elit ullamco dolor irure culpa proident tempor enim irure irure deserunt anim ex. Consequat proident Lorem enim est.", + "registered": "Tuesday, June 20, 2017 5:36 PM", + "latitude": "9.0713", + "longitude": "-13.535663", + "tags": [ + "eu", + "duis", + "deserunt", + "sint", + "consequat", + "magna", + "laborum", + "aliquip", + "anim", + "ex" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Bridges Floyd" }, + { "id": 1, "name": "Barnes Head" }, + { "id": 2, "name": "Conley Barrett" }, + { "id": 3, "name": "Waters Bennett" }, + { "id": 4, "name": "Kaufman Morton" }, + { "id": 5, "name": "Copeland Rose" }, + { "id": 6, "name": "Kendra Daniels" }, + { "id": 7, "name": "Julie Roth" }, + { "id": 8, "name": "Tami Snider" }, + { "id": 9, "name": "Margaret Mcmillan" } + ], + "greeting": "Hello, Kirk! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa341e9858da323f3e8a", + "index": 42, + "guid": "8ae8c734-331c-4707-9225-f38615f7d87c", + "isActive": true, + "balance": "$3,280.97", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "blue", + "name": { "first": "Hickman", "last": "Langley" }, + "company": "VERAQ", + "email": "hickman.langley@veraq.co.uk", + "phone": "+1 (908) 439-3901", + "address": "469 Nova Court, Buxton, Wisconsin, 8132", + "about": "Voluptate et ipsum ea in voluptate. Amet incididunt cupidatat duis veniam ipsum veniam deserunt. Mollit duis exercitation cillum pariatur culpa enim. Excepteur nulla ea velit sunt aliqua. Est velit consectetur in aliqua. Duis pariatur ea sit laborum Lorem quis nisi dolore. Fugiat id ad consectetur irure ipsum adipisicing eu sit duis laboris tempor sunt irure minim.", + "registered": "Monday, December 19, 2016 6:40 PM", + "latitude": "38.352256", + "longitude": "-79.01819", + "tags": [ + "commodo", + "laboris", + "in", + "esse", + "incididunt", + "eiusmod", + "aute", + "amet", + "qui", + "esse" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Snow Stafford" }, + { "id": 1, "name": "Pollard Fischer" }, + { "id": 2, "name": "Lillian Bowers" }, + { "id": 3, "name": "Katy Lancaster" }, + { "id": 4, "name": "Ana Tillman" }, + { "id": 5, "name": "Tanisha Dean" }, + { "id": 6, "name": "Verna Osborn" }, + { "id": 7, "name": "Lorene Blackwell" }, + { "id": 8, "name": "Klein Lindsay" }, + { "id": 9, "name": "Kay Simpson" } + ], + "greeting": "Hello, Hickman! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34745076e981951cad", + "index": 43, + "guid": "cf66637a-0f87-43c1-8d3e-8a8eb32a3b82", + "isActive": true, + "balance": "$3,777.58", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "blue", + "name": { "first": "Dorthy", "last": "Dixon" }, + "company": "AVENETRO", + "email": "dorthy.dixon@avenetro.ca", + "phone": "+1 (865) 445-2658", + "address": "845 Hendrix Street, Mathews, Delaware, 8863", + "about": "Consectetur qui minim tempor proident sint esse est quis. Eiusmod aliqua ea ut officia quis deserunt cillum quis aliqua exercitation ipsum. Magna qui veniam enim ullamco nulla. Occaecat commodo excepteur qui laborum qui ea mollit Lorem non ex nostrud proident reprehenderit nulla. Ipsum laboris irure ullamco do consectetur laboris sunt id adipisicing ullamco duis quis cupidatat.", + "registered": "Wednesday, January 13, 2016 1:56 AM", + "latitude": "-45.361089", + "longitude": "118.758428", + "tags": [ + "esse", + "aute", + "excepteur", + "esse", + "labore", + "ut", + "irure", + "ea", + "cupidatat", + "aliquip" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Dillon Holman" }, + { "id": 1, "name": "Megan Joyner" }, + { "id": 2, "name": "Casandra Branch" }, + { "id": 3, "name": "Linda Livingston" }, + { "id": 4, "name": "Pope Talley" }, + { "id": 5, "name": "Vasquez Cox" }, + { "id": 6, "name": "Skinner Cross" }, + { "id": 7, "name": "Anna Beasley" }, + { "id": 8, "name": "Dawson Gould" }, + { "id": 9, "name": "Dean Shepard" } + ], + "greeting": "Hello, Dorthy! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa34f7481ee6928ebadf", + "index": 44, + "guid": "d5e4825b-cbfe-4994-af1a-03a4a46fd290", + "isActive": false, + "balance": "$2,976.38", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "brown", + "name": { "first": "Lynnette", "last": "Rosales" }, + "company": "YURTURE", + "email": "lynnette.rosales@yurture.info", + "phone": "+1 (931) 424-3261", + "address": "293 Rose Street, Alderpoint, Alabama, 2523", + "about": "Veniam et et laboris irure elit consectetur ut exercitation fugiat. Cillum in eu cillum elit et. Ullamco mollit tempor consectetur excepteur enim laborum amet magna id. Cillum commodo mollit qui consequat eiusmod cupidatat amet. Do labore aute consequat aliqua nostrud ut officia qui elit id labore dolor laboris. Fugiat nostrud ea id officia adipisicing. Incididunt reprehenderit velit sunt elit ex officia nulla nostrud sit culpa pariatur ipsum.", + "registered": "Monday, June 22, 2015 9:25 PM", + "latitude": "83.236293", + "longitude": "-165.695513", + "tags": [ + "sit", + "deserunt", + "non", + "ipsum", + "irure", + "laborum", + "ut", + "amet", + "dolore", + "Lorem" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Harriet Vasquez" }, + { "id": 1, "name": "Warren Sherman" }, + { "id": 2, "name": "Rita Downs" }, + { "id": 3, "name": "Celia Mcclain" }, + { "id": 4, "name": "Bethany Mason" }, + { "id": 5, "name": "Barker Anderson" }, + { "id": 6, "name": "Lucy Santana" }, + { "id": 7, "name": "Aurelia Dickerson" }, + { "id": 8, "name": "Bullock Durham" }, + { "id": 9, "name": "Middleton Huffman" } + ], + "greeting": "Hello, Lynnette! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa3447392bc6d49d3c6a", + "index": 45, + "guid": "93bf294e-6516-462c-affc-fefb2fc25cfb", + "isActive": false, + "balance": "$1,251.30", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "brown", + "name": { "first": "Wagner", "last": "Murphy" }, + "company": "NEXGENE", + "email": "wagner.murphy@nexgene.me", + "phone": "+1 (861) 488-2141", + "address": "567 Cleveland Street, Belva, Northern Mariana Islands, 1561", + "about": "Mollit ut ipsum id qui ex magna duis magna ipsum cillum proident. Veniam eu dolore deserunt nulla amet dolore quis aliqua. Est dolore anim aliqua ex exercitation cupidatat voluptate. Ea ipsum proident sunt non. Minim laborum nisi culpa ex sit excepteur reprehenderit aute exercitation officia veniam. Occaecat est tempor anim incididunt elit incididunt commodo fugiat magna laboris laboris irure. Culpa aliquip ipsum tempor cupidatat non laboris ad anim duis.", + "registered": "Saturday, June 20, 2015 8:46 AM", + "latitude": "26.957528", + "longitude": "-83.855732", + "tags": [ + "officia", + "aliqua", + "et", + "cupidatat", + "labore", + "culpa", + "nisi", + "sit", + "mollit", + "cupidatat" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Gertrude Mclaughlin" }, + { "id": 1, "name": "Esther Pope" }, + { "id": 2, "name": "Jacquelyn Rush" }, + { "id": 3, "name": "Ellen Keith" }, + { "id": 4, "name": "Zimmerman Mejia" }, + { "id": 5, "name": "Craft Franklin" }, + { "id": 6, "name": "Hubbard Christian" }, + { "id": 7, "name": "Bridgett Kline" }, + { "id": 8, "name": "Gonzalez Douglas" }, + { "id": 9, "name": "Larson Justice" } + ], + "greeting": "Hello, Wagner! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa344a1963094ff64da5", + "index": 46, + "guid": "6b9e6342-267d-4844-b030-723bae27c4ce", + "isActive": true, + "balance": "$1,943.18", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "green", + "name": { "first": "Tonya", "last": "Lowery" }, + "company": "MYOPIUM", + "email": "tonya.lowery@myopium.org", + "phone": "+1 (881) 553-2631", + "address": "975 Amboy Street, Nipinnawasee, California, 9715", + "about": "Pariatur dolor exercitation dolore eiusmod et nisi in deserunt laborum nisi magna. Dolor laborum culpa quis aute pariatur labore est velit voluptate. Minim labore occaecat aute fugiat sint laborum voluptate tempor minim.", + "registered": "Wednesday, December 30, 2015 5:12 AM", + "latitude": "13.22295", + "longitude": "159.692667", + "tags": [ + "eu", + "veniam", + "et", + "est", + "est", + "aliquip", + "sint", + "non", + "anim", + "ex" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Debra Stanton" }, + { "id": 1, "name": "Harrington Carney" }, + { "id": 2, "name": "Helena Rivas" }, + { "id": 3, "name": "Pearl Wagner" }, + { "id": 4, "name": "Bridgette Lawson" }, + { "id": 5, "name": "Patel Sutton" }, + { "id": 6, "name": "Horton Saunders" }, + { "id": 7, "name": "Sherri Nelson" }, + { "id": 8, "name": "Jacobson Hurst" }, + { "id": 9, "name": "Shanna Cotton" } + ], + "greeting": "Hello, Tonya! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "5ae0aa34b44b3eb5d573dfe4", + "index": 47, + "guid": "6fc32a51-1b79-4679-910e-5eb13aa223f8", + "isActive": true, + "balance": "$1,559.68", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "green", + "name": { "first": "Johnnie", "last": "Travis" }, + "company": "SURELOGIC", + "email": "johnnie.travis@surelogic.tv", + "phone": "+1 (855) 506-2479", + "address": "289 Anna Court, Denio, Virgin Islands, 7460", + "about": "Adipisicing ipsum enim ullamco laborum nostrud nulla esse quis ipsum voluptate eiusmod. Fugiat ut est consectetur nisi minim. Id sint nostrud eiusmod cupidatat fugiat.", + "registered": "Tuesday, August 1, 2017 5:05 PM", + "latitude": "-4.213212", + "longitude": "-93.529387", + "tags": [ + "est", + "consequat", + "consectetur", + "enim", + "qui", + "et", + "ullamco", + "ipsum", + "reprehenderit", + "mollit" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Ester Harrell" }, + { "id": 1, "name": "Shepard Shelton" }, + { "id": 2, "name": "Enid Romero" }, + { "id": 3, "name": "Effie Baxter" }, + { "id": 4, "name": "Dona Huber" }, + { "id": 5, "name": "Berger Heath" }, + { "id": 6, "name": "Allison Lynn" }, + { "id": 7, "name": "Blackwell Edwards" }, + { "id": 8, "name": "Lottie Chambers" }, + { "id": 9, "name": "Todd Holmes" } + ], + "greeting": "Hello, Johnnie! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "5ae0aa349fe0e22b1f9fbdfd", + "index": 48, + "guid": "3ae5da74-591c-48c9-a328-6ec454619337", + "isActive": false, + "balance": "$2,825.93", + "picture": "http://placehold.it/32x32", + "age": 20, + "eyeColor": "blue", + "name": { "first": "Deanna", "last": "Adkins" }, + "company": "VIRXO", + "email": "deanna.adkins@virxo.io", + "phone": "+1 (981) 554-3807", + "address": "650 Bridge Street, Mappsville, Kansas, 4759", + "about": "Et aliqua laboris do excepteur veniam dolor cupidatat nisi eu voluptate sunt eiusmod non eiusmod. Minim eu dolor sunt aute. Nostrud laborum ad voluptate ipsum occaecat Lorem. Dolore sit amet cupidatat enim cillum ipsum cillum. Et laborum ut proident officia mollit. Eu velit commodo esse id sint aliquip Lorem et occaecat aliqua. Consequat eiusmod fugiat cillum consequat eiusmod eiusmod ex qui est duis consequat et officia.", + "registered": "Tuesday, December 13, 2016 7:50 AM", + "latitude": "33.223746", + "longitude": "15.22617", + "tags": [ + "excepteur", + "ex", + "deserunt", + "qui", + "sit", + "aute", + "nostrud", + "do", + "labore", + "ipsum" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Riddle Reese" }, + { "id": 1, "name": "Selma Henson" }, + { "id": 2, "name": "Yesenia Middleton" }, + { "id": 3, "name": "Nola White" }, + { "id": 4, "name": "Sweet Guerra" }, + { "id": 5, "name": "Terra Small" }, + { "id": 6, "name": "Hamilton Hughes" }, + { "id": 7, "name": "Hester Poole" }, + { "id": 8, "name": "Calhoun Hubbard" }, + { "id": 9, "name": "Bonita Hall" } + ], + "greeting": "Hello, Deanna! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "5ae0aa34e364048f9370e15f", + "index": 49, + "guid": "bf614856-f78f-44c2-8abc-0f89064d6c7b", + "isActive": true, + "balance": "$3,625.36", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "blue", + "name": { "first": "Rosella", "last": "Zimmerman" }, + "company": "ZYTREX", + "email": "rosella.zimmerman@zytrex.name", + "phone": "+1 (928) 486-3626", + "address": "915 Dean Street, Valmy, Iowa, 2698", + "about": "Dolore cupidatat quis ex esse. Mollit labore exercitation exercitation Lorem elit pariatur incididunt culpa nostrud pariatur tempor ut id. Lorem nostrud mollit elit veniam dolore incididunt duis consectetur nostrud proident eu occaecat cupidatat incididunt. Dolor pariatur fugiat sunt do consequat officia sit aliquip officia quis consequat ipsum dolor ad. Occaecat mollit sunt sit occaecat. Quis in irure ipsum sunt. Dolor ullamco sunt dolor labore proident consectetur ex irure est dolor officia.", + "registered": "Sunday, September 24, 2017 5:22 AM", + "latitude": "-58.21478", + "longitude": "2.994387", + "tags": [ + "id", + "irure", + "labore", + "anim", + "non", + "est", + "eiusmod", + "aliquip", + "enim", + "proident" + ], + "range": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "friends": [ + { "id": 0, "name": "Ortiz Rivera" }, + { "id": 1, "name": "Nina Mcclure" }, + { "id": 2, "name": "Donna Whitley" }, + { "id": 3, "name": "Ladonna Salazar" }, + { "id": 4, "name": "Rosario Gay" }, + { "id": 5, "name": "Nelda Rich" }, + { "id": 6, "name": "Harriett Phillips" }, + { "id": 7, "name": "Marianne Leblanc" }, + { "id": 8, "name": "Anastasia Smith" }, + { "id": 9, "name": "Stacy Cochran" } + ], + "greeting": "Hello, Rosella! You have 8 unread messages.", + "favoriteFruit": "apple" + } + ] +} diff --git a/testdata/one.gron b/internal/gron/testdata/one.gron similarity index 100% rename from testdata/one.gron rename to internal/gron/testdata/one.gron diff --git a/testdata/one.jgron b/internal/gron/testdata/one.jgron similarity index 100% rename from testdata/one.jgron rename to internal/gron/testdata/one.jgron diff --git a/testdata/one.json b/internal/gron/testdata/one.json similarity index 100% rename from testdata/one.json rename to internal/gron/testdata/one.json diff --git a/testdata/scalar-stream.gron b/internal/gron/testdata/scalar-stream.gron similarity index 100% rename from testdata/scalar-stream.gron rename to internal/gron/testdata/scalar-stream.gron diff --git a/testdata/scalar-stream.jgron b/internal/gron/testdata/scalar-stream.jgron similarity index 100% rename from testdata/scalar-stream.jgron rename to internal/gron/testdata/scalar-stream.jgron diff --git a/testdata/scalar-stream.json b/internal/gron/testdata/scalar-stream.json similarity index 100% rename from testdata/scalar-stream.json rename to internal/gron/testdata/scalar-stream.json diff --git a/testdata/stream.gron b/internal/gron/testdata/stream.gron similarity index 100% rename from testdata/stream.gron rename to internal/gron/testdata/stream.gron diff --git a/testdata/stream.jgron b/internal/gron/testdata/stream.jgron similarity index 100% rename from testdata/stream.jgron rename to internal/gron/testdata/stream.jgron diff --git a/testdata/stream.json b/internal/gron/testdata/stream.json similarity index 100% rename from testdata/stream.json rename to internal/gron/testdata/stream.json diff --git a/testdata/three.gron b/internal/gron/testdata/three.gron similarity index 100% rename from testdata/three.gron rename to internal/gron/testdata/three.gron diff --git a/testdata/three.jgron b/internal/gron/testdata/three.jgron similarity index 100% rename from testdata/three.jgron rename to internal/gron/testdata/three.jgron diff --git a/testdata/three.json b/internal/gron/testdata/three.json similarity index 100% rename from testdata/three.json rename to internal/gron/testdata/three.json diff --git a/testdata/two-b.json b/internal/gron/testdata/two-b.json similarity index 100% rename from testdata/two-b.json rename to internal/gron/testdata/two-b.json diff --git a/testdata/two.gron b/internal/gron/testdata/two.gron similarity index 100% rename from testdata/two.gron rename to internal/gron/testdata/two.gron diff --git a/testdata/two.jgron b/internal/gron/testdata/two.jgron similarity index 100% rename from testdata/two.jgron rename to internal/gron/testdata/two.jgron diff --git a/testdata/two.json b/internal/gron/testdata/two.json similarity index 100% rename from testdata/two.json rename to internal/gron/testdata/two.json diff --git a/token.go b/internal/gron/token.go similarity index 55% rename from token.go rename to internal/gron/token.go index 8a6aa54..d6be2a7 100644 --- a/token.go +++ b/internal/gron/token.go @@ -1,4 +1,4 @@ -package main +package gron import ( "bytes" @@ -7,72 +7,72 @@ import ( "unicode" ) -// A token is a chunk of text from a statement with a type -type token struct { - text string - typ tokenTyp +// A Token is a chunk of text from a statement with a type +type Token struct { + Text string + Typ TokenTyp } -// A tokenTyp identifies what kind of token something is -type tokenTyp int +// A TokenTyp identifies what kind of token something is +type TokenTyp int const ( // A bare word is a unquoted key; like 'foo' in json.foo = 1; - typBare tokenTyp = iota + TypBare TokenTyp = iota // Numeric key; like '2' in json[2] = "foo"; - typNumericKey + TypNumericKey // A quoted key; like 'foo bar' in json["foo bar"] = 2; - typQuotedKey + TypQuotedKey // Punctuation types - typDot // . - typLBrace // [ - typRBrace // ] - typEquals // = - typSemi // ; - typComma // , + TypDot // . + TypLBrace // [ + TypRBrace // ] + TypEquals // = + TypSemi // ; + TypComma // , // Value types - typString // "foo" - typNumber // 4 - typTrue // true - typFalse // false - typNull // null - typEmptyArray // [] - typEmptyObject // {} + TypString // "foo" + TypNumber // 4 + TypTrue // true + TypFalse // false + TypNull // null + TypEmptyArray // [] + TypEmptyObject // {} // Ignored token - typIgnored + TypIgnored // Error token - typError + TypError ) // a sprintFn adds color to its input type sprintFn func(...interface{}) string // mapping of token types to the appropriate color sprintFn -var sprintFns = map[tokenTyp]sprintFn{ - typBare: bareColor.SprintFunc(), - typNumericKey: numColor.SprintFunc(), - typQuotedKey: strColor.SprintFunc(), - typLBrace: braceColor.SprintFunc(), - typRBrace: braceColor.SprintFunc(), - typString: strColor.SprintFunc(), - typNumber: numColor.SprintFunc(), - typTrue: boolColor.SprintFunc(), - typFalse: boolColor.SprintFunc(), - typNull: boolColor.SprintFunc(), - typEmptyArray: braceColor.SprintFunc(), - typEmptyObject: braceColor.SprintFunc(), +var sprintFns = map[TokenTyp]sprintFn{ + TypBare: bareColor.SprintFunc(), + TypNumericKey: numColor.SprintFunc(), + TypQuotedKey: strColor.SprintFunc(), + TypLBrace: braceColor.SprintFunc(), + TypRBrace: braceColor.SprintFunc(), + TypString: strColor.SprintFunc(), + TypNumber: numColor.SprintFunc(), + TypTrue: boolColor.SprintFunc(), + TypFalse: boolColor.SprintFunc(), + TypNull: boolColor.SprintFunc(), + TypEmptyArray: braceColor.SprintFunc(), + TypEmptyObject: braceColor.SprintFunc(), } // isValue returns true if the token is a valid value type -func (t token) isValue() bool { - switch t.typ { - case typString, typNumber, typTrue, typFalse, typNull, typEmptyArray, typEmptyObject: +func (t Token) isValue() bool { + switch t.Typ { + case TypString, TypNumber, TypTrue, TypFalse, TypNull, TypEmptyArray, TypEmptyObject: return true default: return false @@ -80,9 +80,9 @@ func (t token) isValue() bool { } // isPunct returns true if the token is a punctuation type -func (t token) isPunct() bool { - switch t.typ { - case typDot, typLBrace, typRBrace, typEquals, typSemi, typComma: +func (t Token) isPunct() bool { + switch t.Typ { + case TypDot, TypLBrace, TypRBrace, TypEquals, TypSemi, TypComma: return true default: return false @@ -90,20 +90,20 @@ func (t token) isPunct() bool { } // format returns the formatted version of the token text -func (t token) format() string { - if t.typ == typEquals { - return " " + t.text + " " +func (t Token) format() string { + if t.Typ == TypEquals { + return " " + t.Text + " " } - return t.text + return t.Text } // formatColor returns the colored formatted version of the token text -func (t token) formatColor() string { - text := t.text - if t.typ == typEquals { +func (t Token) formatColor() string { + text := t.Text + if t.Typ == TypEquals { text = " " + text + " " } - fn, ok := sprintFns[t.typ] + fn, ok := sprintFns[t.Typ] if ok { return fn(text) } @@ -113,30 +113,30 @@ func (t token) formatColor() string { // valueTokenFromInterface takes any valid value and // returns a value token to represent it -func valueTokenFromInterface(v interface{}) token { +func valueTokenFromInterface(v interface{}) Token { switch vv := v.(type) { case map[interface{}]interface{}: - return token{"{}", typEmptyObject} + return Token{"{}", TypEmptyObject} case map[string]interface{}: - return token{"{}", typEmptyObject} + return Token{"{}", TypEmptyObject} case []interface{}: - return token{"[]", typEmptyArray} + return Token{"[]", TypEmptyArray} case int, float64: - return token{fmt.Sprintf("%v", vv), typNumber} + return Token{fmt.Sprintf("%v", vv), TypNumber} case json.Number: - return token{vv.String(), typNumber} + return Token{vv.String(), TypNumber} case string: - return token{quoteString(vv), typString} + return Token{quoteString(vv), TypString} case bool: if vv { - return token{"true", typTrue} + return Token{"true", TypTrue} } - return token{"false", typFalse} + return Token{"false", TypFalse} case nil: - return token{"null", typNull} + return Token{"null", TypNull} default: - return token{"", typError} + return Token{"", TypError} } } diff --git a/internal/gron/token_test.go b/internal/gron/token_test.go new file mode 100644 index 0000000..41240b5 --- /dev/null +++ b/internal/gron/token_test.go @@ -0,0 +1,52 @@ +package gron + +import ( + "encoding/json" + "testing" +) + +var cases = []struct { + in interface{} + want Token +}{ + {make(map[string]interface{}), Token{"{}", TypEmptyObject}}, + {make([]interface{}, 0), Token{"[]", TypEmptyArray}}, + {json.Number("1.2"), Token{"1.2", TypNumber}}, + {"foo", Token{`"foo"`, TypString}}, + {"<3", Token{`"<3"`, TypString}}, + {"&", Token{`"&"`, TypString}}, + {"\b", Token{`"\b"`, TypString}}, + {"\f", Token{`"\f"`, TypString}}, + {"\n", Token{`"\n"`, TypString}}, + {"\r", Token{`"\r"`, TypString}}, + {"\t", Token{`"\t"`, TypString}}, + {"wat \u001e", Token{`"wat \u001E"`, TypString}}, + {"Hello, 世界", Token{`"Hello, 世界"`, TypString}}, + {true, Token{"true", TypTrue}}, + {false, Token{"false", TypFalse}}, + {nil, Token{"null", TypNull}}, + {struct{}{}, Token{"", TypError}}, +} + +func TestValueTokenFromInterface(t *testing.T) { + + for _, c := range cases { + have := valueTokenFromInterface(c.in) + + if have != c.want { + t.Logf("input: %#v", have) + t.Logf("have: %#v", have) + t.Logf("want: %#v", c.want) + t.Errorf("have != want") + } + } +} + +func BenchmarkValueTokenFromInterface(b *testing.B) { + + for i := 0; i < b.N; i++ { + for _, c := range cases { + _ = valueTokenFromInterface(c.in) + } + } +} diff --git a/ungron.go b/internal/gron/ungron.go similarity index 71% rename from ungron.go rename to internal/gron/ungron.go index 12c1261..5a9f76a 100644 --- a/ungron.go +++ b/internal/gron/ungron.go @@ -10,9 +10,11 @@ // String ::= '"' (UnescapedRune | ("\" (["\/bfnrt] | ('u' Hex))))* '"' // UnescapedRune ::= [^#x0-#x1f"\] -package main +package gron import ( + "bufio" + "bytes" "encoding/json" "fmt" "reflect" @@ -21,9 +23,110 @@ import ( "unicode" "unicode/utf8" + "github.com/nwidger/jsoncolor" "github.com/pkg/errors" + "io" ) +// Ungron is the reverse of gron. Given assignment statements as input, +// it returns JSON. The only option is optMonochrome +func Ungron(r io.Reader, w io.Writer, opts int) (int, error) { + scanner := bufio.NewScanner(r) + var maker StatementMaker + + // Allow larger internal buffer of the scanner (min: 64KiB ~ max: 1MiB) + scanner.Buffer(make([]byte, 64*1024), 1024*1024) + + if opts&optJSON > 0 { + maker = StatementFromJSONSpec + } else { + maker = StatementFromStringMaker + } + + // Make a list of statements from the input + var ss Statements + for scanner.Scan() { + s, err := maker(scanner.Text()) + if err != nil { + return exitParseStatements, err + } + ss.Add(s) + } + if err := scanner.Err(); err != nil { + return exitReadInput, fmt.Errorf("failed to read input statements") + } + + // turn the statements into a single merged interface{} type + merged, err := ss.ToInterface() + if err != nil { + return exitParseStatements, err + } + + // If there's only one top level key and it's "json", make that the top level thing + mergedMap, ok := merged.(map[string]interface{}) + if ok { + if len(mergedMap) == 1 { + if _, exists := mergedMap["json"]; exists { + merged = mergedMap["json"] + } + } + } + + // Marshal the output into JSON to display to the user + out := &bytes.Buffer{} + enc := json.NewEncoder(out) + enc.SetIndent("", " ") + enc.SetEscapeHTML(false) + err = enc.Encode(merged) + if err != nil { + return exitJSONEncode, errors.Wrap(err, "failed to convert statements to JSON") + } + j := out.Bytes() + + // If the output isn't monochrome, add color to the JSON + if opts&optMonochrome == 0 { + c, err := colorizeJSON(j) + + // If we failed to colorize the JSON for whatever reason, + // we'll just fall back to monochrome output, otherwise + // replace the monochrome JSON with glorious technicolor + if err == nil { + j = c + } + } + + // For whatever reason, the monochrome version of the JSON + // has a trailing newline character, but the colorized version + // does not. Strip the whitespace so that neither has the newline + // character on the end, and then we'll add a newline in the + // Fprintf below + j = bytes.TrimSpace(j) + + fmt.Fprintf(w, "%s\n", j) + + return exitOK, nil +} + +func colorizeJSON(src []byte) ([]byte, error) { + out := &bytes.Buffer{} + f := jsoncolor.NewFormatter() + + f.StringColor = strColor + f.ObjectColor = braceColor + f.ArrayColor = braceColor + f.FieldColor = bareColor + f.NumberColor = numColor + f.TrueColor = boolColor + f.FalseColor = boolColor + f.NullColor = boolColor + + err := f.Format(out, src) + if err != nil { + return out.Bytes(), err + } + return out.Bytes(), nil +} + // errRecoverable is an error type to represent errors that // can be recovered from; e.g. an empty line in the input type errRecoverable struct { @@ -41,7 +144,7 @@ type lexer struct { width int // The width of the current rune in bytes cur rune // The rune at the current position prev rune // The rune at the previous position - tokens []token // The tokens that have been emitted + tokens []Token // The tokens that have been emitted tokenStart int // The starting position of the current token } @@ -51,12 +154,12 @@ func newLexer(text string) *lexer { text: text, pos: 0, tokenStart: 0, - tokens: make([]token, 0), + tokens: make([]Token, 0), } } // lex runs the lexer and returns the lexed statement -func (l *lexer) lex() statement { +func (l *lexer) lex() Statement { for lexfn := lexStatement; lexfn != nil; { lexfn = lexfn(l) @@ -98,10 +201,10 @@ func (l *lexer) ignore() { // emit adds the current token to the token slice and // moves the tokenStart pointer to the current position -func (l *lexer) emit(typ tokenTyp) { - t := token{ - text: l.text[l.tokenStart:l.pos], - typ: typ, +func (l *lexer) emit(typ TokenTyp) { + t := Token{ + Text: l.text[l.tokenStart:l.pos], + Typ: typ, } l.tokenStart = l.pos @@ -207,7 +310,7 @@ func lexStatement(l *lexer) lexFn { case r == utf8.RuneError: return nil default: - l.emit(typError) + l.emit(TypError) return nil } @@ -217,15 +320,15 @@ func lexStatement(l *lexer) lexFn { // E.g: the 'foo' in 'foo.bar' or 'foo[0]' is a bare identifier func lexBareWord(l *lexer) lexFn { if l.accept(".") { - l.emit(typDot) + l.emit(TypDot) } if !l.acceptFunc(validFirstRune) { - l.emit(typError) + l.emit(TypError) return nil } l.acceptRunFunc(validSecondaryRune) - l.emit(typBare) + l.emit(TypBare) return lexStatement } @@ -233,7 +336,7 @@ func lexBareWord(l *lexer) lexFn { // lexBraces lexes keys contained within square braces func lexBraces(l *lexer) lexFn { l.accept("[") - l.emit(typLBrace) + l.emit(TypLBrace) switch { case unicode.IsNumber(l.peek()): @@ -241,7 +344,7 @@ func lexBraces(l *lexer) lexFn { case l.peek() == '"': return lexQuotedKey default: - l.emit(typError) + l.emit(TypError) return nil } } @@ -252,12 +355,12 @@ func lexNumericKey(l *lexer) lexFn { l.ignore() l.acceptRunFunc(unicode.IsNumber) - l.emit(typNumericKey) + l.emit(TypNumericKey) if l.accept("]") { - l.emit(typRBrace) + l.emit(TypRBrace) } else { - l.emit(typError) + l.emit(TypError) return nil } l.ignore() @@ -273,12 +376,12 @@ func lexQuotedKey(l *lexer) lexFn { l.acceptUntilUnescaped(`"`) l.accept(`"`) - l.emit(typQuotedKey) + l.emit(TypQuotedKey) if l.accept("]") { - l.emit(typRBrace) + l.emit(TypRBrace) } else { - l.emit(typError) + l.emit(TypError) return nil } l.ignore() @@ -291,7 +394,7 @@ func lexValue(l *lexer) lexFn { l.ignore() if l.accept("=") { - l.emit(typEquals) + l.emit(TypEquals) } else { return nil } @@ -303,39 +406,39 @@ func lexValue(l *lexer) lexFn { case l.accept(`"`): l.acceptUntilUnescaped(`"`) l.accept(`"`) - l.emit(typString) + l.emit(TypString) case l.accept("t"): l.acceptRun("rue") - l.emit(typTrue) + l.emit(TypTrue) case l.accept("f"): l.acceptRun("alse") - l.emit(typFalse) + l.emit(TypFalse) case l.accept("n"): l.acceptRun("ul") - l.emit(typNull) + l.emit(TypNull) case l.accept("["): l.accept("]") - l.emit(typEmptyArray) + l.emit(TypEmptyArray) case l.accept("{"): l.accept("}") - l.emit(typEmptyObject) + l.emit(TypEmptyObject) default: // Assume number l.acceptUntil(";") - l.emit(typNumber) + l.emit(TypNumber) } l.acceptRun(" ") l.ignore() if l.accept(";") { - l.emit(typSemi) + l.emit(TypSemi) } // The value should always be the last thing @@ -349,21 +452,21 @@ func lexIgnore(l *lexer) lexFn { l.acceptRunFunc(func(r rune) bool { return r != utf8.RuneError }) - l.emit(typIgnored) + l.emit(TypIgnored) return nil } // ungronTokens turns a slice of tokens into an actual datastructure -func ungronTokens(ts []token) (interface{}, error) { +func ungronTokens(ts []Token) (interface{}, error) { if len(ts) == 0 { return nil, errRecoverable{"empty input"} } - if ts[0].typ == typIgnored { + if ts[0].Typ == TypIgnored { return nil, errRecoverable{"ignored token"} } - if ts[len(ts)-1].typ == typError { + if ts[len(ts)-1].Typ == TypError { return nil, errors.New("invalid statement") } @@ -386,42 +489,42 @@ func ungronTokens(ts []token) (interface{}, error) { case t.isValue(): var val interface{} - d := json.NewDecoder(strings.NewReader(t.text)) + d := json.NewDecoder(strings.NewReader(t.Text)) d.UseNumber() err := d.Decode(&val) if err != nil { - return nil, fmt.Errorf("invalid value `%s`", t.text) + return nil, fmt.Errorf("invalid value `%s`", t.Text) } return val, nil - case t.typ == typBare: + case t.Typ == TypBare: val, err := ungronTokens(ts[1:]) if err != nil { return nil, err } out := make(map[string]interface{}) - out[t.text] = val + out[t.Text] = val return out, nil - case t.typ == typQuotedKey: + case t.Typ == TypQuotedKey: val, err := ungronTokens(ts[1:]) if err != nil { return nil, err } key := "" - err = json.Unmarshal([]byte(t.text), &key) + err = json.Unmarshal([]byte(t.Text), &key) if err != nil { - return nil, fmt.Errorf("invalid quoted key `%s`", t.text) + return nil, fmt.Errorf("invalid quoted key `%s`", t.Text) } out := make(map[string]interface{}) out[key] = val return out, nil - case t.typ == typNumericKey: - key, err := strconv.Atoi(t.text) + case t.Typ == TypNumericKey: + key, err := strconv.Atoi(t.Text) if err != nil { - return nil, fmt.Errorf("invalid integer key `%s`", t.text) + return nil, fmt.Errorf("invalid integer key `%s`", t.Text) } val, err := ungronTokens(ts[1:]) @@ -435,7 +538,7 @@ func ungronTokens(ts []token) (interface{}, error) { return out, nil default: - return nil, fmt.Errorf("unexpected token `%s`", t.text) + return nil, fmt.Errorf("unexpected token `%s`", t.Text) } } diff --git a/internal/gron/ungron_test.go b/internal/gron/ungron_test.go new file mode 100644 index 0000000..79247cb --- /dev/null +++ b/internal/gron/ungron_test.go @@ -0,0 +1,292 @@ +package gron + +import ( + "reflect" + "testing" +) + +func TestLex(t *testing.T) { + cases := []struct { + in string + want []Token + }{ + {`json.foo = 1;`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {`foo`, TypBare}, + {`=`, TypEquals}, + {`1`, TypNumber}, + {`;`, TypSemi}, + }}, + + {`json.foo = "bar";`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {`foo`, TypBare}, + {`=`, TypEquals}, + {`"bar"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json.foo = "ba;r";`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {`foo`, TypBare}, + {`=`, TypEquals}, + {`"ba;r"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json.foo = "ba\"r ;";`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {`foo`, TypBare}, + {`=`, TypEquals}, + {`"ba\"r ;"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json = "\\";`, []Token{ + {`json`, TypBare}, + {`=`, TypEquals}, + {`"\\"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json = "\\\\";`, []Token{ + {`json`, TypBare}, + {`=`, TypEquals}, + {`"\\\\"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json = "f\oo\\";`, []Token{ + {`json`, TypBare}, + {`=`, TypEquals}, + {`"f\oo\\"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json.value = "\u003c ;";`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {`value`, TypBare}, + {`=`, TypEquals}, + {`"\u003c ;"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json[0] = "bar";`, []Token{ + {`json`, TypBare}, + {`[`, TypLBrace}, + {`0`, TypNumericKey}, + {`]`, TypRBrace}, + {`=`, TypEquals}, + {`"bar"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json["foo"] = "bar";`, []Token{ + {`json`, TypBare}, + {`[`, TypLBrace}, + {`"foo"`, TypQuotedKey}, + {`]`, TypRBrace}, + {`=`, TypEquals}, + {`"bar"`, TypString}, + {`;`, TypSemi}, + }}, + + {`json.foo["bar"][0] = "bar";`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {`foo`, TypBare}, + {`[`, TypLBrace}, + {`"bar"`, TypQuotedKey}, + {`]`, TypRBrace}, + {`[`, TypLBrace}, + {`0`, TypNumericKey}, + {`]`, TypRBrace}, + {`=`, TypEquals}, + {`"bar"`, TypString}, + {`;`, TypSemi}, + }}, + + {`not an identifier at all`, []Token{ + {`not`, TypBare}, + }}, + + {`alsonotanidentifier`, []Token{ + {`alsonotanidentifier`, TypBare}, + }}, + + {`wat!`, []Token{ + {`wat`, TypBare}, + {``, TypError}, + }}, + + {`json[ = 1;`, []Token{ + {`json`, TypBare}, + {`[`, TypLBrace}, + {``, TypError}, + }}, + + {`json.[2] = 1;`, []Token{ + {`json`, TypBare}, + {`.`, TypDot}, + {``, TypError}, + }}, + + {`json[1 = 1;`, []Token{ + {`json`, TypBare}, + {`[`, TypLBrace}, + {`1`, TypNumericKey}, + {``, TypError}, + }}, + + {`json["foo] = 1;`, []Token{ + {`json`, TypBare}, + {`[`, TypLBrace}, + {`"foo] = 1;`, TypQuotedKey}, + {``, TypError}, + }}, + + {`--`, []Token{ + {`--`, TypIgnored}, + }}, + + {`json = 1;`, []Token{ + {`json`, TypBare}, + {`=`, TypEquals}, + {`1`, TypNumber}, + {`;`, TypSemi}, + }}, + + {`json=1;`, []Token{ + {`json`, TypBare}, + {`=`, TypEquals}, + {`1`, TypNumber}, + {`;`, TypSemi}, + }}, + } + + for _, c := range cases { + l := newLexer(c.in) + have := l.lex() + + if len(have) != len(c.want) { + t.Logf("Input: %#v", c.in) + t.Logf("Want: %#v", c.want) + t.Logf("Have: %#v", have) + t.Fatalf("want %d token.tokens, have %d", len(c.want), len(have)) + } + + for i := range have { + if have[i] != c.want[i] { + t.Logf("Input: %#v", c.in) + t.Logf("Want: %#v", c.want) + t.Logf("Have: %#v", have) + t.Errorf("Want `%#v` in position %d, have `%#v`", c.want[i], i, have[i]) + } + } + } +} + +func TestTokensSimple(t *testing.T) { + in := `json.contact["e-mail"][0] = "mail@tomnomnom.com";` + want := map[string]interface{}{ + "json": map[string]interface{}{ + "contact": map[string]interface{}{ + "e-mail": []interface{}{ + "mail@tomnomnom.com", + }, + }, + }, + } + + l := newLexer(in) + tokens := l.lex() + have, err := ungronTokens(tokens) + + if err != nil { + t.Fatalf("failed to ungron statement: %s", err) + } + + t.Logf("Have: %#v", have) + t.Logf("Want: %#v", want) + + eq := reflect.DeepEqual(have, want) + if !eq { + t.Errorf("Have and want datastructures are unequal") + } +} + +func TestTokensInvalid(t *testing.T) { + cases := []struct { + in []Token + }{ + {[]Token{{``, TypError}}}, // Error token.token + {[]Token{{`foo`, TypString}}}, // Invalid value + {[]Token{{`"foo`, TypQuotedKey}, {"1", TypNumber}}}, // Invalid quoted key + {[]Token{{`foo`, TypNumericKey}, {"1", TypNumber}}}, // Invalid numeric key + {[]Token{{``, -255}, {"1", TypNumber}}}, // Invalid token.token type + } + + for _, c := range cases { + _, err := ungronTokens(c.in) + if err == nil { + t.Errorf("want non-nil error for %#v; have nil", c.in) + } + } +} + +func TestMerge(t *testing.T) { + a := map[string]interface{}{ + "json": map[string]interface{}{ + "contact": map[string]interface{}{ + "e-mail": []interface{}{ + 0: "mail@tomnomnom.com", + }, + }, + }, + } + + b := map[string]interface{}{ + "json": map[string]interface{}{ + "contact": map[string]interface{}{ + "e-mail": []interface{}{ + 1: "test@tomnomnom.com", + 3: "foo@tomnomnom.com", + }, + "twitter": "@TomNomNom", + }, + }, + } + + want := map[string]interface{}{ + "json": map[string]interface{}{ + "contact": map[string]interface{}{ + "e-mail": []interface{}{ + 0: "mail@tomnomnom.com", + 1: "test@tomnomnom.com", + 3: "foo@tomnomnom.com", + }, + "twitter": "@TomNomNom", + }, + }, + } + + t.Logf("A: %#v", a) + t.Logf("B: %#v", b) + have, err := recursiveMerge(a, b) + if err != nil { + t.Fatalf("failed to merge datastructures: %s", err) + } + + t.Logf("Have: %#v", have) + t.Logf("Want: %#v", want) + eq := reflect.DeepEqual(have, want) + if !eq { + t.Errorf("Have and want datastructures are unequal") + } + +} diff --git a/main.go b/main.go index be8746f..2b148bc 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,6 @@ package main import ( - "bufio" - "bytes" - "encoding/json" "flag" "fmt" "io" @@ -15,7 +12,11 @@ import ( "github.com/mattn/go-colorable" "github.com/nwidger/jsoncolor" "github.com/pkg/errors" - "gopkg.in/yaml.v3" + + "bufio" + "bytes" + "encoding/json" + internal "github.com/lafrenierejm/gron/internal/gron" ) // Exit codes @@ -176,13 +177,13 @@ func main() { } // Pick the appropriate action: gron, ungron, gronValues, or gronStream - var a actionFn = gron + var a internal.ActionFn = internal.Gron if ungronFlag { - a = ungron + a = internal.Ungron } else if valuesFlag { a = gronValues } else if streamFlag { - a = gronStream + a = internal.GronStream } exitCode, err := a(rawInput, colorable.NewColorableStdout(), opts) @@ -193,35 +194,16 @@ func main() { os.Exit(exitOK) } -// an actionFn represents a main action of the program, it accepts -// an input, output and a bitfield of options; returning an exit -// code and any error that occurred -type actionFn func(io.Reader, io.Writer, int) (int, error) - -type decoder interface { - Decode(interface{}) error -} - -func makeDecoder(r io.Reader, opts int) decoder { - if opts&optYAML > 0 { - return yaml.NewDecoder(r) - } else { - d := json.NewDecoder(r) - d.UseNumber() - return d - } -} - // gron is the default action. Given JSON as the input it returns a list // of assignment statements. Possible options are optNoSort and optMonochrome func gron(r io.Reader, w io.Writer, opts int) (int, error) { var err error - var conv statementconv + var conv internal.StatementConv if opts&optMonochrome > 0 { - conv = statementToString + conv = internal.StatementToString } else { - conv = statementToColorString + conv = internal.StatementToColorString } top := "json" @@ -229,7 +211,7 @@ func gron(r io.Reader, w io.Writer, opts int) (int, error) { top = "yaml" } - ss, err := statementsFromJSON(makeDecoder(r, opts), statement{{top, typBare}}) + ss, err := internal.StatementsFromJSON(internal.MakeDecoder(r, opts&optYAML), internal.Statement{{top, internal.TypBare}}) if err != nil { goto out } @@ -242,7 +224,7 @@ func gron(r io.Reader, w io.Writer, opts int) (int, error) { for _, s := range ss { if opts&optJSON > 0 { - s, err = s.jsonify() + s, err = s.Jsonify() if err != nil { goto out } @@ -267,34 +249,34 @@ func gronStream(r io.Reader, w io.Writer, opts int) (int, error) { var sc *bufio.Scanner var buf []byte - var conv func(s statement) string + var conv func(s internal.Statement) string if opts&optMonochrome > 0 { - conv = statementToString + conv = internal.StatementToString } else { - conv = statementToColorString + conv = internal.StatementToColorString } // Helper function to make the prefix statements for each line - makePrefix := func(index int) statement { - return statement{ - {"json", typBare}, - {"[", typLBrace}, - {fmt.Sprintf("%d", index), typNumericKey}, - {"]", typRBrace}, + makePrefix := func(index int) internal.Statement { + return internal.Statement{ + {"json", internal.TypBare}, + {"[", internal.TypLBrace}, + {fmt.Sprintf("%d", index), internal.TypNumericKey}, + {"]", internal.TypRBrace}, } } // The first line of output needs to establish that the top-level // thing is actually an array... - top := statement{ - {"json", typBare}, - {"=", typEquals}, - {"[]", typEmptyArray}, - {";", typSemi}, + top := internal.Statement{ + {"json", internal.TypBare}, + {"=", internal.TypEquals}, + {"[]", internal.TypEmptyArray}, + {";", internal.TypSemi}, } if opts&optJSON > 0 { - top, err = top.jsonify() + top, err = top.Jsonify() if err != nil { goto out } @@ -309,10 +291,10 @@ func gronStream(r io.Reader, w io.Writer, opts int) (int, error) { i = 0 for sc.Scan() { - d := makeDecoder(bytes.NewBuffer(sc.Bytes()), opts) + d := internal.MakeDecoder(bytes.NewBuffer(sc.Bytes()), opts) - var ss statements - ss, err = statementsFromJSON(d, makePrefix(i)) + var ss internal.Statements + ss, err = internal.StatementsFromJSON(d, makePrefix(i)) i++ if err != nil { goto out @@ -326,7 +308,7 @@ func gronStream(r io.Reader, w io.Writer, opts int) (int, error) { for _, s := range ss { if opts&optJSON > 0 { - s, err = s.jsonify() + s, err = s.Jsonify() if err != nil { goto out } @@ -351,32 +333,32 @@ out: // it returns JSON. The only option is optMonochrome func ungron(r io.Reader, w io.Writer, opts int) (int, error) { scanner := bufio.NewScanner(r) - var maker statementmaker + var maker internal.StatementMaker // Allow larger internal buffer of the scanner (min: 64KiB ~ max: 1MiB) scanner.Buffer(make([]byte, 64*1024), 1024*1024) if opts&optJSON > 0 { - maker = statementFromJSONSpec + maker = internal.StatementFromJSONSpec } else { - maker = statementFromStringMaker + maker = internal.StatementFromStringMaker } // Make a list of statements from the input - var ss statements + var ss internal.Statements for scanner.Scan() { s, err := maker(scanner.Text()) if err != nil { return exitParseStatements, err } - ss.add(s) + ss.Add(s) } if err := scanner.Err(); err != nil { return exitReadInput, fmt.Errorf("failed to read input statements") } // turn the statements into a single merged interface{} type - merged, err := ss.toInterface() + merged, err := ss.ToInterface() if err != nil { return exitParseStatements, err } @@ -433,31 +415,31 @@ func gronValues(r io.Reader, w io.Writer, opts int) (int, error) { scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { - s := statementFromString(scanner.Text()) + s := internal.StatementFromString(scanner.Text()) // strip off the leading 'json' bare key - if s[0].typ == typBare && s[0].text == "json" { + if s[0].Typ == internal.TypBare && s[0].Text == "json" { s = s[1:] } // strip off the leading dots - if s[0].typ == typDot || s[0].typ == typLBrace { + if s[0].Typ == internal.TypDot || s[0].Typ == internal.TypLBrace { s = s[1:] } for _, t := range s { - switch t.typ { - case typString: + switch t.Typ { + case internal.TypString: var text string - err := json.Unmarshal([]byte(t.text), &text) + err := json.Unmarshal([]byte(t.Text), &text) if err != nil { // just swallow errors and try to continue continue } fmt.Println(text) - case typNumber, typTrue, typFalse, typNull: - fmt.Println(t.text) + case internal.TypNumber, internal.TypTrue, internal.TypFalse, internal.TypNull: + fmt.Println(t.Text) default: // Nothing diff --git a/testdata/long-stream.json b/testdata/long-stream.json deleted file mode 100644 index 47b7db5..0000000 --- a/testdata/long-stream.json +++ /dev/null @@ -1 +0,0 @@ -{"details":[{"_id":"5ae0aa34b3f979b9b85509e0","index":0,"guid":"164542db-58d9-4d63-aacd-fbf3a7739474","isActive":true,"balance":"$2,644.04","picture":"http://placehold.it/32x32","age":38,"eyeColor":"blue","name":{"first":"Tracy","last":"Scott"},"company":"QUOTEZART","email":"tracy.scott@quotezart.io","phone":"+1 (998) 407-3468","address":"324 Cornelia Street, Echo, Indiana, 8046","about":"Nostrud magna ullamco id amet et incididunt officia dolor cillum do. Excepteur amet aliquip non veniam amet est nisi incididunt enim aliqua ad occaecat exercitation. Duis cupidatat ea voluptate consequat anim irure incididunt consequat consectetur amet. Enim exercitation ea eiusmod aliqua occaecat proident proident occaecat incididunt fugiat sint. Eu velit incididunt dolore voluptate in deserunt mollit officia.","registered":"Saturday, October 7, 2017 2:37 PM","latitude":"-19.206275","longitude":"-57.387994","tags":["quis","elit","minim","quis","ut","quis","et","laboris","et","quis"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Gwendolyn Barnett"},{"id":1,"name":"Hill Patrick"},{"id":2,"name":"Corinne Pearson"},{"id":3,"name":"Nona Walters"},{"id":4,"name":"Beach Hart"},{"id":5,"name":"Figueroa Russell"},{"id":6,"name":"Eve Cobb"},{"id":7,"name":"Sanchez Bradshaw"},{"id":8,"name":"Irma Turner"},{"id":9,"name":"Keisha Walls"}],"greeting":"Hello, Tracy! You have 10 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa342f534020c0f882a2","index":1,"guid":"e3ceb40a-9dbd-4769-96cd-283c227952d4","isActive":true,"balance":"$2,449.54","picture":"http://placehold.it/32x32","age":33,"eyeColor":"green","name":{"first":"Nora","last":"Gates"},"company":"ENTALITY","email":"nora.gates@entality.name","phone":"+1 (845) 592-3644","address":"904 Randolph Street, Cowiche, District Of Columbia, 6897","about":"Duis in mollit ex consectetur laboris commodo ad laboris do officia. Proident aute officia aliquip mollit incididunt amet est deserunt. Sunt magna ea sit reprehenderit. Enim et non excepteur dolor proident quis dolor ea. Non dolore tempor esse aliqua ipsum cupidatat quis cupidatat sint veniam pariatur.","registered":"Wednesday, September 3, 2014 5:55 PM","latitude":"-17.863169","longitude":"175.110579","tags":["sunt","ut","sint","labore","adipisicing","velit","esse","consectetur","enim","ad"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Meagan Daugherty"},{"id":1,"name":"Morin Delacruz"},{"id":2,"name":"Robin Blanchard"},{"id":3,"name":"Georgia Mays"},{"id":4,"name":"Cheri Soto"},{"id":5,"name":"Hobbs Lucas"},{"id":6,"name":"Maritza Garza"},{"id":7,"name":"Kathy Whitney"},{"id":8,"name":"Burch Cortez"},{"id":9,"name":"Jenny Campos"}],"greeting":"Hello, Nora! You have 10 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34866f48fd0a12505e","index":2,"guid":"ddcd3d1e-8706-48bf-9dea-554b69706120","isActive":false,"balance":"$3,999.63","picture":"http://placehold.it/32x32","age":20,"eyeColor":"green","name":{"first":"Beatrice","last":"Foley"},"company":"KANGLE","email":"beatrice.foley@kangle.biz","phone":"+1 (832) 487-2607","address":"813 Garden Place, Hackneyville, Kentucky, 4301","about":"Minim dolor eiusmod ipsum laborum proident. Ad cillum ullamco cupidatat dolor proident irure veniam proident nostrud. Enim non cillum nostrud tempor dolor id dolore laboris mollit non adipisicing. In dolore amet dolor incididunt non dolor magna pariatur anim exercitation eiusmod reprehenderit. Ex elit aute eiusmod ullamco amet consequat nostrud est. Ullamco cupidatat adipisicing amet commodo non ipsum aliqua esse excepteur reprehenderit irure quis consectetur enim. Eu aliqua occaecat do amet exercitation ad fugiat.","registered":"Thursday, August 27, 2015 6:31 PM","latitude":"-20.102055","longitude":"-159.81829","tags":["reprehenderit","et","magna","aliquip","sit","pariatur","amet","labore","Lorem","aute"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Lawrence Ratliff"},{"id":1,"name":"Debbie Kent"},{"id":2,"name":"Lynda Morse"},{"id":3,"name":"Wiley Stephenson"},{"id":4,"name":"Mclaughlin Hines"},{"id":5,"name":"Erin Ashley"},{"id":6,"name":"Boyer Dotson"},{"id":7,"name":"Decker Rollins"},{"id":8,"name":"Eddie Lane"},{"id":9,"name":"Cecile Lindsey"}],"greeting":"Hello, Beatrice! You have 7 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34dc3fbdc4ed72a342","index":3,"guid":"5dbc0677-c792-420e-b31e-2ba3e520b9bf","isActive":false,"balance":"$1,227.64","picture":"http://placehold.it/32x32","age":20,"eyeColor":"brown","name":{"first":"Sherrie","last":"Brock"},"company":"NAVIR","email":"sherrie.brock@navir.us","phone":"+1 (886) 472-3610","address":"916 Oakland Place, Rodman, Louisiana, 8864","about":"Eiusmod est minim ullamco minim tempor sunt. Do aliquip tempor et nisi aute do ullamco. Sint non mollit fugiat Lorem laboris pariatur et commodo labore et tempor. Non officia tempor cupidatat aute deserunt ea ut laboris consequat magna.","registered":"Saturday, November 12, 2016 3:31 AM","latitude":"54.818965","longitude":"117.261723","tags":["veniam","voluptate","esse","amet","deserunt","aute","elit","anim","est","excepteur"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Sofia Ray"},{"id":1,"name":"Ronda Bates"},{"id":2,"name":"Robert Blankenship"},{"id":3,"name":"Bowers Potts"},{"id":4,"name":"Holcomb Nieves"},{"id":5,"name":"Marquita Glover"},{"id":6,"name":"Manuela Rocha"},{"id":7,"name":"Carey Fitzpatrick"},{"id":8,"name":"Joann Singleton"},{"id":9,"name":"Vincent Johns"}],"greeting":"Hello, Sherrie! You have 8 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa348f55f735b48cfa46","index":4,"guid":"a1944b22-c22f-49a3-8ac4-45153a3d1de4","isActive":true,"balance":"$2,403.86","picture":"http://placehold.it/32x32","age":22,"eyeColor":"brown","name":{"first":"Stuart","last":"Mendoza"},"company":"SNOWPOKE","email":"stuart.mendoza@snowpoke.biz","phone":"+1 (940) 532-2198","address":"806 High Street, Dunnavant, Idaho, 5507","about":"Aute adipisicing deserunt et elit consequat deserunt amet amet officia aliqua in. Et qui minim ea sit exercitation aliquip do laborum consectetur voluptate eiusmod irure. Exercitation reprehenderit eiusmod proident fugiat laborum in aliqua laboris commodo sint et. Amet qui labore culpa excepteur magna voluptate anim mollit eiusmod. Officia mollit eu et laborum reprehenderit ullamco. Proident incididunt incididunt cillum laborum officia veniam aute voluptate officia irure elit.","registered":"Wednesday, November 12, 2014 9:10 AM","latitude":"-4.553307","longitude":"-92.981375","tags":["voluptate","fugiat","non","fugiat","cupidatat","deserunt","occaecat","dolor","aute","fugiat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Valeria Burgess"},{"id":1,"name":"Cleveland Noel"},{"id":2,"name":"Arline Oneill"},{"id":3,"name":"Tasha Johnston"},{"id":4,"name":"Graciela Mosley"},{"id":5,"name":"Bartlett Gonzales"},{"id":6,"name":"Darla Bond"},{"id":7,"name":"Gail Hatfield"},{"id":8,"name":"Cecilia Clay"},{"id":9,"name":"Keri May"}],"greeting":"Hello, Stuart! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa342f229045f41285f7","index":5,"guid":"a087b56e-cd7c-4832-9c07-ec80217d5355","isActive":false,"balance":"$3,736.67","picture":"http://placehold.it/32x32","age":27,"eyeColor":"blue","name":{"first":"Marjorie","last":"Cunningham"},"company":"IMMUNICS","email":"marjorie.cunningham@immunics.com","phone":"+1 (807) 427-2665","address":"649 Whitty Lane, Thatcher, Michigan, 9747","about":"Aliquip quis proident consequat magna id ullamco nulla culpa laborum. Quis laborum laborum adipisicing duis duis eu sint exercitation deserunt cillum ea. Incididunt laborum magna Lorem quis officia sint cillum commodo laboris exercitation proident proident. Sit sunt nostrud sint duis. Cillum minim cupidatat sunt ipsum eiusmod ipsum fugiat fugiat culpa consequat. Esse irure consectetur ad officia Lorem eu culpa est ad deserunt velit amet exercitation aute.","registered":"Tuesday, October 7, 2014 5:24 PM","latitude":"6.552001","longitude":"-139.202433","tags":["ipsum","est","officia","eiusmod","ea","fugiat","quis","voluptate","proident","dolor"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Glenna Beck"},{"id":1,"name":"Castaneda Spears"},{"id":2,"name":"Justice Michael"},{"id":3,"name":"Shelton Parsons"},{"id":4,"name":"Robertson Good"},{"id":5,"name":"Sheena Burch"},{"id":6,"name":"Tessa Miranda"},{"id":7,"name":"Perkins Barker"},{"id":8,"name":"Maribel Lester"},{"id":9,"name":"Hodge Cabrera"}],"greeting":"Hello, Marjorie! You have 9 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa3482a305f0781a3aba","index":6,"guid":"ccfdf87d-b381-4b64-b517-cd60a8fc9f04","isActive":false,"balance":"$2,116.04","picture":"http://placehold.it/32x32","age":21,"eyeColor":"green","name":{"first":"Yvonne","last":"Duffy"},"company":"KENEGY","email":"yvonne.duffy@kenegy.co.uk","phone":"+1 (956) 575-2780","address":"742 Bergen Court, Mahtowa, Alaska, 4598","about":"Anim nulla est eu laborum proident et. Sunt anim dolore voluptate non laboris sint mollit laborum exercitation enim aliqua exercitation. Veniam consectetur excepteur esse nostrud cupidatat aute nulla aute ad id mollit. Enim exercitation labore culpa voluptate in ea nulla nulla ex. Id tempor nisi ad proident dolore est cillum eiusmod dolor veniam consectetur labore. Mollit velit cupidatat est mollit adipisicing est exercitation. Veniam aliqua reprehenderit ea tempor.","registered":"Monday, December 8, 2014 2:57 AM","latitude":"23.863564","longitude":"150.896594","tags":["voluptate","ex","consequat","in","sit","nulla","commodo","adipisicing","nulla","commodo"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Clemons Snyder"},{"id":1,"name":"Bernard Navarro"},{"id":2,"name":"Burton Burnett"},{"id":3,"name":"Suzette Callahan"},{"id":4,"name":"William Hill"},{"id":5,"name":"Mays Larsen"},{"id":6,"name":"Joanna Graham"},{"id":7,"name":"Fowler Berry"},{"id":8,"name":"Lacey Hayden"},{"id":9,"name":"Shauna Frederick"}],"greeting":"Hello, Yvonne! You have 6 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa349dcd18765c1626dc","index":7,"guid":"425bc7f1-467f-4ed6-be2c-ccbcd9555674","isActive":false,"balance":"$3,403.00","picture":"http://placehold.it/32x32","age":33,"eyeColor":"blue","name":{"first":"Dana","last":"Reed"},"company":"NETPLAX","email":"dana.reed@netplax.ca","phone":"+1 (988) 463-2342","address":"980 Central Avenue, Strykersville, Maryland, 873","about":"Sunt nisi duis dolor cupidatat magna quis. Pariatur eu id commodo ea eiusmod dolore cillum veniam voluptate. Anim ex occaecat sit ipsum proident tempor quis ipsum laborum ad. Minim ut quis enim incididunt aliqua tempor. Ullamco exercitation consectetur quis fugiat cupidatat esse est consequat ad aliqua duis ea consectetur consequat. Id ea commodo minim aute.","registered":"Sunday, March 22, 2015 7:03 PM","latitude":"61.534583","longitude":"123.100188","tags":["non","elit","Lorem","commodo","enim","dolor","sint","qui","aliqua","cupidatat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Chan Keller"},{"id":1,"name":"Mary Dyer"},{"id":2,"name":"Genevieve Whitfield"},{"id":3,"name":"Meyers York"},{"id":4,"name":"James Carr"},{"id":5,"name":"Rollins Frazier"},{"id":6,"name":"Aurora Nguyen"},{"id":7,"name":"Shawn Jacobs"},{"id":8,"name":"Reba Mcfarland"},{"id":9,"name":"Paige Pitts"}],"greeting":"Hello, Dana! You have 9 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34d760d6da02fde756","index":8,"guid":"be208b32-be08-4c6d-86ea-da589d1ec977","isActive":false,"balance":"$1,012.38","picture":"http://placehold.it/32x32","age":23,"eyeColor":"brown","name":{"first":"Schmidt","last":"Sweeney"},"company":"PROWASTE","email":"schmidt.sweeney@prowaste.info","phone":"+1 (994) 493-3642","address":"245 Veterans Avenue, Catherine, Arkansas, 1444","about":"Voluptate ut deserunt nostrud nulla anim fugiat occaecat fugiat nisi anim commodo minim consequat. Tempor velit amet cillum aliquip nisi ut. Eu sunt excepteur amet dolor excepteur laborum. Enim minim elit irure proident pariatur ex nulla aute sunt.","registered":"Wednesday, April 6, 2016 12:10 PM","latitude":"22.555683","longitude":"63.232647","tags":["aute","deserunt","ad","sint","quis","tempor","sunt","consectetur","labore","Lorem"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Browning House"},{"id":1,"name":"Beverly Hoover"},{"id":2,"name":"Mitchell Figueroa"},{"id":3,"name":"Blackburn Camacho"},{"id":4,"name":"Leila Doyle"},{"id":5,"name":"Lee Montoya"},{"id":6,"name":"Beck Velasquez"},{"id":7,"name":"Charlotte Bird"},{"id":8,"name":"Lillie Velez"},{"id":9,"name":"Williamson Elliott"}],"greeting":"Hello, Schmidt! You have 6 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34a2574825a9fad671","index":9,"guid":"b3a104cf-4361-421c-9e13-91ae146e517d","isActive":true,"balance":"$1,454.62","picture":"http://placehold.it/32x32","age":38,"eyeColor":"blue","name":{"first":"Davenport","last":"Marquez"},"company":"MUSANPOLY","email":"davenport.marquez@musanpoly.me","phone":"+1 (843) 438-2469","address":"109 Victor Road, Fruitdale, American Samoa, 8856","about":"Culpa aliquip Lorem elit laborum aliquip laboris dolore non ea. Est occaecat do minim pariatur pariatur mollit velit laborum eu consectetur qui eiusmod. Consectetur nostrud occaecat dolore sunt mollit. Anim excepteur et nulla consequat laborum dolor Lorem ad.","registered":"Sunday, February 16, 2014 11:28 PM","latitude":"5.32883","longitude":"-128.790048","tags":["veniam","cillum","non","qui","ullamco","quis","consequat","incididunt","laborum","deserunt"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Beard Gomez"},{"id":1,"name":"Elaine Lamb"},{"id":2,"name":"Gallegos Merritt"},{"id":3,"name":"Margarita Shepherd"},{"id":4,"name":"Mia Griffin"},{"id":5,"name":"Deena Foreman"},{"id":6,"name":"Muriel Howe"},{"id":7,"name":"Wilder Chang"},{"id":8,"name":"Pearlie Ford"},{"id":9,"name":"Tabatha Mathews"}],"greeting":"Hello, Davenport! You have 10 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34ce8ffcd27683f469","index":10,"guid":"d6d9c317-c71c-48ff-a522-905d54cef18b","isActive":true,"balance":"$2,197.16","picture":"http://placehold.it/32x32","age":39,"eyeColor":"green","name":{"first":"Julianne","last":"Miles"},"company":"EXIAND","email":"julianne.miles@exiand.org","phone":"+1 (981) 429-3214","address":"560 Louis Place, Sperryville, Vermont, 7450","about":"Aute irure Lorem laborum cillum Lorem ad dolore proident tempor in non. Excepteur fugiat amet proident ut exercitation adipisicing cupidatat esse. Occaecat cillum labore dolore cupidatat consectetur est exercitation mollit dolor dolore.","registered":"Wednesday, June 14, 2017 11:19 AM","latitude":"-32.254528","longitude":"-97.815247","tags":["consectetur","cupidatat","est","esse","anim","et","tempor","et","ex","fugiat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Trevino Nash"},{"id":1,"name":"Mills Conley"},{"id":2,"name":"Deirdre Cruz"},{"id":3,"name":"Marsh Webster"},{"id":4,"name":"Frye Johnson"},{"id":5,"name":"Jeanine Craft"},{"id":6,"name":"Fern Richmond"},{"id":7,"name":"Janelle Ramsey"},{"id":8,"name":"Kirby Valentine"},{"id":9,"name":"Lessie Acevedo"}],"greeting":"Hello, Julianne! You have 8 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34d5b29d6058c2450f","index":11,"guid":"925f4c31-5a6b-4cf2-b90d-fb0ee37680a6","isActive":false,"balance":"$1,111.42","picture":"http://placehold.it/32x32","age":34,"eyeColor":"blue","name":{"first":"Elva","last":"Woods"},"company":"MAXIMIND","email":"elva.woods@maximind.tv","phone":"+1 (883) 569-3812","address":"540 Trucklemans Lane, Stollings, Oregon, 2549","about":"Consequat ut deserunt in esse do nisi. Aliquip laboris ex nulla excepteur occaecat et nulla. Incididunt enim irure officia ex aute nulla est consectetur aute eiusmod. Ea ipsum magna nisi quis ex labore qui occaecat eu aute culpa adipisicing aute cupidatat. Consequat mollit dolore ex deserunt. Deserunt do eiusmod Lorem anim laborum dolor esse aute laboris dolor officia esse officia. Cupidatat consectetur veniam ipsum et mollit cupidatat ullamco et non officia exercitation nisi ea.","registered":"Saturday, July 25, 2015 1:20 PM","latitude":"-14.967803","longitude":"160.339242","tags":["incididunt","nulla","aliquip","et","quis","voluptate","aliqua","qui","in","ea"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Compton Holt"},{"id":1,"name":"Christy Padilla"},{"id":2,"name":"Roy Boyer"},{"id":3,"name":"Celina Wright"},{"id":4,"name":"Patton Fowler"},{"id":5,"name":"Juanita Blair"},{"id":6,"name":"Thornton Townsend"},{"id":7,"name":"Mcintyre William"},{"id":8,"name":"Lorena Mckee"},{"id":9,"name":"Alisha Mullen"}],"greeting":"Hello, Elva! You have 10 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34040ef52f7d92ee6a","index":12,"guid":"9ccba22d-2de3-4784-b291-93a18c017a82","isActive":false,"balance":"$1,147.66","picture":"http://placehold.it/32x32","age":26,"eyeColor":"green","name":{"first":"Lizzie","last":"Melton"},"company":"FUTURITY","email":"lizzie.melton@futurity.io","phone":"+1 (875) 595-2680","address":"584 Indiana Place, Blue, New Jersey, 420","about":"Culpa culpa irure duis fugiat magna cillum ut aliqua incididunt. Deserunt nostrud cillum duis reprehenderit ad duis voluptate dolore. Elit officia ullamco minim nisi officia eu eu Lorem sint. Est aute quis occaecat sunt. Excepteur minim commodo exercitation consectetur eiusmod aute elit proident nulla enim ullamco enim. Tempor labore duis ex cupidatat et.","registered":"Friday, October 17, 2014 2:39 PM","latitude":"-52.473183","longitude":"111.529289","tags":["enim","ut","ullamco","tempor","commodo","esse","nisi","eiusmod","exercitation","sit"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Sasha Porter"},{"id":1,"name":"Pittman Wilkerson"},{"id":2,"name":"Lloyd Carter"},{"id":3,"name":"Mathews Armstrong"},{"id":4,"name":"Geraldine Harrison"},{"id":5,"name":"Margo Giles"},{"id":6,"name":"Ewing Pollard"},{"id":7,"name":"Esperanza Simon"},{"id":8,"name":"Christa Wiggins"},{"id":9,"name":"Lorraine Wilkinson"}],"greeting":"Hello, Lizzie! You have 9 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa3468cb0abe9cf31577","index":13,"guid":"3a1566ab-fb93-417b-8c4f-ead8269d6cc8","isActive":false,"balance":"$1,824.72","picture":"http://placehold.it/32x32","age":22,"eyeColor":"blue","name":{"first":"Ford","last":"Randolph"},"company":"INSECTUS","email":"ford.randolph@insectus.name","phone":"+1 (982) 589-2146","address":"231 Centre Street, Coalmont, Washington, 5554","about":"Commodo consequat occaecat ad ea ut id reprehenderit laborum elit ullamco magna. Non aliquip nisi fugiat anim veniam consequat eu qui esse sint magna. Cupidatat officia sunt mollit irure sit nulla excepteur dolor nulla. Fugiat elit deserunt mollit est fugiat laborum magna sint ullamco et in. Commodo voluptate aliqua sit dolore ut excepteur laborum qui dolore.","registered":"Friday, February 28, 2014 9:04 PM","latitude":"-85.796706","longitude":"82.662603","tags":["amet","exercitation","proident","do","incididunt","nisi","sunt","ullamco","commodo","reprehenderit"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Delaney Knowles"},{"id":1,"name":"Simone Nichols"},{"id":2,"name":"Tate Brewer"},{"id":3,"name":"Madeline Paul"},{"id":4,"name":"Jeanette Roberson"},{"id":5,"name":"Sallie Holden"},{"id":6,"name":"Clements Hinton"},{"id":7,"name":"Lourdes Tyler"},{"id":8,"name":"Aline Davidson"},{"id":9,"name":"Tia Collier"}],"greeting":"Hello, Ford! You have 9 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34d4c1ab9766cdd713","index":14,"guid":"0665f792-8282-4efd-b409-9c791ecb1091","isActive":true,"balance":"$2,174.56","picture":"http://placehold.it/32x32","age":35,"eyeColor":"brown","name":{"first":"Grace","last":"Fuentes"},"company":"ZINCA","email":"grace.fuentes@zinca.biz","phone":"+1 (802) 553-2237","address":"166 Sackman Street, Brownsville, Utah, 7296","about":"Lorem incididunt deserunt dolor nulla. Minim sit eu do commodo. Sint aliqua et exercitation duis Lorem laborum irure enim quis pariatur laboris incididunt veniam magna. Ea labore eiusmod incididunt fugiat. Sunt cillum nisi culpa Lorem aliqua nostrud quis dolore incididunt nostrud amet anim cupidatat. Ex pariatur enim esse sunt eiusmod. Aliquip consectetur reprehenderit nisi labore eu nostrud sint consectetur.","registered":"Friday, December 18, 2015 11:18 PM","latitude":"-66.13255","longitude":"179.72211","tags":["ea","sunt","elit","Lorem","nisi","aute","do","fugiat","in","fugiat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Dixon Fletcher"},{"id":1,"name":"Lambert Ingram"},{"id":2,"name":"Mendez Pate"},{"id":3,"name":"Ray Ward"},{"id":4,"name":"Heidi Cardenas"},{"id":5,"name":"Barton Meyer"},{"id":6,"name":"Velma Park"},{"id":7,"name":"Patricia Lynch"},{"id":8,"name":"Eugenia Grant"},{"id":9,"name":"York Sloan"}],"greeting":"Hello, Grace! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa343b56f5acad827190","index":15,"guid":"4c8eb809-8024-490f-b95a-0cace6949320","isActive":true,"balance":"$2,489.41","picture":"http://placehold.it/32x32","age":33,"eyeColor":"green","name":{"first":"Laurel","last":"Contreras"},"company":"DOGNOSIS","email":"laurel.contreras@dognosis.us","phone":"+1 (917) 546-3266","address":"147 Strong Place, Hayes, New Mexico, 2530","about":"Cupidatat nisi quis irure nostrud labore eu et voluptate. Nisi eiusmod enim dolor cillum. Ea dolor et ea adipisicing minim pariatur ea ad minim ad eu amet ea.","registered":"Saturday, December 24, 2016 9:20 AM","latitude":"-54.412123","longitude":"-169.324571","tags":["reprehenderit","quis","irure","dolor","do","adipisicing","veniam","in","aliqua","ipsum"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Laurie Becker"},{"id":1,"name":"Butler Coffey"},{"id":2,"name":"Ruthie Benjamin"},{"id":3,"name":"Jean Lee"},{"id":4,"name":"Lowe Warren"},{"id":5,"name":"Zelma Hudson"},{"id":6,"name":"Wiggins Schwartz"},{"id":7,"name":"Brewer Goodman"},{"id":8,"name":"Melanie Haney"},{"id":9,"name":"Alyson Brooks"}],"greeting":"Hello, Laurel! You have 10 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa3405bf5c4f96c29069","index":16,"guid":"e218adf6-22b7-4e1e-a6f4-31234460fd8e","isActive":true,"balance":"$1,324.19","picture":"http://placehold.it/32x32","age":31,"eyeColor":"green","name":{"first":"Ginger","last":"Pennington"},"company":"CYTREX","email":"ginger.pennington@cytrex.biz","phone":"+1 (827) 512-3179","address":"726 Lake Street, Shindler, Nevada, 4750","about":"Deserunt elit et labore minim officia cupidatat exercitation esse adipisicing enim amet culpa in adipisicing. Amet eiusmod velit amet laboris deserunt minim. Anim duis deserunt proident ex consequat incididunt commodo sint excepteur Lorem proident esse duis. Ad adipisicing veniam anim Lorem sit eu laboris ex nostrud qui nostrud ipsum. Labore exercitation excepteur voluptate aliqua labore anim id fugiat.","registered":"Saturday, December 9, 2017 10:11 AM","latitude":"14.567831","longitude":"66.731219","tags":["incididunt","dolor","commodo","eiusmod","est","est","sint","ad","ut","minim"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Iva Guerrero"},{"id":1,"name":"Cathleen Young"},{"id":2,"name":"Welch Pierce"},{"id":3,"name":"Tyson Raymond"},{"id":4,"name":"Josefa Crawford"},{"id":5,"name":"Cross Burks"},{"id":6,"name":"Crosby Brady"},{"id":7,"name":"Barry Guthrie"},{"id":8,"name":"Margret Duran"},{"id":9,"name":"Reilly Patton"}],"greeting":"Hello, Ginger! You have 7 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa343537eccc1ace3207","index":17,"guid":"7e65b665-28a9-4499-81c0-c1d9042bebdf","isActive":false,"balance":"$3,776.91","picture":"http://placehold.it/32x32","age":36,"eyeColor":"green","name":{"first":"Mckenzie","last":"Chan"},"company":"ENDIPIN","email":"mckenzie.chan@endipin.com","phone":"+1 (824) 566-2134","address":"448 Terrace Place, Cetronia, Puerto Rico, 9914","about":"Deserunt elit nostrud cupidatat labore deserunt cupidatat ea cupidatat consectetur. Labore est velit duis voluptate occaecat quis veniam nostrud incididunt proident minim elit. Nulla velit elit tempor occaecat cillum adipisicing exercitation exercitation id incididunt officia ipsum fugiat sunt. Aliqua pariatur reprehenderit in aliqua esse do quis aliquip. Proident exercitation ullamco nisi id minim id cillum eiusmod mollit ea Lorem. Laborum sit exercitation exercitation Lorem eiusmod ad laborum nisi ex id non.","registered":"Friday, June 23, 2017 11:32 AM","latitude":"-13.394667","longitude":"-158.627154","tags":["ut","quis","laboris","ea","esse","non","do","irure","ea","excepteur"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Woodward Little"},{"id":1,"name":"Patty Gamble"},{"id":2,"name":"Erickson Macias"},{"id":3,"name":"Tanya Pace"},{"id":4,"name":"Hunt Tate"},{"id":5,"name":"Maricela Crane"},{"id":6,"name":"Hanson Rodriguez"},{"id":7,"name":"Goodman Austin"},{"id":8,"name":"Short Donovan"},{"id":9,"name":"Blanche England"}],"greeting":"Hello, Mckenzie! You have 8 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa34290ac8fa63a12eac","index":18,"guid":"547f7c12-6dc2-46bd-ba15-29730366275d","isActive":true,"balance":"$2,585.89","picture":"http://placehold.it/32x32","age":27,"eyeColor":"green","name":{"first":"Frazier","last":"Pickett"},"company":"GRUPOLI","email":"frazier.pickett@grupoli.co.uk","phone":"+1 (897) 581-2849","address":"678 Newton Street, Chelsea, Ohio, 490","about":"Ex non cupidatat non cupidatat enim sint occaecat ut incididunt irure nulla. Ex id culpa voluptate id do id exercitation sit mollit esse id excepteur eu duis. Minim est veniam laboris irure ut minim consectetur fugiat enim ullamco minim. Sint mollit ullamco dolore consequat ipsum eu cillum. Et consectetur elit est sit aliquip et non occaecat.","registered":"Wednesday, March 29, 2017 7:15 PM","latitude":"1.80887","longitude":"28.819849","tags":["tempor","veniam","elit","mollit","aliquip","magna","laboris","labore","anim","proident"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Mcconnell Mccall"},{"id":1,"name":"Harper Fields"},{"id":2,"name":"Kathryn Schultz"},{"id":3,"name":"Campos Hensley"},{"id":4,"name":"Landry Owen"},{"id":5,"name":"Perez Greer"},{"id":6,"name":"Maldonado Bartlett"},{"id":7,"name":"Hendrix Stein"},{"id":8,"name":"Delgado Wade"},{"id":9,"name":"Rene Wallace"}],"greeting":"Hello, Frazier! You have 5 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34e17d55284d96d1f5","index":19,"guid":"c7255282-e5a6-4b8b-af24-3b637fd9b044","isActive":false,"balance":"$1,869.10","picture":"http://placehold.it/32x32","age":25,"eyeColor":"blue","name":{"first":"Ochoa","last":"Madden"},"company":"INSURITY","email":"ochoa.madden@insurity.ca","phone":"+1 (934) 422-2951","address":"422 Emerald Street, Sugartown, North Carolina, 2526","about":"Dolor est aliquip pariatur sunt irure deserunt pariatur excepteur do do. Nisi nostrud esse ullamco duis fugiat aliquip cillum. Sint pariatur occaecat ex id aliqua.","registered":"Friday, February 2, 2018 8:53 PM","latitude":"-67.260494","longitude":"76.369882","tags":["aute","minim","commodo","non","ex","qui","ut","veniam","commodo","aliquip"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Lilia Schroeder"},{"id":1,"name":"Amber Meyers"},{"id":2,"name":"Janette Richards"},{"id":3,"name":"Lucinda Key"},{"id":4,"name":"Kristine Freeman"},{"id":5,"name":"Tillman Horne"},{"id":6,"name":"Cervantes Rosario"},{"id":7,"name":"Kerr Mcdonald"},{"id":8,"name":"Dionne Hancock"},{"id":9,"name":"Huber Hester"}],"greeting":"Hello, Ochoa! You have 6 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa3473ba36f5b47cb4fe","index":20,"guid":"9019a995-b226-4d0e-8dbc-c6dc102d3bcc","isActive":true,"balance":"$1,109.74","picture":"http://placehold.it/32x32","age":27,"eyeColor":"green","name":{"first":"Janie","last":"Hendricks"},"company":"TELEQUIET","email":"janie.hendricks@telequiet.info","phone":"+1 (830) 552-3242","address":"302 Dunham Place, Cataract, South Dakota, 2071","about":"Ea et eiusmod adipisicing labore minim. Veniam nostrud non esse non adipisicing aliquip exercitation incididunt laboris velit occaecat Lorem nisi. Veniam adipisicing veniam magna nulla qui in irure culpa. Sint est aute anim sit magna velit nulla labore eu. Mollit duis amet ea culpa amet exercitation officia. Exercitation pariatur deserunt consequat magna enim occaecat mollit sunt incididunt. Fugiat id non veniam elit in ipsum duis exercitation Lorem non culpa in occaecat.","registered":"Monday, February 29, 2016 4:08 PM","latitude":"52.718238","longitude":"-107.958872","tags":["nulla","aliquip","aliquip","reprehenderit","laboris","non","exercitation","anim","nisi","eiusmod"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Diann Robertson"},{"id":1,"name":"Forbes Molina"},{"id":2,"name":"Phelps Medina"},{"id":3,"name":"Billie James"},{"id":4,"name":"Addie Roach"},{"id":5,"name":"Vickie Petersen"},{"id":6,"name":"Navarro Sanford"},{"id":7,"name":"Mclean Sampson"},{"id":8,"name":"Barlow Bolton"},{"id":9,"name":"Nicholson Zamora"}],"greeting":"Hello, Janie! You have 5 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa3485ccf4bd0ca5238a","index":21,"guid":"ca0b5dc7-21a3-4edb-849e-1d6d81c57f8a","isActive":false,"balance":"$3,102.46","picture":"http://placehold.it/32x32","age":28,"eyeColor":"blue","name":{"first":"Good","last":"Hays"},"company":"GYNKO","email":"good.hays@gynko.me","phone":"+1 (936) 448-2745","address":"538 Lott Place, Rivera, Pennsylvania, 7526","about":"Aliqua veniam aliqua adipisicing aliquip sit aute commodo. Fugiat ut esse laboris duis nisi ipsum ea dolor labore sit pariatur laborum officia. Ipsum ad do tempor nostrud in irure enim ad amet ex id. Nostrud dolore voluptate nulla cupidatat laboris minim.","registered":"Friday, December 9, 2016 10:14 AM","latitude":"-26.185693","longitude":"68.079701","tags":["laborum","dolor","cillum","dolor","duis","in","veniam","enim","aliquip","incididunt"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Erika Dalton"},{"id":1,"name":"Josie Cole"},{"id":2,"name":"Katelyn Dominguez"},{"id":3,"name":"Jasmine Mathis"},{"id":4,"name":"Phoebe Reynolds"},{"id":5,"name":"Bishop Barr"},{"id":6,"name":"Morton Flynn"},{"id":7,"name":"Brock Berger"},{"id":8,"name":"Dominique Obrien"},{"id":9,"name":"Ayers Garrison"}],"greeting":"Hello, Good! You have 10 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa348b68911a5e827ca8","index":22,"guid":"e0df62b2-c28f-40bb-a00e-f95a667b3fa0","isActive":true,"balance":"$3,544.61","picture":"http://placehold.it/32x32","age":31,"eyeColor":"brown","name":{"first":"Golden","last":"Reid"},"company":"KIDGREASE","email":"golden.reid@kidgrease.org","phone":"+1 (882) 440-2209","address":"952 Holly Street, Monument, Minnesota, 7297","about":"Exercitation esse ullamco do ullamco aliquip eiusmod adipisicing proident. Labore do cupidatat in irure proident. Mollit velit fugiat voluptate aliqua qui voluptate laboris aliqua minim laborum sunt amet. Consequat magna duis commodo ea cupidatat ea culpa eiusmod ut cillum ut eu velit aute. Laboris amet ea irure fugiat nisi amet commodo labore officia excepteur dolor tempor mollit magna. Non consequat dolor reprehenderit ullamco dolor tempor quis voluptate magna ad reprehenderit adipisicing incididunt. Velit laboris elit esse nulla quis.","registered":"Monday, February 24, 2014 11:59 AM","latitude":"30.725621","longitude":"-158.551407","tags":["sit","pariatur","nulla","quis","nisi","ea","qui","deserunt","officia","aliquip"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Bradshaw Gilmore"},{"id":1,"name":"Pugh Munoz"},{"id":2,"name":"Nunez Hawkins"},{"id":3,"name":"Julia Washington"},{"id":4,"name":"Rivers Webb"},{"id":5,"name":"Tara Summers"},{"id":6,"name":"Cheryl Odonnell"},{"id":7,"name":"Theresa Williamson"},{"id":8,"name":"Lesley Duke"},{"id":9,"name":"Snyder Bush"}],"greeting":"Hello, Golden! You have 6 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34fc10000370445e6f","index":23,"guid":"22bcb41a-1eb7-458b-80e7-7428f316d8f9","isActive":false,"balance":"$1,233.98","picture":"http://placehold.it/32x32","age":25,"eyeColor":"green","name":{"first":"Green","last":"Mcknight"},"company":"BESTO","email":"green.mcknight@besto.tv","phone":"+1 (817) 590-3548","address":"672 Montauk Court, Grahamtown, Florida, 6020","about":"Non commodo non nisi cillum fugiat. Quis ad fugiat eu ad consequat veniam adipisicing dolor. Non aliqua nulla Lorem id culpa anim veniam. Aliqua ea et eiusmod minim ut. Id ullamco qui sit aute reprehenderit nulla fugiat velit magna nisi eiusmod sit minim.","registered":"Saturday, February 10, 2018 8:53 AM","latitude":"52.299418","longitude":"21.885332","tags":["incididunt","quis","ea","cupidatat","quis","irure","qui","tempor","voluptate","et"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Mercedes Lowe"},{"id":1,"name":"Chen Perry"},{"id":2,"name":"Maxine Price"},{"id":3,"name":"Bryant Koch"},{"id":4,"name":"Benita Adams"},{"id":5,"name":"Clara Winters"},{"id":6,"name":"Alta Cantu"},{"id":7,"name":"Freida Petty"},{"id":8,"name":"Kimberly Bender"},{"id":9,"name":"Mccormick Roberts"}],"greeting":"Hello, Green! You have 8 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa3489c9bb951ae47da8","index":24,"guid":"22a0295f-7b80-4f06-9fc3-be1cdc79bdfb","isActive":false,"balance":"$2,006.10","picture":"http://placehold.it/32x32","age":35,"eyeColor":"brown","name":{"first":"Hilda","last":"Finch"},"company":"CODAX","email":"hilda.finch@codax.io","phone":"+1 (827) 575-2563","address":"395 Seaview Avenue, Hemlock, Connecticut, 5299","about":"Quis ex cillum ipsum id. Lorem ea velit minim ipsum ipsum irure excepteur nisi culpa officia dolore aliqua dolor deserunt. Et esse aliquip ex enim nisi excepteur mollit tempor non tempor in eu.","registered":"Tuesday, October 24, 2017 6:47 PM","latitude":"-50.758977","longitude":"-133.236945","tags":["et","cillum","elit","aliquip","amet","quis","enim","dolor","eiusmod","adipisicing"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Erma Robbins"},{"id":1,"name":"Gwen Evans"},{"id":2,"name":"Connie Cummings"},{"id":3,"name":"Bonnie Valenzuela"},{"id":4,"name":"Martin Bradford"},{"id":5,"name":"Mcmahon Long"},{"id":6,"name":"Trisha Vaughan"},{"id":7,"name":"Allison West"},{"id":8,"name":"Chapman Olsen"},{"id":9,"name":"Minerva Reeves"}],"greeting":"Hello, Hilda! You have 7 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa340fc9dc39242531ff","index":25,"guid":"3d78eba2-0b29-46e1-8119-b2b170f4be97","isActive":true,"balance":"$2,534.73","picture":"http://placehold.it/32x32","age":21,"eyeColor":"blue","name":{"first":"Cora","last":"Franco"},"company":"ENTHAZE","email":"cora.franco@enthaze.name","phone":"+1 (916) 530-2675","address":"217 Beaver Street, Bergoo, Montana, 7013","about":"Amet anim ipsum velit anim magna incididunt proident excepteur laborum ut voluptate voluptate ex cillum. Labore ea amet eu exercitation excepteur magna ex cupidatat laborum. Nisi ipsum id ex reprehenderit eu enim reprehenderit adipisicing. Ullamco eu sint anim et aute. Laborum sit duis quis sit non duis. Enim minim irure laboris veniam incididunt sint cupidatat.","registered":"Thursday, July 16, 2015 4:42 PM","latitude":"-26.445079","longitude":"77.502053","tags":["id","culpa","consequat","deserunt","velit","sint","dolor","ad","nulla","do"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Barnett Jacobson"},{"id":1,"name":"Lynn Mcpherson"},{"id":2,"name":"Beverley Phelps"},{"id":3,"name":"Aguilar Valdez"},{"id":4,"name":"Sweeney Sandoval"},{"id":5,"name":"Potts Allison"},{"id":6,"name":"Chavez Norman"},{"id":7,"name":"Katherine Torres"},{"id":8,"name":"Kelli Russo"},{"id":9,"name":"Joni Rojas"}],"greeting":"Hello, Cora! You have 9 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa34a34dd832ac2eda38","index":26,"guid":"3ac7f2d1-cbc7-404b-915b-9984bc0947bb","isActive":true,"balance":"$3,667.55","picture":"http://placehold.it/32x32","age":29,"eyeColor":"green","name":{"first":"Faye","last":"Guzman"},"company":"CIPROMOX","email":"faye.guzman@cipromox.biz","phone":"+1 (912) 528-3635","address":"633 Livonia Avenue, Gracey, Mississippi, 9805","about":"Id ea duis velit enim qui esse non sunt. Est ad laboris proident et consequat exercitation. Aliquip do exercitation ea officia mollit dolore. Sit ullamco anim anim minim cillum pariatur officia. Exercitation velit ullamco ullamco sint amet voluptate commodo nulla ipsum qui. Elit cillum mollit ut nulla aute aliquip anim consequat ipsum Lorem sunt nisi nisi est.","registered":"Thursday, February 4, 2016 12:04 AM","latitude":"-23.278189","longitude":"-136.239491","tags":["culpa","consequat","Lorem","eiusmod","deserunt","officia","elit","cillum","aliquip","ex"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Cassandra Forbes"},{"id":1,"name":"Poole Mueller"},{"id":2,"name":"Danielle Espinoza"},{"id":3,"name":"Gentry Leach"},{"id":4,"name":"Allen Berg"},{"id":5,"name":"Rhea Fitzgerald"},{"id":6,"name":"Blair Arnold"},{"id":7,"name":"Felicia Fulton"},{"id":8,"name":"Karla Rodgers"},{"id":9,"name":"Alyssa Mcfadden"}],"greeting":"Hello, Faye! You have 5 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34e0f6838816113db8","index":27,"guid":"ca5a4646-8edc-4443-91cf-c5dc73927e7a","isActive":false,"balance":"$3,344.58","picture":"http://placehold.it/32x32","age":32,"eyeColor":"brown","name":{"first":"Ryan","last":"Mcintyre"},"company":"STOCKPOST","email":"ryan.mcintyre@stockpost.us","phone":"+1 (872) 474-3518","address":"272 Barwell Terrace, Tedrow, Hawaii, 5053","about":"Incididunt incididunt commodo nulla eiusmod ullamco velit ipsum ad minim non magna culpa laborum. Exercitation ipsum culpa sint in ipsum qui exercitation eiusmod nulla ex. Magna ex eu officia magna esse. Irure dolore anim aute anim tempor nulla adipisicing culpa culpa voluptate ullamco commodo. Adipisicing pariatur excepteur ad reprehenderit reprehenderit dolor magna velit est. Fugiat laboris laborum in et consectetur laborum elit adipisicing.","registered":"Saturday, April 11, 2015 11:23 PM","latitude":"76.874677","longitude":"94.777546","tags":["id","veniam","ad","do","commodo","amet","tempor","sunt","ullamco","laborum"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Vera Olson"},{"id":1,"name":"West Daniel"},{"id":2,"name":"Socorro Manning"},{"id":3,"name":"Louise Haynes"},{"id":4,"name":"Lela Mann"},{"id":5,"name":"Spence Lyons"},{"id":6,"name":"Wynn Gillespie"},{"id":7,"name":"Lynch Jones"},{"id":8,"name":"Patrica Carlson"},{"id":9,"name":"Marietta Hickman"}],"greeting":"Hello, Ryan! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa344299323300eee507","index":28,"guid":"58a7ace0-c6be-4581-bee8-74a5d60398f7","isActive":false,"balance":"$3,743.38","picture":"http://placehold.it/32x32","age":27,"eyeColor":"blue","name":{"first":"Mcgowan","last":"Mcgowan"},"company":"QUINTITY","email":"mcgowan.mcgowan@quintity.biz","phone":"+1 (881) 485-2266","address":"822 Ridge Court, Somerset, Rhode Island, 458","about":"Laboris in velit voluptate amet cupidatat sit. Ea culpa cupidatat in dolor aute ex dolor ut dolore aliqua aliquip cillum. Ipsum laboris sint dolor esse deserunt amet exercitation sunt mollit.","registered":"Tuesday, June 28, 2016 6:36 AM","latitude":"-25.599677","longitude":"84.225442","tags":["nostrud","consectetur","labore","ex","anim","fugiat","nostrud","sunt","deserunt","in"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Steele Riggs"},{"id":1,"name":"Carmella Moran"},{"id":2,"name":"Allyson Blake"},{"id":3,"name":"Carol Cooke"},{"id":4,"name":"Heath Knight"},{"id":5,"name":"Ware Oconnor"},{"id":6,"name":"Osborne Jackson"},{"id":7,"name":"Lilian Burns"},{"id":8,"name":"Mallory Chen"},{"id":9,"name":"Liza Nunez"}],"greeting":"Hello, Mcgowan! You have 10 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34ad8457b4672e26a6","index":29,"guid":"af06ab7e-2514-4610-805b-9ef1ab10d1b6","isActive":false,"balance":"$2,641.66","picture":"http://placehold.it/32x32","age":40,"eyeColor":"green","name":{"first":"Cathryn","last":"Norris"},"company":"CUIZINE","email":"cathryn.norris@cuizine.com","phone":"+1 (886) 433-3723","address":"631 Hinsdale Street, Edmund, Texas, 818","about":"Enim consectetur eu nulla aliqua enim deserunt veniam deserunt. Commodo dolor anim aliqua anim cupidatat incididunt ex. Consequat qui ex dolor do do ullamco officia laboris ipsum. Sit sunt officia dolore ut dolore veniam dolor Lorem dolor do et qui velit pariatur. Nisi eiusmod ut do duis Lorem cillum do cillum amet dolore. Qui esse officia veniam incididunt consectetur id nostrud deserunt dolor adipisicing ipsum aliquip occaecat. Cillum aliquip sint eu minim aliquip nostrud eiusmod ullamco esse mollit sit amet amet ipsum.","registered":"Wednesday, July 5, 2017 9:58 PM","latitude":"-54.903831","longitude":"-75.383676","tags":["non","minim","fugiat","sint","deserunt","quis","fugiat","do","deserunt","occaecat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Hale Wiley"},{"id":1,"name":"Clarice Holcomb"},{"id":2,"name":"Arlene Rowland"},{"id":3,"name":"Mckee Craig"},{"id":4,"name":"Leann Mullins"},{"id":5,"name":"Lydia Carpenter"},{"id":6,"name":"Franklin Bishop"},{"id":7,"name":"Meadows Rice"},{"id":8,"name":"Lee Bullock"},{"id":9,"name":"Moon Vance"}],"greeting":"Hello, Cathryn! You have 8 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa3438902775803a72d7","index":30,"guid":"0433ad5c-c75b-4e57-b81b-d6f7b4c6ce23","isActive":true,"balance":"$1,413.96","picture":"http://placehold.it/32x32","age":35,"eyeColor":"green","name":{"first":"Gladys","last":"Luna"},"company":"VORTEXACO","email":"gladys.luna@vortexaco.co.uk","phone":"+1 (841) 419-2692","address":"710 Grove Place, Gouglersville, North Dakota, 7911","about":"Adipisicing excepteur incididunt eu ullamco in tempor. Fugiat aute ex veniam culpa labore quis anim magna. Aliqua exercitation culpa cupidatat do ullamco nostrud id. Dolore nisi laborum ullamco fugiat eiusmod laboris exercitation dolore magna id ipsum. Non velit commodo amet fugiat esse cillum tempor ex esse et aliquip ipsum nostrud. Consectetur adipisicing nisi voluptate exercitation amet. Incididunt fugiat dolore elit consequat laboris sunt culpa quis ullamco occaecat consequat enim.","registered":"Thursday, February 25, 2016 1:35 AM","latitude":"-17.405117","longitude":"-94.797563","tags":["ullamco","cupidatat","consectetur","sit","sit","incididunt","voluptate","eu","occaecat","commodo"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Jill Black"},{"id":1,"name":"Myra Wilcox"},{"id":2,"name":"Rojas Mcintosh"},{"id":3,"name":"Duffy Tyson"},{"id":4,"name":"Nettie Payne"},{"id":5,"name":"Pam Avery"},{"id":6,"name":"Guerrero Drake"},{"id":7,"name":"Dunlap Fuller"},{"id":8,"name":"Mercer Hopper"},{"id":9,"name":"Mayra Ramos"}],"greeting":"Hello, Gladys! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34fab19bc37260045d","index":31,"guid":"fbd1f589-514f-4124-a008-6fafdfceebca","isActive":false,"balance":"$2,778.78","picture":"http://placehold.it/32x32","age":29,"eyeColor":"blue","name":{"first":"Mildred","last":"Farrell"},"company":"GLEAMINK","email":"mildred.farrell@gleamink.ca","phone":"+1 (979) 492-2298","address":"285 Lewis Avenue, Toftrees, West Virginia, 2663","about":"Lorem ut incididunt Lorem commodo ipsum nisi sunt consequat officia sit nulla labore nostrud labore. Culpa cupidatat id proident nostrud dolor officia ullamco non veniam. Laborum exercitation amet amet sint. Excepteur excepteur dolor irure laborum. Commodo ut minim incididunt tempor officia consequat occaecat.","registered":"Monday, July 11, 2016 4:58 PM","latitude":"-22.275242","longitude":"138.432225","tags":["dolor","officia","dolor","sit","est","ea","enim","eiusmod","magna","incididunt"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Rodgers Thornton"},{"id":1,"name":"Samantha Stanley"},{"id":2,"name":"Lelia Bowen"},{"id":3,"name":"Herminia Hutchinson"},{"id":4,"name":"Wright Holloway"},{"id":5,"name":"Ava Vinson"},{"id":6,"name":"Francine Schmidt"},{"id":7,"name":"Frederick Bowman"},{"id":8,"name":"Daniel Brown"},{"id":9,"name":"Renee Gill"}],"greeting":"Hello, Mildred! You have 5 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34a398b521eb072327","index":32,"guid":"045c43e8-f6f2-4490-8d26-3fb124098c34","isActive":false,"balance":"$3,371.61","picture":"http://placehold.it/32x32","age":23,"eyeColor":"blue","name":{"first":"Angelina","last":"Hahn"},"company":"QUANTALIA","email":"angelina.hahn@quantalia.info","phone":"+1 (813) 431-3542","address":"894 Louisa Street, Cochranville, Maine, 2019","about":"Tempor Lorem labore et officia id. Laboris aliqua Lorem do aliquip dolore officia quis Lorem quis et qui voluptate sunt. Id Lorem voluptate elit ea dolor occaecat magna occaecat et ad sint. Cillum mollit incididunt nisi reprehenderit Lorem duis reprehenderit minim voluptate exercitation incididunt est nisi esse.","registered":"Monday, December 12, 2016 7:40 AM","latitude":"28.524161","longitude":"97.447644","tags":["pariatur","incididunt","est","ut","pariatur","laboris","duis","nulla","eu","fugiat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Sylvia Bradley"},{"id":1,"name":"Jamie Wells"},{"id":2,"name":"Jodie Mccormick"},{"id":3,"name":"Calderon Hansen"},{"id":4,"name":"Fuentes Walton"},{"id":5,"name":"Lacy Goff"},{"id":6,"name":"Marguerite Cantrell"},{"id":7,"name":"Goldie Best"},{"id":8,"name":"Melva Ware"},{"id":9,"name":"Lina Stuart"}],"greeting":"Hello, Angelina! You have 6 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa3415690121e1d31dc8","index":33,"guid":"1c4d9d82-a2ed-4137-bbb2-1e31c25c3845","isActive":true,"balance":"$1,955.48","picture":"http://placehold.it/32x32","age":38,"eyeColor":"green","name":{"first":"Rosanna","last":"Morgan"},"company":"AQUOAVO","email":"rosanna.morgan@aquoavo.me","phone":"+1 (972) 555-2633","address":"125 Downing Street, Lutsen, Missouri, 7484","about":"Officia officia magna exercitation do culpa nostrud anim minim reprehenderit velit exercitation exercitation excepteur. Cillum est occaecat id nisi. Ipsum dolor quis incididunt non anim. Officia in esse nulla do commodo eu non commodo consequat. Et proident et id officia fugiat consectetur do non. Est ea eu velit fugiat ea nostrud id consequat cillum sit consectetur. Proident ut Lorem incididunt Lorem aliqua mollit Lorem dolore esse mollit elit eu.","registered":"Saturday, November 11, 2017 6:19 AM","latitude":"-26.09161","longitude":"-142.715019","tags":["veniam","exercitation","proident","minim","aliquip","labore","sint","quis","laboris","ut"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Durham Mayo"},{"id":1,"name":"Puckett Clayton"},{"id":2,"name":"Guzman Franks"},{"id":3,"name":"Marion Riddle"},{"id":4,"name":"Bowman Clemons"},{"id":5,"name":"Church Dudley"},{"id":6,"name":"Adeline Gross"},{"id":7,"name":"Wolf Boyle"},{"id":8,"name":"Maggie Fry"},{"id":9,"name":"Molly Willis"}],"greeting":"Hello, Rosanna! You have 9 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa3473b934c37662ee87","index":34,"guid":"9e975a37-6c04-4476-8af8-a8da71f95bce","isActive":false,"balance":"$2,374.83","picture":"http://placehold.it/32x32","age":26,"eyeColor":"green","name":{"first":"Alexis","last":"Stephens"},"company":"VIDTO","email":"alexis.stephens@vidto.org","phone":"+1 (823) 415-2326","address":"129 Cove Lane, Loretto, Federated States Of Micronesia, 4132","about":"Ipsum laboris elit irure sunt velit minim et aliquip qui labore. Cupidatat pariatur cupidatat labore dolore ullamco nisi ipsum aute. Aute fugiat pariatur cupidatat fugiat irure do proident voluptate pariatur duis quis sit est. Ex ipsum ea ipsum nulla nostrud ad veniam sunt cupidatat aliquip occaecat elit est voluptate. Nostrud non enim quis consequat cupidatat voluptate occaecat veniam ad sunt sint Lorem tempor minim.","registered":"Tuesday, February 9, 2016 6:58 AM","latitude":"30.265793","longitude":"133.438276","tags":["veniam","eiusmod","Lorem","officia","consequat","dolor","tempor","sunt","ex","sit"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Fanny Atkinson"},{"id":1,"name":"Maryanne Conrad"},{"id":2,"name":"Catalina Harmon"},{"id":3,"name":"Cooke Rowe"},{"id":4,"name":"Angie Mcgee"},{"id":5,"name":"Stokes Gibson"},{"id":6,"name":"Jones Vega"},{"id":7,"name":"Leah Butler"},{"id":8,"name":"Taylor Peters"},{"id":9,"name":"Cochran Neal"}],"greeting":"Hello, Alexis! You have 10 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa34629b7e6a2d9be431","index":35,"guid":"3c9958e7-c013-4af9-8fcd-b6956105558b","isActive":false,"balance":"$3,908.65","picture":"http://placehold.it/32x32","age":32,"eyeColor":"green","name":{"first":"Aguirre","last":"Mckinney"},"company":"NETPLODE","email":"aguirre.mckinney@netplode.tv","phone":"+1 (894) 423-3860","address":"403 Glendale Court, Wildwood, Massachusetts, 8080","about":"Aliqua elit sunt anim magna aliquip ullamco non incididunt. Proident irure Lorem excepteur aliqua deserunt nisi in ea reprehenderit. Ad laboris aute cillum ut exercitation culpa dolor.","registered":"Wednesday, May 7, 2014 2:56 PM","latitude":"-76.365309","longitude":"-157.854137","tags":["proident","deserunt","est","sint","sint","magna","aliquip","in","commodo","velit"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Dorsey Cote"},{"id":1,"name":"Levy Castro"},{"id":2,"name":"Anne Love"},{"id":3,"name":"Neva Suarez"},{"id":4,"name":"Tammie Gallagher"},{"id":5,"name":"Kristi Parker"},{"id":6,"name":"Waller Miller"},{"id":7,"name":"Nadia Wood"},{"id":8,"name":"Powell Lott"},{"id":9,"name":"Chris Hoffman"}],"greeting":"Hello, Aguirre! You have 7 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa3426ab5d444b6a10f9","index":36,"guid":"8b4fdf0f-9db7-41d4-b39d-139cd785d7b5","isActive":true,"balance":"$2,280.91","picture":"http://placehold.it/32x32","age":30,"eyeColor":"green","name":{"first":"Richards","last":"Snow"},"company":"BLURRYBUS","email":"richards.snow@blurrybus.io","phone":"+1 (905) 463-2264","address":"494 Brightwater Court, Marenisco, Colorado, 1830","about":"Mollit duis nisi eu aliquip tempor irure laborum ad minim aliqua. Ullamco voluptate enim adipisicing consectetur adipisicing occaecat tempor voluptate dolor incididunt tempor fugiat. Adipisicing cupidatat esse ex commodo nostrud officia cupidatat ullamco magna proident incididunt. Adipisicing sint Lorem qui duis laborum non consequat minim incididunt sint quis in voluptate. Minim ea ex ex cupidatat consectetur aliqua proident exercitation cupidatat duis sint ut. Magna enim eu aute aliquip est minim nulla mollit. Occaecat magna ad nisi eiusmod aliqua deserunt consectetur exercitation adipisicing commodo voluptate.","registered":"Thursday, October 13, 2016 7:34 PM","latitude":"-84.839295","longitude":"-173.645597","tags":["ut","veniam","ullamco","culpa","exercitation","fugiat","quis","consequat","amet","nostrud"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Lakeisha Banks"},{"id":1,"name":"Anderson Wooten"},{"id":2,"name":"Marie Hopkins"},{"id":3,"name":"Parks Jensen"},{"id":4,"name":"Wendi Page"},{"id":5,"name":"Hart Andrews"},{"id":6,"name":"Margery Irwin"},{"id":7,"name":"Harrison Kirby"},{"id":8,"name":"Ivy Santiago"},{"id":9,"name":"Tamra Witt"}],"greeting":"Hello, Richards! You have 5 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa345399675c8e97e073","index":37,"guid":"8c6ce068-927a-4c5a-ba09-bc264d9fd709","isActive":true,"balance":"$2,124.25","picture":"http://placehold.it/32x32","age":25,"eyeColor":"brown","name":{"first":"Penny","last":"Swanson"},"company":"PLAYCE","email":"penny.swanson@playce.name","phone":"+1 (874) 539-3904","address":"797 Pershing Loop, Gorst, New York, 2236","about":"Cillum ad irure consequat do cillum culpa aliquip exercitation est cupidatat ex do consectetur aute. Enim proident ea velit dolore ex ea tempor elit consequat laboris. Laborum velit eu minim irure nostrud cupidatat mollit minim nostrud. Tempor ea laboris nostrud tempor veniam. Cillum ex in cupidatat ut laboris. Fugiat nisi in quis velit eu fugiat veniam aliquip aliqua anim est.","registered":"Tuesday, September 13, 2016 10:26 AM","latitude":"46.06826","longitude":"-179.707892","tags":["ea","proident","ea","culpa","consequat","incididunt","incididunt","non","ea","duis"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Webster Alford"},{"id":1,"name":"Stacey Boyd"},{"id":2,"name":"Nellie Delgado"},{"id":3,"name":"Baker Slater"},{"id":4,"name":"Moody Underwood"},{"id":5,"name":"Rosales Buck"},{"id":6,"name":"Hess Todd"},{"id":7,"name":"Lane Farley"},{"id":8,"name":"Smith Sears"},{"id":9,"name":"Newman Caldwell"}],"greeting":"Hello, Penny! You have 10 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa344f3de72033606554","index":38,"guid":"78c70b05-ba42-4c24-a841-3cb06a29112c","isActive":false,"balance":"$2,845.79","picture":"http://placehold.it/32x32","age":26,"eyeColor":"green","name":{"first":"Christi","last":"French"},"company":"SKYPLEX","email":"christi.french@skyplex.biz","phone":"+1 (831) 500-2423","address":"381 Colby Court, Haena, Marshall Islands, 839","about":"Consectetur magna in fugiat quis aute anim elit officia ex sint exercitation. Sunt exercitation pariatur enim laborum mollit labore. Minim enim pariatur enim ex ipsum eiusmod est quis irure.","registered":"Wednesday, August 17, 2016 9:32 PM","latitude":"-70.652626","longitude":"-160.945222","tags":["dolor","reprehenderit","nulla","laborum","esse","est","nostrud","velit","cupidatat","id"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Haley Mcneil"},{"id":1,"name":"Bernadine Bean"},{"id":2,"name":"Agnes Kirk"},{"id":3,"name":"Margie Aguirre"},{"id":4,"name":"Mitzi Harper"},{"id":5,"name":"Hatfield Marks"},{"id":6,"name":"Rachael Harris"},{"id":7,"name":"Serena Sykes"},{"id":8,"name":"Davis Cline"},{"id":9,"name":"Blanca Cameron"}],"greeting":"Hello, Christi! You have 7 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa346c214ead2d9abdf1","index":39,"guid":"eae6507c-4bae-4729-9212-aa5a8c48006b","isActive":false,"balance":"$3,360.83","picture":"http://placehold.it/32x32","age":26,"eyeColor":"green","name":{"first":"Kidd","last":"Stark"},"company":"CENTREXIN","email":"kidd.stark@centrexin.us","phone":"+1 (832) 581-2526","address":"759 Blake Court, Turpin, Oklahoma, 7285","about":"Dolore dolor labore ut aliquip ad enim do enim do. Fugiat voluptate culpa qui ut officia consequat ipsum laboris ullamco exercitation voluptate consectetur proident minim. Laboris nisi amet quis aliquip adipisicing eiusmod pariatur in ut quis.","registered":"Saturday, April 30, 2016 2:38 AM","latitude":"-66.122491","longitude":"178.936101","tags":["pariatur","duis","qui","qui","deserunt","minim","in","aliqua","voluptate","laboris"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Petty Ferrell"},{"id":1,"name":"Jacqueline Reilly"},{"id":2,"name":"Robles Frye"},{"id":3,"name":"Woods Weeks"},{"id":4,"name":"Louisa Levine"},{"id":5,"name":"Hardin Farmer"},{"id":6,"name":"Roach Glass"},{"id":7,"name":"Jacobs Faulkner"},{"id":8,"name":"Oconnor Hurley"},{"id":9,"name":"Loretta Patel"}],"greeting":"Hello, Kidd! You have 9 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa348ff4bb496eae2130","index":40,"guid":"77f38c4e-206a-41ad-b8ec-8c124da29d71","isActive":true,"balance":"$1,227.03","picture":"http://placehold.it/32x32","age":39,"eyeColor":"green","name":{"first":"Angelita","last":"Mills"},"company":"CABLAM","email":"angelita.mills@cablam.biz","phone":"+1 (977) 596-3341","address":"240 Court Street, Collins, South Carolina, 3358","about":"Quis velit labore adipisicing amet excepteur. Exercitation enim adipisicing adipisicing ut nostrud cillum. Est anim duis duis voluptate Lorem occaecat. Ut commodo laborum reprehenderit aliqua dolor eiusmod cupidatat duis. Deserunt et mollit velit excepteur qui non deserunt esse ut tempor ut voluptate. Sit culpa sit officia Lorem nisi ad nulla amet ipsum elit dolore. Mollit amet id Lorem magna esse consequat duis irure ad veniam ea duis.","registered":"Saturday, October 11, 2014 3:14 PM","latitude":"47.351007","longitude":"105.90419","tags":["sunt","non","voluptate","consectetur","ut","est","laborum","ad","cupidatat","esse"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Langley Powers"},{"id":1,"name":"Carson Woodard"},{"id":2,"name":"Peterson Pugh"},{"id":3,"name":"Lorie Perez"},{"id":4,"name":"Case Parks"},{"id":5,"name":"Elizabeth Boone"},{"id":6,"name":"Marian Maddox"},{"id":7,"name":"Mara Sargent"},{"id":8,"name":"Gilliam Garner"},{"id":9,"name":"Weeks Ross"}],"greeting":"Hello, Angelita! You have 10 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34e7a9b39ca8267980","index":41,"guid":"2a508c71-aa4d-4f9e-a96d-3f6495bf102c","isActive":true,"balance":"$2,610.88","picture":"http://placehold.it/32x32","age":34,"eyeColor":"green","name":{"first":"Kirk","last":"Conner"},"company":"ECRATER","email":"kirk.conner@ecrater.com","phone":"+1 (876) 408-2160","address":"984 Erasmus Street, Ronco, Tennessee, 2168","about":"Nisi sint velit reprehenderit ex anim in veniam elit laborum aliquip. Sit exercitation mollit magna veniam officia minim ipsum labore dolore nulla. Dolor ad adipisicing magna amet aliquip. Amet elit aliqua dolore dolore mollit ex veniam sit aliquip proident pariatur duis aliqua do. Eu et id aute in eu qui minim sunt ullamco quis ea ipsum. Elit ullamco dolor irure culpa proident tempor enim irure irure deserunt anim ex. Consequat proident Lorem enim est.","registered":"Tuesday, June 20, 2017 5:36 PM","latitude":"9.0713","longitude":"-13.535663","tags":["eu","duis","deserunt","sint","consequat","magna","laborum","aliquip","anim","ex"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Bridges Floyd"},{"id":1,"name":"Barnes Head"},{"id":2,"name":"Conley Barrett"},{"id":3,"name":"Waters Bennett"},{"id":4,"name":"Kaufman Morton"},{"id":5,"name":"Copeland Rose"},{"id":6,"name":"Kendra Daniels"},{"id":7,"name":"Julie Roth"},{"id":8,"name":"Tami Snider"},{"id":9,"name":"Margaret Mcmillan"}],"greeting":"Hello, Kirk! You have 10 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa341e9858da323f3e8a","index":42,"guid":"8ae8c734-331c-4707-9225-f38615f7d87c","isActive":true,"balance":"$3,280.97","picture":"http://placehold.it/32x32","age":22,"eyeColor":"blue","name":{"first":"Hickman","last":"Langley"},"company":"VERAQ","email":"hickman.langley@veraq.co.uk","phone":"+1 (908) 439-3901","address":"469 Nova Court, Buxton, Wisconsin, 8132","about":"Voluptate et ipsum ea in voluptate. Amet incididunt cupidatat duis veniam ipsum veniam deserunt. Mollit duis exercitation cillum pariatur culpa enim. Excepteur nulla ea velit sunt aliqua. Est velit consectetur in aliqua. Duis pariatur ea sit laborum Lorem quis nisi dolore. Fugiat id ad consectetur irure ipsum adipisicing eu sit duis laboris tempor sunt irure minim.","registered":"Monday, December 19, 2016 6:40 PM","latitude":"38.352256","longitude":"-79.01819","tags":["commodo","laboris","in","esse","incididunt","eiusmod","aute","amet","qui","esse"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Snow Stafford"},{"id":1,"name":"Pollard Fischer"},{"id":2,"name":"Lillian Bowers"},{"id":3,"name":"Katy Lancaster"},{"id":4,"name":"Ana Tillman"},{"id":5,"name":"Tanisha Dean"},{"id":6,"name":"Verna Osborn"},{"id":7,"name":"Lorene Blackwell"},{"id":8,"name":"Klein Lindsay"},{"id":9,"name":"Kay Simpson"}],"greeting":"Hello, Hickman! You have 9 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34745076e981951cad","index":43,"guid":"cf66637a-0f87-43c1-8d3e-8a8eb32a3b82","isActive":true,"balance":"$3,777.58","picture":"http://placehold.it/32x32","age":27,"eyeColor":"blue","name":{"first":"Dorthy","last":"Dixon"},"company":"AVENETRO","email":"dorthy.dixon@avenetro.ca","phone":"+1 (865) 445-2658","address":"845 Hendrix Street, Mathews, Delaware, 8863","about":"Consectetur qui minim tempor proident sint esse est quis. Eiusmod aliqua ea ut officia quis deserunt cillum quis aliqua exercitation ipsum. Magna qui veniam enim ullamco nulla. Occaecat commodo excepteur qui laborum qui ea mollit Lorem non ex nostrud proident reprehenderit nulla. Ipsum laboris irure ullamco do consectetur laboris sunt id adipisicing ullamco duis quis cupidatat.","registered":"Wednesday, January 13, 2016 1:56 AM","latitude":"-45.361089","longitude":"118.758428","tags":["esse","aute","excepteur","esse","labore","ut","irure","ea","cupidatat","aliquip"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Dillon Holman"},{"id":1,"name":"Megan Joyner"},{"id":2,"name":"Casandra Branch"},{"id":3,"name":"Linda Livingston"},{"id":4,"name":"Pope Talley"},{"id":5,"name":"Vasquez Cox"},{"id":6,"name":"Skinner Cross"},{"id":7,"name":"Anna Beasley"},{"id":8,"name":"Dawson Gould"},{"id":9,"name":"Dean Shepard"}],"greeting":"Hello, Dorthy! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa34f7481ee6928ebadf","index":44,"guid":"d5e4825b-cbfe-4994-af1a-03a4a46fd290","isActive":false,"balance":"$2,976.38","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":{"first":"Lynnette","last":"Rosales"},"company":"YURTURE","email":"lynnette.rosales@yurture.info","phone":"+1 (931) 424-3261","address":"293 Rose Street, Alderpoint, Alabama, 2523","about":"Veniam et et laboris irure elit consectetur ut exercitation fugiat. Cillum in eu cillum elit et. Ullamco mollit tempor consectetur excepteur enim laborum amet magna id. Cillum commodo mollit qui consequat eiusmod cupidatat amet. Do labore aute consequat aliqua nostrud ut officia qui elit id labore dolor laboris. Fugiat nostrud ea id officia adipisicing. Incididunt reprehenderit velit sunt elit ex officia nulla nostrud sit culpa pariatur ipsum.","registered":"Monday, June 22, 2015 9:25 PM","latitude":"83.236293","longitude":"-165.695513","tags":["sit","deserunt","non","ipsum","irure","laborum","ut","amet","dolore","Lorem"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Harriet Vasquez"},{"id":1,"name":"Warren Sherman"},{"id":2,"name":"Rita Downs"},{"id":3,"name":"Celia Mcclain"},{"id":4,"name":"Bethany Mason"},{"id":5,"name":"Barker Anderson"},{"id":6,"name":"Lucy Santana"},{"id":7,"name":"Aurelia Dickerson"},{"id":8,"name":"Bullock Durham"},{"id":9,"name":"Middleton Huffman"}],"greeting":"Hello, Lynnette! You have 7 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa3447392bc6d49d3c6a","index":45,"guid":"93bf294e-6516-462c-affc-fefb2fc25cfb","isActive":false,"balance":"$1,251.30","picture":"http://placehold.it/32x32","age":26,"eyeColor":"brown","name":{"first":"Wagner","last":"Murphy"},"company":"NEXGENE","email":"wagner.murphy@nexgene.me","phone":"+1 (861) 488-2141","address":"567 Cleveland Street, Belva, Northern Mariana Islands, 1561","about":"Mollit ut ipsum id qui ex magna duis magna ipsum cillum proident. Veniam eu dolore deserunt nulla amet dolore quis aliqua. Est dolore anim aliqua ex exercitation cupidatat voluptate. Ea ipsum proident sunt non. Minim laborum nisi culpa ex sit excepteur reprehenderit aute exercitation officia veniam. Occaecat est tempor anim incididunt elit incididunt commodo fugiat magna laboris laboris irure. Culpa aliquip ipsum tempor cupidatat non laboris ad anim duis.","registered":"Saturday, June 20, 2015 8:46 AM","latitude":"26.957528","longitude":"-83.855732","tags":["officia","aliqua","et","cupidatat","labore","culpa","nisi","sit","mollit","cupidatat"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Gertrude Mclaughlin"},{"id":1,"name":"Esther Pope"},{"id":2,"name":"Jacquelyn Rush"},{"id":3,"name":"Ellen Keith"},{"id":4,"name":"Zimmerman Mejia"},{"id":5,"name":"Craft Franklin"},{"id":6,"name":"Hubbard Christian"},{"id":7,"name":"Bridgett Kline"},{"id":8,"name":"Gonzalez Douglas"},{"id":9,"name":"Larson Justice"}],"greeting":"Hello, Wagner! You have 10 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa344a1963094ff64da5","index":46,"guid":"6b9e6342-267d-4844-b030-723bae27c4ce","isActive":true,"balance":"$1,943.18","picture":"http://placehold.it/32x32","age":35,"eyeColor":"green","name":{"first":"Tonya","last":"Lowery"},"company":"MYOPIUM","email":"tonya.lowery@myopium.org","phone":"+1 (881) 553-2631","address":"975 Amboy Street, Nipinnawasee, California, 9715","about":"Pariatur dolor exercitation dolore eiusmod et nisi in deserunt laborum nisi magna. Dolor laborum culpa quis aute pariatur labore est velit voluptate. Minim labore occaecat aute fugiat sint laborum voluptate tempor minim.","registered":"Wednesday, December 30, 2015 5:12 AM","latitude":"13.22295","longitude":"159.692667","tags":["eu","veniam","et","est","est","aliquip","sint","non","anim","ex"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Debra Stanton"},{"id":1,"name":"Harrington Carney"},{"id":2,"name":"Helena Rivas"},{"id":3,"name":"Pearl Wagner"},{"id":4,"name":"Bridgette Lawson"},{"id":5,"name":"Patel Sutton"},{"id":6,"name":"Horton Saunders"},{"id":7,"name":"Sherri Nelson"},{"id":8,"name":"Jacobson Hurst"},{"id":9,"name":"Shanna Cotton"}],"greeting":"Hello, Tonya! You have 5 unread messages.","favoriteFruit":"banana"},{"_id":"5ae0aa34b44b3eb5d573dfe4","index":47,"guid":"6fc32a51-1b79-4679-910e-5eb13aa223f8","isActive":true,"balance":"$1,559.68","picture":"http://placehold.it/32x32","age":38,"eyeColor":"green","name":{"first":"Johnnie","last":"Travis"},"company":"SURELOGIC","email":"johnnie.travis@surelogic.tv","phone":"+1 (855) 506-2479","address":"289 Anna Court, Denio, Virgin Islands, 7460","about":"Adipisicing ipsum enim ullamco laborum nostrud nulla esse quis ipsum voluptate eiusmod. Fugiat ut est consectetur nisi minim. Id sint nostrud eiusmod cupidatat fugiat.","registered":"Tuesday, August 1, 2017 5:05 PM","latitude":"-4.213212","longitude":"-93.529387","tags":["est","consequat","consectetur","enim","qui","et","ullamco","ipsum","reprehenderit","mollit"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Ester Harrell"},{"id":1,"name":"Shepard Shelton"},{"id":2,"name":"Enid Romero"},{"id":3,"name":"Effie Baxter"},{"id":4,"name":"Dona Huber"},{"id":5,"name":"Berger Heath"},{"id":6,"name":"Allison Lynn"},{"id":7,"name":"Blackwell Edwards"},{"id":8,"name":"Lottie Chambers"},{"id":9,"name":"Todd Holmes"}],"greeting":"Hello, Johnnie! You have 8 unread messages.","favoriteFruit":"apple"},{"_id":"5ae0aa349fe0e22b1f9fbdfd","index":48,"guid":"3ae5da74-591c-48c9-a328-6ec454619337","isActive":false,"balance":"$2,825.93","picture":"http://placehold.it/32x32","age":20,"eyeColor":"blue","name":{"first":"Deanna","last":"Adkins"},"company":"VIRXO","email":"deanna.adkins@virxo.io","phone":"+1 (981) 554-3807","address":"650 Bridge Street, Mappsville, Kansas, 4759","about":"Et aliqua laboris do excepteur veniam dolor cupidatat nisi eu voluptate sunt eiusmod non eiusmod. Minim eu dolor sunt aute. Nostrud laborum ad voluptate ipsum occaecat Lorem. Dolore sit amet cupidatat enim cillum ipsum cillum. Et laborum ut proident officia mollit. Eu velit commodo esse id sint aliquip Lorem et occaecat aliqua. Consequat eiusmod fugiat cillum consequat eiusmod eiusmod ex qui est duis consequat et officia.","registered":"Tuesday, December 13, 2016 7:50 AM","latitude":"33.223746","longitude":"15.22617","tags":["excepteur","ex","deserunt","qui","sit","aute","nostrud","do","labore","ipsum"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Riddle Reese"},{"id":1,"name":"Selma Henson"},{"id":2,"name":"Yesenia Middleton"},{"id":3,"name":"Nola White"},{"id":4,"name":"Sweet Guerra"},{"id":5,"name":"Terra Small"},{"id":6,"name":"Hamilton Hughes"},{"id":7,"name":"Hester Poole"},{"id":8,"name":"Calhoun Hubbard"},{"id":9,"name":"Bonita Hall"}],"greeting":"Hello, Deanna! You have 10 unread messages.","favoriteFruit":"strawberry"},{"_id":"5ae0aa34e364048f9370e15f","index":49,"guid":"bf614856-f78f-44c2-8abc-0f89064d6c7b","isActive":true,"balance":"$3,625.36","picture":"http://placehold.it/32x32","age":35,"eyeColor":"blue","name":{"first":"Rosella","last":"Zimmerman"},"company":"ZYTREX","email":"rosella.zimmerman@zytrex.name","phone":"+1 (928) 486-3626","address":"915 Dean Street, Valmy, Iowa, 2698","about":"Dolore cupidatat quis ex esse. Mollit labore exercitation exercitation Lorem elit pariatur incididunt culpa nostrud pariatur tempor ut id. Lorem nostrud mollit elit veniam dolore incididunt duis consectetur nostrud proident eu occaecat cupidatat incididunt. Dolor pariatur fugiat sunt do consequat officia sit aliquip officia quis consequat ipsum dolor ad. Occaecat mollit sunt sit occaecat. Quis in irure ipsum sunt. Dolor ullamco sunt dolor labore proident consectetur ex irure est dolor officia.","registered":"Sunday, September 24, 2017 5:22 AM","latitude":"-58.21478","longitude":"2.994387","tags":["id","irure","labore","anim","non","est","eiusmod","aliquip","enim","proident"],"range":[0,1,2,3,4,5,6,7,8,9],"friends":[{"id":0,"name":"Ortiz Rivera"},{"id":1,"name":"Nina Mcclure"},{"id":2,"name":"Donna Whitley"},{"id":3,"name":"Ladonna Salazar"},{"id":4,"name":"Rosario Gay"},{"id":5,"name":"Nelda Rich"},{"id":6,"name":"Harriett Phillips"},{"id":7,"name":"Marianne Leblanc"},{"id":8,"name":"Anastasia Smith"},{"id":9,"name":"Stacy Cochran"}],"greeting":"Hello, Rosella! You have 8 unread messages.","favoriteFruit":"apple"}]} diff --git a/token_test.go b/token_test.go deleted file mode 100644 index 91e4bae..0000000 --- a/token_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "encoding/json" - "testing" -) - -var cases = []struct { - in interface{} - want token -}{ - {make(map[string]interface{}), token{"{}", typEmptyObject}}, - {make([]interface{}, 0), token{"[]", typEmptyArray}}, - {json.Number("1.2"), token{"1.2", typNumber}}, - {"foo", token{`"foo"`, typString}}, - {"<3", token{`"<3"`, typString}}, - {"&", token{`"&"`, typString}}, - {"\b", token{`"\b"`, typString}}, - {"\f", token{`"\f"`, typString}}, - {"\n", token{`"\n"`, typString}}, - {"\r", token{`"\r"`, typString}}, - {"\t", token{`"\t"`, typString}}, - {"wat \u001e", token{`"wat \u001E"`, typString}}, - {"Hello, 世界", token{`"Hello, 世界"`, typString}}, - {true, token{"true", typTrue}}, - {false, token{"false", typFalse}}, - {nil, token{"null", typNull}}, - {struct{}{}, token{"", typError}}, -} - -func TestValueTokenFromInterface(t *testing.T) { - - for _, c := range cases { - have := valueTokenFromInterface(c.in) - - if have != c.want { - t.Logf("input: %#v", have) - t.Logf("have: %#v", have) - t.Logf("want: %#v", c.want) - t.Errorf("have != want") - } - } -} - -func BenchmarkValueTokenFromInterface(b *testing.B) { - - for i := 0; i < b.N; i++ { - for _, c := range cases { - _ = valueTokenFromInterface(c.in) - } - } -} diff --git a/ungron_test.go b/ungron_test.go deleted file mode 100644 index f9f3fb4..0000000 --- a/ungron_test.go +++ /dev/null @@ -1,292 +0,0 @@ -package main - -import ( - "reflect" - "testing" -) - -func TestLex(t *testing.T) { - cases := []struct { - in string - want []token - }{ - {`json.foo = 1;`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {`foo`, typBare}, - {`=`, typEquals}, - {`1`, typNumber}, - {`;`, typSemi}, - }}, - - {`json.foo = "bar";`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {`foo`, typBare}, - {`=`, typEquals}, - {`"bar"`, typString}, - {`;`, typSemi}, - }}, - - {`json.foo = "ba;r";`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {`foo`, typBare}, - {`=`, typEquals}, - {`"ba;r"`, typString}, - {`;`, typSemi}, - }}, - - {`json.foo = "ba\"r ;";`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {`foo`, typBare}, - {`=`, typEquals}, - {`"ba\"r ;"`, typString}, - {`;`, typSemi}, - }}, - - {`json = "\\";`, []token{ - {`json`, typBare}, - {`=`, typEquals}, - {`"\\"`, typString}, - {`;`, typSemi}, - }}, - - {`json = "\\\\";`, []token{ - {`json`, typBare}, - {`=`, typEquals}, - {`"\\\\"`, typString}, - {`;`, typSemi}, - }}, - - {`json = "f\oo\\";`, []token{ - {`json`, typBare}, - {`=`, typEquals}, - {`"f\oo\\"`, typString}, - {`;`, typSemi}, - }}, - - {`json.value = "\u003c ;";`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {`value`, typBare}, - {`=`, typEquals}, - {`"\u003c ;"`, typString}, - {`;`, typSemi}, - }}, - - {`json[0] = "bar";`, []token{ - {`json`, typBare}, - {`[`, typLBrace}, - {`0`, typNumericKey}, - {`]`, typRBrace}, - {`=`, typEquals}, - {`"bar"`, typString}, - {`;`, typSemi}, - }}, - - {`json["foo"] = "bar";`, []token{ - {`json`, typBare}, - {`[`, typLBrace}, - {`"foo"`, typQuotedKey}, - {`]`, typRBrace}, - {`=`, typEquals}, - {`"bar"`, typString}, - {`;`, typSemi}, - }}, - - {`json.foo["bar"][0] = "bar";`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {`foo`, typBare}, - {`[`, typLBrace}, - {`"bar"`, typQuotedKey}, - {`]`, typRBrace}, - {`[`, typLBrace}, - {`0`, typNumericKey}, - {`]`, typRBrace}, - {`=`, typEquals}, - {`"bar"`, typString}, - {`;`, typSemi}, - }}, - - {`not an identifier at all`, []token{ - {`not`, typBare}, - }}, - - {`alsonotanidentifier`, []token{ - {`alsonotanidentifier`, typBare}, - }}, - - {`wat!`, []token{ - {`wat`, typBare}, - {``, typError}, - }}, - - {`json[ = 1;`, []token{ - {`json`, typBare}, - {`[`, typLBrace}, - {``, typError}, - }}, - - {`json.[2] = 1;`, []token{ - {`json`, typBare}, - {`.`, typDot}, - {``, typError}, - }}, - - {`json[1 = 1;`, []token{ - {`json`, typBare}, - {`[`, typLBrace}, - {`1`, typNumericKey}, - {``, typError}, - }}, - - {`json["foo] = 1;`, []token{ - {`json`, typBare}, - {`[`, typLBrace}, - {`"foo] = 1;`, typQuotedKey}, - {``, typError}, - }}, - - {`--`, []token{ - {`--`, typIgnored}, - }}, - - {`json = 1;`, []token{ - {`json`, typBare}, - {`=`, typEquals}, - {`1`, typNumber}, - {`;`, typSemi}, - }}, - - {`json=1;`, []token{ - {`json`, typBare}, - {`=`, typEquals}, - {`1`, typNumber}, - {`;`, typSemi}, - }}, - } - - for _, c := range cases { - l := newLexer(c.in) - have := l.lex() - - if len(have) != len(c.want) { - t.Logf("Input: %#v", c.in) - t.Logf("Want: %#v", c.want) - t.Logf("Have: %#v", have) - t.Fatalf("want %d tokens, have %d", len(c.want), len(have)) - } - - for i := range have { - if have[i] != c.want[i] { - t.Logf("Input: %#v", c.in) - t.Logf("Want: %#v", c.want) - t.Logf("Have: %#v", have) - t.Errorf("Want `%#v` in position %d, have `%#v`", c.want[i], i, have[i]) - } - } - } -} - -func TestUngronTokensSimple(t *testing.T) { - in := `json.contact["e-mail"][0] = "mail@tomnomnom.com";` - want := map[string]interface{}{ - "json": map[string]interface{}{ - "contact": map[string]interface{}{ - "e-mail": []interface{}{ - "mail@tomnomnom.com", - }, - }, - }, - } - - l := newLexer(in) - tokens := l.lex() - have, err := ungronTokens(tokens) - - if err != nil { - t.Fatalf("failed to ungron statement: %s", err) - } - - t.Logf("Have: %#v", have) - t.Logf("Want: %#v", want) - - eq := reflect.DeepEqual(have, want) - if !eq { - t.Errorf("Have and want datastructures are unequal") - } -} - -func TestUngronTokensInvalid(t *testing.T) { - cases := []struct { - in []token - }{ - {[]token{{``, typError}}}, // Error token - {[]token{{`foo`, typString}}}, // Invalid value - {[]token{{`"foo`, typQuotedKey}, {"1", typNumber}}}, // Invalid quoted key - {[]token{{`foo`, typNumericKey}, {"1", typNumber}}}, // Invalid numeric key - {[]token{{``, -255}, {"1", typNumber}}}, // Invalid token type - } - - for _, c := range cases { - _, err := ungronTokens(c.in) - if err == nil { - t.Errorf("want non-nil error for %#v; have nil", c.in) - } - } -} - -func TestMerge(t *testing.T) { - a := map[string]interface{}{ - "json": map[string]interface{}{ - "contact": map[string]interface{}{ - "e-mail": []interface{}{ - 0: "mail@tomnomnom.com", - }, - }, - }, - } - - b := map[string]interface{}{ - "json": map[string]interface{}{ - "contact": map[string]interface{}{ - "e-mail": []interface{}{ - 1: "test@tomnomnom.com", - 3: "foo@tomnomnom.com", - }, - "twitter": "@TomNomNom", - }, - }, - } - - want := map[string]interface{}{ - "json": map[string]interface{}{ - "contact": map[string]interface{}{ - "e-mail": []interface{}{ - 0: "mail@tomnomnom.com", - 1: "test@tomnomnom.com", - 3: "foo@tomnomnom.com", - }, - "twitter": "@TomNomNom", - }, - }, - } - - t.Logf("A: %#v", a) - t.Logf("B: %#v", b) - have, err := recursiveMerge(a, b) - if err != nil { - t.Fatalf("failed to merge datastructures: %s", err) - } - - t.Logf("Have: %#v", have) - t.Logf("Want: %#v", want) - eq := reflect.DeepEqual(have, want) - if !eq { - t.Errorf("Have and want datastructures are unequal") - } - -}