From ade01832cdc9fb711023a60849181981f2b4ee81 Mon Sep 17 00:00:00 2001 From: "Chayim I. Kirshen" Date: Sun, 31 Oct 2021 15:46:32 +0200 Subject: json test conversion continues --- tests/test_json.py | 511 +++++++++++++++++++++++++++++++++- tests/testdata/jsontestdata.py | 617 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1125 insertions(+), 3 deletions(-) create mode 100644 tests/testdata/jsontestdata.py diff --git a/tests/test_json.py b/tests/test_json.py index fb36fc0..3c89ae3 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -1,7 +1,9 @@ import pytest import redis from redis.commands.json.path import Path +from redis import exceptions from .conftest import skip_ifmodversion_lt +from .testdata.jsontestdata import nested_large_key @pytest.fixture @@ -234,8 +236,11 @@ def test_objlenshouldsucceed(client): # assert client.keys() == [] # assert client.get("foo") is None + +######### DUAL + @pytest.mark.redismod -def test_jsondollardelete(client): +def test_json_delete_with_dollar(client): doc1 = {"a": 1, "nested": {"a": 2, "b": 3}} assert client.json().set("doc1", "$", doc1) assert client.json().delete("doc1", "$..a") == 2 @@ -270,7 +275,7 @@ def test_jsondollardelete(client): client.json().delete("not_a_document", "..a") @pytest.mark.redismod -def test_jsondollarforget(client): +def test_json_forget_with_dollar(client): doc1 = {"a": 1, "nested": {"a": 2, "b": 3}} assert client.json().set("doc1", "$", doc1) assert client.json().forget("doc1", "$..a") == 2 @@ -302,4 +307,504 @@ def test_jsondollarforget(client): assert client.json().forget("doc3") == 1 assert client.json().get("doc3", "$") is None - client.json().forget("not_a_document", "..a") \ No newline at end of file + client.json().forget("not_a_document", "..a") + +@pytest.mark.redismod +def test_set_and_get_with_dollar(client): + # Test set and get on large nested key + assert client.json().set("doc1", "$", nested_large_key, "XX") is None + assert client.json().set("doc1", "$", nested_large_key, "NX") + assert client.json().get('doc1', '$') == [nested_large_key] + assert client.json().set("doc1", "$", nested_large_key, "NX") is None + + # Test single path + assert client.json().get('doc1', '$..tm') == [[46,876.85],[134.761,"jcoels",None]] + + # Test multi get and set + assert client.json().get('doc1', '$..foobar') == [3.141592,1.61803398875] + + # Set multi existing values + client.json().set('doc1', '$..foobar', '"new_val"') + assert client.json().get('doc1', '$..foobar') == ["new_val","new_val"] + + # Test multi set and get on small nested key + nested_simple_key = {"a":1,"nested":{"a":2,"b":3}} + client.json().set('doc2', '$', nested_simple_key) + assert client.json().get('doc2', '$') == [nested_simple_key] + # Set multi existing values + client.json().set('doc2', '$..a', '4.2') + assert client.json().get('doc2', '$') == \ + [{"a":4.2,"nested":{"a":4.2,"b":3}}] + + + # Test multi paths + assert client.json().get('doc1', '$..tm', '$..nu') == \ + [[[46,876.85],[134.761,"jcoels",None]],[[377,"qda",True]]] + # Test multi paths - if one path is none-legacy - result format is not legacy + assert client.json().get('doc1', '..tm', '$..nu') == \ + [[[46,876.85],[134.761,"jcoels",None]],[[377,"qda",True]]] + + # Test missing key + assert client.json().get('docX', '..tm', '$..nu') is None + # Test missing path + assert client.json().get('doc1', '..tm', '$..back_in_nov') == \ + [[[46,876.85],[134.761,"jcoels",None]],[]] + assert client.json().get('doc2', '..a', '..b', '$.back_in_nov') == \ + [[4.2,4.2],[3],[]] + + # Test legacy multi path (all paths are legacy) + client.json().get('doc1', '..nu', '..tm') == \ + {"..nu":[377,"qda",True],"..tm":[46,876.85]} + # Test legacy single path + client.json().get('doc1', '..tm') == '[46,876.85]' + + # Test missing legacy path (should return an error for a missing path) + client.json().set('doc2', '$.nested.b', None) + + with pytest.raises(exceptions.DataError): + client.json.get('doc2', '.a', '.nested.b', '.back_in_nov', '.ttyl') + client.json.get('JSON.GET', 'doc2', '.back_in_nov') + +@pytest.mark.redismod +def test_json_mget_dollar(client): + # Test mget with multi paths + client.json().set('doc1', '$', {"a":1, "b": 2, "nested": {"a": 3}, "c": None, "nested2": {"a": None}}) + client.json().set('doc2', '$', {"a":4, "b": 5, "nested": {"a": 6}, "c": None, "nested2": {"a": [None]}}) + # Compare also to single JSON.GET + assert client.json().get('doc1', '$..a') == [1,3,None] + assert client.json().get('doc2', '$..a') == [4,6,[None]] + + # Test mget with single path + client.json().mget('doc1', '$..a') == [1,3,None] + # Test mget with multi path + client.json().mget('doc1', 'doc2', '$..a') == [[1,3,None], [4,6,[None]]] + + # Test missing key + client.json().mget('doc1', 'missing_doc', '$..a') == [[1,3,None], None] + res = client.json().mget('missing_doc1', 'missing_doc2', '$..a') + assert res == [None, None] + +@pytest.mark.redismod +def test_numby_commands_dollar(env): + + r = env + + # Test NUMINCRBY + client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]}) + # Test multi + assert client.json().numincrby('doc1', '$..a', '2') == [None, 4, 7.0, None] + + assert client.json().numincrby('doc1', '$..a', '2.5') == [None, 6.5, 9.5, None] + # Test single + assert client.json().numincrby('doc1', '$.b[1].a', '2') == [11.5] + + assert client.json().numincrby('doc1', '$.b[2].a', '2') == [None] + assert client.json().numincrby('doc1', '$.b[1].a', '3.5') == [15.0] + + # Test NUMMULTBY + client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]}) + + assert client.json().nummultby('doc1', '$..a', '2') == [None, 4, 10, None] + assert client.json().nummultby('doc1', '$..a', '2.5') == [None,10.0,25.0,None] + # Test single + assert client.json().nummultby('doc1', '$.b[1].a', '2') == [50.0] + assert client.json().nummultby('doc1', '$.b[2].a', '2') == [None] + assert client.json().nummultby('doc1', '$.b[1].a', '3') == [150.0] + + # Test NUMPOWBY + client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]}) + # Test multi + assert client.json().numpowby('doc1', '$..a', '2') == [None, 4, 25, None] + # Avoid json.loads to verify the underlying type (integer/float) + assert client.json().numpowby('doc1', '$..a', '2') == [None,16,625.0,None] + + # Test single + assert client.json().numpowby('JSON.NUMPOWBY', 'doc1', '$.b[1].a', '2') == [390625.0] + assert client.json().numpowby('JSON.NUMPOWBY', 'doc1', '$.b[2].a', '2') == [None] + assert client.json().numpowby('JSON.NUMPOWBY', 'doc1', '$.b[1].a', '3') == [5.960464477539062e16] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().numincrby('non_existing_doc', '$..a', '2') + client.json().nummultby('non_existing_doc', '$..a', '2') + + # TODO fixme + r.expect('JSON.NUMPOWBY', 'non_existing_doc', '$..a', '2') + + # Test legacy NUMINCRBY + client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]}) + client.json().numincrby('doc1', '.b[0].a', '3') == 5 + + # Test legacy NUMMULTBY + client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]}) + client.json().nummultby('doc1', '.b[0].a', '3') == 6 + +@pytest.mark.redismod +def test_strappend_dollar(client): + + client.json().set('doc1', '$', {"a":"foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}) + # Test multi + client.json().strappend('doc1', '$..a', '"bar"') == [6, 8, None] + + + client.json().get('doc1', '$') == [{"a":"foobar","nested1":{"a":"hellobar"},"nested2":{"a":31}}] + # Test single + client.json().strappend('doc1', '$.nested1.a', '"baz"') == [11] + + client.json().get('doc1', '$') == [{"a":"foobar","nested1":{"a":"hellobarbaz"},"nested2":{"a":31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().strappend('non_existing_doc', '$..a', '"err"') + + # Test multi + client.json().strappend('doc1', '.*.a', '"bar"') == 8 + client.json.get('doc1', '$') == [{"a":"foo","nested1":{"a":"hellobar"},"nested2":{"a":31}}] + + # Test missing path + with pytest.raises(exceptions.DataError): + client.json().strappend('doc1', '"piu"') + +@pytest.mark.redismod +def test_strlen_dollar(client): + + # Test multi + client.json().set('doc1', '$', {"a":"foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}) + res1 = client.json().strlen('doc1', '$..a') [3, 5, None] + + res2 = client.json().strappend('doc1', '$..a', '"bar"') == [6, 8, None] + res1 = client.json().strlen('doc1', '$..a') + assert res1 == res2 + + # Test single + client.json().strlen('doc1', '$.nested1.a') == [8] + client.json().strlen('doc1', '$.nested2.a') == [None] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().strlen('non_existing_doc', '$..a') + +@pytest.mark.redismod +def test_arrappend_dollar(client): + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi + client.json().arrappend('doc1', '$..a', '"bar"', '"racuda"') == [3, 5, None] + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda"]}, "nested2": {"a": 31}}] + + # Test single + assert client.json().arrappend('doc1', '$.nested1.a', '"baz"') == [6] + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda", "baz"]}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json.arrappend('non_existing_doc', '$..a') + + # Test legacy + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi (all paths are updated, but return result of last path) + assert client.json().arrappend('doc1', '..a', '"bar"', '"racuda"') == 5 + + assert client.json.get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda"]}, "nested2": {"a": 31}}] + # Test single + assert client.json().arrappend('doc1', '.nested1.a', '"baz"') == 6 + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda", "baz"]}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json.arrappend('non_existing_doc', '$..a') + +@pytest.mark.redismod +def test_arrinsert_dollar(client): + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi + assert client.json().arrinsert('doc1', '$..a', '1', '"bar"', '"racuda"') == [3, 5, None] + + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", None, "world"]}, "nested2": {"a": 31}}] + # Test single + assert client.json().arrinsert('doc1', '$.nested1.a', -2, '"baz"') == [6] + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", "baz", None, "world"]}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json.arrappend('non_existing_doc', '$..a') + + # Test legacy + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + assert client.json().arrappend('doc1', '..a', '1', '"bar"', '"racuda"') == 5 + + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", None, "world"]}, "nested2": {"a": 31}}] + # Test single + assert client.json().arrinsert('doc1', '.nested1.a', -2, '"baz"') == 6 + assert client.json().get('doc1', '$') == \ + [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", "baz", None, "world"]}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json.arrinsert('non_existing_doc', '$..a') + +@pytest.mark.redismod +def test_arrlen_dollar(client): + + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + + # Test multi + assert client.json().arrlen('doc1', '$..a') == [1, 3, None] + assert client.json().arrappend('doc1', '$..a', '"non"', '"abba"', '"stanza"') == \ + [4, 6, None] + + client.json().clear('doc1', '$.a') + assert client.json.arrlen('doc1', '$..a') == [0, 6, None] + # Test single + assert client.json().arrlen('doc1', '$.nested1.a') == [6] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json.arrappend('non_existing_doc', '$..a') + + # Test legacy + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi (return result of last path) + assert client.json().arrlen('doc1', '$..a') == [1, 3, None] + assert client.json().arrappend('doc1', '..a', '"non"', '"abba"', '"stanza"') == 6 + + # Test single + assert client.json().arrlen('doc1', '.nested1.a') = 6 + + # Test missing key + assert client.json().arrlen('non_existing_doc', '..a') is None + +@pytest.mark.redismod +def test_arrpop_dollar(client): + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi + assert client.json().arrpop('doc1', '$..a', '1') == ['"foo"', 'null', None] + + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}] + + assert client.json().arrpop('doc1', '$..a', '-1') == [None, '"world"', None] + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": ["hello"]}, "nested2": {"a": 31}}] + + # Test single + assert client.json().arrpop('doc1', '$.nested1.a', -2) == ['"hello"'] + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": []}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().arrpop('non_existing_doc', '..a') + + # Test legacy + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi (all paths are updated, but return result of last path) + client.json().arrpop('doc1', '..a', '1') is None + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}] + + # Test single + assert client.json().arrpop('doc1', '.nested1.a', -2, '"baz"') == '"hello"' + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().arrpop('non_existing_doc', '..a') + +@pytest.mark.redismod +def test_arrtrim_dollar(client): + + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + # Test multi + assert client.json().arrtrim('doc1', '$..a', '1', -1) == [0, 2, None] + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": [None, "world"]}, "nested2": {"a": 31}}] + + assert client.json().arrtrim('doc1', '$..a', '1', '1') == [0, 1, None] + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] + # Test single + assert client.json().arrtrim('doc1', '$.nested1.a', 1, 0) == [0] + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": []}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().arrtrim('non_existing_doc', '..a', '0') + + # Test legacy + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}}) + + # Test multi (all paths are updated, but return result of last path) + assert client.json().arrtrim('doc1', '..a', '1', '-1') == 2 + res = r.execute_command('JSON.GET', 'doc1', '$') == \ + [{"a": [], "nested1": {"a": [None, "world"]}, "nested2": {"a": 31}}] + # Test single + assert client.json().arrtrim('doc1', '.nested1.a', '1', '1') == 1 + assert client.json().get('doc1', '$') == \ + [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().arrtrim('non_existing_doc', '..a') + +@pytest.mark.redismod +def test_objkeys_dollar(client): + client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": {"baz":50}}}) + + # Test multi + assert client.json().objkeys('doc1', '$..a') == [["foo", "bar"], None, ["baz"]] + + # Test single + assert client.json().object('doc1', '$.nested1.a') == [["foo", "bar"]] + + # Test legacy + assert client.json().objkeys('doc1', '.*.a') == ["foo", "bar"] + # Test single + assert client.json().objkeys('doc1', '.nested2.a') == ["baz"] + + # Test missing key + assert client.json().objkeys('non_existing_doc', '..a') is None + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().objkeys('doc1', '$.nowhere') + +@pytest.mark.redismod +def test_objlen_dollar(client): + client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": {"baz":50}}}) + # Test multi + assert client.json().objlen('doc1', '$..a') == [2, None, 1] + # Test single + assert client.json().objlen('doc1', '$.nested1.a') == [2] + + # Test missing key + assert client.json().objlen('non_existing_doc', '$..a') is None + + # Test missing path + with pytest.raises(exceptions.DataError): + client.json().objlen('doc1', '$.nowhere') + + + # Test legacy + assert client.json().objlen('doc1', '.*.a') == 2 + + # Test single + assert client.json().objlen('doc1', '.nested2.a') == 1 + + # Test missing key + assert client.json.objlen('non_existing_doc', '..a') is None + + # Test missing path + with pytest.raises(exceptions.DataError): + client.json().objlen('doc1', '.nowhere') + +@pytest.mark.redismod +def load_types_data(nested_key_name): + types_data = { + 'object': {}, + 'array': [], + 'string': 'str', + 'integer': 42, + 'number': 1.2, + 'boolean': False, + 'null': None, + + } + jdata = {} + types = [] + for i, (k, v) in zip(range(1, len(types_data) + 1), iter(types_data.items())): + jdata["nested" + str(i)] = {nested_key_name: v} + types.append(k) + + return jdata, types + +@pytest.mark.redismod +def test_type_dollar(client): + jdata, jtypes = load_types_data('a') + client.json().set('doc1', '$', jdata) + # Test multi + assert client.json().type('JSON.TYPE', 'doc1', '$..a') == jtypes + + # Test single + assert client.json().type('doc1', '$.nested2.a') == [jtypes[1]] + + # Test legacy + assert client.json().type('doc1', '..a') == jtypes[0] + # Test missing path (defaults to root) + assert client.json().type('doc1') == 'object' + + # Test missing key + assert client.json().type('non_existing_doc', '..a') is None + +@pytest.mark.redismod +def test_clear_dollar(client): + + client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": "claro"}, "nested3": {"a": {"baz":50}}}) + # Test multi + assert client.json().clear('doc1', '$..a') == 3 + + assert client.json().get('doc1', '$') == \ + [{"nested1": {"a": {}}, "a": [], "nested2": {"a": "claro"}, "nested3": {"a": {}}}] + + # Test single + client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": "claro"}, "nested3": {"a": {"baz":50}}}) + assert client.json().clear('doc1', '$.nested1.a') == 1 + assert client.json().get('doc1', '$') == \ + [{"nested1": {"a": {}}, "a": ["foo"], "nested2": {"a": "claro"}, "nested3": {"a": {"baz": 50}}}] + + # Test missing path (defaults to root) + assert client.json().clear('doc1') == 1 + assert client.json().get('doc1', '$') == [{}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().clear('non_existing_doc', '$..a') + +@pytest.mark.redismod +def test_toggle_dollar(client): + client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": False}, "nested2": {"a": 31}, "nested3": {"a": True}}) + # Test multi + assert client.json().toggle('doc1', '$..a') == [None, 1, None, 0] + assert client.json().get('doc1', '$') == \ + [{"a": ["foo"], "nested1": {"a": True}, "nested2": {"a": 31}, "nested3": {"a": False}}] + + # Test single + assert client.json().toggle('doc1', '$.nested1.a') == [0] + assert client.json().get('JSON.GET', 'doc1', '$') == \ + [{"a": ["foo"], "nested1": {"a": False}, "nested2": {"a": 31}, "nested3": {"a": False}}] + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().toggle('non_existing_doc', '$..a') + +@pytest.mark.redismod +def test_debug_dollar(client): + + jdata, jtypes = load_types_data('a') + + client.json().set('doc1', '$', jdata) + + # Test multi + assert client.json().debug('MEMORY', 'doc1', '$..a') == \ + [72, 24, 24, 16, 16, 1, 0] + + # Test single + assert client.json().debug('MEMORY', 'doc1', '$.nested2.a') == [24] + + # Test legacy + assert client.json().debug('MEMORY', 'doc1', '..a') == 72 + + # Test missing path (defaults to root) + assert client.json().debug('MEMORY', 'doc1') == 72 + + # Test missing key + with pytest.raises(exceptions.DataError): + client.json().debug('non_existing_doc', '$..a') \ No newline at end of file diff --git a/tests/testdata/jsontestdata.py b/tests/testdata/jsontestdata.py new file mode 100644 index 0000000..744fe21 --- /dev/null +++ b/tests/testdata/jsontestdata.py @@ -0,0 +1,617 @@ +nested_large_key = r""" +{ + "jkra": [ + 154, + 4472, + [ + 8567, + false, + 363.84, + 5276, + "ha", + "rizkzs", + 93 + ], + false + ], + "hh": 20.77, + "mr": 973.217, + "ihbe": [ + 68, + [ + true, + { + "lqe": [ + 486.363, + [ + true, + { + "mp": { + "ory": "rj", + "qnl": "tyfrju", + "hf": null + }, + "uooc": 7418, + "xela": 20, + "bt": 7014, + "ia": 547, + "szec": 68.73 + }, + null + ], + 3622, + "iwk", + null + ], + "fepi": 19.954, + "ivu": { + "rmnd": 65.539, + "bk": 98, + "nc": "bdg", + "dlb": { + "hw": { + "upzz": [ + true, + { + "nwb": [ + 4259.47 + ], + "nbt": "yl" + }, + false, + false, + 65, + [ + [ + [], + 629.149, + "lvynqh", + "hsk", + [], + 2011.932, + true, + [] + ], + null, + "ymbc", + null + ], + "aj", + 97.425, + "hc", + 58 + ] + }, + "jq": true, + "bi": 3333, + "hmf": "pl", + "mrbj": [ + true, + false + ] + } + }, + "hfj": "lwk", + "utdl": "aku", + "alqb": [ + 74, + 534.389, + 7235, + [ + null, + false, + null + ] + ] + }, + null, + { + "lbrx": { + "vm": "ubdrbb" + }, + "tie": "iok", + "br": "ojro" + }, + 70.558, + [ + { + "mmo": null, + "dryu": null + } + ] + ], + true, + null, + false, + { + "jqun": 98, + "ivhq": [ + [ + [ + 675.936, + [ + 520.15, + 1587.4, + false + ], + "jt", + true, + { + "bn": null, + "ygn": "cve", + "zhh": true, + "aak": 9165, + "skx": true, + "qqsk": 662.28 + }, + { + "eio": 9933.6, + "agl": null, + "pf": false, + "kv": 5099.631, + "no": null, + "shly": 58 + }, + [ + null, + [ + "uiundu", + 726.652, + false, + 94.92, + 259.62, + { + "ntqu": null, + "frv": null, + "rvop": "upefj", + "jvdp": { + "nhx": [], + "bxnu": {}, + "gs": null, + "mqho": null, + "xp": 65, + "ujj": {} + }, + "ts": false, + "kyuk": [ + false, + 58, + {}, + "khqqif" + ] + }, + 167, + true, + "bhlej", + 53 + ], + 64, + { + "eans": "wgzfo", + "zfgb": 431.67, + "udy": [ + { + "gnt": [], + "zeve": {} + }, + { + "pg": {}, + "vsuc": {}, + "dw": 19, + "ffo": "uwsh", + "spk": "pjdyam", + "mc": [], + "wunb": {}, + "qcze": 2271.15, + "mcqx": null + }, + "qob" + ], + "wo": "zy" + }, + { + "dok": null, + "ygk": null, + "afdw": [ + 7848, + "ah", + null + ], + "foobar": 3.141592, + "wnuo": { + "zpvi": { + "stw": true, + "bq": {}, + "zord": true, + "omne": 3061.73, + "bnwm": "wuuyy", + "tuv": 7053, + "lepv": null, + "xap": 94.26 + }, + "nuv": false, + "hhza": 539.615, + "rqw": { + "dk": 2305, + "wibo": 7512.9, + "ytbc": 153, + "pokp": null, + "whzd": null, + "judg": [], + "zh": null + }, + "bcnu": "ji", + "yhqu": null, + "gwc": true, + "smp": { + "fxpl": 75, + "gc": [], + "vx": 9352.895, + "fbzf": 4138.27, + "tiaq": 354.306, + "kmfb": {}, + "fxhy": [], + "af": 94.46, + "wg": {}, + "fb": null + } + }, + "zvym": 2921, + "hhlh": [ + 45, + 214.345 + ], + "vv": "gqjoz" + }, + [ + "uxlu", + null, + "utl", + 64, + [ + 2695 + ], + [ + false, + null, + [ + "cfcrl", + [], + [], + 562, + 1654.9, + {}, + null, + "sqzud", + 934.6 + ], + { + "hk": true, + "ed": "lodube", + "ye": "ziwddj", + "ps": null, + "ir": {}, + "heh": false + }, + true, + 719, + 50.56, + [ + 99, + 6409, + null, + 4886, + "esdtkt", + {}, + null + ], + [ + false, + "bkzqw" + ] + ], + null, + 6357 + ], + { + "asvv": 22.873, + "vqm": { + "drmv": 68.12, + "tmf": 140.495, + "le": null, + "sanf": [ + true, + [], + "vyawd", + false, + 76.496, + [], + "sdfpr", + 33.16, + "nrxy", + "antje" + ], + "yrkh": 662.426, + "vxj": true, + "sn": 314.382, + "eorg": null + }, + "bavq": [ + 21.18, + 8742.66, + { + "eq": "urnd" + }, + 56.63, + "fw", + [ + {}, + "pjtr", + null, + "apyemk", + [], + [], + false, + {} + ], + { + "ho": null, + "ir": 124, + "oevp": 159, + "xdrv": 6705, + "ff": [], + "sx": false + }, + true, + null, + true + ], + "zw": "qjqaap", + "hr": { + "xz": 32, + "mj": 8235.32, + "yrtv": null, + "jcz": "vnemxe", + "ywai": [ + null, + 564, + false, + "vbr", + 54.741 + ], + "vw": 82, + "wn": true, + "pav": true + }, + "vxa": 881 + }, + "bgt", + "vuzk", + 857 + ] + ] + ], + null, + null, + { + "xyzl": "nvfff" + }, + true, + 13 + ], + "npd": null, + "ha": [ + [ + "du", + [ + 980, + { + "zdhd": [ + 129.986, + [ + "liehns", + 453, + { + "fuq": false, + "dxpn": {}, + "hmpx": 49, + "zb": "gbpt", + "vdqc": null, + "ysjg": false, + "gug": 7990.66 + }, + "evek", + [ + {} + ], + "dfywcu", + 9686, + null + ] + ], + "gpi": { + "gt": { + "qe": 7460, + "nh": "nrn", + "czj": 66.609, + "jwd": true, + "rb": "azwwe", + "fj": { + "csn": true, + "foobar": 1.61803398875, + "hm": "efsgw", + "zn": "vbpizt", + "tjo": 138.15, + "teo": {}, + "hecf": [], + "ls": false + } + }, + "xlc": 7916, + "jqst": 48.166, + "zj": "ivctu" + }, + "jl": 369.27, + "mxkx": null, + "sh": [ + true, + 373, + false, + "sdis", + 6217, + { + "ernm": null, + "srbo": 90.798, + "py": 677, + "jgrq": null, + "zujl": null, + "odsm": { + "pfrd": null, + "kwz": "kfvjzb", + "ptkp": false, + "pu": null, + "xty": null, + "ntx": [], + "nq": 48.19, + "lpyx": [] + }, + "ff": null, + "rvi": [ + "ych", + {}, + 72, + 9379, + 7897.383, + true, + {}, + 999.751, + false + ] + }, + true + ], + "ghe": [ + 24, + { + "lpr": true, + "qrs": true + }, + true, + false, + 7951.94, + true, + 2690.54, + [ + 93, + null, + null, + "rlz", + true, + "ky", + true + ] + ], + "vet": false, + "olle": null + }, + "jzm", + true + ], + null, + null, + 19.17, + 7145, + "ipsmk" + ], + false, + { + "du": 6550.959, + "sps": 8783.62, + "nblr": { + "dko": 9856.616, + "lz": { + "phng": "dj" + }, + "zeu": 766, + "tn": "dkr" + }, + "xa": "trdw", + "gn": 9875.687, + "dl": null, + "vuql": null + }, + { + "qpjo": null, + "das": { + "or": { + "xfy": null, + "xwvs": 4181.86, + "yj": 206.325, + "bsr": [ + "qrtsh" + ], + "wndm": { + "ve": 56, + "jyqa": true, + "ca": null + }, + "rpd": 9906, + "ea": "dvzcyt" + }, + "xwnn": 9272, + "rpx": "zpr", + "srzg": { + "beo": 325.6, + "sq": null, + "yf": null, + "nu": [ + 377, + "qda", + true + ], + "sfz": "zjk" + }, + "kh": "xnpj", + "rk": null, + "hzhn": [ + null + ], + "uio": 6249.12, + "nxrv": 1931.635, + "pd": null + }, + "pxlc": true, + "mjer": false, + "hdev": "msr", + "er": null + }, + "ug", + null, + "yrfoix", + 503.89, + 563 + ], + "tcy": 300, + "me": 459.17, + "tm": [ + 134.761, + "jcoels", + null + ], + "iig": 945.57, + "ad": "be" + }, + "ltpdm", + null, + 14.53 + ], + "xi": "gxzzs", + "zfpw": 1564.87, + "ow": null, + "tm": [ + 46, + 876.85 + ], + "xejv": null +} +""" \ No newline at end of file -- cgit v1.2.1