summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2011-10-25 11:31:53 +0200
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2011-10-25 11:31:53 +0200
commit79ab0a667e9d9d11cc1de0f3ed21a37f5c2909ee (patch)
treedefc8568b03b974ec7b306f9e32dab38d97951e9
Long live QtJsonDb!
-rw-r--r--.gitignore32
-rw-r--r--doc/JsonDB-Client.txt106
-rw-r--r--doc/JsonDB-CommandLine-Client.txt37
-rw-r--r--doc/JsonDB-Protocol.txt293
-rw-r--r--doc/doc.pri15
-rw-r--r--doc/drafts/viewsystem.txt176
-rw-r--r--doc/images/example-simplelistmodel.pngbin0 -> 27553 bytes
-rw-r--r--doc/jsondb-dita.qdocconf25
-rw-r--r--doc/jsondb.qdocconf70
-rw-r--r--doc/src/example-desktop-inspector.qdoc7
-rw-r--r--doc/src/example-simplelistmodel.qdoc7
-rw-r--r--doc/src/expression-examples.qdoc112
-rw-r--r--doc/src/index.qdoc106
-rw-r--r--doc/style/style.css137
-rw-r--r--examples/declarative/desktop-inspector/README.txt8
-rw-r--r--examples/declarative/desktop-inspector/content/Button.qml68
-rw-r--r--examples/declarative/desktop-inspector/content/Dialog.qml92
-rw-r--r--examples/declarative/desktop-inspector/content/Editor.qml131
-rw-r--r--examples/declarative/desktop-inspector/content/Generic.qml142
-rw-r--r--examples/declarative/desktop-inspector/content/Header.qml68
-rw-r--r--examples/declarative/desktop-inspector/content/inspector.js264
-rw-r--r--examples/declarative/desktop-inspector/desktop-inspector.qml627
-rw-r--r--examples/declarative/desktop-inspector/desktop-inspector.qmlproject16
-rw-r--r--examples/declarative/simplelistmodel/content/Button.qml69
-rw-r--r--examples/declarative/simplelistmodel/simplelistmodel.qml147
-rw-r--r--examples/declarative/simplelistmodel/simplelistmodel.qmlproject16
-rw-r--r--jsondb.pro20
-rw-r--r--modules/qt_jsondb.pri16
-rw-r--r--modules/qt_jsondb_qson.pri16
-rw-r--r--src/3rdparty/3rdparty.pro2
-rw-r--r--src/3rdparty/btree/btree.pri11
-rw-r--r--src/3rdparty/btree/compat/sys/queue.h527
-rw-r--r--src/3rdparty/btree/compat/sys/tree.h738
-rw-r--r--src/3rdparty/btree/src/btree.cpp3784
-rw-r--r--src/3rdparty/btree/src/btree.h140
-rw-r--r--src/3rdparty/qjson/README18
-rw-r--r--src/3rdparty/qjson/TODO2
-rw-r--r--src/3rdparty/qjson/benchmark/benchmark.pro12
-rw-r--r--src/3rdparty/qjson/benchmark/main.cpp75
-rw-r--r--src/3rdparty/qjson/benchmark/numbers.json19
-rw-r--r--src/3rdparty/qjson/benchmark/test.json66
-rw-r--r--src/3rdparty/qjson/json.pro4
-rw-r--r--src/3rdparty/qjson/qjson.pri1
-rw-r--r--src/3rdparty/qjson/src/json.cpp432
-rw-r--r--src/3rdparty/qjson/src/json.g420
-rw-r--r--src/3rdparty/qjson/src/json.h58
-rw-r--r--src/3rdparty/qjson/src/json.pri4
-rw-r--r--src/3rdparty/qjson/src/jsonparser.cpp527
-rw-r--r--src/3rdparty/qjson/tests/data/non-latin1.json4
-rw-r--r--src/3rdparty/qjson/tests/data/non-latin1.json.ref4
-rw-r--r--src/3rdparty/qjson/tests/data/test.html72
-rw-r--r--src/3rdparty/qjson/tests/data/test.json60
-rw-r--r--src/3rdparty/qjson/tests/data/test.json.ref57
-rw-r--r--src/3rdparty/qjson/tests/data/test_utf-16le-nobom.jsonbin0 -> 2894 bytes
-rw-r--r--src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json.refbin0 -> 2808 bytes
-rw-r--r--src/3rdparty/qjson/tests/data/test_utf-16le.jsonbin0 -> 2896 bytes
-rw-r--r--src/3rdparty/qjson/tests/data/test_utf-16le.json.refbin0 -> 2808 bytes
-rw-r--r--src/3rdparty/qjson/tests/data/test_utf-32le.jsonbin0 -> 5792 bytes
-rw-r--r--src/3rdparty/qjson/tests/data/test_utf-32le.json.refbin0 -> 5616 bytes
-rw-r--r--src/3rdparty/qjson/tests/tests.pro13
-rw-r--r--src/3rdparty/qjson/tests/tst_json.cpp202
-rw-r--r--src/client/client.pro32
-rw-r--r--src/client/jsondb-client.cpp623
-rw-r--r--src/client/jsondb-client.h118
-rw-r--r--src/client/jsondb-client_p.h99
-rw-r--r--src/client/jsondb-connection.cpp621
-rw-r--r--src/client/jsondb-connection_p.h132
-rw-r--r--src/client/jsondb-error.cpp96
-rw-r--r--src/client/jsondb-error.h77
-rw-r--r--src/client/jsondb-global.h65
-rw-r--r--src/client/jsondb-oneshot.cpp46
-rw-r--r--src/client/jsondb-oneshot_p.h109
-rw-r--r--src/client/jsondb-strings_p.h106
-rw-r--r--src/common/common.pri18
-rw-r--r--src/common/jsondb-error.h1
-rw-r--r--src/common/jsondb-global.h1
-rw-r--r--src/common/jsondb-strings.cpp98
-rw-r--r--src/common/jsondb-strings.h1
-rw-r--r--src/common/qsonconversion.cpp98
-rw-r--r--src/common/qsonconversion.h55
-rw-r--r--src/common/qsonstream.cpp151
-rw-r--r--src/common/qsonstream.h85
-rw-r--r--src/daemon/TODO70
-rw-r--r--src/daemon/aodb.cpp569
-rw-r--r--src/daemon/aodb.h170
-rw-r--r--src/daemon/daemon.pri42
-rw-r--r--src/daemon/daemon.pro22
-rw-r--r--src/daemon/dbserver.cpp616
-rw-r--r--src/daemon/dbserver.h112
-rw-r--r--src/daemon/jsondb-map-reduce.cpp757
-rw-r--r--src/daemon/jsondb-map-reduce.h133
-rw-r--r--src/daemon/jsondb-owner.cpp123
-rw-r--r--src/daemon/jsondb-owner.h96
-rw-r--r--src/daemon/jsondb-proxy.cpp164
-rw-r--r--src/daemon/jsondb-proxy.h114
-rw-r--r--src/daemon/jsondb-trace.cpp77
-rw-r--r--src/daemon/jsondb-trace.h55
-rw-r--r--src/daemon/jsondb.cpp1730
-rw-r--r--src/daemon/jsondb.h226
-rw-r--r--src/daemon/jsondb.qrc9
-rw-r--r--src/daemon/jsondbbtreestorage.cpp1846
-rw-r--r--src/daemon/jsondbbtreestorage.h301
-rw-r--r--src/daemon/jsondbindex.cpp334
-rw-r--r--src/daemon/jsondbindex.h131
-rw-r--r--src/daemon/jsondbquery.cpp658
-rw-r--r--src/daemon/jsondbquery.h174
-rw-r--r--src/daemon/main.cpp262
-rw-r--r--src/daemon/notification.cpp80
-rw-r--r--src/daemon/notification.h82
-rw-r--r--src/daemon/objectkey.h96
-rw-r--r--src/daemon/objecttable.cpp587
-rw-r--r--src/daemon/objecttable.h162
-rw-r--r--src/daemon/qsonobjecttypes_impl_p.h335
-rw-r--r--src/daemon/qsonobjecttypes_p.h177
-rw-r--r--src/daemon/schema-validation/checkpoints.h832
-rw-r--r--src/daemon/schema-validation/object.h252
-rw-r--r--src/daemon/schema/Capability.json29
-rw-r--r--src/daemon/schema/Index.json20
-rw-r--r--src/daemon/schema/RootCapability.json14
-rw-r--r--src/daemon/schema/View.json10
-rw-r--r--src/daemon/schema/notification.json12
-rw-r--r--src/daemon/schemamanager_impl_p.h108
-rw-r--r--src/daemon/schemamanager_p.h79
-rw-r--r--src/daemon/signals.cpp123
-rw-r--r--src/daemon/signals.h70
-rw-r--r--src/imports/imports.pro3
-rw-r--r--src/imports/jsondb-listmodel/cuid.cpp65
-rw-r--r--src/imports/jsondb-listmodel/cuid.h55
-rw-r--r--src/imports/jsondb-listmodel/javascript-listmodel.cpp323
-rw-r--r--src/imports/jsondb-listmodel/javascript-listmodel.h99
-rw-r--r--src/imports/jsondb-listmodel/jsondb-listmodel.pro41
-rw-r--r--src/imports/jsondb-listmodel/jsondb-singletonwatcher.cpp110
-rw-r--r--src/imports/jsondb-listmodel/jsondb-singletonwatcher.h95
-rw-r--r--src/imports/jsondb-listmodel/jsondb-watcher.cpp169
-rw-r--r--src/imports/jsondb-listmodel/jsondb-watcher.h88
-rw-r--r--src/imports/jsondb-listmodel/plugin.cpp68
-rw-r--r--src/imports/jsondb-listmodel/plugin.h58
-rw-r--r--src/imports/jsondb-listmodel/qlistmodelinterface_p.h82
-rw-r--r--src/imports/jsondb-listmodel/qlistmodelinterface_p_4.7.0.h85
-rw-r--r--src/imports/jsondb-listmodel/qmldir1
-rw-r--r--src/imports/jsondb-listmodel/qmldir_debug1
-rw-r--r--src/imports/jsondb/jsondb-component.cpp437
-rw-r--r--src/imports/jsondb/jsondb-component.h167
-rw-r--r--src/imports/jsondb/jsondb-listmodel.cpp1323
-rw-r--r--src/imports/jsondb/jsondb-listmodel.h156
-rw-r--r--src/imports/jsondb/jsondb-listmodel_p.h164
-rw-r--r--src/imports/jsondb/jsondb.pro33
-rw-r--r--src/imports/jsondb/plugin.cpp71
-rw-r--r--src/imports/jsondb/plugin.h58
-rw-r--r--src/imports/jsondb/qmldir1
-rw-r--r--src/imports/jsondb/qmldir_debug1
-rw-r--r--src/imports/qimportbase.pri37
-rw-r--r--src/qson/README.txt194
-rw-r--r--src/qson/qson.cpp210
-rw-r--r--src/qson/qson.pro43
-rw-r--r--src/qson/qson_p.h94
-rw-r--r--src/qson/qsonelement.cpp111
-rw-r--r--src/qson/qsonelement_p.h105
-rw-r--r--src/qson/qsonglobal.h52
-rw-r--r--src/qson/qsonlist.cpp472
-rw-r--r--src/qson/qsonlist_p.h122
-rw-r--r--src/qson/qsonmap.cpp958
-rw-r--r--src/qson/qsonmap_p.h169
-rw-r--r--src/qson/qsonobject.cpp163
-rw-r--r--src/qson/qsonobject_p.h276
-rw-r--r--src/qson/qsonpage.cpp615
-rw-r--r--src/qson/qsonpage_p.h161
-rw-r--r--src/qson/qsonparser.cpp264
-rw-r--r--src/qson/qsonparser_p.h108
-rw-r--r--src/qson/qsonstrings.cpp58
-rw-r--r--src/qson/qsonstrings_p.h69
-rw-r--r--src/qson/qsonuuid.cpp75
-rw-r--r--src/qson/qsonuuid_p.h64
-rw-r--r--src/qson/qsonversion.cpp142
-rw-r--r--src/qson/qsonversion_p.h87
-rw-r--r--src/src.pro4
-rw-r--r--sync.profile29
-rw-r--r--tests/auto/auto.pro8
-rw-r--r--tests/auto/bdb/bdb.pro18
-rw-r--r--tests/auto/bdb/tst_jsondb_bdb.cpp919
-rw-r--r--tests/auto/client/.gitignore1
-rw-r--r--tests/auto/client/client.pro17
-rw-r--r--tests/auto/client/create-test.json14
-rw-r--r--tests/auto/client/test-jsondb-client.cpp1204
-rw-r--r--tests/auto/common/common.pro17
-rw-r--r--tests/auto/common/test-common.cpp1536
-rw-r--r--tests/auto/daemon/array.json116
-rw-r--r--tests/auto/daemon/capabilities-test.json37
-rw-r--r--tests/auto/daemon/daemon.pro22
-rw-r--r--tests/auto/daemon/json-validation.qrc5
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-schema.json12
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrLess-empty-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrLess-five-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrLess-two-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrMore-empty-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrMore-five-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrMore-one-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-boundaries-twoOrMore-two-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-empty-empty-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-empty-mixed-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-empty-numbers-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-number-empty-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-number-highnumbers-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-number-mixed-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-number-numbers-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-number-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-number-string-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-object-empty-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-object-missingfoo-valid.json7
-rw-r--r--tests/auto/daemon/json-validation/array-items-object-missingid-invalid.json7
-rw-r--r--tests/auto/daemon/json-validation/array-items-object-numbers-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-object-std-valid.json7
-rw-r--r--tests/auto/daemon/json-validation/array-items-object-strings-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/array-items-schema.json24
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-one-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-two-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-zero-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-one-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-two-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-zero-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-one-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-two-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-one-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-two-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-zero-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/integer-boundaries-schema.json22
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-one-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-two-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-zero-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-one-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-two-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-zero-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-one-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-two-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-zero-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-one-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-two-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-zero-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/numbers-boundaries-schema.json22
-rw-r--r--tests/auto/daemon/json-validation/required-missing-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/required-nested-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/required-notimportent-number-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/required-number-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/required-object-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/required-schema.json12
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-max5chars-silo-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-max5chars-silos-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-max5chars-toolong-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-min5chars-silo-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-min5chars-silos-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-min5chars-toolong-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-pattern-a-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-pattern-aaa-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-pattern-ab-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/string-boundaries-schema.json19
-rw-r--r--tests/auto/daemon/json-validation/type-array-array-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-array-bool-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-array-integer-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-array-number-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-array-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-array-string-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-array-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-false-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-integer-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-number-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-string-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-bool-true-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-integer-array-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-integer-bool-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-integer-double-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-integer-integer-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-integer-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-integer-string-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-mixed-array-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-mixed-double-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-mixed-number-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-mixed-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-mixed-string-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-number-array-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-number-bool-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-number-double-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-number-number-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-number-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-number-string-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-object-array-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-object-bool-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-object-double-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-object-number-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-object-object-valid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-object-string-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-schema.json33
-rw-r--r--tests/auto/daemon/json-validation/type-string-array-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-string-bool-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-string-double-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-string-integer-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-string-object-invalid.json1
-rw-r--r--tests/auto/daemon/json-validation/type-string-string-valid.json1
-rw-r--r--tests/auto/daemon/largeContactsTest.json1002
-rw-r--r--tests/auto/daemon/largeContactsTest10k.json10002
-rw-r--r--tests/auto/daemon/largeContactsTest1k.json1002
-rw-r--r--tests/auto/daemon/largeContactsTest33k.json33290
-rw-r--r--tests/auto/daemon/map-join-sourceuuids.json60
-rw-r--r--tests/auto/daemon/map-join.json77
-rw-r--r--tests/auto/daemon/map-reduce-schema.json92
-rw-r--r--tests/auto/daemon/map-reduce.json74
-rw-r--r--tests/auto/daemon/map-sametarget.json62
-rw-r--r--tests/auto/daemon/pk-capability.json12
-rw-r--r--tests/auto/daemon/reduce-array.json52
-rw-r--r--tests/auto/daemon/reduce-data.json62
-rw-r--r--tests/auto/daemon/reduce-subprop.json58
-rw-r--r--tests/auto/daemon/reduce.json23
-rw-r--r--tests/auto/daemon/schemas/TestView.json10
-rw-r--r--tests/auto/daemon/schemas/address.json17
-rw-r--r--tests/auto/daemon/schemas/contact.json18
-rw-r--r--tests/auto/daemon/schemas/ephemeral.json19
-rw-r--r--tests/auto/daemon/testjsondb.cpp3924
-rw-r--r--tests/auto/jsondb-listmodel/jsondb-listmodel.pro23
-rw-r--r--tests/auto/jsondb-listmodel/list-objects.json39
-rw-r--r--tests/auto/jsondb-listmodel/test-jsondb-listmodel.cpp803
-rw-r--r--tests/auto/jsondb-listmodel/test-jsondb-listmodel.h147
-rw-r--r--tests/auto/qsonstream/qsonstream.pro12
-rw-r--r--tests/auto/qsonstream/test-qsonstream.cpp117
-rw-r--r--tests/auto/tests.xml31
-rw-r--r--tests/benchmarks/benchmarks.pro2
-rw-r--r--tests/benchmarks/client/client-benchmark.cpp490
-rw-r--r--tests/benchmarks/client/client-benchmark.h95
-rw-r--r--tests/benchmarks/client/client.pro25
-rw-r--r--tests/benchmarks/daemon/bench_daemon.cpp986
-rw-r--r--tests/benchmarks/daemon/daemon.pro19
-rw-r--r--tests/benchmarks/jsondb-listmodel/jsondb-listmodel.pro23
-rw-r--r--tests/benchmarks/jsondb-listmodel/listmodel-benchmark.cpp582
-rw-r--r--tests/benchmarks/jsondb-listmodel/listmodel-benchmark.h126
-rw-r--r--tests/benchmarks/tests.xml19
-rw-r--r--tests/manual/bits/bits.pro11
-rwxr-xr-xtests/manual/bits/build.sh7
-rw-r--r--tests/manual/bits/main.cpp111
-rw-r--r--tests/shared/clientwrapper.cpp1
-rw-r--r--tests/shared/clientwrapper.h134
-rw-r--r--tests/shared/shared.pri4
-rw-r--r--tests/shared/util.h105
-rw-r--r--tests/tests.pro3
-rw-r--r--tools/adb-dump/adb-dump.pro19
-rw-r--r--tools/adb-dump/main.cpp82
-rw-r--r--tools/aodbread/aodbread.pro19
-rw-r--r--tools/aodbread/main.cpp303
-rw-r--r--tools/jsondb-client/client.cpp501
-rw-r--r--tools/jsondb-client/client.h115
-rw-r--r--tools/jsondb-client/jsondb-client.pro16
-rw-r--r--tools/jsondb-client/main.cpp118
-rw-r--r--tools/tools.pro3
351 files changed, 92126 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..ff9987bd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+.rcc
+*~
+*.o
+*.moc
+*.a
+*.so
+*.so.[0-9]
+*.so.[0-9].[0-9]
+*.so.[0-9].[0-9].[0-9]
+*.dylib
+*.dylib.[0-9]
+*.dylib.[0-9].[0-9]
+*.dylib.[0-9].[0-9].[0-9]
+.moc
+.obj
+Makefile
+Makefile.Debug
+Makefile.Release
+moc_*.cpp
+obj_*
+qrc_*
+*.app
+lib
+config.pri
+.qmake.cache
+/include
+*.pro.user
+.DS_Store
+tests/*/*/tst_*
+/bin/
+/module-paths/
+src/client/qtaddonjsondbversion.h \ No newline at end of file
diff --git a/doc/JsonDB-Client.txt b/doc/JsonDB-Client.txt
new file mode 100644
index 00000000..e4516c4f
--- /dev/null
+++ b/doc/JsonDB-Client.txt
@@ -0,0 +1,106 @@
+JsonDB Client Library classes
+=============================
+
+
+The JsonDB wire protocol is serialized QVariant objects. The
+VariantStream class handles the serialization.
+
+
+JsonDbConnection
+================
+
+The JsonDbConnection class encapsulates a single database connection.
+A database connection can be to a local unix socket or a remote TCP
+socket. By default, the local socket used will be "jsondb".
+
+Each connection can have a security token. The security token must be
+set before the connection to the database is made. When the
+connection is made, the first message sent to the database informs the
+database of the security token.
+
+For example:
+
+ JsonDbConnection *connection = new JsonDbConnection;
+ connection->setToken("MyMagicToken");
+ connection->connectToServer("jsondb-test");
+
+or
+
+ JsonDbConnection *connection = new JsonDbConnection;
+ connection->setToken("AnotherToken");
+ connection->connectToHost( "testserver.nrcc.noklab.com", 8801 );
+
+
+In most instances you will be connecting to the "jsondb" server on the
+local machine. The static function "instance()" can be used to
+automatically retrieve the default connection. For example:
+
+ JsonDbConnection::setDefaultToken( "MagicToken" ); // Set this once
+ ...
+
+ JsonDbConnection *connection = JsonDbConnection::instance();
+
+The first use of instance() will create a singleton connection object
+and connect it to the local database.
+
+
+To use the JsonDbConnection, you first connect to the "response",
+"error" and optionally "notified" signals. Then create a request
+object. The common request objects are provided through static
+convenience functions: makeFindRequest, makeQueryRequest, etc. The
+"request" member function issues the database command and returns a
+request id. Eventually either a reponse or error signal will be
+returned with that id.
+
+
+There are two static convenience functions for issuing a quick request
+and getting a direct answer.
+
+The "oneShot" static function makes a single request. The response
+and error signal handling slots are connected just for the duration of
+the call. For example:
+
+ JsonDbConnection *conn = JsonDbConnection::instance();
+ conn->oneShot(JsonDbRequest::makeQueryRequest("[?_type=\"IMAGE\"]"),
+ this, SLOT(handleOneShot(const QVariant&)));
+
+The "handleOneShot()" function will be called with the result of the
+query. If you want to catch errors, pass an error function as well.
+Note: you don't have to pass any slots, in which case the result will
+be ignored.
+
+The "sync" static function makes a single request and blocks until a
+result is obtained. You should not use this function in interactive
+or time-critical code. For example:
+
+ QVariant result = JsonDbConnection::instance()->sync(
+ JsonDbConnection::makeQueryRequest("[?_type=\"TURTLE\"]"));
+
+
+============
+JsonDbClient
+============
+
+The challenge with a JsonDbConnection object is that a single process
+may have several elements using the connection simultaneously. Which
+means that the responses coming back from the database need to be
+de-multiplexed. The JsonDbClient object handles the demultiplexing.
+
+Most client code should use JsonDbClient objects directly and avoid
+using the JsonDbConnection objects.
+
+Typical use:
+
+ JsonDbClient client; // Constructs a client of the
+ // JsonDbConnection->instance() object
+
+ connect(&client, SIGNAL(response(int,const QVariant&)),
+ this, SLOT(handleResponse(int, const QVariant&)));
+ int id = client.query("[?_type=\"Toad\"]);
+
+
+The JsonDbClient object has convenience member functions "find",
+"query", "create", "update", and "remove" which wrap appropriate
+JsonDbConnection::makeXXXRequest function calls and issue the request.
+
+
diff --git a/doc/JsonDB-CommandLine-Client.txt b/doc/JsonDB-CommandLine-Client.txt
new file mode 100644
index 00000000..b07e2e7c
--- /dev/null
+++ b/doc/JsonDB-CommandLine-Client.txt
@@ -0,0 +1,37 @@
+jclient is a thin wrapper for testing the jsondb database.
+
+You must specify fairly accurately formated JSON objects to get the
+database to respond.
+
+Here's a sample session:
+
+jclient> create {"name":"Fred", "type":"CONTACT"}
+Received message: {"error" : null,"id" : 0,"result" : {"id" : "{b2c9c712-1ba3-41fd-a454-51c120ce1c8c}"}}
+
+jclient> notify {"query":"[?type='CONTACT']","actions":["create"]}
+Received message: {"error" : null,"id" : 1,"result" : {"active" : true}}
+
+jclient> create {"name":"Wilma","type":"CONTACT"}
+Received message: {"error" : null,"id" : 2,"result" : {"id" : "{35275206-e875-4c5d-a7b9-6cfd1cac67c2}"}}
+Received message: {"id" : 1,"notify" : {"action" : "create","object" : {"id" : "{35275206-e875-4c5d-a7b9-6cfd1cac67c2}","name" : "Wilma","type" : "CONTACT"}}}
+
+jclient> create {"name":"Quarry", "type":"LOCATION"}
+Received message: {"error" : null,"id" : 3,"result" : {"id" : "{0eba3c55-48ac-433a-833c-ca1a8c5c395d}"}}
+
+jclient> find {"query":".*"}
+Received message: {"error" : null,"id" : 4,"result" : {"data" : [{"id" : "{b2c9c712-1ba3-41fd-a454-51c120ce1c8c}","name" : "Fred","type" : "CONTACT"},{"id" : "{35275206-e875-4c5d-a7b9-6cfd1cac67c2}","name" : "Wilma","type" : "CONTACT"},{"id" : "{0eba3c55-48ac-433a-833c-ca1a8c5c395d}","name" : "Quarry","type" : "LOCATION"}],"length" : 3,"offset" : 0}}
+
+jclient> find {"query":"[?type~'location']"}
+Received message: {"error" : null,"id" : 5,"result" : {"data" : [{"id" : "{0eba3c55-48ac-433a-833c-ca1a8c5c395d}","name" : "Quarry","type" : "LOCATION"}],"length" : 1,"offset" : 0}}
+
+jclient> update {"name":"Fred Flintstone", "type":"CONTACT", "id":"{b2c9c712-1ba3-41fd-a454-51c120ce1c8c}"}
+Received message: {"error" : null,"id" : 9,"result" : null}
+
+jclient> find {"query":"[?type='CONTACT']"}
+Received message: {"error" : null,"id" : 10,"result" : {"data" : [{"id" : "{b2c9c712-1ba3-41fd-a454-51c120ce1c8c}","name" : "Fred Flintstone","type" : "CONTACT"},{"id" : "{35275206-e875-4c5d-a7b9-6cfd1cac67c2}","name" : "Wilma","type" : "CONTACT"}],"length" : 2,"offset" : 0}}
+
+jclient> delete {"id":"{35275206-e875-4c5d-a7b9-6cfd1cac67c2}"}
+Received message: {"error" : null,"id" : 11,"result" : null}
+
+jclient> find {"query":".*"}
+Received message: {"error" : null,"id" : 13,"result" : {"data" : [{"id" : "{b2c9c712-1ba3-41fd-a454-51c120ce1c8c}","name" : "Fred Flintstone","type" : "CONTACT"},{"id" : "{0eba3c55-48ac-433a-833c-ca1a8c5c395d}","name" : "Quarry","type" : "LOCATION"}],"length" : 2,"offset" : 0}}
diff --git a/doc/JsonDB-Protocol.txt b/doc/JsonDB-Protocol.txt
new file mode 100644
index 00000000..981660b1
--- /dev/null
+++ b/doc/JsonDB-Protocol.txt
@@ -0,0 +1,293 @@
+The "jsondb" program is a simplified key-value store for JSON
+objects.
+
+By default, data is stored in the current directory in 'database.db' file.
+
+
+Other programs communicate with jsondb over a local socket
+connection. A remote database command is invoked by sending a request
+to the jsondb service. The request is a single object serialized used
+JSON.
+
+It has three properties:
+
+ 'action' - A string containing the action name
+ 'object' - The JSON object being acted upon
+ 'id' - An opaque request id. This will be returned to the caller.
+
+Each request generates a single response. The response object has
+three properties:
+
+ 'result' - The result object (depends on the action)
+ 'error' - An error object. Null if there was no error
+ 'id' - The id that was passed in the original request.
+
+Notification objects can be sent from the server. They contain
+
+ 'notify' - Information about the object that fired the notification
+ '_uuid' - The ID of the notification object
+
+
+===========================================================================
+Authentication
+===========================================================================
+
+Action: Token
+
+ Sets the security token for this session. The security token is an
+ opaque string object.
+
+ { action:"token", object:"XXXYYYZZZ", id: 1000 }
+
+ ---> { result:null, error:null, id:1000 }
+
+===========================================================================
+Database manipulation
+===========================================================================
+
+Action: Create
+
+ Adds the object to the database. The object will be assigned a
+ unique '_uuid' field (if it already has one, it will be replaced).
+ The result object will contain just the new '_uuid' field. For
+ example:
+
+ { action:"create", object:{ name:"Fred"}, id:1000}
+
+ ---> { result:{_uuid:"1001-2022-3242323", _version:1}, error:null, id:1000 }
+
+ It is also valid to pass a list as the object, in which case
+ a series of objects will be created. For example:
+
+ { action:"create", object: [{name:"Joe"},{name:"Sam"}], id:1000}
+
+ ----> { result: {[{_uuid: "1001-2002", _version:"1"},
+ {_uuid: "1001-2003", _version:"1"}]}, error: null, id: 1000 }
+
+
+Action: Update
+
+ Update the object in the database. The object must contain a valid
+ '_uuid' field. The result object will be null. For example:
+
+ Current: { _uuid:"1001-2002", _version:1, firstname:"Fred", lastname:"Flintstone", age:30 }
+
+ { action:"update",
+ object:{ _uuid:"1001-2002",
+ _version:1,
+ firstname:"Barney",
+ lastname:"Rubble" },
+ id:1000}
+
+ ---> { result:{ count: 1
+ _uuid:"1001-2002"
+ version:2
+ parent:parent },
+ error:null,
+ id:1000}
+ Current: { _uuid:"1001-2002", firstname:"Barney", lastname:"Rubble"}
+ Updating an object replaces all its properties.
+
+ As with Create, is is valid to pass a list of objects.
+
+
+Action: Remove
+
+ Remove the object from the database. The object only must contain
+ a valid '_uuid' field (everything else is optional). For example
+
+ Current: { _uuid:"1001-2002", firstname:"Barney", lastname:"Rubble"}
+
+ { action:"remove",
+ object:{ _uuid:"1001-2002" },
+ id:1000}
+
+ ---> { result: { count: 1 }, error:null, id:1000}
+
+ It is also valid to pass a list of objects to Remove.
+
+ It is also possible to remove objects that match a query. For example
+
+ { action:"remove",
+ object:{ query:"[?firstname=Barney]" },
+ id:1000 }
+
+ ---> { result: { count: 1,
+ data:[{_uuid:"1001-2002"}],
+ error:[{_uuid:"5005-6006", error:"error description"}] },
+ error:null, id:1000 }
+
+ result.error contains a list of objects that matched the query, but were
+ not successfully removed.
+
+Action: Find
+
+ Retrieve objects from the database.
+
+ { action:"find",
+ object: { query: QUERY_STRING,
+ limit: NUM, # Limit number of records to return
+ offset: NUM # Specify an offset into the list
+ }
+ id:1000 }
+
+ I'd like to get the QUERY_STRING to match JSONQuery.
+
+ The result object:
+
+ { result: { length: NUM, # Total number of matching records
+ offset: NUM, # Offset we're starting with
+ data: [ { Record1 },
+ { Record2 },
+ ....
+ ]},
+ error: null
+ id: 1000 }
+
+
+When an error is returned, the message format looks like:
+
+ { result: null,
+ error: { code: VALUE,
+ message: STRING },
+ id: ID }
+
+The code is an integer value (defined in jsondb-error.h) The message is a
+human-readable string designed to be displayed in a debugger.
+
+Action: Transaction
+
+ Processing of multiple heterogeneous requests as one transaction. For example\
+
+ { action:"transaction",
+ object: [
+ { 1 : { create: {firstname:"Barney", lastname:"Stinsen"} } },
+ { 2 : { create: {firstname:"Blabla", lastname:"Doe"},
+ insert: {spouse: { ref: 1, property: "_uuid" } } } }
+ ],
+ id:1000}
+
+ ---> { result: {
+ { 1 : { object: {_uuid:1001-1001, _version:1} } },
+ { 2 : { object: {_uuid:1001-2002, _version:1} } }
+ },
+ error:null,
+ id:1000 }
+
+ And the following documents were created:
+ {firstname:"Barney", lastname:"Stinsen", spouse:1001-2002}
+ {firstname:"Blabla", lastname:"Doe"}
+
+ The possible actions inside the transaction are "create", "update" and
+ "remove".
+
+Action: Changes Since
+
+ Retrieve all of the changes that have occurred in the database since it
+ was in a particular state.
+
+ { action: "changesSince",
+ object: { stateNumber: NUM, # The state number to start from
+ collapse: BOOL # Don't return both the before and after. Only return
+ # the after and provide a "Tombstone" object for removed
+ # items
+ }
+ id: 1000 }
+
+ --> { result: {
+ "count": NUM # The number of changed objects returned
+ "startingStateNumber": NUM # The state number of the first state used to build this
+ # history
+ "currentStateNumber": NUM # The current state number of the database
+ "changes": [
+ {
+ "before": {_uuid:"1001-1001", _version: "1", "property1": "property1OldValue" },
+ "after": {_uuid:"1001-1001", _version: "2", "name": "property1NewValue" }
+ },
+ {
+ "before": null,
+ "after" : {_uuid:"2002-2002", _version: "1", "property2": "property2Value" }
+ },
+ {
+ "before": {_uuid:"3003-2003", _version: "1", "_type": "MyObject", "property3": "property3Value" },
+ "after": null
+ }
+ ]
+ },
+ error: null,
+ id: 1000
+ }
+
+The "changes" property contains one object for every object that was changed
+during the specified period. For each of the objects in the "changes" property,
+if the "before" property is null, the change represents creating a new object.
+If the "after" property is null, the change represents the removal of an object.
+All other changes are updates. Objects that were both created and removed during
+the specified time are not included because both their "before" and "after" properties
+would be null.
+
+Asking for changesSince with stateNumber < the oldest state for which we have
+a change history will result in a full dump of the database (with all "before"
+properties having the value null). This condition can be recognized by the fact
+that the "startingStateNumber" will be greater than the stateNumber requested.
+
+===========================================================================
+Notifications
+===========================================================================
+
+Clients use notification objects to be informed of changes to the
+database. Notification objects are created, updated, and removed
+exactly like other objects. However, the life span of a notification
+object is tied to the individual connection. When the connection is
+dropped, the notification object is automatically removed.
+
+Notification objects must match the following format:
+
+ { _type: "notification",
+ query: QUERY_STRING,
+ actions: [ ACTION, ... ] }
+
+ The QUERY_STRING is a standard JSONQuery string to be matched. The
+ "actions" field contains a list of actions to be matched against. It
+can contain 'create', 'update', and 'remove'
+
+For example, to create a notification whenever a new e-mail messsage
+is received or removed, one could:
+
+ { action: "create",
+ object: { _type: "notification",
+ query: "[?_type=\"email\"]",
+ actions: ["create", "remove"] },
+ id: 1000 }
+
+ ---> { error: null, id: 1000, result: {_uuid: "{1111-2222}", _version: VERS }}
+
+The notification object can be updated and removed just like any other
+object.
+
+
+When objects are created, updated, or removed from the database, all
+notification queries are checked against the object. Matches are
+sent a notification message (see format above).
+
+For example, let's assume that some other client did this:
+
+ { action: "create",
+ object: { name: "Fred", _type="email" },
+ id: 100 }
+
+ and got in return:
+
+ { result: { _uuid: "{23423423-234234}", _version: 2 }, error: null, id: 100 }
+
+ The notify action would fire and send a message to the original
+ stream of the form:
+
+ { _uuid: "{1111-2222}",
+ notify: { object: { _uuid: "{23423423-234234}",
+ _version: 2,
+ name: "Fred",
+ _type: "email" },
+ action: "create" }
+
+
diff --git a/doc/doc.pri b/doc/doc.pri
new file mode 100644
index 00000000..17f2ff53
--- /dev/null
+++ b/doc/doc.pri
@@ -0,0 +1,15 @@
+OTHER_FILES += \
+ $$PWD/jsondb.qdocconf \
+ $$PWD/jsondb-dita.qdocconf
+
+docs_target.target = docs
+docs_target.commands = qdoc3 $$PWD/jsondb.qdocconf
+
+ditadocs_target.target = ditadocs
+ditadocs_target.commands = qdoc3 $$PWD/jsondb-dita.qdocconf
+
+QMAKE_EXTRA_TARGETS = docs_target ditadocs_target
+QMAKE_CLEAN += \
+ "-r $$PWD/html" \
+ "-r $$PWD/ditaxml"
+
diff --git a/doc/drafts/viewsystem.txt b/doc/drafts/viewsystem.txt
new file mode 100644
index 00000000..6bd4a9b6
--- /dev/null
+++ b/doc/drafts/viewsystem.txt
@@ -0,0 +1,176 @@
+Assumptions:
+
+ * A view is a materialized query of some sort.
+ * Range queries are assumed to be a frequent access pattern.
+ * Therefore, a view as such is a dependent btree, i.e. its content is
+ generated purely out of persistent documents.
+ * Accelerating join operations between several documents is assumed to
+ be a frequent use case for views.
+ * Therefore, entries in the index are dependent on one ore more
+ document.
+ * If any of the documents an entry depends on are changed, we must
+ consider it invalid, i.e. recompute.
+ * As views are computational expensive, updates should be incremental.
+ * JsonDB is a distributed database, therefore the index definition
+ should be distributable too
+ * Using a high-level scripting language (specifically JS) appears to be
+ favorable as a) the language does not limit the capabilities and b) it
+ already exists
+ * We should allow for functions to be defined in other languages, even
+ if that's just for avoiding difficult questions
+
+Requirements:
+
+ * For each entry, we must be able to tell reliably what documents it is
+ based on (otherwise, we can't invalidate the view)
+
+Challenges of using a scripting language:
+
+ * The halting problem makes detecting infinite loops in the view
+ function impossible. A safe guard mechanism (e.g. triggered based on time)
+ must be establish to kill off rogue functions.
+
+Arguments against having a view produce regular documents:
+
+ * Risk of infinite loops where views produce documents triggering views
+ to produce documents triggering the initial view and so on.
+ * View consistency requires locking write transactions. These locks
+ would be against the primary database. Only locking the view implies
+ capability for "time frozen" read transactions (i.e. the database should
+ not change while producing the view)
+
+Arguments against allowing the view to perform queries itself:
+
+ * Reliably mapping the dependency of view entry to source documents
+ gets very hard
+ * Additional complexity
+
+Proposal:
+
+ * Named views, i.e. each views get a globally unique name (just like
+ documents)
+ * A view is a b-tree with arbitrary key and value, they are not part of
+ the document space
+ * This allows a write transaction independent of the database
+ * Map functions visiting each updated document (i.e. no I/O by the
+ function)
+ * Two functions available inside a map function:
+ * emit(key, value) -> populates the resulting b-tree
+ * inject(doc-id, passed-information) -> schedule another document to
+ be visited including information to be passed
+ * A view may have more than one map function, a map function should
+ (always?) specify the entry type (otherwise each map function has to visit
+ every document)
+ * View updates are either triggered on read (i.e. lazy updates,
+ default) or on document updates (i.e. eager updates), but never inside the
+ db write transaction
+
+Example:
+
+{
+ "A": {
+ "_uuid": "A",
+ "_type": "Person",
+ "knows": "B"
+ },
+ "B": {
+ "_uuid": "B"
+ "_type": "Person",
+ "knows": "C"
+ },
+ "C": {
+ "_uuid": "C",
+ "_type": "Person",
+ },
+ "urn:example:foaf": {
+ "_uuid": "urn:example:foaf",
+ "_type": "View",
+ "lazyUpdates": true
+ },
+ "urn:example:map": {
+ "_uuid": "urn:example:map",
+ "_type": "MapFunction",
+ "targetView": "urn:example:foaf",
+ "startsOn": "Person"
+
+ "implementation": {
+ "application/javascript": "function ..."
+ // inlining sucks,but we don't have binaries yet
+ }
+ }
+}
+
+function foafMap(document, context) {
+ if (!context) { // context is undefined for initial document
+ if (document.knows) {
+ jsondb.lookup(document.knows, {
+ source: document._uuid
+ });
+ }
+ } else if (!context.middleman) {
+ if (document.knows) {
+ jsondb.lookup(document.knows, {
+ source: context.source,
+ middleman: document._uuid
+ });
+ }
+ } else {
+ jsondb.emit(context.source, {
+ foaf: document._uuid,
+ via: context.middleman
+ });
+ }
+}
+
+produces the following entry:
+
+{
+ "key": "A",
+ "value": {
+ "foaf": "C",
+ "via": "B"
+ }
+ "sources": [ a, b, c]
+}
+
+
+
+Imposed Restrictions:
+
+
+ * View system should track which documents have been visited and not
+ allow reentering
+ * (Currently) the map functions fails silently (i.e. inject("foo")
+ where "foo" does not exist would simply end the run)
+
+Required features of the underlying storage system:
+
+ * Document Store (otherwise we have to operate in the db write
+ transaction and operate on update)
+ * Give current state a name
+ * Provide changes since a named state
+ * Give stable read transaction, such that inject() will not advance
+ in time
+ * View Store
+ * The resulting b-tree must be double indexed (i.e. by emitted key
+ and by visited documents to invalidate entries on updates)
+
+ACL:
+
+ * Access to an entry should essentially be equivalent to accessing the
+ original documents it was constructed from
+ * Thanks to inject(), an entry may be constructed from more than one
+ context, making ACL a bit fuzzy
+ * Three possible approaches:
+ * The view is build as "root", but filtered on read (i.e. check read
+ access to all contexts of an entry)
+ * Pro: Minimal data overhead
+ * Con: Storage overhead (contexts per entry), one extra read per
+ context touched by the view, extra check per entry returned
+ * The view is build with ACLs of a certain user, access to a
+ specific user is granted all or nothing
+ * Pro: Minimal overhead
+ * Con: Potential information leak, does not line up well
+ * The view is build per user
+ * Pro: Simple
+ * Con: Redundancy in multi user systems
diff --git a/doc/images/example-simplelistmodel.png b/doc/images/example-simplelistmodel.png
new file mode 100644
index 00000000..9def18df
--- /dev/null
+++ b/doc/images/example-simplelistmodel.png
Binary files differ
diff --git a/doc/jsondb-dita.qdocconf b/doc/jsondb-dita.qdocconf
new file mode 100644
index 00000000..60a7ec4f
--- /dev/null
+++ b/doc/jsondb-dita.qdocconf
@@ -0,0 +1,25 @@
+# Name of the project.
+project = QtJsonDb
+
+
+
+#Do not change the variables after this line unless you know what you are doing.
+
+outputdir = ditaxml
+outputformats = DITAXML
+
+exampledirs += ../examples
+headerdirs += ./src \
+ ../src/client \
+ ../src/imports
+sourcedirs += ./src \
+ ../src/client \
+ ../src/imports
+
+HTML.nobreadcrumbs = "true"
+
+examples.fileextensions = "*.cpp *.h *.js *.svg *.xml *.ui *.qml"
+examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
+headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
+sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
+
diff --git a/doc/jsondb.qdocconf b/doc/jsondb.qdocconf
new file mode 100644
index 00000000..db426dc5
--- /dev/null
+++ b/doc/jsondb.qdocconf
@@ -0,0 +1,70 @@
+# Name of the project.
+project = QtJsonDb
+
+# Directories in which to search for files to document.
+# Paths are relative to the location of this file.
+exampledirs += ../examples
+headerdirs += ./src \
+ ../src/client \
+ ../src/common/qson \
+ ../src/imports/jsondb
+imagedirs += images
+sourcedirs += ./src \
+ ../src/client \
+ ../src/common/qson \
+ ../src/imports/jsondb
+
+# The following parameters are for creating a qhp file, the qhelpgenerator
+# program can convert the qhp file into a qch file which can be opened in
+# Qt Assistant and/or Qt Creator.
+
+# Defines the name of the project. You cannot use operators (+, =, -) in
+# the name. Properties for this project are set using a qhp.<projectname>.property
+# format.
+qhp.projects = QtJsonDb
+
+# Sets the name of the output qhp file.
+qhp.QtJsonDb.file = QtJsonDb.qhp
+
+# Namespace for the output file. This namespace is used to distinguish between
+# different documentation files in Creator/Assistant. The namespace ends with
+# a version being a number containing a major, minor and revision element.
+# E.g. version 1.0 becomes 100.
+qhp.QtJsonDb.namespace = com.nokia.qtjsondb.100
+
+# Title for the package, will be the main title for the package in
+# Assistant/Creator.
+qhp.QtJsonDb.indexTitle = Qt JsonDb Reference Documentation
+
+# Extra files to add to the output which are not linked to from anywhere
+# using a qdoc \l command.
+qhp.QtJsonDb.extraFiles = style/style.css \
+ index.html
+
+# Only updtae the name of the project for the next variables.
+qhp.QtJsonDb.virtualFolder = qdoc
+qhp.QtJsonDb.subprojects = classes
+qhp.QtJsonDb.subprojects.classes.title = Classes
+qhp.QtJsonDb.subprojects.classes.selectors = class fake:headerfile
+qhp.QtJsonDb.subprojects.classes.sortPages = true
+
+
+
+
+# Do NOT change the variables after this line unless you know what you are doing.
+
+outputdir = html
+outputformats = HTML
+
+examples.fileextensions = "*.cpp *.h *.js *.svg *.xml *.ui *.qml"
+examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
+headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
+sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
+
+HTML.nobreadcrumbs = "true"
+
+HTML.templatedir = .
+HTML.stylesheets = style/style.css
+
+HTML.headerstyles = " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n"
+HTML.endheader = "</head>\n"
diff --git a/doc/src/example-desktop-inspector.qdoc b/doc/src/example-desktop-inspector.qdoc
new file mode 100644
index 00000000..0eed29cd
--- /dev/null
+++ b/doc/src/example-desktop-inspector.qdoc
@@ -0,0 +1,7 @@
+/*!
+ \example declarative/desktop-inspector
+ \title Desktop Database Inspector Example
+ \brief The Desktop Database Inspector Example demonstrates how to view any kind of object in the database.
+
+ \image{example-desktop-inspector.png}
+ */
diff --git a/doc/src/example-simplelistmodel.qdoc b/doc/src/example-simplelistmodel.qdoc
new file mode 100644
index 00000000..91ea51d6
--- /dev/null
+++ b/doc/src/example-simplelistmodel.qdoc
@@ -0,0 +1,7 @@
+/*!
+ \example declarative/simplelistmodel
+ \title Simple List Model Example
+ \brief The Simple List Model Example demonstrates adding a contact with random-generated name to the database.
+
+ \image{example-simplelistmodel.png}
+ */
diff --git a/doc/src/expression-examples.qdoc b/doc/src/expression-examples.qdoc
new file mode 100644
index 00000000..5327ca6a
--- /dev/null
+++ b/doc/src/expression-examples.qdoc
@@ -0,0 +1,112 @@
+/*!
+\page expression-examples.html
+\title Expression Examples
+
+\previouspage {index.html}
+
+\table
+\row
+\o \c {[?_type="Application"]}
+\o Return all objects that are Application types.
+\row
+\o \c {[*][/_type]}
+\o All objects in the database, sorted by _type.
+\row
+\o \c {[/_type]}
+\o All objects in the database, sorted by _type.
+\row
+\o \c {[?name exists][/_type]}
+\o All objects with a "name" field in the database, sorted by _type.
+\row
+\o \c {[?name = %thename ][/_type]}
+\o All objects from the database where the "name" field is the same as the
+binding for thename in the bindings object provided to find, sorted by _type.
+\row
+\o \c {[?name != "nancy"]}
+\o All objects in the database with an "name" field not equal to "nancy".
+\row
+\o \c {[?name < "nancy"]}
+\o All objects in the database with an "name" field less than "nancy".
+\row
+\o \c {[?name <= "nancy"]}
+\o All objects in the database with an "name" field less than or equal to
+"nancy".
+\row
+\o \c {[?name > "nancy"]}
+\o All objects in the database with an "name" field greater than "nancy".
+\row
+\o \c {[?name >= "nancy"]}
+\o All objects in the database with an "name" field greater than or equal to
+"nancy".
+\row
+\o \c {[?count != 47]}
+\o All objects in the database with a "count" field not equal to 47.
+\row
+\o \c {[?name < 47]}
+\o All objects in the database with a "count" field less than 47.
+\row
+\o \c {[?name <= 47]}
+\o All objects in the database with a "count field less than or equal to 47.
+\row
+\o \c {[?name > 47]}
+\o All objects in the database with a "count" field greater than 47.
+\row
+\o \c {[?name >= 47]}
+\o All objects in the database with a "count" field greater than or equal to 47.
+\row
+\o \c {[?email contains "foo@example.com"]}
+\o All objects in the database with an "email" field containing the string
+"foo@example.com".
+\row
+\o \c {[?sizes contains 3]}
+\o All objects in the database with a "sizes" field containing the int 3.
+\row
+\o \c {[?sizes contains %three ]}
+\o All objects in the database with a "sizes" field containing the value bound
+to three in the bindings object provided to find.
+\row
+\o \c {[?size in [3, 4, 5]]}
+\o All objects in the database with a "size" field that is contained in the
+list [3, 4, 5].
+\row
+\o \c {[?size notIn [3, 4, 5]]}
+\o All objects in the database with a "size" field that is not contained in the
+list [3, 4, 5].
+\row
+\o \c {?name =~ "!fred.*!"]}
+\o Objects with a name field matching the regular expression "fred.*", case
+sensitive.
+\row
+\o \c {[?name =~ "!fred.*!i"]}
+\o Objects with a name field matching the regular expression "fred.*", case
+insensitive.
+\row
+\o \c {[?name =~ "!fred*!w"]}
+\o Objects with a name field matching the wildcard expression "fred*", case
+sensitive.
+\row
+\o \c {[?name =~ "!fred*!wi"]}
+\o Objects with a name field matching the wildcard expression "fred*", case
+insensitive.
+\row
+\o \c {[?name startsWith "fred"]}
+\o Objects with a name field that start with "fred".
+\row
+\o \c {[?_type="MESSAGE"][?HasAttachments="true"][\DateTimeSent]}
+\o Message objects with attachments, sorted in reverse chronological order.
+\row
+\o \c {[?_type="MESSAGE"][= Subject ]}
+\o List of the subjects from message objects.
+\row
+\o \c {[?_type="MESSAGE"][= [ Subject, DateTimeSent, Sender.Mailbox.EmailAddress] ]}
+\o List of lists containing the subject, sent time, and sender email address
+from message objects.
+\row
+\o \c {[?_type="MESSAGE"][= { subject: Subject, sent: DateTimeSent, sender: Sender.Mailbox.EmailAddress } ]}
+\o List of new objects containing of subject, sent time, and sender email
+address from message objects.
+\row
+\o \c {[?_type="CALL"][= time, duration, contactUuid->name ][/time]}
+\o Time, duration and contact name from call log objects, sorted by time.
+\endtable
+*/
diff --git a/doc/src/index.qdoc b/doc/src/index.qdoc
new file mode 100644
index 00000000..e75025ed
--- /dev/null
+++ b/doc/src/index.qdoc
@@ -0,0 +1,106 @@
+/*!
+\title Qt JsonDb Reference
+\page index.html
+
+\section1 Introduction
+
+\section1 Accessing the Database.
+
+\section2 C++ API
+
+\generatelist annotatedclasses
+
+\section2 QML Elements
+
+\generatelist qmlclasses
+
+\section1 Using the Database
+
+\section2 Schemas
+
+\section2 Query Language
+
+Central to the use of a large object store is the ability to query efficiently
+for objects from within the object store. The JsonDB query language was
+originally modeled off of the JSON Query language, see
+\l {http://docs.persvr.org/documentation/jsonquery}. It has subsequently been
+updated for faster performance and features have been added that make it more
+suitable for our application.
+
+A simple query consists of square brackets surrounding an expression
+(e.g., [EXPR]). A complex query is a string of simple queries concatenated
+together (e.g., [EXPR1][EXPR2][EXPR3]). Each expression filters or applies an
+action.
+
+\section3 Valid Expressions
+
+\table
+\header
+\o Expression
+\o Description
+\row
+\o \c {? filter}
+\o Query for matching objects.
+\row
+\o \c {= fields}
+\o Restrict returned objects to particular fields.
+\row
+\o \c {/ field}
+\o Sort in ascending order by field.
+\row
+\o \c {\ field}
+\o Sort in descending order by field.
+\row
+\o \c {count}
+\o Aggregation operation.
+\row
+\o \c {*}
+\o Match all objects.
+\endtable
+
+See also \l {Expression Examples}
+
+\section3 Stability of Sort in JsonDb
+
+The database as a set of objects with no natural ordering. Any time that we need
+objects in a particular order, we use an index that orders the objects by a
+particular field and comparison operator. It is unlikely that the sorting in one
+index would be stable with respect to all other indexes on that object.
+
+\section2 Indexes
+
+\section3 Query optimization
+
+In general, sorting should only be done on properties for which JSON DB has an
+index. Any sorts done on non-indexed properties will result in all of the
+objects being sorted in-memory, which should be avoided for all but the
+smallest data sets.
+
+\section2 Views
+
+\section2 Notifications
+
+Notifications are created, updated, and removed by creating, updating, and
+removing notification objects, which have the following properties:
+
+\list
+\o _type: "NOTIFICATION"
+\o query: Notifications will be delivered for objects matching this query
+string (e.g., [?_type="com.nokia.mp.content.Image"])
+\o actions: A list specifying for which actions (create, update, remove)
+notifications will be delivered (e.g., ["create", "remove"])
+\endlist
+
+When a notification matches an action performed on the database, the
+application is notified through one of the client APIs. The notification is
+identified by the UUID of the matching notification. The object being acted
+upon and the name of the action are delivered along with the notification UUID
+to the client.
+
+\section1 Examples
+
+\list
+\o \l{declarative/simplelistmodel}{Simple List Model}
+\o \l{declarative/desktop-inspector}{Desktop Database Inspector Example}
+\endlist
+*/
diff --git a/doc/style/style.css b/doc/style/style.css
new file mode 100644
index 00000000..df84049f
--- /dev/null
+++ b/doc/style/style.css
@@ -0,0 +1,137 @@
+a:link, a:visited {
+ color: #00732F;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+body {
+ font: normal 400 14px/1.2 Arial;
+ margin-top: 85px;
+}
+
+h1 {
+ margin: 0;
+}
+
+h2 {
+ font: 500 20px/1.2 Arial;
+}
+
+h3.fn, span.fn {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ word-spacing: 3px;
+ padding: 3px 5px;
+}
+
+table, pre {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border: 1px solid #E6E6E6;
+ border-collapse: separate;
+ font-size: 12px;
+ line-height: 1.2;
+ margin-bottom: 25px;
+ margin-left: 15px;
+}
+
+table td {
+ padding: 3px 15px 3px 20px;
+}
+
+table tr.even {
+ background-color: white;
+ color: #66666E;
+}
+
+table tr.odd {
+ background-color: #F6F6F6;
+ color: #66666E;
+}
+
+li {
+ margin-bottom: 10px;
+ padding-left: 12px;
+}
+
+.cpp {
+ display: block;
+ margin: 10;
+ overflow: hidden;
+ overflow-x: hidden;
+ overflow-y: hidden;
+ padding: 20px 0 20px 0;
+}
+
+.footer {
+ margin-top: 50px;
+}
+
+.memItemLeft {
+ padding-right: 3px;
+}
+
+.memItemRight {
+ padding: 3px 15px 3px 0;
+}
+
+.qml {
+ display: block;
+ margin: 10;
+ overflow: hidden;
+ overflow-x: hidden;
+ overflow-y: hidden;
+ padding: 20px 0 20px 0;
+}
+
+.qmldefault {
+ padding-left: 5px;
+ float: right;
+ color: red;
+}
+
+.qmlreadonly {
+ padding-left: 5px;
+ float: right;
+ color: #254117;
+}
+
+.rightAlign {
+ padding: 3px 5px 3px 10px;
+ text-align: right;
+}
+
+.title {
+ background-color: white;
+ color: #44A51C;
+ font-family: Verdana;
+ font-size: 35px;
+ font-weight: normal;
+ left: 0;
+ padding-bottom: 5px;
+ padding-left: 16px;
+ padding-top: 20px;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+
+.toc {
+ float: right;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border: 1px solid #DDD;
+ margin: 0 20px 10px 10px;
+ padding: 20px 15px 20px 20px;
+ height: auto;
+ width: 200px;
+}
diff --git a/examples/declarative/desktop-inspector/README.txt b/examples/declarative/desktop-inspector/README.txt
new file mode 100644
index 00000000..10155673
--- /dev/null
+++ b/examples/declarative/desktop-inspector/README.txt
@@ -0,0 +1,8 @@
+This is a "desktop" inspector application for JsonDb. It can be used
+to view the JSON database while simultaneously running other
+applications.
+
+The column along the left allows you to show (green square) or hide
+(red square) all objects of a certain type. The text box allows you
+to type in arbitrary queries, the results of which are then displayed.
+Queries can also be saved for later use.
diff --git a/examples/declarative/desktop-inspector/content/Button.qml b/examples/declarative/desktop-inspector/content/Button.qml
new file mode 100644
index 00000000..04c3154f
--- /dev/null
+++ b/examples/declarative/desktop-inspector/content/Button.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: bt
+ width: 120
+ height: 40
+ radius: 10
+ color: ma.pressed?'silver': '#3ba5ff'
+ property alias text:lb.text
+ signal clicked()
+ Text {
+ id: lb
+ anchors.fill:parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide:Text.ElideMiddle
+ text:'button'
+ color:'white'
+ font.pixelSize: 12
+ }
+ MouseArea {
+ id: ma
+ anchors.fill:parent
+ onClicked: {
+ bt.clicked();
+ }
+ }
+}
diff --git a/examples/declarative/desktop-inspector/content/Dialog.qml b/examples/declarative/desktop-inspector/content/Dialog.qml
new file mode 100644
index 00000000..7bbde980
--- /dev/null
+++ b/examples/declarative/desktop-inspector/content/Dialog.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: dialog
+ anchors.fill:parent
+ property alias title: titleLb.children
+ property alias content: contentItem.children
+ property alias buttons: buttonItem.children
+ z:Number.MAX_VALUE
+ visible: false
+ signal accepted()
+
+ function accept() {
+ dialog.accepted();
+ dialog.close();
+ }
+
+ function open() {
+ dialog.visible = true;
+ }
+
+ function close() {
+ dialog.visible = false;
+ }
+
+ Rectangle {
+ anchors.fill:parent
+ color:'black'
+ opacity: 0.9
+ }
+ Item {
+ id: titleLb
+ width: parent.width
+ height: childrenRect.height
+ anchors.top:parent.top
+ anchors.topMargin: 40
+ }
+ Item {
+ id: contentItem
+ width:parent.width
+ height: childrenRect.height
+ anchors.top:titleLb.bottom
+ anchors.topMargin: 10
+ }
+ Item {
+ id: buttonItem
+ width:parent.width
+ height: childrenRect.height
+ anchors.top:contentItem.bottom
+ anchors.topMargin: 10
+ }
+}
diff --git a/examples/declarative/desktop-inspector/content/Editor.qml b/examples/declarative/desktop-inspector/content/Editor.qml
new file mode 100644
index 00000000..99dfabae
--- /dev/null
+++ b/examples/declarative/desktop-inspector/content/Editor.qml
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: container
+ width: 640
+ height: 480
+ color:"Silver"
+ property bool createNewObject: true
+ property alias content:edit.text
+ signal cancelled()
+ signal confirmed()
+ MouseArea {
+ anchors.fill:parent
+ }
+
+ Text {
+ id: titleText
+ anchors.left:parent.left
+ anchors.leftMargin: 20
+ font.pixelSize: 15
+ anchors.top:parent.top
+ anchors.topMargin: 10
+ text: createNewObject ? "Create" :"Edit"
+ }
+
+ Rectangle {
+ id: textBg
+ width: parent.width - 40
+ height: parent.height - 100
+ anchors.top:titleText.bottom
+ anchors.topMargin:10
+ anchors.horizontalCenter:parent.horizontalCenter
+ // color:"silver"
+ border.color:"black"
+
+ Flickable {
+ id: flick
+
+ width: parent.width -20; height: parent.height;
+ anchors.horizontalCenter:parent.horizontalCenter
+ contentWidth: edit.paintedWidth
+ contentHeight: edit.paintedHeight
+ flickableDirection:Flickable.VerticalFlick
+ clip: true
+
+ function ensureVisible(r)
+ {
+ if (contentX >= r.x)
+ contentX = r.x;
+ else if (contentX+width <= r.x+r.width)
+ contentX = r.x+r.width-width;
+ if (contentY >= r.y)
+ contentY = r.y;
+ else if (contentY+height <= r.y+r.height)
+ contentY = r.y+r.height-height;
+ }
+
+ TextEdit {
+ id: edit
+ width: flick.width
+ height: flick.height
+ focus: true
+ wrapMode: TextEdit.Wrap
+ onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
+ }
+ }
+ }
+
+ Button {
+ id: confirmBt
+ text:createNewObject? "Create":"Update"
+ anchors.bottom:parent.bottom
+ anchors.right:parent.right
+ width :80
+ anchors.bottomMargin: 10
+ anchors.rightMargin: 20
+ onClicked:container.confirmed();
+ }
+ Button {
+ id: cancelBt
+ text:"Cancel"
+ anchors.bottom:parent.bottom
+ anchors.right:confirmBt.left
+ width :80
+ anchors.bottomMargin: 10
+ anchors.rightMargin: 20
+ onClicked:container.cancelled();
+ }
+
+}
+
diff --git a/examples/declarative/desktop-inspector/content/Generic.qml b/examples/declarative/desktop-inspector/content/Generic.qml
new file mode 100644
index 00000000..a9d1a1e0
--- /dev/null
+++ b/examples/declarative/desktop-inspector/content/Generic.qml
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Generic item with no real data
+
+import QtQuick 2.0
+
+Rectangle {
+ id: container
+ width: parent.width
+ height: myColumn.height
+ border.color: (hidden ? "transparent" : "#888")
+
+ property string title : "Unknown";
+ property string subtitle : "";
+ property string detail : "Data";
+ property bool hidden: true;
+ property bool expanded: false;
+
+ signal removeMe()
+ signal editMe()
+ signal watchMe()
+
+ MouseArea {
+ id: clickRegion
+ anchors.fill: parent
+ onClicked: { container.expanded = !container.expanded; }
+ }
+ Column {
+ id: myColumn
+ x: 2
+ width: parent.width
+
+ Item {
+ width: parent.width
+ height: childrenRect.height
+
+ Text {
+ id: myLabel
+ text: title
+ color:"darkgray"
+ font.pixelSize: 14
+ }
+
+ Text {
+ id: mySubtitle
+ font.bold: true
+ anchors { left: myLabel.right; leftMargin: 10; baseline: myLabel.baseline }
+ y: 2
+ text: subtitle
+ font.pixelSize: 15
+ }
+ }
+
+ Text {
+ id: itemDetail
+ color: "#444";
+ text: detail
+ font.pixelSize: 14
+ visible: false
+ width: parent.width
+ height: Math.max(childrenRect.height,paintedHeight)
+
+ Column {
+ anchors.right:parent.right
+ spacing: 5
+ Button{
+ id: removeBt
+ text: "Remove"
+ width: 80
+ onClicked:container.removeMe()
+ }
+ Button{
+ id: editBt
+ text: "Edit"
+ width: 80
+ onClicked:container.editMe()
+ }
+ Button{
+ id: watchBt
+ text: "Watch"
+ width: 80
+ visible:false
+ onClicked:container.watchMe()
+ }
+ }
+ }
+ }
+
+
+ states: [
+ State {
+ name: "hidden"
+ when: hidden
+ PropertyChanges { target: myColumn; visible: false}
+ PropertyChanges { target: container; height: 0 }
+ },
+ State {
+ name: "expanded";
+ when: expanded
+ PropertyChanges { target: itemDetail; visible: true; }
+ PropertyChanges { target: container; height: myLabel.height + itemDetail.height + 5 }
+ }
+ ]
+}
diff --git a/examples/declarative/desktop-inspector/content/Header.qml b/examples/declarative/desktop-inspector/content/Header.qml
new file mode 100644
index 00000000..fcf5fe31
--- /dev/null
+++ b/examples/declarative/desktop-inspector/content/Header.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Generic item with no real data
+
+import QtQuick 2.0
+
+Rectangle {
+ id: container
+ width: parent.width
+ height: myHeader.height
+ border.color: "green"
+ color: "#ccc"
+
+ property string title : "Unknown"
+ property int count: 0
+ signal clicked(string title)
+
+ Text {
+ id: myHeader
+ anchors { horizontalCenter: parent.horizontalCenter }
+ text: title + " [" + count + "]";
+ font.pixelSize: 14
+ }
+
+ MouseArea {
+ id: clickRegion
+ anchors.fill: parent
+ onClicked: { container.clicked(title); }
+ }
+}
diff --git a/examples/declarative/desktop-inspector/content/inspector.js b/examples/declarative/desktop-inspector/content/inspector.js
new file mode 100644
index 00000000..3b398efc
--- /dev/null
+++ b/examples/declarative/desktop-inspector/content/inspector.js
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+var componentDict = {};
+var schema = {};
+
+function makeComponent(name) {
+ var component;
+
+ if (name in componentDict) {
+ component = componentDict[name];
+ }
+ else {
+ component = Qt.createComponent(name+".qml");
+ if (component.status != Component.Ready) {
+ console.debug("Error creating " + name + ".qml component");
+ console.debug(component.errorString());
+ throw "InitComponentError";
+ }
+ componentDict[name] = component;
+ }
+
+ var obj = component.createObject(myColumn);
+ if (obj == null) {
+ console.debug("Error creating object of type " + name);
+ console.debug(component.errorString());
+ throw "CreationError";
+ }
+ return obj;
+}
+
+
+var mapping = {
+ "image": "url",
+ "_schemaType": "name",
+ "CONTACT": function(obj) { return obj.NAME.given + " " + obj.NAME.family; }
+};
+
+
+function findsubtitle(record) {
+ try {
+ var list = ["identifier","name"];
+ for (var i = 0; i< list.length; i++) {
+ var p = list[i];
+ if (record._type in mapping)
+ p = mapping[record._type];
+
+ if (typeof(p) == "string" && p in record)
+ return record[p];
+
+ if (typeof(p) == "function")
+ return p(record);
+
+ p = "name";
+ }
+
+ } catch (err) {
+ console.debug(err);
+ }
+ return " ";
+}
+
+var appsets = {};
+
+function headerClick(name) {
+ var set = appsets[name];
+ for (var i = 0 ; i < set.length ; i++) {
+ set[i].hidden = !set[i].hidden;
+ }
+}
+
+/*
+ This is incomplete and won't parse a complete record.
+ Needs to be made recursive
+*/
+
+function prettyFormat( record, schema, indent )
+{
+ var result = "";
+ if ("title" in schema)
+ result += indent + schema.title + "\n";
+
+ if ("properties" in schema) {
+ var schema_properties = schema.properties;
+ for (var property in record) {
+ if (property in schema_properties) {
+ var schema_entry = schema_properties[property];
+ var ptype = (("type" in schema_entry) ? schema_entry["type"] : "undefined");
+ var title = (("title" in schema_entry) ? schema_entry["title"] : ptype);
+ if (ptype == "boolean") {
+ result += indent + " " + title + ": " + (record[property]?"true":"false") + "\n";
+ }
+ if (ptype == "string" || ptype == "integer" || ptype == "number" || ptype == "any")
+ result += indent + " " + title + ": " + record[property] + "\n";
+ else if (ptype == "array") {
+ var a = record[property];
+ if (a.length) {
+ result += indent + " " + title + ": [\n";
+ var array_schema = schema_entry["items"];
+ for (var i = 0 ; i < a.length ; i++ ) {
+ result += prettyFormat( a[i], array_schema, indent + " ");
+ if (i < a.length - 1)
+ result += indent + " ---- ";
+ }
+ result += "]\n";
+ }
+ else {
+ result += indent + " " + title + ": []\n";
+ }
+ }
+ else if (ptype == "object") {
+ result += prettyFormat( record[property], schema_entry, indent + " ");
+ }
+ }
+ }
+ }
+ return result;
+}
+
+
+function loadSchema(next) {
+// jsondb.notification('[?_type="_schemaType"]',['create', 'remove'], function(result, action) {
+// if (action == 'create') {
+// schema[result.name] = result;
+// }else if (action == 'remove') {
+// delete schema[result.name];
+// }
+// }
+//);
+ JsonDb.query('[?_type="_schemaType"]',function(result) {
+ var records = result.data;
+ for (var i = 0; i< records.length; i++) {
+ schema[records[i].name] = records[i];
+ }
+
+ if (next) {
+ next();
+ }
+ }
+ )
+}
+
+function loadQuery(next) {
+ JsonDb.notification('[?_type="UserCommand"]', ['create',"update","remove"], function(result,action) {
+ if (action == 'create') {
+ queryCmdModel.append(result);
+ } else if (action == 'remove') {
+ for (var i = 0; i< queryCmdModel.count ; i++) {
+ if (queryCmdModel.get(i)._uuid && queryCmdModel.get(i)._uuid == result._uuid) {
+ queryCmdModel.remove(i);
+ break;
+ }
+ }
+ } else if ( action == 'update') {
+ for (var i = 0; i< queryCmdModel.count ; i++) {
+ if (queryCmdModel.get(i)._uuid && queryCmdModel.get(i)._uuid == result._uuid) {
+ queryCmdModel.set(i, result);
+ break;
+ }
+ }
+ }
+ }
+);
+ JsonDb.query('[?_type="UserCommand"]', function(result) {
+ var cmds = result.data;
+ for (var i = 0; i < cmds.length; i++) {
+ queryCmdModel.append(cmds[i]);/*{"query":cmds[i].query, "title": cmds[i].title}*/
+ }
+ if (next) {
+ next();
+ }
+ }
+)
+}
+
+function loaddata(queryString) {
+ if (!queryString) {
+ queryString = '[/_type]';
+ }
+ JsonDb.query(queryString, function(data) {
+ var records = data.data;
+ var header;
+ rootModel.clear();
+ records.sort(function(a,b) {
+ return (a._type > b._type ? 1 :
+ (a._type < b._type ? -1 : 0))});
+
+
+ for (var i = 0 ; i < records.length ; i++) {
+ var record = records[i];
+
+ if (typeof(header) == "undefined" || record._type != header) {
+
+ header = record._type;
+ rootModel.append({"Title":record._type, "Visible": true});
+ }
+ }
+ });
+}
+
+function getDetail(record) {
+ var ret = JSON.stringify(record,null," ");
+
+ if (record._type in schema) {
+ try {
+ ret = prettyFormat(record, schema[record._type].schema,"") +
+ "--------------------------------------------\n" + ret;
+
+ } catch (err) {
+ console.debug(err);
+ }
+ }
+ return ret;
+}
+
+
+function inspectorStarted() {
+ loadSchema(loadQuery(loaddata));
+}
+
+function removeObject(uuid) {
+ var obj = {
+ "_uuid":uuid
+ }
+
+ JsonDb.remove(obj);
+}
diff --git a/examples/declarative/desktop-inspector/desktop-inspector.qml b/examples/declarative/desktop-inspector/desktop-inspector.qml
new file mode 100644
index 00000000..003a3e4a
--- /dev/null
+++ b/examples/declarative/desktop-inspector/desktop-inspector.qml
@@ -0,0 +1,627 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtJsonDb 1.0 as JsonDb
+import "content"
+import "content/inspector.js" as InspectorDb
+
+Item {
+ id: screen
+ width: 800
+ height: 600
+
+
+ ListModel {
+ id: rootModel
+ }
+
+ Rectangle{
+ id: allVisible
+ width: 15
+ height: 15
+ anchors.bottom:divider0.top
+ anchors.bottomMargin: 5
+ anchors.right:allInvisible.left
+ anchors.rightMargin: 10
+ color:"green"
+ MouseArea {
+ anchors.fill:parent
+ anchors.margins: -5
+ onClicked: {
+ for (var i = 0 ;i< rootModel.count; i++) {
+ rootModel.setProperty(i, "Visible", true);
+ }
+ }
+ }
+
+ }
+ Rectangle{
+ id: allInvisible
+ width: 15
+ height: 15
+ anchors.bottom:divider0.top
+ anchors.bottomMargin: 5
+ anchors.right:divider1.left
+ anchors.rightMargin: 10
+ color:"red"
+ MouseArea {
+ anchors.fill:parent
+ anchors.margins: -5
+ onClicked: {
+ for (var i = 0 ;i< rootModel.count; i++) {
+ rootModel.setProperty(i, "Visible", false);
+ }
+ }
+ }
+
+ }
+ Rectangle {
+ id: divider0
+ width: 190
+ height: 1
+ anchors.left:screen.left
+ anchors.leftMargin: 10
+ anchors.top:parent.top
+ anchors.topMargin: 40
+ color:"black"
+ }
+ ListView {
+ id: rootView
+ model:rootModel
+
+ anchors.left:parent.left
+ anchors.top:divider0.bottom
+ anchors.margins: 10
+ // color:"lightgray"
+ clip:true
+ width:200
+ height:parent.height - 70
+ delegate: Rectangle {
+ width:parent.width
+ height:title.height + 10
+ Text {
+ id: title
+ width: parent.width - 50
+ anchors.verticalCenter:parent.verticalCenter
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment:Text.AlignLeft
+ anchors.leftMargin: 10
+ anchors.rightMargin: 50
+ text: Title
+ wrapMode:Text.WrapAnywhere
+ font.pixelSize: 12
+ }
+
+ Rectangle{
+ id: visibleCb
+ width: 15
+ height: 15
+ anchors.verticalCenter:parent.verticalCenter
+ anchors.left:title.right
+ anchors.leftMargin: 20
+ property bool nVisible: model.Visible
+ color:nVisible? "green":"red"
+ MouseArea {
+ anchors.fill:parent
+ anchors.margins: -5
+ onClicked: {
+ rootModel.setProperty(index, "Visible",!visibleCb.nVisible )
+ }
+ }
+
+ }
+ Rectangle {
+ width:parent.width - 20
+ height: 1
+ anchors.horizontalCenter:parent.horizontalCenter
+ color:"slategray"
+ anchors.bottom:parent.bottom
+ }
+
+ }
+ }
+
+ Rectangle {
+ id: divider1
+ width: 2
+ height: parent.height - 20
+ anchors.left:rootView.right
+ anchors.leftMargin: 10
+ anchors.verticalCenter:parent.verticalCenter
+ color:"black"
+ }
+
+ Rectangle{
+ id: quickSearchBox
+ anchors.left:rootView.right
+ anchors.right:parent.right
+ anchors.top:parent.top
+ anchors.margins: 20
+ height: 30
+ // width: parent.width - 300
+ border.color:"gray"
+ TextInput {
+ id: searchbox
+ width:parent.width
+ anchors.verticalCenter:parent.verticalCenter
+ font.pixelSize: 20
+ }
+ }
+
+ Flickable {
+ id: flickable
+ anchors.left:rootView.right
+ anchors.right:parent.right
+ anchors.top:quickSearchBox.bottom
+ height: parent.height - 250
+ anchors.topMargin:10
+ anchors.leftMargin: 20
+ anchors.rightMargin:20
+ contentHeight: myColumn.height
+ clip:true
+ flickableDirection:Flickable.VerticalFlick
+
+ Column{
+ id: myColumn
+ width:flickable.width
+ height:childrenRect.height
+ Repeater {
+ model:rootModel
+ delegate: Item {
+ id: dinstance
+ width: flickable.width
+ height: showItems? (header.height + itemsList.height): header.height
+ property bool showItems: false
+ visible: model.Visible //&& (searchText)
+ // property string searchText: searchbox.text
+ // onSearchTextChanged: {
+ // if (searchText ) {
+ // filteredModel.clear();
+ // for (var i = 0; i< dModel.count ; i++) {
+ // var str = JSON.stringify(dModel.get(i));
+ // if (str.indexOf(searchText) != 0) {
+ // filteredModel.append(dModel.get(i));
+ // }
+ // }
+ // }
+ // }
+ onShowItemsChanged: {
+ // if (showItems) {
+ // if (searchText) {
+ // itemsRepeater.model = filteredModel;
+ // }else{
+ // itemsRepeater.model = dModel;
+ // }
+ // }
+
+ if (!itemsRepeater.model) {
+ itemsRepeater.model = dModel;
+ }
+
+ }
+
+ Header {
+ id: header
+ width:parent.width - 1
+ title:Title
+ count: dModel.count
+ onClicked: {
+ dinstance.showItems = !dinstance.showItems;
+ //InspectorDb.headerClick(title);
+ }
+ }
+ Column {
+ id: itemsList
+ width:flickable.width
+ height: childrenRect.height
+
+ visible:dinstance.showItems
+ anchors.top:header.bottom
+ Repeater {
+ id:itemsRepeater
+ delegate: Generic {
+ id: instance
+ width: flickable.width-1
+ hidden: false
+ property bool viewShown: dinstance.showItems
+ title:model._type
+ subtitle : InspectorDb.findsubtitle(model)
+ detail: model.inspector_detail
+ property string searchText: searchbox.text
+ onSearchTextChanged: {
+ if (searchText) {
+ if (detail.indexOf(searchText)!= -1) {
+ instance.hidden = false;
+ }else {
+ instance.hidden = true;
+ }
+ }else {
+ instance.hidden = false;
+ }
+ }
+ onViewShownChanged: {
+ expanded = false;
+ }
+ onRemoveMe: {
+ InspectorDb.removeObject(model._uuid);
+ }
+
+ onEditMe: {
+ objectEditor.show = true;
+ objectEditor.createNewObject = false;
+ objectEditor.content = model.inspector_detail; /*JSON.stringify(d,null," ")*/;
+ }
+
+ Component.onCompleted: {
+ // InspectorDb.setData(instance, model)
+ }
+ }
+ }
+ }
+ ListModel {
+ id: dModel
+ }
+
+ property variant notificationObj:null
+ Component.onCompleted: {
+ var queryStr = textbox.text + '[?_type="' + Title+ '"]';
+
+ notificationObj = JsonDb.notification(queryStr, ['create','update','remove'], function (result, action){
+ if (action == 'create') {
+ dModel.append(result);
+ }else {
+ for (var i = 0; i< dModel.count; i++) {
+ if (dModel.get(i)._uuid == result._uuid) {
+ if (action == 'update') {
+ result.inspector_detail = InspectorDb.getDetail(result);
+
+ dModel.set(i, result);
+ break;
+ }else if (action == 'remove') {
+ dModel.remove(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+ );
+
+ JsonDb.query(queryStr, function(result){
+ var data = result.data;
+ for (var i = 0; i< data.length; i++) {
+ var d = data[i];
+ d.inspector_detail = InspectorDb.getDetail(data[i]);
+ dModel.append(d);
+ }
+ }
+ )
+ }
+ Component.onDestruction: {
+ if (notificationObj) {
+ notificationObj.remove();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: divider2
+ width: flickable.width
+ height: 2
+ anchors.top:flickable.bottom
+ anchors.topMargin:10
+ anchors.right:parent.right
+ anchors.rightMargin:20
+ color:"black"
+ }
+
+ Rectangle {
+ id: divider3
+ width: flickable.width
+ height: 2
+ anchors.top:divider2.bottom
+ anchors.topMargin:60
+ anchors.right:parent.right
+ anchors.rightMargin:20
+ color:"black"
+ }
+
+ Item {
+ id: queryBox
+ // border.color:"gray"
+ anchors.left:divider1.right
+ anchors.leftMargin: 10
+ anchors.right:parent.right
+ anchors.rightMargin: 20
+ anchors.top:divider2.bottom
+ anchors.topMargin: 10
+ anchors.bottom:divider3.top
+ anchors.bottomMargin: 10
+ Rectangle {
+ id: cleanBt
+ width: 20
+ height: 20
+ radius: 15
+ anchors.left:textbg.right
+ anchors.leftMargin: 5
+ anchors.verticalCenter:parent.verticalCenter
+ color:cleanMa.pressed? "gray": "silver"
+ Text {
+ text: "x"
+ color:"red"
+ anchors.centerIn:parent
+ font.pixelSize: 14
+ }
+ MouseArea {
+ id: cleanMa
+ anchors.fill:parent
+ onClicked: {
+ textbox.text = '';
+ }
+ }
+
+ }
+ Rectangle{
+ id: textbg
+ anchors.left:parent.left
+ anchors.top:parent.top
+ anchors.bottom:parent.bottom
+ // anchors.margins: 10
+ width: parent.width - 300
+ border.color:"gray"
+ TextInput {
+ id: textbox
+ width:parent.width
+ anchors.verticalCenter:parent.verticalCenter
+ font.pixelSize: 20
+ }
+ }
+
+ Button {
+ id:searchBt
+ text:"Query"
+ width: 80
+ anchors.left:cleanBt.right
+ anchors.leftMargin: 10
+ anchors.verticalCenter:parent.verticalCenter
+ onClicked: {
+ InspectorDb.loaddata(textbox.text);
+ }
+ }
+
+ Button {
+ id:saveBt
+ text:"Save query"
+ width: 100
+ anchors.left:searchBt.right
+ anchors.leftMargin: 10
+ anchors.verticalCenter:parent.verticalCenter
+ onClicked: {
+ saveQueryDialog.open();
+ // InspectorDb.loaddata(textbox.text);
+ }
+ }
+ Rectangle {
+ id: divider4
+ width: 1
+ height: saveBt.height
+ color:"black"
+ anchors.left:saveBt.right
+ anchors.leftMargin:5
+ anchors.verticalCenter:parent.verticalCenter
+ }
+
+ Button {
+ id:newBt
+ text:"New"
+ width: 60
+ anchors.left:divider4.right
+ anchors.leftMargin: 5
+ anchors.verticalCenter:parent.verticalCenter
+ onClicked: {
+ objectEditor.show = true;
+ objectEditor.createNewObject = true;
+ }
+ }
+ }
+
+
+ Dialog {
+ id: saveQueryDialog
+ onAccepted: {
+ var obj = {
+ "_type":"UserCommand",
+ "query":textbox.text,
+ "title":nameText.text
+ }
+ JsonDb.create(obj);
+ }
+
+ title: [Text {
+ text:"Save query as .."
+ // height: 40
+ width:parent.width
+ verticalAlignment:Text.AlignVCenter
+ horizontalAlignment:Text.AlignHCenter
+ font.family: "Nokia Pure"
+ font.weight:Font.Light
+ font.pixelSize:20
+ color: "#1C97FF"
+ }
+ ]
+ content: [
+ Item{
+ width:parent.width
+ height: 200
+ Rectangle {
+ anchors.centerIn:parent
+ width: 400
+ height: 30
+ color:"white"
+ border.color:"black"
+ TextInput {
+ id: nameText
+ width:parent.width - 10
+ anchors.centerIn:parent
+ font.family: "Nokia Pure"
+ font.weight:Font.Light
+ font.pixelSize:13
+ // wrapMode: Text.WordWrap
+ text:"New query"
+ }
+ }
+
+
+ }
+ ]
+ buttons: [
+ Row{
+ anchors.horizontalCenter:parent.horizontalCenter
+ spacing: 20
+ Button {
+ id: saveQueryBt
+ text: "Save"
+ onClicked: saveQueryDialog.accept()
+ }
+ Button {
+ id: cancelBt
+ // anchors.top: rmAlbumBt.bottom
+ // anchors.topMargin: root.platformStyle.buttonsTopMargin
+ text: "Cancel"
+ onClicked: saveQueryDialog.close()
+ }
+ }
+ ]
+ }
+ ListModel {
+ id: queryCmdModel
+ ListElement {
+ query: '[/_type]'
+ title: 'All items'
+ }
+ ListElement {
+ query: '[?_type="MEDIAINFO"]'
+ title:"All MEDIAINFO"
+ }
+ ListElement {
+ query: '[?_type="UserCommand"]'
+ title:"All commands"
+ }
+ }
+
+ Flow {
+ anchors.left:divider1.right
+ anchors.leftMargin: 10
+ anchors.top:divider3.bottom
+ anchors.topMargin: 10
+ anchors.right:parent.right
+ anchors.rightMargin: 20
+ spacing: 10
+
+ Repeater {
+ model:queryCmdModel
+ delegate: Button {
+ text:title
+ width: 150
+ onClicked: {
+ textbox.text = query;
+ InspectorDb.loaddata(textbox.text);
+ }
+ }
+ }
+ }
+
+ Editor {
+ id: objectEditor
+ width: parent.width
+ height :500
+ // anchors.bottom:parent.bottom
+ y: parent.height
+ property bool show: false
+ onCancelled: {
+ show = false;
+ }
+ onConfirmed: {
+ var obj = JSON.parse(content);
+ if (createNewObject) {
+ if (obj._uuid) {
+ delete obj._uuid;
+ }
+
+ JsonDb.create(obj);
+ }else {
+ if (!obj._uuid) {
+ // console.log(" missing uuid")
+ }else {
+ JsonDb.update(obj);
+ }
+ }
+ show = false;
+ }
+
+ states: [
+ State {
+ name: "show"
+ when: objectEditor.show
+ PropertyChanges {
+ target: objectEditor
+ y: screen.height - objectEditor.height
+ }
+ },
+ State {
+ name: "hide"
+ when: !objectEditor.show
+ PropertyChanges {
+ target: objectEditor
+ y: screen.height
+ }
+ }
+
+ ]
+
+ }
+
+ Component.onCompleted: { /*nokia.debug("Loading");*/ InspectorDb.inspectorStarted(); }
+}
+
diff --git a/examples/declarative/desktop-inspector/desktop-inspector.qmlproject b/examples/declarative/desktop-inspector/desktop-inspector.qmlproject
new file mode 100644
index 00000000..d4909f86
--- /dev/null
+++ b/examples/declarative/desktop-inspector/desktop-inspector.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/simplelistmodel/content/Button.qml b/examples/declarative/simplelistmodel/content/Button.qml
new file mode 100644
index 00000000..9f18fe4b
--- /dev/null
+++ b/examples/declarative/simplelistmodel/content/Button.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: bt
+ anchors.margins : 2
+ width: 100
+ height: 50
+ color: ma.pressed?'#cccccc':'#dddddd'
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ property alias text:lb.text
+ signal clicked()
+ Text {
+ id: lb
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: "Button"
+ font.pointSize: 10
+ }
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ onClicked: {
+ bt.clicked();
+ }
+ }
+}
diff --git a/examples/declarative/simplelistmodel/simplelistmodel.qml b/examples/declarative/simplelistmodel/simplelistmodel.qml
new file mode 100644
index 00000000..f468fd1e
--- /dev/null
+++ b/examples/declarative/simplelistmodel/simplelistmodel.qml
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtJsonDb 1.0 as JsonDb
+import "content"
+
+Item {
+ width: 400
+ height: 300
+
+ JsonDb.JsonDbListModel {
+ id: contacts
+ query: '[?_type="Contact"]'
+ roleNames: ["firstName", "lastName", "_uuid"]
+ limit: 40
+ }
+
+ Button {
+ id: buttonAdd
+ anchors.top: parent.top
+ width: parent.width/4
+ text: "Add contact"
+
+ onClicked: {
+ var firstNames = ["Malcolm", "Zoe", "Hoban", "Inara", "Jayne", "Kaylee", "Simon", "River", "Shepard"]
+ var lastNames = ["Reinolds", "Washburn", "Serra", "Cobb", "Frye", "Tam", "Book"]
+ function rand(n) { return Math.floor(Math.random() * n); }
+
+ var firstName = firstNames[rand(firstNames.length)]
+ var lastName = lastNames[rand(lastNames.length)]
+ JsonDb.create({"_type":"Contact", "firstName":firstName, "lastName":lastName})
+ }
+ }
+
+ Button {
+ id: buttonDelete
+ anchors.top: parent.top
+ anchors.left: buttonAdd.right
+ width: parent.width/4
+ text: "Delete item"
+
+ onClicked: {
+ JsonDb.remove({"_uuid": contacts.get(listView.currentIndex, "_uuid")})
+ console.log("Removed Item : " + contacts.get(listView.currentIndex, "_uuid"))
+ }
+ }
+
+
+ Button {
+ id: buttonSortFName
+ anchors.top: parent.top
+ anchors.left: buttonDelete.right
+ width: parent.width/4
+ text: "Sort firstName"
+
+ onClicked: {
+ contacts.query = ("[?_type=\"Contact\"][/firstName]")
+ }
+ }
+
+ Button {
+ id: buttonSortLName
+ anchors.top: parent.top
+ anchors.left: buttonSortFName.right
+ anchors.right: parent.right
+ text: "Sort lastName"
+
+ onClicked: {
+ contacts.query = ("[?_type=\"Contact\"][/lastName]")
+ }
+ }
+
+
+ ListView {
+ id: listView
+ anchors.top: buttonAdd.bottom
+ anchors.bottom: statusText.top
+ anchors.topMargin: 10
+ anchors.bottomMargin: 10
+ width: parent.width
+ model: contacts
+ highlight: Rectangle { color: "lightsteelblue"; radius: 5 ;width: 200;}
+ focus: true
+ delegate: Row {
+ spacing: 10
+ Text {
+ text: firstName + ", " + lastName
+ MouseArea {
+ anchors.fill: parent;
+ onPressed: {
+ listView.currentIndex = index;
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: statusText
+ anchors.bottom: parent.bottom
+ width: parent.width
+ height: 20
+ color: "lightgray"
+ Text {
+ anchors.centerIn: parent
+ text: "limit : " + contacts.limit + " rowCount : " + contacts.rowCount + " state : " + contacts.state
+ }
+ }
+}
diff --git a/examples/declarative/simplelistmodel/simplelistmodel.qmlproject b/examples/declarative/simplelistmodel/simplelistmodel.qmlproject
new file mode 100644
index 00000000..d4909f86
--- /dev/null
+++ b/examples/declarative/simplelistmodel/simplelistmodel.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/jsondb.pro b/jsondb.pro
new file mode 100644
index 00000000..a483fbda
--- /dev/null
+++ b/jsondb.pro
@@ -0,0 +1,20 @@
+TEMPLATE = subdirs
+
+module_qtjsondb_src.subdir = src
+module_qtjsondb_src.target = module-qtjsondb-src
+
+module_qtjsondb_tools.subdir = tools
+module_qtjsondb_tools.target = module-qtjsondb-tools
+module_qtjsondb_tools.depends = module_qtjsondb_src
+
+module_qtjsondb_tests.subdir = tests
+module_qtjsondb_tests.target = module-qtjsondb-tests
+module_qtjsondb_tests.depends = module_qtjsondb_src
+module_qtjsondb_tests.CONFIG = no_default_install
+# that line does not seem to work and tests are always disabled
+#!contains(QT_BUILD_PARTS,tests):module_qtjsondb_tests.CONFIG += no_default_target
+SUBDIRS += module_qtjsondb_src \
+ module_qtjsondb_tools \
+ module_qtjsondb_tests \
+
+include(doc/doc.pri)
diff --git a/modules/qt_jsondb.pri b/modules/qt_jsondb.pri
new file mode 100644
index 00000000..b1314c4a
--- /dev/null
+++ b/modules/qt_jsondb.pri
@@ -0,0 +1,16 @@
+QT.jsondb.VERSION = 1.0.0
+QT.jsondb.MAJOR_VERSION = 1
+QT.jsondb.MINOR_VERSION = 0
+QT.jsondb.PATCH_VERSION = 0
+
+QT.jsondb.name = QtAddOnJsonDb
+QT.jsondb.bins = $$QT_MODULE_BIN_BASE
+QT.jsondb.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtAddOnJsonDb
+QT.jsondb.private_includes = $$QT_MODULE_INCLUDE_BASE/QtAddOnJsonDb/$$QT.jsondb.VERSION
+QT.jsondb.sources = $$QT_MODULE_BASE/src
+QT.jsondb.libs = $$QT_MODULE_LIB_BASE
+QT.jsondb.plugins = $$QT_MODULE_PLUGIN_BASE
+QT.jsondb.imports = $$QT_MODULE_IMPORT_BASE
+QT.jsondb.depends = core network declarative jsondbqson
+
+QT_CONFIG += jsondb
diff --git a/modules/qt_jsondb_qson.pri b/modules/qt_jsondb_qson.pri
new file mode 100644
index 00000000..8f742f80
--- /dev/null
+++ b/modules/qt_jsondb_qson.pri
@@ -0,0 +1,16 @@
+QT.jsondbqson.VERSION = 1.0.0
+QT.jsondbqson.MAJOR_VERSION = 1
+QT.jsondbqson.MINOR_VERSION = 0
+QT.jsondbqson.PATCH_VERSION = 0
+
+QT.jsondbqson.name = QtJsonDbQson
+QT.jsondbqson.bins = $$QT_MODULE_BIN_BASE
+QT.jsondbqson.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtJsonDbQson
+QT.jsondbqson.private_includes = $$QT_MODULE_INCLUDE_BASE/QtJsonDbQson/$$QT.jsondbqson.VERSION
+QT.jsondbqson.sources = $$QT_MODULE_BASE/src
+QT.jsondbqson.libs = $$QT_MODULE_LIB_BASE
+QT.jsondbqson.plugins = $$QT_MODULE_PLUGIN_BASE
+QT.jsondbqson.imports = $$QT_MODULE_IMPORT_BASE
+QT.jsondbqson.depends = core
+
+QT_CONFIG += jsondbqson
diff --git a/src/3rdparty/3rdparty.pro b/src/3rdparty/3rdparty.pro
new file mode 100644
index 00000000..566e1725
--- /dev/null
+++ b/src/3rdparty/3rdparty.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+
diff --git a/src/3rdparty/btree/btree.pri b/src/3rdparty/btree/btree.pri
new file mode 100644
index 00000000..93ba493b
--- /dev/null
+++ b/src/3rdparty/btree/btree.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD/src $$PWD/compat
+
+HEADERS += \
+ $$PWD/src/btree.h \
+ $$PWD/compat/sys/queue.h \
+ $$PWD/compat/sys/tree.h
+
+SOURCES += \
+ $$PWD/src/btree.cpp
+
+!mac:LIBS += -lssl -lcrypto
diff --git a/src/3rdparty/btree/compat/sys/queue.h b/src/3rdparty/btree/compat/sys/queue.h
new file mode 100644
index 00000000..38130e08
--- /dev/null
+++ b/src/3rdparty/btree/compat/sys/queue.h
@@ -0,0 +1,527 @@
+/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
+ for ((varp) = &SLIST_FIRST((head)); \
+ ((var) = *(varp)) != SLIST_END(head); \
+ (varp) = &SLIST_NEXT((var), field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_NEXT(head, elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ _Q_INVALIDATE((elm)->field.sle_next); \
+ } \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/src/3rdparty/btree/compat/sys/tree.h b/src/3rdparty/btree/compat/sys/tree.h
new file mode 100644
index 00000000..30c62b6d
--- /dev/null
+++ b/src/3rdparty/btree/compat/sys/tree.h
@@ -0,0 +1,738 @@
+/* $OpenBSD: tree.h,v 1.12 2009/03/02 09:42:55 mikeb Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while ((__comp = (cmp)(elm, (head)->sph_root))) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)))\
+ RB_COLOR(oleft, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)))\
+ RB_COLOR(oright, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field))) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field))); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/src/3rdparty/btree/src/btree.cpp b/src/3rdparty/btree/src/btree.cpp
new file mode 100644
index 00000000..d4a00994
--- /dev/null
+++ b/src/3rdparty/btree/src/btree.cpp
@@ -0,0 +1,3784 @@
+/* $OpenBSD: btree.c,v 1.30 2010/09/01 12:13:21 martinh Exp $ */
+
+/*
+ * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(__APPLE__)
+# define COMMON_DIGEST_FOR_OPENSSL
+# include <CommonCrypto/CommonDigest.h>
+# define SHA1 CC_SHA1
+#else
+# include <openssl/sha.h>
+#endif
+
+#include "btree.h"
+
+#define ATTR_PACKED __attribute__((packed))
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DPRINTF(...) do { fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); } while (0)
+#else
+# define DPRINTF(...) do { } while (0)
+#endif
+
+#ifndef NO_ERROR_MESSAGES
+# define EPRINTF(...) do { fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); } while (0)
+#else
+# define EPRINTF(...) do { } while (0)
+#endif
+
+#define PAGESIZE 4096
+#define BT_MINKEYS 4
+#define BT_MAGIC 0xB3DBB3DB
+#define BT_VERSION 4
+#define MAXKEYSIZE 255
+
+#define P_INVALID 0xFFFFFFFF
+
+#define F_ISSET(w, f) (((w) & (f)) == (f))
+
+typedef uint32_t pgno_t;
+typedef uint16_t indx_t;
+
+/* There are four page types: meta, index, leaf and overflow.
+ * They all share the same page header.
+ */
+struct page { /* represents an on-disk page */
+ pgno_t pgno; /* page number */
+#define P_BRANCH 0x01 /* branch page */
+#define P_LEAF 0x02 /* leaf page */
+#define P_OVERFLOW 0x04 /* overflow page */
+#define P_META 0x08 /* meta page */
+#define P_HEAD 0x10 /* header page */
+ uint32_t flags;
+#define lower b.fb.fb_lower
+#define upper b.fb.fb_upper
+#define p_next_pgno b.pb_next_pgno
+ union page_bounds {
+ struct {
+ indx_t fb_lower; /* lower bound of free space */
+ indx_t fb_upper; /* upper bound of free space */
+ } fb;
+ pgno_t pb_next_pgno; /* overflow page linked list */
+ } b;
+ indx_t ptrs[1]; /* dynamic size */
+} ATTR_PACKED;
+
+#define PAGEHDRSZ offsetof(struct page, ptrs)
+
+#define NUMKEYSP(p) (((p)->lower - PAGEHDRSZ) >> 1)
+#define NUMKEYS(mp) (((mp)->page->lower - PAGEHDRSZ) >> 1)
+#define SIZELEFT(mp) (indx_t)((mp)->page->upper - (mp)->page->lower)
+#define PAGEFILL(bt, mp) (1000 * ((bt)->head.psize - PAGEHDRSZ - SIZELEFT(mp)) / \
+ ((bt)->head.psize - PAGEHDRSZ))
+#define IS_LEAF(mp) F_ISSET((mp)->page->flags, P_LEAF)
+#define IS_BRANCH(mp) F_ISSET((mp)->page->flags, P_BRANCH)
+#define IS_OVERFLOW(mp) F_ISSET((mp)->page->flags, P_OVERFLOW)
+
+struct bt_head { /* header page content */
+ uint32_t magic;
+ uint32_t version;
+ uint32_t flags;
+ uint32_t psize; /* page size */
+} ATTR_PACKED;
+
+struct bt_meta { /* meta (footer) page content */
+#define BT_TOMBSTONE 0x01 /* file is replaced */
+#define BT_MARKER 0x02 /* flushed with fsync */
+ uint32_t flags;
+ pgno_t root; /* page number of root page */
+ pgno_t prev_meta; /* previous meta page number */
+ uint64_t created_at; /* time_t type */
+ uint32_t branch_pages;
+ uint32_t leaf_pages;
+ uint32_t overflow_pages;
+ uint32_t revisions;
+ uint32_t depth;
+ uint64_t entries;
+ uint32_t tag;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+} ATTR_PACKED;
+
+struct btkey {
+ size_t len;
+ char str[MAXKEYSIZE];
+};
+
+struct mpage { /* an in-memory cached page */
+ RB_ENTRY(mpage) entry; /* page cache entry */
+ SIMPLEQ_ENTRY(mpage) next; /* queue of dirty pages */
+ TAILQ_ENTRY(mpage) lru_next; /* LRU queue */
+ struct mpage *parent; /* NULL if root */
+ unsigned int parent_index; /* keep track of node index */
+ struct btkey prefix;
+ struct page *page;
+ pgno_t pgno; /* copy of page->pgno */
+ short ref; /* increased by cursors */
+ short dirty; /* 1 if on dirty queue */
+};
+RB_HEAD(page_cache, mpage);
+SIMPLEQ_HEAD(dirty_queue, mpage);
+TAILQ_HEAD(lru_queue, mpage);
+
+static int mpage_cmp(struct mpage *a, struct mpage *b);
+static struct mpage *mpage_lookup(struct btree *bt, pgno_t pgno);
+static void mpage_add(struct btree *bt, struct mpage *mp);
+static void mpage_free(struct mpage *mp);
+static void mpage_del(struct btree *bt, struct mpage *mp);
+static void mpage_flush(struct btree *bt);
+static struct mpage *mpage_copy(struct btree *bt, struct mpage *mp);
+static void mpage_prune(struct btree *bt);
+static void mpage_dirty(struct btree *bt, struct mpage *mp);
+static struct mpage *mpage_touch(struct btree *bt, struct mpage *mp);
+
+RB_PROTOTYPE(page_cache, mpage, entry, mpage_cmp);
+RB_GENERATE(page_cache, mpage, entry, mpage_cmp);
+
+struct ppage { /* ordered list of pages */
+ SLIST_ENTRY(ppage) entry;
+ struct mpage *mpage;
+ unsigned int ki; /* cursor index on page */
+};
+SLIST_HEAD(page_stack, ppage);
+
+#define CURSOR_EMPTY(c) SLIST_EMPTY(&(c)->stack)
+#define CURSOR_TOP(c) SLIST_FIRST(&(c)->stack)
+#define CURSOR_POP(c) SLIST_REMOVE_HEAD(&(c)->stack, entry)
+#define CURSOR_PUSH(c,p) SLIST_INSERT_HEAD(&(c)->stack, p, entry)
+
+struct cursor {
+ struct btree *bt;
+ struct btree_txn *txn;
+ struct page_stack stack; /* stack of parent pages */
+ short initialized; /* 1 if initialized */
+ short eof; /* 1 if end is reached */
+};
+
+#define METAHASHLEN offsetof(struct bt_meta, hash)
+#define METADATA(p) ((bt_meta *)((char *)p + PAGEHDRSZ))
+
+struct node {
+#define n_pgno p.np_pgno
+#define n_dsize p.np_dsize
+ union {
+ pgno_t np_pgno; /* child page number */
+ uint32_t np_dsize; /* leaf data size */
+ } p;
+ uint16_t ksize; /* key size */
+#define F_BIGDATA 0x01 /* data put on overflow page */
+ uint8_t flags;
+ char data[1];
+} ATTR_PACKED;
+
+struct btree_txn {
+ pgno_t root; /* current / new root page */
+ pgno_t next_pgno; /* next unallocated page */
+ struct btree *bt; /* btree is ref'd */
+ struct dirty_queue *dirty_queue; /* modified pages */
+#define BT_TXN_RDONLY 0x01 /* read-only transaction */
+#define BT_TXN_ERROR 0x02 /* an error has occurred */
+ unsigned int flags;
+ unsigned int tag; /* a tag on which the transaction was initiated */
+};
+
+class btree {
+public:
+ btree();
+ int fd;
+ char *path;
+#define BT_FIXPADDING 0x01 /* internal */
+ unsigned int flags;
+ bt_cmp_func cmp; /* user compare function */
+ struct bt_head head;
+ struct bt_meta meta;
+ struct page_cache *page_cache;
+ struct lru_queue *lru_queue;
+ struct btree_txn *txn; /* current write transaction */
+ int ref; /* increased by cursors & txn */
+ struct btree_stat stat;
+ off_t size; /* current file size */
+};
+
+btree::btree()
+ : fd(0)
+ , path(0)
+ , flags(0)
+ , cmp(0)
+ , lru_queue(0)
+ , txn(0)
+ , ref(0)
+ , size(0)
+{
+ memset(&head, 0, sizeof(head));
+ memset(&meta, 0, sizeof(meta));
+ memset(&stat, 0, sizeof(stat));
+}
+
+#define NODESIZE offsetof(struct node, data)
+
+#define INDXSIZE(k) (NODESIZE + ((k) == NULL ? 0 : (k)->size))
+#define LEAFSIZE(k, d) (NODESIZE + (k)->size + (d)->size)
+#define NODEPTRP(p, i) ((struct node *)((char *)(p) + (p)->ptrs[i]))
+#define NODEPTR(mp, i) NODEPTRP((mp)->page, i)
+#define NODEKEY(node) (char *)((node)->data)
+#define NODEDATA(node) (char *)((char *)(node)->data + (node)->ksize)
+#define NODEPGNO(node) ((node)->p.np_pgno)
+#define NODEDSZ(node) ((node)->p.np_dsize)
+
+#define BT_COMMIT_PAGES 64 /* max number of pages to write in one commit */
+#define BT_MAXCACHE_DEF 1024 /* max number of pages to keep in cache */
+
+
+
+void btree_dump_tree(struct btree *bt, pgno_t pgno, int depth);
+void btree_dump_page_from_memory(struct page *p);
+void btree_dump(struct btree *bt);
+
+static int btree_read_page(struct btree *bt, pgno_t pgno,
+ struct page *page);
+static struct mpage *btree_get_mpage(struct btree *bt, pgno_t pgno);
+enum SearchType {
+ SearchKey=0,
+ SearchFirst=1,
+ SearchLast=2,
+};
+static int btree_search_page_root(struct btree *bt,
+ struct mpage *root, struct btval *key,
+ struct cursor *cursor, enum SearchType searchType, int modify,
+ struct mpage **mpp);
+static int btree_search_page(struct btree *bt,
+ struct btree_txn *txn, struct btval *key,
+ struct cursor *cursor, enum SearchType searchType, int modify,
+ struct mpage **mpp);
+
+static int btree_write_header(struct btree *bt, int fd);
+static int btree_read_header(struct btree *bt);
+static int btree_is_meta_page(struct page *p);
+static int btree_read_meta(struct btree *bt, pgno_t *p_next);
+static int btree_write_meta(struct btree *bt, pgno_t root,
+ unsigned int flags, uint32_t tag);
+static void btree_ref(struct btree *bt);
+
+static struct node *btree_search_node(struct btree *bt, struct mpage *mp,
+ struct btval *key, int *exactp, unsigned int *kip);
+static int btree_add_node(struct btree *bt, struct mpage *mp,
+ indx_t indx, struct btval *key, struct btval *data,
+ pgno_t pgno, uint8_t flags);
+static void btree_del_node(struct btree *bt, struct mpage *mp,
+ indx_t indx);
+static int btree_read_data(struct btree *bt, struct mpage *mp,
+ struct node *leaf, struct btval *data);
+
+static int btree_rebalance(struct btree *bt, struct mpage *mp);
+static int btree_update_key(struct btree *bt, struct mpage *mp,
+ indx_t indx, struct btval *key);
+static int btree_adjust_prefix(struct btree *bt,
+ struct mpage *src, int delta);
+static int btree_move_node(struct btree *bt, struct mpage *src,
+ indx_t srcindx, struct mpage *dst, indx_t dstindx);
+static int btree_merge(struct btree *bt, struct mpage *src,
+ struct mpage *dst);
+static int btree_split(struct btree *bt, struct mpage **mpp,
+ unsigned int *newindxp, struct btval *newkey,
+ struct btval *newdata, pgno_t newpgno);
+static struct mpage *btree_new_page(struct btree *bt, uint32_t flags);
+static int btree_write_overflow_data(struct btree *bt,
+ struct page *p, struct btval *data);
+
+static void cursor_pop_page(struct cursor *cursor);
+static struct ppage *cursor_push_page(struct cursor *cursor,
+ struct mpage *mp);
+
+static int bt_set_key(struct btree *bt, struct mpage *mp,
+ struct node *node, struct btval *key);
+static int btree_sibling(struct cursor *cursor, int move_right, int rightmost);
+static int btree_cursor_next(struct cursor *cursor,
+ struct btval *key, struct btval *data);
+static int btree_cursor_prev(struct cursor *cursor,
+ struct btval *key, struct btval *data);
+static int btree_cursor_set(struct cursor *cursor,
+ struct btval *key, struct btval *data, int *exactp);
+static int btree_cursor_first(struct cursor *cursor,
+ struct btval *key, struct btval *data);
+
+static void bt_reduce_separator(struct btree *bt, struct node *min,
+ struct btval *sep);
+static void remove_prefix(struct btree *bt, struct btval *key,
+ size_t pfxlen);
+static void expand_prefix(struct btree *bt, struct mpage *mp,
+ indx_t indx, struct btkey *expkey);
+static void concat_prefix(struct btree *bt, char *pfxstr, size_t pfxlen,
+ char *keystr, size_t keylen,char *dest, size_t *size);
+static void common_prefix(struct btree *bt, struct btkey *min,
+ struct btkey *max, struct btkey *pfx);
+static void find_common_prefix(struct btree *bt, struct mpage *mp);
+
+static size_t bt_leaf_size(struct btree *bt, struct btval *key,
+ struct btval *data);
+static size_t bt_branch_size(struct btree *bt, struct btval *key);
+
+static pgno_t btree_compact_tree(struct btree *bt, pgno_t pgno,
+ struct btree *btc);
+
+static int memncmp(const void *s1, size_t n1,
+ const void *s2, size_t n2, void *);
+static int memnrcmp(const void *s1, size_t n1,
+ const void *s2, size_t n2, void *);
+
+static int
+memncmp(const void *s1, size_t n1, const void *s2, size_t n2, void *)
+{
+ if (n1 < n2) {
+ int ret = memcmp(s1, s2, n1);
+ if (ret == 0)
+ return -1;
+ else return ret;
+ }
+ else if (n1 > n2) {
+ int ret = memcmp(s1, s2, n2);
+ if (ret == 0)
+ return 1;
+ else return ret;
+ }
+ return memcmp(s1, s2, n1);
+}
+
+static int
+memnrcmp(const void *s1, size_t n1, const void *s2, size_t n2, void *)
+{
+ const unsigned char *p1;
+ const unsigned char *p2;
+
+ if (n1 == 0)
+ return n2 == 0 ? 0 : -1;
+
+ if (n2 == 0)
+ return n1 == 0 ? 0 : 1;
+
+ p1 = (const unsigned char *)s1 + n1 - 1;
+ p2 = (const unsigned char *)s2 + n2 - 1;
+
+ while (*p1 == *p2) {
+ if (p1 == s1)
+ return (p2 == s2) ? 0 : -1;
+ if (p2 == s2)
+ return (p1 == p2) ? 0 : 1;
+ p1--;
+ p2--;
+ }
+ return *p1 - *p2;
+}
+
+void
+btree_set_cmp(struct btree *bt, bt_cmp_func cmp)
+{
+ bt->cmp = cmp;
+}
+
+int
+btree_cmp(struct btree *bt, const struct btval *a, const struct btval *b)
+{
+ return bt->cmp((const char *)a->data, a->size, (const char *)b->data, b->size, 0);
+}
+
+static void
+common_prefix(struct btree *bt, struct btkey *min, struct btkey *max,
+ struct btkey *pfx)
+{
+ size_t n = 0;
+ char *p1;
+ char *p2;
+
+ if (min->len == 0 || max->len == 0 || bt->cmp) {
+ pfx->len = 0;
+ return;
+ }
+
+ if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
+ p1 = min->str + min->len - 1;
+ p2 = max->str + max->len - 1;
+
+ while (*p1 == *p2) {
+ p1--;
+ p2--;
+ n++;
+ if (p1 < min->str || p2 < max->str)
+ break;
+ }
+
+ assert(n <= (int)sizeof(pfx->str));
+ pfx->len = n;
+ bcopy(p2 + 1, pfx->str, n);
+ } else {
+ p1 = min->str;
+ p2 = max->str;
+
+ while (*p1 == *p2) {
+ p1++;
+ p2++;
+ n++;
+ if (n == min->len || n == max->len)
+ break;
+ }
+
+ assert(n <= (int)sizeof(pfx->str));
+ pfx->len = n;
+ bcopy(max->str, pfx->str, n);
+ }
+}
+
+static void
+remove_prefix(struct btree *bt, struct btval *key, size_t pfxlen)
+{
+ assert(bt);
+ if (pfxlen == 0 || bt->cmp != NULL)
+ return;
+
+ DPRINTF("removing %zu bytes of prefix from key [%.*s]", pfxlen,
+ (int)key->size, (char *)key->data);
+ assert(pfxlen <= key->size);
+ key->size -= pfxlen;
+ if (!F_ISSET(bt->flags, BT_REVERSEKEY))
+ key->data = (char *)key->data + pfxlen;
+}
+
+static void
+expand_prefix(struct btree *bt, struct mpage *mp, indx_t indx,
+ struct btkey *expkey)
+{
+ struct node *node;
+
+ node = NODEPTR(mp, indx);
+ expkey->len = sizeof(expkey->str);
+ concat_prefix(bt, mp->prefix.str, mp->prefix.len,
+ NODEKEY(node), node->ksize, expkey->str, &expkey->len);
+}
+
+static int
+bt_cmp(struct btree *bt, const struct btval *key1, const struct btval *key2,
+ struct btkey *pfx)
+{
+ if (bt->cmp) {
+ return bt->cmp((const char*)key1->data, key1->size, (const char*)key2->data, key2->size, 0);
+ } else {
+ if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
+ return memnrcmp(key1->data, key1->size - pfx->len,
+ key2->data, key2->size, 0);
+ } else {
+ return memncmp((char *)key1->data + pfx->len, key1->size - pfx->len,
+ key2->data, key2->size, 0);
+
+ }
+ }
+}
+
+void
+btval_reset(struct btval *btv)
+{
+ if (btv) {
+ if (btv->mp)
+ btv->mp->ref--;
+ if (btv->free_data)
+ free(btv->data);
+ bzero(btv, sizeof(*btv));
+ }
+}
+
+static int
+mpage_cmp(struct mpage *a, struct mpage *b)
+{
+ if (a->pgno > b->pgno)
+ return 1;
+ if (a->pgno < b->pgno)
+ return -1;
+ return 0;
+}
+
+static struct mpage *
+mpage_lookup(struct btree *bt, pgno_t pgno)
+{
+ struct mpage find;
+ struct mpage *mp = 0;
+
+ find.pgno = pgno;
+ mp = RB_FIND(page_cache, bt->page_cache, &find);
+ if (mp) {
+ bt->stat.hits++;
+ /* Update LRU queue. Move page to the end. */
+ TAILQ_REMOVE(bt->lru_queue, mp, lru_next);
+ TAILQ_INSERT_TAIL(bt->lru_queue, mp, lru_next);
+ }
+ return mp;
+}
+
+static void
+mpage_add(struct btree *bt, struct mpage *mp)
+{
+ assert(RB_INSERT(page_cache, bt->page_cache, mp) == NULL);
+ DPRINTF("mpage_add: mp=%p pgno=%d", mp, mp->pgno);
+ bt->stat.cache_size++;
+ TAILQ_INSERT_TAIL(bt->lru_queue, mp, lru_next);
+}
+
+static void
+mpage_free(struct mpage *mp)
+{
+ if (mp != NULL) {
+ free(mp->page);
+ free(mp);
+ }
+}
+
+static void
+mpage_del(struct btree *bt, struct mpage *mp)
+{
+ assert(RB_REMOVE(page_cache, bt->page_cache, mp) == mp);
+ DPRINTF("mpage_del: mp=%p pgno=%d", mp, mp->pgno);
+ assert(bt->stat.cache_size > 0);
+ bt->stat.cache_size--;
+ TAILQ_REMOVE(bt->lru_queue, mp, lru_next);
+}
+
+static void
+mpage_flush(struct btree *bt)
+{
+ struct mpage *mp;
+
+ while ((mp = RB_MIN(page_cache, bt->page_cache)) != NULL) {
+ mpage_del(bt, mp);
+ mpage_free(mp);
+ }
+}
+
+static struct mpage *
+mpage_copy(struct btree *bt, struct mpage *mp)
+{
+ struct mpage *copy;
+
+ if ((copy = (mpage *)calloc(1, sizeof(*copy))) == NULL)
+ return NULL;
+ if ((copy->page = (page *)malloc(bt->head.psize)) == NULL) {
+ free(copy);
+ return NULL;
+ }
+ bcopy(mp->page, copy->page, bt->head.psize);
+ bcopy(&mp->prefix, &copy->prefix, sizeof(mp->prefix));
+ copy->parent = mp->parent;
+ copy->parent_index = mp->parent_index;
+ copy->pgno = mp->pgno;
+
+ return copy;
+}
+
+/* Remove the least recently used memory pages until the cache size is
+ * within the configured bounds. Pages referenced by cursors or returned
+ * key/data are not pruned.
+ */
+static void
+mpage_prune(struct btree *bt)
+{
+ struct mpage *mp, *next;
+
+ for (mp = TAILQ_FIRST(bt->lru_queue); mp; mp = next) {
+ if (bt->stat.cache_size <= bt->stat.max_cache)
+ break;
+ next = TAILQ_NEXT(mp, lru_next);
+ if (!mp->dirty && mp->ref <= 0) {
+ mpage_del(bt, mp);
+ mpage_free(mp);
+ }
+ }
+}
+
+/* Mark a page as dirty and push it on the dirty queue.
+ */
+static void
+mpage_dirty(struct btree *bt, struct mpage *mp)
+{
+ assert(bt != NULL);
+ assert(bt->txn != NULL);
+
+ if (!mp->dirty) {
+ mp->dirty = 1;
+ SIMPLEQ_INSERT_TAIL(bt->txn->dirty_queue, mp, next);
+ }
+}
+
+/* Touch a page: make it dirty and re-insert into tree with updated pgno.
+ */
+static struct mpage *
+mpage_touch(struct btree *bt, struct mpage *mp)
+{
+ assert(bt != NULL);
+ assert(bt->txn != NULL);
+ assert(mp != NULL);
+
+ if (!mp->dirty) {
+ DPRINTF("touching page %u -> %u", mp->pgno, bt->txn->next_pgno);
+ if (mp->ref == 0)
+ mpage_del(bt, mp);
+ else {
+ if ((mp = mpage_copy(bt, mp)) == NULL)
+ return NULL;
+ }
+ mp->pgno = mp->page->pgno = bt->txn->next_pgno++;
+ mpage_dirty(bt, mp);
+ mpage_add(bt, mp);
+
+ /* Update the page number to new touched page. */
+ if (mp->parent != NULL)
+ NODEPGNO(NODEPTR(mp->parent,
+ mp->parent_index)) = mp->pgno;
+ }
+
+ return mp;
+}
+
+static int
+btree_read_page(struct btree *bt, pgno_t pgno, struct page *page)
+{
+ ssize_t rc;
+
+ DPRINTF("reading page %u", pgno);
+ bt->stat.reads++;
+ if ((rc = pread(bt->fd, page, bt->head.psize, (off_t)pgno*bt->head.psize)) == 0) {
+ DPRINTF("page %u doesn't exist", pgno);
+ errno = ENOENT;
+ return BT_FAIL;
+ } else if (rc != (ssize_t)bt->head.psize) {
+ if (rc > 0)
+ errno = EINVAL;
+ fprintf(stderr, "%s:%d: short pread rc=%Zd psize=%d\n",
+ __FUNCTION__, __LINE__, rc, bt->head.psize);
+ DPRINTF("read: %s", strerror(errno));
+ return BT_FAIL;
+ }
+
+ if (page->pgno != pgno) {
+ DPRINTF("page numbers don't match: %u != %u", pgno, page->pgno);
+ fprintf(stderr, "%s:%d: page numbers don't match\n",
+ __FUNCTION__, __LINE__);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ DPRINTF("page %u has flags 0x%X", pgno, page->flags);
+
+ return BT_SUCCESS;
+}
+
+int
+btree_sync_internal(struct btree *bt)
+{
+ if (!F_ISSET(bt->flags, BT_NOSYNC))
+ return fsync(bt->fd);
+ return 0;
+}
+int
+btree_sync(struct btree *bt)
+{
+ if (!F_ISSET(bt->flags, BT_NOSYNC))
+ return fsync(bt->fd);
+ if (F_ISSET(bt->flags, BT_USEMARKER) && !F_ISSET(bt->meta.flags, BT_MARKER)) {
+ /* we want to use marker and the last meta page doesn't have it */
+ /* put a copy of the last meta page but this time with a marker */
+ if (bt->txn) {
+ EPRINTF("btree_sync while in transaction is not a good idea");
+ return BT_FAIL;
+ }
+ if (fsync(bt->fd) != 0)
+ return BT_FAIL;
+ bt->txn = btree_txn_begin(bt, 0);
+ if (bt->txn == 0)
+ return BT_FAIL;
+ if (btree_write_meta(bt, bt->meta.root, BT_MARKER, bt->meta.tag) == BT_FAIL) {
+ btree_txn_abort(bt->txn);
+ return BT_FAIL;
+ }
+ btree_txn_abort(bt->txn);
+ return BT_SUCCESS;
+ }
+ return 0;
+}
+
+
+struct btree_txn *
+btree_txn_begin(struct btree *bt, int rdonly)
+{
+ struct btree_txn *txn;
+
+ if (!rdonly && bt->txn != NULL) {
+ DPRINTF("write transaction already begun");
+ errno = EBUSY;
+ return NULL;
+ }
+
+ if ((txn = (btree_txn *)calloc(1, sizeof(*txn))) == NULL) {
+ DPRINTF("calloc: %s", strerror(errno));
+ return NULL;
+ }
+
+ if (rdonly) {
+ txn->flags |= BT_TXN_RDONLY;
+ } else {
+ txn->dirty_queue = (dirty_queue *)calloc(1, sizeof(*txn->dirty_queue));
+ if (txn->dirty_queue == NULL) {
+ free(txn);
+ return NULL;
+ }
+ SIMPLEQ_INIT(txn->dirty_queue);
+
+ DPRINTF("taking write lock on txn %p", txn);
+ if (flock(bt->fd, LOCK_EX | LOCK_NB) != 0) {
+ DPRINTF("flock: %s", strerror(errno));
+ errno = EBUSY;
+ free(txn->dirty_queue);
+ free(txn);
+ return NULL;
+ }
+ bt->txn = txn;
+ }
+
+ txn->bt = bt;
+ btree_ref(bt);
+
+ if (btree_read_meta(bt, &txn->next_pgno) != BT_SUCCESS) {
+ btree_txn_abort(txn);
+ return NULL;
+ }
+
+ txn->root = bt->meta.root;
+ txn->tag = bt->meta.tag;
+ DPRINTF("begin transaction on btree %p, root page %u (tag %d)", bt, txn->root, txn->tag);
+
+ return txn;
+}
+
+void
+btree_txn_abort(struct btree_txn *txn)
+{
+ struct mpage *mp;
+ struct btree *bt;
+
+ if (txn == NULL)
+ return;
+
+ bt = txn->bt;
+ DPRINTF("abort transaction on btree %p, root page %u", bt, txn->root);
+
+ if (!F_ISSET(txn->flags, BT_TXN_RDONLY)) {
+ /* Discard all dirty pages.
+ */
+ while (!SIMPLEQ_EMPTY(txn->dirty_queue)) {
+ mp = SIMPLEQ_FIRST(txn->dirty_queue);
+ assert(mp->ref == 0); /* cursors should be closed */
+ mpage_del(bt, mp);
+ SIMPLEQ_REMOVE_HEAD(txn->dirty_queue, next);
+ mpage_free(mp);
+ }
+
+ DPRINTF("releasing write lock on txn %p", txn);
+ txn->bt->txn = NULL;
+ if (flock(txn->bt->fd, LOCK_UN) != 0) {
+ DPRINTF("failed to unlock fd %d: %s",
+ txn->bt->fd, strerror(errno));
+ }
+ free(txn->dirty_queue);
+ }
+
+ btree_close(txn->bt);
+ free(txn);
+}
+
+unsigned int
+btree_txn_get_tag(struct btree_txn *txn)
+{
+ assert(txn != 0);
+ return txn->tag;
+}
+
+int
+btree_txn_commit(struct btree_txn *txn, unsigned int tag, unsigned int flags)
+{
+ int n, done;
+ ssize_t rc;
+ off_t size;
+ struct mpage *mp;
+ struct btree *bt;
+ struct iovec iov[BT_COMMIT_PAGES];
+ const int needfsync = !F_ISSET(txn->bt->flags, BT_NOSYNC) || F_ISSET(flags, BT_FORCE_MARKER);
+
+ assert(txn != NULL);
+ assert(txn->bt != NULL);
+
+ bt = txn->bt;
+
+ if (F_ISSET(txn->flags, BT_TXN_RDONLY)) {
+ DPRINTF("attempt to commit read-only transaction");
+ btree_txn_abort(txn);
+ errno = EPERM;
+ return BT_FAIL;
+ }
+
+ if (txn != bt->txn) {
+ EPRINTF("attempt to commit unknown transaction");
+ btree_txn_abort(txn);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (F_ISSET(txn->flags, BT_TXN_ERROR)) {
+ EPRINTF("error flag is set, can't commit");
+ btree_txn_abort(txn);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (SIMPLEQ_EMPTY(txn->dirty_queue)) {
+ if (bt->stat.tag != tag) {
+ if (btree_write_meta(bt, txn->root, BT_MARKER, tag) != BT_SUCCESS) {
+ btree_txn_abort(txn);
+ return BT_FAIL;
+ }
+ }
+ goto done;
+ }
+
+ if (F_ISSET(bt->flags, BT_FIXPADDING)) {
+ size = lseek(bt->fd, 0, SEEK_END);
+ size += bt->head.psize - (size % bt->head.psize);
+ DPRINTF("extending to multiple of page size: %llu", (long long unsigned)size);
+ if (ftruncate(bt->fd, size) != 0) {
+ DPRINTF("ftruncate: %s", strerror(errno));
+ btree_txn_abort(txn);
+ return BT_FAIL;
+ }
+ bt->flags &= ~BT_FIXPADDING;
+ }
+
+ DPRINTF("committing transaction on btree %p, root page %u",
+ bt, txn->root);
+
+ /* Commit up to BT_COMMIT_PAGES dirty pages to disk until done.
+ */
+ do {
+ n = 0;
+ done = 1;
+ SIMPLEQ_FOREACH(mp, txn->dirty_queue, next) {
+ DPRINTF("commiting page %u", mp->pgno);
+ iov[n].iov_len = bt->head.psize;
+ iov[n].iov_base = mp->page;
+ if (++n >= BT_COMMIT_PAGES) {
+ done = 0;
+ break;
+ }
+ }
+
+ if (n == 0)
+ break;
+
+ DPRINTF("commiting %u dirty pages", n);
+ rc = writev(bt->fd, iov, n);
+ if (rc != (ssize_t)bt->head.psize*n) {
+ if (rc > 0) {
+ DPRINTF("short write, filesystem full?");
+ } else {
+ DPRINTF("writev: %s", strerror(errno));
+ }
+ btree_txn_abort(txn);
+ return BT_FAIL;
+ }
+
+ /* Remove the dirty flag from the written pages.
+ */
+ while (!SIMPLEQ_EMPTY(txn->dirty_queue)) {
+ mp = SIMPLEQ_FIRST(txn->dirty_queue);
+ mp->dirty = 0;
+ SIMPLEQ_REMOVE_HEAD(txn->dirty_queue, next);
+ if (--n == 0)
+ break;
+ }
+ } while (!done);
+
+ if (needfsync) {
+ if (fsync(bt->fd) != 0) {
+ btree_txn_abort(txn);
+ return BT_FAIL;
+ }
+ }
+ if (btree_write_meta(bt, txn->root,
+ needfsync ? BT_MARKER : 0,
+ tag) != BT_SUCCESS) {
+ btree_txn_abort(txn);
+ return BT_FAIL;
+ }
+
+done:
+ mpage_prune(bt);
+ btree_txn_abort(txn);
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_write_header(struct btree *bt, int fd)
+{
+ struct stat sb;
+ struct bt_head *h;
+ struct page *p;
+ ssize_t rc;
+ unsigned int psize;
+
+ DPRINTF("writing header page");
+ assert(bt != NULL);
+
+ /* Ask stat for optimal blocksize for I/O but
+ don't use smaller than the initial page size */
+ psize = PAGESIZE;
+ if (fstat(fd, &sb) == 0 && sb.st_blksize > PAGESIZE)
+ psize = sb.st_blksize;
+
+ if ((p = (page *)calloc(1, psize)) == NULL)
+ return -1;
+ p->flags = P_HEAD;
+
+ h = (bt_head *)METADATA(p);
+ h->magic = BT_MAGIC;
+ h->version = BT_VERSION;
+ h->psize = psize;
+ bcopy(h, &bt->head, sizeof(*h));
+
+ rc = write(fd, p, bt->head.psize);
+ free(p);
+ if (rc != (ssize_t)bt->head.psize) {
+ if (rc > 0)
+ DPRINTF("short write, filesystem full?");
+ return BT_FAIL;
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_read_header(struct btree *bt)
+{
+ char page[PAGESIZE];
+ struct page *p;
+ struct bt_head *h;
+ int rc;
+
+ assert(bt != NULL);
+
+ /* We don't know the page size yet, so use a minimum value.
+ */
+
+ if ((rc = pread(bt->fd, page, PAGESIZE, 0)) == 0) {
+ errno = ENOENT;
+ return -1;
+ } else if (rc != PAGESIZE) {
+ if (rc > 0)
+ errno = EINVAL;
+ EPRINTF("read: %s", strerror(errno));
+ return -1;
+ }
+
+ p = (struct page *)page;
+
+ if (!F_ISSET(p->flags, P_HEAD)) {
+ EPRINTF("page %d not a header page", p->pgno);
+ errno = EINVAL;
+ return -1;
+ }
+
+ h = (bt_head *)METADATA(p);
+ if (h->magic != BT_MAGIC) {
+ EPRINTF("header has invalid magic");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (h->version != BT_VERSION) {
+ EPRINTF("database is version %u, expected version %u",
+ bt->head.version, BT_VERSION);
+ errno = EINVAL;
+ return -1;
+ }
+
+ bcopy(h, &bt->head, sizeof(*h));
+ DPRINTF("btree_read_header: magic = %x", bt->head.magic);
+ DPRINTF("btree_read_header: version = %d", bt->head.version);
+ DPRINTF("btree_read_header: flags = %d", bt->head.flags);
+ DPRINTF("btree_read_header: psize = %d", bt->head.psize);
+ return 0;
+}
+
+static int
+btree_write_meta(struct btree *bt, pgno_t root, unsigned int flags, uint32_t tag)
+{
+ struct mpage *mp;
+ struct bt_meta *meta;
+ ssize_t rc;
+
+ DPRINTF("writing meta page for root page %u with flags %d and tag %d", root, flags, tag);
+
+ assert(bt != NULL);
+ assert(bt->txn != NULL);
+
+ if ((mp = btree_new_page(bt, P_META)) == NULL)
+ return -1;
+
+ bt->meta.prev_meta = bt->meta.root;
+ bt->meta.root = root;
+ bt->meta.flags = flags;
+ bt->meta.created_at = time(0);
+ bt->meta.revisions++;
+ bt->meta.tag = tag;
+ SHA1((unsigned char *)&bt->meta, METAHASHLEN, bt->meta.hash);
+
+ /* Copy the meta data changes to the new meta page. */
+ meta = METADATA(mp->page);
+ bcopy(&bt->meta, meta, sizeof(*meta));
+
+ rc = write(bt->fd, mp->page, bt->head.psize);
+ mp->dirty = 0;
+ SIMPLEQ_REMOVE_HEAD(bt->txn->dirty_queue, next);
+ if (rc != (ssize_t)bt->head.psize) {
+ if (rc > 0)
+ DPRINTF("short write, filesystem full?");
+ return BT_FAIL;
+ }
+
+ if ((bt->size = lseek(bt->fd, 0, SEEK_END)) == -1) {
+ DPRINTF("failed to update file size: %s", strerror(errno));
+ bt->size = 0;
+ }
+ return BT_SUCCESS;
+}
+
+/* Returns true if page p is a valid meta page, false otherwise.
+ */
+static int
+btree_is_meta_page(struct page *p)
+{
+ struct bt_meta *m;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ m = METADATA(p);
+ if (!F_ISSET(p->flags, P_META)) {
+ DPRINTF("page %d not a meta page", p->pgno);
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (m->root >= p->pgno && m->root != P_INVALID) {
+ EPRINTF("page %d points to an invalid root page", p->pgno);
+ errno = EINVAL;
+ return 0;
+ }
+
+ SHA1((unsigned char *)m, METAHASHLEN, hash);
+
+ if (bcmp(hash, m->hash, SHA_DIGEST_LENGTH) != 0) {
+ EPRINTF("page %d has an invalid digest", p->pgno);
+ errno = EINVAL;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+btree_read_meta(struct btree *bt, pgno_t *p_next)
+{
+ struct mpage *mp;
+ struct bt_meta *meta;
+ pgno_t meta_pgno, next_pgno;
+ off_t size;
+
+ assert(bt != NULL);
+
+ if ((size = lseek(bt->fd, 0, SEEK_END)) == -1) {
+ fprintf(stderr, "failed to lseek errno=%d\n", errno);
+ goto fail;
+ }
+
+ DPRINTF("btree_read_meta: size = %llu", (long long unsigned)size);
+
+ if (size < bt->size) {
+ DPRINTF("file has shrunk!");
+ fprintf(stderr, "file has shrunk\n");
+ errno = EIO;
+ goto fail;
+ }
+
+ if ((uint32_t)size == bt->head.psize) { /* there is only the header */
+ if (p_next != NULL)
+ *p_next = 1;
+ return BT_SUCCESS; /* new file */
+ }
+
+ next_pgno = size / bt->head.psize;
+ if (next_pgno == 0) {
+ DPRINTF("corrupt file");
+ fprintf(stderr, "corrupt file\n");
+ errno = EIO;
+ goto fail;
+ }
+
+ meta_pgno = next_pgno - 1;
+
+ if (size % bt->head.psize != 0) {
+ DPRINTF("filesize not a multiple of the page size!");
+ bt->flags |= BT_FIXPADDING;
+ next_pgno++;
+ }
+
+ if (p_next != NULL)
+ *p_next = next_pgno;
+
+ if (size == bt->size) {
+ DPRINTF("size unchanged, keeping current meta page");
+ if (F_ISSET(bt->meta.flags, BT_TOMBSTONE)) {
+ DPRINTF("file is dead");
+ errno = ESTALE;
+ return BT_FAIL;
+ } else
+ return BT_SUCCESS;
+ }
+ bt->size = size;
+
+ while (meta_pgno > 0) {
+ mp = btree_get_mpage(bt, meta_pgno);
+ if (mp && btree_is_meta_page(mp->page)) {
+ meta = METADATA(mp->page);
+ DPRINTF("flags = 0x%x", meta->flags);
+ if (F_ISSET(meta->flags, BT_TOMBSTONE)) {
+ DPRINTF("file is dead");
+ errno = ESTALE;
+ return BT_FAIL;
+ } else if (F_ISSET(bt->flags, BT_USEMARKER) && !F_ISSET(meta->flags, BT_MARKER)) {
+ DPRINTF("found a meta page %d but without marker, skipping...", meta_pgno);
+ /* skipping this meta page */
+ } else {
+ /* Make copy of last meta page. */
+ bcopy(meta, &bt->meta, sizeof(bt->meta));
+ return BT_SUCCESS;
+ }
+ }
+ --meta_pgno; /* scan backwards to first valid meta page */
+ }
+
+ errno = EIO;
+ fprintf(stderr, "failed somehow errno=%d\n", errno);
+fail:
+ if (p_next != NULL)
+ *p_next = P_INVALID;
+ return BT_FAIL;
+}
+
+struct btree *
+btree_open_fd(const char *path, int fd, unsigned int flags)
+{
+ struct btree *bt;
+ int fl;
+
+ fl = fcntl(fd, F_GETFL, 0);
+ int rc;
+ if ((rc = fcntl(fd, F_SETFL, fl | O_APPEND)) == -1) {
+ fprintf(stderr, "fcntl fd=%d rc=%d errno=%d\n", fd, rc, errno);
+ return NULL;
+ }
+
+ bt = new btree; // FIXME add out of memory check
+ bt->path = strdup(path);
+ bt->fd = fd;
+ bt->flags = flags;
+ bt->flags &= ~BT_FIXPADDING;
+ bt->ref = 1;
+ bt->meta.root = P_INVALID;
+
+ if ((bt->page_cache = (struct page_cache *)calloc(1, sizeof(*bt->page_cache))) == NULL)
+ goto fail;
+ bt->stat.max_cache = BT_MAXCACHE_DEF;
+ RB_INIT(bt->page_cache);
+
+ if ((bt->lru_queue = (lru_queue *)calloc(1, sizeof(*bt->lru_queue))) == NULL) {
+ fprintf(stderr, "failed to allocate lru_queue\n");
+ goto fail;
+ }
+ TAILQ_INIT(bt->lru_queue);
+
+ if (btree_read_header(bt) != 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "failed to read header\n");
+ goto fail;
+ }
+ DPRINTF("new database");
+ btree_write_header(bt, bt->fd);
+ }
+
+ if (btree_read_meta(bt, NULL) != 0) {
+ fprintf(stderr, "failed to read meta\n");
+ goto fail;
+ }
+
+ DPRINTF("opened database version %u, pagesize %u",
+ bt->head.version, bt->head.psize);
+ DPRINTF("timestamp: %s", ctime((const time_t *)&bt->meta.created_at));
+ DPRINTF("depth: %u", bt->meta.depth);
+ DPRINTF("entries: %llu", (long long unsigned)bt->meta.entries);
+ DPRINTF("revisions: %u", bt->meta.revisions);
+ DPRINTF("branch pages: %u", bt->meta.branch_pages);
+ DPRINTF("leaf pages: %u", bt->meta.leaf_pages);
+ DPRINTF("overflow pages: %u", bt->meta.overflow_pages);
+ DPRINTF("root: %u", bt->meta.root);
+ DPRINTF("previous meta page: %u", bt->meta.prev_meta);
+
+ return bt;
+
+fail:
+ fprintf(stderr, "%s: fail errno=%d\n", bt->path, errno);
+ free(bt->lru_queue);
+ free(bt->page_cache);
+ free(bt->path);
+ delete bt;
+ return NULL;
+}
+
+struct btree *
+btree_open(const char *path, unsigned int flags, mode_t mode)
+{
+ int fd, oflags;
+ struct btree *bt;
+
+ if (F_ISSET(flags, BT_RDONLY))
+ oflags = O_RDONLY;
+ else
+ oflags = O_RDWR | O_CREAT | O_APPEND;
+
+ fd = open(path, oflags, mode);
+ if (fd == -1)
+ return NULL;
+ if ((bt = btree_open_fd(path, fd, flags)) == NULL)
+ close(fd);
+ else {
+ DPRINTF("opened btree %p", bt);
+ }
+
+ return bt;
+}
+
+int btree_get_fd(struct btree *bt)
+{
+ return bt->fd;
+}
+
+static void
+btree_ref(struct btree *bt)
+{
+ bt->ref++;
+ DPRINTF("ref is now %d on btree %p", bt->ref, bt);
+}
+
+void
+btree_close(struct btree *bt)
+{
+ if (bt == NULL)
+ return;
+
+ if (bt->ref == 1 && F_ISSET(bt->flags, BT_USEMARKER))
+ btree_sync(bt);
+
+ if (--bt->ref == 0) {
+ DPRINTF("ref is zero, closing btree %p:%s", bt, bt->path);
+ close(bt->fd);
+ mpage_flush(bt);
+ free(bt->page_cache);
+ free(bt->lru_queue);
+ free(bt->path);
+ delete bt;
+ } else
+ DPRINTF("ref is now %d on btree %p", bt->ref, bt);
+}
+
+/* Search for key within a leaf page, using binary search.
+ * Returns the smallest entry larger or equal to the key.
+ * If exactp is non-null, stores whether the found entry was an exact match
+ * in *exactp (1 or 0).
+ * If kip is non-null, stores the index of the found entry in *kip.
+ * If no entry larger of equal to the key is found, returns NULL.
+ */
+static struct node *
+btree_search_node(struct btree *bt, struct mpage *mp, struct btval *key,
+ int *exactp, unsigned int *kip)
+{
+ unsigned int i = 0;
+ int low, high;
+ int rc = 0;
+ struct node *node;
+ struct btval nodekey;
+
+ DPRINTF("searching for [%.*s] in %lu keys in %s page %u with prefix [%.*s]",
+ key->size, (const char*)key->data,
+ NUMKEYS(mp),
+ IS_LEAF(mp) ? "leaf" : "branch",
+ mp->pgno, (int)mp->prefix.len, (char *)mp->prefix.str);
+
+ assert(NUMKEYS(mp) > 0);
+
+ bzero(&nodekey, sizeof(nodekey));
+
+ low = IS_LEAF(mp) ? 0 : 1;
+ high = NUMKEYS(mp) - 1;
+ while (low <= high) {
+ i = (low + high) >> 1;
+ node = NODEPTR(mp, i);
+
+ nodekey.size = node->ksize;
+ nodekey.data = NODEKEY(node);
+
+ rc = bt_cmp(bt, key, &nodekey, &mp->prefix);
+
+ if (IS_LEAF(mp))
+ DPRINTF("found leaf index %u [%.*s], rc = %i",
+ i, (int)nodekey.size, (char *)nodekey.data, rc);
+ else
+ DPRINTF("found branch index %u [%.*s -> %u], rc = %i",
+ i, (int)node->ksize, (char *)NODEKEY(node),
+ node->n_pgno, rc);
+
+ if (rc == 0)
+ break;
+ if (rc > 0)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ if (rc > 0) { /* Found entry is less than the key. */
+ i++; /* Skip to get the smallest entry larger than key. */
+ if (i >= NUMKEYS(mp))
+ /* There is no entry larger or equal to the key. */
+ return NULL;
+ }
+ if (exactp)
+ *exactp = (rc == 0);
+ if (kip) /* Store the key index if requested. */
+ *kip = i;
+
+ return NODEPTR(mp, i);
+}
+
+static void
+cursor_pop_page(struct cursor *cursor)
+{
+ struct ppage *top;
+
+ top = CURSOR_TOP(cursor);
+ CURSOR_POP(cursor);
+ top->mpage->ref--;
+
+ DPRINTF("popped page %u off cursor %p", top->mpage->pgno, cursor);
+
+ free(top);
+}
+
+static struct ppage *
+cursor_push_page(struct cursor *cursor, struct mpage *mp)
+{
+ struct ppage *ppage;
+
+ DPRINTF("pushing page %u on cursor %p", mp->pgno, cursor);
+
+ if ((ppage = (struct ppage *)calloc(1, sizeof(struct ppage))) == NULL)
+ return NULL;
+ ppage->mpage = mp;
+ mp->ref++;
+ CURSOR_PUSH(cursor, ppage);
+ return ppage;
+}
+
+static struct mpage *
+btree_get_mpage(struct btree *bt, pgno_t pgno)
+{
+ struct mpage *mp;
+
+ mp = mpage_lookup(bt, pgno);
+ if (mp == NULL) {
+ if ((mp = (mpage *)calloc(1, sizeof(*mp))) == NULL)
+ return NULL;
+ if ((mp->page = (page *)malloc(bt->head.psize)) == NULL) {
+ free(mp);
+ return NULL;
+ }
+ if (btree_read_page(bt, pgno, mp->page) != BT_SUCCESS) {
+ mpage_free(mp);
+ return NULL;
+ }
+ mp->pgno = pgno;
+ mpage_add(bt, mp);
+ } else
+ DPRINTF("returning page %u from cache", pgno);
+
+ DPRINTF("btree_get_mpage %p", mp);
+ return mp;
+}
+
+static void
+concat_prefix(struct btree *bt, char *s1, size_t n1, char *s2, size_t n2,
+ char *cs, size_t *cn)
+{
+ assert(*cn >= n1 + n2);
+ if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
+ bcopy(s2, cs, n2);
+ bcopy(s1, cs + n2, n1);
+ } else {
+ bcopy(s1, cs, n1);
+ bcopy(s2, cs + n1, n2);
+ }
+ *cn = n1 + n2;
+}
+
+static void
+find_common_prefix(struct btree *bt, struct mpage *mp)
+{
+ if (bt->cmp != NULL)
+ return;
+
+ indx_t lbound = 0, ubound = 0;
+ struct mpage *lp, *up;
+ struct btkey lprefix, uprefix;
+
+ mp->prefix.len = 0;
+
+ lp = mp;
+ while (lp->parent != NULL) {
+ if (lp->parent_index > 0) {
+ lbound = lp->parent_index;
+ break;
+ }
+ lp = lp->parent;
+ }
+
+ up = mp;
+ while (up->parent != NULL) {
+ if (up->parent_index + 1 < (indx_t)NUMKEYS(up->parent)) {
+ ubound = up->parent_index + 1;
+ break;
+ }
+ up = up->parent;
+ }
+
+ if (lp->parent != NULL && up->parent != NULL) {
+ expand_prefix(bt, lp->parent, lbound, &lprefix);
+ expand_prefix(bt, up->parent, ubound, &uprefix);
+ common_prefix(bt, &lprefix, &uprefix, &mp->prefix);
+ }
+ else if (mp->parent)
+ bcopy(&mp->parent->prefix, &mp->prefix, sizeof(mp->prefix));
+
+ DPRINTF("found common prefix [%.*s] (len %zu) for page %u",
+ (int)mp->prefix.len, mp->prefix.str, mp->prefix.len, mp->pgno);
+}
+
+static int
+btree_search_page_root(struct btree *bt, struct mpage *root, struct btval *key,
+ struct cursor *cursor, enum SearchType searchType, int modify, struct mpage **mpp)
+{
+ struct mpage *mp, *parent;
+
+ if (cursor && cursor_push_page(cursor, root) == NULL)
+ return BT_FAIL;
+
+ mp = root;
+ DPRINTF("searchType=%d isBranch=%d", searchType, IS_BRANCH(mp));
+ while (IS_BRANCH(mp)) {
+ unsigned int i = 0;
+ struct node *node;
+
+ DPRINTF("branch page %u has %lu keys", mp->pgno, NUMKEYS(mp));
+ assert(NUMKEYS(mp) > 1);
+ DPRINTF("found index 0 to page %u", NODEPGNO(NODEPTR(mp, 0)));
+
+ if (searchType == SearchFirst) /* Initialize cursor to first page. */
+ i = 0;
+ else if (searchType == SearchLast) { /* Initialize cursor to last page. */
+ i = NUMKEYS(mp) - 1;
+ DPRINTF("SearchLast i=%d", i);
+ } else {
+ int exact;
+ node = btree_search_node(bt, mp, key, &exact, &i);
+ if (node == NULL)
+ i = NUMKEYS(mp) - 1;
+ else if (!exact) {
+ assert(i > 0);
+ i--;
+ }
+ }
+
+ if (key)
+ DPRINTF("following index %u for key %.*s",
+ i, (int)key->size, (char *)key->data);
+ assert(i < NUMKEYS(mp));
+ node = NODEPTR(mp, i);
+
+ if (cursor)
+ CURSOR_TOP(cursor)->ki = i;
+
+ parent = mp;
+ if ((mp = btree_get_mpage(bt, NODEPGNO(node))) == NULL)
+ return BT_FAIL;
+ mp->parent = parent;
+ mp->parent_index = i;
+ find_common_prefix(bt, mp);
+
+ if (cursor && cursor_push_page(cursor, mp) == NULL)
+ return BT_FAIL;
+
+ if (modify && (mp = mpage_touch(bt, mp)) == NULL)
+ return BT_FAIL;
+ }
+
+ if (!IS_LEAF(mp)) {
+ DPRINTF("internal error, index points to a %02X page!?",
+ mp->page->flags);
+ return BT_FAIL;
+ }
+
+ DPRINTF("found leaf page %u for key %.*s", mp->pgno,
+ key ? (int)key->size : 0, key ? (char *)key->data : NULL);
+
+ *mpp = mp;
+ return BT_SUCCESS;
+}
+
+/* Search for the page a given key should be in.
+ * Stores a pointer to the found page in *mpp.
+ * Searches for key if searchType is SearchKey
+ * Searches for the lowest page if searchType is SearchFirst
+ * Searches for the highest page if searchType is SearchLast
+ * If cursor is non-null, pushes parent pages on the cursor stack.
+ * If modify is true, visited pages are updated with new page numbers.
+ */
+static int
+btree_search_page(struct btree *bt, struct btree_txn *txn, struct btval *key,
+ struct cursor *cursor, enum SearchType searchType, int modify, struct mpage **mpp)
+{
+ int rc;
+ pgno_t root;
+ struct mpage *mp = 0;
+
+ /* Can't modify pages outside a transaction. */
+ if (txn == NULL && modify) {
+ EPRINTF("cannot modify pages outside a transaction");
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ /* Choose which root page to start with. If a transaction is given
+ * use the root page from the transaction, otherwise read the last
+ * committed root page.
+ */
+ if (txn == NULL) {
+ if ((rc = btree_read_meta(bt, NULL)) != BT_SUCCESS)
+ return rc;
+ root = bt->meta.root;
+ } else if (F_ISSET(txn->flags, BT_TXN_ERROR)) {
+ EPRINTF("transaction has failed, must abort");
+ errno = EINVAL;
+ return BT_FAIL;
+ } else
+ root = txn->root;
+
+ if (root == P_INVALID) { /* Tree is empty. */
+ DPRINTF("tree is empty");
+ errno = ENOENT;
+ return BT_FAIL;
+ }
+
+ if ((mp = btree_get_mpage(bt, root)) == NULL)
+ return BT_FAIL;
+
+ DPRINTF("root page has flags 0x%X mp=%p", mp->page->flags, mp);
+
+ assert(mp->parent == NULL);
+ assert(mp->prefix.len == 0);
+
+ if (modify && !mp->dirty) {
+ if ((mp = mpage_touch(bt, mp)) == NULL)
+ return BT_FAIL;
+ txn->root = mp->pgno;
+ }
+
+ return btree_search_page_root(bt, mp, key, cursor, searchType, modify, mpp);
+}
+
+static int
+btree_read_data(struct btree *bt, struct mpage *mp, struct node *leaf,
+ struct btval *data)
+{
+ struct mpage *omp; /* overflow mpage */
+ size_t psz;
+ size_t max;
+ size_t sz = 0;
+ pgno_t pgno;
+
+ bzero(data, sizeof(*data));
+ max = bt->head.psize - PAGEHDRSZ;
+
+ if (!F_ISSET(leaf->flags, F_BIGDATA)) {
+ data->size = leaf->n_dsize;
+ if (data->size > 0) {
+ if (mp == NULL) {
+ if ((data->data = malloc(data->size)) == NULL)
+ return BT_FAIL;
+ bcopy(NODEDATA(leaf), data->data, data->size);
+ data->free_data = 1;
+ data->mp = NULL;
+ } else {
+ data->data = NODEDATA(leaf);
+ data->free_data = 0;
+ data->mp = mp;
+ mp->ref++;
+ }
+ }
+ return BT_SUCCESS;
+ }
+
+ /* Read overflow data.
+ */
+ DPRINTF("allocating %u byte for overflow data", leaf->n_dsize);
+ if ((data->data = malloc(leaf->n_dsize)) == NULL)
+ return BT_FAIL;
+ data->size = leaf->n_dsize;
+ data->free_data = 1;
+ data->mp = NULL;
+ bcopy(NODEDATA(leaf), &pgno, sizeof(pgno));
+ for (sz = 0; sz < data->size; ) {
+ if ((omp = btree_get_mpage(bt, pgno)) == NULL ||
+ !F_ISSET(omp->page->flags, P_OVERFLOW)) {
+ DPRINTF("read overflow page %u failed", pgno);
+ free(data->data);
+ mpage_free(omp);
+ return BT_FAIL;
+ }
+ psz = data->size - sz;
+ if (psz > max)
+ psz = max;
+ bcopy(omp->page->ptrs, (char *)data->data + sz, psz);
+ sz += psz;
+ pgno = omp->page->p_next_pgno;
+ }
+
+ return BT_SUCCESS;
+}
+
+int
+btree_txn_get(struct btree *bt, struct btree_txn *txn,
+ struct btval *key, struct btval *data)
+{
+ int rc, exact;
+ struct node *leaf;
+ struct mpage *mp;
+
+ assert(key);
+ assert(data);
+ DPRINTF("===> get key [%.*s]", (int)key->size, (char *)key->data);
+
+ if (bt != NULL && txn != NULL && bt != txn->bt) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (bt == NULL) {
+ if (txn == NULL) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+ bt = txn->bt;
+ }
+
+ if (key->size == 0 || key->size > MAXKEYSIZE) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if ((rc = btree_search_page(bt, txn, key, NULL, SearchKey, 0, &mp)) != BT_SUCCESS)
+ return rc;
+
+ leaf = btree_search_node(bt, mp, key, &exact, NULL);
+ if (leaf && exact)
+ rc = btree_read_data(bt, mp, leaf, data);
+ else {
+ errno = ENOENT;
+ rc = BT_FAIL;
+ }
+
+ mpage_prune(bt);
+ return rc;
+}
+
+static int
+btree_sibling(struct cursor *cursor, int move_right, int rightmost)
+{
+ int rc;
+ struct node *indx;
+ struct ppage *parent, *top;
+ struct mpage *mp;
+
+ top = CURSOR_TOP(cursor);
+ if ((parent = SLIST_NEXT(top, entry)) == NULL) {
+ errno = ENOENT;
+ return BT_FAIL; /* root has no siblings */
+ }
+
+ DPRINTF("parent page is page %u, index %u",
+ parent->mpage->pgno, parent->ki);
+
+ cursor_pop_page(cursor);
+ if (move_right ? (parent->ki + 1 >= NUMKEYS(parent->mpage))
+ : (parent->ki == 0)) {
+ DPRINTF("no more keys left, moving to %s node of %s sibling",
+ rightmost ? "rightmost" : "leftmost",
+ move_right ? "right" : "left");
+ if ((rc = btree_sibling(cursor, move_right, rightmost)) != BT_SUCCESS)
+ return rc;
+ parent = CURSOR_TOP(cursor);
+ } else {
+ if (move_right)
+ parent->ki++;
+ else
+ parent->ki--;
+ DPRINTF("just moving to %s index key %u",
+ move_right ? "right" : "left", parent->ki);
+ }
+ assert(IS_BRANCH(parent->mpage));
+
+ indx = NODEPTR(parent->mpage, parent->ki);
+ if ((mp = btree_get_mpage(cursor->bt, indx->n_pgno)) == NULL)
+ return BT_FAIL;
+ mp->parent = parent->mpage;
+ mp->parent_index = parent->ki;
+
+ top = cursor_push_page(cursor, mp);
+ find_common_prefix(cursor->bt, mp);
+ if (rightmost)
+ top->ki = NUMKEYS(mp)-1;
+
+ return BT_SUCCESS;
+}
+
+static int
+bt_set_key(struct btree *bt, struct mpage *mp, struct node *node,
+ struct btval *key)
+{
+ if (key == NULL)
+ return 0;
+
+ if (mp->prefix.len > 0) {
+ key->size = node->ksize + mp->prefix.len;
+ key->data = malloc(key->size);
+ if (key->data == NULL)
+ return -1;
+ concat_prefix(bt,
+ mp->prefix.str, mp->prefix.len,
+ NODEKEY(node), node->ksize,
+ (char *)key->data, &key->size);
+ key->free_data = 1;
+ } else {
+ key->size = node->ksize;
+ key->data = NODEKEY(node);
+ key->free_data = 0;
+ key->mp = mp;
+ mp->ref++;
+ }
+
+ return 0;
+}
+
+static int
+btree_cursor_next(struct cursor *cursor, struct btval *key, struct btval *data)
+{
+ struct ppage *top;
+ struct mpage *mp;
+ struct node *leaf;
+
+ if (cursor->eof) {
+ errno = ENOENT;
+ return BT_FAIL;
+ }
+
+ assert(cursor->initialized);
+
+ top = CURSOR_TOP(cursor);
+ mp = top->mpage;
+
+ DPRINTF("cursor_next: top page is %u in cursor %p", mp->pgno, cursor);
+
+ if (top->ki + 1 >= NUMKEYS(mp)) {
+ DPRINTF("=====> move to next sibling page");
+ if (btree_sibling(cursor, 1, 0) != BT_SUCCESS) {
+ cursor->eof = 1;
+ return BT_FAIL;
+ }
+ top = CURSOR_TOP(cursor);
+ mp = top->mpage;
+ DPRINTF("next page is %u, key index %u", mp->pgno, top->ki);
+ } else
+ top->ki++;
+
+ DPRINTF("==> cursor points to page %u with %lu keys, key index %u",
+ mp->pgno, NUMKEYS(mp), top->ki);
+
+ assert(IS_LEAF(mp));
+ leaf = NODEPTR(mp, top->ki);
+
+ if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
+ return BT_FAIL;
+
+ if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
+ return BT_FAIL;
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_cursor_prev(struct cursor *cursor, struct btval *key, struct btval *data)
+{
+ struct ppage *top;
+ struct mpage *mp;
+ struct node *leaf;
+
+ if (cursor->eof) {
+ errno = ENOENT;
+ return BT_FAIL;
+ }
+
+ assert(cursor->initialized);
+
+ top = CURSOR_TOP(cursor);
+ mp = top->mpage;
+
+ DPRINTF("top page is %u in cursor %p", mp->pgno, cursor);
+
+ if (top->ki - 1 == -1u) {
+ DPRINTF("=====> move to prev sibling page");
+ if (btree_sibling(cursor, 0, 1) != BT_SUCCESS) {
+ cursor->eof = 1;
+ return BT_FAIL;
+ }
+ top = CURSOR_TOP(cursor);
+ mp = top->mpage;
+ DPRINTF("next page is %u, key index %u", mp->pgno, top->ki);
+ } else
+ top->ki--;
+
+ DPRINTF("==> cursor points to page %u with %lu keys, key index %u",
+ mp->pgno, NUMKEYS(mp), top->ki);
+
+ assert(IS_LEAF(mp));
+ leaf = NODEPTR(mp, top->ki);
+
+ if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
+ return BT_FAIL;
+
+ if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
+ return BT_FAIL;
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_cursor_set(struct cursor *cursor, struct btval *key, struct btval *data,
+ int *exactp)
+{
+ int rc;
+ struct node *leaf;
+ struct mpage *mp;
+ struct ppage *top;
+
+ assert(cursor);
+ assert(key);
+ assert(key->size > 0);
+
+ rc = btree_search_page(cursor->bt, cursor->txn, key, cursor, SearchKey, 0, &mp);
+ if (rc != BT_SUCCESS)
+ return rc;
+ assert(IS_LEAF(mp));
+
+ top = CURSOR_TOP(cursor);
+ leaf = btree_search_node(cursor->bt, mp, key, exactp, &top->ki);
+ if (exactp != NULL && !*exactp) {
+ /* BT_CURSOR_EXACT specified and not an exact match. */
+ errno = ENOENT;
+ return BT_FAIL;
+ }
+
+ if (leaf == NULL) {
+ DPRINTF("===> inexact leaf not found, goto sibling");
+ if (btree_sibling(cursor, 1, 0) != BT_SUCCESS)
+ return BT_FAIL; /* no entries matched */
+ top = CURSOR_TOP(cursor);
+ top->ki = 0;
+ mp = top->mpage;
+ assert(IS_LEAF(mp));
+ leaf = NODEPTR(mp, 0);
+ }
+
+ cursor->initialized = 1;
+ cursor->eof = 0;
+
+ if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
+ return BT_FAIL;
+
+ if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
+ return BT_FAIL;
+ DPRINTF("==> cursor placed on key %.*s",
+ (int)key->size, (char *)key->data);
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_cursor_first(struct cursor *cursor, struct btval *key, struct btval *data)
+{
+ int rc;
+ struct mpage *mp;
+ struct node *leaf;
+
+ rc = btree_search_page(cursor->bt, cursor->txn, NULL, cursor, SearchFirst, 0, &mp);
+ if (rc != BT_SUCCESS)
+ return rc;
+ assert(IS_LEAF(mp));
+
+ leaf = NODEPTR(mp, 0);
+ cursor->initialized = 1;
+ cursor->eof = 0;
+
+ if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
+ return BT_FAIL;
+
+ if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
+ return BT_FAIL;
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_cursor_last(struct cursor *cursor, struct btval *key, struct btval *data)
+{
+ int rc;
+ struct mpage *mp;
+ struct node *leaf;
+ struct ppage *top;
+
+ rc = btree_search_page(cursor->bt, cursor->txn, NULL, cursor, SearchLast, 0, &mp);
+ if (rc != BT_SUCCESS)
+ return rc;
+ assert(IS_LEAF(mp));
+
+ top = CURSOR_TOP(cursor);
+ // get the last leaf in the page
+ top->ki = NUMKEYS(mp)-1;
+ leaf = NODEPTR(mp, top->ki);
+ cursor->initialized = 1;
+ cursor->eof = 0;
+
+ if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
+ return BT_FAIL;
+
+ if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
+ return BT_FAIL;
+
+ return BT_SUCCESS;
+}
+
+int
+btree_cursor_get(struct cursor *cursor, struct btval *key, struct btval *data,
+ enum cursor_op op)
+{
+ int rc;
+ int exact = 0;
+
+ assert(cursor);
+
+ switch (op) {
+ case BT_CURSOR:
+ case BT_CURSOR_EXACT:
+ while (CURSOR_TOP(cursor) != NULL)
+ cursor_pop_page(cursor);
+ if (key == NULL || key->size == 0 || key->size > MAXKEYSIZE) {
+ errno = EINVAL;
+ rc = BT_FAIL;
+ } else if (op == BT_CURSOR_EXACT)
+ rc = btree_cursor_set(cursor, key, data, &exact);
+ else
+ rc = btree_cursor_set(cursor, key, data, NULL);
+ break;
+ case BT_NEXT:
+ if (!cursor->initialized)
+ rc = btree_cursor_first(cursor, key, data);
+ else
+ rc = btree_cursor_next(cursor, key, data);
+ break;
+ case BT_PREV:
+ if (!cursor->initialized)
+ rc = btree_cursor_last(cursor, key, data);
+ else
+ rc = btree_cursor_prev(cursor, key, data);
+ break;
+ case BT_FIRST:
+ while (CURSOR_TOP(cursor) != NULL)
+ cursor_pop_page(cursor);
+ rc = btree_cursor_first(cursor, key, data);
+ break;
+ case BT_LAST:
+ while (CURSOR_TOP(cursor) != NULL)
+ cursor_pop_page(cursor);
+ rc = btree_cursor_last(cursor, key, data);
+ break;
+ default:
+ DPRINTF("unhandled/unimplemented cursor operation %u", op);
+ rc = BT_FAIL;
+ break;
+ }
+
+ mpage_prune(cursor->bt);
+
+ return rc;
+}
+
+static struct mpage *
+btree_new_page(struct btree *bt, uint32_t flags)
+{
+ struct mpage *mp;
+
+ assert(bt != NULL);
+ assert(bt->txn != NULL);
+
+ DPRINTF("allocating new mpage %u, page size %u, flags %0X",
+ bt->txn->next_pgno, bt->head.psize, flags);
+ if ((mp = (mpage *)calloc(1, sizeof(*mp))) == NULL)
+ return NULL;
+ if ((mp->page = (page *)malloc(bt->head.psize)) == NULL) {
+ free(mp);
+ return NULL;
+ }
+ memset(mp->page, 0, bt->head.psize);
+ mp->pgno = mp->page->pgno = bt->txn->next_pgno++;
+ mp->page->flags = flags;
+ mp->page->lower = PAGEHDRSZ;
+ mp->page->upper = bt->head.psize;
+
+ if (IS_BRANCH(mp))
+ bt->meta.branch_pages++;
+ else if (IS_LEAF(mp))
+ bt->meta.leaf_pages++;
+ else if (IS_OVERFLOW(mp))
+ bt->meta.overflow_pages++;
+
+ mpage_add(bt, mp);
+ mpage_dirty(bt, mp);
+
+ return mp;
+}
+
+static size_t
+bt_leaf_size(struct btree *bt, struct btval *key, struct btval *data)
+{
+ size_t sz;
+
+ sz = LEAFSIZE(key, data);
+ if (data->size >= bt->head.psize / BT_MINKEYS) {
+ /* put on overflow page */
+ sz -= data->size - sizeof(pgno_t);
+ }
+
+ return sz + sizeof(indx_t);
+}
+
+static size_t
+bt_branch_size(struct btree *bt, struct btval *key)
+{
+ size_t sz;
+
+ sz = INDXSIZE(key);
+ if (sz >= bt->head.psize / BT_MINKEYS) {
+ /* put on overflow page */
+ /* not implemented */
+ /* sz -= key->size - sizeof(pgno_t); */
+ }
+
+ return sz + sizeof(indx_t);
+}
+
+static int
+btree_write_overflow_data(struct btree *bt, struct page *p, struct btval *data)
+{
+ size_t done = 0;
+ size_t sz;
+ size_t max;
+ pgno_t *linkp; /* linked page stored here */
+ struct mpage *next = NULL;
+
+ max = bt->head.psize - PAGEHDRSZ;
+
+ while (done < data->size) {
+ if (next != NULL)
+ p = next->page;
+ linkp = &p->p_next_pgno;
+ if (data->size - done > max) {
+ /* need another overflow page */
+ if ((next = btree_new_page(bt, P_OVERFLOW)) == NULL)
+ return BT_FAIL;
+ *linkp = next->pgno;
+ DPRINTF("linking overflow page %u", next->pgno);
+ } else
+ *linkp = 0; /* indicates end of list */
+ sz = data->size - done;
+ if (sz > max)
+ sz = max;
+ DPRINTF("copying %zu bytes to overflow page %u", sz, p->pgno);
+ bcopy((char *)data->data + done, p->ptrs, sz);
+ done += sz;
+ }
+
+ return BT_SUCCESS;
+}
+
+/* Key prefix should already be stripped.
+ */
+static int
+btree_add_node(struct btree *bt, struct mpage *mp, indx_t indx,
+ struct btval *key, struct btval *data, pgno_t pgno, uint8_t flags)
+{
+ unsigned int i;
+ size_t node_size = NODESIZE;
+ indx_t ofs;
+ struct node *node;
+ struct page *p;
+ struct mpage *ofp = NULL; /* overflow page */
+
+ p = mp->page;
+ assert(p->upper >= p->lower);
+
+ DPRINTF("add node [%.*s] to %s page %u at index %i, key size %zu",
+ key ? (int)key->size : 0, key ? (char *)key->data : NULL,
+ IS_LEAF(mp) ? "leaf" : "branch",
+ mp->pgno, indx, key ? key->size : 0);
+
+ if (key != NULL)
+ node_size += key->size;
+
+ if (IS_LEAF(mp)) {
+ assert(data);
+ node_size += data->size;
+ if (F_ISSET(flags, F_BIGDATA)) {
+ /* Data already on overflow page. */
+ node_size -= data->size - sizeof(pgno_t);
+ } else if ((data->size >= bt->head.psize / BT_MINKEYS)
+ || (node_size + sizeof(indx_t) > SIZELEFT(mp))) {
+ /* Put data on overflow page. */
+ DPRINTF("data size is %zu, put on overflow page",
+ data->size);
+ node_size -= data->size - sizeof(pgno_t);
+ if ((ofp = btree_new_page(bt, P_OVERFLOW)) == NULL)
+ return BT_FAIL;
+ DPRINTF("allocated overflow page %u", ofp->pgno);
+ flags |= F_BIGDATA;
+ }
+ }
+
+ if (node_size + sizeof(indx_t) > SIZELEFT(mp)) {
+ DPRINTF("not enough room in page %u, got %lu ptrs",
+ mp->pgno, NUMKEYS(mp));
+ DPRINTF("upper - lower = %u - %u = %u", p->upper, p->lower,
+ p->upper - p->lower);
+ DPRINTF("node size = %zu", node_size);
+ return BT_FAIL;
+ }
+
+ /* Move higher pointers up one slot. */
+ for (i = NUMKEYS(mp); i > indx; i--)
+ p->ptrs[i] = p->ptrs[i - 1];
+
+ /* Adjust free space offsets. */
+ ofs = p->upper - node_size;
+ assert(ofs >= p->lower + sizeof(indx_t));
+ p->ptrs[indx] = ofs;
+ p->upper = ofs;
+ p->lower += sizeof(indx_t);
+
+ /* Write the node data. */
+ node = NODEPTR(mp, indx);
+ node->ksize = (key == NULL) ? 0 : key->size;
+ node->flags = flags;
+ if (IS_LEAF(mp)) {
+ node->n_dsize = data->size;
+ } else {
+ node->n_pgno = pgno;
+ }
+
+ if (key)
+ bcopy(key->data, NODEKEY(node), key->size);
+
+ if (IS_LEAF(mp)) {
+ assert(key);
+ if (ofp == NULL) {
+ if (F_ISSET(flags, F_BIGDATA))
+ bcopy(data->data, node->data + key->size,
+ sizeof(pgno_t));
+ else
+ bcopy(data->data, node->data + key->size,
+ data->size);
+ } else {
+ bcopy(&ofp->pgno, node->data + key->size,
+ sizeof(pgno_t));
+ if (btree_write_overflow_data(bt, ofp->page,
+ data) == BT_FAIL)
+ return BT_FAIL;
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+static void
+btree_del_node(struct btree *, struct mpage *mp, indx_t indx)
+{
+ unsigned int sz;
+ indx_t i, j, numkeys, ptr;
+ struct node *node;
+ char *base;
+
+ DPRINTF("delete node %u on %s page %u", indx,
+ IS_LEAF(mp) ? "leaf" : "branch", mp->pgno);
+ assert(indx < NUMKEYS(mp));
+
+ node = NODEPTR(mp, indx);
+ sz = NODESIZE + node->ksize;
+ if (IS_LEAF(mp)) {
+ if (F_ISSET(node->flags, F_BIGDATA))
+ sz += sizeof(pgno_t);
+ else
+ sz += NODEDSZ(node);
+ }
+
+ ptr = mp->page->ptrs[indx];
+ numkeys = NUMKEYS(mp);
+ for (i = j = 0; i < numkeys; i++) {
+ if (i != indx) {
+ mp->page->ptrs[j] = mp->page->ptrs[i];
+ if (mp->page->ptrs[i] < ptr)
+ mp->page->ptrs[j] += sz;
+ j++;
+ }
+ }
+
+ base = (char *)mp->page + mp->page->upper;
+ bcopy(base, base + sz, ptr - mp->page->upper);
+
+ mp->page->lower -= sizeof(indx_t);
+ mp->page->upper += sz;
+}
+
+struct cursor *
+btree_txn_cursor_open(struct btree *bt, struct btree_txn *txn)
+{
+ struct cursor *cursor;
+
+ if (bt != NULL && txn != NULL && bt != txn->bt) {
+ errno = EINVAL;
+ DPRINTF("bt=%p does not belong to txn=%p (txn->bt=%p)", bt, txn, txn->bt);
+ return NULL;
+ }
+
+ if (bt == NULL) {
+ if (txn == NULL) {
+ errno = EINVAL;
+ DPRINTF("bt and txn both null");
+ return NULL;
+ }
+ bt = txn->bt;
+ }
+
+ if ((cursor = (struct cursor *)calloc(1, sizeof(struct cursor))) != NULL) {
+ SLIST_INIT(&cursor->stack);
+ cursor->bt = bt;
+ cursor->txn = txn;
+ btree_ref(bt);
+ }
+
+ return cursor;
+}
+
+void
+btree_cursor_close(struct cursor *cursor)
+{
+ if (cursor != NULL) {
+ while (!CURSOR_EMPTY(cursor))
+ cursor_pop_page(cursor);
+
+ btree_close(cursor->bt);
+ free(cursor);
+ }
+}
+
+static int
+btree_update_key(struct btree *, struct mpage *mp, indx_t indx,
+ struct btval *key)
+{
+ indx_t ptr, i, numkeys;
+ int delta;
+ size_t len;
+ struct node *node;
+ char *base;
+
+ node = NODEPTR(mp, indx);
+ ptr = mp->page->ptrs[indx];
+ DPRINTF("update key %u (ofs %u) [%.*s] to [%.*s] on page %u",
+ indx, ptr,
+ (int)node->ksize, (char *)NODEKEY(node),
+ (int)key->size, (char *)key->data,
+ mp->pgno);
+
+ if (key->size != node->ksize) {
+ delta = key->size - node->ksize;
+ if (delta > 0 && SIZELEFT(mp) < delta) {
+ DPRINTF("OUCH! Not enough room, delta = %d", delta);
+ return BT_FAIL;
+ }
+
+ numkeys = NUMKEYS(mp);
+ for (i = 0; i < numkeys; i++) {
+ if (mp->page->ptrs[i] <= ptr)
+ mp->page->ptrs[i] -= delta;
+ }
+
+ base = (char *)mp->page + mp->page->upper;
+ len = ptr - mp->page->upper + NODESIZE;
+ bcopy(base, base - delta, len);
+ mp->page->upper -= delta;
+
+ node = NODEPTR(mp, indx);
+ node->ksize = key->size;
+ }
+
+ bcopy(key->data, NODEKEY(node), key->size);
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_adjust_prefix(struct btree *bt, struct mpage *src, int delta)
+{
+ indx_t i;
+ struct node *node;
+ struct btkey tmpkey;
+ struct btval key;
+
+ DPRINTF("adjusting prefix lengths on page %u with delta %d",
+ src->pgno, delta);
+ assert(delta != 0);
+
+ for (i = 0; i < NUMKEYS(src); i++) {
+ node = NODEPTR(src, i);
+ tmpkey.len = node->ksize - delta;
+ if (delta > 0) {
+ if (F_ISSET(bt->flags, BT_REVERSEKEY))
+ bcopy(NODEKEY(node), tmpkey.str, tmpkey.len);
+ else
+ bcopy((char *)NODEKEY(node) + delta, tmpkey.str,
+ tmpkey.len);
+ } else {
+ if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
+ bcopy(NODEKEY(node), tmpkey.str, node->ksize);
+ bcopy(src->prefix.str, tmpkey.str + node->ksize,
+ -delta);
+ } else {
+ bcopy(src->prefix.str + src->prefix.len + delta,
+ tmpkey.str, -delta);
+ bcopy(NODEKEY(node), tmpkey.str - delta,
+ node->ksize);
+ }
+ }
+ key.size = tmpkey.len;
+ key.data = tmpkey.str;
+ if (btree_update_key(bt, src, i, &key) != BT_SUCCESS)
+ return BT_FAIL;
+ }
+
+ return BT_SUCCESS;
+}
+
+/* Move a node from src to dst.
+ */
+static int
+btree_move_node(struct btree *bt, struct mpage *src, indx_t srcindx,
+ struct mpage *dst, indx_t dstindx)
+{
+ int rc;
+ unsigned int pfxlen, mp_pfxlen = 0;
+ struct node *srcnode;
+ struct mpage *mp = NULL;
+ struct btkey tmpkey, srckey;
+ struct btval key, data;
+
+ assert(src->parent);
+ assert(dst->parent);
+
+ srcnode = NODEPTR(src, srcindx);
+ DPRINTF("moving %s node %u [%.*s] on page %u to node %u on page %u",
+ IS_LEAF(src) ? "leaf" : "branch",
+ srcindx,
+ (int)srcnode->ksize, (char *)NODEKEY(srcnode),
+ src->pgno,
+ dstindx, dst->pgno);
+
+ find_common_prefix(bt, src);
+
+ if (IS_BRANCH(src)) {
+ /* Need to check if the page the moved node points to
+ * changes prefix.
+ */
+ if ((mp = btree_get_mpage(bt, NODEPGNO(srcnode))) == NULL)
+ return BT_FAIL;
+ mp->parent = src;
+ mp->parent_index = srcindx;
+ find_common_prefix(bt, mp);
+ mp_pfxlen = mp->prefix.len;
+ }
+
+ /* Mark src and dst as dirty. */
+ if ((src = mpage_touch(bt, src)) == NULL ||
+ (dst = mpage_touch(bt, dst)) == NULL)
+ return BT_FAIL;
+
+ find_common_prefix(bt, dst);
+
+ /* Check if src node has destination page prefix. Otherwise the
+ * destination page must expand its prefix on all its nodes.
+ */
+ srckey.len = srcnode->ksize;
+ bcopy(NODEKEY(srcnode), srckey.str, srckey.len);
+ common_prefix(bt, &srckey, &dst->prefix, &tmpkey);
+ if (tmpkey.len != dst->prefix.len) {
+ if (btree_adjust_prefix(bt, dst,
+ tmpkey.len - dst->prefix.len) != BT_SUCCESS)
+ return BT_FAIL;
+ bcopy(&tmpkey, &dst->prefix, sizeof(tmpkey));
+ }
+
+ if (srcindx == 0 && IS_BRANCH(src)) {
+ struct mpage *low;
+
+ /* must find the lowest key below src
+ */
+ assert(btree_search_page_root(bt, src, NULL, NULL, SearchFirst, 0,
+ &low) == BT_SUCCESS);
+ expand_prefix(bt, low, 0, &srckey);
+ DPRINTF("found lowest key [%.*s] on leaf page %u",
+ (int)srckey.len, srckey.str, low->pgno);
+ } else {
+ srckey.len = srcnode->ksize;
+ bcopy(NODEKEY(srcnode), srckey.str, srcnode->ksize);
+ }
+ find_common_prefix(bt, src);
+
+ /* expand the prefix */
+ tmpkey.len = sizeof(tmpkey.str);
+ concat_prefix(bt, src->prefix.str, src->prefix.len,
+ srckey.str, srckey.len, tmpkey.str, &tmpkey.len);
+
+ /* Add the node to the destination page. Adjust prefix for
+ * destination page.
+ */
+ key.size = tmpkey.len;
+ key.data = tmpkey.str;
+ remove_prefix(bt, &key, dst->prefix.len);
+ data.size = NODEDSZ(srcnode);
+ data.data = NODEDATA(srcnode);
+ rc = btree_add_node(bt, dst, dstindx, &key, &data, NODEPGNO(srcnode),
+ srcnode->flags);
+ if (rc != BT_SUCCESS)
+ return rc;
+
+ /* Delete the node from the source page.
+ */
+ btree_del_node(bt, src, srcindx);
+
+ /* Update the parent separators.
+ */
+ if (srcindx == 0 && src->parent_index != 0) {
+ expand_prefix(bt, src, 0, &tmpkey);
+ key.size = tmpkey.len;
+ key.data = tmpkey.str;
+ remove_prefix(bt, &key, src->parent->prefix.len);
+
+ DPRINTF("update separator for source page %u to [%.*s]",
+ src->pgno, (int)key.size, (char *)key.data);
+ if (btree_update_key(bt, src->parent, src->parent_index,
+ &key) != BT_SUCCESS)
+ return BT_FAIL;
+ }
+
+ if (srcindx == 0 && IS_BRANCH(src)) {
+ struct btval nullkey;
+ nullkey.size = 0;
+ assert(btree_update_key(bt, src, 0, &nullkey) == BT_SUCCESS);
+ }
+
+ if (dstindx == 0 && dst->parent_index != 0) {
+ expand_prefix(bt, dst, 0, &tmpkey);
+ key.size = tmpkey.len;
+ key.data = tmpkey.str;
+ remove_prefix(bt, &key, dst->parent->prefix.len);
+
+ DPRINTF("update separator for destination page %u to [%.*s]",
+ dst->pgno, (int)key.size, (char *)key.data);
+ if (btree_update_key(bt, dst->parent, dst->parent_index,
+ &key) != BT_SUCCESS)
+ return BT_FAIL;
+ }
+
+ if (dstindx == 0 && IS_BRANCH(dst)) {
+ struct btval nullkey;
+ nullkey.size = 0;
+ assert(btree_update_key(bt, dst, 0, &nullkey) == BT_SUCCESS);
+ }
+
+ /* We can get a new page prefix here!
+ * Must update keys in all nodes of this page!
+ */
+ pfxlen = src->prefix.len;
+ find_common_prefix(bt, src);
+ if (src->prefix.len != pfxlen) {
+ if (btree_adjust_prefix(bt, src,
+ src->prefix.len - pfxlen) != BT_SUCCESS)
+ return BT_FAIL;
+ }
+
+ pfxlen = dst->prefix.len;
+ find_common_prefix(bt, dst);
+ if (dst->prefix.len != pfxlen) {
+ if (btree_adjust_prefix(bt, dst,
+ dst->prefix.len - pfxlen) != BT_SUCCESS)
+ return BT_FAIL;
+ }
+
+ if (IS_BRANCH(dst)) {
+ assert(mp);
+ mp->parent = dst;
+ mp->parent_index = dstindx;
+ find_common_prefix(bt, mp);
+ if (mp->prefix.len != mp_pfxlen) {
+ DPRINTF("moved branch node has changed prefix");
+ if ((mp = mpage_touch(bt, mp)) == NULL)
+ return BT_FAIL;
+ if (btree_adjust_prefix(bt, mp,
+ mp->prefix.len - mp_pfxlen) != BT_SUCCESS)
+ return BT_FAIL;
+ }
+ }
+
+ return BT_SUCCESS;
+}
+
+static int
+btree_merge(struct btree *bt, struct mpage *src, struct mpage *dst)
+{
+ int rc;
+ indx_t i;
+ unsigned int pfxlen;
+ struct node *srcnode;
+ struct btkey tmpkey, dstpfx;
+ struct btval key, data;
+
+ DPRINTF("merging page %u and %u", src->pgno, dst->pgno);
+
+ assert(src->parent); /* can't merge root page */
+ assert(dst->parent);
+ assert(bt->txn != NULL);
+
+ /* Mark src and dst as dirty. */
+ if ((src = mpage_touch(bt, src)) == NULL ||
+ (dst = mpage_touch(bt, dst)) == NULL)
+ return BT_FAIL;
+
+ find_common_prefix(bt, src);
+ find_common_prefix(bt, dst);
+
+ /* Check if source nodes has destination page prefix. Otherwise
+ * the destination page must expand its prefix on all its nodes.
+ */
+ common_prefix(bt, &src->prefix, &dst->prefix, &dstpfx);
+ if (dstpfx.len != dst->prefix.len) {
+ if (btree_adjust_prefix(bt, dst,
+ dstpfx.len - dst->prefix.len) != BT_SUCCESS)
+ return BT_FAIL;
+ bcopy(&dstpfx, &dst->prefix, sizeof(dstpfx));
+ }
+
+ /* Move all nodes from src to dst.
+ */
+ for (i = 0; i < NUMKEYS(src); i++) {
+ srcnode = NODEPTR(src, i);
+
+ /* If branch node 0 (implicit key), find the real key.
+ */
+ if (i == 0 && IS_BRANCH(src)) {
+ struct mpage *low;
+
+ /* must find the lowest key below src
+ */
+ assert(btree_search_page_root(bt, src, NULL, NULL, SearchFirst, 0,
+ &low) == BT_SUCCESS);
+ expand_prefix(bt, low, 0, &tmpkey);
+ DPRINTF("found lowest key [%.*s] on leaf page %u",
+ (int)tmpkey.len, tmpkey.str, low->pgno);
+ } else {
+ expand_prefix(bt, src, i, &tmpkey);
+ }
+
+ key.size = tmpkey.len;
+ key.data = tmpkey.str;
+
+ remove_prefix(bt, &key, dst->prefix.len);
+ data.size = NODEDSZ(srcnode);
+ data.data = NODEDATA(srcnode);
+ rc = btree_add_node(bt, dst, NUMKEYS(dst), &key,
+ &data, NODEPGNO(srcnode), srcnode->flags);
+ if (rc != BT_SUCCESS)
+ return rc;
+ }
+
+ DPRINTF("dst page %u now has %lu keys (%.1f%% filled)",
+ dst->pgno, NUMKEYS(dst), (float)PAGEFILL(bt, dst) / 10);
+
+ /* Unlink the src page from parent.
+ */
+ btree_del_node(bt, src->parent, src->parent_index);
+ if (src->parent_index == 0) {
+ key.size = 0;
+ if (btree_update_key(bt, src->parent, 0, &key) != BT_SUCCESS)
+ return BT_FAIL;
+
+ pfxlen = src->prefix.len;
+ find_common_prefix(bt, src);
+ assert (src->prefix.len == pfxlen);
+ }
+
+ if (IS_LEAF(src))
+ bt->meta.leaf_pages--;
+ else
+ bt->meta.branch_pages--;
+
+ return btree_rebalance(bt, src->parent);
+}
+
+#define FILL_THRESHOLD 250
+
+static int
+btree_rebalance(struct btree *bt, struct mpage *mp)
+{
+ struct node *node;
+ struct mpage *parent;
+ struct mpage *root;
+ struct mpage *neighbor = NULL;
+ indx_t si = 0, di = 0;
+
+ assert(bt != NULL);
+ assert(bt->txn != NULL);
+ assert(mp != NULL);
+
+ DPRINTF("rebalancing %s page %u (has %lu keys, %.1f%% full)",
+ IS_LEAF(mp) ? "leaf" : "branch",
+ mp->pgno, NUMKEYS(mp), (float)PAGEFILL(bt, mp) / 10);
+
+ if (PAGEFILL(bt, mp) >= FILL_THRESHOLD) {
+ DPRINTF("no need to rebalance page %u, above fill threshold",
+ mp->pgno);
+ return BT_SUCCESS;
+ }
+
+ parent = mp->parent;
+
+ if (parent == NULL) {
+ if (NUMKEYS(mp) == 0) {
+ DPRINTF("tree is completely empty");
+ bt->txn->root = P_INVALID;
+ bt->meta.depth--;
+ bt->meta.leaf_pages--;
+ } else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) {
+ DPRINTF("collapsing root page!");
+ bt->txn->root = NODEPGNO(NODEPTR(mp, 0));
+ if ((root = btree_get_mpage(bt, bt->txn->root)) == NULL)
+ return BT_FAIL;
+ root->parent = NULL;
+ bt->meta.depth--;
+ bt->meta.branch_pages--;
+ } else
+ DPRINTF("root page doesn't need rebalancing");
+ return BT_SUCCESS;
+ }
+
+ /* The parent (branch page) must have at least 2 pointers,
+ * otherwise the tree is invalid.
+ */
+ assert(NUMKEYS(parent) > 1);
+
+ /* Leaf page fill factor is below the threshold.
+ * Try to move keys from left or right neighbor, or
+ * merge with a neighbor page.
+ */
+
+ /* Find neighbors.
+ */
+ if (mp->parent_index == 0) {
+ /* We're the leftmost leaf in our parent.
+ */
+ DPRINTF("reading right neighbor");
+ node = NODEPTR(parent, mp->parent_index + 1);
+ if ((neighbor = btree_get_mpage(bt, NODEPGNO(node))) == NULL)
+ return BT_FAIL;
+ neighbor->parent_index = mp->parent_index + 1;
+ si = 0;
+ di = NUMKEYS(mp);
+ } else {
+ /* There is at least one neighbor to the left.
+ */
+ DPRINTF("reading left neighbor");
+ node = NODEPTR(parent, mp->parent_index - 1);
+ if ((neighbor = btree_get_mpage(bt, NODEPGNO(node))) == NULL)
+ return BT_FAIL;
+ neighbor->parent_index = mp->parent_index - 1;
+ si = NUMKEYS(neighbor) - 1;
+ di = 0;
+ }
+ neighbor->parent = parent;
+
+ DPRINTF("found neighbor page %u (%lu keys, %.1f%% full)",
+ neighbor->pgno, NUMKEYS(neighbor), (float)PAGEFILL(bt, neighbor) / 10);
+
+ // Calculate the size of the node to be moved
+ find_common_prefix (bt, neighbor);
+ struct btkey oldMpPrefix = mp->prefix;
+ find_common_prefix (bt, mp);
+
+ node = NODEPTR(neighbor, si);
+ size_t siSize = NODESIZE + node->ksize + neighbor->prefix.len;
+ siSize += IS_BRANCH(neighbor) ? 0 : NODEDSZ(node);
+
+ // Calculate the delta for the destination page prefix
+ struct btkey nKey, newPrefix;
+ nKey.len = node->ksize;
+ bcopy(NODEKEY(node), nKey.str, nKey.len);
+ common_prefix(bt, &nKey, &oldMpPrefix, &newPrefix);
+ size_t prfxDelta = mp->prefix.len - newPrefix.len;
+
+ /* If the neighbor page is above threshold and has at least two
+ * keys, move one key from it.
+ *
+ * Otherwise we should try to merge them, but that might not be
+ * possible, even if both are below threshold, as prefix expansion
+ * might make keys larger. FIXME: detect this
+ */
+ if (PAGEFILL(bt, neighbor) >= FILL_THRESHOLD && NUMKEYS(neighbor) >= 2 &&
+ NUMKEYS(mp)*prfxDelta + siSize < SIZELEFT(mp)) {
+ // Key in parent of the source can change, if
+ // we move the node from idx 0
+ // We need to make sure that the new key fits into
+ // parent page
+ bool canUpdate = true;
+ if (si == 0 && neighbor->parent_index != 0) {
+ expand_prefix(bt, neighbor, 1, &nKey);
+ node = NODEPTR(neighbor->parent, neighbor->parent_index);
+ int oldLength = node->ksize;
+ int newLength = nKey.len - neighbor->parent->prefix.len;
+ if (newLength - oldLength > SIZELEFT(neighbor->parent)) canUpdate = false;
+ }
+ // Key in parent can change if we move into index 0
+ // in destination page
+ // We need to ensure that the new key fits into
+ // parent page
+ if (canUpdate && di == 0 && mp->parent_index != 0) {
+ expand_prefix(bt, neighbor, si, &nKey);
+ node = NODEPTR(mp->parent, mp->parent_index);
+ int oldLength = node->ksize;
+ int newLength = nKey.len - mp->parent->prefix.len;
+ if (newLength - oldLength > SIZELEFT(mp->parent)) canUpdate = false;
+ }
+ if (canUpdate) {
+ return btree_move_node(bt, neighbor, si, mp, di);
+ }
+ }
+ else { /* FIXME: if (has_enough_room()) */
+ // Calculate the worst case space requirement
+ // This could be improved by calculating the 'prefix difference'
+ // Note that worst case free can be negative
+ // We are not changing the node at idx 0 so the parent
+ // page free space shouldn't be an issue
+ int nFree = SIZELEFT(neighbor) - NUMKEYS(neighbor)*neighbor->prefix.len;
+ int mpFree = SIZELEFT(mp) - NUMKEYS(mp)*mp->prefix.len;
+ int nRequired = 0;
+ for (unsigned int i=0; i<NUMKEYS(neighbor); i++) {
+ node = NODEPTR(neighbor, i);
+ nRequired += NODESIZE + node->ksize;
+ nRequired += IS_BRANCH(neighbor) ? 0 : NODEDSZ(node);
+ }
+ int mpRequired = 0;
+ for (unsigned int i=0; i<NUMKEYS(mp); i++) {
+ node = NODEPTR(mp, i);
+ mpRequired += NODESIZE + node->ksize;
+ mpRequired += IS_BRANCH(mp) ? 0 : NODEDSZ(node);
+ }
+
+ if (mp->parent_index == 0 && mpFree > nRequired)
+ return btree_merge(bt, neighbor, mp);
+ else if (nFree > mpRequired)
+ return btree_merge(bt, mp, neighbor);
+ }
+ return BT_SUCCESS;
+}
+
+int
+btree_txn_del(struct btree *bt, struct btree_txn *txn,
+ struct btval *key, struct btval *data)
+{
+ int rc, exact, close_txn = 0;
+ unsigned int ki;
+ struct node *leaf;
+ struct mpage *mp;
+
+ DPRINTF("========> delete key %.*s", (int)key->size, (char *)key->data);
+
+ assert(key != NULL);
+
+ if (bt != NULL && txn != NULL && bt != txn->bt) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (txn != NULL && F_ISSET(txn->flags, BT_TXN_RDONLY)) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (bt == NULL) {
+ if (txn == NULL) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+ bt = txn->bt;
+ }
+
+ if (key->size == 0 || key->size > MAXKEYSIZE) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (txn == NULL) {
+ close_txn = 1;
+ if ((txn = btree_txn_begin(bt, 0)) == NULL)
+ return BT_FAIL;
+ }
+
+ if ((rc = btree_search_page(bt, txn, key, NULL, SearchKey, 1, &mp)) != BT_SUCCESS)
+ goto done;
+
+ leaf = btree_search_node(bt, mp, key, &exact, &ki);
+ if (leaf == NULL || !exact) {
+ errno = ENOENT;
+ rc = BT_FAIL;
+ goto done;
+ }
+
+ if (data && (rc = btree_read_data(bt, NULL, leaf, data)) != BT_SUCCESS)
+ goto done;
+ btree_del_node(bt, mp, ki);
+ bt->meta.entries--;
+ rc = btree_rebalance(bt, mp);
+ if (rc != BT_SUCCESS)
+ txn->flags |= BT_TXN_ERROR;
+
+done:
+ if (close_txn) {
+ if (rc == BT_SUCCESS)
+ rc = btree_txn_commit(txn, 0, 0);
+ else
+ btree_txn_abort(txn);
+ }
+ mpage_prune(bt);
+ return rc;
+}
+
+/* Reduce the length of the prefix separator <sep> to the minimum length that
+ * still makes it uniquely distinguishable from <min>.
+ *
+ * <min> is guaranteed to be sorted less than <sep>
+ *
+ * On return, <sep> is modified to the minimum length.
+ */
+static void
+bt_reduce_separator(struct btree *bt, struct node *min, struct btval *sep)
+{
+ assert(bt);
+ size_t n = 0;
+ char *p1;
+ char *p2;
+
+ if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
+
+ assert(sep->size > 0);
+
+ p1 = (char *)NODEKEY(min) + min->ksize - 1;
+ p2 = (char *)sep->data + sep->size - 1;
+
+ while (p1 >= (char *)NODEKEY(min) && *p1 == *p2) {
+ assert(p2 > (char *)sep->data);
+ p1--;
+ p2--;
+ n++;
+ }
+
+ sep->data = p2;
+ sep->size = n + 1;
+ } else {
+
+ assert(min->ksize > 0);
+ assert(sep->size > 0);
+
+ p1 = (char *)NODEKEY(min);
+ p2 = (char *)sep->data;
+
+ while (*p1 == *p2) {
+ p1++;
+ p2++;
+ n++;
+ if (n == min->ksize || n == sep->size)
+ break;
+ }
+
+ sep->size = n + 1;
+ }
+
+ DPRINTF("reduced separator to [%.*s] > [%.*s]",
+ (int)sep->size, (char *)sep->data,
+ (int)min->ksize, (char *)NODEKEY(min));
+}
+
+/* Split page <*mpp>, and insert <key,(data|newpgno)> in either left or
+ * right sibling, at index <*newindxp> (as if unsplit). Updates *mpp and
+ * *newindxp with the actual values after split, ie if *mpp and *newindxp
+ * refer to a node in the new right sibling page.
+ */
+static int
+btree_split(struct btree *bt, struct mpage **mpp, unsigned int *newindxp,
+ struct btval *newkey, struct btval *newdata, pgno_t newpgno)
+{
+ uint8_t flags;
+ int rc = BT_SUCCESS, ins_new = 0;
+ indx_t newindx;
+ pgno_t pgno = 0;
+ size_t orig_pfx_len, left_pfx_diff, right_pfx_diff, pfx_diff;
+ unsigned int i, j, split_indx;
+ struct node *node;
+ struct mpage *pright, *p, *mp;
+ struct btval sepkey, rkey, rdata;
+ struct btkey tmpkey;
+ struct page *copy;
+
+ assert(bt != NULL);
+ assert(bt->txn != NULL);
+
+ mp = *mpp;
+ newindx = *newindxp;
+
+ DPRINTF("-----> splitting %s page %u and adding [%.*s] at index %i",
+ IS_LEAF(mp) ? "leaf" : "branch", mp->pgno,
+ (int)newkey->size, (char *)newkey->data, *newindxp);
+ DPRINTF("page %u has prefix [%.*s]", mp->pgno,
+ (int)mp->prefix.len, (char *)mp->prefix.str);
+ orig_pfx_len = mp->prefix.len;
+
+ if (mp->parent == NULL) {
+ if ((mp->parent = btree_new_page(bt, P_BRANCH)) == NULL)
+ return BT_FAIL;
+ mp->parent_index = 0;
+ bt->txn->root = mp->parent->pgno;
+ DPRINTF("root split! new root = %u", mp->parent->pgno);
+ bt->meta.depth++;
+
+ /* Add left (implicit) pointer. */
+ if (btree_add_node(bt, mp->parent, 0, NULL, NULL,
+ mp->pgno, 0) != BT_SUCCESS)
+ return BT_FAIL;
+ } else {
+ DPRINTF("parent branch page is %u", mp->parent->pgno);
+ }
+
+ /* Create a right sibling. */
+ if ((pright = btree_new_page(bt, mp->page->flags)) == NULL)
+ return BT_FAIL;
+
+ pright->parent = mp->parent;
+ pright->parent_index = mp->parent_index + 1;
+ DPRINTF("new right sibling: page %u", pright->pgno);
+
+ /* Move half of the keys to the right sibling. */
+ if ((copy = (page *)malloc(bt->head.psize)) == NULL)
+ return BT_FAIL;
+ bcopy(mp->page, copy, bt->head.psize);
+ assert(mp->ref == 0); /* XXX */
+ bzero(&mp->page->ptrs, bt->head.psize - PAGEHDRSZ);
+ mp->page->lower = PAGEHDRSZ;
+ mp->page->upper = bt->head.psize;
+
+ split_indx = NUMKEYSP(copy) / 2 + 1;
+ DPRINTF("splitting copy of page %d [split index:%d, newindex:%d]", copy->pgno, split_indx, newindx);
+
+ /* First find the separating key between the split pages.
+ */
+ bzero(&sepkey, sizeof(sepkey));
+ if (newindx == split_indx) {
+ sepkey.size = newkey->size;
+ sepkey.data = newkey->data;
+ remove_prefix(bt, &sepkey, mp->prefix.len);
+ } else {
+ node = NODEPTRP(copy, split_indx);
+ sepkey.size = node->ksize;
+ sepkey.data = NODEKEY(node);
+ }
+
+ if (IS_LEAF(mp) && bt->cmp == NULL) {
+ /* Find the smallest separator. */
+ /* Ref: Prefix B-trees, R. Bayer, K. Unterauer, 1977 */
+ node = NODEPTRP(copy, split_indx - 1);
+ bt_reduce_separator(bt, node, &sepkey);
+ }
+
+ /* Fix separator wrt parent prefix. */
+ if (bt->cmp == NULL) {
+ DPRINTF("concat prefix [%.*s] to separator [%.*s]",
+ mp->prefix.len, mp->prefix.str,
+ sepkey.size, (char *)sepkey.data);
+ tmpkey.len = sizeof(tmpkey.str);
+ concat_prefix(bt, mp->prefix.str, mp->prefix.len,
+ (char *)sepkey.data, sepkey.size, tmpkey.str, &tmpkey.len);
+ sepkey.data = tmpkey.str;
+ sepkey.size = tmpkey.len;
+ }
+
+ DPRINTF("separator is [%.*s]", (int)sepkey.size, (char *)sepkey.data);
+ DPRINTF("%d bytes left in parent page %d with branch size %d",
+ SIZELEFT(pright->parent), pright->parent->pgno,
+ bt_branch_size(bt, &sepkey));
+
+ /* Copy separator key to the parent.
+ */
+ if (SIZELEFT(pright->parent) < bt_branch_size(bt, &sepkey)) {
+ rc = btree_split(bt, &pright->parent, &pright->parent_index,
+ &sepkey, NULL, pright->pgno);
+
+ /* Right page might now have changed parent.
+ * Check if left page also changed parent.
+ */
+ if (pright->parent != mp->parent &&
+ mp->parent_index >= NUMKEYS(mp->parent)) {
+ mp->parent = pright->parent;
+ mp->parent_index = pright->parent_index - 1;
+ }
+ } else {
+ DPRINTF("removing %d bytes from seperator [%.*s]",
+ pright->parent->prefix.len,
+ sepkey.size, sepkey.data);
+ remove_prefix(bt, &sepkey, pright->parent->prefix.len);
+ DPRINTF("adding sepkey [%.*s] to page %d with reference to page %d",
+ sepkey.size, sepkey.data,
+ pright->parent->pgno, pright->pgno);
+ rc = btree_add_node(bt, pright->parent, pright->parent_index,
+ &sepkey, NULL, pright->pgno, 0);
+ }
+
+ if (rc != BT_SUCCESS) {
+ free(copy);
+ return BT_FAIL;
+ }
+
+ /* Update prefix for right and left page, if the parent was split.
+ */
+ find_common_prefix(bt, pright);
+ assert(orig_pfx_len <= pright->prefix.len);
+ right_pfx_diff = pright->prefix.len - orig_pfx_len;
+ DPRINTF("right page %d prefix length = %d, diff = %d", pright->pgno, pright->prefix.len, right_pfx_diff);
+
+ find_common_prefix(bt, mp);
+ assert(orig_pfx_len <= mp->prefix.len);
+ left_pfx_diff = mp->prefix.len - orig_pfx_len;
+ DPRINTF("left page %d prefix length = %d, diff = %d", mp->pgno, mp->prefix.len, left_pfx_diff);
+
+ for (i = j = 0; i <= NUMKEYSP(copy); j++) {
+ if (i < split_indx) {
+ /* Re-insert in left sibling. */
+ p = mp;
+ pfx_diff = left_pfx_diff;
+ } else {
+ /* Insert in right sibling. */
+ if (i == split_indx) {
+ /* Reset insert index for right sibling. */
+ j = (i == newindx && ins_new);
+ }
+ p = pright;
+ pfx_diff = right_pfx_diff;
+ }
+
+ if (i == newindx && !ins_new) {
+ /* Insert the original entry that caused the split. */
+ rkey.data = newkey->data;
+ rkey.size = newkey->size;
+ if (IS_LEAF(mp)) {
+ rdata.data = newdata->data;
+ rdata.size = newdata->size;
+ } else
+ pgno = newpgno;
+ flags = 0;
+ pfx_diff = p->prefix.len;
+
+ ins_new = 1;
+
+ /* Update page and index for the new key. */
+ *newindxp = j;
+ *mpp = p;
+ } else if (i == NUMKEYSP(copy)) {
+ break;
+ } else {
+ node = NODEPTRP(copy, i);
+ rkey.data = NODEKEY(node);
+ rkey.size = node->ksize;
+ if (IS_LEAF(mp)) {
+ rdata.data = NODEDATA(node);
+ rdata.size = node->n_dsize;
+ } else
+ pgno = node->n_pgno;
+ flags = node->flags;
+
+ i++;
+ }
+
+ if (!IS_LEAF(mp) && j == 0) {
+ /* First branch index doesn't need key data. */
+ rkey.size = 0;
+ } else {
+ remove_prefix(bt, &rkey, pfx_diff);
+ }
+
+ rc = btree_add_node(bt, p, j, &rkey, &rdata, pgno,flags);
+ }
+
+ free(copy);
+ return rc;
+}
+
+int
+btree_txn_put(struct btree *bt, struct btree_txn *txn,
+ struct btval *key, struct btval *data, unsigned int flags)
+{
+ int rc = BT_SUCCESS, exact, close_txn = 0;
+ unsigned int ki;
+ struct node *leaf;
+ struct mpage *mp;
+ struct btval xkey;
+
+ assert(key != NULL);
+ assert(data != NULL);
+
+ if (bt != NULL && txn != NULL && bt != txn->bt) {
+ fprintf(stderr, "%s:%d: transaction does not belong to btree\n",
+ __FUNCTION__, __LINE__);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (txn != NULL && F_ISSET(txn->flags, BT_TXN_RDONLY)) {
+ fprintf(stderr, "%s:%d: read-only transaction\n",
+ __FUNCTION__, __LINE__);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if (bt == NULL) {
+ if (txn == NULL) {
+ fprintf(stderr, "%s:%d: neither transaction nor btree\n",
+ __FUNCTION__, __LINE__);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+ bt = txn->bt;
+ }
+
+ if (key->size == 0 || key->size > MAXKEYSIZE) {
+ fprintf(stderr, "%s:%d: bad key size %Zu (MAXKEYSIZE %d)\n",
+ __FUNCTION__, __LINE__, key->size, MAXKEYSIZE);
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ DPRINTF("==> put key %.*s, size %zu, data size %zu",
+ (int)key->size, (char *)key->data, key->size, data->size);
+
+ if (txn == NULL) {
+ close_txn = 1;
+ if ((txn = btree_txn_begin(bt, 0)) == NULL)
+ return BT_FAIL;
+ }
+
+ rc = btree_search_page(bt, txn, key, NULL, SearchKey, 1, &mp);
+ if (rc == BT_SUCCESS) {
+ leaf = btree_search_node(bt, mp, key, &exact, &ki);
+ if (leaf && exact) {
+ if (F_ISSET(flags, BT_NOOVERWRITE)) {
+ DPRINTF("duplicate key %.*s",
+ (int)key->size, (char *)key->data);
+ fprintf(stderr, "db=%s flags=%x duplicate key %.*s",
+ bt->path, flags,
+ (int)key->size, (char *)key->data);
+ errno = EEXIST;
+ rc = BT_FAIL;
+ goto done;
+ }
+ if (!F_ISSET(flags, BT_ALLOWDUPS))
+ btree_del_node(bt, mp, ki);
+ }
+ if (leaf == NULL) { /* append if not found */
+ ki = NUMKEYS(mp);
+ DPRINTF("appending key at index %i", ki);
+ }
+ } else if (errno == ENOENT) {
+ /* new file, just write a root leaf page */
+ DPRINTF("allocating new root leaf page");
+ if ((mp = btree_new_page(bt, P_LEAF)) == NULL) {
+ rc = BT_FAIL;
+ goto done;
+ }
+ txn->root = mp->pgno;
+ bt->meta.depth++;
+ ki = 0;
+ }
+ else
+ goto done;
+
+ assert(IS_LEAF(mp));
+ DPRINTF("there are %lu keys, should insert new key at index %i",
+ NUMKEYS(mp), ki);
+
+ /* Copy the key pointer as it is modified by the prefix code. The
+ * caller might have malloc'ed the data.
+ */
+ xkey.data = key->data;
+ xkey.size = key->size;
+
+ if (SIZELEFT(mp) < bt_leaf_size(bt, key, data)) {
+ rc = btree_split(bt, &mp, &ki, &xkey, data, P_INVALID);
+ } else {
+ /* There is room already in this leaf page. */
+ remove_prefix(bt, &xkey, mp->prefix.len);
+ rc = btree_add_node(bt, mp, ki, &xkey, data, 0, 0);
+ }
+
+ if (rc != BT_SUCCESS)
+ txn->flags |= BT_TXN_ERROR;
+ else
+ bt->meta.entries++;
+
+done:
+ if (close_txn) {
+ if (rc == BT_SUCCESS)
+ rc = btree_txn_commit(txn, 0, 0);
+ else
+ btree_txn_abort(txn);
+ }
+ mpage_prune(bt);
+ return rc;
+}
+
+static pgno_t
+btree_compact_tree(struct btree *bt, pgno_t pgno, struct btree *btc)
+{
+ ssize_t rc;
+ indx_t i;
+ pgno_t *pnext, next;
+ struct node *node;
+ struct page *p;
+ struct mpage *mp;
+ /* Get the page and make a copy of it.
+ */
+ if ((mp = btree_get_mpage(bt, pgno)) == NULL)
+ return P_INVALID;
+ if ((p = (page *)malloc(bt->head.psize)) == NULL)
+ return P_INVALID;
+ bcopy(mp->page, p, bt->head.psize);
+
+ /* Go through all nodes in the (copied) page and update the
+ * page pointers.
+ */
+ if (F_ISSET(p->flags, P_BRANCH)) {
+ for (i = 0; i < NUMKEYSP(p); i++) {
+ node = NODEPTRP(p, i);
+ node->n_pgno = btree_compact_tree(bt, node->n_pgno, btc);
+ if (node->n_pgno == P_INVALID) {
+ free(p);
+ return P_INVALID;
+ }
+ }
+ } else if (F_ISSET(p->flags, P_LEAF)) {
+ for (i = 0; i < NUMKEYSP(p); i++) {
+ node = NODEPTRP(p, i);
+ if (F_ISSET(node->flags, F_BIGDATA)) {
+ bcopy(NODEDATA(node), &next, sizeof(next));
+ next = btree_compact_tree(bt, next, btc);
+ if (next == P_INVALID) {
+ free(p);
+ return P_INVALID;
+ }
+ bcopy(&next, NODEDATA(node), sizeof(next));
+ }
+ }
+ } else if (F_ISSET(p->flags, P_OVERFLOW)) {
+ pnext = &p->p_next_pgno;
+ if (*pnext > 0) {
+ *pnext = btree_compact_tree(bt, *pnext, btc);
+ if (*pnext == P_INVALID) {
+ free(p);
+ return P_INVALID;
+ }
+ }
+ } else
+ assert(0);
+
+ pgno = p->pgno = btc->txn->next_pgno++;
+ rc = write(btc->fd, p, bt->head.psize);
+ free(p);
+ if (rc != (ssize_t)bt->head.psize)
+ return P_INVALID;
+ mpage_prune(bt);
+ return pgno;
+}
+
+int
+btree_compact(struct btree *bt)
+{
+ char *compact_path = NULL;
+ struct btree *btc;
+ struct btree_txn *txn, *txnc = NULL;
+ int fd;
+ pgno_t root;
+
+ assert(bt != NULL);
+
+ DPRINTF("compacting btree %p with path %s", bt, bt->path);
+
+ if (bt->path == NULL) {
+ errno = EINVAL;
+ return BT_FAIL;
+ }
+
+ if ((txn = btree_txn_begin(bt, 0)) == NULL)
+ return BT_FAIL;
+
+ asprintf(&compact_path, "%s.compact.XXXXXX", bt->path);
+ fd = mkstemp(compact_path);
+ if (fd == -1) {
+ free(compact_path);
+ btree_txn_abort(txn);
+ return BT_FAIL;
+ }
+
+ if ((btc = btree_open_fd(compact_path, fd, 0)) == NULL)
+ goto failed;
+ bcopy(&bt->meta, &btc->meta, sizeof(bt->meta));
+ btc->meta.revisions = 0;
+
+ if ((txnc = btree_txn_begin(btc, 0)) == NULL)
+ goto failed;
+
+ if (bt->meta.root != P_INVALID) {
+ root = btree_compact_tree(bt, bt->meta.root, btc);
+ if (root == P_INVALID)
+ goto failed;
+ fsync(fd);
+ if (btree_write_meta(btc, root, BT_MARKER, bt->meta.tag) != BT_SUCCESS)
+ goto failed;
+ } else {
+ if (btree_write_meta(btc, btc->meta.root, BT_MARKER, bt->meta.tag) != BT_SUCCESS)
+ goto failed;
+ }
+
+ fsync(fd);
+
+ DPRINTF("renaming %s to %s", compact_path, bt->path);
+ if (rename(compact_path, bt->path) != 0)
+ goto failed;
+
+ /* Write a "tombstone" meta page so other processes can pick up
+ * the change and re-open the file.
+ */
+ if (btree_write_meta(bt, P_INVALID, BT_TOMBSTONE, 0) != BT_SUCCESS)
+ goto failed;
+
+ btree_txn_abort(txn);
+ btree_txn_abort(txnc);
+ free(compact_path);
+ btree_close(btc);
+ mpage_prune(bt);
+ return 0;
+
+failed:
+ btree_txn_abort(txn);
+ btree_txn_abort(txnc);
+ unlink(compact_path);
+ free(compact_path);
+ btree_close(btc);
+ mpage_prune(bt);
+ return BT_FAIL;
+}
+
+/* Reverts the last change. Truncates the file at the last root page.
+ */
+int
+btree_revert(struct btree *bt)
+{
+ if (btree_read_meta(bt, NULL) != 0)
+ return -1;
+
+ DPRINTF("truncating file at page %u", bt->meta.root);
+ fprintf(stderr, "truncating file at page %u\n", bt->meta.root);
+ return ftruncate(bt->fd, bt->head.psize * bt->meta.root);
+}
+
+/* Rollback to the previous meta page. Truncates the file at that root page.
+ */
+int
+btree_rollback(struct btree *bt)
+{
+ if (btree_read_meta(bt, NULL) != 0)
+ return -1;
+
+ pgno_t prev_meta_pgno = bt->meta.prev_meta;
+ DPRINTF("prev_meta_pgno=%d\n", prev_meta_pgno);
+ struct mpage *mp;
+ if ((mp = btree_get_mpage(bt, prev_meta_pgno)) == NULL) {
+ return -1;
+ }
+ struct bt_meta *meta;
+ if (btree_is_meta_page(mp->page)) {
+ meta = METADATA(mp->page);
+ } else {
+ fprintf(stderr, "mp->page flags %x\n", mp->page->flags);
+ return -2;
+ }
+
+ DPRINTF("truncating file at page %u", meta->root);
+ return ftruncate(bt->fd, bt->head.psize * meta->root);
+}
+
+void
+btree_set_cache_size(struct btree *bt, unsigned int cache_size)
+{
+ bt->stat.max_cache = cache_size;
+}
+
+unsigned int
+btree_get_flags(struct btree *bt)
+{
+ return (bt->flags & ~BT_FIXPADDING);
+}
+
+const char *
+btree_get_path(struct btree *bt)
+{
+ return bt->path;
+}
+
+const struct btree_stat *
+btree_stat(struct btree *bt)
+{
+ if (bt == NULL)
+ return NULL;
+
+ bt->stat.branch_pages = bt->meta.branch_pages;
+ bt->stat.leaf_pages = bt->meta.leaf_pages;
+ bt->stat.overflow_pages = bt->meta.overflow_pages;
+ bt->stat.revisions = bt->meta.revisions;
+ bt->stat.depth = bt->meta.depth;
+ bt->stat.entries = bt->meta.entries;
+ bt->stat.psize = bt->head.psize;
+ bt->stat.created_at = bt->meta.created_at;
+ bt->stat.tag = bt->meta.tag;
+
+ return &bt->stat;
+}
+
+const char *tohexstr(const char *src, size_t srclen, char* dst, int dstlen, int tobytes = 0)
+{
+ assert(dstlen > 1);
+ char temp[3];
+ int len = 0;
+ *dst = 0;
+ for (size_t i = 0; i < srclen; ++i) {
+ if (!tobytes) {
+ sprintf(temp, "%02X", src[i]);
+ temp[2] = 0;
+ len += 2;
+ } else {
+ sprintf(temp, "%c", src[i]);
+ temp[1] = 0;
+ len += 1;
+ }
+
+ if (len < dstlen)
+ strcat(dst, temp);
+ }
+ return dst;
+}
+
+void
+btree_dump_tree(struct btree *bt, pgno_t pgno, int depth)
+{
+ indx_t i;
+ pgno_t *pnext, next;
+ struct node *node;
+ struct page *p;
+ struct mpage *mp;
+ char indent[32] = {0};
+ const int hexlen = 512;
+ char hexstr[hexlen];
+
+ for (i = 0; i < depth + 1; ++i)
+ strcat(&indent[i], "\t");
+
+ /* Get the page.
+ */
+ if ((mp = btree_get_mpage(bt, pgno)) == NULL)
+ return;
+ p = mp->page;
+ if (F_ISSET(p->flags, P_BRANCH)) {
+ fprintf(stderr, "%s", indent);
+ fprintf(stderr, "Branch page %d [bytes-free:%d, num-keys:%lu]\n",
+ pgno,
+ SIZELEFT(mp),
+ NUMKEYSP(p));
+ for (i = 0; i < NUMKEYSP(p); i++) {
+ node = NODEPTRP(p, i);
+ fprintf(stderr, "%s", indent);
+ fprintf(stderr, "-> Node %d points to page %d with seperator [%s]\n",
+ i,
+ NODEPGNO(node),
+ tohexstr((const char*)node->data, node->ksize, hexstr, hexlen));
+ btree_dump_tree(bt, node->n_pgno, depth + 1);
+ }
+ } else if (F_ISSET(p->flags, P_LEAF)) {
+ fprintf(stderr, "%s", indent);
+ fprintf(stderr, "Leaf page %d [bytes-free:%d, num-keys:%lu] with prefix [%.*s]\n",
+ pgno,
+ SIZELEFT(mp),
+ NUMKEYSP(p),
+ (int)mp->prefix.len, mp->prefix.str);
+ for (i = 0; i < NUMKEYSP(p); i++) {
+ node = NODEPTRP(p, i);
+ fprintf(stderr, "%s", indent);
+ fprintf(stderr, "-> Node %d [key:%s, data:%s]\n",
+ i,
+ tohexstr((const char*)node->data, node->ksize, hexstr, hexlen),
+ tohexstr((const char*)NODEDATA(node), NODEDSZ(node), hexstr, hexlen));
+ if (F_ISSET(node->flags, F_BIGDATA)) {
+ bcopy(NODEDATA(node), &next, sizeof(next));
+ fprintf(stderr, "%s", indent);
+ fprintf (stderr, "[!] Data is on overflow page %d\n", next);
+ btree_dump_tree(bt, next, depth + 1);
+ }
+ }
+ } else if (F_ISSET(p->flags, P_OVERFLOW)) {
+ fprintf(stderr, "%s", indent);
+ fprintf (stderr, "Page: %d is an overflow page\n", pgno);
+ pnext = &p->p_next_pgno;
+ if (*pnext > 0) {
+ btree_dump_tree(bt, *pnext, depth + 1);
+ }
+ } else
+ assert(0);
+}
+
+void
+btree_dump(struct btree *bt)
+{
+ assert(bt != NULL);
+ fprintf(stderr, "btree_dump %s\n", bt->path);
+ if (bt->meta.root != P_INVALID) {
+ fprintf(stderr, "Root page %d [depth:%d, entries:%lld, leaves:%d, branches:%d]\n",
+ bt->meta.root,
+ bt->meta.depth,
+ bt->meta.entries,
+ bt->meta.leaf_pages,
+ bt->meta.branch_pages);
+ btree_dump_tree(bt, bt->meta.root, 0);
+ } else {
+ fprintf(stderr, "Root page invalid.\n");
+ }
+}
+
+void
+btree_dump_page_from_memory(struct page *p)
+{
+ indx_t i;
+ pgno_t pgno;
+ struct node *node;
+ struct bt_head *head;
+ const char *pgstr = F_ISSET(p->flags, P_BRANCH) ? "Branch" : "Leaf";
+ const int hexlen = 512;
+ char hexstr[hexlen];
+
+ head = (bt_head*)METADATA(p);
+ pgno = p->pgno;
+
+ if (head->magic != BT_MAGIC) {
+ EPRINTF("header has invalid magic");
+ errno = EINVAL;
+ return;
+ }
+
+ if (head->version != BT_VERSION) {
+ EPRINTF("database is version %u, expected version %u",
+ head->version, BT_VERSION);
+ errno = EINVAL;
+ return;
+ }
+
+ fprintf(stderr, "* %s page %d with flags %0X offsets [%d -> %d]\n", pgstr, pgno,
+ p->flags, p->lower, p->upper);
+
+ for (i = 0; i < NUMKEYSP(p); i++) {
+ node = NODEPTRP(p, i);
+ fprintf(stderr, "-> Node %d [key:%s, data:%s]\n",
+ i,
+ tohexstr((const char*)node->data, node->ksize, hexstr, hexlen),
+ tohexstr((const char*)NODEDATA(node), NODEDSZ(node), hexstr, hexlen));
+ }
+}
+
+int
+btree_dump_page_from_file(const char *filename, unsigned int pagen)
+{
+ int fd;
+ ssize_t rc;
+ char header[PAGESIZE];
+ struct page *p;
+ struct bt_head *h;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == 0)
+ return 0;
+
+ // read header
+ if ((rc = pread(fd, header, PAGESIZE, 0)) == 0) {
+ errno = ENOENT;
+ return 0;
+ } else if (rc != PAGESIZE) {
+ if (rc > 0)
+ errno = EINVAL;
+ EPRINTF("read: %s", strerror(errno));
+ return 0;
+ }
+
+ p = (struct page *)header;
+
+ if (!F_ISSET(p->flags, P_HEAD)) {
+ EPRINTF("page %d not a header page", p->pgno);
+ errno = EINVAL;
+ return 0;
+ }
+
+ h = (bt_head *)METADATA(p);
+ if (h->magic != BT_MAGIC) {
+ EPRINTF("header has invalid magic");
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (h->version != BT_VERSION) {
+ EPRINTF("database is version %u, expected version %u",
+ h->version, BT_VERSION);
+ errno = EINVAL;
+ return 0;
+ }
+
+ if ((p = (page *)calloc(1, h->psize)) == NULL)
+ return 0;
+ rc = pread(fd, p, h->psize, pagen * h->psize);
+ if (rc < 0) {
+ fprintf(stderr, "error reading page %d\n", pagen);
+ return 0;
+ } else if (rc < (ssize_t)h->psize) {
+ fprintf(stderr, "read incomplete page %d (%d != %d)\n", pagen, h->psize, (int32_t)rc);
+ return 0;
+ }
+
+ fprintf(stderr, "page %d:\n", pagen);
+ fprintf(stderr, "\tpgno:%d\n", p->pgno);
+ fprintf(stderr, "\tflags:%d: ", p->flags);
+ if (p->flags & P_BRANCH)
+ fprintf(stderr, "BRANCH ");
+ if (p->flags & P_LEAF)
+ fprintf(stderr, "LEAF ");
+ if (p->flags & P_OVERFLOW)
+ fprintf(stderr, "OVERFLOW ");
+ if (p->flags & P_META)
+ fprintf(stderr, "META ");
+ if (p->flags & P_HEAD)
+ fprintf(stderr, "HEAD");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "\tb.fb_lower:%d\n", p->b.fb.fb_lower);
+ fprintf(stderr, "\tb.fb_upper:%d\n", p->b.fb.fb_upper);
+ fprintf(stderr, "\tb.pb_next_pgno:%d\n", p->b.pb_next_pgno);
+
+ free(p);
+ return 1;
+}
diff --git a/src/3rdparty/btree/src/btree.h b/src/3rdparty/btree/src/btree.h
new file mode 100644
index 00000000..e83da336
--- /dev/null
+++ b/src/3rdparty/btree/src/btree.h
@@ -0,0 +1,140 @@
+/* $OpenBSD: btree.h,v 1.6 2010/07/02 01:43:00 martinh Exp $ */
+
+/*
+ * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _btree_h_
+#define _btree_h_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+struct mpage;
+struct cursor;
+struct btree_txn;
+
+struct btval {
+ void *data;
+ size_t size;
+ int free_data; /* true if data malloc'd */
+ struct mpage *mp; /* ref'd memory page */
+};
+
+typedef int (*bt_cmp_func)(const char *adata, size_t asize,
+ const char *bdata, size_t bsize, void *opdata);
+typedef void (*bt_prefix_func)(const struct btval *a,
+ const struct btval *b,
+ struct btval *sep);
+
+#define BT_NOOVERWRITE 1
+#define BT_ALLOWDUPS 2
+
+/* flags for btree_txn_commit */
+#define BT_FORCE_MARKER 0x01
+
+enum cursor_op { /* cursor operations */
+ BT_CURSOR, /* position at given key */
+ BT_CURSOR_EXACT, /* position at key, or fail */
+ BT_FIRST,
+ BT_NEXT,
+ BT_LAST, /* not implemented */
+ BT_PREV /* not implemented */
+};
+
+/* return codes */
+#define BT_FAIL -1
+#define BT_SUCCESS 0
+
+/* btree flags */
+#define BT_NOSYNC 0x02 /* don't fsync after commit */
+#define BT_RDONLY 0x04 /* read only */
+#define BT_REVERSEKEY 0x08 /* use reverse string keys */
+#define BT_USEMARKER 0x10 /* find last marked meta page when opening db */
+
+struct btree_stat {
+ unsigned long long int hits; /* cache hits */
+ unsigned long long int reads; /* page reads */
+ unsigned int max_cache; /* max cached pages */
+ unsigned int cache_size; /* current cache size */
+ unsigned int branch_pages;
+ unsigned int leaf_pages;
+ unsigned int overflow_pages;
+ unsigned int revisions;
+ unsigned int depth;
+ unsigned long long int entries;
+ unsigned int psize;
+ time_t created_at;
+ unsigned int tag;
+};
+
+struct btree *btree_open_fd(const char *path, int fd, unsigned int flags);
+struct btree *btree_open(const char *path, unsigned int flags,
+ mode_t mode);
+int btree_get_fd(struct btree *bt);
+void btree_close(struct btree *bt);
+const struct btree_stat *btree_stat(struct btree *bt);
+
+struct btree_txn *btree_txn_begin(struct btree *bt, int rdonly);
+unsigned int btree_txn_get_tag(struct btree_txn *txn);
+int btree_txn_commit(struct btree_txn *txn, unsigned int tag, unsigned int flags);
+void btree_txn_abort(struct btree_txn *txn);
+
+int btree_txn_get(struct btree *bt, struct btree_txn *txn,
+ struct btval *key, struct btval *data);
+int btree_txn_put(struct btree *bt, struct btree_txn *txn,
+ struct btval *key, struct btval *data,
+ unsigned int flags);
+int btree_txn_del(struct btree *bt, struct btree_txn *txn,
+ struct btval *key, struct btval *data);
+
+#define btree_get(bt, key, data) \
+ btree_txn_get(bt, NULL, key, data)
+#define btree_put(bt, key, data, flags) \
+ btree_txn_put(bt, NULL, key, data, flags)
+#define btree_del(bt, key, data) \
+ btree_txn_del(bt, NULL, key, data)
+
+void btree_set_cache_size(struct btree *bt,
+ unsigned int cache_size);
+unsigned int btree_get_flags(struct btree *bt);
+const char *btree_get_path(struct btree *bt);
+
+#define btree_cursor_open(bt) \
+ btree_txn_cursor_open(bt, NULL)
+struct cursor *btree_txn_cursor_open(struct btree *bt,
+ struct btree_txn *txn);
+void btree_cursor_close(struct cursor *cursor);
+int btree_cursor_get(struct cursor *cursor,
+ struct btval *key, struct btval *data,
+ enum cursor_op op);
+
+int btree_sync(struct btree *bt);
+int btree_compact(struct btree *bt);
+int btree_revert(struct btree *bt);
+int btree_rollback(struct btree *bt);
+
+void btree_set_cmp(struct btree *bt, bt_cmp_func cmp);
+
+int btree_cmp(struct btree *bt, const struct btval *a,
+ const struct btval *b);
+void btval_reset(struct btval *btv);
+
+void btree_dump(struct btree *bt);
+int btree_dump_page_from_file(const char *filename, unsigned int pagen);
+
+#endif
+
diff --git a/src/3rdparty/qjson/README b/src/3rdparty/qjson/README
new file mode 100644
index 00000000..450e97ee
--- /dev/null
+++ b/src/3rdparty/qjson/README
@@ -0,0 +1,18 @@
+This is a Qt JSON Parser and serializer.
+
+The API is trivial:
+ QVariant Json::parse(jsonString)
+ QByteArray Json::stringize(QVariant)
+
+Compilation:
+ The code uses QLALR (in Qt respository. $QTDIR/util/qlalr). Just,
+ 'qlalr json.g' produces the parser 'jsonparser.cpp'. This generated file is
+ checked into the respository for convenience, so that the user does
+ not need to build qlalr.
+
+Using in external projects:
+ Just drop 3 files - src/json.cpp src/json.h src/jsonparser.cpp into your code.
+ Add json.cpp to SOURCES and you are good to go. jsonparser.cpp is included by
+ json.cpp so you should not add it to SOURCES. You may add json.h to HEADERS but
+ it's not necessary since it does not contains any mocable content.
+
diff --git a/src/3rdparty/qjson/TODO b/src/3rdparty/qjson/TODO
new file mode 100644
index 00000000..e41f2ebe
--- /dev/null
+++ b/src/3rdparty/qjson/TODO
@@ -0,0 +1,2 @@
+What's needed before MR
+1. Docs
diff --git a/src/3rdparty/qjson/benchmark/benchmark.pro b/src/3rdparty/qjson/benchmark/benchmark.pro
new file mode 100644
index 00000000..478b14a7
--- /dev/null
+++ b/src/3rdparty/qjson/benchmark/benchmark.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT += testlib
+QT -= gui
+
+include(../src/json.pri)
+
+# Input
+SOURCES += main.cpp
diff --git a/src/3rdparty/qjson/benchmark/main.cpp b/src/3rdparty/qjson/benchmark/main.cpp
new file mode 100644
index 00000000..af82c991
--- /dev/null
+++ b/src/3rdparty/qjson/benchmark/main.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 Denis Dzyubenko <shadone@gmail.com>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QTest>
+
+#include "json.h"
+
+class tst_Json : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testByteArray();
+ void testString();
+ void testNumbers();
+};
+
+void tst_Json::testNumbers()
+{
+ QFile file(QLatin1String("numbers.json"));
+ file.open(QFile::ReadOnly);
+ QByteArray ba = file.readAll();
+ QString data = QString::fromLocal8Bit(ba.constData(), ba.size());
+
+ QBENCHMARK {
+ JsonReader reader;
+ if (!reader.parse(data)) {
+ qDebug() << "Failed to parse: " << reader.errorString();
+ return;
+ }
+ QVariant result = reader.result();
+ }
+}
+
+void tst_Json::testString()
+{
+ QFile file(QLatin1String("test.json"));
+ file.open(QFile::ReadOnly);
+ QByteArray ba = file.readAll();
+ QString data = QString::fromLocal8Bit(ba.constData(), ba.size());
+
+ QBENCHMARK {
+ JsonReader reader;
+ if (!reader.parse(data)) {
+ qDebug() << "Failed to parse: " << reader.errorString();
+ return;
+ }
+ QVariant result = reader.result();
+ }
+}
+
+void tst_Json::testByteArray()
+{
+ QFile file(QLatin1String("test.json"));
+ file.open(QFile::ReadOnly);
+ QByteArray testJson = file.readAll();
+
+ QBENCHMARK {
+ JsonReader reader;
+ if (!reader.parse(testJson)) {
+ qDebug() << "Failed to parse: " << reader.errorString();
+ return;
+ }
+ QVariant result = reader.result();
+ }
+}
+
+QTEST_MAIN(tst_Json)
+#include "main.moc"
diff --git a/src/3rdparty/qjson/benchmark/numbers.json b/src/3rdparty/qjson/benchmark/numbers.json
new file mode 100644
index 00000000..469156a7
--- /dev/null
+++ b/src/3rdparty/qjson/benchmark/numbers.json
@@ -0,0 +1,19 @@
+[
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E66,
+ "zero": 0,
+ "one": 1
+ },
+ [
+ -1234567890,
+ -1234567890,
+ -1234567890,
+ 1234567890,
+ 1234567890,
+ 1234567890
+ ]
+]
diff --git a/src/3rdparty/qjson/benchmark/test.json b/src/3rdparty/qjson/benchmark/test.json
new file mode 100644
index 00000000..7c935fff
--- /dev/null
+++ b/src/3rdparty/qjson/benchmark/test.json
@@ -0,0 +1,66 @@
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E66,
+ "zero": 0,
+ "one": 1,
+ "space": " ",
+ "quote": "\"",
+ "backslash": "\\",
+ "controls": "\b\f\n\r\t",
+ "slash": "/ & \/",
+ "alpha": "abcdefghijklmnopqrstuvwxyz",
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "digit": "0123456789",
+ "0123456789": "digit",
+ "special": "`1~!@#$%^&*()_+-={\':[,]}|;.</>?",
+ "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "address": "50 St. James Street",
+ "url": "http://www.JSON.org/",
+ "comment": "// /* <!-- --",
+ "# -- --> */": " ",
+ " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?" : "A key can be any string"
+ },
+ 0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,
+2e+00,
+2e-00,
+"rosebud",
+{"foo": "bar"},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}}
+]
+
diff --git a/src/3rdparty/qjson/json.pro b/src/3rdparty/qjson/json.pro
new file mode 100644
index 00000000..ffb1ce99
--- /dev/null
+++ b/src/3rdparty/qjson/json.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = tests benchmark
diff --git a/src/3rdparty/qjson/qjson.pri b/src/3rdparty/qjson/qjson.pri
new file mode 100644
index 00000000..680b5818
--- /dev/null
+++ b/src/3rdparty/qjson/qjson.pri
@@ -0,0 +1 @@
+include(src/json.pri)
diff --git a/src/3rdparty/qjson/src/json.cpp b/src/3rdparty/qjson/src/json.cpp
new file mode 100644
index 00000000..a7489e3d
--- /dev/null
+++ b/src/3rdparty/qjson/src/json.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#include "json.h"
+#include "jsonparser.cpp"
+
+#include <QTextCodec>
+#include <qnumeric.h>
+
+/*!
+ \class JsonReader
+ \internal
+ \reentrant
+
+ \brief The JsonReader class provides a fast parser for reading
+ well-formed JSON into a QVariant.
+
+ The parser converts JSON types into QVariant types. For example, JSON
+ arrays are translated into QVariantList and JSON objects are translated
+ into QVariantMap. For example,
+ \code
+ JsonReader reader;
+ if (reader.parse("{ \"id\": 123, \"company\": \"Nokia\", \"authors\": [\"Denis\",\"Ettrich\",\"Girish\"])) {
+ QVariant result = reader.result();
+ QVariantMap map = result.toMap(); // the JSON object
+ qDebug() << map.count(); // 3
+ qDebug() << map["id"].toInt(); // 123
+ qDebug() << map["company"].toString(); // "Nokia"
+ QVariantList list = map["authors"].toList();
+ qDebug() << list[1].toString(); // "Girish"
+ } else {
+ qDebug() << reader.errorString();
+ }
+ \endcode
+
+ As seen above, the reader converts the JSON into a QVariant with arbitrary nesting.
+ A complete listing of JSON to QVariant conversion is documented at parse().
+
+ JsonWriter can be used to convert a QVariant into JSON string.
+*/
+
+/*!
+ Constructs a JSON reader.
+ */
+JsonReader::JsonReader()
+{
+}
+
+/*!
+ Destructor
+ */
+JsonReader::~JsonReader()
+{
+}
+
+/*!
+ Parses the JSON \a ba as a QVariant.
+
+ If the parse succeeds, this function returns true and the QVariant can
+ be accessed using result(). If the parse fails, this function returns
+ false and the error message can be accessed using errorMessage().
+
+ The encoding of \ba is auto-detected based on the pattern of nulls in the
+ initial 4 octets as described in "Section 3. Encoding" of RFC 2647. If an
+ encoding could not be auto-detected, this function assumes UTF-8.
+
+ The conversion from JSON type into QVariant type is as listed below:
+ \table
+ \row
+ \o false
+ \o QVariant::Bool with the value false.
+ \row
+ \o true
+ \o QVariant::Bool with the value true.
+ \row
+ \o null
+ \o QVariant::Invalid i.e QVariant()
+ \row
+ \o object
+ \o QVariant::Map i.e QVariantMap
+ \row
+ \o array
+ \o QVariant::List i.e QVariantList
+ \row
+ \o string
+ \o QVariant::String i.e QString
+ \row
+ \o number
+ \o QVariant::Double or QVariant::LongLong. If the JSON number contains a '.' or 'e'
+ or 'E', QVariant::Double is used.
+ \endtable
+
+ The byte array \ba may or may not contain a BOM.
+ */
+bool JsonReader::parse(const QByteArray &ba)
+{
+ int mib = 106; // utf-8
+
+ QTextCodec *codec = QTextCodec::codecForUtfText(ba, 0); // try BOM detection
+ if (!codec) {
+ if (ba.length() > 3) { // auto-detect
+ const char *data = ba.constData();
+ if (data[0] != 0) {
+ if (data[1] != 0)
+ mib = 106; // utf-8
+ else if (data[2] != 0)
+ mib = 1014; // utf16 le
+ else
+ mib = 1019; // utf32 le
+ } else if (data[1] != 0)
+ mib = 1013; // utf16 be
+ else
+ mib = 1018; // utf32 be
+ }
+ codec = QTextCodec::codecForMib(mib);
+ }
+ QString str = codec->toUnicode(ba);
+ return parse(str);
+}
+
+/*!
+ Parses the JSON string \a str as a QVariant.
+
+ If the parse succeeds, this function returns true and the QVariant can
+ be accessed using result(). If the parse fails, this function returns
+ false and the error message can be accessed using errorMessage().
+ */
+bool JsonReader::parse(const QString &str)
+{
+ JsonLexer lexer(str);
+ JsonParser parser;
+ if (!parser.parse(&lexer)) {
+ m_errorString = parser.errorMessage();
+ m_result = QVariant();
+ return false;
+ }
+ m_errorString.clear();
+ m_result = parser.result();
+ return true;
+}
+
+/*!
+ Returns the result of the last parse() call.
+
+ If parse() failed, this function returns an invalid QVariant.
+ */
+QVariant JsonReader::result() const
+{
+ return m_result;
+}
+
+/*!
+ Returns the error message for the last parse() call.
+
+ If parse() succeeded, this functions return an empty string. The error message
+ should be used for debugging purposes only.
+ */
+QString JsonReader::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \class JsonWriter
+ \internal
+ \reentrant
+
+ \brief The JsonWriter class converts a QVariant into a JSON string.
+
+ The writer converts specific supported types stored in a QVariant into JSON.
+ For example,
+ \code
+ QVariant v;
+ QVariantMap map;
+ map["id"] = 123;
+ map["company"] = "Nokia";
+ QVariantList list;
+ list << "Denis" << "Ettrich" << "Girish";
+ map["authors"] = list;
+
+ JsonWriter writer;
+ QString json = writer.toString(v);
+ qDebug() << json; // {"authors": ["Denis", "Ettrich", "Girish"], "company": "Nokia", "id": 123 }
+ \endcode
+
+ The list of QVariant types that the writer supports is listed in toString(). Note that
+ custom C++ types registered using Q_DECLARE_METATYPE are not supported.
+*/
+
+/*!
+ Creates a JsonWriter.
+ */
+JsonWriter::JsonWriter()
+ : m_autoFormatting(false), m_autoFormattingIndent(4, QLatin1Char(' '))
+{
+}
+
+/*!
+ Destructor.
+ */
+JsonWriter::~JsonWriter()
+{
+}
+
+/*!
+ Enables auto formatting if \a enable is \c true, otherwise
+ disables it.
+
+ When auto formatting is enabled, the writer automatically inserts
+ spaces and new lines to make the output more human readable.
+
+ The default value is \c false.
+ */
+void JsonWriter::setAutoFormatting(bool enable)
+{
+ m_autoFormatting = enable;
+}
+
+/*!
+ Returns \c true if auto formattting is enabled, otherwise \c false.
+ */
+bool JsonWriter::autoFormatting() const
+{
+ return m_autoFormatting;
+}
+
+/*!
+ Sets the number of spaces or tabs used for indentation when
+ auto-formatting is enabled. Positive numbers indicate spaces,
+ negative numbers tabs.
+
+ The default indentation is 4.
+
+ \sa setAutoFormatting()
+*/
+void JsonWriter::setAutoFormattingIndent(int spacesOrTabs)
+{
+ m_autoFormattingIndent = QString(qAbs(spacesOrTabs), QLatin1Char(spacesOrTabs >= 0 ? ' ' : '\t'));
+}
+
+/*!
+ Retuns the numbers of spaces or tabs used for indentation when
+ auto-formatting is enabled. Positive numbers indicate spaces,
+ negative numbers tabs.
+
+ The default indentation is 4.
+
+ \sa setAutoFormatting()
+*/
+int JsonWriter::autoFormattingIndent() const
+{
+ return m_autoFormattingIndent.count(QLatin1Char(' ')) - m_autoFormattingIndent.count(QLatin1Char('\t'));
+}
+
+/*! \internal
+ Inserts escape character \ for characters in string as described in JSON specification.
+ */
+static QString escape(const QVariant &variant)
+{
+ QString str = variant.toString();
+ QString res;
+ res.reserve(str.length());
+ for (int i = 0; i < str.length(); i++) {
+ if (str[i] == QLatin1Char('\b')) {
+ res += QLatin1String("\\b");
+ } else if (str[i] == QLatin1Char('\f')) {
+ res += QLatin1String("\\f");
+ } else if (str[i] == QLatin1Char('\n')) {
+ res += QLatin1String("\\n");
+ } else if (str[i] == QLatin1Char('\r')) {
+ res += QLatin1String("\\r");
+ } else if (str[i] == QLatin1Char('\t')) {
+ res += QLatin1String("\\t");
+ } else if (str[i] == QLatin1Char('\"')) {
+ res += QLatin1String("\\\"");
+ } else if (str[i] == QLatin1Char('\\')) {
+ res += QLatin1String("\\\\");
+ } else if (str[i] == QLatin1Char('/')) {
+ res += QLatin1String("\\/");
+ } else if (str[i].unicode() > 127) {
+ res += QLatin1String("\\u") + QString::number(str[i].unicode(), 16).rightJustified(4, QLatin1Char('0'));
+ } else {
+ res += str[i];
+ }
+ }
+ return res;
+}
+
+/*! \internal
+ Stringifies \a variant.
+ */
+QString JsonWriter::stringify(const QVariant &variant, int depth)
+{
+ QString result;
+ if (variant.type() == QVariant::List || variant.type() == QVariant::StringList) {
+ result += QLatin1Char('[');
+ QVariantList list = variant.toList();
+ for (int i = 0; i < list.count(); i++) {
+ if (i != 0) {
+ result += QLatin1Char(',');
+ if (m_autoFormatting)
+ result += QLatin1Char(' ');
+ }
+ result += stringify(list[i], depth+1);
+ }
+ result += QLatin1Char(']');
+ } else if (variant.type() == QVariant::Map) {
+ QString indent = m_autoFormattingIndent.repeated(depth);
+ QVariantMap map = variant.toMap();
+ if (m_autoFormatting && depth != 0) {
+ result += QLatin1Char('\n');
+ result += indent;
+ result += QLatin1String("{\n");
+ } else {
+ result += QLatin1Char('{');
+ }
+ for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) {
+ if (it != map.constBegin()) {
+ result += QLatin1Char(',');
+ if (m_autoFormatting)
+ result += QLatin1Char('\n');
+ }
+ if (m_autoFormatting)
+ result += indent + QLatin1Char(' ');
+ result += QLatin1Char('\"') + escape(it.key()) + QLatin1String("\":");
+ result += stringify(it.value(), depth+1);
+ }
+ if (m_autoFormatting) {
+ result += QLatin1Char('\n');
+ result += indent;
+ }
+ result += QLatin1Char('}');
+ } else if (variant.type() == QVariant::String || variant.type() == QVariant::ByteArray) {
+ result = QLatin1Char('\"') + escape(variant) + QLatin1Char('\"');
+ } else if (variant.type() == QVariant::Double || (int)variant.type() == (int)QMetaType::Float) {
+ double d = variant.toDouble();
+ if (qIsFinite(d))
+ result.setNum(variant.toDouble(), 'g', 15);
+ else
+ result = QLatin1String("null");
+ } else if (variant.type() == QVariant::Bool) {
+ result = variant.toBool() ? QLatin1String("true") : QLatin1String("false");
+ } else if (variant.type() == QVariant::Invalid) {
+ result = QLatin1String("null");
+ } else if (variant.type() == QVariant::ULongLong) {
+ result = QString::number(variant.toULongLong());
+ } else if (variant.type() == QVariant::LongLong) {
+ result = QString::number(variant.toLongLong());
+ } else if (variant.type() == QVariant::Int) {
+ result = QString::number(variant.toInt());
+ } else if (variant.type() == QVariant::UInt) {
+ result = QString::number(variant.toUInt());
+ } else if (variant.type() == QVariant::Char) {
+ QChar c = variant.toChar();
+ if (c.unicode() > 127)
+ result = QLatin1String("\"\\u") + QString::number(c.unicode(), 16).rightJustified(4, QLatin1Char('0')) + QLatin1Char('\"');
+ else
+ result = QLatin1Char('\"') + c + QLatin1Char('\"');
+ } else if (variant.canConvert<qlonglong>()) {
+ result = QString::number(variant.toLongLong());
+ } else if (variant.canConvert<QString>()) {
+ result = QLatin1Char('\"') + escape(variant) + QLatin1Char('\"');
+ } else {
+ result = QLatin1String("null");
+ }
+
+ return result;
+}
+
+/*!
+ Converts the variant \a var into a JSON string.
+
+ The stringizer converts \a var into JSON based on the type of it's contents. The supported
+ types and their conversion into JSON is as listed below:
+
+ \table
+ \row
+ \o QVariant::List, QVariant::StringList
+ \o JSON array []
+ \row
+ \o QVariant::Map
+ \o JSON object {}
+ \row
+ \o QVariant::String, QVariant::ByteArray
+ \o JSON string encapsulated in double quotes. String contents are escaped using '\' if necessary.
+ \row
+ \o QVariant::Double, QMetaType::Float
+ \o JSON number with a precision 15. Infinity and NaN are converted into null.
+ \row
+ \o QVariant::Bool
+ \o JSON boolean true and false
+ \row
+ \o QVariant::Invalid
+ \o JSON null
+ \row
+ \o QVariant::ULongLong, QVariant::LongLong, QVariant::Int, QVariant::UInt,
+ \o JSON number
+ \row
+ \o QVariant::Char
+ \o JSON string. Non-ASCII characters are converted into the \uXXXX notation.
+ \endtable
+
+ As a fallback, the writer attempts to convert a type not listed above into a long long or a
+ QString using QVariant::canConvert. See the QVariant documentation for possible conversions.
+
+ JsonWriter does not support stringizing custom user types stored in the QVariant. Any such
+ value would be converted into JSON null.
+ */
+QString JsonWriter::toString(const QVariant &var)
+{
+ return stringify(var);
+}
+
+/*!
+ Converts the variant \a var into a JSON string.
+
+ The returned QByteArray is UTF-8 encoded and does not contain a BOM. The list of supported
+ C++ types is documented in toString().
+
+ \sa toString()
+ */
+QByteArray JsonWriter::toByteArray(const QVariant &var)
+{
+ return stringify(var).toUtf8();
+}
+
diff --git a/src/3rdparty/qjson/src/json.g b/src/3rdparty/qjson/src/json.g
new file mode 100644
index 00000000..d1f9e17f
--- /dev/null
+++ b/src/3rdparty/qjson/src/json.g
@@ -0,0 +1,420 @@
+-- ***************************************************************************
+--
+-- Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+-- Copyright (c) 2011 Denis Dzyubenko <shadone@gmail.com>
+--
+-- Use, modification and distribution is allowed without limitation,
+-- warranty, liability or support of any kind.
+--
+-- **************************************************************************
+
+%parser JsonGrammar
+%merged_output jsonparser.cpp
+
+%token T_STRING "string"
+%token T_NUMBER "number"
+%token T_LCURLYBRACKET "{"
+%token T_RCURLYBRACKET "}"
+%token T_LSQUAREBRACKET "["
+%token T_RSQUAREBRACKET "]"
+%token T_COLON ":"
+%token T_COMMA ","
+%token T_FALSE "false"
+%token T_TRUE "true"
+%token T_NULL "null"
+%token ERROR "error"
+
+%start Root
+
+/:
+/****************************************************************************
+**
+** Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+** Copyright (c) 2011 Denis Dzyubenko <shadone@gmail.com>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#ifndef JSONPARSER_P_H
+#define JSONPARSER_P_H
+
+#include <QString>
+#include <QVariant>
+#include <QVector>
+
+class JsonLexer
+{
+public:
+ JsonLexer(const QString &string);
+ ~JsonLexer();
+
+ int lex();
+ QVariant symbol() const { return m_symbol; }
+ int lineNumber() const { return m_lineNumber; }
+ int pos() const { return m_pos; }
+
+private:
+ int parseNumber();
+ int parseString();
+ int parseKeyword();
+
+ QString m_strdata;
+ int m_lineNumber;
+ int m_pos;
+ QVariant m_symbol;
+};
+
+class JsonParser : protected $table
+{
+public:
+ JsonParser();
+ ~JsonParser();
+
+ bool parse(JsonLexer *lex);
+ QVariant result() const { return m_result; }
+ QString errorMessage() const { return QString::fromLatin1("%1 at line %2 pos %3").arg(m_errorMessage).arg(m_errorLineNumber).arg(m_errorPos); }
+
+private:
+ void reallocateStack();
+
+ inline QVariant &sym(int index)
+ { return m_symStack[m_tos + index - 1]; }
+ inline QVariantMap &map(int index)
+ { return m_mapStack[m_tos + index - 1]; }
+ inline QVariantList &list(int index)
+ { return m_listStack[m_tos + index - 1]; }
+
+ int m_tos;
+ QVector<int> m_stateStack;
+ QVector<QVariant> m_symStack;
+ QVector<QVariantMap> m_mapStack;
+ QVector<QVariantList> m_listStack;
+ QString m_errorMessage;
+ int m_errorLineNumber;
+ int m_errorPos;
+ QVariant m_result;
+};
+
+#endif // JSONPARSER_P_H
+:/
+
+/.
+/****************************************************************************
+**
+** Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+** Copyright (c) 2011 Denis Dzyubenko <shadone@gmail.com>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#include <QtDebug>
+
+#define L1C(c) ushort(uchar(c))
+
+JsonLexer::JsonLexer(const QString &str)
+ : m_strdata(str), m_lineNumber(1), m_pos(0)
+{
+}
+
+
+
+JsonLexer::~JsonLexer()
+{
+}
+
+int JsonLexer::parseString()
+{
+ bool esc = false;
+ ++m_pos; // skip initial "
+ int start = m_pos;
+
+ const ushort *uc = m_strdata.utf16();
+ const int remaining = m_strdata.length() - m_pos;
+ int i;
+ for (i = 0; i < remaining; ++i) {
+ const ushort c = uc[m_pos + i];
+ if (c == L1C('\"')) {
+ m_symbol = QString((QChar *)uc + m_pos, i);
+ m_pos += i;
+ ++m_pos; // eat quote
+ return JsonGrammar::T_STRING;
+ } else if (c == L1C('\\')) {
+ ++m_pos; // eat backslash
+ esc = true;
+ break;
+ }
+ }
+
+ QString str;
+ if (i) {
+ str.resize(i);
+ memcpy((char *)str.utf16(), uc + start, i * 2);
+ m_pos += i;
+ }
+
+ for (; m_pos < m_strdata.length(); ++m_pos) {
+ const ushort c = uc[m_pos];
+ if (esc) {
+ if (c == L1C('b')) str += QLatin1Char('\b');
+ else if (c == L1C('f')) str += QLatin1Char('\f');
+ else if (c == L1C('n')) str += QLatin1Char('\n');
+ else if (c == L1C('r')) str += QLatin1Char('\r');
+ else if (c == L1C('t')) str += QLatin1Char('\t');
+ else if (c == L1C('\\')) str += QLatin1Char('\\');
+ else if (c == L1C('\"')) str += QLatin1Char('\"');
+ else if (c == L1C('u') && m_pos+4<m_strdata.length()-1) {
+ QString u = m_strdata.mid(m_pos+1, 4);
+ str += QChar(u.toUShort(0, 16));
+ m_pos += 4;
+ } else {
+ str += QChar(c);
+ }
+ esc = false;
+ } else if (c == L1C('\\')) {
+ esc = true;
+ } else if (c == L1C('\"')) {
+ m_symbol = str;
+ ++m_pos;
+ return JsonGrammar::T_STRING;
+ } else {
+ str += QChar(c);
+ }
+ }
+ return JsonGrammar::ERROR;
+}
+
+int JsonLexer::parseNumber()
+{
+ int start = m_pos;
+ bool isDouble = false;
+ const ushort *uc = m_strdata.utf16();
+ const int l = m_strdata.length();
+ const int negative = (uc[m_pos] == L1C('-') ? ++m_pos, -1 : (uc[m_pos] == L1C('+') ? ++m_pos, 1 : 1));
+ qlonglong value = 0;
+ for (; m_pos < l; ++m_pos) {
+ const ushort &c = uc[m_pos];
+ if (c == L1C('+') || c == L1C('-'))
+ continue;
+ if (c == L1C('.') || c == L1C('e') || c == L1C('E')) {
+ isDouble = true;
+ continue;
+ }
+ if (c >= L1C('0') && c <= L1C('9')) {
+ if (!isDouble) {
+ value *= 10;
+ value += c - L1C('0');
+ }
+ continue;
+ }
+ break;
+ }
+ if (!isDouble) {
+ m_symbol = value * negative;
+ } else {
+ QString number = QString::fromRawData((QChar *)uc+start, m_pos-start);
+ m_symbol = number.toDouble();
+ }
+ return JsonGrammar::T_NUMBER;
+}
+
+int JsonLexer::parseKeyword()
+{
+ int start = m_pos;
+ for (; m_pos < m_strdata.length(); ++m_pos) {
+ const ushort c = m_strdata.at(m_pos).unicode();
+ if (c >= L1C('a') && c <= L1C('z'))
+ continue;
+ break;
+ }
+ const ushort *k = (const ushort *)m_strdata.constData() + start;
+ const int l = m_pos-start;
+ if (l == 4) {
+ static const ushort true_data[] = { 't', 'r', 'u', 'e' };
+ static const ushort null_data[] = { 'n', 'u', 'l', 'l' };
+ if (!memcmp(k, true_data, 4))
+ return JsonGrammar::T_TRUE;
+ if (!memcmp(k, null_data, 4))
+ return JsonGrammar::T_NULL;
+ } else if (l == 5) {
+ static const ushort false_data[] = { 'f', 'a', 'l', 's', 'e' };
+ if (!memcmp(k, false_data, 5))
+ return JsonGrammar::T_FALSE;
+ }
+ return JsonGrammar::ERROR;
+}
+
+int JsonLexer::lex()
+{
+ m_symbol.clear();
+
+ const ushort *uc = m_strdata.utf16();
+ const int len = m_strdata.length();
+ while (m_pos < len) {
+ const ushort c = uc[m_pos];
+ switch (c) {
+ case L1C('['): ++m_pos; return JsonGrammar::T_LSQUAREBRACKET;
+ case L1C(']'): ++m_pos; return JsonGrammar::T_RSQUAREBRACKET;
+ case L1C('{'): ++m_pos; return JsonGrammar::T_LCURLYBRACKET;
+ case L1C('}'): ++m_pos; return JsonGrammar::T_RCURLYBRACKET;
+ case L1C(':'): ++m_pos; return JsonGrammar::T_COLON;
+ case L1C(','): ++m_pos; return JsonGrammar::T_COMMA;
+ case L1C(' '): case L1C('\r'): case L1C('\t'): ++m_pos; break;
+ case L1C('\n'): ++m_pos; ++m_lineNumber; break;
+ case L1C('"'): return parseString();
+ default:
+ if (c == L1C('+') || c == L1C('-') || (c >= L1C('0') && c <= L1C('9'))) {
+ return parseNumber();
+ }
+ if (c >= L1C('a') && c <= L1C('z')) {
+ return parseKeyword();
+ }
+ return JsonGrammar::ERROR;
+ }
+ }
+ return JsonGrammar::EOF_SYMBOL;
+}
+#undef L1C
+
+JsonParser::JsonParser()
+{
+}
+
+JsonParser::~JsonParser()
+{
+}
+
+void JsonParser::reallocateStack()
+{
+ int size = m_stateStack.size();
+ if (size == 0)
+ size = 128;
+ else
+ size <<= 1;
+
+ m_symStack.resize(size);
+ m_mapStack.resize(size);
+ m_listStack.resize(size);
+ m_stateStack.resize(size);
+}
+
+bool JsonParser::parse(JsonLexer *lexer)
+{
+ const int INITIAL_STATE = 0;
+ int yytoken = -1;
+ reallocateStack();
+ m_tos = 0;
+ m_stateStack[++m_tos] = INITIAL_STATE;
+
+ while (true) {
+ const int state = m_stateStack[m_tos];
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[state]) {
+ yytoken = lexer->lex();
+ }
+ int act = t_action(state, yytoken);
+ if (act == ACCEPT_STATE)
+ return true;
+ else if (act > 0) {
+ if (++m_tos == m_stateStack.size())
+ reallocateStack();
+ m_stateStack[m_tos] = act;
+ m_symStack[m_tos] = lexer->symbol();
+ yytoken = -1;
+ } else if (act < 0) {
+ int r = -act-1;
+ m_tos -= rhs[r];
+ act = m_stateStack.at(m_tos++);
+ switch (r) {
+./
+
+Root ::= Value;
+/. case $rule_number: { m_result = sym(1); break; } ./
+
+Object ::= T_LCURLYBRACKET Members T_RCURLYBRACKET;
+/. case $rule_number: { sym(1) = map(2); break; } ./
+
+Members ::= T_STRING T_COLON Value;
+/. case $rule_number: { QVariantMap m; m.insert(sym(1).toString(), sym(3)); map(1) = m; break; } ./
+
+Members ::= Members T_COMMA T_STRING T_COLON Value;
+/. case $rule_number: { map(1).insert(sym(3).toString(), sym(5)); break; } ./
+
+Members ::= ;
+/. case $rule_number: { map(1) = QVariantMap(); break; } ./
+
+Value ::= T_FALSE;
+/. case $rule_number: { sym(1) = QVariant(false); break; } ./
+
+Value ::= T_TRUE;
+/. case $rule_number: { sym(1) = QVariant(true); break; } ./
+
+Value ::= T_NULL;
+Value ::= Object;
+Value ::= Array;
+Value ::= T_NUMBER;
+Value ::= T_STRING;
+
+Array ::= T_LSQUAREBRACKET Values T_RSQUAREBRACKET;
+/. case $rule_number: { sym(1) = list(2); break; } ./
+
+Values ::= Value;
+/. case $rule_number: { QVariantList l; l.append(sym(1)); list(1) = l; break; } ./
+
+Values ::= Values T_COMMA Value;
+/. case $rule_number: { list(1).append(sym(3)); break; } ./
+
+Values ::= ;
+/. case $rule_number: { list(1) = QVariantList(); break; } ./
+
+/.
+ } // switch
+ m_stateStack[m_tos] = nt_action(act, lhs[r] - TERMINAL_COUNT);
+ } else {
+ int ers = state;
+ int shifts = 0;
+ int reduces = 0;
+ int expected_tokens[3];
+ for (int tk = 0; tk < TERMINAL_COUNT; ++tk) {
+ int k = t_action(ers, tk);
+
+ if (! k)
+ continue;
+ else if (k < 0)
+ ++reduces;
+ else if (spell[tk]) {
+ if (shifts < 3)
+ expected_tokens[shifts] = tk;
+ ++shifts;
+ }
+ }
+
+ m_errorLineNumber = lexer->lineNumber();
+ m_errorPos = lexer->pos();
+ m_errorMessage.clear();
+ if (shifts && shifts < 3) {
+ bool first = true;
+
+ for (int s = 0; s < shifts; ++s) {
+ if (first)
+ m_errorMessage += QLatin1String("Expected ");
+ else
+ m_errorMessage += QLatin1String(", ");
+
+ first = false;
+ m_errorMessage += QLatin1String("'");
+ m_errorMessage += QLatin1String(spell[expected_tokens[s]]);
+ m_errorMessage += QLatin1String("'");
+ }
+ }
+ return false;
+ }
+ }
+
+ return false;
+}
+
+./
+
diff --git a/src/3rdparty/qjson/src/json.h b/src/3rdparty/qjson/src/json.h
new file mode 100644
index 00000000..62f33a40
--- /dev/null
+++ b/src/3rdparty/qjson/src/json.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#ifndef JSON_H
+#define JSON_H
+
+#include <QByteArray>
+#include <QVariant>
+
+class JsonReader
+{
+public:
+ JsonReader();
+ ~JsonReader();
+
+ bool parse(const QByteArray &ba);
+ bool parse(const QString &str);
+
+ QVariant result() const;
+
+ QString errorString() const;
+
+private:
+ QVariant m_result;
+ QString m_errorString;
+ void *reserved;
+};
+
+class JsonWriter
+{
+public:
+ JsonWriter();
+ ~JsonWriter();
+
+ QString toString(const QVariant &variant);
+ QByteArray toByteArray(const QVariant &variant);
+
+ void setAutoFormatting(bool autoFormat);
+ bool autoFormatting() const;
+
+ void setAutoFormattingIndent(int spaceOrTabs);
+ int autoFormattingIndent() const;
+
+private:
+ QString stringify(const QVariant &variant, int depth = 0);
+ bool m_autoFormatting;
+ QString m_autoFormattingIndent;
+ void *reserved;
+};
+
+#endif // JSON_H
+
diff --git a/src/3rdparty/qjson/src/json.pri b/src/3rdparty/qjson/src/json.pri
new file mode 100644
index 00000000..0244a158
--- /dev/null
+++ b/src/3rdparty/qjson/src/json.pri
@@ -0,0 +1,4 @@
+INCLUDEPATH += $$PWD
+SOURCES += $$PWD/json.cpp
+
+#DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_BYTEARRAY
diff --git a/src/3rdparty/qjson/src/jsonparser.cpp b/src/3rdparty/qjson/src/jsonparser.cpp
new file mode 100644
index 00000000..899103f9
--- /dev/null
+++ b/src/3rdparty/qjson/src/jsonparser.cpp
@@ -0,0 +1,527 @@
+// This file was generated by qlalr - DO NOT EDIT!
+#ifndef JSONPARSER_CPP
+#define JSONPARSER_CPP
+
+class JsonGrammar
+{
+public:
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ ERROR = 12,
+ T_COLON = 7,
+ T_COMMA = 8,
+ T_FALSE = 9,
+ T_LCURLYBRACKET = 3,
+ T_LSQUAREBRACKET = 5,
+ T_NULL = 11,
+ T_NUMBER = 2,
+ T_RCURLYBRACKET = 4,
+ T_RSQUAREBRACKET = 6,
+ T_STRING = 1,
+ T_TRUE = 10,
+
+ ACCEPT_STATE = 12,
+ RULE_COUNT = 17,
+ STATE_COUNT = 27,
+ TERMINAL_COUNT = 13,
+ NON_TERMINAL_COUNT = 7,
+
+ GOTO_INDEX_OFFSET = 27,
+ GOTO_INFO_OFFSET = 37,
+ GOTO_CHECK_OFFSET = 37
+ };
+
+ static const char *const spell [];
+ static const short lhs [];
+ static const short rhs [];
+
+#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO
+ static const int rule_index [];
+ static const int rule_info [];
+#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO
+
+ static const short goto_default [];
+ static const short action_default [];
+ static const short action_index [];
+ static const short action_info [];
+ static const short action_check [];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
+};
+
+
+const char *const JsonGrammar::spell [] = {
+ "end of file", "string", "number", "{", "}", "[", "]", ":", ",", "false",
+ "true", "null", "error",
+#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO
+"Root", "Value", "Object", "Members", "Array", "Values", "$accept"
+#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO
+};
+
+const short JsonGrammar::lhs [] = {
+ 13, 15, 16, 16, 16, 14, 14, 14, 14, 14,
+ 14, 14, 17, 18, 18, 18, 19};
+
+const short JsonGrammar::rhs [] = {
+ 1, 3, 3, 5, 0, 1, 1, 1, 1, 1,
+ 1, 1, 3, 1, 3, 0, 2};
+
+
+#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO
+const int JsonGrammar::rule_info [] = {
+ 13, 14
+ , 15, 3, 16, 4
+ , 16, 1, 7, 14
+ , 16, 16, 8, 1, 7, 14
+ , 16
+ , 14, 9
+ , 14, 10
+ , 14, 11
+ , 14, 15
+ , 14, 17
+ , 14, 2
+ , 14, 1
+ , 17, 5, 18, 6
+ , 18, 14
+ , 18, 18, 8, 14
+ , 18
+ , 19, 13, 0};
+
+const int JsonGrammar::rule_index [] = {
+ 0, 2, 6, 10, 16, 17, 19, 21, 23, 25,
+ 27, 29, 31, 35, 37, 41, 42};
+#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO
+
+const short JsonGrammar::action_default [] = {
+ 0, 10, 9, 0, 6, 5, 16, 8, 11, 12,
+ 7, 1, 17, 0, 0, 0, 2, 0, 0, 4,
+ 0, 3, 14, 0, 0, 13, 15};
+
+const short JsonGrammar::goto_default [] = {
+ 3, 11, 2, 13, 1, 23, 0};
+
+const short JsonGrammar::action_index [] = {
+ 24, -13, -13, 12, -13, -1, 24, -13, -13, -13,
+ -13, -13, -13, 1, -5, 2, -13, -6, 24, -13,
+ 24, -13, -13, -2, 24, -13, -13,
+
+ -7, -7, -7, -7, -7, -7, 1, -7, -7, -7,
+ -7, -7, -7, -7, -7, -7, -7, -7, 0, -7,
+ -1, -7, -7, -7, 5, -7, -7};
+
+const short JsonGrammar::action_info [] = {
+ 14, 18, 20, 17, 25, 16, 24, 0, 0, 15,
+ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 8, 5, 0, 6,
+ 0, 0, 0, 4, 10, 7, 0,
+
+ 21, 19, 22, 0, 0, 0, 26, 0, 0, 0,
+ 0, 0};
+
+const short JsonGrammar::action_check [] = {
+ 1, 7, 7, 1, 6, 4, 8, -1, -1, 8,
+ -1, -1, 0, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 1, 2, 3, -1, 5,
+ -1, -1, -1, 9, 10, 11, -1,
+
+ 1, 1, 1, -1, -1, -1, 1, -1, -1, -1,
+ -1, -1};
+
+
+#line 29 "json.g"
+
+/****************************************************************************
+**
+** Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+** Copyright (c) 2011 Denis Dzyubenko <shadone@gmail.com>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#ifndef JSONPARSER_P_H
+#define JSONPARSER_P_H
+
+#include <QString>
+#include <QVariant>
+#include <QVector>
+
+class JsonLexer
+{
+public:
+ JsonLexer(const QString &string);
+ ~JsonLexer();
+
+ int lex();
+ QVariant symbol() const { return m_symbol; }
+ int lineNumber() const { return m_lineNumber; }
+ int pos() const { return m_pos; }
+
+private:
+ int parseNumber();
+ int parseString();
+ int parseKeyword();
+
+ QString m_strdata;
+ int m_lineNumber;
+ int m_pos;
+ QVariant m_symbol;
+};
+
+class JsonParser : protected JsonGrammar
+{
+public:
+ JsonParser();
+ ~JsonParser();
+
+ bool parse(JsonLexer *lex);
+ QVariant result() const { return m_result; }
+ QString errorMessage() const { return QString::fromLatin1("%1 at line %2 pos %3").arg(m_errorMessage).arg(m_errorLineNumber).arg(m_errorPos); }
+
+private:
+ void reallocateStack();
+
+ inline QVariant &sym(int index)
+ { return m_symStack[m_tos + index - 1]; }
+ inline QVariantMap &map(int index)
+ { return m_mapStack[m_tos + index - 1]; }
+ inline QVariantList &list(int index)
+ { return m_listStack[m_tos + index - 1]; }
+
+ int m_tos;
+ QVector<int> m_stateStack;
+ QVector<QVariant> m_symStack;
+ QVector<QVariantMap> m_mapStack;
+ QVector<QVariantList> m_listStack;
+ QString m_errorMessage;
+ int m_errorLineNumber;
+ int m_errorPos;
+ QVariant m_result;
+};
+
+#endif // JSONPARSER_P_H
+
+#line 103 "json.g"
+
+/****************************************************************************
+**
+** Copyright (c) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+** Copyright (c) 2011 Denis Dzyubenko <shadone@gmail.com>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#include <QtDebug>
+
+#define L1C(c) ushort(uchar(c))
+
+JsonLexer::JsonLexer(const QString &str)
+ : m_strdata(str), m_lineNumber(1), m_pos(0)
+{
+}
+
+
+
+JsonLexer::~JsonLexer()
+{
+}
+
+int JsonLexer::parseString()
+{
+ bool esc = false;
+ ++m_pos; // skip initial "
+ int start = m_pos;
+
+ const ushort *uc = m_strdata.utf16();
+ const int remaining = m_strdata.length() - m_pos;
+ int i;
+ for (i = 0; i < remaining; ++i) {
+ const ushort c = uc[m_pos + i];
+ if (c == L1C('\"')) {
+ m_symbol = QString((QChar *)uc + m_pos, i);
+ m_pos += i;
+ ++m_pos; // eat quote
+ return JsonGrammar::T_STRING;
+ } else if (c == L1C('\\')) {
+ ++m_pos; // eat backslash
+ esc = true;
+ break;
+ }
+ }
+
+ QString str;
+ if (i) {
+ str.resize(i);
+ memcpy((char *)str.utf16(), uc + start, i * 2);
+ m_pos += i;
+ }
+
+ for (; m_pos < m_strdata.length(); ++m_pos) {
+ const ushort c = uc[m_pos];
+ if (esc) {
+ if (c == L1C('b')) str += QLatin1Char('\b');
+ else if (c == L1C('f')) str += QLatin1Char('\f');
+ else if (c == L1C('n')) str += QLatin1Char('\n');
+ else if (c == L1C('r')) str += QLatin1Char('\r');
+ else if (c == L1C('t')) str += QLatin1Char('\t');
+ else if (c == L1C('\\')) str += QLatin1Char('\\');
+ else if (c == L1C('\"')) str += QLatin1Char('\"');
+ else if (c == L1C('u') && m_pos+4<m_strdata.length()-1) {
+ // FIXME: This code is wrong
+ QString u1 = m_strdata.mid(m_pos+1, 2); // TODO: QStringRef please
+ QString u2 = m_strdata.mid(m_pos+3, 2);
+ bool ok;
+ str += QChar(u2.toInt(&ok, 16), u1.toInt(&ok, 16));
+ m_pos += 4;
+ } else {
+ str += QChar(c);
+ }
+ esc = false;
+ } else if (c == L1C('\\')) {
+ esc = true;
+ } else if (c == L1C('\"')) {
+ m_symbol = str;
+ ++m_pos;
+ return JsonGrammar::T_STRING;
+ } else {
+ str += QChar(c);
+ }
+ }
+ return JsonGrammar::ERROR;
+}
+
+int JsonLexer::parseNumber()
+{
+ int start = m_pos;
+ bool isDouble = false;
+ const ushort *uc = m_strdata.utf16();
+ const int l = m_strdata.length();
+ const int negative = (uc[m_pos] == L1C('-') ? ++m_pos, -1 : (uc[m_pos] == L1C('+') ? ++m_pos, 1 : 1));
+ qlonglong value = 0;
+ for (; m_pos < l; ++m_pos) {
+ const ushort &c = uc[m_pos];
+ if (c == L1C('+') || c == L1C('-'))
+ continue;
+ if (c == L1C('.') || c == L1C('e') || c == L1C('E')) {
+ isDouble = true;
+ continue;
+ }
+ if (c >= L1C('0') && c <= L1C('9')) {
+ if (!isDouble) {
+ value *= 10;
+ value += c - L1C('0');
+ }
+ continue;
+ }
+ break;
+ }
+ if (!isDouble) {
+ m_symbol = value * negative;
+ } else {
+ QString number = QString::fromRawData((QChar *)uc+start, m_pos-start);
+ m_symbol = number.toDouble();
+ }
+ return JsonGrammar::T_NUMBER;
+}
+
+int JsonLexer::parseKeyword()
+{
+ int start = m_pos;
+ for (; m_pos < m_strdata.length(); ++m_pos) {
+ const ushort c = m_strdata.at(m_pos).unicode();
+ if (c >= L1C('a') && c <= L1C('z'))
+ continue;
+ break;
+ }
+ const ushort *k = (const ushort *)m_strdata.constData() + start;
+ const int l = m_pos-start;
+ if (l == 4) {
+ static const ushort true_data[] = { 't', 'r', 'u', 'e' };
+ static const ushort null_data[] = { 'n', 'u', 'l', 'l' };
+ if (!memcmp(k, true_data, 4))
+ return JsonGrammar::T_TRUE;
+ if (!memcmp(k, null_data, 4))
+ return JsonGrammar::T_NULL;
+ } else if (l == 5) {
+ static const ushort false_data[] = { 'f', 'a', 'l', 's', 'e' };
+ if (!memcmp(k, false_data, 5))
+ return JsonGrammar::T_FALSE;
+ }
+ return JsonGrammar::ERROR;
+}
+
+int JsonLexer::lex()
+{
+ m_symbol.clear();
+
+ const ushort *uc = m_strdata.utf16();
+ const int len = m_strdata.length();
+ while (m_pos < len) {
+ const ushort c = uc[m_pos];
+ switch (c) {
+ case L1C('['): ++m_pos; return JsonGrammar::T_LSQUAREBRACKET;
+ case L1C(']'): ++m_pos; return JsonGrammar::T_RSQUAREBRACKET;
+ case L1C('{'): ++m_pos; return JsonGrammar::T_LCURLYBRACKET;
+ case L1C('}'): ++m_pos; return JsonGrammar::T_RCURLYBRACKET;
+ case L1C(':'): ++m_pos; return JsonGrammar::T_COLON;
+ case L1C(','): ++m_pos; return JsonGrammar::T_COMMA;
+ case L1C(' '): case L1C('\r'): case L1C('\t'): ++m_pos; break;
+ case L1C('\n'): ++m_pos; ++m_lineNumber; break;
+ case L1C('"'): return parseString();
+ default:
+ if (c == L1C('+') || c == L1C('-') || (c >= L1C('0') && c <= L1C('9'))) {
+ return parseNumber();
+ }
+ if (c >= L1C('a') && c <= L1C('z')) {
+ return parseKeyword();
+ }
+ return JsonGrammar::ERROR;
+ }
+ }
+ return JsonGrammar::EOF_SYMBOL;
+}
+#undef L1C
+
+JsonParser::JsonParser()
+{
+}
+
+JsonParser::~JsonParser()
+{
+}
+
+void JsonParser::reallocateStack()
+{
+ int size = m_stateStack.size();
+ if (size == 0)
+ size = 128;
+ else
+ size <<= 1;
+
+ m_symStack.resize(size);
+ m_mapStack.resize(size);
+ m_listStack.resize(size);
+ m_stateStack.resize(size);
+}
+
+bool JsonParser::parse(JsonLexer *lexer)
+{
+ const int INITIAL_STATE = 0;
+ int yytoken = -1;
+ reallocateStack();
+ m_tos = 0;
+ m_stateStack[++m_tos] = INITIAL_STATE;
+
+ while (true) {
+ const int state = m_stateStack[m_tos];
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[state]) {
+ yytoken = lexer->lex();
+ }
+ int act = t_action(state, yytoken);
+ if (act == ACCEPT_STATE)
+ return true;
+ else if (act > 0) {
+ if (++m_tos == m_stateStack.size())
+ reallocateStack();
+ m_stateStack[m_tos] = act;
+ m_symStack[m_tos] = lexer->symbol();
+ yytoken = -1;
+ } else if (act < 0) {
+ int r = -act-1;
+ m_tos -= rhs[r];
+ act = m_stateStack.at(m_tos++);
+ switch (r) {
+
+#line 337 "json.g"
+ case 0: { m_result = sym(1); break; }
+#line 340 "json.g"
+ case 1: { sym(1) = map(2); break; }
+#line 343 "json.g"
+ case 2: { QVariantMap m; m.insert(sym(1).toString(), sym(3)); map(1) = m; break; }
+#line 346 "json.g"
+ case 3: { map(1).insert(sym(3).toString(), sym(5)); break; }
+#line 349 "json.g"
+ case 4: { map(1) = QVariantMap(); break; }
+#line 352 "json.g"
+ case 5: { sym(1) = QVariant(false); break; }
+#line 355 "json.g"
+ case 6: { sym(1) = QVariant(true); break; }
+#line 364 "json.g"
+ case 12: { sym(1) = list(2); break; }
+#line 367 "json.g"
+ case 13: { QVariantList l; l.append(sym(1)); list(1) = l; break; }
+#line 370 "json.g"
+ case 14: { list(1).append(sym(3)); break; }
+#line 373 "json.g"
+ case 15: { list(1) = QVariantList(); break; }
+#line 375 "json.g"
+
+ } // switch
+ m_stateStack[m_tos] = nt_action(act, lhs[r] - TERMINAL_COUNT);
+ } else {
+ int ers = state;
+ int shifts = 0;
+ int reduces = 0;
+ int expected_tokens[3];
+ for (int tk = 0; tk < TERMINAL_COUNT; ++tk) {
+ int k = t_action(ers, tk);
+
+ if (! k)
+ continue;
+ else if (k < 0)
+ ++reduces;
+ else if (spell[tk]) {
+ if (shifts < 3)
+ expected_tokens[shifts] = tk;
+ ++shifts;
+ }
+ }
+
+ m_errorLineNumber = lexer->lineNumber();
+ m_errorPos = lexer->pos();
+ m_errorMessage.clear();
+ if (shifts && shifts < 3) {
+ bool first = true;
+
+ for (int s = 0; s < shifts; ++s) {
+ if (first)
+ m_errorMessage += QLatin1String("Expected ");
+ else
+ m_errorMessage += QLatin1String(", ");
+
+ first = false;
+ m_errorMessage += QLatin1String("'");
+ m_errorMessage += QLatin1String(spell[expected_tokens[s]]);
+ m_errorMessage += QLatin1String("'");
+ }
+ }
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+#endif // JSONPARSER_CPP
+
diff --git a/src/3rdparty/qjson/tests/data/non-latin1.json b/src/3rdparty/qjson/tests/data/non-latin1.json
new file mode 100644
index 00000000..4adddef3
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/non-latin1.json
@@ -0,0 +1,4 @@
+{
+ "name": "தஹெரா"
+}
+
diff --git a/src/3rdparty/qjson/tests/data/non-latin1.json.ref b/src/3rdparty/qjson/tests/data/non-latin1.json.ref
new file mode 100644
index 00000000..42f0b7fe
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/non-latin1.json.ref
@@ -0,0 +1,4 @@
+{
+ "name": "\u0ba4\u0bb9\u0bc6\u0bb0\u0bbe"
+}
+
diff --git a/src/3rdparty/qjson/tests/data/test.html b/src/3rdparty/qjson/tests/data/test.html
new file mode 100644
index 00000000..bb3b40c5
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test.html
@@ -0,0 +1,72 @@
+<html>
+<script>
+ JSON_STRING = '[\
+ "JSON Test Pattern pass1",\
+ {"object with 1 member":["array with 1 element"]},\
+ {},\
+ [],\
+ -42,\
+ true,\
+ false,\
+ null,\
+ {\
+ "integer": 1234567890,\
+ "real": -9876.543210,\
+ "e": 0.123456789e-12,\
+ "E": 1.234567890E+34,\
+ "": 23456789012E66,\
+ "zero": 0,\
+ "one": 1,\
+ "space": " ",\
+ "quote": "\\"",\
+ "backslash": "\\\\",\
+ "controls": "\\b\\f\\n\\r\\t",\
+ "slash": "/ & \\/",\
+ "alpha": "abcdefghijklmnopqrstuvwxyz",\
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",\
+ "digit": "0123456789",\
+ "0123456789": "digit",\
+ "special": "`1~!@#$%^&*()_+-={\':[,]}|;.</>?",\
+ "hex": "\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A",\
+ "true": true,\
+ "false": false,\
+ "null": null,\
+ "array":[ ],\
+ "object":{ },\
+ "address": "50 St. James Street",\
+ "url": "http://www.JSON.org/",\
+ "comment": "// /* <!-- --",\
+ "# -- --> */": " ",\
+ " s p a c e d " :[1,2 , 3\
+\
+,\
+\
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],\
+ "jsontext": "{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}",\
+ "quotes": "&#34; \\u0022 %22 0x22 034 &#x22;",\
+ "\\/\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?" : "A key can be any string"\
+ },\
+ 0.5 ,98.6\
+,\
+99.44\
+,\
+\
+1066,\
+1e1,\
+0.1e1,\
+1e-1,\
+1e00,\
+2e+00,\
+2e-00,\
+"rosebud"]';
+
+ function testJson() {
+ var obj = JSON.parse(JSON_STRING);
+ document.write(JSON.stringify(obj))
+ }
+</script>
+
+<body onload="testJson()">
+ Hello
+</body>
+</html> \ No newline at end of file
diff --git a/src/3rdparty/qjson/tests/data/test.json b/src/3rdparty/qjson/tests/data/test.json
new file mode 100644
index 00000000..c5b8e211
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test.json
@@ -0,0 +1,60 @@
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E66,
+ "zero": 0,
+ "one": 1,
+ "space": " ",
+ "quote": "\"",
+ "backslash": "\\",
+ "controls": "\b\f\n\r\t",
+ "slash": "/ & \/",
+ "alpha": "abcdefghijklmnopqrstuvwxyz",
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "digit": "0123456789",
+ "0123456789": "digit",
+ "special": "`1~!@#$%^&*()_+-={\':[,]}|;.</>?",
+ "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "address": "50 St. James Street",
+ "url": "http://www.JSON.org/",
+ "comment": "// /* <!-- --",
+ "# -- --> */": " ",
+ " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?" : "A key can be any string"
+ },
+ 0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,
+2e+00,
+2e-00,
+"rosebud"]
+
diff --git a/src/3rdparty/qjson/tests/data/test.json.ref b/src/3rdparty/qjson/tests/data/test.json.ref
new file mode 100644
index 00000000..b4206236
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test.json.ref
@@ -0,0 +1,57 @@
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "": 2.3456789012e+76,
+ " s p a c e d " :[1,2 , 3,4 , 5, 6 ,7],
+ "# -- --> *\/": " ",
+ "\/\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?" : "A key can be any string",
+ "0123456789": "digit",
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "E": 1.23456789e+34,
+ "address": "50 St. James Street",
+ "alpha": "abcdefghijklmnopqrstuvwxyz",
+ "array":[ ],
+ "backslash": "\\",
+ "comment": "\/\/ \/* <!-- --",
+ "compact":[1,2,3,4,5,6,7],
+ "controls": "\b\f\n\r\t",
+ "digit": "0123456789",
+ "e": 1.23456789e-13,
+ "false": false,
+ "hex": "\u0123\u4567\u89ab\ucdef\uabcd\uef4a",
+ "integer": 1234567890,
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "null": null,
+ "object":{ },
+ "one": 1,
+ "quote": "\"",
+ "quotes": "&#34; \" %22 0x22 034 &#x22;",
+ "real": -9876.54321,
+ "slash": "\/ & \/",
+ "space": " ",
+ "special": "`1~!@#$%^&*()_+-={':[,]}|;.<\/>?",
+ "true": true,
+ "url": "http:\/\/www.JSON.org\/",
+ "zero": 0
+ },
+ 0.5 ,98.6
+,
+99.44
+,
+
+1066,
+10,
+1,
+0.1,
+1,
+2,
+2,
+"rosebud"]
+
diff --git a/src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json b/src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json
new file mode 100644
index 00000000..aed8eb32
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json
Binary files differ
diff --git a/src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json.ref b/src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json.ref
new file mode 100644
index 00000000..8b9d9b91
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test_utf-16le-nobom.json.ref
Binary files differ
diff --git a/src/3rdparty/qjson/tests/data/test_utf-16le.json b/src/3rdparty/qjson/tests/data/test_utf-16le.json
new file mode 100644
index 00000000..277dc529
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test_utf-16le.json
Binary files differ
diff --git a/src/3rdparty/qjson/tests/data/test_utf-16le.json.ref b/src/3rdparty/qjson/tests/data/test_utf-16le.json.ref
new file mode 100644
index 00000000..8b9d9b91
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test_utf-16le.json.ref
Binary files differ
diff --git a/src/3rdparty/qjson/tests/data/test_utf-32le.json b/src/3rdparty/qjson/tests/data/test_utf-32le.json
new file mode 100644
index 00000000..7345dafb
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test_utf-32le.json
Binary files differ
diff --git a/src/3rdparty/qjson/tests/data/test_utf-32le.json.ref b/src/3rdparty/qjson/tests/data/test_utf-32le.json.ref
new file mode 100644
index 00000000..2624ef36
--- /dev/null
+++ b/src/3rdparty/qjson/tests/data/test_utf-32le.json.ref
Binary files differ
diff --git a/src/3rdparty/qjson/tests/tests.pro b/src/3rdparty/qjson/tests/tests.pro
new file mode 100644
index 00000000..1f0de7ae
--- /dev/null
+++ b/src/3rdparty/qjson/tests/tests.pro
@@ -0,0 +1,13 @@
+QT += testlib
+
+include(../src/json.pri)
+SOURCES += tst_json.cpp
+
+TARGET = tst_json
+
+wince {
+ DEFINES += SRCDIR=\\\"\\\"
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD/\\\"
+}
+
diff --git a/src/3rdparty/qjson/tests/tst_json.cpp b/src/3rdparty/qjson/tests/tst_json.cpp
new file mode 100644
index 00000000..1dceea73
--- /dev/null
+++ b/src/3rdparty/qjson/tests/tst_json.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 Girish Ramakrishnan <girish@forwardbias.in>
+**
+** Use, modification and distribution is allowed without limitation,
+** warranty, liability or support of any kind.
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include "json.h"
+
+class tst_Json : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void parseAndStringify_data();
+ void parseAndStringify();
+
+ void stringify_data();
+ void stringify();
+
+ void parseError_data();
+ void parseError();
+};
+
+static QByteArray unformat(const QByteArray &input)
+{
+ QByteArray output;
+ bool inQuote = false, escape = false;
+ for (int i = 0; i < input.count(); i++) {
+ char c = input[i];
+ if (escape) {
+ escape = false;
+ } else if (c == '\\') {
+ escape = true;
+ } else {
+ if (c == '\"')
+ inQuote = !inQuote;
+ if (!inQuote && (c == ' ' || c == '\r' || c == '\n' || c == '\t'))
+ continue;
+ }
+ output += c;
+ }
+ return output;
+}
+
+void tst_Json::parseAndStringify_data()
+{
+ QTest::addColumn<QByteArray>("json");
+ QTest::addColumn<QByteArray>("reference"); // always UTF-8
+ QDir dir;
+ dir.cd(QLatin1String(SRCDIR "data/"));
+ foreach(QString filename , dir.entryList(QStringList() << QLatin1String("*.json"))) {
+ QFile jsonFile(dir.filePath(filename));
+ jsonFile.open(QFile::ReadOnly);
+ QByteArray json = jsonFile.readAll();
+ QFile refFile(dir.filePath(filename + QLatin1String(".ref")));
+ QByteArray reference;
+ if (refFile.open(QFile::ReadOnly)) {
+ reference = refFile.readAll();
+ } else {
+ reference = json;
+ }
+ if (filename.contains(QLatin1String("utf-16"))) {
+ reference = QTextCodec::codecForName("UTF-16LE")->toUnicode(reference).toUtf8();
+ } else if (filename.contains(QLatin1String("utf-32"))) {
+ reference = QTextCodec::codecForName("UTF-32LE")->toUnicode(reference).toUtf8();
+ }
+ reference = unformat(reference);
+ QTest::newRow(dir.filePath(filename).toLatin1().data()) << json << reference;
+ }
+}
+
+void tst_Json::parseAndStringify()
+{
+ QFETCH(QByteArray, json);
+ QFETCH(QByteArray, reference);
+
+ JsonReader reader;
+ QVERIFY2(reader.parse(json), reader.errorString().toLocal8Bit().constData());
+ QVariant result = reader.result();
+
+ JsonWriter writer;
+ QByteArray jsonAgain = writer.toByteArray(result);
+ QVERIFY(jsonAgain == reference);
+
+ // test pretty writing
+ writer.setAutoFormatting(true);
+ jsonAgain = writer.toByteArray(result);
+ QVERIFY(unformat(jsonAgain) == reference);
+}
+
+struct CustomType {
+ int x;
+};
+Q_DECLARE_METATYPE(CustomType)
+
+void tst_Json::stringify_data()
+{
+ QTest::addColumn<QVariant>("input");
+ QTest::addColumn<QString>("output");
+
+ QTest::newRow("null_variant") << QVariant() << "null";
+
+ // bool
+ QTest::newRow("true") << QVariant(true) << "true";
+ QTest::newRow("false") << QVariant(false) << "false";
+
+ // lists
+ QTest::newRow("empty list") << QVariant(QVariantList()) << "[]";
+
+ // objects
+ QTest::newRow("empty object") << QVariant(QVariantMap()) << "{}";
+
+ // numbers
+ QTest::newRow("number") << QVariant(42) << "42";
+ QTest::newRow("nan") << QVariant(double(NAN)) << "null";
+ QTest::newRow("inf") << QVariant(double(INFINITY)) << "null";
+ QTest::newRow("-inf") << QVariant(double(-INFINITY)) << "null";
+
+ // unicode
+ QTest::newRow("non-ascii/latin1") << QVariant(QChar(0xFB)) << "\"\\u00fb\"";
+
+ const char utf8[] = {0xE0, 0xAE, 0x9F, 0xE0, 0xAE, 0xBF, 0x00 };
+ QTest::newRow("tamil tee") << QVariant(QString::fromUtf8(utf8)) << "\"\\u0b9f\\u0bbf\"";
+
+ // various QVariant types
+ QVariantList vlist;
+ vlist = QVariantList() << QVariant(float(1)) << QVariant(qlonglong(13))
+ << QVariant(qulonglong(14)) << QVariant(quint32(15))
+ << QVariant(char('x')) << QVariant(QChar(QLatin1Char('X')));
+ QTest::newRow("various types") << QVariant(vlist) << "[1,13,14,15,120,\"X\"]";
+
+ // custom types
+ // It is out of the scope of the standard to specify what happens when
+ // a custom type that cannot be stringized is present. We generate a null
+ // for unsupported types
+ CustomType c;
+ QTest::newRow("unpresentable object") << qVariantFromValue(c) << "null";
+
+ vlist = QVariantList() << 1 << qVariantFromValue(c) << 2;
+ QTest::newRow("unpresentable object[]") << QVariant(vlist) << "[1,null,2]";
+
+ QVariantMap map;
+ map[QLatin1String("one")] = 1;
+ map[QLatin1String("two")] = 2;
+ map[QLatin1String("custom")] = qVariantFromValue(c);
+ QTest::newRow("unpresentable object{}") << QVariant(map) << "{\"custom\":null,\"one\":1,\"two\":2}";
+}
+
+void tst_Json::stringify()
+{
+ QFETCH(QVariant, input);
+ QFETCH(QString, output);
+
+ JsonWriter writer;
+ QCOMPARE(writer.toString(input), output);
+
+ // just check if it parses, just in case
+ JsonReader reader;
+ QVERIFY(reader.parse(writer.toString(input)));
+}
+
+void tst_Json::parseError_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<int>("line");
+ QTest::addColumn<int>("pos");
+ QTest::addColumn<QString>("expect");
+
+ // Most of the time the error message itself is not useful. These tests exist
+ // primarily to make sure that parsing fails
+ QTest::newRow("error 1") << "!" << 1 << 0 << "";
+ QTest::newRow("error 2") << "[1,2," << 1 << 5 << "";
+ QTest::newRow("error 3") << "[1,2" << 1 << 4 << "Expected ']', ','";
+ QTest::newRow("error 4") << "[1,2p" << 1 << 5 << "Expected ']', ','";
+ QTest::newRow("error 5") << "[1,2] {" << 1 << 7 << "Expected 'end of file'";
+ QTest::newRow("error 6") << "{ foo: bar }" << 1 << 5 << "Expected '}', ','";
+ QTest::newRow("error 7") << "\n\n{ \"cat\" : \"pillar\"" << 3 << 20 << "Expected '}', ','";
+ QTest::newRow("success") << "true" << -1 << -1 << "";
+}
+
+void tst_Json::parseError()
+{
+ QFETCH(QString, input);
+ QFETCH(int, line);
+ QFETCH(int, pos);
+ QFETCH(QString, expect);
+
+ JsonReader reader;
+ QVERIFY(!reader.parse(input) || line == -1);
+
+ if (line != -1)
+ QCOMPARE(reader.errorString(), QString::fromUtf8("%1 at line %2 pos %3").arg(expect).arg(line).arg(pos));
+}
+
+QTEST_MAIN(tst_Json)
+
+#include "tst_json.moc"
+
diff --git a/src/client/client.pro b/src/client/client.pro
new file mode 100644
index 00000000..1e9da2a1
--- /dev/null
+++ b/src/client/client.pro
@@ -0,0 +1,32 @@
+TEMPLATE = lib
+TARGET = $$QT.jsondb.name
+MODULE = jsondb
+
+load(qt_module)
+load(qt_module_config)
+
+DESTDIR = $$QT.jsondb.libs
+VERSION = $$QT.jsondb.VERSION
+DEFINES += QT_ADDON_JSONDB_LIB
+
+QT = core network jsondbqson-private
+
+CONFIG += module create_prl
+MODULE_PRI = ../../modules/qt_jsondb.pri
+
+include(../common/common.pri)
+
+HEADERS += qtaddonjsondbversion.h
+
+HEADERS += \
+ jsondb-client.h \
+ jsondb-client_p.h \
+ jsondb-connection_p.h \
+ jsondb-oneshot_p.h
+
+SOURCES += \
+ jsondb-client.cpp \
+ jsondb-connection.cpp \
+ jsondb-oneshot.cpp
+
+mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$QT.jsondb.name
diff --git a/src/client/jsondb-client.cpp b/src/client/jsondb-client.cpp
new file mode 100644
index 00000000..0ee098df
--- /dev/null
+++ b/src/client/jsondb-client.cpp
@@ -0,0 +1,623 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-client.h"
+#include "jsondb-client_p.h"
+#include "jsondb-strings.h"
+
+#include "jsondb-connection_p.h"
+
+/*!
+ \namespace QtAddOn
+ \inmodule QtJsonDb
+ \target Qt Namespace
+*/
+
+/*!
+ \namespace QtAddOn::JsonDb
+ \inmodule QtJsonDb
+ \target QtAddOn::JsonDb Namespace
+
+ \brief The QtAddOn::JsonDb namespace contains the C++ client for JsonDb.
+
+ To use namespace QtAddOn::JsonDb from C++, use macro Q_USE_JSONDB_NAMESPACE.
+
+ \code
+ #include <jsondb-client.h>
+ Q_USE_JSONDB_NAMESPACE
+ \endcode
+
+To declare the class without including the declaration of the class:
+ \code
+ #include <jsondb-global.h>
+ Q_ADDON_JSONDB_BEGIN_NAMESPACE
+ class JsonDbClient;
+ Q_ADDON_JSONDB_END_NAMESPACE
+ Q_USE_JSONDB_NAMESPACE
+ \endcode
+
+*/
+
+/*!
+ \macro Q_USE_JSONDB_NAMESPACE
+ \inmodule QtJsonDb
+ \brief Makes namespace QtAddOn::JsonDb visible to C++ source code.
+*/
+
+namespace QtAddOn { namespace JsonDb {
+
+/*!
+ \class QtAddOn::JsonDb::JsonDbClient
+
+ \brief The JsonDbClient class provides a client interface which connects to the JsonDb server.
+*/
+
+/*!
+ \fn QtAddOn::JsonDb::JsonDbClient::JsonDbClient(JsonDbConnection *connection, QObject *parent)
+
+ \brief The JsonDbClient class provides a client interface which connects to the JsonDb server.
+
+ Uses JsonDbConnection \a connection to connect.
+
+*/
+JsonDbClient::JsonDbClient(JsonDbConnection *connection, QObject *parent)
+ : QObject(parent), d_ptr(new JsonDbClientPrivate(this, connection))
+{
+ Q_D(JsonDbClient);
+ d->init();
+}
+
+/*!
+ \fn QtAddOn::JsonDb::JsonDbClient::JsonDbClient(const QString &socketName, QObject *parent)
+
+ \brief The JsonDbClient class provides a client interface which connects to the JsonDb server.
+
+ Creates a new JsonDbConnection and connects to the socket named \a socketName.
+
+ \sa QtAddOn::JsonDb::JsonDbConnection
+*/
+JsonDbClient::JsonDbClient(const QString &socketName, QObject *parent)
+ : QObject(parent)
+{
+ JsonDbConnection *connection = new JsonDbConnection(this);
+ connection->connectToServer(socketName);
+ d_ptr.reset(new JsonDbClientPrivate(this, connection));
+ Q_D(JsonDbClient);
+ d->init();
+}
+
+/*!
+ \fn QtAddOn::JsonDb::JsonDbClient::JsonDbClient(QObject *parent)
+
+ \brief The JsonDbClient class provides a client interface which connects to the JsonDb server.
+
+ Uses the singleton object returned by \c
+ JsonDbConnection::instance() as for the database connection.
+
+ \sa JsonDbConnection::instance()
+*/
+JsonDbClient::JsonDbClient(QObject *parent)
+ : QObject(parent), d_ptr(new JsonDbClientPrivate(this, JsonDbConnection::instance()))
+{
+ Q_D(JsonDbClient);
+ d->init();
+}
+
+JsonDbClient::~JsonDbClient()
+{
+}
+
+/*!
+ \fn bool QtAddOn::JsonDb::JsonDbClient::isConnected() const
+
+ Returns true if the client is connected to the database.
+*/
+bool JsonDbClient::isConnected() const
+{
+ Q_D(const JsonDbClient);
+ Q_ASSERT(d->connection);
+ return d->connection->isConnected();
+}
+
+/*!
+ \class JsonDbClientPrivate
+ \internal
+*/
+JsonDbClientPrivate::JsonDbClientPrivate(JsonDbClient *q, JsonDbConnection *c)
+ :q_ptr(q), connection(c)
+{
+ Q_ASSERT(connection);
+}
+
+JsonDbClientPrivate::~JsonDbClientPrivate()
+{
+}
+
+void JsonDbClientPrivate::init(Qt::ConnectionType type)
+{
+ Q_Q(JsonDbClient);
+ q->connect(connection, SIGNAL(notified(QString,QsonObject,QString)),
+ SLOT(_q_handleNotified(QString,QsonObject,QString)),type);
+ q->connect(connection, SIGNAL(notified(QString,QsonObject,QString)),
+ SIGNAL(notified(QString,QsonObject,QString)),type);
+ q->connect(connection, SIGNAL(notified(QString,QVariant,QString)),
+ SIGNAL(notified(QString,QVariant,QString)),type);
+ q->connect(connection, SIGNAL(response(int,QsonObject)),
+ SLOT(_q_handleResponse(int,QsonObject)),type);
+ q->connect(connection, SIGNAL(error(int,int,QString)),
+ SLOT(_q_handleError(int,int,QString)),type);
+ q->connect(connection, SIGNAL(disconnected()), SIGNAL(disconnected()));
+ q->connect(connection, SIGNAL(readyWrite()), SIGNAL(readyWrite()));
+}
+
+void JsonDbClientPrivate::_q_handleNotified(const QString &notifyUuid, const QsonObject &data, const QString &action)
+{
+ NotifyCallback c = notifyCallbacks.value(notifyUuid);
+ c.method.invoke(c.object.data(), Q_ARG(QString, notifyUuid), Q_ARG(QsonObject, data), Q_ARG(QString, action));
+}
+
+void JsonDbClientPrivate::_q_handleResponse(int id, const QsonObject &data)
+{
+ Q_Q(JsonDbClient);
+ QHash<int, NotifyCallback>::iterator it = unprocessedNotifyCallbacks.find(id);
+ if (it != unprocessedNotifyCallbacks.end()) {
+ NotifyCallback c = it.value();
+ unprocessedNotifyCallbacks.erase(it);
+ QString notifyUuid = data.toMap().valueString(JsonDbString::kUuidStr);
+ notifyCallbacks.insert(notifyUuid, c);
+ }
+ QHash<int, Callback>::iterator idsit = ids.find(id);
+ if (idsit == ids.end())
+ return;
+ Callback c = idsit.value();
+ ids.erase(idsit);
+ if (QObject *object = c.object.data()) {
+ const QMetaObject *mo = object->metaObject();
+ int idx = mo->indexOfMethod(c.successSlot+1);
+ if (idx < 0) {
+ QByteArray norm = QMetaObject::normalizedSignature(c.successSlot);
+ idx = mo->indexOfMethod(norm.constData()+1);
+ }
+ if (idx >= 0)
+ mo->method(idx).invoke(object, Q_ARG(int, id), Q_ARG(QsonObject, data));
+ }
+ emit q->response(id, qsonToVariant(data));
+ emit q->response(id, data);
+}
+
+void JsonDbClientPrivate::_q_handleError(int id, int code, const QString &message)
+{
+ Q_Q(JsonDbClient);
+ unprocessedNotifyCallbacks.remove(id);
+ QHash<int, Callback>::iterator it = ids.find(id);
+ if (it == ids.end())
+ return;
+ Callback c = it.value();
+ ids.erase(it);
+ if (QObject *object = c.object.data()) {
+ const QMetaObject *mo = object->metaObject();
+ int idx = mo->indexOfMethod(c.errorSlot+1);
+ if (idx < 0) {
+ QByteArray norm = QMetaObject::normalizedSignature(c.errorSlot);
+ idx = mo->indexOfMethod(norm.constData()+1);
+ }
+ if (idx >= 0)
+ mo->method(idx).invoke(object, Q_ARG(int, id), Q_ARG(int, code), Q_ARG(QString, message));
+ }
+ emit q->error(id, (JsonDbError::ErrorCode)code, message);
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::find(const QVariant &object)
+ \deprecated
+
+ Sends \a queryObject to the database. Returns the reference id of the query.
+
+ The \a queryObject contains \c query: a query string and my
+ optionally contain \c bindings, \c limit and \c offset values. If
+ provided, \c bindings maps names in the query string to values
+ used in the query.
+
+ A successful response will include the following properties:
+
+ \list
+ \o \c data: a list of objects matching the query
+ \o \c length: the number of returned objects
+ \o \c offset: the offset of the returned objects in the list of all objects matching the query.
+ \endlist
+
+ \sa response(), error()
+*/
+int JsonDbClient::find(const QVariant &object)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeFindRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback());
+ return id;
+}
+
+int JsonDbClient::find(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeFindRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+int JsonDbClient::query(const QString &queryString, int offset, int limit,
+ QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeQueryRequest(queryString, offset, limit));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::create(const QVariant object)
+ \deprecated
+
+ Sends a request to insert \a object into the database. Returns the reference id of the query.
+
+ The \a queryObject contains \c query: a query string and my
+ optionally contain \c bindings, \c limit and \c offset values. If
+ provided, \c bindings maps names in the query string to values
+ used in the query.
+
+ A successful response will include the following properties:
+
+ \list
+ \o \c data: a list of objects matching the query
+ \o \c length: the number of returned objects
+ \o \c offset: the offset of the returned objects in the list of all objects matching the query.
+ \endlist
+
+ \sa response(), error()
+*/
+int JsonDbClient::create(const QVariant &object)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeCreateRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback());
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::create(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+ \inmodule QtJsonDb
+
+ \brief Sends a request to insert \a object into the database. Returns the reference id of the query.
+
+ Upon success, invokes \a successSlot of \a target, if provided, else emits \c response().
+ On error, invokes \a errorSlot of \a target, if provided, else emits \c error().
+
+ A successful response will include the following properties:
+
+ \list
+ \o \c _uuid: the unique id of the created object
+ \o \c _version: the version of the created object
+ \endlist
+
+ \sa response()
+ \sa error()
+*/
+int JsonDbClient::create(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeCreateRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::update(const QVariant &object)
+ \inmodule QtJsonDb
+ \deprecated
+*/
+int JsonDbClient::update(const QVariant &object)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeUpdateRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback());
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::update(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+ \inmodule QtJsonDb
+
+ \brief Sends a request to update \a object in the database. Returns the reference id of the query.
+
+ Upon success, invokes \a successSlot of \a target, if provided, else emits \c response().
+ On error, invokes \a errorSlot of \a target, if provided, else emits \c error().
+
+ A successful response will include the following properties:
+
+ \list
+ \o \c _uuid: the unique id of the updated object
+ \o \c _version: the version of the updated object
+ \endlist
+
+ \sa response()
+ \sa error()
+*/
+int JsonDbClient::update(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeUpdateRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::remove(const QVariant &object)
+ \inmodule QtJsonDb
+ \deprecated
+*/
+int JsonDbClient::remove(const QVariant &object)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeRemoveRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback());
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::remove(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+ \inmodule QtJsonDb
+
+ \brief Sends a request to remove \a object from the database. Returns the reference id of the query.
+
+ Upon success, invokes \a successSlot of \a target, if provided, else emits \c response().
+ On error, invokes \a errorSlot of \a target, if provided, else emits \c error().
+
+ A successful response will include the following properties:
+
+ \list
+ \o \c _uuid: the unique id of the removed object
+ \endlist
+
+ \sa response()
+ \sa error()
+*/
+int JsonDbClient::remove(const QsonObject &object, QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeRemoveRequest(object));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+/*!
+ \fn int QtAddOn::JsonDb::JsonDbClient::remove(const QString &queryString, QObject *target, const char *successSlot, const char *errorSlot)
+ \inmodule QtJsonDb
+
+ \brief Sends a request to remove from the database objects that match \a queryString. Returns the reference id of the query.
+
+ Upon success, invokes \a successSlot of \a target, if provided, else emits \c response().
+ On error, invokes \a errorSlot of \a target, if provided, else emits \c error().
+
+ A successful response will include the following properties:
+ \list
+ \o \c _uuid: the unique id of the removed object
+ \endlist
+
+ \sa response()
+ \sa error()
+*/
+int JsonDbClient::remove(const QString &queryString, QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeRemoveRequest(queryString));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+int JsonDbClient::notify(NotifyTypes types, const QString &query,
+ QObject *notifyTarget, const char *notifySlot,
+ QObject *responseTarget, const char *responseSuccessSlot, const char *responseErrorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ QVariantList actions;
+ if (types & JsonDbClient::NotifyCreate)
+ actions.append(JsonDbString::kCreateStr);
+ if (types & JsonDbClient::NotifyRemove)
+ actions.append(JsonDbString::kRemoveStr);
+ if (types & JsonDbClient::NotifyUpdate)
+ actions.append(JsonDbString::kUpdateStr);
+ QVariantMap create;
+ create.insert(JsonDbString::kTypeStr, JsonDbString::kNotificationTypeStr);
+ create.insert(JsonDbString::kQueryStr, query);
+ create.insert(JsonDbString::kActionsStr, actions);
+ int id = d->connection->request(JsonDbConnection::makeCreateRequest(create));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(responseTarget, responseSuccessSlot, responseErrorSlot));
+ if (notifyTarget && notifySlot) {
+ const QMetaObject *mo = notifyTarget->metaObject();
+ int idx = mo->indexOfMethod(notifySlot+1);
+ if (idx < 0) {
+ QByteArray norm = QMetaObject::normalizedSignature(notifySlot);
+ idx = mo->indexOfMethod(norm.constData()+1);
+ }
+ if (idx < 0) {
+ qWarning("JsonDbClient::notify: No such method %s::%s",
+ mo->className(), notifySlot);
+ } else {
+ d->unprocessedNotifyCallbacks.insert(id, JsonDbClientPrivate::NotifyCallback(notifyTarget, mo->method(idx)));
+ }
+ }
+ return id;
+}
+
+/*!
+ \fn int JsonDbClient::changesSince(int stateNumber, QStringList types, QObject *target, const char *successSlot, const char *errorSlot)
+ \inmodule QtJsonDb
+
+ \brief Sends a request to retrieve a description of changes since
+ database state \a stateNumber. Limits the change descriptions to
+ those for the types in \a types, if not empty. Returns the reference
+ id of the query.
+
+ Upon success, invokes \a successSlot of \a target, if provided, else emits \c response().
+ On error, invokes \a errorSlot of \a target, if provided, else emits \c error().
+
+ \sa response()
+ \sa error()
+*/
+int JsonDbClient::changesSince(int stateNumber, QStringList types,
+ QObject *target, const char *successSlot, const char *errorSlot)
+{
+ Q_D(JsonDbClient);
+ if (!d->connection)
+ return -1;
+ int id = d->connection->request(JsonDbConnection::makeChangesSinceRequest(stateNumber, types));
+ if (id == -1)
+ return -1;
+ d->ids.insert(id, JsonDbClientPrivate::Callback(target, successSlot, errorSlot));
+ return id;
+}
+
+/*!
+ \fn void QtAddOn::JsonDb::JsonDbClient::notified(const QString &notify_uuid, const QVariant &object, const QString &action)
+
+ Signal that a notification has been received. The notification
+ object must have been created previously, usually with the
+ \c create() function (an object with ``_type="notification"``). The
+ \a notify_uuid field is the uuid of the notification object. The
+ \a object field is the actual database object and the \a action
+ field is the action that started the notification (one of
+ "create", "update", or "remove").
+
+ \sa notify(), create()
+*/
+
+/*!
+ \fn void notified(const QString &notify_uuid, const QsonObject &object, const QString &action)
+
+ Signal that a notification has been received. The notification
+ object must have been created previously, usually with the
+ \c create() function (an object with ``_type="notification"``). The
+ \a notify_uuid field is the uuid of the notification object. The
+ \a object field is the actual database object and the \a action
+ field is the action that started the notification (one of
+ "create", "update", or "remove").
+
+ \sa notify(), create()
+*/
+
+/*!
+ \fn void QtAddOn::JsonDb::JsonDbClient::response(int id, const QVariant &object)
+
+ Signal that a response to a request has been received from the
+ database. The \a id parameter will match with the return result
+ of the request to the database. The \a object parameter depends
+ on the type of the original request.
+
+ \sa create(), update(), remove()
+*/
+
+/*!
+ \fn void QtAddOn::JsonDb::JsonDbClient::response(int id, const QsonObject &object)
+
+ Signal that a response to a request has been received from the
+ database. The \a id parameter will match with the return result
+ of the request to the database. The \a object parameter depends
+ on the type of the original request.
+
+ \sa create(), update(), remove()
+*/
+
+/*!
+ \fn void QtAddOn::JsonDb::JsonDbClient::error(int id, int code, const QString &message)
+
+ Signals an error in the database request. The \a id parameter
+ will match the return result of the original request to the
+ database. The \a code and \a message parameters indicate the error.
+
+ \sa create(), update(), remove(), JsonDbError::ErrorCode
+*/
+
+#include "moc_jsondb-client.cpp"
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/client/jsondb-client.h b/src/client/jsondb-client.h
new file mode 100644
index 00000000..c95cc42e
--- /dev/null
+++ b/src/client/jsondb-client.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_CLIENT_H
+#define JSONDB_CLIENT_H
+
+#include <QObject>
+#include <QVariant>
+#include <QList>
+#include <QStringList>
+#include <QScopedPointer>
+
+#include "jsondb-global.h"
+#include "jsondb-error.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+class QsonObject;
+
+class JsonDbConnection;
+class JsonDbClientPrivate;
+
+class Q_ADDON_JSONDB_EXPORT JsonDbClient : public QObject
+{
+ Q_OBJECT
+public:
+ JsonDbClient(JsonDbConnection *connection, QObject *parent = 0);
+ JsonDbClient(const QString &socketName, QObject *parent = 0);
+ JsonDbClient(QObject *parent = 0);
+ ~JsonDbClient();
+
+ bool isConnected() const;
+
+ enum NotifyType {
+ NotifyCreate = 0x01,
+ NotifyUpdate = 0x02,
+ NotifyRemove = 0x04
+ };
+ Q_DECLARE_FLAGS(NotifyTypes, NotifyType)
+
+public slots:
+ int find(const QsonObject &query, QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+ int query(const QString &query, int offset = 0, int limit = -1, QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+ int create(const QsonObject &object, QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+ int update(const QsonObject &object, QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+ int remove(const QsonObject &object, QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+ int remove(const QString &query, QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+ int notify(NotifyTypes types, const QString &query,
+ QObject *notifyTarget = 0, const char *notifySlot = 0,
+ QObject *responseTarget = 0, const char *responseSuccessSlot = 0, const char *responseErrorSlot = 0);
+ int changesSince(int stateNumber, QStringList types = QStringList(), QObject *target = 0, const char *successSlot = 0, const char *errorSlot = 0);
+
+ // obsolete
+ int find(const QVariant &query);
+ int create(const QVariant &object);
+ int update(const QVariant &object);
+ int remove(const QVariant &object);
+
+signals:
+ void notified(const QString &notify_uuid, const QVariant &object, const QString &action);
+ void notified(const QString &notify_uuid, const QsonObject &object, const QString &action);
+ void response(int id, const QVariant &object);
+ void response(int id, const QsonObject &object);
+ void error(int id, int code, const QString &message);
+ void disconnected();
+ void readyWrite();
+
+private:
+ Q_DISABLE_COPY(JsonDbClient)
+ Q_DECLARE_PRIVATE(JsonDbClient)
+ QScopedPointer<JsonDbClientPrivate> d_ptr;
+ Q_PRIVATE_SLOT(d_func(), void _q_handleResponse(int, const QsonObject&))
+ Q_PRIVATE_SLOT(d_func(), void _q_handleError(int, int, const QString&))
+ Q_PRIVATE_SLOT(d_func(), void _q_handleNotified(const QString &notifyUuid, const QsonObject &data, const QString &action))
+};
+} } // end namespace QtAddOn::JsonDb
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QtAddOn::JsonDb::JsonDbClient::NotifyTypes)
+
+#endif // JSONDB_CLIENT_H
diff --git a/src/client/jsondb-client_p.h b/src/client/jsondb-client_p.h
new file mode 100644
index 00000000..95a05eb7
--- /dev/null
+++ b/src/client/jsondb-client_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDBCLIENT_P_H
+#define JSONDBCLIENT_P_H
+
+#include "jsondb-global.h"
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include <QMetaMethod>
+#include <QWeakPointer>
+
+namespace QtAddOn { namespace JsonDb {
+
+/*!
+ \class JsonDbClientPrivate
+ \internal
+*/
+class JsonDbClientPrivate
+{
+ Q_DECLARE_PUBLIC(JsonDbClient)
+public:
+ JsonDbClientPrivate(JsonDbClient *q, JsonDbConnection *c);
+ ~JsonDbClientPrivate();
+ void init(Qt::ConnectionType type=Qt::AutoConnection);
+
+ void _q_handleNotified(const QString &, const QsonObject &, const QString &);
+ void _q_handleResponse(int id, const QsonObject &data);
+ void _q_handleError(int id, int code, const QString &message);
+
+ JsonDbClient *q_ptr;
+ JsonDbConnection *connection;
+
+ struct Callback
+ {
+ QWeakPointer<QObject> object;
+ const char *successSlot;
+ const char *errorSlot;
+
+ inline Callback(QObject *obj = 0, const char *success = 0, const char *error = 0)
+ : object(obj), successSlot(success), errorSlot(error) { }
+ };
+ QHash<int, Callback> ids;
+
+ struct NotifyCallback
+ {
+ QWeakPointer<QObject> object;
+ QMetaMethod method;
+ NotifyCallback(QObject *obj = 0, QMetaMethod m = QMetaMethod())
+ : object(obj), method(m) { }
+ };
+
+ QHash<int, NotifyCallback> unprocessedNotifyCallbacks;
+ QHash<QString, NotifyCallback> notifyCallbacks;
+
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // JSONDBCLIENT_P_H
diff --git a/src/client/jsondb-connection.cpp b/src/client/jsondb-connection.cpp
new file mode 100644
index 00000000..267afa3c
--- /dev/null
+++ b/src/client/jsondb-connection.cpp
@@ -0,0 +1,621 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+#include "jsondb-oneshot_p.h"
+#include "jsondb-connection_p.h"
+#include "qsonstream.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+static JsonDbConnection* sJsonDbConnection;
+static QString sDefaultToken;
+
+class JsonDbConnectionPrivate
+{
+ Q_DECLARE_PUBLIC(JsonDbConnection)
+public:
+ JsonDbConnectionPrivate(JsonDbConnection *q);
+ ~JsonDbConnectionPrivate();
+
+ JsonDbConnection *q_ptr;
+ QsonStream mStream;
+ int mId;
+ QString mToken;
+};
+
+JsonDbConnectionPrivate::JsonDbConnectionPrivate(JsonDbConnection *q)
+ : q_ptr(q), mId(1)
+{
+}
+
+JsonDbConnectionPrivate::~JsonDbConnectionPrivate()
+{
+
+}
+
+/*!
+ \class QtAddOn::JsonDb::JsonDbConnection
+
+ \brief The JsonDbConnection class provides a connection to the
+ database server. Generally used via \c class
+ QtAddOn::JsonDb::JsonDbClient.
+
+ \sa QtAddOn::JsonDb::JsonDbClient
+*/
+
+/*!
+ \fn JsonDbConnection *QtAddOn::JsonDb::JsonDbConnection::instance()
+ Returns a singleton instance of \c JsonDbConnection.
+*/
+JsonDbConnection *JsonDbConnection::instance()
+{
+ if (!sJsonDbConnection) {
+ sJsonDbConnection = new JsonDbConnection;
+ sJsonDbConnection->connectToServer();
+ }
+ return sJsonDbConnection;
+}
+
+/*!
+ \fn void JsonDbConnection::setDefaultToken( const QString& token )
+ Sets the default security token to \a token.
+*/
+void JsonDbConnection::setDefaultToken( const QString& token )
+{
+ sDefaultToken = token;
+}
+
+/*!
+ \fn QString JsonDbConnection::defaultToken()
+ Returns the default security for the connection.
+*/
+QString JsonDbConnection::defaultToken()
+{
+ return sDefaultToken;
+}
+
+/*!
+ \fn bool JsonDbConnection::waitForConnected(int msecs)
+ Waits up to \a msecs milliseconds for the connection to the database to be completed.
+ Returns true if connected.
+*/
+bool JsonDbConnection::waitForConnected(int msecs)
+{
+ Q_D(JsonDbConnection);
+ QIODevice *device = d->mStream.device();
+ if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
+ return socket->waitForConnected(msecs);
+ else if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
+ return socket->waitForConnected(msecs);
+ return false;
+}
+
+/*!
+ \fn bool JsonDbConnection::waitForDisconnected(int msecs)
+ Waits up to \a msecs milliseconds for the connection to the database to be closed.
+ Returns true if disconnected.
+*/
+bool JsonDbConnection::waitForDisconnected(int msecs)
+{
+ Q_D(JsonDbConnection);
+ QIODevice *device = d->mStream.device();
+ if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
+ return socket->waitForDisconnected(msecs);
+ else if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
+ return socket->waitForDisconnected(msecs);
+ return false;
+}
+
+bool JsonDbConnection::waitForBytesWritten(int msecs)
+{
+ Q_D(JsonDbConnection);
+ QIODevice *device = d->mStream.device();
+ if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
+ return socket->waitForBytesWritten(msecs);
+ else if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
+ return socket->waitForBytesWritten(msecs);
+ return false;
+}
+
+QVariantMap JsonDbConnection::makeFindRequest( const QVariant& object )
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kFindStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QsonObject JsonDbConnection::makeFindRequest( const QsonObject& object )
+{
+ QsonMap request;
+
+ request.insert(JsonDbString::kActionStr, JsonDbString::kFindStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QVariantMap JsonDbConnection::makeQueryRequest( const QString& queryString, int offset, int limit )
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kFindStr);
+ QVariantMap object;
+ object.insert(JsonDbString::kQueryStr, queryString);
+ if (offset != 0)
+ object.insert(JsonDbString::kOffsetStr, offset);
+ if (limit != -1)
+ object.insert(JsonDbString::kLimitStr, limit);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QVariantMap JsonDbConnection::makeCreateRequest( const QVariant& object )
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kCreateStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QsonObject JsonDbConnection::makeCreateRequest( const QsonObject& object )
+{
+ QsonMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kCreateStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QVariantMap JsonDbConnection::makeUpdateRequest( const QVariant& object )
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kUpdateStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QsonObject JsonDbConnection::makeUpdateRequest( const QsonObject& object )
+{
+ QsonMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kUpdateStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QVariantMap JsonDbConnection::makeRemoveRequest( const QVariant& object )
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kRemoveStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QsonObject JsonDbConnection::makeRemoveRequest( const QsonObject& object )
+{
+ QsonMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kRemoveStr);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QVariantMap JsonDbConnection::makeRemoveRequest( const QString &queryString)
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kRemoveStr);
+ QVariantMap object;
+ object.insert(JsonDbString::kQueryStr, queryString);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+QVariantMap JsonDbConnection::makeNotification( const QString& query,
+ const QVariantList& actions )
+{
+ QVariantMap notification;
+ notification.insert(JsonDbString::kTypeStr,
+ JsonDbString::kNotificationTypeStr);
+ notification.insert(JsonDbString::kQueryStr, query);
+ notification.insert(JsonDbString::kActionsStr, actions);
+ return notification;
+}
+
+QsonObject JsonDbConnection::makeNotification( const QString& query,
+ const QsonObject& actions )
+{
+ QsonMap notification;
+ notification.insert(JsonDbString::kTypeStr,
+ JsonDbString::kNotificationTypeStr);
+ notification.insert(JsonDbString::kQueryStr, query);
+ notification.insert(JsonDbString::kActionsStr, actions);
+ return notification;
+}
+
+QVariantMap JsonDbConnection::makeChangesSinceRequest(int stateNumber, const QStringList &types)
+{
+ QVariantMap request;
+ request.insert(JsonDbString::kActionStr, JsonDbString::kChangesSinceStr);
+ QVariantMap object;
+ object.insert(JsonDbString::kStateNumberStr, stateNumber);
+ if (!types.isEmpty())
+ object.insert(JsonDbString::kTypesStr, types);
+ request.insert(JsonDbString::kObjectStr, object);
+ return request;
+}
+
+/***************************************************************************/
+
+/*!
+ \fn JsonDbConnection::JsonDbConnection(QObject *parent)
+ Constructs a \c JsonDbConnection.
+*/
+JsonDbConnection::JsonDbConnection(QObject *parent)
+ : QObject(parent), d_ptr(new JsonDbConnectionPrivate(this))
+{
+ Q_D(JsonDbConnection);
+ if (!sDefaultToken.isEmpty())
+ d->mToken = sDefaultToken;
+ else
+ d->mToken = QLatin1String(::getenv("JSONDB_TOKEN"));
+}
+
+JsonDbConnection::~JsonDbConnection()
+{
+ Q_D(JsonDbConnection);
+ // QsonStreams don't own the socket
+ QIODevice *device = d->mStream.device();
+ d->mStream.setDevice(0);
+ if (device)
+ delete device;
+}
+
+void JsonDbConnection::init(QIODevice *device)
+{
+ Q_D(JsonDbConnection);
+ d->mStream.setDevice(device);
+ connect(&d->mStream, SIGNAL(receive(QsonObject)),
+ this, SLOT(receiveMessage(QsonObject)));
+ connect(&d->mStream, SIGNAL(readyWrite()),
+ this, SIGNAL(readyWrite()));
+
+ if (!d->mToken.isEmpty()) {
+ QsonMap request;
+ request.insert(JsonDbString::kIdStr, d->mId++);
+ request.insert(JsonDbString::kActionStr, JsonDbString::kTokenStr);
+ request.insert(JsonDbString::kObjectStr, d->mToken);
+ d->mStream << request;
+ }
+}
+
+/*
+ * Connects to the named local socket.
+ */
+
+/*!
+ \fn void JsonDbConnection::connectToServer(const QString &socketName)
+ Connects to the named local socket \a socketName.
+ */
+void JsonDbConnection::connectToServer(const QString &socketName)
+{
+ Q_D(JsonDbConnection);
+ Q_ASSERT(d->mStream.device() == 0);
+ Q_UNUSED(d);
+
+ QString name = socketName;
+ if (name.isEmpty())
+ name = QLatin1String(::getenv("JSONDB_SOCKET"));
+ if (name.isEmpty())
+ name = QLatin1String("qt5jsondb");
+
+ QLocalSocket *socket = new QLocalSocket(this);
+ connect(socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ socket->connectToServer(name);
+ if (socket->waitForConnected())
+ init(socket);
+ else
+ qCritical() << "JsonDbConnection: Unable to connect to socket" << name << socket->errorString();
+}
+
+/*
+ * Connects to the named remote host.
+ */
+
+/*!
+ \fn void JsonDbConnection::connectToServer(const QString &hostname, quint16 port)
+ Connects to the databsae via a TCP connection to \a hostname and \a port.
+ */
+void JsonDbConnection::connectToHost(const QString &hostname, quint16 port)
+{
+ Q_D(JsonDbConnection);
+ Q_ASSERT(d->mStream.device() == 0);
+ Q_UNUSED(d);
+
+ QTcpSocket *socket = new QTcpSocket(this);
+ connect(socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ socket->connectToHost(hostname, port);
+ if (socket->waitForConnected())
+ init(socket);
+ else
+ qCritical() << "JsonDbConnection: Unable to connect to remote server: "
+ << hostname << port << socket->errorString();
+}
+
+/*!
+ \fn int JsonDbConnection::request(const QVariantMap &dbrequest)
+ \deprecated
+
+ Sends request \a dbrequest to the database and returns the request identification number.
+*/
+int JsonDbConnection::request(const QVariantMap &dbrequest)
+{
+ if(!isConnected())
+ return -1;
+ Q_D(JsonDbConnection);
+ QVariantMap r = dbrequest;
+ int newid = d->mId + 1;
+ r.insert(JsonDbString::kIdStr, newid);
+ if (!d->mStream.send(variantToQson(r)))
+ return -1;
+ d->mId = newid;
+ return newid;
+}
+
+/*!
+ \fn int JsonDbConnection::request(const QsonObject &dbrequest)
+
+ Sends request \a dbrequest to the database and returns the request identification number.
+*/
+int JsonDbConnection::request(const QsonObject &dbrequest)
+{
+ if(!isConnected())
+ return -1;
+ Q_D(JsonDbConnection);
+ QsonMap r = dbrequest.toMap();
+ int newid = d->mId + 1;
+ r.insert(JsonDbString::kIdStr, newid);
+ if (!d->mStream.send(r))
+ return -1;
+ d->mId = newid;
+ return newid;
+}
+
+void JsonDbConnection::receiveMessage(const QsonObject &msg)
+{
+ QsonMap qsonMsg = msg.toMap();
+ if (qsonMsg.contains(JsonDbString::kNotifyStr)) {
+ QsonMap nmap = qsonMsg.subObject(JsonDbString::kNotifyStr).toMap();
+ emit notified(qsonMsg.valueString(JsonDbString::kUuidStr),
+ qsonToVariant(nmap.subObject(JsonDbString::kObjectStr)),
+ nmap.valueString(JsonDbString::kActionStr));
+ emit notified(qsonMsg.valueString(JsonDbString::kUuidStr),
+ nmap.subObject(JsonDbString::kObjectStr),
+ nmap.valueString(JsonDbString::kActionStr));
+ } else {
+ int id = qsonMsg.valueInt(JsonDbString::kIdStr);
+ QsonObject qsonResult = qsonMsg.subObject(JsonDbString::kResultStr);
+ QVariantMap result = qsonToVariant(qsonResult).toMap();
+ if (result.size()) {
+ emit response(id, qsonResult);
+ emit response(id, result);
+ } else {
+ QVariantMap emap = qsonToVariant(qsonMsg.subObject(JsonDbString::kErrorStr)).toMap();
+ emit error(id,
+ emap.value(JsonDbString::kCodeStr).toInt(),
+ emap.value(JsonDbString::kMessageStr).toString());
+ }
+ }
+}
+
+
+/*!
+ \fn void JsonDbConnection::oneShot(const QVariantMap &dbrequest, QObject *receiver, const char *responseSlot, const char *errorSlot)
+ \deprecated
+
+ \sa JsonDbClient
+*/
+void JsonDbConnection::oneShot(const QVariantMap &dbrequest, QObject *receiver,
+ const char *responseSlot, const char *errorSlot)
+{
+ JsonDbOneShot *oneShot = new JsonDbOneShot;
+ oneShot->setParent(this);
+
+ connect(this, SIGNAL(response(int,QVariant)),
+ oneShot, SLOT(handleResponse(int,QVariant)));
+ connect(this, SIGNAL(error(int,int,QString)),
+ oneShot, SLOT(handleError(int,int,QString)));
+
+ if (responseSlot && !connect(oneShot, SIGNAL(response(QVariant)), receiver, responseSlot))
+ qCritical() << Q_FUNC_INFO << "failed to connect to slot" << responseSlot;
+ if (errorSlot && !connect(oneShot, SIGNAL(error(int,QString)), receiver, errorSlot))
+ qCritical() << Q_FUNC_INFO << "failed to connect to slot" << errorSlot;
+
+ oneShot->mId = request(dbrequest);
+ if (!responseSlot && !errorSlot)
+ oneShot->deleteLater();
+}
+
+QVariant JsonDbConnection::sync(const QVariantMap &dbrequest)
+{
+ QVariant result;
+ QThread syncThread;
+ JsonDbSyncCall *call = new JsonDbSyncCall(&dbrequest, &result);
+
+ connect(&syncThread, SIGNAL(started()),
+ call, SLOT(createSyncRequest()));
+ connect(&syncThread, SIGNAL(finished()),
+ call, SLOT(deleteLater()));
+ call->moveToThread(&syncThread);
+ syncThread.start();
+ syncThread.wait();
+ return result;
+}
+
+/*!
+ \fn QsonObject JsonDbConnection::sync(const QsonMap &dbrequest)
+ Sends request \a dbrequest to the database, waits synchronously for it to complete, and returns the response.
+
+ This operation creates a new thread with a new connection to the
+ database and blocks the thread in which it is running. This should
+ only be used from agents and daemons. It should never be called from
+ a user interface thread.
+*/
+QsonObject JsonDbConnection::sync(const QsonMap &dbrequest)
+{
+ QsonObject result;
+ QThread syncThread;
+ JsonDbSyncCall *call = new JsonDbSyncCall(&dbrequest, &result);
+
+ connect(&syncThread, SIGNAL(started()),
+ call, SLOT(createSyncQsonRequest()));
+ connect(&syncThread, SIGNAL(finished()),
+ call, SLOT(deleteLater()));
+ call->moveToThread(&syncThread);
+ syncThread.start();
+ syncThread.wait();
+ return result;
+}
+
+/*!
+ \fn void JsonDbConnection::setToken(const QString &token)
+ Sets the security token for this connection.
+*/
+void JsonDbConnection::setToken(const QString &token)
+{
+ d_func()->mToken = token;
+}
+
+/*!
+ \fn bool JsonDbConnection::isConnected() const
+ Returns true if connected to the database.
+*/
+bool JsonDbConnection::isConnected() const
+{
+ Q_D(const JsonDbConnection);
+ QIODevice *device = d->mStream.device();
+ if (!device)
+ return false;
+ if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
+ return socket->state() == QLocalSocket::ConnectedState;
+ else if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
+ return socket->state() == QAbstractSocket::ConnectedState;
+
+ return false;
+}
+
+/*!
+ \fn void disconnected()
+ This signal is emitted when the connection to the database is lost.
+*/
+
+/*!
+ \class JsonDbSyncCall
+ \internal
+*/
+JsonDbSyncCall::JsonDbSyncCall(const QVariantMap &dbrequest, QVariant &result)
+ : mDbRequest(&dbrequest), mDbQsonRequest(0), mResult(&result), mQsonResult(0), mSyncJsonDbConnection(0)
+{
+}
+
+JsonDbSyncCall::JsonDbSyncCall(const QVariantMap *dbrequest, QVariant *result)
+ : mDbRequest(dbrequest), mDbQsonRequest(0), mResult(result), mQsonResult(0), mSyncJsonDbConnection(0)
+{
+}
+
+JsonDbSyncCall::JsonDbSyncCall(const QsonMap *dbrequest, QsonObject *result)
+ : mDbRequest(0), mDbQsonRequest(dbrequest), mResult(0), mQsonResult(result), mSyncJsonDbConnection(0)
+{
+}
+
+JsonDbSyncCall::~JsonDbSyncCall()
+{
+ if (mSyncJsonDbConnection)
+ delete mSyncJsonDbConnection;
+}
+
+void JsonDbSyncCall::createSyncRequest()
+{
+ mSyncJsonDbConnection = new JsonDbConnection;
+ mSyncJsonDbConnection->connectToServer();
+
+ connect(mSyncJsonDbConnection, SIGNAL(response(int,QVariant)),
+ this, SLOT(handleResponse(int,QVariant)));
+ connect(mSyncJsonDbConnection, SIGNAL(error(int,int,QString)),
+ this, SLOT(handleError(int,int,QString)));
+ mId = mSyncJsonDbConnection->request(*mDbRequest);
+}
+
+void JsonDbSyncCall::createSyncQsonRequest()
+{
+ mSyncJsonDbConnection = new JsonDbConnection;
+ mSyncJsonDbConnection->connectToServer();
+
+ connect(mSyncJsonDbConnection, SIGNAL(response(int,QsonObject)),
+ this, SLOT(handleResponse(int,QsonObject)));
+ connect(mSyncJsonDbConnection, SIGNAL(error(int,int,QString)),
+ this, SLOT(handleError(int,int,QString)));
+ mId = mSyncJsonDbConnection->request(*mDbQsonRequest);
+}
+
+
+void JsonDbSyncCall::handleResponse(int id, const QVariant& data)
+{
+ if (id == mId) {
+ *mResult = data;
+ QThread::currentThread()->quit();
+ }
+}
+
+void JsonDbSyncCall::handleResponse(int id, const QsonObject& data)
+{
+ if (id == mId) {
+ *mQsonResult = data;
+ QThread::currentThread()->quit();
+ }
+}
+
+void JsonDbSyncCall::handleError(int id, int code, const QString& message)
+{
+ if (id == mId) {
+ qCritical() << "Illegal result" << code << message;
+ QThread::currentThread()->quit();
+ }
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/client/jsondb-connection_p.h b/src/client/jsondb-connection_p.h
new file mode 100644
index 00000000..287adabb
--- /dev/null
+++ b/src/client/jsondb-connection_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_CONNECTION_H
+#define JSONDB_CONNECTION_H
+
+#include <QObject>
+#include <QVariant>
+#include <QSet>
+#include <QStringList>
+#include <QLocalSocket>
+#include <QTcpSocket>
+#include <QScopedPointer>
+
+#include "jsondb-global.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+class QsonObject;
+class QsonMap;
+
+class JsonDbConnectionPrivate;
+class Q_ADDON_JSONDB_EXPORT JsonDbConnection : public QObject
+{
+ Q_OBJECT
+public:
+ static JsonDbConnection *instance();
+ static void setDefaultToken( const QString& token );
+ static QString defaultToken();
+
+ static QVariantMap makeFindRequest( const QVariant& );
+ static QsonObject makeFindRequest( const QsonObject& );
+ static QVariantMap makeQueryRequest( const QString&, int offset = 0, int limit = -1);
+ static QVariantMap makeCreateRequest( const QVariant& );
+ static QsonObject makeCreateRequest( const QsonObject& );
+ static QVariantMap makeUpdateRequest( const QVariant& );
+ static QsonObject makeUpdateRequest( const QsonObject& );
+ static QVariantMap makeRemoveRequest( const QVariant& );
+ static QsonObject makeRemoveRequest( const QsonObject& );
+ static QVariantMap makeRemoveRequest( const QString& );
+ static QVariantMap makeNotification( const QString&, const QVariantList& );
+ static QsonObject makeNotification( const QString&, const QsonObject& );
+ static QVariantMap makeChangesSinceRequest(int stateNumber, const QStringList &types=QStringList());
+
+ JsonDbConnection(QObject *parent = 0);
+ ~JsonDbConnection();
+
+ // One-shot functions allow you to avoid constructing a JsonDbClient
+ QT_DEPRECATED
+ void oneShot( const QVariantMap& dbrequest, QObject *receiver=0,
+ const char *responseSlot=0, const char *errorSlot=0);
+ // Synchronized calls pause execution until successful
+ QsonObject sync(const QsonMap &dbrequest);
+ QVariant sync(const QVariantMap &dbrequest);
+
+ void setToken(const QString &token);
+ void connectToServer(const QString &socketName = QString());
+ void connectToHost(const QString &hostname, quint16 port);
+
+ // General purpose request
+ int request(const QVariantMap &request);
+ int request(const QsonObject &request);
+ bool isConnected() const;
+ Q_DECL_DEPRECATED inline bool connected() const
+ { return isConnected(); }
+
+ bool waitForConnected(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+ bool waitForBytesWritten(int msecs = 30000);
+
+signals:
+ void notified(const QString &notify_uuid, const QVariant &object, const QString &action);
+ void notified(const QString &notify_uuid, const QsonObject &object, const QString &action);
+ void response(int id, const QVariant &data);
+ void response(int id, const QsonObject &data);
+ void error(int id, int code, const QString &message);
+ void disconnected();
+ void readyWrite();
+
+private slots:
+ void receiveMessage(const QsonObject &msg);
+
+private:
+ void init(QIODevice *);
+
+private:
+ Q_DISABLE_COPY(JsonDbConnection)
+ Q_DECLARE_PRIVATE(JsonDbConnection)
+ QScopedPointer<JsonDbConnectionPrivate> d_ptr;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif /* JSONDB_H */
diff --git a/src/client/jsondb-error.cpp b/src/client/jsondb-error.cpp
new file mode 100644
index 00000000..d16c31fb
--- /dev/null
+++ b/src/client/jsondb-error.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-global.h"
+#include "jsondb-error.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+/*!
+ \class QtAddOn::JsonDb::JsonDbError
+ \sa JsonDbError::ErrorCode.
+ */
+
+/*!
+ \enum QtAddOn::JsonDb::JsonDbError::ErrorCode
+ \value InvalidMessage
+ Unable to parse the query message.
+ \value InvalidRequest
+ Request object doesn't contain correct elements.
+ \value MissingObject
+ Invalid or missing "object" field.
+ \value DatabaseError
+ Error directly from the database.
+ \value MissingUUID
+ Missing id field.
+ \value MissingType
+ Missing _type field.
+ \value MissingQuery
+ Missing query field.
+ \value InvalidLimit
+ Invalid limit field.
+ \value InvalidOffset
+ Invalid offset field.
+ \value MismatchedNotifyId
+ Request to delete notify doesn't match existing notification.
+ \value InvalidActions
+ List of actions supplied to setNotification is invalid.
+ \value UpdatingStaleVersion
+ Updating stale version of object.
+ \value OperationNotPermitted
+ Operation prohibited by access control policy.
+ \value QuotaExceeded
+ Operation would exceed quota.
+ \value FailedSchemaValidation
+ Object to be created/updated was invalid according to the schema.
+ \value InvalidMap
+ The Map definition is invalid.
+ \value InvalidReduce
+ The Reduce definition is invalid.
+ \value InvalidSchemaOperation
+ Attempted to create a schema that already exists or to remove a schema when there are still objects belonging to the schema's type.
+ \value InvalidPartition
+ Invalid partition.
+ */
+
+ }
+}
+
diff --git a/src/client/jsondb-error.h b/src/client/jsondb-error.h
new file mode 100644
index 00000000..9bd1f39d
--- /dev/null
+++ b/src/client/jsondb-error.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_ERRORS_H
+#define JSONDB_ERRORS_H
+
+#include "jsondb-global.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDbError {
+public:
+ enum ErrorCode {
+ NoError = 0,
+ InvalidMessage, // Unable to parse the query message
+ InvalidRequest, // Request object doesn't contain correct elements
+ MissingObject, // Invalid or missing "object" field
+ DatabaseError, // Error directly from the database
+ MissingUUID, // Missing id field
+ MissingType, // Missing _type field
+ MissingQuery, // Missing query field
+ InvalidLimit, // Invalid limit field
+ InvalidOffset, // Invalid offset field
+ MismatchedNotifyId, // Request to delete notify doesn't match existing notification
+ InvalidActions, // List of actions supplied to setNotification is invalid
+ UpdatingStaleVersion, // Updating stale version of object
+ OperationNotPermitted,
+ QuotaExceeded,
+ FailedSchemaValidation, // Invalid according to the schema
+ InvalidMap, // The Map definition is invalid
+ InvalidReduce, // The Reduce definition is invalid
+ InvalidSchemaOperation,
+ InvalidPartition
+ };
+};
+
+} } // namespace
+
+#endif // JSONDB_ERRORS_H
diff --git a/src/client/jsondb-global.h b/src/client/jsondb-global.h
new file mode 100644
index 00000000..d1aaf1c4
--- /dev/null
+++ b/src/client/jsondb-global.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef JSONDB_GLOBAL_H
+#define JSONDB_GLOBAL_H
+
+#include "qglobal.h"
+
+#if defined(QT_ADDON_JSONDB_LIB)
+# define Q_ADDON_JSONDB_EXPORT Q_DECL_EXPORT
+#else
+# define Q_ADDON_JSONDB_EXPORT Q_DECL_IMPORT
+#endif
+
+#define Q_ADDON_JSONDB_BEGIN_NAMESPACE namespace QtAddOn { namespace JsonDb {
+#define Q_ADDON_JSONDB_END_NAMESPACE } }
+#define Q_USE_JSONDB_NAMESPACE using namespace QtAddOn::JsonDb;
+#define Q_ADDON_JSONDB_PREPEND_NAMESPACE(name) ::QtAddOn::JsonDb::name
+
+# define Q_ADDON_JSONDB_FORWARD_DECLARE_CLASS(name) \
+ Q_ADDON_JSONDB_BEGIN_NAMESPACE class name; Q_ADDON_JSONDB_END_NAMESPACE \
+ using Q_ADDON_JSONDB_PREPEND_NAMESPACE(name);
+
+# define Q_ADDON_JSONDB_FORWARD_DECLARE_STRUCT(name) \
+ Q_ADDON_JSONDB_BEGIN_NAMESPACE struct name; Q_ADDON_JSONDB_END_NAMESPACE \
+ using Q_ADDON_JSONDB_PREPEND_NAMESPACE(name);
+
+#endif // JSONDB_GLOBAL_H
diff --git a/src/client/jsondb-oneshot.cpp b/src/client/jsondb-oneshot.cpp
new file mode 100644
index 00000000..181c85e4
--- /dev/null
+++ b/src/client/jsondb-oneshot.cpp
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-oneshot_p.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/client/jsondb-oneshot_p.h b/src/client/jsondb-oneshot_p.h
new file mode 100644
index 00000000..8276fb30
--- /dev/null
+++ b/src/client/jsondb-oneshot_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_ONESHOT_P_H
+#define JSONDB_ONESHOT_P_H
+
+#include <QObject>
+#include <QVariant>
+#include <QDebug>
+#include <QEventLoop>
+#include <QThread>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "jsondb-global.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+/*
+ * The one-shot class is strictly for the private use of the connection object
+ */
+
+class JsonDbOneShot : public QObject {
+ Q_OBJECT
+ friend class JsonDbConnection;
+public slots:
+ void handleResponse( int id, const QVariant& data ) {
+ if (id == mId) { emit response(data); deleteLater(); }
+ }
+ void handleError( int id, int code, const QString& message ) {
+ if (id == mId) { emit error(code, message); deleteLater(); }
+ }
+signals:
+ void response(const QVariant& object);
+ void error(int code, const QString& message);
+private:
+ int mId;
+};
+
+
+/*
+ * The sync class forces a response before the program will continue
+ */
+class JsonDbConnection;
+class JsonDbSyncCall : public QObject {
+ Q_OBJECT
+ friend class JsonDbConnection;
+public:
+ QT_DEPRECATED
+ JsonDbSyncCall(const QVariantMap &dbrequest, QVariant &result);
+ JsonDbSyncCall(const QVariantMap *dbrequest, QVariant *result);
+ JsonDbSyncCall(const QsonMap *dbrequest, QsonObject *result);
+ ~JsonDbSyncCall();
+public slots:
+ void createSyncRequest();
+ void createSyncQsonRequest();
+ void handleResponse( int id, const QVariant& data );
+ void handleResponse( int id, const QsonObject& data );
+ void handleError( int id, int code, const QString& message );
+private:
+ int mId;
+ const QVariantMap *mDbRequest;
+ const QsonMap *mDbQsonRequest;
+ QVariant *mResult;
+ QsonObject *mQsonResult;
+ JsonDbConnection *mSyncJsonDbConnection;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // JSONDB_ONESHOT_P_H
diff --git a/src/client/jsondb-strings_p.h b/src/client/jsondb-strings_p.h
new file mode 100644
index 00000000..c4109280
--- /dev/null
+++ b/src/client/jsondb-strings_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_STRINGS_H
+#define JSONDB_STRINGS_H
+
+#include <QString>
+#include "jsondb-global.h"
+
+Q_ADDON_JSONDB_BEGIN_NAMESPACE
+
+class Q_ADDON_JSONDB_EXPORT JsonDbString {
+public:
+ static const QString kActionStr;
+ static const QString kActionsStr;
+ static const QString kActiveStr;
+ static const QString kAddIndexStr;
+ static const QString kCodeStr;
+ static const QString kConnectStr;
+ static const QString kCountStr;
+ static const QString kCreateStr;
+ static const QString kDropStr;
+ static const QString kCurrentStr;
+ static const QString kDataStr;
+ static const QString kDeletedStr;
+ static const QString kDisconnectStr;
+ static const QString kDomainStr;
+ static const QString kErrorStr;
+ static const QString kExplanationStr;
+ static const QString kFieldNameStr;
+ static const QString kFindStr;
+ static const QString kNameStr;
+ static const QString kIdStr;
+ static const QString kLengthStr;
+ static const QString kLimitStr;
+ static const QString kMapTypeStr;
+ static const QString kMessageStr;
+ static const QString kNotifyStr;
+ static const QString kNotificationTypeStr;
+ static const QString kObjectStr;
+ static const QString kParentStr;
+ static const QString kOffsetStr;
+ static const QString kOwnerStr;
+ static const QString kQueryStr;
+ static const QString kReduceTypeStr;
+ static const QString kRemoveStr;
+ static const QString kResultStr;
+ static const QString kSchemaStr;
+ static const QString kSchemaTypeStr;
+ static const QString kTypeStr;
+ static const QString kTypesStr;
+ static const QString kUpdateStr;
+ static const QString kUuidStr;
+ static const QString kVersionStr;
+ static const QString kViewTypeStr;
+ static const QString kTokenStr;
+ static const QString kSettingsStr;
+ static const QString kChangesSinceStr;
+ static const QString kStateNumberStr;
+ static const QString kCollapsedStr;
+ static const QString kCurrentStateNumberStr;
+ static const QString kStartingStateNumberStr;
+ static const QString kTombstoneStr;
+};
+
+Q_ADDON_JSONDB_END_NAMESPACE
+
+#endif /* JSONDB-STRINGS_H */
diff --git a/src/common/common.pri b/src/common/common.pri
new file mode 100644
index 00000000..e9ab4312
--- /dev/null
+++ b/src/common/common.pri
@@ -0,0 +1,18 @@
+INCLUDEPATH += $$PWD
+
+include(../3rdparty/qjson/qjson.pri)
+
+QSONCONVERSION_HEADERS = \
+ $$PWD/qsonconversion.h
+QSONCONVERSION_SOURCES = \
+ $$PWD/qsonconversion.cpp
+
+HEADERS += \
+ $$PWD/jsondb-global.h \
+ $$PWD/jsondb-error.h \
+ $$PWD/jsondb-strings.h \
+ $$PWD/qsonstream.h
+
+SOURCES += \
+ $$PWD/jsondb-strings.cpp \
+ $$PWD/qsonstream.cpp
diff --git a/src/common/jsondb-error.h b/src/common/jsondb-error.h
new file mode 100644
index 00000000..141f8665
--- /dev/null
+++ b/src/common/jsondb-error.h
@@ -0,0 +1 @@
+#include "../client/jsondb-error.h"
diff --git a/src/common/jsondb-global.h b/src/common/jsondb-global.h
new file mode 100644
index 00000000..24b19d87
--- /dev/null
+++ b/src/common/jsondb-global.h
@@ -0,0 +1 @@
+#include "../client/jsondb-global.h"
diff --git a/src/common/jsondb-strings.cpp b/src/common/jsondb-strings.cpp
new file mode 100644
index 00000000..6dcbbeac
--- /dev/null
+++ b/src/common/jsondb-strings.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-strings.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+const QString JsonDbString::kUuidStr = QString::fromLatin1("_uuid");
+const QString JsonDbString::kVersionStr = QString::fromLatin1("_version");
+const QString JsonDbString::kIdStr = QString::fromLatin1("id");
+const QString JsonDbString::kResultStr = QString::fromLatin1("result");
+const QString JsonDbString::kErrorStr = QString::fromLatin1("error");
+const QString JsonDbString::kFieldNameStr = QString::fromLatin1("fieldName");
+const QString JsonDbString::kCodeStr = QString::fromLatin1("code");
+const QString JsonDbString::kMessageStr = QString::fromLatin1("message");
+const QString JsonDbString::kNameStr = QString::fromLatin1("name");
+const QString JsonDbString::kCountStr = QString::fromLatin1("count");
+const QString JsonDbString::kCurrentStr = QString::fromLatin1("_current");
+const QString JsonDbString::kDomainStr = QString::fromLatin1("_domain");
+const QString JsonDbString::kOwnerStr = QString::fromLatin1("_owner");
+const QString JsonDbString::kTypeStr = QString::fromLatin1("_type");
+const QString JsonDbString::kTypesStr = QString::fromLatin1("types");
+const QString JsonDbString::kParentStr = QString::fromLatin1("_parent");
+const QString JsonDbString::kSchemaTypeStr = QString::fromLatin1("_schemaType");
+
+const QString JsonDbString::kActionStr = QString::fromLatin1("action");
+const QString JsonDbString::kActionsStr = QString::fromLatin1("actions");
+const QString JsonDbString::kActiveStr = QString::fromLatin1("active");
+const QString JsonDbString::kAddIndexStr = QString::fromLatin1("addIndex");
+const QString JsonDbString::kCreateStr = QString::fromLatin1("create");
+const QString JsonDbString::kDropStr = QString::fromLatin1("drop");
+const QString JsonDbString::kConnectStr = QString::fromLatin1("connect");
+const QString JsonDbString::kDataStr = QString::fromLatin1("data");
+const QString JsonDbString::kDeletedStr = QString::fromLatin1("_deleted");
+const QString JsonDbString::kDisconnectStr = QString::fromLatin1("disconnect");
+const QString JsonDbString::kExplanationStr = QString::fromLatin1("explanation");
+const QString JsonDbString::kFindStr = QString::fromLatin1("find");
+const QString JsonDbString::kLengthStr = QString::fromLatin1("length");
+const QString JsonDbString::kLimitStr = QString::fromLatin1("limit");
+const QString JsonDbString::kMapTypeStr = QString::fromLatin1("Map");
+const QString JsonDbString::kNotifyStr = QString::fromLatin1("notify");
+const QString JsonDbString::kNotificationTypeStr = QString::fromLatin1("notification");
+const QString JsonDbString::kObjectStr = QString::fromLatin1("object");
+const QString JsonDbString::kOffsetStr = QString::fromLatin1("offset");
+const QString JsonDbString::kQueryStr = QString::fromLatin1("query");
+const QString JsonDbString::kReduceTypeStr = QString::fromLatin1("Reduce");
+const QString JsonDbString::kRemoveStr = QString::fromLatin1("remove");
+const QString JsonDbString::kSchemaStr = QString::fromLatin1("schema");
+const QString JsonDbString::kUpdateStr = QString::fromLatin1("update");
+const QString JsonDbString::kTokenStr = QString::fromLatin1("token");
+const QString JsonDbString::kSettingsStr = QString::fromLatin1("settings");
+const QString JsonDbString::kViewTypeStr = QString::fromLatin1("View");
+const QString JsonDbString::kChangesSinceStr = QString::fromLatin1("changesSince");
+const QString JsonDbString::kStateNumberStr = QString::fromLatin1("stateNumber");
+const QString JsonDbString::kCollapsedStr = QString::fromLatin1("collapsed");
+const QString JsonDbString::kCurrentStateNumberStr = QString::fromLatin1("currentStateNumber");
+const QString JsonDbString::kStartingStateNumberStr = QString::fromLatin1("startingStateNumber");
+const QString JsonDbString::kTombstoneStr = QString::fromLatin1("Tombstone");
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/common/jsondb-strings.h b/src/common/jsondb-strings.h
new file mode 100644
index 00000000..5f98dbeb
--- /dev/null
+++ b/src/common/jsondb-strings.h
@@ -0,0 +1 @@
+#include "../client/jsondb-strings_p.h"
diff --git a/src/common/qsonconversion.cpp b/src/common/qsonconversion.cpp
new file mode 100644
index 00000000..5973fe21
--- /dev/null
+++ b/src/common/qsonconversion.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonconversion.h"
+#include "qjsengine.h"
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+static QJSValue qsonListToJSValue(const QsonList &list, QJSEngine *engine)
+{
+ int count = list.count();
+ QJSValue result = engine->newArray(count);
+
+ for (int i = 0; i < count; ++i)
+ result.setProperty(i, qsonToJSValue(list.at<QsonElement>(i), engine));
+ return result;
+}
+
+static QJSValue qsonMapToJSValue(const QsonMap &map, QJSEngine *engine)
+{
+ QJSValue result = engine->newObject();
+ QStringList keys = map.keys();
+ foreach (const QString &key, keys)
+ result.setProperty(key, qsonToJSValue(map.value<QsonElement>(key), engine));
+ return result;
+}
+
+QJSValue qsonToJSValue(const QsonObject &object, QJSEngine *engine)
+{
+ switch (object.type()) {
+ case QsonObject::ListType:
+ return qsonListToJSValue(object.toList(), engine);
+ case QsonObject::MapType:
+ return qsonMapToJSValue(object.toMap(), engine);
+ case QsonObject::StringType:
+ return QJSValue(engine, QsonElement(object).value<QString>());
+ case QsonObject::DoubleType:
+ return QJSValue(engine, QsonElement(object).value<double>());
+ case QsonObject::IntType:
+ return QJSValue(engine, QsonElement(object).value<int>());
+ case QsonObject::UIntType:
+ return QJSValue(engine, QsonElement(object).value<uint>());
+ case QsonObject::BoolType:
+ return QJSValue(engine, QsonElement(object).value<bool>());
+ case QsonObject::NullType:
+ return engine->nullValue();
+ default:
+ break;
+ }
+ return QJSValue();
+}
+
+QsonObject jsValueToQson(const QJSValue &object)
+{
+ return variantToQson(object.toVariant());
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/common/qsonconversion.h b/src/common/qsonconversion.h
new file mode 100644
index 00000000..2296eeed
--- /dev/null
+++ b/src/common/qsonconversion.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONCONVERSION_H
+#define QSONCONVERSION_H
+
+#include <QtJsonDbQson/private/qsonobject_p.h>
+#include <QtDeclarative/qjsvalue.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+QJSValue qsonToJSValue(const QsonObject &object, QJSEngine *engine);
+QsonObject jsValueToQson(const QJSValue &object);
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONCONVERSION_H
diff --git a/src/common/qsonstream.cpp b/src/common/qsonstream.cpp
new file mode 100644
index 00000000..9d015c2a
--- /dev/null
+++ b/src/common/qsonstream.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonstream.h"
+#include <QDebug>
+#include <QDataStream>
+#include <QLocalSocket>
+#include <QAbstractSocket>
+#include <QtEndian>
+
+#ifdef QT_DEBUG
+#include <QUdpSocket>
+#include <QDateTime>
+#include <QCoreApplication>
+#endif
+
+namespace QtAddOn { namespace JsonDb {
+
+QsonStream::QsonStream(QIODevice *device, QObject *parent) :
+ QObject(parent),
+ mDevice(0)
+{
+ setDevice(device);
+}
+
+QIODevice *QsonStream::device() const
+{
+ return mDevice;
+}
+
+/** Set the device used by the QsonStream.
+ The stream does not take ownership of the device.
+*/
+void QsonStream::setDevice(QIODevice *device)
+{
+ if (mDevice) {
+ disconnect(mDevice, SIGNAL(readyRead()), this, SLOT(deviceReadyRead()));
+ disconnect(mDevice, SIGNAL(bytesWritten(qint64)), this, SLOT(deviceBytesWritten(qint64)));
+ disconnect(mDevice, SIGNAL(aboutToClose()), this, SIGNAL(aboutToClose()));
+ }
+ mDevice = device;
+ if (mDevice) {
+ connect(mDevice, SIGNAL(readyRead()), this, SLOT(deviceReadyRead()));
+ connect(mDevice, SIGNAL(bytesWritten(qint64)), this, SLOT(deviceBytesWritten(qint64)));
+ connect(mDevice, SIGNAL(aboutToClose()), this, SIGNAL(aboutToClose()));
+ }
+}
+
+bool QsonStream::send(const QsonObject &qson)
+{
+ sendQsonPage(*qson.mHeader);
+ foreach (const QsonPagePtr body, qson.mBody)
+ sendQsonPage(*body);
+ sendQsonPage(*qson.mFooter);
+ return true;
+}
+
+void QsonStream::sendQsonPage(const QsonPage &page)
+{
+ int shouldWrite = page.dataSize();
+ if (mWriteBuffer.isEmpty()) {
+ int didWrite = mDevice->write(page.constData(), shouldWrite);
+ if (didWrite < 0) {
+ qWarning() << "Error writing to socket" << mDevice->errorString();
+ } else if (didWrite < shouldWrite) {
+ mWriteBuffer.append(page.constData() + didWrite, shouldWrite - didWrite);
+ }
+ } else {
+ qWarning() << "Buffering, slow down your writes";
+ mWriteBuffer.append(page.constData(), shouldWrite);
+ }
+}
+
+void QsonStream::deviceReadyRead()
+{
+ mReadBuffer.resize(0xFFFF);
+ while (!mDevice->atEnd()) {
+ int bytesRead = mDevice->read(mReadBuffer.data(), mReadBuffer.size());
+ if (bytesRead < 0) {
+ qWarning() << "Error reading from socket" << mDevice->errorString();
+ continue;
+ }
+ mReadBuffer.truncate(bytesRead);
+ mParser.append(mReadBuffer);
+
+ while (mParser.isObjectReady()) {
+ QsonObject qson = mParser.getObject();
+ receive(qson);
+ }
+
+ if (mParser.hasError()) {
+ qWarning() << "Parser error, trying to recover!";
+ // TODO: Improve!
+ mParser = QsonParser();
+ }
+ }
+}
+
+void QsonStream::deviceBytesWritten(qint64 bytes)
+{
+ if (!mWriteBuffer.isEmpty()) {
+ int didWrite = mDevice->write(mWriteBuffer);
+ mWriteBuffer = mWriteBuffer.mid(didWrite);
+ }
+}
+
+QsonStream& operator<<(QsonStream& s, const QsonObject& map)
+{
+ s.send(map);
+ return s;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/common/qsonstream.h b/src/common/qsonstream.h
new file mode 100644
index 00000000..c022f6a8
--- /dev/null
+++ b/src/common/qsonstream.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONSTREAM_H
+#define QSONSTREAM_H
+
+#include <QIODevice>
+#include <QtJsonDbQson/private/qson_p.h>
+#include <QtJsonDbQson/private/qsonparser_p.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+class QsonStream : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QsonStream(QIODevice *device = 0, QObject *parent = 0);
+
+ QIODevice *device() const;
+ void setDevice(QIODevice *device);
+
+ bool send(const QsonObject &data);
+
+signals:
+ void receive(const QsonObject &data);
+ void aboutToClose();
+ void readyWrite();
+
+protected slots:
+ void deviceReadyRead();
+ void deviceBytesWritten(qint64 bytes);
+
+private:
+ void sendQsonPage(const QsonPage &page);
+
+ QIODevice *mDevice;
+ QByteArray mWriteBuffer;
+ QsonParser mParser;
+ QByteArray mReadBuffer;
+
+};
+
+QsonStream& operator<<( QsonStream&, const QsonObject& );
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONSTREAM_H
diff --git a/src/daemon/TODO b/src/daemon/TODO
new file mode 100644
index 00000000..f56c8c3c
--- /dev/null
+++ b/src/daemon/TODO
@@ -0,0 +1,70 @@
+ TODO
+======
+ * convenience API: getOrCreate, CreateOrIgnore
+
+ * API for querying via json object rather than a query string
+ * Separate find(), which returns objects in database, from query(), which returns data
+ * Define and implement joins as part of query()
+ * Fold the javascript wrapper into the client
+ * Implement attached content
+ * Implement jsondb:// scheme as part of QNetworkAccessManager
+ * Implement policy/demand based synchronization and caching of content
+ * Add full text indexing of object fields
+ * Implement table model
+ * Investigate speed of QVariant vs custom JsonDbValue
+ * Test indexing of int field type
+ * Test indexing of double field type
+ * Finish implementing addIndex with typeName for JsonDbSqlite
+ * Specific index type for datetime?
+
+ * owner -> forward value
+ * quota for elements returned in query
+ * create indicies from jsonquery expressions
+ * use this to create per-app indices
+ * Move metadata from -Indexes to main table?
+ * procedure to rebuild metadata and indexes
+ * use multiple indexes in query based on statistics of the indexes?
+ * benchmark c++ client performance
+ * benchmark QML/Javascript client performance
+ * update/remove object properties
+ * increment/decrement fields containing numbers or sets of values
+
+List model:
+ * benchmark listmodel performance
+ * use range/limit instead of offset/limit?
+
+Access control
+ * default order query to allowed types or owners rather than uuid, based on populations of each
+ * set access control policy via policy objects? widget objects?
+
+EWS:
+ * EWS folder objects
+ * EWS message/calendar subsets (e.g., by date)
+ * EWS minimal calendar metadata
+ * EWS send meeting invites
+ * EWS send message
+ * EWS message flags update / message removal
+ * EWS calendar item create/up/removal
+ * EWS contact create/update/removal
+
+ Done
+======
+ * Add indexing of nested fields. -- done
+ * Reindex all objects when new index is added
+ * BDB: forward key QVariant fieldvalue
+ * BDB: reverse key QVariant fieldvalue
+ * Finish implementing addIndex with typeName for JsonDbBerkeley
+ * Use a key instead of TYPE in indexes
+ * Add chaff to contacts benchmark
+ * type -> forward value from forward key
+ * Use a key instead of UUID to identify objects in indexes
+ * Fix reindex objects in BDB backend!
+ * Fix indexObject in BDB backend!
+ * _owner -> mandatory object property
+ * create, update, and remove access control
+ * filter queries on allowed types
+ * filter queries on allowed owners
+ * query on field value in set
+ * listmodel instance of QAbstractItemModel as recommended?
+ * Implement string matching =~ "%a%" for unindexed queries
+ * Implement string prefix matching =~ "a%" for indexed queries
diff --git a/src/daemon/aodb.cpp b/src/daemon/aodb.cpp
new file mode 100644
index 00000000..ebd7cb6e
--- /dev/null
+++ b/src/daemon/aodb.cpp
@@ -0,0 +1,569 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QFileInfo>
+#include <QStringList>
+#include <QDebug>
+
+#include "aodb.h"
+#include "btree.h"
+
+#include <errno.h>
+#include <string.h>
+
+// Every gCompactRate commits, compact the btree. Do not compact if zero.
+int gCompactRate = qgetenv("JSONDB_COMPACT_RATE").size() ? ::atoi(qgetenv("JSONDB_COMPACT_RATE")) : 1000;
+// Every gSyncRate commits, fsync the btree. Do not fsync if zero.
+int gSyncRate = qgetenv("JSONDB_SYNC_RATE").size() ? ::atoi(qgetenv("JSONDB_SYNC_RATE")) : 100;
+
+// number of pages to keep in cache
+int gCacheSize = qgetenv("BENCHMARK_MANY").size() ? ::atoi(qgetenv("BENCHMARK_MANY")) : 32;
+
+AoDb::AoDb()
+ : mBtreeFlags(0), mBtree(0), mTxn(0), mCmp(0), mCommitCount(0), mCacheSize(gCacheSize)
+{
+}
+
+AoDb::~AoDb()
+{
+ close();
+}
+
+bool AoDb::clear()
+{
+ close();
+ int rc = unlink(mFilename.toLocal8Bit().constData());
+ if (rc)
+ qDebug() << "AoDb::clear" << "unlink failed" << errno << mFilename;
+ if (!reopen())
+ return false;
+ return (rc == 0);
+}
+
+bool AoDb::compact()
+{
+ Q_ASSERT(mBtree);
+ if (!mBtree)
+ return false;
+
+ unsigned int flags = btree_get_flags(mBtree);
+
+ if (flags & BT_RDONLY)
+ return false;
+
+ if (btree_compact(mBtree) != BT_SUCCESS)
+ return false;
+
+ if (!reopen())
+ return false;
+
+ return true;
+}
+
+QString AoDb::errorMessage() const
+{
+ return QString("AoDb: %1: %2").arg(mFilename, strerror(errno));
+}
+
+bool AoDb::setCmpFunc(AoDb::CmpFunc cmp)
+{
+ if (mBtree)
+ btree_set_cmp(mBtree, (bt_cmp_func)cmp);
+ mCmp = cmp;
+ return true;
+}
+
+bool AoDb::open(const QString &filename, AoDb::DbFlags flags)
+{
+ QFileInfo fi(filename);
+ if (fi.suffix().isEmpty())
+ fi.setFile(filename + ".db");
+ fi.makeAbsolute();
+ mFilename = fi.filePath();
+
+ int btflags = 0;
+ if (flags & AoDb::ReverseKeys)
+ btflags |= BT_REVERSEKEY;
+ if (flags & AoDb::NoSync)
+ btflags |= BT_NOSYNC;
+ if (flags & AoDb::ReadOnly)
+ btflags |= BT_RDONLY;
+ if (flags & AoDb::UseSyncMarker)
+ btflags |= BT_USEMARKER;
+
+ mBtreeFlags = btflags;
+ mBtree = btree_open(mFilename.toLocal8Bit().constData(), btflags, 0644);
+ if (!mBtree) {
+ qDebug() << "Aodb::open" << "failed" << errno;
+ return false;
+ }
+ btree_set_cache_size(mBtree, mCacheSize);
+ btree_set_cmp(mBtree, mCmp);
+
+ Q_ASSERT(mBtree);
+ return true;
+}
+
+quint64 AoDb::count() const
+{
+ Q_ASSERT(mBtree);
+ const struct btree_stat *stat = btree_stat(mBtree);
+ return stat->entries;
+}
+
+bool AoDb::get(const QByteArray &baKey, QByteArray &baValue)
+{
+ Q_ASSERT(mBtree);
+ struct btval btkey;
+ btkey.data = (void*)baKey.constData();
+ btkey.size = baKey.size();
+ btkey.free_data = 0;
+ btkey.mp = 0;
+
+ struct btval btvalue;
+ int ok = btree_txn_get(mBtree, mTxn, &btkey, &btvalue);
+ if (ok == BT_SUCCESS) {
+ baValue.resize(btvalue.size);
+ memcpy(baValue.data(), btvalue.data, btvalue.size);
+ btval_reset(&btvalue);
+ } else {
+ //qDebug() << "btree_txn_get" << ok << errno;
+ }
+ return ok == BT_SUCCESS;
+}
+
+bool AoDb::put(const QByteArray &baKey, const QByteArray &baValue)
+{
+ Q_ASSERT(mBtree);
+ struct btval btkey;
+ btkey.data = (void*)baKey.constData();
+ btkey.size = baKey.size();
+ btkey.free_data = 0;
+ btkey.mp = 0;
+ struct btval btvalue;
+ btvalue.data = (void*)baValue.constData();
+ btvalue.size = baValue.size();
+ btvalue.free_data = 0;
+ btvalue.mp = 0;
+
+ int ok = btree_txn_put(mBtree, mTxn, &btkey, &btvalue, 0);
+ if (ok != BT_SUCCESS) {
+ qDebug() << "btree_txn_put" << ok << errno << endl << mFilename;
+ }
+ return (ok == BT_SUCCESS);
+}
+
+bool AoDb::remove(const QByteArray &baKey)
+{
+ Q_ASSERT(mBtree);
+ struct btval btkey;
+ btkey.data = (void*)baKey.constData();
+ btkey.size = baKey.size();
+ btkey.free_data = 0;
+ btkey.mp = 0;
+ int ok = btree_txn_del(mBtree, mTxn, &btkey, 0);
+ if (ok != BT_SUCCESS) qDebug() << "db->del" << ok << errno << baKey.toHex() << endl
+ << mFilename;
+ return (ok == BT_SUCCESS);
+}
+
+void AoDb::sync()
+{
+ if (mBtree)
+ btree_sync(mBtree);
+}
+
+void AoDb::close()
+{
+ if (mBtree) {
+ if (mTxn) {
+ qCritical() << "AoDb::close()" << "transaction in progress aborted.";
+ btree_txn_abort(mTxn);
+ mTxn = 0;
+ }
+ if (mBtree) {
+ btree_close(mBtree);
+ mBtree = 0;
+ }
+ }
+}
+
+bool AoDb::begin()
+{
+ Q_ASSERT(mBtree);
+ if (mBtree && !mTxn) {
+ mTxn = btree_txn_begin(mBtree, 0);
+ if (!mTxn) {
+ qCritical() << "AoDb::begin" << "txn failed" << errno << mFilename;
+ return false;
+ }
+ return true;
+ } else if (mTxn) {
+ qCritical() << "AoDb::begin" << "txn already started" << mFilename;
+ return false;
+ } else {
+ qCritical() << "AoDb::begin" << "no tree";
+ return false;
+ }
+}
+
+bool AoDb::beginRead()
+{
+ Q_ASSERT(mBtree);
+ if (mBtree && !mTxn) {
+ mTxn = btree_txn_begin(mBtree, 1);
+ if (!mTxn) {
+ qCritical() << "AoDb::beginRead" << "txn failed" << errno << mFilename;
+ return false;
+ }
+ return true;
+ } else if (mTxn) {
+ qCritical() << "AoDb::begin" << "txn already started" << mFilename;
+ return false;
+ } else {
+ qCritical() << "AoDb::begin" << "no tree";
+ return false;
+ }
+}
+
+bool AoDb::commit(quint32 tag)
+{
+ Q_ASSERT(mTxn);
+ if (mTxn) {
+ unsigned int flags = (gSyncRate && mCommitCount % gSyncRate == 0) ? BT_FORCE_MARKER : 0;
+ int rc = btree_txn_commit(mTxn, tag, flags);
+ mTxn = 0;
+ if (gCompactRate && (mCommitCount++ > gCompactRate)) {
+ compact();
+ mCommitCount = 0;
+ }
+ return rc == 0;
+ } else {
+ qCritical() << "AoDb::commit()" << "no txn" << mFilename;
+ return false;
+ }
+}
+
+bool AoDb::abort()
+{
+ Q_ASSERT(mTxn);
+ if (mTxn) {
+ btree_txn_abort(mTxn);
+ mTxn = 0;
+ return true;
+ } else {
+ qCritical() << "AoDb::abort()" << "no txn";
+ return false;
+ }
+}
+
+quint32 AoDb::tag() const
+{
+ Q_ASSERT(mBtree);
+ const struct btree_stat *stat = btree_stat(mBtree);
+ return stat->tag;
+}
+
+int AoDb::revert()
+{
+ Q_ASSERT(mBtree);
+ mTxn = 0;
+ return btree_rollback(mBtree);
+}
+
+const struct btree_stat *AoDb::stat() const
+{
+ Q_ASSERT(mBtree);
+ return btree_stat(mBtree);
+}
+
+AoDbCursor *AoDb::cursor()
+{
+ return new AoDbCursor(this);
+}
+
+void AoDb::setCacheSize(unsigned int cacheSize)
+{
+ mCacheSize = cacheSize;
+ if (mBtree)
+ btree_set_cache_size(mBtree, cacheSize);
+ mCacheSize = cacheSize;
+}
+void AoDb::dump()
+{
+ btree_dump(mBtree);
+}
+
+bool AoDb::reopen()
+{
+ if (mBtree)
+ btree_close(mBtree);
+ mBtree = btree_open(mFilename.toLocal8Bit().constData(), mBtreeFlags, 0644);
+ if (!mBtree) {
+ qDebug() << "Aodb::reopen" << "failed" << errno;
+ return false;
+ }
+ btree_set_cache_size(mBtree, mCacheSize);
+ btree_set_cmp(mBtree, mCmp);
+ return true;
+}
+
+AoDbCursor::AoDbCursor(AoDb *bdb, bool committedStateOnly)
+ : mAoDb(bdb)
+{
+ Q_ASSERT(bdb->mBtree);
+ if (committedStateOnly)
+ mTxn = 0;
+ else
+ mTxn = bdb->mTxn;
+ mBtreeCursor = btree_txn_cursor_open(bdb->mBtree, mTxn);
+ if (!mBtreeCursor)
+ qDebug() << "AoDbCursor" << errno;
+ mBtkey.reset((struct btval *)malloc(sizeof(struct btval)));
+ memset(mBtkey.data(), 0, sizeof(struct btval));
+ mBtvalue.reset((struct btval *)malloc(sizeof(struct btval)));
+ memset(mBtvalue.data(), 0, sizeof(struct btval));
+}
+
+
+AoDbCursor::~AoDbCursor()
+{
+ if (mBtreeCursor)
+ btree_cursor_close(mBtreeCursor);
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ mTxn = 0;
+ mBtreeCursor = 0;
+}
+
+bool AoDbCursor::first()
+{
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ int ok = btree_cursor_get(mBtreeCursor, mBtkey.data(), mBtvalue.data(), BT_FIRST);
+ if (ok == BT_SUCCESS) {
+ return true;
+ } else {
+ btval_reset(mBtkey.data());
+ return false;
+ }
+}
+
+bool AoDbCursor::current(QByteArray &baKey, QByteArray &baValue)
+{
+ if (!mBtkey->size)
+ return false;
+
+ baKey = QByteArray((const char *)mBtkey->data, mBtkey->size);
+
+ baValue = QByteArray((const char *)mBtvalue->data, mBtvalue->size);
+ return true;
+}
+
+bool AoDbCursor::currentKey(QByteArray &baKey)
+{
+ if (!mBtkey->size)
+ return false;
+
+ baKey = QByteArray((const char *)mBtkey->data, mBtkey->size);
+
+ return true;
+}
+
+bool AoDbCursor::currentValue(QByteArray &baValue)
+{
+ if (!mBtkey->size)
+ return false;
+
+ baValue = QByteArray((const char *)mBtvalue->data, mBtvalue->size);
+
+ return true;
+}
+
+bool AoDbCursor::last()
+{
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ int ok = btree_cursor_get(mBtreeCursor, mBtkey.data(), mBtvalue.data(), BT_LAST);
+ if (ok == BT_SUCCESS) {
+ return true;
+ } else {
+ btval_reset(mBtkey.data());
+ return false;
+ }
+}
+
+bool AoDbCursor::next()
+{
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ int ok = btree_cursor_get(mBtreeCursor, mBtkey.data(), mBtvalue.data(), BT_NEXT);
+ if (ok == BT_SUCCESS) {
+ return true;
+ } else {
+ btval_reset(mBtkey.data());
+ return false;
+ }
+}
+
+bool AoDbCursor::prev()
+{
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ int ok = btree_cursor_get(mBtreeCursor, mBtkey.data(), mBtvalue.data(), BT_PREV);
+ return ok == BT_SUCCESS;
+}
+
+bool AoDbCursor::seek(const QByteArray &baKey)
+{
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ mBtkey->data = (void*)baKey.constData();
+ mBtkey->size = baKey.size();
+ int ok = btree_cursor_get(mBtreeCursor, mBtkey.data(), mBtvalue.data(), BT_CURSOR_EXACT);
+ if (ok == BT_SUCCESS) {
+ return true;
+ } else {
+ btval_reset(mBtkey.data());
+ return false;
+ }
+}
+
+bool AoDbCursor::seekRange(const QByteArray &baKey)
+{
+ btval_reset(mBtkey.data());
+ btval_reset(mBtvalue.data());
+ mBtkey->data = (void*)baKey.constData();
+ mBtkey->size = baKey.size();
+ int ok = btree_cursor_get(mBtreeCursor, mBtkey.data(), mBtvalue.data(), BT_CURSOR);
+ return ok == BT_SUCCESS;
+}
+
+QString AoDbCursor::errorMessage() const
+{
+ return QString("AoDbCursor: %1: %2").arg(mAoDb->fileName(), strerror(errno));
+}
+
+AoDbLocker::AoDbLocker()
+ : mTag(0), mCommitTag(0)
+{
+}
+
+AoDbLocker::~AoDbLocker()
+{
+ commit(mCommitTag);
+}
+
+void AoDbLocker::add(AoDb *db)
+{
+ if (mDbs.contains(db)) {
+ qCritical("Attempting to add the same db to the transaction twice!");
+ Q_ASSERT(false);
+ return;
+ }
+ mDbs.append(db);
+}
+
+bool AoDbLocker::begin()
+{
+ mLastError = QString();
+ mTag = 0;
+ if (mDbs.isEmpty())
+ return false;
+ for (int i = 0; i < mDbs.size(); ++i) {
+ AoDb *db = mDbs.at(i);
+ if (!db->begin()) {
+ mLastError = db->errorMessage();
+ for (int k = 0; k < i; ++k) {
+ AoDb *db = mDbs.at(k);
+ db->abort();
+ }
+ mDbs.clear();
+ return false;
+ }
+ if (i == 0) {
+ mTag = db->tag();
+ } else {
+ if (mTag != db->tag()) {
+ mLastError = QString::fromLatin1("Tag mismatch %1 != %2 (in %3)")
+ .arg(mTag).arg(db->tag()).arg(db->fileName());
+ for (int k = 0; k < i; ++k) {
+ AoDb *db = mDbs.at(k);
+ db->abort();
+ }
+ mDbs.clear();
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+quint32 AoDbLocker::tag() const
+{
+ return mTag;
+}
+
+bool AoDbLocker::abort()
+{
+ QStringList errors;
+ foreach (AoDb *db, mDbs) {
+ if (!db->abort()) {
+ errors.append(db->errorMessage());
+ }
+ }
+ mDbs.clear();
+ mLastError = errors.join("\n");
+ return errors.isEmpty();
+}
+
+bool AoDbLocker::commit(quint32 tag)
+{
+ QStringList errors;
+ foreach (AoDb *db, mDbs) {
+ if (!db->commit(tag)) {
+ errors.append(db->errorMessage());
+ }
+ }
+ mDbs.clear();
+ mLastError = errors.join("\n");
+ return errors.isEmpty();
+}
diff --git a/src/daemon/aodb.h b/src/daemon/aodb.h
new file mode 100644
index 00000000..3b5924c9
--- /dev/null
+++ b/src/daemon/aodb.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef _AODB_H_
+#define _AODB_H_
+
+#include <QFile>
+#include <QtEndian>
+
+class btree;
+struct btree_txn;
+struct btval;
+struct btree_stat;
+class AoDbCursor;
+
+class AoDb
+{
+public:
+ enum DbFlag {
+ Default=0x0000,
+ ReverseKeys=0x001,
+ NoSync=0x004,
+ ReadOnly=0x008,
+ UseSyncMarker=0x010
+ };
+ Q_DECLARE_FLAGS(DbFlags, DbFlag)
+
+ AoDb();
+ ~AoDb();
+
+ bool open(const QString &filename, DbFlags flags = Default);
+ void close();
+
+ bool get(const QByteArray &baKey, QByteArray &baValue);
+ bool put(const QByteArray &baKey, const QByteArray &baValue);
+ bool remove(const QByteArray &baKey);
+
+ void sync();
+
+ bool begin();
+ bool beginRead();
+ bool commit(quint32 tag);
+ bool abort();
+ bool isTransaction() const { return mTxn != 0; }
+
+ int revert();
+
+ QString fileName() const { return mFilename; }
+ const struct btree_stat *stat() const;
+ quint64 count() const;
+ btree *handle() const { return mBtree; }
+ quint32 tag() const;
+
+ bool clear();
+ bool compact();
+
+ QString errorMessage() const;
+
+ typedef int (*CmpFunc)(const char *a, size_t asize, const char *b, size_t bsize, void *context);
+ bool setCmpFunc(CmpFunc cmp);
+
+ void setCacheSize(unsigned int cacheSize);
+ void dump();
+
+ AoDbCursor *cursor();
+
+private:
+ bool reopen();
+ QString mFilename;
+ int mBtreeFlags;
+ btree *mBtree;
+ btree_txn *mTxn;
+ CmpFunc mCmp;
+ int mCommitCount;
+ int mCacheSize;
+
+ AoDb(const AoDb&);
+ friend class AoDbCursor;
+};
+
+class AoDbCursor
+{
+public:
+ AoDbCursor(AoDb *bdb, bool committedStateOnly=false);
+ virtual ~AoDbCursor();
+ bool first();
+ bool current(QByteArray &baKey, QByteArray &baValue);
+ bool currentKey(QByteArray &baKey);
+ bool currentValue(QByteArray &baValue);
+ bool last();
+ bool next();
+ bool prev();
+ bool seek(const QByteArray &baKey);
+ bool seekRange(const QByteArray &baKey);
+ QString errorMessage() const;
+
+private:
+ AoDb *mAoDb;
+ struct cursor *mBtreeCursor;
+ struct btree_txn *mTxn;
+ QScopedPointer<struct btval, QScopedPointerPodDeleter> mBtkey, mBtvalue;
+ AoDbCursor(const AoDbCursor&);
+};
+
+class AoDbLocker
+{
+public:
+ AoDbLocker();
+ ~AoDbLocker();
+
+ void add(AoDb *db);
+ bool begin();
+ bool abort();
+ bool commit(quint32 tag);
+
+ void setCommitTag(quint32 tag) { mCommitTag = tag; }
+ quint32 commitTag() const { return mCommitTag; }
+
+ quint32 tag() const;
+
+ QString errorMessage() const { return mLastError; }
+
+private:
+ QList<AoDb *> mDbs;
+ quint32 mTag;
+ quint32 mCommitTag;
+ QString mLastError;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AoDb::DbFlags)
+
+#endif
diff --git a/src/daemon/daemon.pri b/src/daemon/daemon.pri
new file mode 100644
index 00000000..03a75da8
--- /dev/null
+++ b/src/daemon/daemon.pri
@@ -0,0 +1,42 @@
+include($$PWD/../3rdparty/btree/btree.pri)
+include($$PWD/../common/common.pri)
+
+RESOURCES = $$PWD/jsondb.qrc
+HEADERS += \
+ $$PWD/aodb.h \
+ $$PWD/jsondb-map-reduce.h \
+ $$PWD/jsondb-owner.h \
+ $$PWD/jsondb-proxy.h \
+ $$PWD/jsondb-trace.h \
+ $$PWD/jsondb.h \
+ $$PWD/jsondbbtreestorage.h \
+ $$PWD/jsondbindex.h \
+ $$PWD/jsondbquery.h \
+ $$PWD/notification.h \
+ $$PWD/objectkey.h \
+ $$PWD/objecttable.h \
+ $$PWD/signals.h \
+ $$PWD/schema-validation/object.h \
+ $$PWD/schema-validation/checkpoints.h \
+ $$PWD/schemamanager_impl_p.h \
+ $$PWD/schemamanager_p.h \
+ $$PWD/qsonobjecttypes_p.h \
+ $$PWD/qsonobjecttypes_impl_p.h
+
+HEADERS += $$QSONCONVERSION_HEADERS
+
+SOURCES += \
+ $$PWD/aodb.cpp \
+ $$PWD/jsondb-map-reduce.cpp \
+ $$PWD/jsondb-owner.cpp \
+ $$PWD/jsondb-proxy.cpp \
+ $$PWD/jsondb-trace.cpp \
+ $$PWD/jsondb.cpp \
+ $$PWD/jsondbbtreestorage.cpp \
+ $$PWD/jsondbindex.cpp \
+ $$PWD/jsondbquery.cpp \
+ $$PWD/notification.cpp \
+ $$PWD/objecttable.cpp \
+ $$PWD/signals.cpp
+
+SOURCES += $$QSONCONVERSION_SOURCES
diff --git a/src/daemon/daemon.pro b/src/daemon/daemon.pro
new file mode 100644
index 00000000..69987c0a
--- /dev/null
+++ b/src/daemon/daemon.pro
@@ -0,0 +1,22 @@
+CONFIG += debug
+
+TARGET = jsondb
+DESTDIR = $$QT.jsondb.bins
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+LIBS += -L$$QT.jsondb.libs
+!mac:LIBS += -lssl -lcrypto
+
+QT = core network declarative jsondbqson-private
+
+mac:CONFIG -= app_bundle
+
+include(daemon.pri)
+
+HEADERS += \
+ $$PWD/dbserver.h \
+
+SOURCES += \
+ $$PWD/main.cpp \
+ $$PWD/dbserver.cpp \
diff --git a/src/daemon/dbserver.cpp b/src/daemon/dbserver.cpp
new file mode 100644
index 00000000..5ad04353
--- /dev/null
+++ b/src/daemon/dbserver.cpp
@@ -0,0 +1,616 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtNetwork>
+#include <QElapsedTimer>
+
+#include <json.h>
+
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+#include "jsondb.h"
+#include "jsondbbtreestorage.h"
+#include "dbserver.h"
+
+#ifdef Q_OS_UNIX
+#include <sys/socket.h>
+#endif
+
+namespace QtAddOn { namespace JsonDb {
+
+#ifndef QT_NO_DEBUG_OUTPUT
+extern bool gDebug;
+#define DBG() if (gDebug) qDebug() << Q_FUNC_INFO
+#else
+#define DBG() if (0) qDebug() << Q_FUNC_INFO
+#endif
+bool gPerformanceLog = (::getenv("JSONDB_PERFORMANCE_LOG") ? (QLatin1String(::getenv("JSONDB_PERFORMANCE_LOG")) == "true") : false);
+
+/*********************************************/
+
+#if 0
+static void sendResult( QsonStream *stream, const QVariant& result, const QVariant& id )
+{
+ QsonObject map;
+ map.insert( JsonDbString::kResultStr, result);
+ map.insert( JsonDbString::kErrorStr, QVariant());
+ map.insert( JsonDbString::kIdStr, id );
+ stream->send(map);
+}
+#endif
+
+static QsonMap createError( JsonDbError::ErrorCode code, const QString& message )
+{
+ QsonMap map;
+ map.insert(JsonDbString::kResultStr, QsonMap::NullValue);
+ QsonMap errormap;
+ errormap.insert(JsonDbString::kCodeStr, (int)code);
+ errormap.insert(JsonDbString::kMessageStr, message);
+ map.insert( JsonDbString::kErrorStr, errormap );
+ return map;
+}
+
+static void sendError( QsonStream *stream, JsonDbError::ErrorCode code,
+ const QString& message, int id )
+{
+ QsonMap map;
+ map.insert( JsonDbString::kResultStr, QsonObject::NullValue);
+ QsonMap errormap;
+ errormap.insert(JsonDbString::kCodeStr, code);
+ errormap.insert(JsonDbString::kMessageStr, message);
+ map.insert( JsonDbString::kErrorStr, errormap );
+ map.insert( JsonDbString::kIdStr, id );
+
+ DBG() << "Sending error" << map;
+ stream->send(map);
+}
+
+/*********************************************/
+
+DBServer::DBServer(const QString &fileName, QObject *parent)
+ : QObject(parent),
+ mTcpServerPort(0),
+ mServer(NULL),
+ mTcpServer(NULL),
+ mJsonDb(NULL),
+ mFileName(fileName)
+{
+ mMasterToken = ::getenv("JSONDB_TOKEN");
+ DBG() << "Master JSON-DB token" << mMasterToken;
+
+ if (mFileName.isEmpty()) {
+ QDir defaultDir(QDir::homePath() + QDir::separator() + QLatin1String(".jsondb"));
+ if (!defaultDir.exists())
+ defaultDir.mkpath(defaultDir.path());
+ mFileName = defaultDir.path();
+ mFileName += QDir::separator() + QLatin1String("database.db");
+ }
+}
+
+bool DBServer::socket()
+{
+ QString socketName = ::getenv("JSONDB_SOCKET");
+ if (socketName.isEmpty())
+ socketName = "qt5jsondb";
+ DBG() << "Listening on socket" << socketName;
+ QLocalServer::removeServer(socketName);
+ mServer = new QLocalServer(this);
+ connect(mServer, SIGNAL(newConnection()), this, SLOT(handleConnection()));
+ if (!mServer->listen(socketName))
+ qCritical() << "DBServer::start - Unable to open" << socketName << "socket";
+
+ if (mTcpServerPort) {
+ mTcpServer = new QTcpServer(this);
+ connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(handleTcpConnection()));
+ if (!mTcpServer->listen(QHostAddress::Any, mTcpServerPort))
+ qCritical() << QString("Unable to open jsondb remote socket on port %1").arg(mTcpServerPort);
+ }
+ return true;
+}
+
+bool DBServer::start()
+{
+ mJsonDb = new JsonDb(mFileName, this);
+
+ if (!connect(mJsonDb, SIGNAL(notified(QString,QsonMap,QString)),
+ this, SLOT(notified(QString,QsonMap,QString)),
+ Qt::QueuedConnection))
+ qWarning() << "DBServer::start - failed to connect SIGNAL(notified)";
+ if (!connect(mJsonDb, SIGNAL(requestViewUpdate(QString,QString)),
+ this, SLOT(updateView(QString,QString)),
+ Qt::QueuedConnection))
+ qWarning() << "DBServer::start - failed to connect SIGNAL(requestViewUpdate)";
+
+ if (!mJsonDb->open()) {
+ qCritical() << "DBServer::start - Unable to open database";
+ return false;
+ }
+ return true;
+}
+
+bool DBServer::clear()
+{
+ return mJsonDb->clear();
+}
+
+void DBServer::load(const QString &jsonFileName)
+{
+ mJsonDb->load(jsonFileName);
+}
+
+void DBServer::sigHUP()
+{
+ DBG() << "SIGHUP received";
+ mJsonDb->checkValidity();
+}
+
+void DBServer::sigTerm()
+{
+ DBG() << "SIGTERM received";
+ mJsonDb->close();
+ QCoreApplication::exit();
+}
+
+void DBServer::sigINT()
+{
+ DBG() << "SIGINT received";
+ mJsonDb->close();
+ QCoreApplication::exit();
+}
+
+void DBServer::handleConnection()
+{
+ if (QIODevice *connection = mServer->nextPendingConnection()) {
+ //connect(connection, SIGNAL(error(QLocalSocket::LocalSocketError)),
+ // this, SLOT(handleConnectionError()));
+ DBG() << "client connected to jsondb server" << connection;
+ connect(connection, SIGNAL(disconnected()), this, SLOT(removeConnection()));
+ QsonStream *stream = new QsonStream(connection, this);
+ connect(stream, SIGNAL(receive(QsonObject)), this,
+ SLOT(receiveMessage(QsonObject)));
+ mConnections.insert(connection, stream);
+ }
+}
+
+void DBServer::handleTcpConnection()
+{
+ if (QTcpSocket *connection = mTcpServer->nextPendingConnection()) {
+ //connect(connection, SIGNAL(error(QLocalSocket::LocalSocketError)),
+ // this, SLOT(handleConnectionError()));
+ DBG() << "remote client connected to jsondb server" << connection;
+ connect(connection, SIGNAL(disconnected()), this, SLOT(removeConnection()));
+ QsonStream *stream = new QsonStream(connection, this);
+ connect(stream, SIGNAL(receive(QsonObject)), this,
+ SLOT(receiveMessage(QsonObject)));
+ mConnections.insert(connection, stream);
+ }
+}
+
+JsonDbOwner *DBServer::getOwner(QsonStream *stream)
+{
+ QIODevice *device = stream->device();
+ if (!mOwners.contains(device)) {
+ // security hole
+ JsonDbOwner *owner = new JsonDbOwner(this);
+ owner->setOwnerId("unknown app");
+ owner->setDomain("unknown app domain");
+ mOwners[stream->device()] = owner;
+ }
+ Q_ASSERT(mOwners[device]);
+ return mOwners[device];
+}
+
+void DBServer::notified( const QString &notificationId, QsonMap object, const QString &action )
+{
+ DBG() << "DBServer::notified" << "notificationId" << notificationId << "object" << object;
+
+ QsonMap map, obj;
+ obj.insert( JsonDbString::kObjectStr, object );
+ obj.insert( JsonDbString::kActionStr, action );
+ map.insert( JsonDbString::kNotifyStr, obj );
+ map.insert( JsonDbString::kUuidStr, notificationId );
+ QsonStream *stream = mNotifications.value(notificationId);
+ if (stream) {
+ DBG() << "Sending notify" << map;
+ stream->send(map);
+ }
+ else {
+ qWarning("Notification fired on non-existent QsonStream");
+ }
+}
+
+void DBServer::updateView( const QString &viewType, const QString &partitionName )
+{
+ mJsonDb->updateView(viewType, partitionName);
+}
+
+
+void DBServer::processCreate( QsonStream *stream, QsonObject object, int id )
+{
+ QsonMap result;
+ JsonDbOwner *owner = getOwner(stream);
+ switch (object.type()) {
+ case QsonObject::ListType: {
+ // TODO: Properly handle creating notifications from a list
+ QsonList list = object.toList();
+ result = mJsonDb->createList(owner, list);
+ break; }
+ case QsonObject::MapType: {
+ QsonMap obj = object.toMap();
+ result = mJsonDb->create(owner, obj);
+ QString uuid = result.value<QsonMap>(JsonDbString::kResultStr).valueString(JsonDbString::kUuidStr);
+ if ( !uuid.isEmpty() &&
+ obj.valueString(JsonDbString::kTypeStr) == JsonDbString::kNotificationTypeStr )
+ mNotifications.insert(uuid, stream);
+ break; }
+ default:
+ result = createError( JsonDbError::MissingObject, "Create requires list or object" );
+ break;
+ }
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+}
+
+void DBServer::processUpdate( QsonStream *stream, QsonObject object, int id, bool replication)
+{
+ QsonMap result;
+ JsonDbOwner *owner = getOwner(stream);
+ switch (object.type()) {
+ case QsonObject::ListType: {
+ // TODO: Properly handle updating notifications from a list
+ QsonList list = object.toList();
+ result = mJsonDb->updateList(owner, list, QString(), replication); // TOOD: partition
+ break; }
+ case QsonObject::MapType: {
+ QsonMap obj = object.toMap();
+
+ // The user could be changing a _type='notification' object to some other type
+ QString uuid = obj.valueString(JsonDbString::kUuidStr);
+ if (!uuid.isEmpty())
+ mNotifications.remove(uuid);
+
+ result = mJsonDb->update(owner, obj, QString(), replication); // TODO: partition
+ if (result.contains(JsonDbString::kErrorStr) && !result.isNull(JsonDbString::kErrorStr))
+ qCritical() << "UPDATE:" << obj << " Error Message : " << result.subObject(JsonDbString::kErrorStr).valueString(JsonDbString::kMessageStr);
+
+ if ( !uuid.isEmpty() &&
+ obj.valueString(JsonDbString::kTypeStr) == JsonDbString::kNotificationTypeStr )
+ mNotifications.insert(uuid, stream);
+ break; }
+ default:
+ result = createError(JsonDbError::MissingObject, "Update requires list or object");
+ break;
+ }
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+}
+
+void DBServer::processRemove( QsonStream *stream, QsonObject object, int id )
+{
+ JsonDbOwner *owner = getOwner(stream);
+ QsonMap result;
+ switch (object.type()) {
+ case QsonObject::ListType:
+ // TODO: Properly handle removing notifications from a list
+ result = mJsonDb->removeList(owner, object.toList());
+ break;
+ case QsonObject::MapType: {
+ QsonMap obj = object.toMap();
+ if (obj.contains(JsonDbString::kUuidStr)) {
+ // removing a single item
+ QString uuid = obj.valueString(JsonDbString::kUuidStr);
+ mNotifications.remove(uuid);
+ result = mJsonDb->remove(owner, obj);
+ } else {
+ // treat input as a query and remove the result of it
+ if (obj.valueString(JsonDbString::kQueryStr).isEmpty()) {
+ result = createError(JsonDbError::MissingQuery, "Remove requires a query or an object");
+ break;
+ }
+ QsonMap queryResult = mJsonDb->find(owner, obj);
+ if (queryResult.contains(JsonDbString::kErrorStr)
+ && !queryResult.isNull(JsonDbString::kErrorStr)) {
+ result = queryResult;
+ break;
+ }
+ QsonList itemsToRemove = queryResult.subObject(JsonDbString::kResultStr).subList(QLatin1String("data"));
+ // TODO: Properly handle removing notifications from a list
+ result = mJsonDb->removeList(owner, itemsToRemove);
+ }
+ break; }
+ default:
+ result = createError(JsonDbError::MissingObject, "Remove requires list or object");
+ break;
+ }
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+}
+
+void DBServer::processFind( QsonStream *stream, QsonObject object, int id )
+{
+ JsonDbOwner *owner = getOwner(stream);
+ QsonMap result;
+ switch (object.type()) {
+ case QsonObject::MapType:
+ result = mJsonDb->find(owner, object);
+ break;
+ default:
+ result = createError(JsonDbError::InvalidRequest, "Invalid find object");
+ break;
+ }
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+}
+
+void DBServer::processChangesSince( QsonStream *stream, QsonObject object, int id )
+{
+ JsonDbOwner *owner = getOwner(stream);
+ QsonMap result;
+ switch (object.type()) {
+ case QsonObject::MapType:
+ result = mJsonDb->changesSince(owner, object);
+ break;
+ default:
+ result = createError(JsonDbError::InvalidRequest, "Invalid find object");
+ break;
+ }
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+}
+
+bool DBServer::validateToken( QsonStream *stream, const QsonMap &securityObject )
+{
+ bool valid = false;
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ pid_t pid = securityObject.valueUInt("pid");
+ ucred peercred;
+ socklen_t peercredlen = sizeof peercred;
+ int s = 0;
+ QLocalSocket *sock = qobject_cast<QLocalSocket *>(stream->device());
+ if (sock) {
+ s = sock->socketDescriptor();
+ } else {
+ QAbstractSocket *sock = qobject_cast<QAbstractSocket *>(stream->device());
+ if (sock)
+ s = sock->socketDescriptor();
+ }
+ if (!getsockopt(s, SOL_SOCKET, SO_PEERCRED, &peercred, &peercredlen)) {
+ valid = (pid == peercred.pid);
+ }
+#else
+ valid = true;
+#endif
+ return valid;
+}
+
+// This will create a dummy owner. Used only when the policies are not enforced.
+// When policies are not enforced the JsonDbOwner allows access to everybody.
+void DBServer::createDummyOwner( QsonStream *stream, int id )
+{
+ if (gEnforceAccessControlPolicies)
+ return;
+
+ JsonDbOwner *owner = new JsonDbOwner(this);
+ owner->setOwnerId(QString("unknown app"));
+ owner->setDomain(QString("unknown domain"));
+ QsonMap capabilities;
+ owner->setCapabilities(capabilities, mJsonDb);
+ mOwners[stream->device()] = owner;
+
+ QsonMap result;
+ result.insert( JsonDbString::kResultStr, QLatin1String("Okay") );
+ result.insert( JsonDbString::kErrorStr, QsonObject::NullValue);
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+}
+
+void DBServer::processToken( QsonStream *stream, QVariant object, int id )
+{
+ if (!gEnforceAccessControlPolicies) {
+ // We are not enforcing policies here, allow 'token' requests
+ // from all applications.
+ // ### TODO: We will have to remove this afterwards
+ createDummyOwner(stream, id);
+ return;
+ }
+
+ bool tokenValidated = false;
+ QsonMap result;
+ QString errorStr(QLatin1String("Invalid token"));
+ if (object.type() == QVariant::String) {
+ QString token = object.toString();
+
+ // grant all access to applications with the master token.
+ if (!mMasterToken.isEmpty() && mMasterToken == token) {
+ JsonDbOwner *owner = new JsonDbOwner(this);
+ owner->setAllowAll(true);
+ owner->setStorageQuota(-1);
+ mOwners[stream->device()] = owner;
+ tokenValidated = true;
+ } else {
+ QsonMap request;
+ request.insert(JsonDbString::kQueryStr, (QString("[?%1=\"com.nokia.mp.core.Security\"][?%2=\"%3\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg(JsonDbString::kTokenStr).arg(token)));
+
+ QsonMap result = mJsonDb->find(mJsonDb->owner(), request);
+ QsonList securityObjects = result.subObject(JsonDbString::kResultStr).subList(JsonDbString::kDataStr);
+ if (securityObjects.size() == 1) {
+ QsonMap securityObject = securityObjects.at<QsonMap>(0);
+ if (validateToken(stream, securityObject)) {
+ QString identifier = securityObject.valueString("identifier");
+ QString domain = securityObject.valueString("domain");
+ QsonMap capabilities = securityObject.subObject("capabilities");
+
+ JsonDbOwner *owner = new JsonDbOwner(this);
+ owner->setOwnerId(identifier);
+ owner->setDomain(domain);
+ owner->setCapabilities(capabilities, mJsonDb);
+
+ QStringList keys = capabilities.keys();
+ if (keys.contains("quotas")) {
+ QsonMap quotas = capabilities.subObject("quotas");
+ int storageQuota = quotas.valueInt("storage");
+ owner->setStorageQuota(storageQuota);
+ }
+ mOwners[stream->device()] = owner;
+ tokenValidated = true;
+ }
+ } else {
+ if (securityObjects.size()) {
+ errorStr = QLatin1String("Wrong number of security objects found.");
+ DBG() << Q_FUNC_INFO << "Wrong number of security objects found." << securityObjects.size();
+ } else {
+ errorStr = QLatin1String("No security object for token");
+ DBG() << Q_FUNC_INFO << "No security object for token" << token << "Using default owner and access control";
+ }
+ }
+ }
+ }
+ if (tokenValidated) {
+ QsonMap resultObject;
+ resultObject.insert(JsonDbString::kResultStr, QLatin1String("Okay"));
+ result.insert(JsonDbString::kResultStr, resultObject);
+ result.insert(JsonDbString::kErrorStr, QsonObject::NullValue);
+ } else {
+ result = createError(JsonDbError::InvalidRequest, errorStr);
+ }
+ result.insert(JsonDbString::kIdStr, id);
+ stream->send(result);
+ // in case of an invalid token, close the connection
+ if (!tokenValidated) {
+ QLocalSocket *socket = qobject_cast<QLocalSocket *>(stream->device());
+ if (socket) {
+ socket->disconnectFromServer();
+ } else {
+ QTcpSocket *tcpSocket = qobject_cast<QTcpSocket *>(stream->device());
+ if (tcpSocket)
+ tcpSocket->disconnectFromHost();
+ }
+ }
+}
+
+void DBServer::receiveMessage(QsonObject message)
+{
+ QsonMap map = message.toMap();
+ QsonStream *stream = qobject_cast<QsonStream *>(sender());
+
+ QString action = map.valueString(JsonDbString::kActionStr);
+ QsonObject object = map.value<QsonElement>(JsonDbString::kObjectStr);
+ int id = map.valueInt(JsonDbString::kIdStr);
+
+ QElapsedTimer timer;
+ if (gPerformanceLog)
+ timer.start();
+
+ if ( action == JsonDbString::kCreateStr )
+ processCreate( stream, object, id );
+ else if ( action == JsonDbString::kUpdateStr )
+ processUpdate( stream, object, id, map.valueBool("replication"));
+ else if ( action == JsonDbString::kRemoveStr )
+ processRemove( stream, object, id );
+ else if ( action == JsonDbString::kFindStr )
+ processFind( stream, object, id );
+ else if ( action == JsonDbString::kTokenStr )
+ processToken( stream, qsonToVariant(map.value<QsonElement>(JsonDbString::kObjectStr)), id );
+ else if (action == JsonDbString::kChangesSinceStr)
+ processChangesSince(stream, object, id);
+ else {
+ const QMetaObject *mo = mJsonDb->metaObject();
+ QsonMap result;
+ // DBG() << QString("using QMetaObject to invoke method %1").arg(action);
+ if (mo->invokeMethod(mJsonDb, action.toLatin1().data(),
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QsonObject, result),
+ Q_ARG(JsonDbOwner *, getOwner(stream)),
+ Q_ARG(QsonObject, object.toMap()))) {
+ result.insert( JsonDbString::kIdStr, id );
+ stream->send(result);
+ } else {
+ sendError(stream, JsonDbError::InvalidRequest,
+ QString("Invalid request '%1'").arg(action), id);
+ return;
+ }
+ }
+ if (gPerformanceLog)
+ qDebug() << "jsondb" << "processed" << action << "ms" << timer.elapsed();
+}
+
+void DBServer::handleConnectionError()
+{
+ QIODevice *connection = qobject_cast<QIODevice *>(sender());
+ qWarning() << connection->errorString();
+}
+
+void DBServer::removeConnection()
+{
+ QIODevice *connection = qobject_cast<QIODevice *>(sender());
+ JsonDbOwner *owner = mOwners[connection];
+ QMutableMapIterator<QString, QsonStream *> iter(mNotifications);
+ while (iter.hasNext()) {
+ iter.next();
+ if (iter.value()
+ && (iter.value()->device() == connection)) {
+ QString notificationId = iter.key();
+ QsonMap notificationObject;
+ notificationObject.insert(JsonDbString::kUuidStr, notificationId);
+ mJsonDb->remove(owner, notificationObject);
+ mNotifications.remove(notificationId);
+ }
+ }
+
+ if (mConnections.contains(connection)) {
+ QsonStream *stream = mConnections.value(connection);
+ if (stream)
+ stream->deleteLater();
+
+ mConnections.remove(connection);
+ }
+ if (mOwners.contains(connection)) {
+ JsonDbOwner *owner =mOwners.value(connection);
+ if (owner)
+ owner->deleteLater();
+ mOwners.remove(connection);
+ }
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/dbserver.h b/src/daemon/dbserver.h
new file mode 100644
index 00000000..3d7e24ab
--- /dev/null
+++ b/src/daemon/dbserver.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DBSERVER_H
+#define DBSERVER_H
+
+#include <QObject>
+#include <QVariant>
+#include <QAbstractSocket>
+
+#include "qsonstream.h"
+#include "notification.h"
+#include "jsondb.h"
+
+class QIODevice;
+class QLocalServer;
+class QTcpServer;
+
+namespace QtAddOn { namespace JsonDb {
+
+class DBServer : public QObject
+{
+ Q_OBJECT
+public:
+ DBServer(const QString &fileName, QObject *parent = 0);
+ void setTcpServerPort(quint16 port) { mTcpServerPort = port; }
+ quint16 tcpServerPort() const { return mTcpServerPort; }
+
+ bool start();
+ bool socket();
+ bool clear();
+ void load(const QString &jsonFileName);
+
+public slots:
+ void sigTerm();
+ void sigHUP();
+ void sigINT();
+
+protected slots:
+ void handleConnection();
+ void handleTcpConnection();
+ void receiveMessage( QsonObject );
+ void handleConnectionError();
+ void removeConnection();
+
+ void notified( const QString &id, QsonMap object, const QString &action );
+ void updateView( const QString &viewType, const QString &partitionName );
+
+private:
+ void processFind( QsonStream *stream, QsonObject object, int id );
+ void processCreate( QsonStream *stream, QsonObject object, int id );
+ void processUpdate( QsonStream *stream, QsonObject object, int id, bool replication = false );
+ void processRemove( QsonStream *stream, QsonObject object, int id );
+ void processToken( QsonStream *stream, QVariant object, int id );
+ void processChangesSince( QsonStream *stream, QsonObject object, int id );
+
+ JsonDbOwner *getOwner( QsonStream *stream );
+ bool validateToken( QsonStream *stream, const QsonMap &securityObject );
+ void createDummyOwner( QsonStream *stream, int id );
+
+ quint16 mTcpServerPort;
+ QLocalServer *mServer;
+ QTcpServer *mTcpServer;
+ QMap<QIODevice*,QsonStream *> mConnections;
+ QMap<QIODevice*,JsonDbOwner*> mOwners;
+ QMap<QString,QsonStream *> mNotifications; // maps notification Id to socket
+ JsonDb *mJsonDb;
+ QString mMasterToken;
+ QString mFileName;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // DBSERVER_H
diff --git a/src/daemon/jsondb-map-reduce.cpp b/src/daemon/jsondb-map-reduce.cpp
new file mode 100644
index 00000000..4033ff6f
--- /dev/null
+++ b/src/daemon/jsondb-map-reduce.cpp
@@ -0,0 +1,757 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-trace.h"
+
+#include <QDebug>
+#include <QRegExp>
+#include <QJSValue>
+#include <QStringList>
+
+#include <QtJsonDbQson/private/qson_p.h>
+#include "qsonconversion.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "jsondbbtreestorage.h"
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+#include "json.h"
+
+#include "jsondb.h"
+#include "jsondb-proxy.h"
+#include "objecttable.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+void JsonDb::initMap(const QString &partition)
+{
+ if (gVerbose) qDebug() << "Initializing views on partition" << partition;
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ {
+ QsonMap getObjectResponse = getObject(JsonDbString::kTypeStr, "Map", partition);
+ QsonList mrdList = getObjectResponse.subList("result");
+ for (int i = 0; i < mrdList.size(); ++i) {
+ QsonMap mrd = mrdList.at<QsonMap>(i);
+ createMapDefinition(mrd, false, partition);
+ storage->addView(mrd.value<QString>("targetType"));
+ }
+ }
+ {
+ QsonMap getObjectResponse = getObject(JsonDbString::kTypeStr, "Reduce", partition);
+ QsonList mrdList = getObjectResponse.subList("result");
+ for (int i = 0; i < mrdList.size(); ++i) {
+ QsonMap mrd = mrdList.at<QsonMap>(i);
+ createReduceDefinition(mrd, false, partition);
+ storage->addView(mrd.value<QString>("targetType"));
+ }
+ }
+}
+
+void JsonDb::createMapDefinition(QsonMap mapDefinition, bool firstTime, const QString &partition)
+{
+ QString targetType = mapDefinition.valueString("targetType");
+ QString sourceType = mapDefinition.valueString("sourceType");
+
+ if (gVerbose)
+ qDebug() << "createMapDefinition" << sourceType << targetType;
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ storage->addView(targetType);
+ storage->addIndex("sourceUuids.*", "string", targetType);
+ storage->addIndex("key", "string", targetType);
+ storage->addIndex("mapUuid", "string", targetType);
+
+ JsonDbMapDefinition *def = new JsonDbMapDefinition(this, mOwner, partition, mapDefinition, this);
+ mMapDefinitionsBySource.insert(sourceType, def);
+ mMapDefinitionsByTarget.insert(targetType, def);
+
+ if (firstTime && def->isActive()) {
+ QsonMap getObjectResponse = getObject(JsonDbString::kTypeStr, sourceType);
+ QsonList objects = getObjectResponse.subList("result");
+ for (int i = 0; i < objects.size(); i++)
+ def->mapObject(objects.objectAt(i));
+ }
+}
+
+void JsonDb::removeMapDefinition(QsonMap mapDefinition)
+{
+ QString targetType = mapDefinition.valueString("targetType");
+ QString sourceType = mapDefinition.valueString("sourceType");
+
+ JsonDbMapDefinition *def = 0;
+ foreach (JsonDbMapDefinition *d, mMapDefinitionsBySource.values(sourceType)) {
+ if (d->uuid() == mapDefinition.valueString(JsonDbString::kUuidStr)) {
+ def = d;
+ mMapDefinitionsBySource.remove(sourceType, def);
+ mMapDefinitionsByTarget.remove(targetType, def);
+ break;
+ }
+ }
+
+ // remove the output objects
+ QsonMap getObjectResponse = getObject("mapUuid", mapDefinition.valueString(JsonDbString::kUuidStr), targetType);
+ QsonList objects = getObjectResponse.subList("result");
+ for (int i = 0; i < objects.size(); i++)
+ removeViewObject(mOwner, objects.objectAt(i));
+}
+
+void JsonDb::createReduceDefinition(QsonMap reduceDefinition, bool firstTime, const QString &partition)
+{
+ QString targetType = reduceDefinition.valueString("targetType");
+ QString sourceType = reduceDefinition.valueString("sourceType");
+
+ if (gDebug)
+ qDebug() << "createReduceDefinition" << targetType << sourceType;
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ storage->addView(targetType);
+
+ JsonDbReduceDefinition *def = new JsonDbReduceDefinition(this, mOwner, partition, reduceDefinition, this);
+ mReduceDefinitionsBySource.insert(sourceType, def);
+ mReduceDefinitionsByTarget.insert(targetType, def);
+
+ storage->addIndex("sourceUuids.*", "string", targetType);
+ storage->addIndex(def->sourceKeyName(), "string", sourceType);
+ storage->addIndex("key", "string", targetType);
+ storage->addIndex("reduceUuid", "string", targetType);
+
+ if (firstTime && def->isActive()) {
+ QsonMap getObjectResponse = getObject(JsonDbString::kTypeStr, sourceType);
+ QsonList objects = getObjectResponse.subList("result");
+ for (int i = 0; i < objects.size(); i++)
+ def->updateObject(QsonMap(), objects.objectAt(i));
+ }
+}
+
+void JsonDb::removeReduceDefinition(QsonMap reduceDefinition)
+{
+ QString targetType = reduceDefinition.valueString("targetType");
+ QString sourceType = reduceDefinition.valueString("sourceType");
+
+ if (gVerbose)
+ qDebug() << "removeReduceDefinition" << sourceType << targetType;
+
+ JsonDbReduceDefinition *def = 0;
+ foreach (JsonDbReduceDefinition *d, mReduceDefinitionsBySource.values(sourceType)) {
+ if (d->uuid() == reduceDefinition.valueString(JsonDbString::kUuidStr)) {
+ def = d;
+ mReduceDefinitionsBySource.remove(def->sourceType(), def);
+ mReduceDefinitionsByTarget.remove(def->targetType(), def);
+ break;
+ }
+ }
+ // remove the output objects
+ QsonMap getObjectResponse = getObject("reduceUuid", reduceDefinition.valueString(JsonDbString::kUuidStr), targetType);
+ QsonList objects = getObjectResponse.subList("result");
+ for (int i = 0; i < objects.size(); i++)
+ removeViewObject(mOwner, objects.objectAt(i));
+ //TODO: actually remove the table
+}
+
+void JsonDb::updateView(const QString &viewType, const QString &partitionName)
+{
+ if (viewType.isEmpty())
+ return;
+ JsonDbBtreeStorage *partition = findPartition(partitionName);
+ ObjectTable *objectTable = partition->mainObjectTable();
+ ObjectTable *targetTable = partition->findObjectTable(viewType);
+ if ((objectTable == targetTable)
+ || (objectTable->stateNumber() == targetTable->stateNumber()))
+ return;
+
+ updateMap(viewType, partitionName);
+ updateReduce(viewType, partitionName);
+}
+
+void JsonDb::updateMap(const QString &viewType, const QString &partitionName)
+{
+ JsonDbBtreeStorage *partition = findPartition(partitionName);
+ ObjectTable *targetTable = partition->findObjectTable(viewType);
+ quint32 targetStateNumber = qMax(1u, targetTable->stateNumber());
+ if (0) qDebug() << "JsonDb::updateMap" << viewType << targetStateNumber << mViewsUpdating.contains(viewType) << "targetStateNumber" << targetStateNumber;
+ if (mViewsUpdating.contains(viewType))
+ return;
+ mViewsUpdating.insert(viewType);
+
+ QHash<QString,JsonDbMapDefinition*> mapDefinitions;
+ QSet<ObjectTable*> sourceTables;
+ QMultiMap<ObjectTable*,QString> objectTableSourceType;
+ QMap<QString, QsonMap> addedMapDefinitions; // uuid -> added definition
+ QMap<QString, QsonMap> removedMapDefinitions; // uuid -> removed definition
+ quint32 endStateNumber =
+ findUpdatedMapReduceDefinitions(partition, JsonDbString::kMapTypeStr,
+ viewType, targetStateNumber, addedMapDefinitions, removedMapDefinitions);
+ for (QMap<QString,JsonDbMapDefinition*>::const_iterator it = mMapDefinitionsByTarget.find(viewType);
+ (it != mMapDefinitionsByTarget.end() && it.key() == viewType);
+ ++it) {
+ JsonDbMapDefinition *def = it.value();
+ const QString &sourceType = def->sourceType();
+ ObjectTable *sourceTable = partition->findObjectTable(sourceType);
+
+ sourceTables.insert(sourceTable);
+ objectTableSourceType.insert(sourceTable, sourceType);
+ mapDefinitions.insert(sourceType, def);
+ }
+ if (sourceTables.isEmpty() && addedMapDefinitions.isEmpty() && removedMapDefinitions.isEmpty()) {
+ mViewsUpdating.remove(viewType);
+ return;
+ }
+
+ for (QMap<ObjectTable*,QString>::const_iterator it = objectTableSourceType.begin();
+ it != objectTableSourceType.end();
+ ++it) {
+ QString sourceType = it.value();
+ // make sure the source is updated
+ updateView(sourceType);
+
+ if (!endStateNumber) {
+ ObjectTable *sourceTable = it.key();
+ quint32 sourceStateNumber = sourceTable->stateNumber();
+ endStateNumber = sourceStateNumber;
+ }
+ }
+
+ // this transaction private to targetTable
+ targetTable->begin();
+
+ for (QMap<QString,QsonMap>::const_iterator it = removedMapDefinitions.begin();
+ it != removedMapDefinitions.end();
+ ++it) {
+ QsonMap def = it.value();
+ removeMapDefinition(def);
+ }
+ for (QMap<QString,QsonMap>::const_iterator it = addedMapDefinitions.begin();
+ it != addedMapDefinitions.end();
+ ++it) {
+ QsonMap def = it.value();
+ createMapDefinition(def, true, partitionName);
+ }
+
+ for (QSet<ObjectTable*>::const_iterator it = sourceTables.begin();
+ it != sourceTables.end();
+ ++it) {
+ ObjectTable *sourceTable = *it;
+ QStringList sourceTypes = objectTableSourceType.values(sourceTable);
+ QsonMap changes = sourceTable->changesSince(targetStateNumber).subObject("result");
+ quint32 count = changes.valueInt("count", 0);
+ QsonList changeList = changes.subList("changes");
+ for (quint32 i = 0; i < count; i++) {
+ QsonMap change = changeList.objectAt(i).toMap();
+ QsonMap before = change.subObject("before").toMap();
+ QsonMap after = change.subObject("after").toMap();
+ if (!before.isEmpty()) {
+ QString sourceType = before.valueString(JsonDbString::kTypeStr);
+ if (sourceTypes.contains(sourceType)) {
+ mapDefinitions.value(sourceType)->unmapObject(before);
+ }
+ }
+ if (!after.isEmpty()) {
+ QString sourceType = after.valueString(JsonDbString::kTypeStr);
+ if (sourceTypes.contains(sourceType)) {
+ Q_ASSERT(mapDefinitions.value(sourceType));
+ mapDefinitions.value(sourceType)->mapObject(after);
+ }
+ }
+ }
+ }
+
+ targetTable->commit(endStateNumber);
+ mViewsUpdating.remove(viewType);
+}
+
+quint32 JsonDb::findUpdatedMapReduceDefinitions(JsonDbBtreeStorage *partition, const QString &definitionType,
+ const QString &viewType, quint32 targetStateNumber,
+ QMap<QString,QsonMap> &addedDefinitions, QMap<QString,QsonMap> &removedDefinitions) const
+{
+ ObjectTable *objectTable = partition->findObjectTable(definitionType);
+ quint32 stateNumber = objectTable->stateNumber();
+ if (stateNumber == targetStateNumber)
+ return stateNumber;
+ QSet<QString> limitTypes;
+ limitTypes << definitionType;
+ QsonMap changes = objectTable->changesSince(targetStateNumber, limitTypes).subObject("result");
+ quint32 count = changes.valueInt("count", 0);
+ QsonList changeList = changes.subList("changes");
+ for (quint32 i = 0; i < count; i++) {
+ QsonMap change = changeList.objectAt(i).toMap();
+ if (change.contains("before")) {
+ QsonMap before = change.subObject("before").toMap();
+ if ((before.valueString(JsonDbString::kTypeStr) == definitionType)
+ && (before.valueString("targetType") == viewType))
+ removedDefinitions.insert(before.valueString(JsonDbString::kUuidStr), before);
+ }
+ if (change.contains("after")) {
+ QsonMap after = change.subObject("after").toMap();
+ if ((after.valueString(JsonDbString::kTypeStr) == definitionType)
+ && (after.valueString("targetType") == viewType))
+ addedDefinitions.insert(after.valueString(JsonDbString::kUuidStr), after);
+ }
+ }
+ return stateNumber;
+}
+
+void JsonDb::updateReduce(const QString &viewType, const QString &partitionName)
+{
+ //Q_ASSERT(mReduceDefinitionsByTarget.contains(viewType));
+ JsonDbBtreeStorage *partition = findPartition(partitionName);
+ ObjectTable *targetTable = partition->findObjectTable(viewType);
+ quint32 targetStateNumber = qMax(1u, targetTable->stateNumber());
+ if (0) qDebug() << "JsonDb::updateReduce" << viewType << targetStateNumber << mViewsUpdating.contains(viewType);
+ if (mViewsUpdating.contains(viewType))
+ return;
+ mViewsUpdating.insert(viewType);
+ QHash<QString,JsonDbReduceDefinition*> reduceDefinitions;
+ QSet<ObjectTable*> sourceTables;
+ QMultiMap<ObjectTable*,QString> objectTableSourceType;
+ QMap<QString, QsonMap> addedReduceDefinitions; // uuid -> added definition
+ QMap<QString, QsonMap> removedReduceDefinitions; // uuid -> removed definition
+ quint32 endStateNumber =
+ findUpdatedMapReduceDefinitions(partition, JsonDbString::kReduceTypeStr,
+ viewType, targetStateNumber, addedReduceDefinitions, removedReduceDefinitions);
+ for (QMap<QString,JsonDbReduceDefinition*>::const_iterator it = mReduceDefinitionsByTarget.find(viewType);
+ (it != mReduceDefinitionsByTarget.end() && it.key() == viewType);
+ ++it) {
+ JsonDbReduceDefinition *def = it.value();
+ if (addedReduceDefinitions.contains(def->uuid()) || removedReduceDefinitions.contains(def->uuid()))
+ continue;
+ const QString &sourceType = def->sourceType();
+ ObjectTable *sourceTable = partition->findObjectTable(sourceType);
+
+ sourceTables.insert(sourceTable);
+ objectTableSourceType.insert(sourceTable, sourceType);
+ reduceDefinitions.insert(sourceType, def);
+ }
+ if (sourceTables.isEmpty() && addedReduceDefinitions.isEmpty() && removedReduceDefinitions.isEmpty()) {
+ mViewsUpdating.remove(viewType);
+ return;
+ }
+
+ for (QMap<ObjectTable*,QString>::const_iterator it = objectTableSourceType.begin();
+ it != objectTableSourceType.end();
+ ++it) {
+ QString sourceType = it.value();
+ // make sure the source is updated
+ updateView(sourceType);
+
+ if (!endStateNumber) {
+ ObjectTable *sourceTable = it.key();
+ quint32 sourceStateNumber = sourceTable->stateNumber();
+ endStateNumber = sourceStateNumber;
+ }
+ }
+
+ // transaction private to this objecttable
+ targetTable->begin();
+
+ for (QMap<QString,QsonMap>::const_iterator it = removedReduceDefinitions.begin();
+ it != removedReduceDefinitions.end();
+ ++it) {
+ QsonMap def = it.value();
+ removeReduceDefinition(def);
+ }
+ for (QMap<QString,QsonMap>::const_iterator it = addedReduceDefinitions.begin();
+ it != addedReduceDefinitions.end();
+ ++it) {
+ QsonMap def = it.value();
+ createReduceDefinition(def, true, partitionName);
+ }
+
+ for (QSet<ObjectTable*>::const_iterator it = sourceTables.begin();
+ it != sourceTables.end();
+ ++it) {
+ ObjectTable *sourceTable = *it;
+ QStringList sourceTypes = objectTableSourceType.values(sourceTable);
+ QsonMap changes = sourceTable->changesSince(targetStateNumber).subObject("result");
+ quint32 count = changes.valueInt("count", 0);
+ QsonList changeList = changes.subList("changes");
+ for (quint32 i = 0; i < count; i++) {
+ QsonMap change = changeList.objectAt(i).toMap();
+ QsonMap before = change.subObject("before").toMap();
+ QsonMap after = change.subObject("after").toMap();
+ QString sourceType = before.valueString(JsonDbString::kTypeStr);
+ if (sourceTypes.contains(sourceType))
+ reduceDefinitions.value(sourceType)->updateObject(before, after);
+ }
+ }
+
+ targetTable->commit(endStateNumber);
+ mViewsUpdating.remove(viewType);
+}
+
+JsonDbMapDefinition::JsonDbMapDefinition(JsonDb *jsonDb, JsonDbOwner *owner, const QString &partition, QsonMap definition, QObject *parent)
+ : QObject(parent)
+ , mJsonDb(jsonDb)
+ , mPartition(partition)
+ , mOwner(owner)
+ , mDefinition(definition)
+ , mScriptEngine(new QJSEngine(this))
+ , mUuid(definition.valueString(JsonDbString::kUuidStr))
+ , mTargetType(definition.valueString("targetType"))
+ , mSourceType(definition.valueString("sourceType"))
+ , mTargetTable(jsonDb->findPartition(partition)->findObjectTable(mTargetType))
+ , mSourceTable(jsonDb->findPartition(partition)->findObjectTable(mSourceType))
+{
+
+ mJsonDbProxy = new JsonDbMapProxy(mOwner, mJsonDb, this);
+ connect(mJsonDbProxy, SIGNAL(lookupRequested(QString,QJSValue,QJSValue,QJSValue)),
+ this, SLOT(lookupRequested(QString,QJSValue,QJSValue,QJSValue)));
+ connect(mJsonDbProxy, SIGNAL(viewObjectEmitted(QString,QJSValue)),
+ this, SLOT(viewObjectEmitted(QString,QJSValue)));
+
+ QJSValue globalObject = mScriptEngine->globalObject();
+ globalObject.setProperty("jsondb", mScriptEngine->newQObject(mJsonDbProxy));
+ globalObject.setProperty("console", mScriptEngine->newQObject(new Console()));
+
+ QString script = mDefinition.valueString("map");
+ Q_ASSERT(!script.isEmpty());
+
+ mMapFunction = mScriptEngine->evaluate(QString("var %1 = %2; %1;").arg("map").arg(script));
+ if (mMapFunction.isError() || !mMapFunction.isFunction())
+ setError( "Unable to parse map function: " + mMapFunction.toString());
+}
+
+void JsonDbMapDefinition::mapObject(QsonMap object)
+{
+ QJSValue globalObject = mScriptEngine->globalObject();
+
+ QJSValue sv = qsonToJSValue(object, mScriptEngine);
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ mSourceUuids.clear();
+ mSourceUuids.append(uuid);
+ QJSValue mapped;
+ mJsonDbProxy->clear();
+ Q_ASSERT(mMapFunction.isFunction());
+
+ QJSValueList mapArgs;
+ mapArgs << sv;
+ mapped = mMapFunction.call(globalObject, mapArgs);
+
+ if (mapped.isError())
+ setError("Error executing map function: " + mapped.toString());
+}
+
+void JsonDbMapDefinition::unmapObject(const QsonMap &object)
+{
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ QsonMap getObjectResponse = mTargetTable->getObject("sourceUuids.*", uuid, mTargetType);
+ QsonList dependentObjects = getObjectResponse.subList("result");
+
+ for (int i = 0; i < dependentObjects.size(); i++) {
+ QsonMap dependentObject = dependentObjects.objectAt(i).toMap();
+ if (dependentObject.valueString(JsonDbString::kTypeStr) != mTargetType)
+ continue;
+ mJsonDb->removeViewObject(mOwner, dependentObject);
+ QStringList sourceUuids = dependentObject.value<QsonList>("sourceUuids").toStringList();
+ int pos = sourceUuids.indexOf(uuid);
+ if (pos > 0) {
+ // TODO: should queue this for later
+ QString remapUuid = sourceUuids[0];
+
+ QsonMap getObjectResponse = mJsonDb->getObject(JsonDbString::kUuidStr, remapUuid);
+ if (getObjectResponse.valueInt("count", 0) == 1) {
+ QsonList objectsToUpdateList = getObjectResponse.subList("result");
+ mapObject(objectsToUpdateList.objectAt(0));
+ }
+ }
+ }
+}
+
+void JsonDbMapDefinition::lookupRequested(const QString &findKey, const QJSValue &findValue, const QJSValue &objectType, const QJSValue &context)
+{
+ QsonMap getObjectResponse =
+ mSourceTable->getObject(findKey, findValue.toVariant(), objectType.toString());
+ QsonList objectList = getObjectResponse.subList("result");
+ for (int i = 0; i < objectList.size(); ++i) {
+ QsonMap object = objectList.at<QsonMap>(i);
+ const QString uuid = object.valueString(JsonDbString::kUuidStr);
+ mSourceUuids.append(uuid);
+ QJSValueList mapArgs;
+ QJSValue sv = qsonToJSValue(object, mScriptEngine);
+
+ mapArgs << sv << context;
+ QJSValue globalObject = mScriptEngine->globalObject();
+ QJSValue mapped = mMapFunction.call(globalObject, mapArgs);
+
+ if (mapped.isError())
+ setError("Error executing map function during lookup: " + mapped.toString());
+
+ mSourceUuids.removeLast();
+ }
+ if (objectType.isUndefined()) {
+ JsonDbBtreeStorage *storage = mJsonDb->findPartition(kDefaultPartitionName);
+ for (QHash<QString, QPointer<ObjectTable> >::const_iterator it = storage->mViews.begin();
+ it != storage->mViews.end();
+ ++it) {
+ ObjectTable *objectTable = it.value();
+ QsonMap getObjectResponse = objectTable->getObject(findKey, findValue.toVariant(), objectType.toString());
+ QsonList objectList = getObjectResponse.subList("result");
+ for (int i = 0; i < objectList.size(); ++i) {
+ QsonMap object = objectList.at<QsonMap>(i);
+ const QString uuid = object.valueString(JsonDbString::kUuidStr);
+ mSourceUuids.append(uuid);
+ QJSValueList mapArgs;
+ QJSValue sv = qsonToJSValue(object, mScriptEngine);
+
+ mapArgs << sv << context;
+ QJSValue globalObject = mScriptEngine->globalObject();
+ QJSValue mapped = mMapFunction.call(globalObject, mapArgs);
+
+ if (mapped.isError())
+ setError("Error executing map function during lookup: " + mapped.toString());
+
+ mSourceUuids.removeLast();
+ }
+ }
+ }
+}
+
+
+void JsonDbMapDefinition::viewObjectEmitted(const QString &key, const QJSValue &value)
+{
+ if (key.isEmpty()) {
+ setError("Empty key provided to emitViewObject");
+ return;
+ }
+
+ QsonMap newItem;
+ newItem.insert(JsonDbString::kTypeStr, mTargetType);
+ newItem.insert("key", key);
+ newItem.insert("value", variantToQson(value.toVariant()));
+ QsonList sourceUuids;
+ foreach (const QString &str, mSourceUuids)
+ sourceUuids.append(str);
+ newItem.insert("sourceUuids", sourceUuids);
+ newItem.insert("mapUuid", mUuid);
+
+ QsonMap res = mJsonDb->createViewObject(mOwner, newItem);
+ if (JsonDb::responseIsError(res))
+ setError("Error executing map function during emitViewObject: " +
+ res.subObject(JsonDbString::kErrorStr).valueString(JsonDbString::kMessageStr));
+}
+
+bool JsonDbMapDefinition::isActive() const
+{
+ return mDefinition.isNull(JsonDbString::kActiveStr) || mDefinition.valueBool(JsonDbString::kActiveStr);
+}
+
+void JsonDbMapDefinition::setError(const QString &errorMsg)
+{
+ mDefinition.insert(JsonDbString::kActiveStr, false);
+ mDefinition.insert(JsonDbString::kErrorStr, errorMsg);
+ if (JsonDbBtreeStorage *storage = mJsonDb->findPartition(mPartition)) {
+ WithTransaction transaction(storage, "JsonDbMapDefinition::setError");
+ ObjectTable *objectTable = storage->findObjectTable(JsonDbString::kMapTypeStr);
+ transaction.addObjectTable(objectTable);
+ storage->updatePersistentObject(mDefinition);
+ transaction.commit();
+ }
+}
+
+JsonDbReduceDefinition::JsonDbReduceDefinition(JsonDb *jsonDb, JsonDbOwner *owner, const QString &partition,
+ QsonMap definition, QObject *parent)
+ : QObject(parent)
+ , mJsonDb(jsonDb)
+ , mOwner(owner)
+ , mPartition(partition)
+ , mDefinition(definition)
+ , mScriptEngine(new QJSEngine(this))
+ , mUuid(mDefinition.valueString(JsonDbString::kUuidStr))
+ , mTargetType(mDefinition.valueString("targetType"))
+ , mSourceType(mDefinition.valueString("sourceType"))
+ , mSourceKeyName(mDefinition.contains("sourceKeyName") ? mDefinition.valueString("sourceKeyName") : QString("key"))
+{
+ Q_ASSERT(!mDefinition.valueString("add").isEmpty());
+ Q_ASSERT(!mDefinition.valueString("subtract").isEmpty());
+
+ QJSValue globalObject = mScriptEngine->globalObject();
+ globalObject.setProperty("console", mScriptEngine->newQObject(new Console()));
+
+ QString script = mDefinition.valueString("add");
+ mAddFunction = mScriptEngine->evaluate(QString("var %1 = %2; %1;").arg("add").arg(script));
+
+ if (mAddFunction.isError() || !mAddFunction.isFunction()) {
+ setError("Unable to parse add function: " + mAddFunction.toString());
+ return;
+ }
+
+ script = mDefinition.valueString("subtract");
+ mSubtractFunction = mScriptEngine->evaluate(QString("var %1 = %2; %1;").arg("subtract").arg(script));
+
+ if (mSubtractFunction.isError() || !mSubtractFunction.isFunction())
+ setError("Unable to parse subtract function: " + mSubtractFunction.toString());
+}
+
+void JsonDbReduceDefinition::updateObject(QsonMap before, QsonMap after)
+{
+ Q_ASSERT(mAddFunction.isFunction());
+
+ QString beforeKeyValue = mSourceKeyName.contains(".") ? JsonDb::propertyLookup(before, mSourceKeyName).toString()
+ : before.valueString(mSourceKeyName);
+ QString afterKeyValue = mSourceKeyName.contains(".") ? JsonDb::propertyLookup(after, mSourceKeyName).toString()
+ : after.valueString(mSourceKeyName);
+
+ if (!after.isEmpty() && (beforeKeyValue != afterKeyValue)) {
+ // do a subtract only on the before key
+ //qDebug() << "beforeKeyValue" << beforeKeyValue << "afterKeyValue" << afterKeyValue;
+ //qDebug() << "before" << before << endl << "after" << after << endl;
+ if (!beforeKeyValue.isEmpty())
+ updateObject(before, QsonMap());
+
+ // and then continue here with the add with the after key
+ before = QsonMap();
+ }
+
+ const QString keyValue(after.isEmpty() ? beforeKeyValue : afterKeyValue);
+ if (keyValue.isEmpty())
+ return;
+
+ QsonMap getObjectResponse = mJsonDb->getObject("key", keyValue, mTargetType);
+ QsonMap previousResult;
+ QsonObject previousValue;
+
+ QsonList previousResults = getObjectResponse.subList("result");
+ for (int k = 0; k < previousResults.size(); ++k) {
+ QsonMap previous = previousResults.at<QsonMap>(k);
+ if (previous.valueString("reduceUuid") == mUuid) {
+ previousResult = previous;
+
+ if (!previousResult.subObject("value").isEmpty())
+ previousValue = previousResult.subObject("value");
+ break;
+ }
+ }
+
+ QsonObject value = previousValue;
+ if (!before.isEmpty())
+ value = subtractObject(keyValue, value, before);
+ if (!after.isEmpty())
+ value = addObject(keyValue, value, after);
+
+ QsonMap res;
+ if (!previousResult.valueString(JsonDbString::kUuidStr).isEmpty()) {
+ if (value.isEmpty()) {
+ res = mJsonDb->removeViewObject(mOwner, previousResult);
+ } else {
+ previousResult.insert("value", value);
+ res = mJsonDb->updateViewObject(mOwner, previousResult);
+ }
+ } else {
+ previousResult.insert(JsonDbString::kTypeStr, mTargetType);
+ previousResult.insert("key", keyValue);
+ previousResult.insert("value", value);
+ previousResult.insert("reduceUuid", mUuid);
+ res = mJsonDb->createViewObject(mOwner, previousResult);
+ }
+
+ if (JsonDb::responseIsError(res))
+ setError("Error executing add function: " +
+ res.subObject(JsonDbString::kErrorStr).valueString(JsonDbString::kMessageStr));
+}
+
+QsonObject JsonDbReduceDefinition::addObject(const QString &keyValue, const QsonObject &previousValue, QsonMap object)
+{
+ QJSValue globalObject = mScriptEngine->globalObject();
+ QJSValue svKeyValue = mScriptEngine->toScriptValue(keyValue);
+ QJSValue svPreviousValue = mScriptEngine->toScriptValue(qsonToVariant(previousValue));
+ QJSValue svObject = qsonToJSValue(object, mScriptEngine);
+
+ QJSValueList reduceArgs;
+ reduceArgs << svKeyValue << svPreviousValue << svObject;
+ QJSValue reduced = mAddFunction.call(globalObject, reduceArgs);
+
+ if (reduced.isObject() && !reduced.isError()) {
+ QVariantMap vReduced = mScriptEngine->fromScriptValue<QVariantMap>(reduced);
+ return variantToQson(vReduced);
+ } else {
+
+ if (reduced.isError())
+ setError("Error executing add function: " + reduced.toString());
+
+ return QsonObject();
+ }
+}
+
+QsonObject JsonDbReduceDefinition::subtractObject(const QString &keyValue, const QsonObject &previousValue, QsonMap object)
+{
+ Q_ASSERT(mSubtractFunction.isFunction());
+
+ QJSValue globalObject = mScriptEngine->globalObject();
+
+ QJSValue svKeyValue = mScriptEngine->toScriptValue(keyValue);
+ QJSValue svPreviousValue = mScriptEngine->toScriptValue(qsonToVariant(previousValue));
+ QJSValue sv = qsonToJSValue(object, mScriptEngine);
+
+ QJSValueList reduceArgs;
+ reduceArgs << svKeyValue << svPreviousValue << sv;
+ QJSValue reduced = mSubtractFunction.call(globalObject, reduceArgs);
+
+ if (reduced.isObject() && !reduced.isError()) {
+ QVariantMap vReduced = mScriptEngine->fromScriptValue<QVariantMap>(reduced);
+ return variantToQson(vReduced);
+ } else {
+ if (reduced.isError())
+ setError("Error executing subtract function: " + reduced.toString());
+ return QsonObject();
+ }
+}
+
+bool JsonDbReduceDefinition::isActive() const
+{
+ return mDefinition.isNull(JsonDbString::kActiveStr) || mDefinition.valueBool(JsonDbString::kActiveStr);
+}
+
+void JsonDbReduceDefinition::setError(const QString &errorMsg)
+{
+ mDefinition.insert(JsonDbString::kActiveStr, false);
+ mDefinition.insert(JsonDbString::kErrorStr, errorMsg);
+ if (JsonDbBtreeStorage *storage = mJsonDb->findPartition(mPartition)) {
+ WithTransaction transaction(storage, "JsonDbReduceDefinition::setError");
+ ObjectTable *objectTable = storage->findObjectTable(JsonDbString::kMapTypeStr);
+ transaction.addObjectTable(objectTable);
+ storage->updatePersistentObject(mDefinition);
+ transaction.commit();
+ }
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondb-map-reduce.h b/src/daemon/jsondb-map-reduce.h
new file mode 100644
index 00000000..a82cc45a
--- /dev/null
+++ b/src/daemon/jsondb-map-reduce.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_MAP_REDUCE_H
+#define JSONDB_MAP_REDUCE_H
+
+#include <QJSEngine>
+
+#include "jsondb-global.h"
+#include <QtJsonDbQson/private/qson_p.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDb;
+class JsonDbOwner;
+class JsonDbMapProxy;
+class ObjectTable;
+
+class JsonDbMapDefinition : public QObject
+{
+ Q_OBJECT
+public:
+ JsonDbMapDefinition(JsonDb *mJsonDb, JsonDbOwner *mOwner, const QString &partition, QsonMap mapDefinition, QObject *parent = 0);
+ QString uuid() const { return mUuid; }
+ QString targetType() const { return mTargetType; }
+ QString sourceType() const { return mSourceType; }
+ QString partition() const { return mPartition; }
+ bool isActive() const;
+ QsonObject definition() const { return mDefinition; }
+ const QJSValue &mapFunction() const { return mMapFunction; }
+
+ void mapObject(QsonMap object);
+ void unmapObject(const QsonMap &object);
+
+public slots:
+ void viewObjectEmitted(const QString &key, const QJSValue &value);
+ void lookupRequested(const QString &findKey, const QJSValue &findValue, const QJSValue &objectType, const QJSValue &context);
+
+private:
+ void setError(const QString &errorMsg);
+
+ JsonDb *mJsonDb;
+ QString mPartition;
+ JsonDbOwner *mOwner;
+ QsonMap mDefinition;
+ QJSEngine *mScriptEngine;
+ JsonDbMapProxy *mJsonDbProxy;
+ QJSValue mMapFunction;
+ QString mUuid;
+ QString mTargetType;
+ QString mSourceType;
+ ObjectTable *mTargetTable;
+ ObjectTable *mSourceTable;
+ QList<QString> mSourceUuids;
+};
+
+class JsonDbReduceDefinition : public QObject
+{
+ Q_OBJECT
+public:
+ JsonDbReduceDefinition(JsonDb *mJsonDb, JsonDbOwner *mOwner, const QString &partition, QsonMap reduceDefinition, QObject *parent = 0);
+ QString uuid() const { return mUuid; }
+ QString targetType() const { return mTargetType; }
+ QString sourceType() const { return mSourceType; }
+ QString partition() const { return mPartition; }
+ QString sourceKeyName() const { return mSourceKeyName; }
+ bool isActive() const;
+ QsonObject definition() const { return mDefinition; }
+ const QJSValue &addFunction() const { return mAddFunction; }
+ const QJSValue &subtractFunction() const { return mSubtractFunction; }
+
+ void updateObject(QsonMap before, QsonMap after);
+ QsonObject addObject(const QString &keyValue, const QsonObject &previousResult, QsonMap object);
+ QsonObject subtractObject(const QString &keyValue, const QsonObject &previousResult, QsonMap object);
+
+private:
+ void setError(const QString &errorMsg);
+
+ JsonDb *mJsonDb;
+ JsonDbOwner *mOwner;
+ QString mPartition;
+ QsonMap mDefinition;
+ QJSEngine *mScriptEngine;
+ QJSValue mAddFunction;
+ QJSValue mSubtractFunction;
+ QString mUuid;
+ QString mTargetType;
+ QString mSourceType;
+ QString mKeyName;
+ QString mSourceKeyName;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif
diff --git a/src/daemon/jsondb-owner.cpp b/src/daemon/jsondb-owner.cpp
new file mode 100644
index 00000000..e4e52ce2
--- /dev/null
+++ b/src/daemon/jsondb-owner.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-owner.h"
+#include "jsondb.h"
+#include "jsondb-strings.h"
+#include <qdebug.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+bool gEnforceAccessControlPolicies = false;
+
+JsonDbOwner::JsonDbOwner( QObject *parent )
+ : QObject(parent), mStorageQuota(100*1000*1000), mAllowAll(false)
+{
+ QList<QString> defaultQueries;
+ defaultQueries.append(".*");
+ setAllowedObjects("read", defaultQueries);
+ setAllowedObjects("write", defaultQueries);
+}
+
+JsonDbOwner::~JsonDbOwner()
+{
+}
+
+void JsonDbOwner::setAllowedObjects(const QString &op, const QList<QString> &queries)
+{
+ mAllowedObjects[op] = queries;
+ mAllowedObjectQueries[op].clear();
+ QsonMap nullBindings;
+ foreach (const QString &query, queries) {
+ mAllowedObjectQueries[op].append(JsonDbQuery::parse(query, nullBindings));
+ }
+}
+
+void JsonDbOwner::setCapabilities(QsonMap &applicationCapabilities, JsonDb *jsondb)
+{
+ QsonMap request;
+ request.insert(JsonDbString::kQueryStr, (QString("[?%1=\"%2\"]").arg(JsonDbString::kTypeStr).arg("Capability")));
+ QsonMap result = jsondb->find(jsondb->owner(), request);
+ QsonList translations = result.subObject("result").subList("data");
+ //qDebug() << "JsonDbOwner::setCapabilities" << "translations" << translations;
+
+ QMap<QString, QSet<QString> > allowedObjects;
+ const QStringList ops = (QStringList() << "read" << "write");
+
+ for (int i = 0; i < translations.size(); ++i) {
+ QsonMap translation = translations.at<QsonMap>(i);
+ QString name = translation.valueString("name");
+ if (applicationCapabilities.contains(name)) {
+ QsonMap accessRules = translation.subObject("accessRules");
+ QStringList accessTypesAllowed = applicationCapabilities.value<QsonList>(name).toStringList();
+ foreach (QString accessTypeAllowed, accessTypesAllowed) {
+ QsonMap accessTypeTranslation = accessRules.subObject(accessTypeAllowed);
+ foreach (const QString op, ops) {
+ if (accessTypeTranslation.contains(op)) {
+ allowedObjects[op].unite(QSet<QString>::fromList(accessTypeTranslation.value<QsonList>(op).toStringList()));
+ }
+ }
+ }
+ }
+ }
+ foreach (const QString op, ops) {
+ setAllowedObjects(op, allowedObjects.value(op).toList());
+ }
+ if (gVerbose) {
+ qDebug() << "setCapabilities" << mOwnerId;
+ qDebug() << mAllowedObjects << endl;
+ }
+}
+
+bool JsonDbOwner::isAllowed (QsonObject &object, const QString &op) const
+{
+ if (mAllowAll || !gEnforceAccessControlPolicies)
+ return true;
+
+ QList<JsonDbQuery> queries = mAllowedObjectQueries[op];
+ foreach (const JsonDbQuery &query, queries) {
+ if (query.match(object, NULL, NULL))
+ return true;
+ }
+ return false;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondb-owner.h b/src/daemon/jsondb-owner.h
new file mode 100644
index 00000000..9b5b28d1
--- /dev/null
+++ b/src/daemon/jsondb-owner.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_OWNER_H
+#define JSONDB_OWNER_H
+
+#include <QObject>
+#include <QMap>
+#include <QString>
+#include <QSet>
+
+#include "jsondb-global.h"
+#include "jsondbquery.h"
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+class TestJsonDb;
+
+namespace QtAddOn { namespace JsonDb {
+
+extern bool gEnforceAccessControlPolicies;
+
+class JsonDb;
+
+class JsonDbOwner : public QObject
+{
+ Q_OBJECT
+public:
+ JsonDbOwner( QObject *parent = 0 );
+ ~JsonDbOwner();
+ QString ownerId() const { return mOwnerId; }
+ void setOwnerId(const QString &ownerId) { mOwnerId = ownerId; }
+ QString domain() const { return mDomain; }
+ void setDomain(const QString &domain) { mDomain = domain; }
+
+ QList<QString> allowedObjects(const QString &op) const;
+
+ void setAllowedObjects(const QString &op, const QList<QString> &queries);
+ void setCapabilities(QsonMap &capabilities, JsonDb *jsondb);
+ void setAllowAll(bool allowAll) { mAllowAll = allowAll; }
+
+ bool isAllowed(QsonObject &object, const QString &op) const;
+ int storageQuota() const { return mStorageQuota; }
+ void setStorageQuota(int storageQuota) { mStorageQuota = storageQuota; }
+
+private:
+ QString mOwnerId; // from security object
+ QString mDomain; // from security object
+ QMap<QString, QList<QString> > mAllowedObjects; // list of querie strings
+ QMap<QString, QList<JsonDbQuery> > mAllowedObjectQueries;
+ int mStorageQuota;
+ bool mAllowAll;
+ friend class ::TestJsonDb;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // JSONDB_OWNER_H
diff --git a/src/daemon/jsondb-proxy.cpp b/src/daemon/jsondb-proxy.cpp
new file mode 100644
index 00000000..2b3693ec
--- /dev/null
+++ b/src/daemon/jsondb-proxy.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-proxy.h"
+#include "jsondb-strings.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+extern bool gDebug;
+
+JsonDbProxy::JsonDbProxy( const JsonDbOwner *owner, JsonDb *jsonDb, QObject *parent )
+ : QObject(parent)
+ , mOwner(owner)
+ , mJsonDb(jsonDb)
+{
+}
+JsonDbProxy::~JsonDbProxy()
+{
+}
+
+QVariantMap JsonDbProxy::find(QVariantMap object)
+{
+ QsonMap bson = variantToQson(object).toMap();
+ return qsonToVariant(mJsonDb->find(mOwner, bson)).toMap();
+}
+QVariantMap JsonDbProxy::create(QVariantMap object )
+{
+ QsonMap bson = variantToQson(object).toMap();
+ return qsonToVariant(mJsonDb->create(mOwner, bson)).toMap();
+}
+QVariantMap JsonDbProxy::update(QVariantMap object )
+{
+ QsonMap bson = variantToQson(object).toMap();
+ return qsonToVariant(mJsonDb->update(mOwner, bson)).toMap();
+}
+QVariantMap JsonDbProxy::remove(QVariantMap object )
+{
+ QsonMap bson = variantToQson(object).toMap();
+ return qsonToVariant(mJsonDb->remove(mOwner, bson)).toMap();
+}
+QVariantMap JsonDbProxy::notification(QString query, QStringList actions, QString script)
+{
+ QsonList actionsList;
+ foreach (const QString &action, actions)
+ actionsList.append(action);
+
+ QsonMap notificationObject;
+ notificationObject.insert(JsonDbString::kTypeStr, JsonDbString::kNotificationTypeStr);
+ notificationObject.insert(JsonDbString::kQueryStr, query);
+ notificationObject.insert(JsonDbString::kActionsStr, actionsList);
+ notificationObject.insert("script", script);
+ return qsonToVariant(mJsonDb->create(mOwner, notificationObject)).toMap();
+}
+
+QVariantMap JsonDbProxy::createList(QVariantList list)
+{
+ QsonList blist;
+ for (int i = 0; i < list.size(); i++) {
+ QsonObject bson = variantToQson(list[i]);
+ blist.append(bson);
+ }
+ return qsonToVariant(mJsonDb->createList(mOwner, blist)).toMap();
+}
+
+QVariantMap JsonDbProxy::updateList(QVariantList list)
+{
+ QsonList blist;
+ for (int i = 0; i < list.size(); i++) {
+ QsonObject bson = variantToQson(list[i]);
+ blist.append(bson);
+ }
+ return qsonToVariant(mJsonDb->removeList(mOwner, blist)).toMap();
+}
+
+QVariantMap JsonDbProxy::removeList(QVariantList list)
+{
+ QsonList blist;
+ for (int i = 0; i < list.size(); i++) {
+ QsonObject bson = variantToQson(list[i]);
+ blist.append(bson);
+ }
+ return qsonToVariant(mJsonDb->removeList(mOwner, blist)).toMap();
+}
+
+JsonDbMapProxy::JsonDbMapProxy( const JsonDbOwner *owner, JsonDb *jsonDb, QObject *parent )
+ : QObject(parent)
+ , mOwner(owner)
+ , mJsonDb(jsonDb)
+{
+}
+JsonDbMapProxy::~JsonDbMapProxy()
+{
+}
+
+void JsonDbMapProxy::emitViewObject(const QString &key, const QJSValue &v)
+{
+ //qDebug() << "emitViewItem" << key << v.toVariant();
+ emit viewObjectEmitted(key, v);
+}
+
+void JsonDbMapProxy::lookup(const QString &key, const QJSValue &value, const QJSValue &context)
+{
+ emit lookupRequested(key, value, QJSValue(), context);
+}
+
+void JsonDbMapProxy::lookupWithType(const QString &key, const QJSValue &value, const QJSValue &objectType, const QJSValue &context)
+{
+ emit lookupRequested(key, value, objectType, context);
+}
+
+Console::Console()
+{
+}
+
+void Console::log(const QString &s)
+{
+ qDebug() << s;
+}
+
+void Console::debug(const QString &s)
+{
+// if (gDebug)
+ qDebug() << s;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondb-proxy.h b/src/daemon/jsondb-proxy.h
new file mode 100644
index 00000000..b1560672
--- /dev/null
+++ b/src/daemon/jsondb-proxy.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JsonDbProxy_H
+#define JsonDbProxy_H
+
+#include <QObject>
+#include <QMultiMap>
+#include <QJSValue>
+
+#include "jsondb.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDbProxy : public QObject {
+ Q_OBJECT
+public:
+ JsonDbProxy( const JsonDbOwner *owner, JsonDb *jsonDb, QObject *parent=0 );
+ ~JsonDbProxy();
+
+ Q_SCRIPTABLE QVariantMap find(QVariantMap object);
+ Q_SCRIPTABLE QVariantMap create(QVariantMap object );
+ Q_SCRIPTABLE QVariantMap update(QVariantMap object );
+ Q_SCRIPTABLE QVariantMap remove(QVariantMap object );
+
+ Q_SCRIPTABLE QVariantMap notification(QString query, QStringList actions, QString script);
+
+ Q_SCRIPTABLE QVariantMap createList(QVariantList);
+ Q_SCRIPTABLE QVariantMap updateList(QVariantList);
+ Q_SCRIPTABLE QVariantMap removeList(QVariantList );
+
+ void setOwner(const JsonDbOwner *owner) { mOwner = owner; }
+
+private:
+ const JsonDbOwner *mOwner;
+ JsonDb *mJsonDb;
+};
+
+class JsonDbMapProxy : public QObject {
+ Q_OBJECT
+public:
+ JsonDbMapProxy( const JsonDbOwner *owner, JsonDb *jsonDb, QObject *parent=0 );
+ ~JsonDbMapProxy();
+
+ Q_SCRIPTABLE void emitViewObject(const QString &key, const QJSValue &value );
+ Q_SCRIPTABLE void lookup(const QString &key, const QJSValue &value, const QJSValue &context );
+ Q_SCRIPTABLE void lookupWithType(const QString &key, const QJSValue &value, const QJSValue &objectType, const QJSValue &context);
+
+ void setOwner(const JsonDbOwner *owner) { mOwner = owner; }
+
+ void clear() { mEmitted.clear(); mLookup.clear(); mContext = QJSValue(); }
+ const QMultiMap<QString,QJSValue> &emitted() { return mEmitted; }
+ const QJSValue &context() { return mContext; }
+
+ signals:
+ void viewObjectEmitted(const QString &, const QJSValue &);
+ void lookupRequested(const QString &, const QJSValue &, const QJSValue &, const QJSValue &);
+private:
+ const JsonDbOwner *mOwner;
+ JsonDb *mJsonDb;
+ QMultiMap<QString,QJSValue> mEmitted;
+ QMultiMap<QString,QJSValue> mLookup;
+ QJSValue mContext;
+};
+
+class Console : public QObject {
+ Q_OBJECT
+public:
+ Console();
+ Q_SCRIPTABLE void log(const QString &string);
+ Q_SCRIPTABLE void debug(const QString &string);
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif
diff --git a/src/daemon/jsondb-trace.cpp b/src/daemon/jsondb-trace.cpp
new file mode 100644
index 00000000..77c912f5
--- /dev/null
+++ b/src/daemon/jsondb-trace.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+
+// Backtraces are not support in uClibc
+#ifndef __UCLIBC__
+#include <execinfo.h>
+#endif
+
+void print_trace () {
+#ifndef __UCLIBC__
+ void *array[20];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 20);
+ strings = backtrace_symbols (array, size);
+
+ for (i = 0; i < size; i++)
+ printf ("%s\n", strings[i]);
+
+ free (strings);
+#endif
+}
+
+void jsondb_assert(const char *assertion, const char *file, int line)
+{
+ qCritical("JSONDB ASSERT: \"%s\" in file %s, line %d", assertion, file, line);
+ print_trace();
+ abort();
+}
+void jsondb_assert_x(const char *where, const char *what, const char *file, int line)
+{
+ qCritical("JSONDB ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line);
+ print_trace();
+ abort();
+}
diff --git a/src/daemon/jsondb-trace.h b/src/daemon/jsondb-trace.h
new file mode 100644
index 00000000..ec713ec2
--- /dev/null
+++ b/src/daemon/jsondb-trace.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_TRACE_H
+#define JSONDB_TRACE_H
+
+extern void print_trace ();
+extern void jsondb_assert(const char *assertion, const char *file, int line);
+extern void jsondb_assert_x(const char *where, const char *what, const char *file, int line);
+
+#undef Q_ASSERT_X
+#define Q_ASSERT_X(cond, where, what) ((!(cond)) ? jsondb_assert_x(where, what,__FILE__,__LINE__) : qt_noop())
+#undef Q_ASSERT
+#define Q_ASSERT(cond) ((!(cond)) ? jsondb_assert(#cond,__FILE__,__LINE__) : qt_noop())
+
+#endif
+
diff --git a/src/daemon/jsondb.cpp b/src/daemon/jsondb.cpp
new file mode 100644
index 00000000..6b8794f4
--- /dev/null
+++ b/src/daemon/jsondb.cpp
@@ -0,0 +1,1730 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QFile>
+#include <QString>
+#include <QStringList>
+#include <QStringBuilder>
+#include <QCryptographicHash>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QRegExp>
+#include <QJSValue>
+#include <QJSValueIterator>
+#include <QElapsedTimer>
+#include <QtAlgorithms>
+#include <QDebug>
+
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+
+#include <json.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <QtJsonDbQson/private/qson_p.h>
+#include <QtJsonDbQson/private/qsonstrings_p.h>
+#include <QtJsonDbQson/private/qsonparser_p.h>
+
+#include "jsondb.h"
+#include "jsondb-proxy.h"
+#include "jsondb-map-reduce.h"
+#include "jsondbbtreestorage.h"
+#include "schemamanager_impl_p.h"
+#include "qsonobjecttypes_impl_p.h"
+
+#include "aodb.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+bool gUseQsonInDb = true;
+bool gUseJsonInDb = false;
+bool gValidateSchemas = (::getenv("JSONDB_VALIDATE_SCHEMAS") ? (QLatin1String(::getenv("JSONDB_VALIDATE_SCHEMAS")) == "true") : false);
+bool gRejectStaleUpdates = (::getenv("JSONDB_REJECT_STALE_UPDATES") ? (QLatin1String(::getenv("JSONDB_REJECT_STALE_UPDATES")) == "true") : false);
+bool gVerbose = (::getenv("JSONDB_VERBOSE") ? (QLatin1String(::getenv("JSONDB_VERBOSE")) == "true") : false);
+bool gShowErrors = (::getenv("JSONDB_SHOW_ERRORS") ? (QLatin1String(::getenv("JSONDB_SHOW_ERRORS")) == "true") : false);
+#ifndef QT_NO_DEBUG_OUTPUT
+bool gDebug = (::getenv("JSONDB_DEBUG") ? (QLatin1String(::getenv("JSONDB_DEBUG")) == "true") : false);
+bool gDebugRecovery = (::getenv("JSONDB_DEBUG_RECOVERY") ? (QLatin1String(::getenv("JSONDB_DEBUG_RECOVERY")) == "true") : false);
+#endif
+
+const QString kDefaultPartitionName = QLatin1String("default");
+const QString kSortKeysStr = QLatin1String("sortKeys");
+const QString kStateStr = QLatin1String("state");
+
+#ifndef QT_NO_DEBUG_OUTPUT
+#define DBG() if (gDebug) qDebug() << Q_FUNC_INFO
+#else
+#define DBG() if (0) qDebug() << Q_FUNC_INFO
+#endif
+
+#define RETURN_IF_ERROR(errmap, toCheck) \
+ ({ \
+ errmap = toCheck; \
+ if (!errmap.isEmpty()) { \
+ QsonMap _r; \
+ return makeResponse(_r, errmap); \
+ } \
+ })
+
+void JsonDb::setError(QsonMap &map, int code, const QString &message)
+{
+ map.insert(JsonDbString::kCodeStr, code);
+ map.insert(JsonDbString::kMessageStr, message);
+}
+
+QsonMap JsonDb::makeError(int code, const QString &message)
+{
+ QsonMap map;
+ setError(map, code, message);
+ return map;
+}
+
+QsonMap JsonDb::makeResponse( QsonMap& resultmap, QsonMap& errormap, bool silent )
+{
+ QsonMap map;
+ if (gVerbose && !silent && !errormap.isEmpty()) {
+ qCritical() << errormap;
+ }
+ if (!resultmap.isEmpty())
+ map.insert( JsonDbString::kResultStr, resultmap);
+ else
+ map.insert( JsonDbString::kResultStr, QsonObject::NullValue);
+
+ if (!errormap.isEmpty())
+ map.insert( JsonDbString::kErrorStr, errormap );
+ else
+ map.insert( JsonDbString::kErrorStr, QsonObject::NullValue);
+ return map;
+}
+
+QsonMap JsonDb::makeErrorResponse(QsonMap &resultmap,
+ int code, const QString &message, bool silent)
+{
+ QsonMap errormap;
+ setError(errormap, code, message);
+ return makeResponse(resultmap, errormap, silent);
+}
+
+bool JsonDb::responseIsError( QsonMap responseMap )
+{
+ return responseMap.contains(JsonDbString::kErrorStr)
+ && !responseMap.isNull(JsonDbString::kErrorStr);
+}
+
+//bool JsonDb::responseIsGood( QsonObject responseMap )
+//{
+// return !responseMap.contains(JsonDbString::kErrorStr);
+//}
+
+QString JsonDb::uuidhex(uint data, int digits)
+{
+ return QString::number(data, 16).rightJustified(digits, QLatin1Char('0'));
+}
+
+QString JsonDb::createDatabaseId()
+{
+ QFile devUrandom;
+ uint data[3];
+ devUrandom.setFileName(QLatin1String("/dev/urandom"));
+ if (!devUrandom.open(QIODevice::ReadOnly)) {
+ } else {
+ qint64 numToRead = 3 * sizeof(uint);
+ devUrandom.read((char *) data, numToRead); // should read 128-bits of data
+ }
+ return (QString("%1-%2-%3")
+ .arg(uuidhex(data[0], 8))
+ .arg(uuidhex(data[1], 8))
+ .arg(uuidhex(data[2], 8)));
+}
+
+/*!
+ This function takes a single QsonObject,
+ adds a "uuid" field to it with a unique UUID (overwriting a
+ previous "uuid" field if necessary), and stores it in the object
+ database.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "uuid", STRING } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+ This method must be overridden in a subclass.
+*/
+
+/*
+ QsonObject JsonDb::create(const JsonDbOwner *owner, QsonObject object)
+ {
+ }
+*/
+
+/*!
+ This function takes a single QsonObject with a valid "uuid" field.
+ It updates the database to match the new object.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : NULL }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+ This method must be overridden in a subclass.
+*/
+
+/*
+ QsonObject JsonDb::update(QsonObject object)
+ {
+ }
+*/
+
+
+/*!
+ This function takes a QsonList of objects. It creates
+ the items in the database, assigning each a unique "uuid" field.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count": NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+
+ This class should be optimized by a JsonDb subclass.
+*/
+
+QsonMap JsonDb::createList(const JsonDbOwner *owner, QsonList& list, const QString &partition)
+{
+ int count = 0;
+ QsonList resultList;
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ WithTransaction lock(storage);
+ CHECK_LOCK_RETURN(lock, "createList");
+
+ for (int i = 0; i < list.size(); ++i) {
+ QsonMap o = list.at<QsonMap>(i);
+ QsonMap r = create(owner, o, partition);
+ if (responseIsError(r))
+ return r;
+ count += 1;
+ resultList.append(r.subObject("result"));
+ }
+ lock.commit();
+
+ QsonMap resultmap, errormap;
+ resultmap.insert( JsonDbString::kDataStr, resultList );
+ resultmap.insert( JsonDbString::kCountStr, count );
+ return makeResponse( resultmap, errormap );
+}
+
+/*!
+ This function takes a QsonList of objects each with a valid
+ "uuid" field. It updates the items in the database.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count": NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+ This class should be optimized by a JsonDb subclass.
+*/
+
+QsonMap JsonDb::updateList(const JsonDbOwner *owner, QsonList& list, const QString &partition, bool replication)
+{
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ WithTransaction transaction(storage);
+ CHECK_LOCK_RETURN(transaction, "updateList");
+ int count = 0;
+ QsonList resultList;
+
+ for (int i = 0; i < list.size(); ++i) {
+ QsonMap o = list.at<QsonMap>(i);
+ QsonMap r = update(owner, o, partition, replication);
+ if (responseIsError(r))
+ return r;
+ count += r.subObject(JsonDbString::kResultStr).valueInt(JsonDbString::kCountStr);
+ resultList.append(r.subObject("result"));
+ }
+ transaction.commit();
+
+ QsonMap resultmap, errormap;
+ resultmap.insert( JsonDbString::kDataStr, resultList );
+ resultmap.insert( JsonDbString::kCountStr, count );
+ return makeResponse( resultmap, errormap );
+}
+
+/*!
+ This function takes a QsonList of objects each with a valid
+ "uuid" field. It removes the items from the database.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count": NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+ This class should be optimized by a JsonDb subclass.
+*/
+
+QsonMap JsonDb::removeList(const JsonDbOwner *owner, QsonList list, const QString &partition)
+{
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ WithTransaction transaction(storage);
+ CHECK_LOCK_RETURN(transaction, "removeList");
+ int count = 0;
+ QsonList removedList, errorsList;
+ for (int i = 0; i < list.size(); ++i) {
+ QsonMap o = list.at<QsonMap>(i);
+ QString uuid = o.valueString(JsonDbString::kUuidStr);
+ QsonMap r = remove(owner, o, partition);
+ QsonMap error = r.subObject(JsonDbString::kErrorStr);
+ if (!error.isEmpty()) {
+ QsonMap obj;
+ obj.insert(JsonDbString::kUuidStr, uuid);
+ obj.insert(JsonDbString::kErrorStr, error);
+ errorsList.append(obj);
+ continue;
+ }
+ count += r.subObject(JsonDbString::kResultStr).valueInt(JsonDbString::kCountStr);
+ QsonMap item;
+ item.insert(JsonDbString::kUuidStr, uuid);
+ removedList.append(item);
+ }
+ transaction.commit();
+
+ QsonMap resultmap;
+ resultmap.insert(JsonDbString::kCountStr, count);
+ resultmap.insert(JsonDbString::kDataStr, removedList);
+ resultmap.insert(JsonDbString::kErrorStr, errorsList);
+ QsonMap errormap;
+ return makeResponse(resultmap, errormap);
+}
+
+QsonMap JsonDb::changesSince(const JsonDbOwner * /* owner */, QsonMap object, const QString &partition)
+{
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ int stateNumber = object.valueInt(JsonDbString::kStateNumberStr, 0);
+ if (object.contains(JsonDbString::kTypesStr)) {
+ QSet<QString> limitTypes;
+ QsonList l = object.subList(JsonDbString::kTypesStr);
+ for (int i = 0; i < l.size(); i++)
+ limitTypes.insert(l.at<QString>(i));
+ return storage->changesSince(stateNumber, limitTypes);
+ } else {
+ return storage->changesSince(stateNumber);
+ }
+}
+
+QVariant JsonDb::propertyLookup(QsonMap v, const QString &path)
+{
+ return propertyLookup(v, path.split('.'));
+}
+
+QVariant JsonDb::propertyLookup(QVariantMap object, const QStringList &path)
+{
+ QVariant v = object;
+ for (int i = 0; i < path.size(); i++) {
+ object = v.toMap();
+ QString key = path[i];
+ if (object.contains(key))
+ v = object.value(key);
+ else
+ return QVariant();
+ }
+ return v;
+}
+
+QVariant JsonDb::propertyLookup(QsonMap object, const QStringList &path)
+{
+ if (!path.size()) {
+ qCritical() << "JsonDb::propertyLookup empty path";
+ abort();
+ return QVariant();
+ }
+ QsonMap emptyMap;
+ QsonList emptyList;
+ QsonList objectList;
+ for (int i = 0; i < path.size() - 1; i++) {
+ const QString &key = path.at(i);
+ // this part of the property is a list
+ if (!objectList.isEmpty()) {
+ bool ok = false;
+ int index = key.toInt(&ok);
+ if (ok && (index >= 0) && (objectList.count() > index)) {
+ if (objectList.typeAt(index) == QsonObject::ListType) {
+ objectList = objectList.listAt(index);
+ object = emptyMap;
+ } else {
+ object = objectList.objectAt(index);
+ objectList = emptyList;
+ }
+ continue;
+ }
+ }
+ // this part is a map
+ if (object.contains(key)) {
+ if (object.valueType(key) == QsonObject::ListType) {
+ objectList = object.subList(key);
+ object = emptyMap;
+ } else {
+ object = object.subObject(key);
+ objectList = emptyList;
+ }
+ } else {
+ return QVariant();
+ }
+ }
+ const QString &key = path.last();
+ // get the last part from the list
+ if (!objectList.isEmpty()) {
+ bool ok = false;
+ int index = key.toInt(&ok);
+ if (ok && (index >= 0) && (objectList.count() > index)) {
+ if (objectList.typeAt(index) == QsonObject::ListType) {
+ return qsonToVariant(objectList.listAt(index));
+ } else {
+ return qsonToVariant(objectList.objectAt(index));
+ }
+ }
+ }
+ // if the last part is in a map
+ if (object.valueType(key) == QsonObject::ListType)
+ return qsonToVariant(object.subList(key));
+ else
+ return qsonToVariant(object.value<QsonElement>(key));
+}
+
+JsonDb::JsonDb(const QString &path, QObject *parent)
+ : QObject(parent)
+ , mBdbInfo(new AoDb), mOwner(0)
+ , mScriptEngine(new QJSEngine(this))
+ , mJsonDbProxy(new JsonDbProxy(0, this, this))
+ , mOpen(false)
+{
+ QFileInfo fi(path);
+ if (fi.isDir())
+ mFilePath = fi.filePath();
+ mFilePath = fi.dir().path();
+ if (mFilePath.at(mFilePath.size()-1) != QLatin1Char('/'))
+ mFilePath += QLatin1Char('/');
+
+ mOwner = new JsonDbOwner(this);
+ mOwner->setOwnerId("com.nrcc.noklab.JsonDb");
+
+ QJSValue globalObject = mScriptEngine->globalObject();
+ globalObject.setProperty("jsondb", mScriptEngine->newQObject(mJsonDbProxy));
+ globalObject.setProperty("console", mScriptEngine->newQObject( new Console));
+ mJsonDbProxy->setOwner(owner());
+
+}
+
+JsonDb::~JsonDb()
+{
+ close();
+ delete mBdbInfo; mBdbInfo = 0;
+}
+
+bool JsonDb::open()
+{
+ QString infodb = mFilePath + QLatin1String("info.db");
+ if (!mBdbInfo->open(infodb, AoDb::NoSync)) {
+ qDebug() << "Cannot open " << infodb;
+ return false;
+ }
+
+ // read partition information from the db
+ QByteArray value;
+ mBdbInfo->get(QByteArray("partitions"), value);
+ QsonList partitions = QsonParser::fromRawData(value).toList();
+ if (partitions.isEmpty()) {
+ // make a default partition
+ QsonMap partition;
+ partition.insert(QLatin1String("name"), kDefaultPartitionName);
+ partition.insert(QLatin1String("file"), mFilePath + QLatin1String("default.db"));
+ partitions.append(partition);
+ if (!mBdbInfo->put(QByteArray("partitions"), partitions.data())) {
+ qCritical() << "Cannot put a default partition";
+ return false;
+ }
+ }
+
+ for (int i = 0; i < partitions.size(); ++i) {
+ QsonMap part = partitions.at<QsonMap>(i);
+ QString filename = part.value<QString>(QLatin1String("file"));
+ QString name = part.value<QString>(QLatin1String("name"));
+
+ if (mStorages.contains(name)) {
+ qWarning() << "Duplicate partition found, ignoring" << name << "at" << filename;
+ continue;
+ }
+
+ JsonDbBtreeStorage *storage = new JsonDbBtreeStorage(filename, name, this);
+ if (gVerbose) qDebug() << "Opening partition" << name;
+
+ if (!storage->open()) {
+ qWarning() << "Failed to initialize partition" << name << "at" << filename;
+ continue;
+ }
+ mStorages.insert(name, storage);
+ }
+
+ mViewTypes.clear();
+ mEagerViewSourceTypes.clear();
+ mMapDefinitionsBySource.clear();
+ mMapDefinitionsByTarget.clear();
+ mReduceDefinitionsBySource.clear();
+ mReduceDefinitionsByTarget.clear();
+
+ initSchemas();
+
+ foreach (const QString &partition, mStorages.keys())
+ initMap(partition);
+
+ mOpen = true;
+ return true;
+}
+bool JsonDb::clear()
+{
+ bool fail = false;
+ foreach(JsonDbBtreeStorage *storage, mStorages)
+ fail = !storage->clear() || fail;
+ return !fail;
+}
+
+bool JsonDb::checkValidity()
+{
+ bool fail = false;
+ foreach(JsonDbBtreeStorage *storage, mStorages)
+ fail = !storage->checkValidity() || fail;
+ return !fail;
+}
+
+void JsonDb::close()
+{
+ if (mOpen) {
+ foreach (JsonDbBtreeStorage *storage, mStorages)
+ storage->close();
+ mBdbInfo->close();
+ }
+ mOpen = false;
+}
+
+void JsonDb::load(const QString &jsonFileName)
+{
+ QFile jsonFile(jsonFileName);
+ if (!jsonFile.exists()) {
+ qCritical() << QString("File %1 does not exist").arg(jsonFileName);
+ return;
+ }
+ if (!jsonFile.open(QIODevice::ReadOnly)) {
+ qCritical() << QString("Cannot open file %1").arg(jsonFileName);
+ return;
+ }
+
+ QByteArray json = jsonFile.readAll();
+ QJSValue sv = scriptEngine()->evaluate(QString::fromUtf8(json.constData(), json.size()), jsonFileName);
+ if (sv.isError()) {
+ qWarning() << QString("DbServer::Load load %1: error:\n").arg(jsonFileName) << sv.toVariant();
+ } else if (sv.isValid()) {
+ if (gDebug)
+ qDebug() << QString("DbServer::Load load %1: result:\n").arg(jsonFileName) << sv.toVariant();
+ }
+}
+
+QsonMap JsonDb::find(const JsonDbOwner *owner, QsonMap obj, const QString &partition)
+{
+// QElapsedTimer time;
+// QsonMap times;
+// time.start();
+ QsonMap resultmap, errormap;
+
+ QString query = obj.valueString(JsonDbString::kQueryStr);
+ QsonMap bindings = obj.subObject("bindings");
+
+ int limit = obj.valueInt(JsonDbString::kLimitStr, -1);
+ int offset = obj.valueInt(JsonDbString::kOffsetStr, 0);
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ if ( limit < -1 )
+ setError( errormap, JsonDbError::InvalidLimit, "Invalid limit" );
+ else if ( offset < 0 )
+ setError( errormap, JsonDbError::InvalidOffset, "Invalid offset" );
+ else if ( query.isEmpty() )
+ setError( errormap, JsonDbError::MissingQuery, "Missing query string");
+ else {
+// times.insert("time0 before parse", time.elapsed());
+ JsonDbQuery parsedQuery = JsonDbQuery::parse(query, bindings);
+// times.insert("time1 after parse", time.elapsed());
+
+ if (!parsedQuery.queryTerms.size() && !parsedQuery.orderTerms.size()) {
+ setError( errormap, JsonDbError::MissingQuery, QString("Missing query: ") + parsedQuery.queryExplanation.join("\n"));
+ return makeResponse( resultmap, errormap );
+ }
+
+ QStringList explanation = parsedQuery.queryExplanation;
+ QVariant::Type resultType = parsedQuery.resultType;
+ QStringList mapExpressions = parsedQuery.mapExpressionList;
+ QStringList mapKeys = parsedQuery.mapKeyList;
+
+ QsonMap queryResult;
+ if (partition.isEmpty() && (mStorages.size() > 1))
+ queryResult = storage->queryPersistentObjects(owner, parsedQuery, limit, offset, mStorages.values());
+ else
+ queryResult = storage->queryPersistentObjects(owner, parsedQuery, limit, offset);
+ QsonList results = queryResult.subList("data");
+ if (gDebug) {
+ const QList<OrQueryTerm> &orQueryTerms = parsedQuery.queryTerms;
+ for (int i = 0; i < orQueryTerms.size(); i++) {
+ const OrQueryTerm orQueryTerm = orQueryTerms[i];
+ foreach (const QueryTerm &queryTerm, orQueryTerm.terms()) {
+ if (gVerbose) {
+ qDebug() << __FILE__ << __LINE__
+ << (QString(" %1%4%5 %2 %3 ")
+ .arg(queryTerm.fieldName())
+ .arg(queryTerm.op())
+ .arg(JsonWriter().toString(queryTerm.value()))
+ .arg(queryTerm.joinField().size() ? "->" : "").arg(queryTerm.joinField()));
+ }
+ }
+ }
+ QList<OrderTerm> &orderTerms = parsedQuery.orderTerms;
+ for (int i = 0; i < orderTerms.size(); i++) {
+ const OrderTerm &orderTerm = orderTerms[i];
+ if (gVerbose) qDebug() << __FILE__ << __LINE__ << QString(" %1 %2 ").arg(orderTerm.fieldName).arg(orderTerm.ascending ? "ascending" : "descending");
+ }
+ }
+ DBG() << endl
+#if 0
+ << " orderTerms: " << serializer.serialize(orderTerms) << endl
+ << " queryTerms: " << serializer.serialize(queryTerms) << endl
+#endif
+ << " limit: " << limit << endl
+ << " offset: " << offset << endl
+ << " results: " << results;
+
+ int length = results.count();
+
+ if (mapExpressions.length() && parsedQuery.mAggregateOperation.compare("count")) {
+ QMap<QString, QsonMap> objectCache;
+ int nExpressions = mapExpressions.length();
+ QVector<QVector<QStringList> > joinPaths(nExpressions);
+ for (int i = 0; i < nExpressions; i++) {
+ QString fieldName = mapExpressions[i];
+ QStringList joinPath = fieldName.split("->");
+ int joinPathSize = joinPath.size();
+ QVector<QStringList> fieldPaths(joinPathSize);
+ for (int j = 0; j < joinPathSize; j++) {
+ QString joinField = joinPath[j];
+ fieldPaths[j] = joinField.split('.');
+ }
+ joinPaths[i] = fieldPaths;
+ }
+
+ QsonList mappedResult;
+ for (int r = 0; r < results.count(); r++) {
+ const QsonMap obj = results.at<QsonMap>(r);
+ QsonList list;
+ QsonMap map;
+ for (int i = 0; i < nExpressions; i++) {
+ QVariant v;
+
+ QVector<QStringList> &joinPath = joinPaths[i];
+ int joinPathSize = joinPath.size();
+ if (joinPathSize == 1) {
+ v = propertyLookup(obj, joinPath[joinPathSize-1]);
+ } else {
+ QsonMap baseObject = obj;
+ for (int j = 0; j < joinPathSize-1; j++) {
+ QString uuid = propertyLookup(baseObject, joinPath[j]).toString();
+ if (uuid.isEmpty()) {
+ baseObject = QsonMap();
+ } else if (objectCache.contains(uuid)) {
+ baseObject = objectCache.value(uuid);
+ } else {
+ ObjectKey objectKey(uuid);
+ baseObject = storage->lookupObject(objectKey);
+ if (!baseObject.isEmpty())
+ objectCache.insert(uuid, baseObject);
+ }
+ }
+ v = propertyLookup(baseObject, joinPath[joinPathSize-1]);
+ }
+
+ if (resultType == QVariant::Map)
+ map.insert(mapKeys[i], variantToQson(v));
+ else if (resultType == QVariant::List)
+ list.append(variantToQson(v));
+ else
+ mappedResult.append(variantToQson(v));
+ }
+ if (resultType == QVariant::Map)
+ mappedResult.append(map);
+ else if (resultType == QVariant::List)
+ mappedResult.append(list);
+ }
+
+ resultmap.insert(JsonDbString::kDataStr, mappedResult);
+ } else {
+ resultmap.insert(JsonDbString::kDataStr, results);
+ }
+
+ resultmap.insert(JsonDbString::kLengthStr, length);
+ resultmap.insert(JsonDbString::kOffsetStr, offset);
+ resultmap.insert(JsonDbString::kExplanationStr, variantToQson(explanation));
+ if (queryResult.contains(kSortKeysStr))
+ resultmap.insert(kSortKeysStr, queryResult.subList(kSortKeysStr));
+ if (queryResult.contains(kStateStr))
+ resultmap.insert(kStateStr, queryResult.valueInt(kStateStr));
+ }
+
+ return makeResponse( resultmap, errormap );
+}
+
+/*!
+ This function takes a single QsonObject,
+ adds a "_uuid" field to it with a unique UUID (overwriting a
+ previous "_uuid" field if necessary), and stores it in the object
+ database.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "_uuid", STRING } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+*/
+
+QsonMap JsonDb::create(const JsonDbOwner *owner, QsonMap& object, const QString &partition)
+{
+ QsonMap resultmap, errormap;
+
+ if (object.isDocument()) {
+ setError(errormap, JsonDbError::InvalidRequest, "New object should not have _uuid");
+ return makeResponse(resultmap, errormap);
+ }
+
+ populateIdBySchema(owner, object);
+ object.generateUuid();
+
+ return update(owner, object, partition);
+}
+
+QsonMap JsonDb::createViewObject(const JsonDbOwner *owner, QsonMap& object, const QString &partition)
+{
+ QsonMap resultmap, errormap;
+
+ if (object.contains(JsonDbString::kUuidStr)) {
+ setError(errormap, JsonDbError::InvalidRequest, "New object should not have _uuid");
+ return makeResponse(resultmap, errormap);
+ }
+ QString objectType;
+ RETURN_IF_ERROR(errormap, checkTypePresent(object, objectType));
+ RETURN_IF_ERROR(errormap, checkAccessControl(owner, object, "write"));
+ RETURN_IF_ERROR(errormap, validateSchema(objectType, object));
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ populateIdBySchema(owner, object);
+ object.generateUuid();
+ object.computeVersion();
+
+ int dataSize = object.dataSize();
+ RETURN_IF_ERROR(errormap, checkQuota(owner, dataSize, storage));
+
+ QsonMap response = storage->createPersistentObject(object);
+
+ if (responseIsError(response))
+ return response;
+
+ storage->addToQuota(owner, dataSize);
+
+ checkNotifications( object, Notification::Create );
+
+ return response;
+}
+
+/*!
+ This function takes a single QsonObject with a valid "_uuid" field.
+ It updates the database to match the new object.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count" : NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+*/
+
+QsonMap JsonDb::update(const JsonDbOwner *owner, QsonMap& object, const QString &partition, bool replication)
+{
+ QsonMap resultmap, errormap;
+ QString uuid, objectType;
+
+ RETURN_IF_ERROR(errormap, checkUuidPresent(object, uuid));
+ RETURN_IF_ERROR(errormap, checkTypePresent(object, objectType));
+ RETURN_IF_ERROR(errormap, checkNaturalObjectType(object, objectType));
+ if (!object.contains(JsonDbString::kDeletedStr) || !object.valueBool(JsonDbString::kDeletedStr, false))
+ RETURN_IF_ERROR(errormap, validateSchema(objectType, object));
+ RETURN_IF_ERROR(errormap, checkAccessControl(owner, object, "write"));
+
+ if (populateIdBySchema(owner, object)) {
+ object.generateUuid();
+
+ if (object.valueString(JsonDbString::kUuidStr) != uuid) {
+ setError(errormap, JsonDbError::InvalidRequest, "_uuid mismatch, use create()");
+ return makeResponse(resultmap, errormap);
+ }
+ }
+ object.computeVersion();
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ WithTransaction transaction(storage);
+ ObjectTable *objectTable = storage->findObjectTable(objectType);
+ transaction.addObjectTable(objectTable);
+
+ // retrieve record we are updating to use
+ QsonMap master;
+ bool forCreation = true;
+
+ QsonMap _delrec = storage->lookupObject(uuid, objectType);
+ if (!_delrec.isEmpty()) {
+ master = _delrec;
+ forCreation = false;
+ Q_ASSERT(master.isDocument());
+ } else if (!replication && object.valueBool(JsonDbString::kDeletedStr, false)) {
+ setError(errormap, JsonDbError::MissingObject, QLatin1String("Cannot remove non-existing object"));
+ return makeResponse(resultmap, errormap);
+ }
+
+ if (forCreation || !gRejectStaleUpdates) {
+ master = object;
+ // hack to make sure _lastVersion equals _version
+ master.insert(JsonDbString::kVersionStr, master.valueString(JsonDbString::kVersionStr));
+ } else {
+ int conflictsBefore = master.subObject(QsonStrings::kMetaStr).subList(QsonStrings::kConflictsStr).size();
+ if (!master.mergeVersions(object, replication)) {
+ // replay
+ resultmap.insert(JsonDbString::kUuidStr, uuid);
+ resultmap.insert(JsonDbString::kVersionStr, object.valueString(JsonDbString::kVersionStr));
+ resultmap.insert(JsonDbString::kCountStr, 1);
+
+ return makeResponse(resultmap, errormap);
+ }
+ int conflictsAfter = master.subObject(QsonStrings::kMetaStr).subList(QsonStrings::kConflictsStr).size();
+
+ if (!replication && (conflictsBefore < conflictsAfter)) {
+ setError( errormap, JsonDbError::UpdatingStaleVersion, "Updating stale version of object.");
+ return makeResponse(resultmap, errormap);
+ }
+ }
+ objectType = master.valueString(JsonDbString::kTypeStr);
+ bool forRemoval = master.valueBool(JsonDbString::kDeletedStr, false);
+
+ if (forCreation && forRemoval && !replication) {
+ setError( errormap, JsonDbError::MissingObject, "Can not create a deleted object.");
+ return makeResponse(resultmap, errormap);
+ }
+
+ if (objectType == "Partition") {
+ if (!forCreation) {
+ setError(errormap, JsonDbError::InvalidPartition, "Updates to partition objects not supported yet!");
+ return makeResponse(resultmap, errormap);
+ }
+
+ if (!partition.isEmpty() && partition != kDefaultPartitionName) {
+ setError(errormap, JsonDbError::InvalidPartition, "Partition objects can only be created in default partition");
+ return makeResponse(resultmap, errormap);
+ }
+
+ return createPartition(object);
+ }
+
+ // if the old object is a schema, make sure it's ok to remove it
+ if (_delrec.valueString(JsonDbString::kTypeStr) == JsonDbString::kSchemaTypeStr)
+ RETURN_IF_ERROR(errormap, checkCanRemoveSchema(_delrec));
+
+ // validate the new object
+ if (objectType == JsonDbString::kSchemaTypeStr)
+ RETURN_IF_ERROR(errormap, checkCanAddSchema(master, _delrec));
+ else if (objectType == JsonDbString::kMapTypeStr)
+ RETURN_IF_ERROR(errormap, validateMapObject(master));
+ else if (objectType == JsonDbString::kReduceTypeStr)
+ RETURN_IF_ERROR(errormap, validateReduceObject(master));
+
+ int dataSize = master.dataSize() - _delrec.dataSize();
+ if (!forRemoval)
+ RETURN_IF_ERROR(errormap, checkQuota(owner, dataSize, storage));
+
+ QsonMap response;
+
+ Notification::Action action;
+ if (forRemoval) {
+ action = Notification::Delete;
+ response = storage->removePersistentObject(_delrec, master);
+ } else if (!_delrec.isDocument()) {
+ action = Notification::Create;
+ response = storage->createPersistentObject(master);
+ } else {
+ action = Notification::Update;
+ response = storage->updatePersistentObject(master);
+ }
+
+ if (responseIsError(response))
+ return response;
+
+ if (forRemoval)
+ storage->addToQuota(owner, -_delrec.dataSize());
+ else
+ storage->addToQuota(owner, dataSize);
+
+ // replication might do a write not changing the head version
+ bool headVersionUpdated =
+ !forCreation && QsonVersion::version(_delrec) != QsonVersion::version(master);
+
+
+ // handle removing old schema, map, etc.
+ if (headVersionUpdated) {
+ QString oldType = _delrec.valueString(JsonDbString::kTypeStr);
+ if (oldType == JsonDbString::kSchemaTypeStr)
+ removeSchema(_delrec.valueString("name"));
+ else if (oldType == JsonDbString::kNotificationTypeStr)
+ removeNotification(uuid);
+ }
+
+ // create new schema, map, etc.
+ if (!forRemoval && (forCreation || headVersionUpdated)) {
+ if (objectType == JsonDbString::kSchemaTypeStr)
+ setSchema(object.valueString("name"), object.subObject("schema"));
+ else if (objectType == JsonDbString::kNotificationTypeStr)
+ createNotification(owner, master);
+ else if (objectType == kIndexTypeStr)
+ addIndex(master, partition);
+ }
+
+ // only notify if there is a visible change
+ // TODO: fix tests/benchmarks/jsondb-listmodel before re-enabling this
+ // if (forCreation || headVersionUpdated)
+ if (!forRemoval)
+ checkNotifications( object, action );
+ else
+ checkNotifications( _delrec, action );
+
+ return response;
+}
+
+/*!
+ This function takes a single QsonObject with a valid "_uuid" field.
+ It updates the database to match the new object.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count" : NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+*/
+QsonMap JsonDb::updateViewObject(const JsonDbOwner *owner, QsonMap& object, const QString &partition)
+{
+ QsonMap resultmap, errormap;
+ QString uuid, objectType;
+ bool replication = false;
+
+ RETURN_IF_ERROR(errormap, checkUuidPresent(object, uuid));
+ RETURN_IF_ERROR(errormap, checkTypePresent(object, objectType));
+ RETURN_IF_ERROR(errormap, validateSchema(objectType, object));
+ RETURN_IF_ERROR(errormap, checkAccessControl(owner, object, "write"));
+
+ if (populateIdBySchema(owner, object)) {
+ object.generateUuid();
+
+ if (object.valueString(JsonDbString::kUuidStr) != uuid) {
+ setError(errormap, JsonDbError::InvalidRequest, "_uuid mismatch, use create()");
+ return makeResponse(resultmap, errormap);
+ }
+ }
+ object.computeVersion();
+
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ if (!storage) {
+ setError(errormap, JsonDbError::InvalidPartition, QString("Invalid partition '%1'").arg(partition));
+ return makeResponse(resultmap, errormap);
+ }
+
+ // retrieve record we are updating to use
+ QsonMap master;
+
+ QsonMap _delrec = storage->lookupObject(uuid, objectType);
+ if (!_delrec.isEmpty()) {
+ master =_delrec;
+ } else if (!replication && object.valueBool(JsonDbString::kDeletedStr, false)) {
+ setError(errormap, JsonDbError::MissingObject, QLatin1String("Cannot remove non-existing object"));
+ return makeResponse(resultmap, errormap);
+ }
+
+ if (master.isDocument() && gRejectStaleUpdates) {
+ int conflictsBefore = master.subObject(QsonStrings::kMetaStr).subList(QsonStrings::kConflictsStr).size();
+ if (!master.mergeVersions(object)) {
+ // replay
+ resultmap.insert(JsonDbString::kUuidStr, uuid);
+ resultmap.insert(JsonDbString::kVersionStr, object.valueString(JsonDbString::kVersionStr));
+ resultmap.insert(JsonDbString::kCountStr, 1);
+
+ return makeResponse(resultmap, errormap);
+ }
+ int conflictsAfter = master.subObject(QsonStrings::kMetaStr).subList(QsonStrings::kConflictsStr).size();
+
+ if (!replication && (conflictsBefore < conflictsAfter)) {
+ setError( errormap, JsonDbError::UpdatingStaleVersion, "Updating stale version of object.");
+ return makeResponse(resultmap, errormap);
+ }
+ } else {
+ master = object;
+ // hack to make sure _lastVersion equals _version
+ master.insert(JsonDbString::kVersionStr, master.valueString(JsonDbString::kVersionStr));
+ }
+ objectType = master.valueString(JsonDbString::kTypeStr);
+
+ bool forRemoval = object.valueBool(JsonDbString::kDeletedStr, false);
+
+ // if the old object is a schema, make sure it's ok to remove it
+ if (_delrec.valueString(JsonDbString::kTypeStr) == JsonDbString::kSchemaTypeStr)
+ RETURN_IF_ERROR(errormap, checkCanRemoveSchema(_delrec));
+
+ // validate the new object
+ if (objectType == JsonDbString::kSchemaTypeStr)
+ RETURN_IF_ERROR(errormap, checkCanAddSchema(master, _delrec));
+ else if (objectType == JsonDbString::kMapTypeStr)
+ RETURN_IF_ERROR(errormap, validateMapObject(master));
+ else if (objectType == JsonDbString::kReduceTypeStr)
+ RETURN_IF_ERROR(errormap, validateReduceObject(master));
+
+ int dataSize = master.dataSize() - _delrec.dataSize();
+ if (!forRemoval)
+ RETURN_IF_ERROR(errormap, checkQuota(owner, dataSize, storage));
+
+ QsonMap response;
+
+ Notification::Action action;
+ if (forRemoval) {
+ action = Notification::Delete;
+ response = storage->removePersistentObject(_delrec, master);
+ } else if (!_delrec.isDocument()) {
+ action = Notification::Create;
+ response = storage->createPersistentObject(master);
+ } else {
+ action = Notification::Update;
+ response = storage->updatePersistentObject(master);
+ }
+
+ if (responseIsError(response))
+ return response;
+
+ if (forRemoval)
+ storage->addToQuota(owner, -_delrec.dataSize());
+ else
+ storage->addToQuota(owner, dataSize);
+
+ QString oldType = _delrec.valueString(JsonDbString::kTypeStr);
+ // handle removing old schema, map, etc.
+ if (oldType == JsonDbString::kSchemaTypeStr)
+ removeSchema(_delrec.valueString("name"));
+ else if (oldType == JsonDbString::kNotificationTypeStr)
+ removeNotification(uuid);
+
+ // create new schema, map, etc.
+ if (objectType == JsonDbString::kSchemaTypeStr)
+ setSchema(object.valueString("name"), object.subObject("schema"));
+ else if (objectType == JsonDbString::kNotificationTypeStr)
+ createNotification(owner, master);
+
+ checkNotifications( (action == Notification::Delete ? _delrec : object), action );
+
+ return response;
+}
+
+
+/*!
+ This function takes a single QsonObject with valid "_uuid" and "_version" fields.
+ It removes the item's verstion from the database by replacing it with a tombstone.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count": NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+*/
+
+QsonMap JsonDb::remove(const JsonDbOwner *owner, const QsonMap &object, const QString &partition)
+{
+ QsonMap errormap;
+ QString uuid;
+ RETURN_IF_ERROR(errormap, checkUuidPresent(object, uuid));
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+
+ // quick fix for the case when object only contains _uuid
+ // TODO: refactor
+ JsonDbBtreeStorage *storage = findPartition(partition);
+ QsonMap delrec = storage->lookupObject(uuid, objectType);
+ if (delrec.isEmpty())
+ delrec = object;
+
+ QsonMap tombstone;
+ tombstone.insert(JsonDbString::kUuidStr, uuid);
+ tombstone.insert(JsonDbString::kDeletedStr, true);
+ if (delrec.contains(JsonDbString::kTypeStr))
+ tombstone.insert(JsonDbString::kTypeStr, delrec.valueString(JsonDbString::kTypeStr));
+ if (delrec.contains(JsonDbString::kVersionStr))
+ tombstone.insert(JsonDbString::kVersionStr, delrec.valueString(JsonDbString::kVersionStr));
+ return update(owner, tombstone, partition);
+}
+
+/*!
+ This function takes a single QsonObject with a valid "_uuid" field.
+ It removes the item from the database.
+
+ On success it returns a QsonObject of the form:
+ { "error": NULL, "result" : { "count": NUMBER } }
+
+ On failure it returns a QsonObject of the form:
+ { "error": { "code": VALUE, "message": STRING }, "result": NULL }
+
+*/
+
+QsonMap JsonDb::removeViewObject(const JsonDbOwner *owner, QsonMap object, const QString &partition)
+{
+ QsonMap resultmap, errormap;
+ QString uuid;
+
+ RETURN_IF_ERROR(errormap, checkUuidPresent(object, uuid));
+
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+
+ QsonMap tombstone;
+ tombstone.insert(JsonDbString::kTypeStr, object.valueString(JsonDbString::kTypeStr));
+ tombstone.insert(JsonDbString::kUuidStr, object.valueString(JsonDbString::kUuidStr));
+ tombstone.insert(JsonDbString::kVersionStr, object.valueString(JsonDbString::kVersionStr));
+ tombstone.insert(JsonDbString::kDeletedStr, true);
+
+ QsonMap result = updateViewObject(owner, tombstone, partition);
+ return result;
+}
+
+QsonMap JsonDb::getObject(const QString &keyName, const QVariant &key, const QString &type, const QString &partition) const
+{
+ const QString &objectType = (keyName == JsonDbString::kTypeStr) ? key.toString() : type;
+ if (JsonDbBtreeStorage *storage = findPartition(partition))
+ return storage->getObject(keyName, key, objectType);
+ return QsonMap();
+}
+
+void JsonDb::checkNotifications( QsonMap object, Notification::Action action )
+{
+ //DBG() << object;
+
+ QStringList notificationKeys;
+ if (object.contains(JsonDbString::kTypeStr)) {
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+ notificationKeys << objectType;
+ if (mEagerViewSourceTypes.contains(objectType)) {
+ const QSet<QString> &targetTypes = mEagerViewSourceTypes[objectType];
+ for (QSet<QString>::const_iterator it = targetTypes.begin(); it != targetTypes.end(); ++it)
+ emit requestViewUpdate(*it, kDefaultPartitionName);
+ }
+ }
+ if (object.contains(JsonDbString::kUuidStr))
+ notificationKeys << object.valueString(JsonDbString::kUuidStr);
+ notificationKeys << "__generic_notification__";
+
+ QHash<QString, QsonMap> objectCache;
+ for (int i = 0; i < notificationKeys.size(); i++) {
+ QString key = notificationKeys[i];
+ QMultiMap<QString, Notification *>::const_iterator it = mKeyedNotifications.find(key);
+ while ((it != mKeyedNotifications.end()) && (it.key() == key)) {
+ Notification *n = it.value();
+ DBG() << "Notification" << n->query() << n->actions();
+ if ( n->actions() & action ) {
+ QsonMap r;
+ if (!n->query().isEmpty()) {
+ DBG() << "Checking notification" << n->query() << endl
+ << " for object" << object;
+ JsonDbQuery *query = n->parsedQuery();
+ if (query->match(object, &objectCache, 0/*mStorage*/))
+ r = object;
+ DBG() << "Got result" << r;
+ } else {
+ r = object;
+ }
+ if (!r.isEmpty()) {
+ QString actionStr = ( action == Notification::Create ? JsonDbString::kCreateStr :
+ (action == Notification::Update ? JsonDbString::kUpdateStr :
+ JsonDbString::kRemoveStr ));
+ emit notified(n->uuid(), r, actionStr);
+ }
+ }
+
+ ++it;
+ }
+ }
+}
+
+QsonMap JsonDb::addIndex(const QString &fieldName, const QString &fieldType, const QString &objectType, const QString &partition)
+{
+ if (JsonDbBtreeStorage *storage = findPartition(partition))
+ return storage->addIndex(fieldName, fieldType, objectType);
+ return QsonMap();
+}
+
+void JsonDb::addIndex(QsonMap indexObject, const QString &partition)
+{
+ QString fieldName = indexObject.valueString(kFieldStr);
+ QString fieldType = indexObject.valueString(kFieldTypeStr);
+ QString objectType = indexObject.valueString(kObjectTypeStr);
+
+ if (JsonDbBtreeStorage *storage = findPartition(partition))
+ storage->addIndex(fieldName, fieldType, objectType);
+}
+
+void JsonDb::updateSchemaIndexes(const QString &schemaName, QsonMap object, const QStringList &path)
+{
+ QsonMap properties = object.subObject("properties");
+ const QList<QString> keys = properties.keys();
+ for (int i = 0; i < keys.size(); i++) {
+ const QString &k = keys[i];
+ QsonMap propertyInfo = properties.subObject(k);
+ if (propertyInfo.contains("indexed")) {
+ QString propertyType = (propertyInfo.contains("type") ? propertyInfo.valueString("type") : "string");
+ QStringList kpath = path;
+ kpath << k;
+ JsonDbBtreeStorage *storage = findPartition(kDefaultPartitionName);
+ storage->addIndex(kpath.join("."), propertyType, schemaName);
+ }
+ if (propertyInfo.contains("properties")) {
+ updateSchemaIndexes(schemaName, propertyInfo, path + (QStringList() << k));
+ }
+ }
+}
+
+bool JsonDb::populateIdBySchema(const JsonDbOwner *owner, QsonMap &object)
+{
+ // minimize inserts
+ if (object.valueString(JsonDbString::kOwnerStr) != owner->ownerId())
+ object.insert(JsonDbString::kOwnerStr, owner->ownerId());
+
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+ if (mSchemas.contains(objectType)) {
+ QsonMap schema = mSchemas.value(objectType);
+ if (schema.contains("primaryKey")) {
+ QsonObject::Type pkType = schema.valueType("primaryKey");
+ QString _id = QString("primaryKey::%1:").arg(objectType);
+
+ if (pkType == QsonObject::StringType) {
+ QString keyName = schema.valueString("primaryKey");
+ _id.append(keyName).append('=').append(object.valueString(keyName));
+ } else if (pkType == QsonObject::ListType) {
+ QsonList keyList = schema.subList("primaryKey");
+ for (int i = 0; i < keyList.size(); i++) {
+ QString keyName = keyList.at<QString>(i);
+ _id.append(":").append(keyName).append('=').append(object.valueString(keyName));
+ }
+ }
+ // minimize inserts
+ if (object.valueString("_id") != _id)
+ object.insert("_id", _id);
+
+ return true;
+ }
+ }
+ return false;
+}
+
+void JsonDb::initSchemas()
+{
+ if (gVerbose) qDebug() << "initSchemas";
+ {
+ QsonMap getObjectResponse = getObject(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr,
+ QString(), kDefaultPartitionName);
+ QsonList schemas = getObjectResponse.subList("result");
+ for (int i = 0; i < schemas.size(); ++i) {
+ QsonMap schemaObject = schemas.at<QsonMap>(i);
+ QString schemaName = schemaObject.valueString("name");
+ QsonMap schema = schemaObject.subObject("schema");
+ setSchema(schemaName, schema);
+ }
+ }
+ foreach (const QString &schemaName, (QStringList() << JsonDbString::kNotificationTypeStr << JsonDbString::kViewTypeStr
+ << "Capability" << kIndexTypeStr)) {
+ if (!mSchemas.contains(schemaName)) {
+ QFile schemaFile(QString(":schema/%1.json").arg(schemaName));
+ schemaFile.open(QIODevice::ReadOnly);
+ JsonReader parser;
+ bool ok = parser.parse(schemaFile.readAll());
+ if (!ok) {
+ qWarning() << "Parsing " << schemaName << " schema" << parser.errorString();
+ return;
+ }
+ QsonMap schema = variantToQson(parser.result().toMap());
+ QsonMap schemaObject;
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", schemaName);
+ schemaObject.insert("schema", schema);
+ create(mOwner, schemaObject);
+ }
+ }
+ {
+ addIndex("name", "string", "Capability");
+ const QString capabilityName("RootCapability");
+ QFile capabilityFile(QString(":schema/%1.json").arg(capabilityName));
+ capabilityFile.open(QIODevice::ReadOnly);
+ JsonReader parser;
+ bool ok = parser.parse(capabilityFile.readAll());
+ if (!ok) {
+ qWarning() << "Parsing " << capabilityName << " capability" << parser.errorString();
+ return;
+ }
+ QsonMap capability = variantToQson(parser.result().toMap());
+ QString name = capability.valueString("name");
+ QsonMap getObjectResponse = getObject("name", name, "Capability");
+ int count = getObjectResponse.valueInt("count", 0);
+ if (!count) {
+ if (gVerbose)
+ qDebug() << "Creating capability" << capability;
+ create(mOwner, capability);
+ } else {
+ QsonMap currentCapability = getObjectResponse.subList("result").at<QsonMap>(0);
+ if (currentCapability.value<QsonElement>("accessRules") != capability.value<QsonElement>("accessRules")) {
+ currentCapability.insert("accessRules", capability.value<QsonElement>("accessRules"));
+ update(mOwner, currentCapability);
+ }
+ }
+ }
+}
+
+void JsonDb::setSchema(const QString &schemaName, QsonMap schema)
+{
+ if (gVerbose)
+ qDebug() << "setSchema" << schemaName << schema;
+ QsonMap errors = mSchemas.insert(schemaName, schema);
+
+ if (!errors.isEmpty()) {
+ //if (gVerbose) {
+ qDebug() << "setSchema failed because of errors" << schemaName << schema;
+ qDebug() << errors;
+ //}
+ // FIXME should we accept broken schemas?
+ // return;
+ }
+ if (schema.contains("extends")) {
+ QString extendedSchemaName = schema.valueString("extends");
+ if (extendedSchemaName == JsonDbString::kViewTypeStr) {
+ mViewTypes.insert(schemaName);
+ //TODO fix call to findPartition
+ JsonDbBtreeStorage *storage = findPartition(kDefaultPartitionName);
+ storage->addView(schemaName);
+ if (gVerbose) qDebug() << "viewTypes" << mViewTypes;
+ }
+ }
+ if (schema.contains("properties"))
+ updateSchemaIndexes(schemaName, schema);
+}
+
+void JsonDb::removeSchema(const QString &schemaName)
+{
+ if (gVerbose)
+ qDebug() << "removeSchema" << schemaName;
+
+ if (mSchemas.contains(schemaName)) {
+ QsonMap schema = mSchemas.take(schemaName);
+
+ if (schema.valueString("extends") == JsonDbString::kViewTypeStr)
+ mViewTypes.remove(schemaName);
+ }
+}
+
+QsonMap JsonDb::validateSchema(const QString &schemaName, QsonMap object)
+{
+ if (!gValidateSchemas) {
+ DBG() << "Not validating schemas";
+ return QsonMap();
+ }
+
+ return mSchemas.validate(schemaName, object);
+}
+
+QsonMap JsonDb::validateMapObject(QsonMap map)
+{
+ QString targetType = map.valueString("targetType");
+ QString sourceType = map.valueString("sourceType");
+
+ if (map.valueBool(JsonDbString::kDeletedStr, false))
+ return QsonMap();
+ if (targetType.isEmpty())
+ return makeError(JsonDbError::InvalidMap, "targetType property for Map not specified");
+ if (!mViewTypes.contains(targetType))
+ return makeError(JsonDbError::InvalidMap, "targetType must be of a type that extends View");
+ if (sourceType.isEmpty())
+ return makeError(JsonDbError::InvalidMap, "sourceType property for Map not specified");
+ if (map.valueString("map").isEmpty())
+ return makeError(JsonDbError::InvalidMap, "map function for Map not specified");
+
+ return QsonMap();
+}
+
+QsonMap JsonDb::validateReduceObject(QsonMap reduce)
+{
+ QString targetType = reduce.valueString("targetType");
+ QString sourceType = reduce.valueString("sourceType");
+
+ if (reduce.valueBool(JsonDbString::kDeletedStr, false))
+ return QsonMap();
+ if (targetType.isEmpty())
+ return makeError(JsonDbError::InvalidReduce, "targetType property for Reduce not specified");
+ if (!mViewTypes.contains(targetType))
+ return makeError(JsonDbError::InvalidReduce, "targetType must be of a type that extends View");
+ if (sourceType.isEmpty())
+ return makeError(JsonDbError::InvalidReduce, "sourceType property for Reduce not specified");
+ if (reduce.valueString("sourceKeyName").isEmpty())
+ return makeError(JsonDbError::InvalidReduce, "sourceKeyName property for Reduce not specified");
+ if (reduce.valueString("add").isEmpty())
+ return makeError(JsonDbError::InvalidReduce, "add function for Reduce not specified");
+ if (reduce.valueString("subtract").isEmpty())
+ return makeError(JsonDbError::InvalidReduce, "subtract function for Reduce not specified");
+
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkUuidPresent(QsonMap object, QString &uuid)
+{
+ if (!object.isDocument())
+ return makeError(JsonDbError::MissingUUID, "Missing '_uuid' field in object");
+ uuid = object.valueString(JsonDbString::kUuidStr);
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkTypePresent(QsonMap object, QString &type)
+{
+ type = object.valueString(JsonDbString::kTypeStr);
+ if (type.isEmpty()) {
+ QString str = JsonWriter().toString(qsonToVariant(object));
+ return makeError(JsonDbError::MissingType, QString("Missing '_type' field in object '%1'").arg(str));
+ }
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkNaturalObjectType(QsonMap object, QString &type)
+{
+ type = object.valueString(JsonDbString::kTypeStr);
+ if (mViewTypes.contains(type)) {
+ QString str = JsonWriter().toString(qsonToVariant(object));
+ return makeError(JsonDbError::MissingType, QString("Cannot create/remove object of view type '%1': '%2'").arg(type).arg(str));
+ }
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkAccessControl(const JsonDbOwner *owner, QsonMap object,
+ const QString &op)
+{
+ if (!owner->isAllowed(object, op))
+ return makeError(JsonDbError::OperationNotPermitted, "Access denied");
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkQuota(const JsonDbOwner *owner, int size, JsonDbBtreeStorage *partition)
+{
+ if (!partition->checkQuota(owner, size))
+ return makeError(JsonDbError::QuotaExceeded, "Quota exceeded.");
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkCanAddSchema(QsonMap schema, QsonMap oldSchema)
+{
+ if (schema.valueBool(JsonDbString::kDeletedStr, false))
+ return QsonMap();
+ if (!schema.contains("name")
+ || !schema.contains("schema"))
+ return makeError(JsonDbError::InvalidSchemaOperation,
+ "_schemaType objects must specify both name and schema properties");
+
+ QString schemaName = schema.valueString("name");
+
+ if (schemaName.isEmpty())
+ return makeError(JsonDbError::InvalidSchemaOperation,
+ "name property of _schemaType object must be specified");
+
+ if (mSchemas.contains(schemaName) && oldSchema.valueString("name") != schemaName)
+ return makeError(JsonDbError::InvalidSchemaOperation,
+ QString("A schema with name %1 already exists").arg(schemaName));
+
+ return QsonMap();
+}
+
+QsonMap JsonDb::checkCanRemoveSchema(QsonMap schema)
+{
+ QString schemaName = schema.valueString("name");
+
+ // check if any objects exist
+ QsonMap getObjectResponse = getObject(JsonDbString::kTypeStr, schemaName);
+ // for non-View types, if objects exist the schema cannot be removed
+ if (!mViewTypes.contains(schemaName)) {
+ if (getObjectResponse.valueInt("count") != 0)
+ return makeError(JsonDbError::InvalidSchemaOperation,
+ QString("%1 object(s) of type %2 exist. You cannot remove the schema")
+ .arg(getObjectResponse.valueInt("count"))
+ .arg(schemaName));
+ }
+
+ // for View types, make sure no Maps or Reduces point at this type
+ // the call to getObject will have updated the view, so pending Map or Reduce object removes will be forced
+ if (mMapDefinitionsByTarget.contains(schemaName)) {
+ return makeError(JsonDbError::InvalidSchemaOperation,
+ QString("A Map object with targetType of %2 exists. You cannot remove the schema")
+ .arg(schemaName));
+ }
+
+ if (mReduceDefinitionsByTarget.contains(schemaName)) {
+ return makeError(JsonDbError::InvalidSchemaOperation,
+ QString("A Reduce object with targetType of %2 exists. You cannot remove the schema")
+ .arg(schemaName));
+ }
+
+ return QsonMap();
+}
+
+const Notification *JsonDb::createNotification(const JsonDbOwner *owner, QsonMap object)
+{
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ QStringList actions = object.value<QsonList>(JsonDbString::kActionsStr).toStringList();
+ QString query = object.valueString(JsonDbString::kQueryStr);
+ QsonMap bindings = object.subObject("bindings");
+
+ Notification *n = new Notification(owner, uuid, query, actions);
+ JsonDbQuery parsedQuery = JsonDbQuery::parse(query, bindings);
+ const QList<OrQueryTerm> &orQueryTerms = parsedQuery.queryTerms;
+ n->setCompiledQuery(new JsonDbQuery(parsedQuery.queryTerms, parsedQuery.orderTerms));
+
+ bool generic = true;
+ for (int i = 0; i < orQueryTerms.size(); i++) {
+ const OrQueryTerm &orQueryTerm = orQueryTerms[i];
+ const QList<QueryTerm> &terms = orQueryTerm.terms();
+ if (terms.size() == 1) {
+ const QueryTerm &term = terms[0];
+ if (term.op() == "=") {
+ if (term.fieldName() == JsonDbString::kUuidStr) {
+ mKeyedNotifications.insert(term.value().toString(), n);
+ generic = false;
+ break;
+ } else if (term.fieldName() == JsonDbString::kTypeStr) {
+ QString objectType = term.value().toString();
+ mKeyedNotifications.insert(objectType, n);
+ updateEagerViewTypes(objectType);
+ generic = false;
+ break;
+ }
+ }
+ }
+ }
+ if (generic) {
+ mKeyedNotifications.insert("__generic_notification__", n);
+ }
+
+ mNotificationMap[uuid] = n;
+ return n;
+}
+
+void JsonDb::removeNotification(const QString &uuid)
+{
+ if (mNotificationMap.contains(uuid)) {
+ Notification *n = mNotificationMap.value(uuid);
+ mNotificationMap.remove(uuid);
+ const JsonDbQuery *parsedQuery = n->parsedQuery();
+ const QList<OrQueryTerm> &orQueryTerms = parsedQuery->queryTerms;
+ for (int i = 0; i < orQueryTerms.size(); i++) {
+ const OrQueryTerm &orQueryTerm = orQueryTerms[i];
+ const QList<QueryTerm> &terms = orQueryTerm.terms();
+ if (terms.size() == 1) {
+ const QueryTerm &term = terms[0];
+ if (term.op() == "=") {
+ if (term.fieldName() == JsonDbString::kTypeStr) {
+ mKeyedNotifications.remove(term.value().toString(), n);
+ } else if (term.fieldName() == JsonDbString::kUuidStr) {
+ QString objectType = term.value().toString();
+ mKeyedNotifications.remove(objectType, n);
+ }
+ }
+ }
+ }
+
+ mKeyedNotifications.remove("__generic_notification__", n);
+
+ delete n;
+ }
+}
+
+void JsonDb::updateEagerViewTypes(const QString &objectType)
+{
+ for (QMap<QString,JsonDbMapDefinition*>::const_iterator it = mMapDefinitionsByTarget.find(objectType);
+ (it != mMapDefinitionsByTarget.end() && it.key() == objectType);
+ ++it) {
+ JsonDbMapDefinition *def = it.value();
+ QString sourceType = def->sourceType();
+ QSet<QString> &targetTypes = mEagerViewSourceTypes[sourceType];
+ targetTypes.insert(objectType);
+ // now recurse until we get to a non-view sourceType
+ updateEagerViewTypes(sourceType);
+ }
+ for (QMap<QString,JsonDbReduceDefinition*>::const_iterator it = mReduceDefinitionsByTarget.find(objectType);
+ (it != mReduceDefinitionsByTarget.end() && it.key() == objectType);
+ ++it) {
+ JsonDbReduceDefinition *def = it.value();
+ QString sourceType = def->sourceType();
+ QSet<QString> &targetTypes = mEagerViewSourceTypes[sourceType];
+ targetTypes.insert(objectType);
+ // now recurse until we get to a non-view sourceType
+ updateEagerViewTypes(sourceType);
+ }
+}
+
+JsonDbBtreeStorage *JsonDb::findPartition(const QString &name) const
+{
+ if (name.isEmpty())
+ return mStorages.value(kDefaultPartitionName, 0);
+ return mStorages.value(name, 0);
+}
+
+QsonMap JsonDb::createPartition(const QsonMap &object)
+{
+ QString name = object.value<QString>("name");
+ if (mStorages.contains(name)) {
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Already have a partition with a given name '%1'").arg(name));
+ return makeResponse(resultmap, errormap);
+ }
+ // verify partition name - only alphanum characters allowed
+ bool isAlNum = true;
+ for (int i = 0; i < name.length(); ++i) {
+ if (!name.at(i).isLetterOrNumber()) {
+ isAlNum = false;
+ break;
+ }
+ }
+ if (!isAlNum) {
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Partition name can only be alphanumeric '%1'").arg(name));
+ return makeResponse(resultmap, errormap);
+ }
+
+ QString filename = mFilePath + name;
+
+ quint32 infostate = mBdbInfo->tag();
+ mBdbInfo->begin();
+
+ QByteArray value;
+ mBdbInfo->get(QByteArray("partitions"), value);
+ QsonList partitions = QsonParser::fromRawData(value).toList();
+
+ QsonMap partition;
+ partition.insert(QLatin1String("name"), name);
+ partition.insert(QLatin1String("file"), filename);
+ partitions.append(partition);
+ mBdbInfo->put(QByteArray("partitions"), partitions.data());
+
+ mBdbInfo->commit(infostate + 1);
+
+ JsonDbBtreeStorage *storage = new JsonDbBtreeStorage(filename, name, this);
+ if (gVerbose) qDebug() << "Opening partition" << name;
+
+ if (!storage->open()) {
+ qWarning() << "Failed to initialize partition" << name << "at" << filename;
+ QsonMap resultmap, errormap;
+ setError(errormap, JsonDbError::InvalidPartition, QString("Cannot initialize a partition '%1'").arg(name));
+ return makeResponse(resultmap, errormap);
+ }
+ mStorages.insert(name, storage);
+ initMap(name);
+
+ QsonMap resultmap, errormap;
+ return makeResponse(resultmap, errormap);
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondb.h b/src/daemon/jsondb.h
new file mode 100644
index 00000000..7eeca857
--- /dev/null
+++ b/src/daemon/jsondb.h
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_H
+#define JSONDB_H
+
+#include <QDebug>
+#include <QObject>
+#include <QHash>
+#include <QJSEngine>
+#include <QStringList>
+#include <QVariant>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "jsondbquery.h"
+#include "jsondbbtreestorage.h"
+#include "jsondb-map-reduce.h"
+#include "notification.h"
+#include "schemamanager_p.h"
+
+class TestJsonDb;
+class AoDb;
+
+namespace QtAddOn { namespace JsonDb {
+
+extern bool gValidateSchemas;
+extern bool gRejectStaleUpdates;
+extern bool gUseQsonInDb;
+extern bool gUseJsonInDb;
+extern bool gVerbose;
+extern bool gPrintErrors;
+#ifndef QT_NO_DEBUG_OUTPUT
+extern bool gDebug;
+extern bool gDebugRecovery;
+#else
+static const bool gDebug = false;
+static const bool gDebugRecovery = false;
+#endif
+
+extern const QString kDefaultPartitionName;
+extern const QString kSortKeysStr;
+extern const QString kStateStr;
+
+class JsonDbProxy;
+class JsonDbQuery;
+class ObjectTable;
+class JsonDbBtreeStorage;
+
+class JsonDb : public QObject
+{
+ Q_OBJECT
+
+public:
+ JsonDb( const QString& filename, QObject *parent=0 );
+ ~JsonDb();
+
+ bool open();
+ void close();
+ bool clear();
+ bool checkValidity();
+
+ QsonMap find(const JsonDbOwner *owner, QsonMap object, const QString &partition = QString());
+ QsonMap create(const JsonDbOwner *owner, QsonMap&, const QString &partition = QString());
+ QsonMap update(const JsonDbOwner *owner, QsonMap&, const QString &partition = QString(), bool replication = false);
+ QsonMap remove(const JsonDbOwner *owner, const QsonMap&, const QString &partition = QString());
+
+ QsonMap createList(const JsonDbOwner *owner, QsonList&, const QString &partition = QString());
+ QsonMap updateList(const JsonDbOwner *owner, QsonList&, const QString &partition = QString(), bool replication = false);
+ QsonMap removeList(const JsonDbOwner *owner, QsonList, const QString &partition = QString());
+
+ QsonMap createViewObject(const JsonDbOwner *owner, QsonMap&, const QString &partition = QString());
+ QsonMap updateViewObject(const JsonDbOwner *owner, QsonMap&, const QString &partition = QString());
+ QsonMap removeViewObject(const JsonDbOwner *owner, QsonMap, const QString &partition = QString());
+
+ QsonMap changesSince(const JsonDbOwner *owner, QsonMap object, const QString &partition = QString());
+
+ JsonDbOwner *owner() const { return mOwner; }
+ QJSEngine *scriptEngine() { return mScriptEngine; }
+ void load(const QString &jsonFileName);
+
+ QsonMap getObject(const QString &keyName, const QVariant &key, const QString &type = QString(), const QString &partition = QString()) const;
+
+ QString getTablePrefix();
+ void setTablePrefix(const QString &prefix);
+
+ static QVariant propertyLookup(QsonMap v, const QString &path);
+ static QVariant propertyLookup(QVariantMap v, const QStringList &path);
+ static QVariant propertyLookup(QsonMap o, const QStringList &path);
+
+ void updateView(const QString &viewType, const QString &partitionName = kDefaultPartitionName);
+
+protected:
+ bool populateIdBySchema(const JsonDbOwner *owner, QsonMap &object);
+
+ void initSchemas();
+ void updateSchemaIndexes(const QString &schemaName, QsonMap object, const QStringList &path=QStringList());
+ void setSchema(const QString &schemaName, QsonMap object);
+ void removeSchema(const QString &schemaName);
+
+ QsonMap validateSchema(const QString &schemaName, QsonMap object);
+ QsonMap validateMapObject(QsonMap map);
+ QsonMap validateReduceObject(QsonMap reduce);
+ QsonMap checkUuidPresent(QsonMap object, QString &uuid);
+ QsonMap checkTypePresent(QsonMap, QString &type);
+ QsonMap checkNaturalObjectType(QsonMap object, QString &type);
+ QsonMap checkAccessControl(const JsonDbOwner *owner, QsonMap object, const QString &op);
+ QsonMap checkQuota(const JsonDbOwner *owner, int size, JsonDbBtreeStorage *partition);
+ QsonMap checkCanAddSchema(QsonMap schema, QsonMap oldSchema = QsonMap());
+ QsonMap checkCanRemoveSchema(QsonMap schema);
+
+ enum Action { Create, Remove };
+
+ QsonMap addIndex(const QString &fieldName, const QString &typeName = QString("string"),
+ const QString &objectType = QString(),
+ const QString &partition = QString());
+ void addIndex(QsonMap indexObject, const QString &partition);
+
+ void initMap(const QString &partition);
+ void createMapDefinition(QsonMap mapDefinition, bool firstTime, const QString &partition);
+ void removeMapDefinition(QsonMap mapDefinition);
+
+ void createReduceDefinition(QsonMap reduceDefinition, bool firstTime, const QString &partition);
+ void removeReduceDefinition(QsonMap reduceDefinition);
+ void removeReduceDefinition(JsonDbReduceDefinition *def);
+ quint32 findUpdatedMapReduceDefinitions(JsonDbBtreeStorage *partition, const QString &definitionType, const QString &viewType, quint32 targetStateNumber,
+ QMap<QString, QsonMap> &removedDefinitions, QMap<QString, QsonMap> &addedDefinitions) const;
+
+ void updateMap(const QString &viewType, const QString &partitionName);
+ void updateReduce(const QString &viewType, const QString &partitionName);
+ void updateEagerViewTypes(const QString &objectType);
+
+ JsonDbQuery parseJsonQuery(const QString &query, QsonObject &bindings) const;
+
+ void checkNotifications(QsonMap obj, Notification::Action action);
+
+ const Notification *createNotification(const JsonDbOwner *owner, QsonMap object);
+ void removeNotification(const QString &uuid);
+
+ QString filePath() const { return mFilePath; }
+
+ static void setError( QsonMap& map, int code, const QString &message );
+ static QsonMap makeError(int code, const QString &message);
+ static QsonMap makeResponse( QsonMap& resultmap, QsonMap& errormap, bool silent = false );
+ static QsonMap makeErrorResponse(QsonMap &resultmap, int code, const QString &message, bool silent = false );
+ static bool responseIsError( QsonMap responseMap );
+// static bool responseIsGood( QsonMap responseMap );
+ static QString uuidhex(uint data, int digits);
+ static QString createDatabaseId();
+
+ JsonDbBtreeStorage *findPartition(const QString &name) const;
+ QsonMap createPartition(const QsonMap &object);
+
+signals:
+ void notified(const QString &id, QsonMap, const QString &action);
+ void requestViewUpdate(QString viewType, QString partition);
+
+protected:
+ AoDb *mBdbInfo;
+ JsonDbOwner *mOwner;
+ QHash<QString, JsonDbBtreeStorage *> mStorages;
+ QJSEngine *mScriptEngine;
+ JsonDbProxy *mJsonDbProxy;
+ bool mOpen;
+ QString mFilePath;
+ QString mDatabaseId;
+ SchemaManager mSchemas;
+ QMap<QString,Notification*> mNotificationMap;
+ QMultiMap<QString,Notification*> mKeyedNotifications;
+ QSet<QString> mViewTypes;
+ QMap<QString,QSet<QString> > mEagerViewSourceTypes; // set of eager view types dependent on this source type
+ QMultiMap<QString,JsonDbMapDefinition*> mMapDefinitionsBySource; // maps map source type to view definition
+ QMultiMap<QString,JsonDbMapDefinition*> mMapDefinitionsByTarget; // maps map target type to view definition
+ QMultiMap<QString,JsonDbReduceDefinition*> mReduceDefinitionsBySource; // maps reduce source type to view definition
+ QMultiMap<QString,JsonDbReduceDefinition*> mReduceDefinitionsByTarget; // maps reduce target type to view definition
+ QSet<QString> mViewsUpdating;
+
+ friend class ::TestJsonDb;
+ friend class JsonDbBtreeStorage;
+ friend class JsonDbMapDefinition;
+ friend class JsonDbReduceDefinition;
+ friend class JsonDbQuery;
+ friend class ObjectTable;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif /* JSONDB_H */
diff --git a/src/daemon/jsondb.qrc b/src/daemon/jsondb.qrc
new file mode 100644
index 00000000..2a12e110
--- /dev/null
+++ b/src/daemon/jsondb.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>schema/notification.json</file>
+ <file>schema/View.json</file>
+ <file>schema/Capability.json</file>
+ <file>schema/RootCapability.json</file>
+ <file>schema/Index.json</file>
+ </qresource>
+</RCC>
diff --git a/src/daemon/jsondbbtreestorage.cpp b/src/daemon/jsondbbtreestorage.cpp
new file mode 100644
index 00000000..309a3740
--- /dev/null
+++ b/src/daemon/jsondbbtreestorage.cpp
@@ -0,0 +1,1846 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-trace.h"
+
+#include <QObject>
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QRegExp>
+#include <QString>
+#include <QElapsedTimer>
+#include <QUuid>
+#include <QtAlgorithms>
+#include <QtEndian>
+#include <QStringBuilder>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <QtJsonDbQson/private/qson_p.h>
+#include <QtJsonDbQson/private/qsonparser_p.h>
+
+#include "jsondb.h"
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+#include "aodb.h"
+#include "jsondbbtreestorage.h"
+#include "jsondbindex.h"
+#include "objecttable.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+//#define QT_NO_DEBUG_OUTPUT
+#ifndef QT_NO_DEBUG_OUTPUT
+extern bool gDebug;
+#define DBG() if (gDebug) qDebug() << Q_FUNC_INFO << __LINE__
+#else
+#define DBG() if (0) qDebug() << Q_FUNC_INFO
+#endif
+bool gVerboseCheckValidity = false;
+
+const QString kDbidTypeStr("DatabaseId");
+const QString kIndexTypeStr("Index");
+const QString kFieldStr("fieldName");
+const QString kFieldTypeStr("fieldType");
+const QString kObjectTypeStr("objectType");
+const QString kDatabaseSchemaVersionStr("databaseSchemaVersion");
+const QString gDatabaseSchemaVersion = "0.2";
+
+int forwardKeyCmp(const char *aptr, size_t asiz, const char *bptr, size_t bsiz, void *op);
+
+JsonDbBtreeStorage::JsonDbBtreeStorage(const QString &filename, const QString &name, JsonDb *jsonDb)
+ : QObject(jsonDb)
+ , mJsonDb(jsonDb)
+ , mObjectTable(0)
+ , mBdbIndexes(0)
+ , mPartitionName(name)
+ , mFilename(filename)
+ , mTransactionDepth(0)
+ , mWildCardPrefixRegExp("([^*?\\[\\]\\\\]+).*")
+{
+}
+
+JsonDbBtreeStorage::~JsonDbBtreeStorage()
+{
+ if (mTransactionDepth) {
+ qCritical() << "JsonDbBtreeStorage::~JsonDbBtreeStorage"
+ << "closing while transaction open" << "mTransactionDepth" << mTransactionDepth;
+ }
+ close();
+}
+
+bool JsonDbBtreeStorage::close()
+{
+ foreach (ObjectTable *table, mViews.values()) {
+ delete table;
+ }
+ mViews.clear();
+
+ delete mObjectTable;
+ mObjectTable = 0;
+
+ for (int i = 0; i < (int)(sizeof(mBdbs)/sizeof(mBdbs[0])); ++i) {
+ delete mBdbs[i];
+ mBdbs[i] = 0;
+ }
+ return true;
+}
+
+bool JsonDbBtreeStorage::open()
+{
+ DBG() << "JsonDbBtree::open" << mPartitionName << mFilename;
+
+ QFileInfo fi(mFilename);
+
+ mObjectTable = new ObjectTable(this);
+ mBdbs[0] = mBdbIndexes = new AoDb();
+
+ mObjectTable->open(mFilename, AoDb::NoSync | AoDb::UseSyncMarker);
+
+#if 0
+ if (!mBdbIndexes->setCmpFunc(objectKeyCmp, 0)) {
+ qCritical() << "mBdbIndexes->setCmpFunc" << mBdb->errorMessage();
+ return false;
+ }
+#endif
+
+ QString dir = fi.dir().path();
+ QString basename = fi.fileName();
+ if (basename.endsWith(".db"))
+ basename.chop(3);
+ if (!mBdbIndexes->open(QString("%1/%2-Indexes.db").arg(dir).arg(basename),
+ AoDb::NoSync | AoDb::UseSyncMarker)) {
+ qCritical() << "mBdbIndexes->open" << mBdbIndexes->errorMessage();
+ mBdbIndexes->close();
+ return false;
+ }
+
+ if (!checkStateConsistency()) {
+ qCritical() << "JsonDbBtreeStorage::open()" << "Unable to recover database";
+ return false;
+ }
+
+ bool rebuildingDatabaseMetadata = false;
+
+ QString partitionId;
+ if (mBdbIndexes->count()) {
+ QByteArray baKey, baValue;
+ AoDbCursor cursor(mBdbIndexes);
+ if (cursor.first()) {
+ cursor.current(baKey, baValue);
+ if (baValue.size() > 4) {
+ QsonMap object = QsonParser::fromRawData(baValue).toMap();
+ if (object.valueString(JsonDbString::kTypeStr) != kDbidTypeStr) {
+ qCritical() << __FUNCTION__ << __LINE__ << "no dbid in indexes table";
+ } else {
+ partitionId = object.valueString("id");
+ QString partitionName = object.value<QString>("name");
+ if (partitionName != mPartitionName || !object.contains(kDatabaseSchemaVersionStr)
+ || object.valueString(kDatabaseSchemaVersionStr) != gDatabaseSchemaVersion) {
+ if (gVerbose) qDebug() << "Rebuilding database metadata";
+ rebuildingDatabaseMetadata = true;
+ }
+ }
+ }
+ }
+ }
+ if (rebuildingDatabaseMetadata) {
+ mBdbIndexes->clear();
+ }
+ if (partitionId.isEmpty() || rebuildingDatabaseMetadata) {
+ if (partitionId.isEmpty())
+ partitionId = QUuid::createUuid().toString();
+
+ QByteArray baKey(4, 0);
+ qToBigEndian(0, (uchar *)baKey.data());
+
+ QsonMap object;
+ object.insert(JsonDbString::kTypeStr, kDbidTypeStr);
+ object.insert(QLatin1String("id"), partitionId);
+ object.insert(QLatin1String("name"), mPartitionName);
+ object.insert(kDatabaseSchemaVersionStr, gDatabaseSchemaVersion);
+ QByteArray baObject = object.data();
+ bool ok = mBdbIndexes->put(baKey, baObject);
+ Q_ASSERT(ok);
+ }
+ if (gVerbose) qDebug() << "partition" << mPartitionName << "id" << partitionId;
+
+ initIndexes();
+
+ return true;
+}
+
+bool JsonDbBtreeStorage::clear()
+{
+ if (mObjectTable->bdb()) {
+ qCritical() << "Cannot clear database while it is open.";
+ return false;
+ }
+ QStringList filters;
+ QFileInfo fi(mFilename);
+ filters << QString::fromLatin1("%1*.db").arg(fi.baseName());
+ QDir dir(fi.absolutePath());
+ QStringList lst = dir.entryList(filters);
+ foreach (const QString &fileName, lst) {
+ if (gVerbose)
+ qDebug() << "removing" << fileName;
+ if (!dir.remove(fileName)) {
+ qCritical() << "Failed to remove" << fileName;
+ return false;
+ }
+ }
+ return true;
+}
+
+
+enum FieldValueKind {
+ FvkVoid,
+ FvkString,
+ FvkInt,
+ FvkDouble,
+
+ FvkLastKind = FvkDouble
+};
+
+inline FieldValueKind qVariantFieldValueKind(const QVariant &v)
+{
+ if (!v.isValid())
+ return FvkVoid;
+ if (v.type() == QVariant::String) // this test here because String canConvert to Int
+ return FvkString;
+ else if (v.canConvert(QVariant::Int))
+ return FvkInt;
+ else if (v.canConvert(QVariant::Double))
+ return FvkDouble;
+ else
+ return FvkString;
+}
+
+inline quint16 fieldValueSize(FieldValueKind fvk, const QVariant &fieldValue)
+{
+ switch (fvk) {
+ case FvkVoid:
+ return 0;
+ case FvkInt:
+ return 4;
+ case FvkDouble:
+ return 8;
+ case FvkString:
+ return 2*fieldValue.toString().count();
+ }
+ return 0;
+}
+
+void memcpyFieldValue(char *data, FieldValueKind fvk, const QVariant &fieldValue)
+{
+ switch (fvk) {
+ case FvkVoid:
+ break;
+ case FvkInt: {
+ qint32 value = fieldValue.toInt();
+ qToBigEndian(value, (uchar *)data);
+ } break;
+ case FvkDouble: {
+ double value = fieldValue.toDouble();
+ memcpy(data, &value, 8);
+ } break;
+ case FvkString: {
+ QString str = fieldValue.toString();
+ memcpy(data, (const char *)str.constData(), 2*str.count());
+ }
+ }
+}
+
+void memcpyFieldValue(FieldValueKind fvk, QVariant &fieldValue, const char *data, quint16 size)
+{
+ switch (fvk) {
+ case FvkVoid:
+ break;
+ case FvkInt: {
+ fieldValue = qFromBigEndian<qint32>((const uchar *)data);
+ } break;
+ case FvkDouble: {
+ double value;
+ memcpy(&value, data, size);
+ fieldValue = value;
+ } break;
+ case FvkString: {
+ fieldValue = QString((const QChar *)data, size/2);
+ }
+ }
+}
+
+int objectKeyCmp(const char *aptr, size_t alen, const char *bptr, size_t blen, void *)
+{
+ Q_UNUSED(alen);
+ Q_UNUSED(blen);
+ quint32 a = qFromBigEndian<quint32>((const uchar *)aptr);
+ quint32 b = qFromBigEndian<quint32>((const uchar *)bptr);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+}
+
+int intcmp(const uchar *aptr, const uchar *bptr)
+{
+ qint32 a = qFromBigEndian<qint32>((const uchar *)aptr);
+ qint32 b = qFromBigEndian<qint32>((const uchar *)bptr);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+}
+int doublecmp(const uchar *aptr, const uchar *bptr)
+{
+ double a, b;
+ memcpy(&a, aptr, 8);
+ memcpy(&b, bptr, 8);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+}
+int qstringcmp(const quint16 *achar, quint32 acount, const quint16 *bchar, quint32 bcount)
+{
+ int rv = 0;
+ quint32 minCount = qMin(acount, bcount);
+ for (quint32 i = 0; i < minCount; i++) {
+ if ((rv = (achar[i] - bchar[i])) != 0)
+ return rv;
+ }
+ return acount-bcount;
+}
+
+QByteArray makeForwardKey(const QVariant &fieldValue, const ObjectKey &objectKey)
+{
+ FieldValueKind fvk = qVariantFieldValueKind(fieldValue);
+ Q_ASSERT(fvk <= FvkLastKind);
+ quint32 size = fieldValueSize(fvk, fieldValue);
+
+ QByteArray forwardKey(4+size+16, 0);
+ char *data = forwardKey.data();
+ qToBigEndian<quint32>(fvk, (uchar *)&data[0]);
+ memcpyFieldValue(data+4, fvk, fieldValue);
+ qToBigEndian(objectKey, (uchar *)&data[4+size]);
+
+ return forwardKey;
+}
+void forwardKeySplit(const QByteArray &forwardKey, QVariant &fieldValue)
+{
+ const char *data = forwardKey.constData();
+ FieldValueKind fvk = (FieldValueKind)qFromBigEndian<quint32>((const uchar *)&data[0]);
+ Q_ASSERT(fvk <= FvkLastKind);
+ quint32 fvSize = forwardKey.size()-4-16;
+ memcpyFieldValue(fvk, fieldValue, data+4, fvSize);
+}
+void forwardKeySplit(const QByteArray &forwardKey, QVariant &fieldValue, ObjectKey &objectKey)
+{
+ const char *data = forwardKey.constData();
+ FieldValueKind fvk = (FieldValueKind)qFromBigEndian<quint32>((const uchar *)&data[0]);
+ Q_ASSERT(fvk <= FvkLastKind);
+ quint32 fvSize = forwardKey.size()-4-16;
+ memcpyFieldValue(fvk, fieldValue, data+4, fvSize);
+ objectKey = qFromBigEndian<ObjectKey>((const uchar *)&data[4+fvSize]);
+}
+int forwardKeyCmp(const char *aptr, size_t asiz, const char *bptr, size_t bsiz, void *)
+{
+ int rv = 0;
+ FieldValueKind afvk = (FieldValueKind)qFromBigEndian<quint32>((const uchar *)&aptr[0]);
+ FieldValueKind bfvk = (FieldValueKind)qFromBigEndian<quint32>((const uchar *)&bptr[0]);
+ if (afvk > FvkLastKind) {
+ qDebug() << "forwardKeyCmp" << "afvk" << afvk;
+ *(double *)17 = 22.0;
+ }
+ if (bfvk > FvkLastKind) {
+ qDebug() << "forwardKeyCmp" << "bfvk" << bfvk;
+ *(double *)17 = 22.0;
+ }
+ Q_ASSERT(afvk <= FvkLastKind);
+ Q_ASSERT(bfvk <= FvkLastKind);
+ quint32 asize = asiz - 4 - 16;
+ quint32 bsize = bsiz - 4 - 16;
+ if (afvk != bfvk) {
+ //DBG() << "afvk" << afvk << "bfvk" << bfvk;
+ return afvk - bfvk;
+ }
+
+ const char *aData = aptr + 4;
+ const char *bData = bptr + 4;
+ switch (afvk) {
+ case FvkInt:
+ rv = intcmp((const uchar *)aData, (const uchar *)bData);
+ break;
+ case FvkDouble:
+ rv = doublecmp((const uchar *)aData, (const uchar *)bData);
+ break;
+ case FvkString:
+ rv = qstringcmp((const quint16 *)aData, asize/2, (const quint16 *)bData, bsize/2);
+ break;
+ case FvkVoid:
+ rv = 0;
+ break;
+ }
+ if (rv != 0)
+ return rv;
+ ObjectKey aObjectKey = qFromBigEndian<ObjectKey>((const uchar *)aptr+4+asize);
+ ObjectKey bObjectKey = qFromBigEndian<ObjectKey>((const uchar *)bptr+4+bsize);
+ if (aObjectKey == bObjectKey)
+ return 0;
+ return aObjectKey < bObjectKey ? -1 : 1;
+}
+
+QByteArray makeForwardValue(const ObjectKey &objectKey)
+{
+ QByteArray forwardValue(16, 0);
+ char *data = forwardValue.data();
+ qToBigEndian(objectKey, (uchar *)&data[0]);
+ return forwardValue;
+}
+void forwardValueSplit(const QByteArray &forwardValue, ObjectKey &objectKey)
+{
+ const uchar *data = (const uchar *)forwardValue.constData();
+ objectKey = qFromBigEndian<ObjectKey>(&data[0]);
+}
+
+QsonMap JsonDbBtreeStorage::createPersistentObject(QsonMap &object)
+{
+ QsonMap resultmap, errormap;
+
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ QString version = object.valueString(JsonDbString::kVersionStr);
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+
+ ObjectKey objectKey(object.uuid());
+ ObjectTable *table = findObjectTable(objectType);
+
+ bool ok = table->put(objectKey, object);
+ if (!ok) {
+ return JsonDb::makeErrorResponse(resultmap, JsonDbError::DatabaseError,
+ table->errorMessage());
+ }
+
+ table->storeStateChange(objectKey, ObjectChange::Created);
+ table->indexObject(objectKey, object, table->stateNumber());
+
+ resultmap.insert(JsonDbString::kUuidStr, uuid);
+ resultmap.insert(JsonDbString::kVersionStr, version);
+ resultmap.insert(JsonDbString::kCountStr, 1);
+
+ return JsonDb::makeResponse( resultmap, errormap );
+}
+
+void JsonDbBtreeStorage::addView(const QString &viewType)
+{
+ if (!mViews.contains(viewType)) {
+ ObjectTable *viewObjectTable = new ObjectTable(this);
+ QFileInfo fi(mFilename);
+ QString dirName = fi.dir().path();
+ QString baseName = fi.fileName();
+ baseName.replace(".db", "");
+ if (!viewObjectTable->open(QString("%1/%2-%3-View.db")
+ .arg(dirName)
+ .arg(baseName)
+ .arg(viewType),
+ AoDb::NoSync | AoDb::UseSyncMarker)) {
+ qCritical() << "viewDb->open" << viewObjectTable->errorMessage();
+ return;
+ }
+ mViews.insert(viewType, viewObjectTable);
+ viewObjectTable->addIndex(JsonDbString::kUuidStr, "string", viewType, false);
+ // TODO: special case for the following
+ viewObjectTable->addIndex(JsonDbString::kTypeStr, "string", viewType, false);
+ }
+}
+
+void JsonDbBtreeStorage::updateView(const QString &objectType)
+{
+ if (!mViews.contains(objectType))
+ return;
+ // TODO partition name
+ mJsonDb->updateView(objectType);
+}
+
+void JsonDbBtreeStorage::updateView(ObjectTable *objectTable)
+{
+ QString targetType = mViews.key(objectTable, QString());
+ // TODO partition name
+ if (!targetType.isEmpty())
+ mJsonDb->updateView(targetType);
+}
+
+ObjectTable *JsonDbBtreeStorage::findObjectTable(const QString &objectType) const
+{
+ if (mViews.contains(objectType))
+ return mViews.value(objectType);
+ else
+ return mObjectTable;
+}
+
+bool JsonDbBtreeStorage::beginTransaction()
+{
+ if (mTransactionDepth++ == 0) {
+ bool ok = true;
+ int db = -1;
+ for (unsigned i = 0; i < sizeof(mBdbs)/sizeof(mBdbs[0]); ++i) {
+ AoDb *bdb = mBdbs[i];
+ if (!bdb->begin()) {
+ qCritical() << __FILE__ << __LINE__ << bdb->errorMessage();
+ break;
+ }
+ db = i;
+ }
+ Q_ASSERT(mTableTransactions.isEmpty());
+ if (!ok) {
+ while (db >= 0) {
+ AoDb *bdb = mBdbs[db];
+ bdb->abort();
+ db--;
+ };
+ mTransactionDepth--;
+ qCritical() << "transaction failed" << __FUNCTION__ << __LINE__;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool JsonDbBtreeStorage::commitTransaction(quint32 stateNumber)
+{
+ if (--mTransactionDepth == 0) {
+ bool ret = true;
+ quint32 nextStateNumber = stateNumber ? stateNumber : (mObjectTable->stateNumber() + 1);
+ if (gDebug) qDebug() << "commitTransaction" << stateNumber;
+ if (!stateNumber && (mTableTransactions.size() == 1))
+ nextStateNumber = mTableTransactions.at(0)->stateNumber() + 1;
+
+ for (unsigned i = 0; i < sizeof(mBdbs)/sizeof(mBdbs[0]); ++i) {
+ AoDb *bdb = mBdbs[i];
+ if (!bdb->commit(nextStateNumber)) {
+ qCritical() << __FILE__ << __LINE__ << bdb->errorMessage();
+ ret = false;
+ }
+ }
+ for (int i = 0; i < mTableTransactions.size(); i++) {
+ ObjectTable *table = mTableTransactions.at(i);
+ if (!table->commit(nextStateNumber)) {
+ qCritical() << __FILE__ << __LINE__ << "Failed to commit transaction on object table";
+ ret = false;
+ }
+ }
+ mTableTransactions.clear();
+ return ret;
+ }
+ return true;
+}
+
+bool JsonDbBtreeStorage::abortTransaction()
+{
+ if (--mTransactionDepth == 0) {
+ if (gVerbose) qDebug() << "JsonDbBtreeStorage::abortTransaction()";
+ bool ret = true;
+ for (unsigned i = 0; i < sizeof(mBdbs)/sizeof(mBdbs[0]); ++i) {
+ AoDb *bdb = mBdbs[i];
+ if (!bdb->abort()) {
+ qCritical() << __FILE__ << __LINE__ << i << bdb->errorMessage();
+ ret = false;
+ }
+ }
+ for (int i = 0; i < mTableTransactions.size(); i++) {
+ ObjectTable *table = mTableTransactions.at(i);
+ if (!table->abort()) {
+ qCritical() << __FILE__ << __LINE__ << "Failed to abort transaction";
+ ret = false;
+ }
+ }
+ mTableTransactions.clear();
+ return ret;
+ }
+ return true;
+}
+
+QsonMap JsonDbBtreeStorage::updatePersistentObject(QsonMap &object)
+{
+ QsonMap resultmap, errormap;
+
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ QString version = object.valueString(JsonDbString::kVersionStr);
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+ ObjectTable *table = findObjectTable(objectType);
+ ObjectKey objectKey(uuid);
+
+ QsonObject oldObject;
+ bool exists = table->get(objectKey, oldObject);
+
+ objectKey = ObjectKey(object.uuid());
+
+ if (exists) {
+ table->deindexObject(objectKey, oldObject, table->stateNumber());
+ }
+
+ if (!table->put(objectKey, object)) {
+ return JsonDb::makeErrorResponse(resultmap, JsonDbError::DatabaseError,
+ table->errorMessage());
+ }
+
+ if (gDebug) qDebug() << "updateObject" << objectKey << endl << object << endl << oldObject;
+
+ if (exists) {
+ table->storeStateChange(objectKey, ObjectChange::Updated, oldObject);
+ } else {
+ table->storeStateChange(objectKey, ObjectChange::Created);
+ }
+
+ table->indexObject(objectKey, object, table->stateNumber());
+
+ resultmap.insert( JsonDbString::kCountStr, 1 );
+ resultmap.insert( JsonDbString::kUuidStr, uuid );
+ resultmap.insert( JsonDbString::kVersionStr, version );
+
+ return JsonDb::makeResponse( resultmap, errormap );
+}
+
+QsonMap JsonDbBtreeStorage::removePersistentObject(QsonMap object, const QsonMap &ts)
+{
+ if (gDebug) qDebug() << "removePersistentObject" << object;
+
+ QsonMap resultmap, errormap;
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ QString objectType = object.valueString(JsonDbString::kTypeStr);
+
+ ObjectTable *table = findObjectTable(objectType);
+
+ ObjectKey objectKey(uuid);
+
+ QsonMap oldObject;
+ bool ok = table->get(objectKey, oldObject);
+ if (!ok) {
+ qDebug() << "Failed to get object" << objectKey << table->errorMessage();
+ JsonDb::setError( errormap, JsonDbError::InvalidRequest, QString("No object with _uuid %1 in database").arg(uuid));
+ QsonList errors;
+ errors.append(errormap);
+ resultmap.insert(JsonDbString::kCountStr, 0);
+ resultmap.insert(JsonDbString::kDataStr, QsonObject::NullValue);
+ resultmap.insert(JsonDbString::kErrorStr, errors);
+ return JsonDb::makeResponse(resultmap, errormap);
+ }
+ QString version = oldObject.valueString(JsonDbString::kVersionStr);
+
+ QsonMap tombstone(ts);
+ if (!tombstone.valueBool(JsonDbString::kDeletedStr, false))
+ tombstone.insert(JsonDbString::kDeletedStr, true);
+ tombstone.insert(JsonDbString::kUuidStr, uuid);
+ tombstone.insert(JsonDbString::kVersionStr, version);
+
+ ok = table->put(objectKey, tombstone);
+ if (!ok) {
+ return JsonDb::makeErrorResponse(resultmap,
+ JsonDbError::DatabaseError,
+ table->errorMessage());
+ }
+
+ table->storeStateChange(objectKey, ObjectChange::Deleted, oldObject);
+ table->deindexObject(objectKey, oldObject, table->stateNumber());
+
+ QsonMap item;
+ item.insert(JsonDbString::kUuidStr, uuid);
+
+ QsonList data;
+ data.append(item);
+ resultmap.insert(JsonDbString::kCountStr, 1);
+ resultmap.insert(JsonDbString::kDataStr, data);
+ resultmap.insert(JsonDbString::kErrorStr, QsonObject::NullValue);
+ QsonMap result = JsonDb::makeResponse( resultmap, errormap );
+ return result;
+}
+
+QsonMap JsonDbBtreeStorage::lookupObject(const QString &uuid, const QString &objectType) const
+{
+ ObjectKey objectKey(uuid);
+ return lookupObject(objectKey, objectType);
+}
+
+QsonMap JsonDbBtreeStorage::lookupObject(const ObjectKey &objectKey, const QString &objectType) const
+{
+ ObjectTable *table = findObjectTable(objectType);
+
+ QsonMap object = table->lookupObject(objectKey);
+ if (!object.isEmpty())
+ return object;
+ QHash<QString,QPointer<ObjectTable> >::const_iterator it = mViews.begin();
+ for (; it != mViews.end(); ++it) {
+ object = it.value()->lookupObject(objectKey);
+ if (!object.isEmpty())
+ return object;
+ }
+ return QsonMap();
+}
+
+QsonMap JsonDbBtreeStorage::getObject(const QString &keyName, const QVariant &keyValue, const QString &_objectType)
+{
+ QsonMap resultmap;
+ QsonList objectList;
+ const QString &objectType = (keyName == JsonDbString::kTypeStr) ? keyValue.toString() : _objectType;
+ bool typeSpecified = !objectType.isEmpty();
+
+ ObjectTable *table = findObjectTable(objectType);
+
+ updateView(objectType);
+
+ if (keyName == JsonDbString::kUuidStr) {
+ ObjectKey objectKey(keyValue.toString());
+ QsonList objectList;
+ QsonObject object = table->lookupObject(objectKey);
+ if (!object.isEmpty())
+ objectList.append(object);
+ resultmap.insert(QByteArray("result"), objectList);
+ resultmap.insert(JsonDbString::kCountStr, objectList.size());
+ return resultmap;
+ }
+
+ const IndexSpec *indexSpec = table->indexSpec(keyName);
+ if (!indexSpec) {
+ qDebug() << "getObject" << "no index for" << objectType << keyName;
+ resultmap.insert(JsonDbString::kCountStr, 0);
+ return resultmap;
+ }
+
+ if (indexSpec->lazy)
+ updateIndex(table, indexSpec->index);
+ JsonDbIndexCursor cursor(indexSpec->index);
+ if (cursor.seekRange(keyValue)) {
+ do {
+ QVariant key;
+ ObjectKey objectKey;
+ if (!cursor.current(key, objectKey))
+ continue;
+ if (key != keyValue)
+ break;
+
+ QsonObject object;
+ if (table->get(objectKey, object)) {
+ QsonMap map = object.toMap();
+ if (map.contains(JsonDbString::kDeletedStr) && map.valueBool(JsonDbString::kDeletedStr, false))
+ continue;
+ if (typeSpecified && (map.valueString(JsonDbString::kTypeStr) != objectType))
+ continue;
+
+ objectList.append(object);
+ } else {
+ DBG() << "Failed to get object" << objectKey << table->errorMessage();
+ }
+ } while (cursor.next());
+ }
+ resultmap.insert(QByteArray("result"), objectList);
+ resultmap.insert(JsonDbString::kCountStr, objectList.size());
+ return resultmap;
+}
+
+QsonMap JsonDbBtreeStorage::changesSince(quint32 stateNumber, const QSet<QString> &limitTypes)
+{
+ return mObjectTable->changesSince(stateNumber, limitTypes);
+}
+
+bool JsonDbBtreeStorage::checkValidity()
+{
+ bool noErrors = true;
+#if 0
+ if (gVerboseCheckValidity) qDebug() << "JsonDbBtreeStorage::checkValidity {";
+ QMap<quint32, QString> keyUuids; // objectKey -> uuid
+ QMap<QString, quint32> uuidKeys; // objectKey -> uuid
+ QMap<QString, QsonObject> objects; // uuid -> object
+
+ AoDbCursor cursor(mObjectTable->bdb());
+ for (bool ok = cursor.first(); ok; ok = cursor.next()) {
+ QByteArray baKey, baValue;
+ if (!cursor.current(baKey, baValue))
+ continue;
+ if (baValue.size() == 0)
+ continue;
+ quint32 objectKey = qFromBigEndian<quint32>((const uchar *)baKey.data());
+ if (baValue.size() == 4)
+ continue;
+ QsonMap object = QsonParser::fromRawData(baValue).toMap();
+ QString uuid = object.valueString(JsonDbString::kUuidStr);
+ QString typeName = object.valueString(JsonDbString::kTypeStr);
+ if (uuidKeys.contains(uuid)) {
+ quint32 previousKey = uuidKeys.value(uuid);
+ keyUuids.remove(previousKey);
+ }
+ if (deleted) {
+ objects.remove(uuid);
+ uuidKeys.remove(uuid);
+ } else {
+ objects.insert(uuid, object);
+ uuidKeys.insert(uuid, objectKey);
+ keyUuids.insert(objectKey, uuid);
+ }
+
+ if (gVerboseCheckValidity || gDebug) {
+ qDebug() << objectKey << uuid << object.valueString(JsonDbString::kTypeStr);
+ qDebug() << object;
+ }
+ //Q_ASSERT(objectKey > lastObjectKey);
+ }
+ for (QHash<QString,IndexSpec>::const_iterator it = mIndexes.begin();
+ it != mIndexes.end();
+ ++it) {
+ const IndexSpec &indexSpec = it.value();
+ if (!indexSpec.index.isNull()) {
+ if (!indexSpec.index->checkValidity(objects, keyUuids, uuidKeys, this))
+ noErrors = false;
+ }
+ }
+ if (gVerboseCheckValidity) qDebug() << "} JsonDbBtreeStorage::checkValidity done";
+#endif
+ return noErrors;
+}
+
+void JsonDbBtreeStorage::initIndexes()
+{
+ QByteArray baFieldName;
+ QByteArray baIndexObject;
+
+ AoDbCursor cursor(mBdbIndexes);
+ for (bool ok = cursor.first(); ok; ok = cursor.next()) {
+ if (!cursor.current(baFieldName, baIndexObject))
+ break;
+
+ if (baIndexObject.size() == 4)
+ continue;
+ QsonObject object = QsonParser::fromRawData(baIndexObject);
+ if (object.isNull())
+ continue;
+ QsonMap indexObject = object.toMap();
+ if (gVerbose) qDebug() << "initIndexes" << "index" << indexObject;
+ QString indexObjectType = indexObject.valueString(JsonDbString::kTypeStr);
+ if (indexObjectType == kIndexTypeStr) {
+ QString fieldName = indexObject.valueString(kFieldStr);
+ QString fieldType = indexObject.valueString(kFieldTypeStr);
+ QString objectType = indexObject.valueString(kObjectTypeStr);
+ bool lazy = indexObject.valueBool("lazy");
+ QStringList path = fieldName.split('.');
+
+ ObjectTable *table = findObjectTable(objectType);
+ table->addIndex(fieldName, fieldType, objectType, lazy);
+ //checkIndexConsistency(index);
+ }
+ }
+
+
+ beginTransaction();
+ mObjectTable->addIndex(JsonDbString::kUuidStr, "string", QString(), false);
+ mObjectTable->addIndex(JsonDbString::kTypeStr, "string", QString(), false);
+ commitTransaction();
+}
+
+QsonObject JsonDbBtreeStorage::addIndex(const QString &fieldname, const QString &fieldType, const QString &objectType, bool lazy)
+{
+ //qDebug() << "JsonDbBtreeStorage::addIndex" << fieldname << objectType;
+ QsonObject resultmap, errormap;
+ ObjectTable *table = findObjectTable(objectType);
+ const IndexSpec *indexSpec = table->indexSpec(fieldname);
+ if (indexSpec)
+ return QsonObject();
+ //if (gVerbose) qDebug() << "JsonDbBtreeStorage::addIndex" << fieldname << objectType;
+ table->addIndex(fieldname, fieldType, objectType, lazy);
+ return QsonObject();
+}
+
+bool JsonDbBtreeStorage::checkStateConsistency()
+{
+ return true;
+}
+
+void JsonDbBtreeStorage::checkIndexConsistency(ObjectTable *objectTable, JsonDbIndex *index)
+{
+ quint32 indexStateNumber = index->bdb()->tag();
+ quint32 objectStateNumber = objectTable->stateNumber();
+ if (indexStateNumber > objectTable->stateNumber()) {
+ qCritical() << "reverting index" << index->fieldName() << indexStateNumber << objectStateNumber;
+ while (indexStateNumber > objectTable->stateNumber()) {
+ int rc = index->bdb()->revert();
+ quint32 newIndexStateNumber = index->bdb()->tag();
+ if (newIndexStateNumber == indexStateNumber) {
+ qDebug() << "failed to revert. clearing" << rc;
+ index->bdb()->clear();
+ break;
+ }
+ qCritical() << " reverted index to state" << indexStateNumber;
+ }
+ }
+ if (indexStateNumber < objectTable->stateNumber())
+ updateIndex(objectTable, index);
+}
+
+static bool sDebugQuery = (::getenv("JSONDB_DEBUG_QUERY") ? (QLatin1String(::getenv("JSONDB_DEBUG_QUERY")) == "true") : false);
+
+IndexQuery *IndexQuery::indexQuery(JsonDbBtreeStorage *storage, ObjectTable *table, const QString &fieldName, const JsonDbOwner *owner, bool ascending)
+{
+ if (fieldName == JsonDbString::kUuidStr)
+ return new UuidQuery(storage, table, fieldName, owner, ascending);
+ else
+ return new IndexQuery(storage, table, fieldName, owner, ascending);
+}
+
+UuidQuery::UuidQuery(JsonDbBtreeStorage *storage, ObjectTable *table, const QString &fieldName, const JsonDbOwner *owner, bool ascending)
+ : IndexQuery(storage, table, fieldName, owner, ascending)
+{
+}
+
+IndexQuery::IndexQuery(JsonDbBtreeStorage *storage, ObjectTable *table, const QString &fieldName, const JsonDbOwner *owner, bool ascending)
+ : mStorage(storage)
+ , mObjectTable(table)
+ , mBdbIndex(0)
+ , mCursor(0)
+ , mOwner(owner)
+ , mAscending(ascending)
+ , mFieldName(fieldName)
+ , mSparseMatchPossible(false)
+ , mResidualQuery(0)
+{
+ if (fieldName != JsonDbString::kUuidStr) {
+ mBdbIndex = table->indexSpec(fieldName)->index->bdb();
+ mCursor = mBdbIndex->cursor();
+ } else {
+ mCursor = new AoDbCursor(table->bdb(), true);
+ }
+}
+IndexQuery::~IndexQuery()
+{
+ if (mResidualQuery) {
+ delete mResidualQuery;
+ mResidualQuery = 0;
+ }
+ if (mCursor) {
+ delete mCursor;
+ mCursor = 0;
+ }
+ for (int i = 0; i < mQueryConstraints.size(); i++) {
+ delete mQueryConstraints[i];
+ }
+}
+
+quint32 IndexQuery::stateNumber() const
+{
+ return mBdbIndex->tag();
+}
+
+bool IndexQuery::matches(const QVariant &fieldValue)
+{
+ for (int i = 0; i < mQueryConstraints.size(); i++) {
+ if (!mQueryConstraints[i]->matches(fieldValue))
+ return false;
+ }
+ return true;
+}
+
+bool IndexQuery::seekToStart(QVariant &fieldValue)
+{
+ QByteArray forwardKey;
+ if (mAscending) {
+ forwardKey = makeForwardKey(mMin, ObjectKey());
+ if (sDebugQuery) qDebug() << __FUNCTION__ << __LINE__ << "mMin" << mMin << "key" << forwardKey.toHex();
+ } else {
+ forwardKey = makeForwardKey(mMax, ObjectKey());
+ if (sDebugQuery) qDebug() << __FUNCTION__ << __LINE__ << "mMax" << mMin << "key" << forwardKey.toHex();
+ }
+
+ bool ok = false;
+ if (mAscending) {
+ if (mMin.isValid()) {
+ ok = mCursor->seekRange(forwardKey);
+ if (sDebugQuery) qDebug() << "IndexQuery::first" << __LINE__ << "ok after seekRange" << ok;
+ }
+ if (!ok) {
+ ok = mCursor->first();
+ }
+ } else {
+ // need a seekDescending
+ ok = mCursor->last();
+ }
+ if (ok) {
+ QByteArray baKey;
+ mCursor->currentKey(baKey);
+ forwardKeySplit(baKey, fieldValue);
+ }
+ //qDebug() << "IndexQuery::seekToStart" << (mAscending ? mMin : mMax) << "ok" << ok << fieldValue;
+ return ok;
+}
+
+bool IndexQuery::seekToNext(QVariant &fieldValue)
+{
+ bool ok = mAscending ? mCursor->next() : mCursor->prev();
+ if (ok) {
+ QByteArray baKey;
+ mCursor->currentKey(baKey);
+ forwardKeySplit(baKey, fieldValue);
+ }
+ //qDebug() << "IndexQuery::seekToNext" << "ok" << ok << fieldValue;
+ return ok;
+}
+
+QsonMap IndexQuery::currentObjectAndTypeNumber(ObjectKey &objectKey)
+{
+ QByteArray baValue;
+ mCursor->currentValue(baValue);
+ forwardValueSplit(baValue, objectKey);
+
+ if (sDebugQuery) qDebug() << __FILE__ << __LINE__ << "objectKey" << objectKey << baValue.toHex();
+ return mObjectTable->lookupObject(objectKey);
+}
+
+quint32 UuidQuery::stateNumber() const
+{
+ return mObjectTable->stateNumber();
+}
+
+bool UuidQuery::seekToStart(QVariant &fieldValue)
+{
+ bool ok;
+ if (mAscending) {
+ if (mMin.isValid()) {
+ ObjectKey objectKey(mMin.toString());
+ ok = mCursor->seekRange(objectKey.toByteArray());
+ } else {
+ ok = mCursor->first();
+ }
+ } else {
+ if (mMax.isValid()) {
+ ObjectKey objectKey(mMax.toString());
+ ok = mCursor->seekRange(objectKey.toByteArray());
+ } else {
+ ok = mCursor->last();
+ }
+ }
+ QByteArray baKey;
+ while (ok) {
+ mCursor->currentKey(baKey);
+ if (!isStateKey(baKey))
+ break;
+ if (mAscending)
+ ok = mCursor->next();
+ else
+ ok = mCursor->prev();
+ }
+ if (ok) {
+ QUuid quuid(QUuid::fromRfc4122(baKey));
+ ObjectKey objectKey(quuid);
+ fieldValue = objectKey.key.toString();
+ }
+ //qDebug() << "seekToStart" << (mAscending ? mMin : mMax) << "ok" << ok << fieldValue;
+ return ok;
+}
+
+bool UuidQuery::seekToNext(QVariant &fieldValue)
+{
+ bool ok = mAscending ? mCursor->next() : mCursor->prev();
+ QByteArray baKey;
+ while (ok) {
+ mCursor->currentKey(baKey);
+ if (!isStateKey(baKey))
+ break;
+ if (mAscending)
+ ok = mCursor->next();
+ else
+ ok = mCursor->prev();
+ }
+ if (ok) {
+ QUuid quuid(QUuid::fromRfc4122(baKey));
+ ObjectKey objectKey(quuid);
+ fieldValue = objectKey.key.toString();
+ }
+ //qDebug() << "seekToNext" << "ok" << ok << fieldValue;
+ return ok;
+}
+
+QsonMap UuidQuery::currentObjectAndTypeNumber(ObjectKey &objectKey)
+{
+ QByteArray baKey;
+ mCursor->currentKey(baKey);
+ objectKey = ObjectKey(baKey);
+
+ if (sDebugQuery) qDebug() << __FILE__ << __LINE__ << "objectKey" << objectKey << baKey.toHex();
+ return mObjectTable->lookupObject(objectKey);
+}
+
+QsonMap IndexQuery::first()
+{
+ mSparseMatchPossible = false;
+ for (int i = 0; i < mQueryConstraints.size(); i++) {
+ mSparseMatchPossible |= mQueryConstraints[i]->sparseMatchPossible();
+ }
+
+ QVariant fieldValue;
+ bool ok = seekToStart(fieldValue);
+ if (sDebugQuery) qDebug() << "IndexQuery::first" << __LINE__ << "ok after first/last()" << ok;
+ for (; ok; ok = seekToNext(fieldValue)) {
+ mFieldValue = fieldValue;
+ if (sDebugQuery) qDebug() << "IndexQuery::first()"
+ << "mFieldName" << mFieldName
+ << "fieldValue" << fieldValue
+ << (mAscending ? "ascending" : "descending");
+
+ if (sDebugQuery) qDebug() << "IndexQuery::first()" << "matches(fieldValue)" << matches(fieldValue);
+
+ if (!matches(fieldValue))
+ continue;
+
+ ObjectKey objectKey;
+ QsonMap object(currentObjectAndTypeNumber(objectKey));
+ if (sDebugQuery) qDebug() << "IndexQuery::first()" << __LINE__ << "objectKey" << objectKey << object.valueBool(JsonDbString::kDeletedStr, false);
+ if (object.contains(JsonDbString::kDeletedStr) && object.valueBool(JsonDbString::kDeletedStr, false))
+ continue;
+
+ if (!mTypeNames.isEmpty() && !mTypeNames.contains(object.valueString(JsonDbString::kTypeStr)))
+ continue;
+
+ if (mResidualQuery && !mResidualQuery->match(object, &mObjectCache, mStorage))
+ continue;
+
+ if (sDebugQuery) qDebug() << "IndexQuery::first()" << "returning objectKey" << objectKey;
+
+ return object;
+ }
+ mUuid.clear();
+ return QsonMap();
+}
+QsonMap IndexQuery::next()
+{
+ QVariant fieldValue;
+ while (seekToNext(fieldValue)) {
+ if (sDebugQuery) qDebug() << "IndexQuery::next()" << "mFieldName" << mFieldName
+ << "fieldValue" << fieldValue
+ << (mAscending ? "ascending" : "descending");
+ if (sDebugQuery) qDebug() << "IndexQuery::next()" << "matches(fieldValue)" << matches(fieldValue);
+ if (!matches(fieldValue)) {
+ if (mSparseMatchPossible)
+ continue;
+ else
+ break;
+ }
+
+ ObjectKey objectKey;
+ QsonMap object(currentObjectAndTypeNumber(objectKey));
+ if (object.contains(JsonDbString::kDeletedStr) && object.valueBool(JsonDbString::kDeletedStr, false))
+ continue;
+
+ if (!mTypeNames.isEmpty() && !mTypeNames.contains(object.valueString(JsonDbString::kTypeStr)))
+ continue;
+
+ if (sDebugQuery) qDebug() << "IndexQuery::next()" << "objectKey" << objectKey;
+
+ if (mResidualQuery && !mResidualQuery->match(object, &mObjectCache, mStorage))
+ continue;
+
+ return object;
+ }
+ mUuid.clear();
+ return QsonMap();
+}
+
+class QueryConstraintGt: public QueryConstraint {
+public:
+ QueryConstraintGt(const QVariant &v) { mValue = v.toString(); }
+ bool matches(const QVariant &v) { return v.toString() > mValue; }
+private:
+ QString mValue;
+};
+class QueryConstraintGe: public QueryConstraint {
+public:
+ QueryConstraintGe(const QVariant &v) { mValue = v.toString(); }
+ bool matches(const QVariant &v) { return v.toString() >= mValue; }
+private:
+ QString mValue;
+};
+class QueryConstraintLt: public QueryConstraint {
+public:
+ QueryConstraintLt(const QVariant &v) { mValue = v.toString(); }
+ bool matches(const QVariant &v) { return v.toString() < mValue; }
+private:
+ QString mValue;
+};
+class QueryConstraintLe: public QueryConstraint {
+public:
+ QueryConstraintLe(const QVariant &v) { mValue = v.toString(); }
+ bool matches(const QVariant &v) { return v.toString() <= mValue; }
+private:
+ QString mValue;
+};
+class QueryConstraintEq: public QueryConstraint {
+public:
+ QueryConstraintEq(const QVariant &v) { mValue = v.toString(); }
+ bool matches(const QVariant &v) { return v.toString() == mValue; }
+private:
+ QString mValue;
+};
+class QueryConstraintNe: public QueryConstraint {
+public:
+ QueryConstraintNe(const QVariant &v) { mValue = v.toString(); }
+ bool sparseMatchPossible() const { return true; }
+ bool matches(const QVariant &v) { return v.toString() != mValue; }
+private:
+ QString mValue;
+};
+class QueryConstraintHas: public QueryConstraint {
+public:
+ QueryConstraintHas() { }
+ bool matches(const QVariant &v) { return v.isValid(); }
+private:
+};
+class QueryConstraintIn: public QueryConstraint {
+public:
+ QueryConstraintIn(const QVariant &v) { mList = v.toList();}
+ bool sparseMatchPossible() const { return true; }
+
+ bool matches(const QVariant &v) {
+ return mList.contains(v);
+ }
+private:
+ QVariantList mList;
+};
+class QueryConstraintNotIn: public QueryConstraint {
+public:
+ QueryConstraintNotIn(const QVariant &v) { mList = v.toList();}
+ bool sparseMatchPossible() const { return true; }
+ bool matches(const QVariant &v) {
+ return !mList.contains(v);
+ }
+private:
+ QVariantList mList;
+};
+class QueryConstraintContains: public QueryConstraint {
+public:
+ QueryConstraintContains(const QVariant &v) { mValue = v;}
+ bool sparseMatchPossible() const { return true; }
+ bool matches(const QVariant &v) {
+ return v.toList().contains(mValue);
+ }
+private:
+ QVariant mValue;
+};
+class QueryConstraintStartsWith: public QueryConstraint {
+public:
+ QueryConstraintStartsWith(const QString &v) { mValue = v;}
+ bool sparseMatchPossible() const { return true; }
+ bool matches(const QVariant &v) {
+ return v.toString().startsWith(mValue);
+ }
+private:
+ QString mValue;
+};
+class QueryConstraintRegExp: public QueryConstraint {
+public:
+ QueryConstraintRegExp(const QRegExp &regexp) : mRegExp(regexp) {}
+ bool matches(const QVariant &v) { return mRegExp.exactMatch(v.toString()); }
+ bool sparseMatchPossible() const { return true; }
+private:
+ QString mValue;
+ QRegExp mRegExp;
+};
+
+void JsonDbBtreeStorage::compileOrQueryTerm(IndexQuery *indexQuery, const QueryTerm &queryTerm)
+{
+ QString op = queryTerm.op();
+ QVariant fieldValue = queryTerm.value();
+ if (op == ">") {
+ indexQuery->addConstraint(new QueryConstraintGt(fieldValue));
+ indexQuery->setMin(fieldValue);
+ } else if (op == ">=") {
+ indexQuery->addConstraint(new QueryConstraintGe(fieldValue));
+ indexQuery->setMin(fieldValue);
+ } else if (op == "<") {
+ indexQuery->addConstraint(new QueryConstraintLt(fieldValue));
+ indexQuery->setMax(fieldValue);
+ } else if (op == "<=") {
+ indexQuery->addConstraint(new QueryConstraintLe(fieldValue));
+ indexQuery->setMax(fieldValue);
+ } else if (op == "=") {
+ indexQuery->addConstraint(new QueryConstraintEq(fieldValue));
+ indexQuery->setMin(fieldValue);
+ indexQuery->setMax(fieldValue);
+ } else if (op == "=~") {
+ const QRegExp re = queryTerm.regExpConst();
+ QRegExp::PatternSyntax syntax = re.patternSyntax();
+ Qt::CaseSensitivity cs = re.caseSensitivity();
+ QString pattern = re.pattern();
+ indexQuery->addConstraint(new QueryConstraintRegExp(re));
+ if (cs == Qt::CaseSensitive) {
+ QString prefix;
+ if ((syntax == QRegExp::Wildcard)
+ && mWildCardPrefixRegExp.exactMatch(pattern)) {
+ prefix = mWildCardPrefixRegExp.cap(1);
+ if (gDebug) qDebug() << "wildcard regexp prefix" << pattern << prefix;
+ }
+ indexQuery->setMin(prefix);
+ indexQuery->setMax(prefix);
+ }
+ } else if (op == "!=") {
+ indexQuery->addConstraint(new QueryConstraintNe(fieldValue));
+ } else if (op == "exists") {
+ indexQuery->addConstraint(new QueryConstraintHas);
+ } else if (op == "in") {
+ QVariantList value = queryTerm.value().toList();
+ //qDebug() << "in" << value << value.size();
+ if (value.size() == 1)
+ indexQuery->addConstraint(new QueryConstraintEq(value.at(0)));
+ else
+ indexQuery->addConstraint(new QueryConstraintIn(queryTerm.value()));
+ } else if (op == "notIn") {
+ indexQuery->addConstraint(new QueryConstraintNotIn(queryTerm.value()));
+ } else if (op == "in") {
+ indexQuery->addConstraint(new QueryConstraintContains(queryTerm.value()));
+ } else if (op == "startsWith") {
+ indexQuery->addConstraint(new QueryConstraintStartsWith(queryTerm.value().toString()));
+ }
+}
+
+void JsonDbBtreeStorage::updateIndex(ObjectTable *table, JsonDbIndex *index)
+{
+ table->updateIndex(index);
+}
+
+IndexQuery *JsonDbBtreeStorage::compileIndexQuery(const JsonDbOwner *owner, const JsonDbQuery &query)
+{
+ IndexQuery *indexQuery = 0;
+ JsonDbQuery *residualQuery = new JsonDbQuery();
+ QString orderField;
+ QSet<QString> typeNames;
+ const QList<OrderTerm> &orderTerms = query.orderTerms;
+ const QList<OrQueryTerm> &orQueryTerms = query.queryTerms;
+ QString indexCandidate;
+ ObjectTable *table = mObjectTable; //TODO fix me
+ int indexedQueryTermCount = 0;
+ if (orQueryTerms.size()) {
+ for (int i = 0; i < orQueryTerms.size(); i++) {
+ const OrQueryTerm orQueryTerm = orQueryTerms[i];
+ const QList<QString> &queryFieldNames = orQueryTerm.fieldNames();
+ if (queryFieldNames.size() == 1) {
+ //QString fieldValue = queryTerm.value().toString();
+ QString fieldName = queryFieldNames[0];
+
+ const QList<QueryTerm> &queryTerms = orQueryTerm.terms();
+ const QueryTerm &queryTerm = queryTerms[0];
+
+ if ((typeNames.size() == 1)
+ && mViews.contains(typeNames.toList()[0]))
+ table = mViews[typeNames.toList()[0]];
+
+ if (table->indexSpec(fieldName))
+ indexedQueryTermCount++;
+ else if (indexCandidate.isEmpty() && (fieldName != JsonDbString::kTypeStr)) {
+ indexCandidate = fieldName;
+ if (!queryTerm.joinField().isEmpty())
+ indexCandidate = queryTerm.joinPaths()[0].join("->");
+
+ }
+
+ fieldName = queryTerm.fieldName();
+ QString fieldValue = queryTerm.value().toString();
+ QString op = queryTerm.op();
+ if (fieldName == JsonDbString::kTypeStr) {
+ if ((op == "=") || (op == "in")) {
+ QSet<QString> types;
+ if (op == "=")
+ types << fieldValue;
+ else
+ types = QSet<QString>::fromList(queryTerm.value().toStringList());
+
+ if (typeNames.count()) {
+ typeNames.intersect(types);
+ if (!typeNames.count()) {
+ // make this a null query -- I really need a domain (partial order) here and not a set
+ typeNames = types;
+ }
+ } else {
+ typeNames = types;
+ }
+ } else if ((op == "!=") || (op == "notIn")) {
+ QSet<QString> types;
+ if (op == "!=")
+ types << fieldValue;
+ else
+ types = QSet<QString>::fromList(queryTerm.value().toStringList());
+ }
+ }
+ }
+ }
+ }
+ if ((typeNames.size() == 1)
+ && mViews.contains(typeNames.toList()[0]))
+ table = mViews[typeNames.toList()[0]];
+ if (!indexedQueryTermCount && !indexCandidate.isEmpty()) {
+ if (gVerbose) qDebug() << "adding index" << indexCandidate;
+ table->addIndex(indexCandidate);
+ if (gVerbose) qDebug() << "done adding index" << indexCandidate;
+ }
+
+ for (int i = 0; i < orderTerms.size(); i++) {
+ const OrderTerm &orderTerm = orderTerms[i];
+ QString fieldName = orderTerm.fieldName;
+ if (!table->indexSpec(fieldName)) {
+ if (gVerbose) qDebug() << "Unindexed sort term" << fieldName << orderTerm.ascending;
+ if (gVerbose) qDebug() << "adding index for sort term" << fieldName;
+ Q_ASSERT(table);
+ table->addIndex(fieldName);
+ Q_ASSERT(table->indexSpec(fieldName));
+ if (gVerbose) qDebug() << "done adding index" << fieldName;
+ //residualQuery->orderTerms.append(orderTerm);
+ //continue;
+ }
+ if (!indexQuery) {
+ orderField = fieldName;
+ const IndexSpec *indexSpec = table->indexSpec(fieldName);
+ updateView(table);
+
+ if (indexSpec->lazy)
+ updateIndex(table, indexSpec->index);
+ indexQuery = IndexQuery::indexQuery(this, table, fieldName, owner, orderTerm.ascending);
+ } else if (orderField != fieldName) {
+ qCritical() << QString("unimplemented: multiple order terms. Sorting on '%1'").arg(orderField);
+ residualQuery->orderTerms.append(orderTerm);
+ }
+ }
+
+ for (int i = 0; i < orQueryTerms.size(); i++) {
+ const OrQueryTerm &orQueryTerm = orQueryTerms[i];
+ const QList<QueryTerm> &queryTerms = orQueryTerm.terms();
+ if (queryTerms.size() == 1) {
+ QueryTerm queryTerm = queryTerms[0];
+ QString fieldName = queryTerm.fieldName();
+ QString fieldValue = queryTerm.value().toString();
+ QString op = queryTerm.op();
+
+ if (!queryTerm.joinField().isEmpty()) {
+ residualQuery->queryTerms.append(queryTerm);
+ fieldName = queryTerm.joinField();
+ op = "exists";
+ queryTerm.setFieldName(fieldName);
+ queryTerm.setOp(op);
+ queryTerm.setJoinField(QString());
+ }
+ if (!table->indexSpec(fieldName)
+ || (indexQuery
+ && (fieldName != orderField))) {
+ if (gVerbose || gDebug) qDebug() << "residual query term" << fieldName << "orderField" << orderField;
+ residualQuery->queryTerms.append(queryTerm);
+ continue;
+ }
+
+ if (!indexQuery && (fieldName != JsonDbString::kTypeStr) && table->indexSpec(fieldName)) {
+ orderField = fieldName;
+ const IndexSpec *indexSpec = table->indexSpec(fieldName);
+ updateView(table);
+ if (indexSpec->lazy)
+ updateIndex(table, indexSpec->index);
+ indexQuery = IndexQuery::indexQuery(this, table, fieldName, owner);
+ }
+
+ if (fieldName == orderField) {
+ compileOrQueryTerm(indexQuery, queryTerm);
+ }
+ } else {
+ residualQuery->queryTerms.append(orQueryTerm);
+ }
+ }
+
+ if (!indexQuery) {
+ QString defaultIndex = JsonDbString::kUuidStr;
+ if (typeNames.size()) {
+ if ((typeNames.size() == 1)
+ && mViews.contains(typeNames.toList()[0]))
+ table = mViews[typeNames.toList()[0]];
+ else
+ defaultIndex = JsonDbString::kTypeStr;
+ }
+ const IndexSpec *indexSpec = table->indexSpec(defaultIndex);
+
+ //qDebug() << "defaultIndex" << defaultIndex << "on table" << indexSpec->objectType;
+
+ updateView(table);
+ if (indexSpec->lazy)
+ updateIndex(table, indexSpec->index);
+ indexQuery = IndexQuery::indexQuery(this, table, defaultIndex, owner);
+ if (typeNames.size() == 0)
+ qCritical() << "searching all objects" << query.query;
+ }
+ if (typeNames.count() > 0)
+ indexQuery->setTypeNames(typeNames);
+ if (residualQuery->queryTerms.size() || residualQuery->orderTerms.size())
+ indexQuery->setResidualQuery(residualQuery);
+ else
+ delete residualQuery;
+ indexQuery->setAggregateOperation(query.mAggregateOperation);
+ return indexQuery;
+}
+
+void JsonDbBtreeStorage::doIndexQuery(const JsonDbOwner *owner, QsonList &results, int &limit, int &offset,
+ IndexQuery *indexQuery)
+{
+ if (sDebugQuery) qDebug() << "doIndexQuery" << "limit" << limit << "offset" << offset;
+ bool countOnly = (indexQuery->aggregateOperation() == "count");
+ int count = 0;
+ for (QsonMap object = indexQuery->first();
+ !object.isEmpty();
+ object = indexQuery->next()) {
+ if (!owner->isAllowed(object, QString("read")))
+ continue;
+ if (limit && (offset <= 0)) {
+ if (!countOnly) {
+ if (sDebugQuery) qDebug() << "appending result" << object << endl;
+ results.append(object);
+ }
+ limit--;
+ count++;
+ }
+ offset--;
+ if (limit == 0)
+ break;
+ }
+ if (countOnly) {
+ QsonMap countObject;
+ countObject.insert(QLatin1String("count"), count);
+ results.append(countObject);
+ }
+}
+
+static int findMinHead(QList<QsonMap> &heads, QStringList path, bool ascending)
+{
+ int minIndex = 0;
+ QString minVal = JsonDb::propertyLookup(heads[0], path).toString();
+ for (int i = 1; i < heads.size(); i++) {
+ QString val = JsonDb::propertyLookup(heads[i], path).toString();
+ if (ascending ? (val < minVal) : (val > minVal)) {
+ minVal = val;
+ minIndex = i;
+ }
+ }
+ return minIndex;
+}
+
+void JsonDbBtreeStorage::doMultiIndexQuery(const JsonDbOwner *owner, QsonList &results, int &limit, int &offset,
+ const QList<IndexQuery *> &indexQueries)
+{
+ Q_ASSERT(indexQueries.size());
+ if (indexQueries.size() == 1)
+ return doIndexQuery(owner, results, limit, offset, indexQueries[0]);
+
+ QList<QsonMap> heads;
+ QList<IndexQuery*> queries;
+ int nPartitions = indexQueries.size();
+
+ QString field0 = indexQueries[0]->fieldName();
+ QStringList path0 = field0.split('.');
+ bool ascending = indexQueries[0]->ascending();
+
+ if (sDebugQuery) qDebug() << "doMultiIndexQuery" << "limit" << limit << "offset" << offset << "fieldName" << indexQueries[0]->fieldName();
+
+ for (int i = 0; i < nPartitions; i++) {
+ QsonMap object = indexQueries[i]->first();
+ qDebug() << i << "first" << object;
+ if (!object.isEmpty()) {
+ heads.append(object);
+ queries.append(indexQueries[i]);
+ }
+ }
+
+ bool countOnly = (indexQueries[0]->aggregateOperation() == "count");
+ int count = 0;
+ int s = 0;
+ while (queries.size()) {
+ QsonMap object;
+ // if this is an ordered query, should take the minimum of the values
+ s = findMinHead(heads, path0, ascending);
+ object = heads[s];
+ heads[s] = queries[s]->next();
+ if (heads[s].isEmpty()) {
+ heads.takeAt(s);
+ queries.takeAt(s);
+ }
+ if (object.isEmpty())
+ break;
+
+ if (!owner->isAllowed(object, QString("read")))
+ continue;
+ if (limit && (offset <= 0)) {
+ if (!countOnly) {
+ if (sDebugQuery) qDebug() << "appending result" << object << endl;
+ results.append(object);
+ }
+ limit--;
+ count++;
+ }
+ offset--;
+ if (limit == 0)
+ break;
+ }
+ if (countOnly) {
+ QsonMap countObject;
+ countObject.insert(QLatin1String("count"), count);
+ results.append(countObject);
+ }
+}
+
+bool JsonDbBtreeStorage::checkQuota(const JsonDbOwner *owner, int size) const
+{
+ int quota = owner->storageQuota();
+ if (quota <= 0)
+ return true;
+
+ const QString ownerId(owner->ownerId());
+ if (ownerId.isEmpty())
+ return false;
+ QByteArray baKey = QByteArray::fromRawData((const char *)ownerId.constData(), 2*ownerId.size());
+ QByteArray baValue;
+ bool ok = mBdbIndexes->get(baKey, baValue);
+ int oldSize = (ok) ? qFromLittleEndian<quint32>((const uchar *)baValue.data()) : 0;
+ if ((oldSize + size) <= quota)
+ return true;
+ else {
+ DBG() << QString("Failed checkQuota: oldSize=%1 size=%2 quota=%3").arg(oldSize).arg(size).arg(quota);
+ return false;
+ }
+}
+
+bool JsonDbBtreeStorage::addToQuota(const JsonDbOwner *owner, int size)
+{
+ if (!size)
+ return true;
+ const QString ownerId(owner->ownerId());
+ if (ownerId.isEmpty())
+ return true;
+ WithTransaction transaction(this);
+ CHECK_LOCK(transaction, "addToQuota");
+ QByteArray baKey = QByteArray::fromRawData((const char *)ownerId.constData(), 2*ownerId.size());
+ QByteArray baValue;
+ quint32 value = 0;
+ if (mBdbIndexes->get(baKey, baValue) && baValue.size() == 4)
+ value = qFromLittleEndian<quint32>((const uchar *)baValue.constData());
+ value += size;
+ baValue.resize(4);
+ qToLittleEndian(value, (uchar *)baValue.data());
+ mBdbIndexes->put(baKey, baValue);
+ return true;
+}
+
+QsonMap JsonDbBtreeStorage::queryPersistentObjects(const JsonDbOwner *owner, const JsonDbQuery &query, int limit, int offset)
+{
+ QsonList results;
+ QsonList joinedResults;
+
+ QElapsedTimer time;
+ time.start();
+ IndexQuery *indexQuery = compileIndexQuery(owner, query);
+
+ int elapsedToCompile = time.elapsed();
+ doIndexQuery(owner, results, limit, offset, indexQuery);
+ int elapsedToQuery = time.elapsed();
+ quint32 stateNumber = indexQuery->stateNumber();
+ int length = results.size();
+ JsonDbQuery *residualQuery = indexQuery->residualQuery();
+ if (residualQuery && residualQuery->orderTerms.size()) {
+ if (gVerbose) qDebug() << "queryPersistentObjects" << "sorting";
+ sortValues(residualQuery, results, joinedResults);
+ }
+
+ QsonList sortKeys;
+ sortKeys.append(indexQuery->fieldName());
+
+ delete indexQuery;
+
+ QsonMap map;
+ map.insert(JsonDbString::kLengthStr, length);
+ map.insert(JsonDbString::kOffsetStr, offset);
+ map.insert(JsonDbString::kDataStr, results);
+ map.insert(kStateStr, stateNumber);
+ map.insert(QByteArray("joinedData"), joinedResults);
+ map.insert(kSortKeysStr, sortKeys);
+ int elapsedToDone = time.elapsed();
+ if (gVerbose)
+ qDebug() << "elapsed" << elapsedToCompile << elapsedToQuery << elapsedToDone << query.query;
+ return map;
+}
+
+QsonMap JsonDbBtreeStorage::queryPersistentObjects(const JsonDbOwner *owner, const JsonDbQuery &query, int limit, int offset, QList<JsonDbBtreeStorage *> partitions)
+{
+ Q_ASSERT(partitions.size());
+ QsonList results;
+ QsonList joinedResults;
+
+ QElapsedTimer time;
+ time.start();
+ QList<IndexQuery *> indexQueries;
+ for (int i = 0; i < partitions.size(); i++)
+ indexQueries.append(partitions[i]->compileIndexQuery(owner, query));
+
+ int elapsedToCompile = time.elapsed();
+ doMultiIndexQuery(owner, results, limit, offset, indexQueries);
+ int elapsedToQuery = time.elapsed();
+
+ int length = results.size();
+ JsonDbQuery *residualQuery = indexQueries[0]->residualQuery();
+ if (residualQuery && residualQuery->orderTerms.size()) {
+ if (gVerbose) qDebug() << "queryPersistentObjects" << "sorting";
+ sortValues(residualQuery, results, joinedResults);
+ }
+
+ QsonList sortKeys;
+ sortKeys.append(indexQueries[0]->fieldName());
+
+ for (int i = 0; i < indexQueries.size(); i++)
+ delete indexQueries[i];
+
+ QsonMap map;
+ map.insert(JsonDbString::kLengthStr, length);
+ map.insert(JsonDbString::kOffsetStr, offset);
+ map.insert(JsonDbString::kDataStr, results);
+ map.insert(kSortKeysStr, sortKeys);
+ map.insert(QByteArray("joinedData"), joinedResults);
+ int elapsedToDone = time.elapsed();
+ if (gVerbose)
+ qDebug() << "elapsed" << elapsedToCompile << elapsedToQuery << elapsedToDone << query.query;
+ return map;
+}
+
+void JsonDbBtreeStorage::checkIndex(const QString &fieldName)
+{
+// TODO
+ if (mObjectTable->indexSpec(fieldName))
+ mObjectTable->indexSpec(fieldName)->index->checkIndex();
+}
+
+bool JsonDbBtreeStorage::compact()
+{
+ for (QHash<QString,QPointer<ObjectTable> >::const_iterator it = mViews.begin();
+ it != mViews.end();
+ ++it) {
+ it.value()->compact();
+ }
+ return mObjectTable->compact()
+ && mBdbIndexes->compact();
+}
+
+QString JsonDbBtreeStorage::name() const
+{
+ return mPartitionName;
+}
+void JsonDbBtreeStorage::setName(const QString &name)
+{
+ mPartitionName = name;
+}
+
+struct StringSortable {
+ QString key;
+ QsonMap result;
+ QsonMap joinedResult;
+};
+
+bool lessThan(const StringSortable &a, const StringSortable &b)
+{
+ return a.key < b.key;
+}
+bool greaterThan(const StringSortable &a, const StringSortable &b)
+{
+ return a.key > b.key;
+}
+
+void JsonDbBtreeStorage::sortValues(const JsonDbQuery *parsedQuery, QsonList &results, QsonList &joinedResults)
+{
+ const QList<OrderTerm> &orderTerms = parsedQuery->orderTerms;
+ if (!orderTerms.size() || (results.size() < 2))
+ return;
+ const OrderTerm &orderTerm0 = orderTerms[0];
+ QString field0 = orderTerm0.fieldName;
+ bool ascending = orderTerm0.ascending;
+ QStringList path0 = field0.split('.');
+
+ if (orderTerms.size() == 1) {
+ QVector<StringSortable> valuesToSort(results.size());
+ int resultsSize = results.size();
+ int joinedResultsSize = joinedResults.size();
+
+ for (int i = 0; i < resultsSize; i++) {
+ StringSortable *p = &valuesToSort[i];
+ QsonMap r = results.at<QsonMap>(i);
+ p->key = JsonDb::propertyLookup(r, path0).toString();
+ p->result = r;
+ if (joinedResultsSize > i)
+ p->joinedResult = joinedResults.at<QsonMap>(i);
+ }
+
+ if (ascending)
+ qStableSort(valuesToSort.begin(), valuesToSort.end(), lessThan);
+ else
+ qStableSort(valuesToSort.begin(), valuesToSort.end(), greaterThan);
+
+ results = QsonList();
+ joinedResults = QsonList();
+ for (int i = 0; i < resultsSize; i++) {
+ StringSortable *p = &valuesToSort[i];
+ results.append(p->result);
+ if (joinedResultsSize > i)
+ joinedResults.append(p->joinedResult);
+ }
+ } else {
+ qCritical() << "Unimplemented: sorting on multiple keys or non-string keys";
+ }
+}
+
+bool WithTransaction::addObjectTable(ObjectTable *table)
+{
+ if (!mStorage)
+ return false;
+ if (!mStorage->mTableTransactions.contains(table)) {
+ bool ok = table->begin();
+ mStorage->mTableTransactions.append(table);
+ return ok;
+ }
+ return true;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondbbtreestorage.h b/src/daemon/jsondbbtreestorage.h
new file mode 100644
index 00000000..91e4b243
--- /dev/null
+++ b/src/daemon/jsondbbtreestorage.h
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_BTREE_H
+#define JSONDB_BTREE_H
+
+#include <QStringList>
+#include <QRegExp>
+#include <QSet>
+#include <QTimer>
+#include <QVector>
+#include <QPointer>
+
+#include "jsondb.h"
+#include "jsondb-owner.h"
+
+#include "objectkey.h"
+
+class TestJsonDb;
+class AoDb;
+class AoDbCursor;
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDbOwner;
+class ObjectTable;
+class JsonDbIndex;
+
+extern const QString kDbidTypeStr;
+extern const QString kIndexTypeStr;
+extern const QString kFieldStr;
+extern const QString kFieldTypeStr;
+extern const QString kObjectTypeStr;
+extern const QString kDatabaseSchemaVersionStr;
+extern const QString gDatabaseSchemaVersion;
+
+class QueryConstraint {
+public:
+ virtual ~QueryConstraint() { }
+ virtual bool matches(const QVariant &value) = 0;
+ virtual bool sparseMatchPossible() const
+ { return false; }
+};
+
+class IndexQuery {
+protected:
+ IndexQuery(JsonDbBtreeStorage *storage, ObjectTable *table, const QString &fieldName, const JsonDbOwner *owner, bool ascending = true);
+public:
+ static IndexQuery *indexQuery(JsonDbBtreeStorage *storage, ObjectTable *table, const QString &fieldName, const JsonDbOwner *owner, bool ascending = true);
+ ~IndexQuery();
+
+ void addConstraint(QueryConstraint *qc) { mQueryConstraints.append(qc); }
+ bool ascending() const { return mAscending; }
+ QString fieldName() const { return mFieldName; }
+ void setTypeNames(const QSet<QString> typeNames) { mTypeNames = typeNames; }
+ void setMin(const QVariant &minv) { mMin = minv; }
+ void setMax(const QVariant &maxv) { mMax = maxv; }
+ QString aggregateOperation() const { return mAggregateOperation; }
+ void setAggregateOperation(QString op) { mAggregateOperation = op; }
+
+ QsonMap first(); // returns first matching object
+ QsonMap next(); // returns next matching object
+ bool matches(const QVariant &value);
+ QVariant fieldValue() const { return mFieldValue; }
+ JsonDbQuery *residualQuery() const { return mResidualQuery; }
+ void setResidualQuery(JsonDbQuery *residualQuery) { mResidualQuery = residualQuery; }
+ virtual quint32 stateNumber() const;
+
+protected:
+ virtual bool seekToStart(QVariant &fieldValue);
+ virtual bool seekToNext(QVariant &fieldValue);
+ virtual QsonMap currentObjectAndTypeNumber(ObjectKey &objectKey);
+
+protected:
+ JsonDbBtreeStorage *mStorage;
+ ObjectTable *mObjectTable;
+ AoDb *mBdbIndex;
+ AoDbCursor *mCursor;
+ const JsonDbOwner *mOwner;
+ QVariant mMin, mMax;
+ QSet<QString> mTypeNames;
+ bool mAscending;
+ QString mUuid;
+ QVector<QueryConstraint*> mQueryConstraints;
+ QString mAggregateOperation;
+ QString mFieldName;
+ QVariant mFieldValue; // value of field for the object the cursor is pointing at
+ bool mSparseMatchPossible;
+ QHash<QString, QsonMap> mObjectCache;
+ JsonDbQuery *mResidualQuery;
+};
+
+class UuidQuery : public IndexQuery {
+protected:
+ UuidQuery(JsonDbBtreeStorage *storage, ObjectTable *table, const QString &fieldName, const JsonDbOwner *owner, bool ascending = true);
+ virtual bool seekToStart(QVariant &fieldValue);
+ virtual bool seekToNext(QVariant &fieldValue);
+ virtual QsonMap currentObjectAndTypeNumber(ObjectKey &objectKey);
+ virtual quint32 stateNumber() const;
+ friend class IndexQuery;
+};
+
+class JsonDbBtreeStorage : public QObject
+{
+ Q_OBJECT
+public:
+
+ JsonDbBtreeStorage(const QString &filename, const QString &name, JsonDb *jsonDb);
+ ~JsonDbBtreeStorage();
+ bool open();
+ bool close();
+ bool clear();
+ bool beginTransaction();
+ bool commitTransaction(quint32 stateNumber = 0);
+ bool abortTransaction();
+
+ void initIndexes();
+ bool checkValidity();
+ QsonObject addIndex(const QString &fieldName,
+ const QString &fieldType = QString("string"),
+ const QString &objectType = QString(),
+ bool lazy=true);
+
+ bool checkQuota(const JsonDbOwner *owner, int size) const;
+ bool addToQuota(const JsonDbOwner *owner, int size);
+
+ QsonMap queryPersistentObjects(const JsonDbOwner *owner, const JsonDbQuery &query, int limit=-1, int offset=0);
+ QsonMap queryPersistentObjects(const JsonDbOwner *owner, const JsonDbQuery &query, int limit, int offset,
+ QList<JsonDbBtreeStorage *> partitions);
+ QsonMap createPersistentObject(QsonMap& );
+ QsonMap updatePersistentObject(QsonMap& );
+ QsonMap removePersistentObject(QsonMap object, const QsonMap &tombStone );
+
+ void addView(const QString &viewType);
+ void removeView(const QString &viewType);
+ ObjectTable *mainObjectTable() const { return mObjectTable; }
+ ObjectTable *findObjectTable(const QString &objectType) const;
+
+ QsonMap lookupObject(const QString &uuid, const QString &objectType = QString()) const;
+ QsonMap lookupObject(const ObjectKey & objectKey, const QString &objectType = QString()) const;
+
+ QsonMap getObject(const QString &keyName, const QVariant &key, const QString &type = QString());
+
+ QsonMap changesSince(quint32 stateNumber, const QSet<QString> &limitTypes = QSet<QString>());
+ void dumpIndexes(QString label);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString getTablePrefix();
+ void setTablePrefix(const QString &prefix);
+
+ void checkIndex(const QString &fieldName);
+ bool compact();
+
+protected:
+ bool checkStateConsistency();
+ void checkIndexConsistency(ObjectTable *table, JsonDbIndex *index);
+ void updateIndex(ObjectTable *table, JsonDbIndex *index);
+ void updateView(ObjectTable *table);
+ void updateView(const QString &objectType);
+
+ IndexQuery *compileIndexQuery(const JsonDbOwner *owner, const JsonDbQuery &query);
+ void compileOrQueryTerm(IndexQuery *indexQuery, const QueryTerm &queryTerm);
+
+ void doIndexQuery(const JsonDbOwner *owner, QsonList &results, int &limit, int &offset,
+ IndexQuery *indexQuery);
+ void doMultiIndexQuery(const JsonDbOwner *owner, QsonList &results, int &limit, int &offset,
+ const QList<IndexQuery *> &indexQueries);
+
+ static void sortValues(const JsonDbQuery *query, QsonList &results, QsonList &joinedResults);
+
+private:
+ JsonDb *mJsonDb;
+ ObjectTable *mObjectTable;
+ AoDb *mBdbIndexes;
+ AoDb *mBdbs[1];
+ QVector<ObjectTable *> mTableTransactions;
+
+ QString mPartitionName;
+ QString mFilename;
+ int mTransactionDepth;
+ bool mTransactionOk;
+ QHash<QString,QPointer<ObjectTable> > mViews;
+ QRegExp mWildCardPrefixRegExp;
+
+ friend class IndexQuery;
+ friend class ObjectTable;
+ friend class JsonDbMapDefinition;
+ friend class WithTransaction;
+ friend class ::TestJsonDb;
+};
+
+class WithTransaction {
+public:
+ WithTransaction(JsonDbBtreeStorage *storage, QString name=QString())
+ : mStorage(storage)
+ {
+ Q_UNUSED(name)
+ //qDebug() << "WithTransaction" << "depth" << mStorage->mTransactionDepth << name;
+ if (!mStorage->beginTransaction())
+ mStorage = 0;
+ }
+
+ ~WithTransaction()
+ {
+ if (mStorage)
+ mStorage->commitTransaction();
+ }
+
+ bool hasBegin() { return mStorage; }
+ bool addObjectTable(ObjectTable *table);
+
+ void abort()
+ {
+ mStorage->abortTransaction();
+ mStorage = 0;
+ }
+
+ void commit(quint32 stateNumber = 0)
+ {
+ mStorage->commitTransaction(stateNumber);
+ mStorage = 0;
+ }
+
+private:
+ JsonDbBtreeStorage *mStorage;
+};
+
+#define CHECK_LOCK(lock, context) \
+ if (!lock.hasBegin()) { \
+ QsonMap errormap; \
+ errormap.insert(JsonDbString::kCodeStr, (int)JsonDbError::DatabaseError); \
+ QString error = QString("Failed to set begin transaction [%1:%2]") \
+ .arg(context, QString::number(__LINE__)); \
+ qCritical() << error; \
+ }
+
+#define CHECK_LOCK_RETURN(lock, context) \
+ if (!lock.hasBegin()) { \
+ QsonMap errormap; \
+ errormap.insert(JsonDbString::kCodeStr, (int)JsonDbError::DatabaseError); \
+ QString error = QString("Failed to set begin transaction [%1:%2]") \
+ .arg(context, QString::number(__LINE__)); \
+ errormap.insert(JsonDbString::kMessageStr, error); \
+ QsonMap result; \
+ result.insert(JsonDbString::kResultStr, QsonObject::NullValue); \
+ result.insert(JsonDbString::kErrorStr, errormap); \
+ return result; \
+ }
+
+QByteArray makeForwardKey(const QVariant &fieldValue, const ObjectKey &objectKey);
+int forwardKeyCmp(const char *aptr, size_t asiz, const char *bptr, size_t bsiz, void *op);
+void forwardKeySplit(const QByteArray &forwardKey, QVariant &fieldValue);
+void forwardKeySplit(const QByteArray &forwardKey, QVariant &fieldValue, ObjectKey &objectKey);
+QByteArray makeForwardValue(const ObjectKey &);
+void forwardValueSplit(const QByteArray &forwardValue, ObjectKey &objectKey);
+
+QDebug &operator<<(QDebug &, const ObjectKey &);
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif /* JSONDB_H */
diff --git a/src/daemon/jsondbindex.cpp b/src/daemon/jsondbindex.cpp
new file mode 100644
index 00000000..85fa9ec6
--- /dev/null
+++ b/src/daemon/jsondbindex.cpp
@@ -0,0 +1,334 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QObject>
+#include <QByteArray>
+#include <QVariant>
+#include <QFileInfo>
+#include <QDir>
+
+#include "jsondb-strings.h"
+#include "jsondb.h"
+#include "jsondbindex.h"
+#include "aodb.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+static bool debugIndexObject = false;
+
+JsonDbIndex::JsonDbIndex(const QString &fileName, const QString &fieldName, QObject *parent)
+ : QObject(parent)
+ , mFieldName(fieldName)
+ , mPath(fieldName.split('.'))
+ , mStateNumber(0)
+ , mBdb(0)
+{
+ QFileInfo fi(fileName);
+ QDir dir(fi.absolutePath());
+ QString dirName = fi.dir().path();
+ QString baseName = fi.fileName();
+ if (baseName.endsWith(".db"))
+ baseName.chop(3);
+ mFileName = QString("%1/%2-%3-Index.db").arg(dirName).arg(baseName).arg(fieldName);
+}
+
+JsonDbIndex::~JsonDbIndex()
+{
+ if (mBdb) {
+ close();
+ mBdb.reset();
+ }
+}
+
+bool JsonDbIndex::open()
+{
+ if (mFieldName == JsonDbString::kUuidStr)
+ return true;
+
+ mBdb.reset(new AoDb());
+
+ if (!mBdb->open(mFileName, AoDb::NoSync | AoDb::UseSyncMarker)) {
+ qCritical() << "mBdb->open" << mBdb->errorMessage();
+ return false;
+ }
+
+ if (!mBdb->setCmpFunc(forwardKeyCmp)) {
+ qCritical() << "mBdb->setCmpFunc" << mBdb->errorMessage();
+ return false;
+ }
+
+ mStateNumber = mBdb->tag();
+ if (gDebugRecovery) qDebug() << "JsonDbIndex::open" << mStateNumber << mFileName;
+ return true;
+}
+
+void JsonDbIndex::close()
+{
+ if (mBdb)
+ mBdb->close();
+}
+
+AoDb *JsonDbIndex::bdb()
+{
+ if (!mBdb)
+ open();
+ return mBdb.data();
+}
+
+void JsonDbIndex::indexObject(const ObjectKey &objectKey, QsonObject &object, quint32 stateNumber, bool inTransaction)
+{
+ if (mFieldName == JsonDbString::kUuidStr)
+ return;
+
+ bool ok;
+ if (!mBdb)
+ open();
+ QVariantList fieldValues;
+ int size = mPath.size();
+ if (mPath[size-1] == QString("*")) {
+ QVariant v = JsonDb::propertyLookup(object, mPath.mid(0, size-1));
+ fieldValues = v.toList();
+ } else {
+ QVariant v = JsonDb::propertyLookup(object, mPath);
+ fieldValues.append(v);
+ }
+ //qDebug() << "JsonDbIndex::indexObject" << mPath << fieldValues;
+ if (!inTransaction)
+ mBdb->begin();
+ foreach (const QVariant fieldValue, fieldValues) {
+ if (!fieldValue.isValid())
+ continue;
+ QByteArray forwardKey(makeForwardKey(fieldValue, objectKey));
+ QByteArray forwardValue(makeForwardValue(objectKey));
+
+ if (debugIndexObject)
+ qDebug() << "indexing" << objectKey << mFieldName << fieldValue
+ << "forwardIndex" << "key" << forwardKey.toHex()
+ << "forwardIndex" << "value" << forwardValue.toHex()
+ << object;
+ ok = mBdb->put(forwardKey, forwardValue);
+ if (!ok) qCritical() << __FUNCTION__ << "putting fowardIndex" << mBdb->errorMessage();
+ }
+ if (!inTransaction)
+ mBdb->commit(stateNumber);
+ if (gDebugRecovery && (stateNumber < mStateNumber))
+ qDebug() << "JsonDbIndex::indexObject" << "stale update" << stateNumber << mStateNumber << mFileName;
+ mStateNumber = qMax(stateNumber, mStateNumber);
+
+#ifdef CHECK_INDEX_ORDERING
+ checkIndex()
+#endif
+}
+
+void JsonDbIndex::deindexObject(const ObjectKey &objectKey, QsonObject &object, quint32 stateNumber, bool inTransaction)
+{
+ if (mFieldName == JsonDbString::kUuidStr)
+ return;
+ if (!mBdb)
+ open();
+ QVariantList fieldValues;
+ int size = mPath.size();
+ if (mPath[size-1] == QString("*")) {
+ QVariant v = JsonDb::propertyLookup(object, mPath.mid(0, size-1));
+ fieldValues = v.toList();
+ } else {
+ QVariant v = JsonDb::propertyLookup(object, mPath);
+ fieldValues.append(v);
+ }
+ if (!inTransaction)
+ mBdb->begin();
+ foreach (const QVariant fieldValue, fieldValues) {
+ if (!fieldValue.isValid())
+ continue;
+ if (debugIndexObject)
+ qDebug() << "deindexing" << objectKey << mFieldName << fieldValue;
+ QByteArray forwardKey(makeForwardKey(fieldValue, objectKey));
+ if (!mBdb->remove(forwardKey)) {
+ qDebug() << "deindexing failed" << objectKey << mFieldName << fieldValue << object << forwardKey.toHex();
+ }
+ }
+ if (gDebugRecovery && (stateNumber < mStateNumber))
+ qDebug() << "JsonDbIndex::deindexObject" << "stale update" << stateNumber << mStateNumber << mFileName;
+ if (!inTransaction)
+ mBdb->commit(stateNumber);
+#ifdef CHECK_INDEX_ORDERING
+ checkIndex();
+#endif
+}
+
+quint32 JsonDbIndex::stateNumber() const
+{
+ return mStateNumber;
+}
+
+bool JsonDbIndex::begin()
+{
+ if (!mBdb)
+ open();
+ return mBdb->begin();
+}
+bool JsonDbIndex::commit(quint32 stateNumber)
+{
+ return mBdb->commit(stateNumber);
+}
+bool JsonDbIndex::abort()
+{
+ return mBdb->abort();
+}
+bool JsonDbIndex::clear()
+{
+ return mBdb->clear();
+}
+
+void JsonDbIndex::checkIndex()
+{
+ if (mFieldName == JsonDbString::kUuidStr)
+ return;
+
+ qDebug() << "checkIndex" << mFieldName;
+ int countf = 0;
+ AoDbCursor cursorf(mBdb.data());
+ bool ok = cursorf.first();
+ if (ok) {
+ countf++;
+ QByteArray outkey1;
+ ok = cursorf.currentKey(outkey1);
+ while (cursorf.next()) {
+ countf++;
+ QByteArray outkey2;
+ cursorf.currentKey(outkey2);
+ //qDebug() << outkey1.toHex() << outkey2.toHex();
+ if (memcmp(outkey1.constData(), outkey2.constData(), outkey1.size()) >= 0) {
+ qDebug() << "out of order index" << mFieldName << endl
+ << outkey1.toHex() << endl
+ << outkey2.toHex() << endl;
+ }
+ outkey1 = outkey2;
+ }
+ }
+
+ qDebug() << "checkIndex" << mFieldName << "reversed";
+ // now check other direction
+ int countr = 0;
+ AoDbCursor cursorr(mBdb.data());
+ ok = cursorr.last();
+ if (ok) {
+ countr++;
+ QByteArray outkey1;
+ ok = cursorr.currentKey(outkey1);
+ while (cursorr.prev()) {
+ countr++;
+ QByteArray outkey2;
+ cursorr.currentKey(outkey2);
+ //qDebug() << outkey1.toHex() << outkey2.toHex();
+ if (memcmp(outkey1.constData(), outkey2.constData(), outkey1.size()) <= 0) {
+ qDebug() << "reverse walk: out of order index" << mFieldName << endl
+ << outkey1.toHex() << endl
+ << outkey2.toHex() << endl;
+ }
+ outkey1 = outkey2;
+ }
+ }
+ qDebug() << "checkIndex" << mFieldName << "done" << countf << countr << "entries checked";
+
+}
+
+JsonDbIndexCursor::JsonDbIndexCursor(JsonDbIndex *index)
+ : mCursor(index->bdb())
+{
+}
+
+bool JsonDbIndexCursor::seek(const QVariant &value)
+{
+ QByteArray forwardKey(makeForwardKey(value, ObjectKey()));
+ return mCursor.seek(forwardKey);
+}
+
+bool JsonDbIndexCursor::seekRange(const QVariant &value)
+{
+ QByteArray forwardKey(makeForwardKey(value, ObjectKey()));
+ return mCursor.seekRange(forwardKey);
+}
+
+bool JsonDbIndexCursor::current(QVariant &key, ObjectKey &value)
+{
+ QByteArray baKey, baValue;
+ if (!mCursor.current(baKey, baValue))
+ return false;
+ forwardKeySplit(baKey, key);
+ forwardValueSplit(baValue, value);
+ return true;
+}
+
+bool JsonDbIndexCursor::currentKey(QVariant &key)
+{
+ QByteArray baKey;
+ if (!mCursor.currentKey(baKey))
+ return false;
+ forwardKeySplit(baKey, key);
+ return true;
+}
+
+bool JsonDbIndexCursor::currentValue(ObjectKey &value)
+{
+ QByteArray baValue;
+ if (!mCursor.currentValue(baValue))
+ return false;
+ forwardValueSplit(baValue, value);
+ return true;
+}
+
+bool JsonDbIndexCursor::first()
+{
+ return mCursor.first();
+}
+
+bool JsonDbIndexCursor::next()
+{
+ return mCursor.next();
+}
+
+bool JsonDbIndexCursor::prev()
+{
+ return mCursor.prev();
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondbindex.h b/src/daemon/jsondbindex.h
new file mode 100644
index 00000000..f333078e
--- /dev/null
+++ b/src/daemon/jsondbindex.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_INDEX_H
+#define JSONDB_INDEX_H
+
+#include <QObject>
+#include <QPointer>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "jsondb-global.h"
+#include "aodb.h"
+#include "objectkey.h"
+
+class Bdb;
+class AoDb;
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDbBtreeStorage;
+
+class JsonDbIndex : public QObject
+{
+ Q_OBJECT
+public:
+ JsonDbIndex(const QString &fileName, const QString &fieldName, QObject *parent = 0);
+ ~JsonDbIndex();
+
+ QString fieldName() const { return mFieldName; }
+ QStringList fieldPath() const { return mPath; }
+
+ AoDb *bdb();
+
+ void indexObject(const ObjectKey &objectKey, QsonObject &object, quint32 stateNumber, bool inTransaction=false);
+ void deindexObject(const ObjectKey &objectKey, QsonObject &object, quint32 stateNumber, bool inTransaction=false);
+
+ quint32 stateNumber() const;
+
+ bool begin();
+ bool commit(quint32);
+ bool abort();
+ bool clear();
+
+ void checkIndex();
+// bool checkValidity(const QMap<QString, QsonObject> &objects,
+// const QMap<quint32, QString> &keyUuids,
+// const QMap<QString, quint32> &uuidKeys,
+// JsonDbBtreeStorage *storage);
+ bool open();
+ void close();
+
+private:
+ QString mFileName;
+ QString mFieldName;
+ QStringList mPath;
+ quint32 mStateNumber;
+ QScopedPointer<AoDb> mBdb;
+};
+
+class JsonDbIndexCursor
+{
+public:
+ JsonDbIndexCursor(JsonDbIndex *index);
+
+ bool seek(const QVariant &value);
+ bool seekRange(const QVariant &value);
+
+ bool first();
+ bool current(QVariant &key, ObjectKey &value);
+ bool currentKey(QVariant &key);
+ bool currentValue(ObjectKey &value);
+ bool next();
+ bool prev();
+
+private:
+ AoDbCursor mCursor;
+
+ JsonDbIndexCursor(const JsonDbIndexCursor&);
+};
+
+class IndexSpec {
+public:
+ QString fieldName;
+ QStringList path;
+ QString fieldType;
+ QString objectType;
+ bool lazy;
+ QPointer<JsonDbIndex> index;
+};
+
+} } // end namespace QtAddOn::JsonDb
+#endif
diff --git a/src/daemon/jsondbquery.cpp b/src/daemon/jsondbquery.cpp
new file mode 100644
index 00000000..c75b8ba8
--- /dev/null
+++ b/src/daemon/jsondbquery.cpp
@@ -0,0 +1,658 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QFile>
+#include <QString>
+#include <QStringList>
+
+#include "jsondb-strings.h"
+#include "jsondb.h"
+#include "jsondbbtreestorage.h"
+#include "jsondbquery.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+#ifndef QT_NO_DEBUG_OUTPUT
+extern bool gDebug;
+#define DBG() if (gDebug) qDebug() << Q_FUNC_INFO
+#else
+#define DBG() if (0) qDebug() << Q_FUNC_INFO
+#endif
+
+struct TokenClassInitializer { QChar c; JsonDbQueryTokenizer::TokenClass tokenClass;};
+static TokenClassInitializer sTokenClasses[] = {
+ { '[', JsonDbQueryTokenizer::Singleton },
+ { ']', JsonDbQueryTokenizer::Singleton },
+ { '{', JsonDbQueryTokenizer::Singleton },
+ { '}', JsonDbQueryTokenizer::Singleton },
+ { '/', JsonDbQueryTokenizer::Singleton },
+ { '\\', JsonDbQueryTokenizer::Singleton },
+ { '?', JsonDbQueryTokenizer::Singleton },
+ { ',', JsonDbQueryTokenizer::Singleton },
+ { ':', JsonDbQueryTokenizer::Singleton },
+ { '=', JsonDbQueryTokenizer::Operator },
+ { '>', JsonDbQueryTokenizer::Operator },
+ { '<', JsonDbQueryTokenizer::Operator },
+ { '!', JsonDbQueryTokenizer::Operator },
+ { '-', JsonDbQueryTokenizer::Operator },
+ { '~', JsonDbQueryTokenizer::Operator }
+};
+
+JsonDbQueryTokenizer::TokenClass JsonDbQueryTokenizer::sTokenClass[128];
+JsonDbQueryTokenizer::JsonDbQueryTokenizer(QString input)
+ : mInput(input), mPos(0)
+{
+ if (sTokenClass[sTokenClasses[0].c.unicode()] != sTokenClasses[0].tokenClass) {
+ memset(sTokenClass, 0, sizeof(sTokenClass));
+ for (unsigned int i = 0; i < sizeof(sTokenClasses)/sizeof(TokenClassInitializer); i++)
+ sTokenClass[sTokenClasses[i].c.unicode()] = sTokenClasses[i].tokenClass;
+ }
+}
+
+QString JsonDbQueryTokenizer::pop()
+{
+ QString token;
+ if (!mNextToken.isEmpty()) {
+ token = mNextToken;
+ mNextToken.clear();
+ } else {
+ token = getNextToken();
+ }
+ return token;
+}
+
+QString JsonDbQueryTokenizer::peek()
+{
+ if (mNextToken.isEmpty())
+ mNextToken = getNextToken();
+ return mNextToken;
+}
+
+QString JsonDbQueryTokenizer::getNextToken()
+{
+ QString result;
+ bool indexExpression = false;
+ while (mPos < mInput.size()) {
+ QChar c = mInput[mPos++];
+ JsonDbQueryTokenizer::TokenClass tokenClass = getTokenClass(c);
+ if (tokenClass == JsonDbQueryTokenizer::Singleton) {
+ result.append(c);
+ return result;
+ } else if (tokenClass == JsonDbQueryTokenizer::Operator) {
+ result.append(c);
+ if (getTokenClass(mInput[mPos]) == JsonDbQueryTokenizer::Operator)
+ result.append(mInput[mPos++]);
+ return result;
+ } else if (c == '"') {
+ // match string
+ result.append(c);
+ bool escaped = false;
+ QChar sc;
+ int size = mInput.size();
+ int i;
+ //qDebug() << "start of string";
+ for (i = mPos; (i < size); i++) {
+ sc = mInput[i];
+ //qDebug() << i << sc << escaped;
+ if (!escaped && (sc == '"'))
+ break;
+ escaped = (sc == '\\');
+ }
+ //qDebug() << "end" << i << sc << escaped;
+ //qDebug() << mInput.mid(mPos, i-mPos+1);
+ if ((i < size) && (sc == '"')) {
+ //qDebug() << mPos << i-mPos << "string is" << mInput.mid(mPos, i-mPos);
+ result.append(mInput.mid(mPos, i-mPos+1));
+ mPos = i+1;
+ } else {
+ mPos = i;
+ result = QString();
+ }
+ return result;
+ } else if (c.isSpace()) {
+ if (result.size())
+ return result;
+ else
+ continue;
+ } else {
+ result.append(c);
+ if (mPos < mInput.size()) {
+ QChar next = mInput[mPos];
+ JsonDbQueryTokenizer::TokenClass nextTokenClass = getTokenClass(next);
+ //qDebug() << mInput[mPos] << mInput[mPos].unicode() << "nextTokenTokenClass" << nextTokenClass << indexExpression;
+ if (nextTokenClass == JsonDbQueryTokenizer::Other)
+ continue;
+ else if ((next == '[')
+ || (indexExpression && (next == ']'))) {
+ // handle [*] as a special case
+ result.append(mInput[mPos++]);
+ indexExpression = (next == '[');
+ continue;
+ } else
+ return result;
+ }
+ }
+ }
+ return QString();
+}
+
+JsonDbQuery::~JsonDbQuery()
+{
+ queryTerms.clear();
+ orderTerms.clear();
+}
+
+QVariant JsonDbQuery::parseJsonLiteral(const QString &json, QueryTerm *term, QsonMap &bindings, bool *ok)
+{
+ const ushort trueLiteral[] = {'t','r','u','e', 0};
+ const ushort falseLiteral[] = {'f','a','l','s','e', 0};
+ const ushort *literal = json.utf16();
+ if (ok) { *ok = true; }
+ switch (literal[0]) {
+ case '"':
+ term->setValue(json.mid(1, json.size()-2));
+ break;
+ case 't':
+ // we will interpret "true0something" as true is it a real problem ?
+ for (int i = 1; i < 5 /* 'true0' length */; ++i) {
+ if (trueLiteral[i] != literal[i]) {
+ if (ok) { *ok = false; }
+ return term->value();
+ }
+ }
+ term->setValue(true);
+ break;
+ case 'f':
+ // we will interpret "false0something" as false is it a real problem ?
+ for (int i = 1; i < 6 /* 'false0' length */; ++i) {
+ if (falseLiteral[i] != literal[i]) {
+ if (ok) { *ok = false; }
+ return term->value();
+ }
+ }
+ term->setValue(false);
+ break;
+ case '%':
+ {
+ const QString name = json.mid(1); // TODO use .midRef()?
+ QVariant value = qsonToVariant(bindings.value<QsonElement>(name));
+ term->setValue(value);
+ break;
+ }
+ case 0:
+ // This can happen if json.length() == 0
+ if (ok) { *ok = false; }
+ return term->value();
+ default:
+ int result = json.toInt(ok);
+ if (ok) {
+ term->setValue(result);
+ } else {
+ // bad luck, it can be only a double
+ term->setValue(json.toDouble(ok));
+ }
+ }
+ return term->value();
+}
+
+JsonDbQuery JsonDbQuery::parse(const QString &query, QsonMap &bindings)
+{
+ JsonDbQuery parsedQuery;
+ parsedQuery.query = query;
+
+ bool parseError = false;
+ JsonDbQueryTokenizer tokenizer(query);
+ QString token;
+ while (!parseError
+ && !(token = tokenizer.pop()).isEmpty()) {
+ if (token != "[") {
+ qCritical() << "unexpected token" << token;
+ break;
+ }
+ token = tokenizer.pop();
+ if (token == "?") {
+ OrQueryTerm oqt;
+ do {
+ QString fieldSpec = tokenizer.pop();
+ if (fieldSpec == "|")
+ fieldSpec = tokenizer.pop();
+
+ QString opOrJoin = tokenizer.pop();
+ QString op;
+ QStringList joinFields;
+ QString joinField;
+ while (opOrJoin == "->") {
+ joinFields.append(fieldSpec);
+ fieldSpec = tokenizer.pop();
+ opOrJoin = tokenizer.pop();
+ }
+ if (joinFields.size())
+ joinField = joinFields.join("->");
+ op = opOrJoin;
+
+
+ QueryTerm term;
+ if (!joinField.isEmpty())
+ term.setJoinField(joinField);
+ term.setFieldName(fieldSpec);
+ term.setOp(op);
+ if (op == "=~") {
+ QString tvs = tokenizer.pop();
+ if (!tvs.startsWith("\"")) {
+ parsedQuery.queryExplanation.append(QString("Failed to parse query regular expression '%1' in query '%2' %3 op %4")
+ .arg(tvs)
+ .arg(parsedQuery.query)
+ .arg(fieldSpec)
+ .arg(op));
+ parseError = true;
+ break;
+ }
+ QChar sep = tvs[1];
+ int eor = 1;
+ do {
+ eor = tvs.indexOf(sep, eor+1); // end of regexp;
+ //qDebug() << "tvs" << tvs << "eor" << eor << "tvs[eor-1]" << ((eor > 0) ? tvs[eor-1] : QChar('*'));
+ if (eor <= 1) {
+ parseError = true;
+ break;
+ }
+ } while ((eor > 0) && (tvs[eor-1] == '\\'));
+ QString modifiers = tvs.mid(eor+1,tvs.size()-eor-2);
+ if (gDebug) qDebug() << "modifiers" << modifiers;
+ if (gDebug) qDebug() << "regexp" << tvs.mid(2, eor-2);
+ if (modifiers.contains('w'))
+ term.regExp().setPatternSyntax(QRegExp::Wildcard);
+ if (modifiers.contains('i'))
+ term.regExp().setCaseSensitivity(Qt::CaseInsensitive);
+ //qDebug() << "pattern" << tvs.mid(2, eor-2);
+ term.regExp().setPattern(tvs.mid(2, eor-2));
+ } else if (op != "exists") {
+ QString value = tokenizer.pop();
+ bool ok = true;;
+ if (value == "[") {
+ QVariantList values;
+ while (1) {
+ value = tokenizer.pop();
+ if (value == "]")
+ break;
+ parseJsonLiteral(value, &term, bindings, &ok);
+ if (!ok)
+ break;
+ values.append(term.value());
+ if (tokenizer.peek() == ",")
+ tokenizer.pop();
+ }
+ term.setValue(values);
+ } else {
+ parseJsonLiteral(value, &term, bindings, &ok);
+ }
+ if (!ok) {
+ parsedQuery.queryExplanation.append(QString("Failed to parse query value '%1' in query '%2' %3 op %4")
+ .arg(value)
+ .arg(parsedQuery.query)
+ .arg(fieldSpec)
+ .arg(op));
+ parseError = true;
+ break;
+ }
+ }
+
+ oqt.addTerm(term);
+ } while (tokenizer.peek() != "]");
+ parsedQuery.queryTerms.append(oqt);
+ } else if (token == "=") {
+ bool isMapObject = false;
+ bool isListObject = false;
+ bool inListObject = false;
+ QString nextToken;
+ while (!(nextToken = tokenizer.pop()).isEmpty()) {
+ if (nextToken == "{")
+ isMapObject = true;
+ else if (nextToken == "[") {
+ isListObject = true;
+ inListObject = true;
+ } else if (nextToken == "]") {
+ if (!inListObject)
+ tokenizer.push(nextToken);
+ else
+ inListObject = false;
+ break;
+ } else if (nextToken == "}") {
+ break;
+ } else {
+ if (isMapObject) {
+ //qDebug() << "isMapObject" << nextToken << tokenizer.peek();
+ parsedQuery.mapKeyList.append(nextToken);
+ QString colon = tokenizer.pop();
+ if (colon != ":") {
+ parsedQuery.queryExplanation.append(QString("Parse error: expecting ':' but got '%1'").arg(colon));
+ parseError = true;
+ break;
+ }
+ nextToken = tokenizer.pop();
+ }
+ while (tokenizer.peek() == "->") {
+ QString op = tokenizer.pop();
+ nextToken.append(op);
+ nextToken.append(tokenizer.pop());
+ }
+ parsedQuery.mapExpressionList.append(nextToken);
+ QString maybeComma = tokenizer.pop();
+ if ((maybeComma == "}") || (maybeComma == "]")) {
+ tokenizer.push(maybeComma);
+ continue;
+ } else if (maybeComma != ",") {
+ parsedQuery.queryExplanation.append(QString("Parse error: expecting ',', ']', or '}' but got '%1'")
+ .arg(maybeComma));
+ parseError = true;
+ break;
+ }
+ }
+ }
+ if (gDebug) qDebug() << "isListObject" << isListObject << parsedQuery.mapExpressionList;
+ if (isListObject)
+ parsedQuery.resultType = QVariant::List;
+ else if (isMapObject)
+ parsedQuery.resultType = QVariant::Map;
+ else
+ parsedQuery.resultType = QVariant::String;
+ } else if ((token == "/") || (token == "\\") || (token == ">") || (token == "<")) {
+ QString ordering = token;
+ OrderTerm term;
+ term.fieldName = tokenizer.pop();
+ term.ascending = ((ordering == "/") || (ordering == ">"));
+ parsedQuery.orderTerms.append(term);
+ } else if (token == "count") {
+ parsedQuery.mAggregateOperation = "count";
+ } else if (token == "*") {
+ // match all objects
+ } else {
+ qCritical() << QString("Parse error: expecting '?', '/', '\\', or 'count' but got '%1'").arg(token);
+ parseError = true;
+ break;
+ }
+ QString closeBracket = tokenizer.pop();
+ if (closeBracket != "]") {
+ qCritical() << QString("Parse error: expecting ']' but got '%1'").arg(closeBracket);
+ parseError = true;
+ break;
+ }
+ }
+
+ if (parseError) {
+ QStringList explanation = parsedQuery.queryExplanation;
+ parsedQuery = JsonDbQuery();
+ parsedQuery.queryExplanation = explanation;
+ qCritical() << "Parser error: query" << query;
+ return parsedQuery;
+ }
+
+ foreach (const OrQueryTerm &oqt, parsedQuery.queryTerms) {
+ foreach (const QueryTerm &term, oqt.terms()) {
+ if (term.fieldName() == JsonDbString::kTypeStr) {
+ if (term.op() == "=") {
+ parsedQuery.mMatchedTypes.clear();
+ parsedQuery.mMatchedTypes.insert(term.value().toString());
+ } else if (term.op() == "!=") {
+ parsedQuery.mMatchedTypes.insert(term.value().toString());
+ }
+ }
+ }
+ }
+ // TODO look at this again
+ if (!parsedQuery.queryTerms.size() && !parsedQuery.orderTerms.size()) {
+ // match everything -- sort on type
+ OrderTerm term;
+ term.fieldName = JsonDbString::kTypeStr;
+ term.ascending = true;
+ parsedQuery.orderTerms.append(term);
+ }
+
+ //qDebug() << "queryTerms.size()" << parsedQuery.queryTerms.size();
+ //qDebug() << "orderTerms.size()" << parsedQuery.orderTerms.size();
+ return parsedQuery;
+}
+
+bool JsonDbQuery::match(const QsonMap &object, QHash<QString, QsonMap> *objectCache, JsonDbBtreeStorage *storage) const
+{
+ for (int i = 0; i < queryTerms.size(); i++) {
+ const OrQueryTerm &orQueryTerm = queryTerms[i];
+ bool matches = false;
+ foreach (const QueryTerm &term, orQueryTerm.terms()) {
+ const QString &joinFieldName = term.joinField();
+ const QString &op = term.op();
+ const QVariant &termValue = term.value();
+
+ QVariant objectFieldValue;
+ if (!joinFieldName.isEmpty()) {
+ QsonMap joinedObject = object;
+ const QVector<QStringList> &joinPaths = term.joinPaths();
+ for (int j = 0; j < joinPaths.size(); j++) {
+ if (!joinPaths[j].size()) {
+ DBG() << term.joinField() << term.joinPaths();
+ }
+ QString uuidValue = JsonDb::propertyLookup(joinedObject, joinPaths[j]).toString();
+ if (objectCache && objectCache->contains(uuidValue))
+ joinedObject = objectCache->value(uuidValue);
+ else if (storage) {
+ ObjectKey objectKey(uuidValue);
+ joinedObject = storage->lookupObject(objectKey);
+ if (objectCache) objectCache->insert(uuidValue, joinedObject);
+ }
+ }
+ objectFieldValue = JsonDb::propertyLookup(joinedObject, term.fieldPath());
+ } else {
+ objectFieldValue = JsonDb::propertyLookup(object, term.fieldPath());
+ }
+
+ if ((op == "=") || (op == "==")) {
+ if (termValue.type() == QVariant::Int) {
+ if (objectFieldValue.toInt() == termValue.toInt())
+ matches = true;
+ } else if (termValue.type() == QVariant::Double) {
+ if (objectFieldValue.toDouble() == termValue.toDouble())
+ matches = true;
+ } else {
+ if (objectFieldValue == termValue)
+ matches = true;
+ }
+ } else if ((op == "<>") || (op == "!=")) {
+ if (objectFieldValue != termValue)
+ matches = true;
+ } else if (op == "=~") {
+ DBG() << objectFieldValue.toString() << term.regExpConst().exactMatch(objectFieldValue.toString());
+ if (term.regExpConst().exactMatch(objectFieldValue.toString()))
+ matches = true;
+ } else if (op == "<=") {
+ if (objectFieldValue.type() == QVariant::Double) {
+ if (objectFieldValue.toDouble() <= termValue.toDouble())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Bool) {
+ if (objectFieldValue.toBool() <= termValue.toBool())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Int){
+ if (objectFieldValue.toInt() <= termValue.toInt())
+ matches = true;
+ } else {
+ if (objectFieldValue.toString() <= termValue.toString())
+ matches = true;
+ }
+ } else if (op == "<") {
+ if (objectFieldValue.type() == QVariant::Double) {
+ if (objectFieldValue.toDouble() < termValue.toDouble())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Bool) {
+ if (objectFieldValue.toBool() < termValue.toBool())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Int){
+ if (objectFieldValue.toInt() < termValue.toInt())
+ matches = true;
+ } else {
+ if (objectFieldValue.toString() < termValue.toString())
+ matches = true;
+ }
+ } else if (op == ">=") {
+ if (objectFieldValue.type() == QVariant::Double) {
+ if (objectFieldValue.toDouble() >= termValue.toDouble())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Bool) {
+ if (objectFieldValue.toBool() >= termValue.toBool())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Int){
+ if (objectFieldValue.toInt() >= termValue.toInt())
+ matches = true;
+ } else {
+ if (objectFieldValue.toString() >= termValue.toString())
+ matches = true;
+ }
+ } else if (op == ">") {
+ if (objectFieldValue.type() == QVariant::Double) {
+ if (objectFieldValue.toDouble() > termValue.toDouble())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Bool) {
+ if (objectFieldValue.toBool() > termValue.toBool())
+ matches = true;
+ } else if (objectFieldValue.type() == QVariant::Int){
+ if (objectFieldValue.toInt() > termValue.toInt())
+ matches = true;
+ } else {
+ if (objectFieldValue.toString() > termValue.toString())
+ matches = true;
+ }
+ } else if (op == "exists") {
+ if (objectFieldValue.isValid())
+ matches = true;
+ } else if (op == "in") {
+ if (0) qDebug() << __FUNCTION__ << __LINE__ << objectFieldValue << "in" << termValue
+ << termValue.toList().contains(objectFieldValue.toString());
+ if (termValue.toList().contains(objectFieldValue.toString()))
+ matches = true;
+ } else if (op == "notIn") {
+ if (0) qDebug() << __FUNCTION__ << __LINE__ << objectFieldValue << "notIn" << termValue
+ << !termValue.toList().contains(objectFieldValue.toString());
+ if (!termValue.toList().contains(objectFieldValue.toString()))
+ matches = true;
+ } else if (op == "contains") {
+ if (0) qDebug() << __FUNCTION__ << __LINE__ << objectFieldValue << "contains" << termValue
+ << objectFieldValue.toList().contains(termValue);
+ if (objectFieldValue.toList().contains(termValue))
+ matches = true;
+ } else {
+ qCritical() << "match" << "unhandled term" << term.fieldName() << term.op() << term.value() << term.joinField();
+ }
+ }
+ if (!matches)
+ return false;
+ }
+ return true;
+}
+
+
+
+QueryTerm::QueryTerm()
+ : mJoinPaths()
+ , mRegExp()
+{
+}
+#if 0
+QueryTerm::QueryTerm(const QueryTerm &other)
+ : mFieldName(other.mFieldName)
+ , mFieldPath(other.mFieldPath)
+ , mOp(other.mOp)
+ , mJoinField(other.mJoinField)
+ , mJoinPaths(other.mJoinPaths)
+ , mValue(other.mValue)
+ , mRegExp()
+{
+}
+
+QueryTerm &QueryTerm::operator=(const QueryTerm &other)
+{
+ mFieldName = other.mFieldName;
+ mFieldPath = other.mFieldPath;
+ mOp = other.mOp;
+ mJoinField = other.mJoinField;
+ mJoinPaths = other.mJoinPaths;
+ mValue = other.mValue;
+ return *this;
+}
+#endif
+
+QueryTerm::~QueryTerm()
+{
+ mValue = QVariant();
+ mJoinPaths.clear();
+}
+
+OrQueryTerm::OrQueryTerm()
+{
+}
+
+OrQueryTerm::OrQueryTerm(const QueryTerm &term)
+{
+ mTerms.append(term);
+}
+
+OrQueryTerm::~OrQueryTerm()
+{
+}
+
+QList<QString> OrQueryTerm::fieldNames() const
+{
+ QList<QString> fieldNames;
+ foreach (const QueryTerm &term, mTerms) {
+ QString fieldName = term.fieldName();
+ if (!fieldNames.contains(fieldName))
+ fieldNames.append(fieldName);
+ }
+ return fieldNames;
+}
+
+OrderTerm::OrderTerm()
+{
+}
+
+OrderTerm::~OrderTerm()
+{
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/jsondbquery.h b/src/daemon/jsondbquery.h
new file mode 100644
index 00000000..0ba6edf7
--- /dev/null
+++ b/src/daemon/jsondbquery.h
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JsonDbQuery_H
+#define JsonDbQuery_H
+
+#include <QDebug>
+#include <QObject>
+#include <QHash>
+#include <QStringList>
+#include <QVariant>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDbBtreeStorage;
+
+class JsonDbQueryTokenizer {
+public:
+ enum TokenClass {
+ Other = 0,
+ Singleton,
+ Operator
+ };
+
+ JsonDbQueryTokenizer(QString input);
+ QString pop();
+ QString peek();
+ void push(QString token) {
+ if (!mNextToken.isEmpty())
+ qCritical() << Q_FUNC_INFO << "Cannot push multiple tokens";
+ mNextToken = token;
+ }
+protected:
+ QString getNextToken();
+ TokenClass getTokenClass(QChar c) {
+ int u = c.unicode();
+ TokenClass tc = (u < 128) ? sTokenClass[u] : Other;
+ return tc;
+ }
+private:
+ QString mInput;
+ int mPos;
+ QString mNextToken;
+ static TokenClass sTokenClass[128];
+};
+
+
+class QueryTerm {
+public:
+ QueryTerm();
+ ~QueryTerm();
+ QString fieldName() const { return mFieldName; }
+ void setFieldName(QString fieldName) { mFieldName = fieldName; mFieldPath = fieldName.split('.'); }
+ const QStringList &fieldPath() const { return mFieldPath; }
+
+ QString op() const { return mOp; }
+ void setOp(QString op) { mOp = op; }
+
+ QString joinField() const { return mJoinField; }
+ void setJoinField(QString joinField) {
+ mJoinField = joinField;
+ if (!joinField.isEmpty()) {
+ QStringList joinFields = joinField.split("->");
+ mJoinPaths.resize(joinFields.size());
+ for (int j = 0; j < joinFields.size(); j++)
+ mJoinPaths[j] = joinFields[j].split('.');
+ }
+ }
+ const QVector<QStringList> &joinPaths() const { return mJoinPaths; }
+
+ QVariant value() const { return mValue; }
+ void setValue(QVariant v) { mValue = v; }
+ QRegExp &regExp() { return mRegExp; }
+ const QRegExp &regExpConst() const { return mRegExp; }
+
+ private:
+ QString mFieldName;
+ QStringList mFieldPath;
+ QString mOp;
+ QString mJoinField;
+ QVector<QStringList> mJoinPaths;
+ QVariant mValue;
+ QRegExp mRegExp;
+ //QString valueString;
+};
+
+class OrQueryTerm {
+public:
+ OrQueryTerm();
+ OrQueryTerm(const QueryTerm &term);
+ ~OrQueryTerm();
+ const QList<QueryTerm> &terms() const { return mTerms; }
+ void addTerm(const QueryTerm &term) { mTerms.append(term); }
+ QList<QString> fieldNames() const;
+private:
+ QList<QueryTerm> mTerms;
+};
+
+class OrderTerm {
+public:
+ OrderTerm();
+ ~OrderTerm();
+ bool ascending;
+ QString fieldName;
+};
+
+class JsonDbQuery {
+public:
+ JsonDbQuery() {}
+ JsonDbQuery(const QList<OrQueryTerm> &qt, const QList<OrderTerm> &ot)
+ : queryTerms(qt), orderTerms(ot) {}
+ ~JsonDbQuery();
+ QList<OrQueryTerm> queryTerms;
+ QList<OrderTerm> orderTerms;
+ QString query;
+ QVariant::Type resultType;
+ QStringList mapExpressionList;
+ QStringList mapKeyList;
+ QStringList queryExplanation;
+ QString mAggregateOperation;
+
+ QSet<QString> matchedTypes() const { return mMatchedTypes; }
+ bool match(const QsonMap &object, QHash<QString, QsonMap> *objectCache, JsonDbBtreeStorage *storage = 0) const;
+
+ static QVariant parseJsonLiteral(const QString &json, QueryTerm *term, QsonMap &bindings, bool *ok);
+ static JsonDbQuery parse(const QString &query, QsonMap &bindings);
+
+private:
+ QSet<QString> mMatchedTypes;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
new file mode 100644
index 00000000..33337b2a
--- /dev/null
+++ b/src/daemon/main.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QAbstractSocket>
+#include <iostream>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <errno.h>
+
+#include "signals.h"
+#include "dbserver.h"
+
+QString progname;
+
+namespace QtAddOn { namespace JsonDb {
+
+extern bool gUseJsonInDb;
+extern bool gPerformanceLog;
+
+} } // end namespace QtAddOn::JsonDb
+
+Q_USE_JSONDB_NAMESPACE
+
+/***************************************************************************/
+
+void daemonize()
+{
+ if (::getppid() == 1)
+ return; // Already a daemon if owned by init
+
+ int i = fork();
+ if (i < 0) exit(1); // Fork error
+ if (i > 0) exit(0); // Parent exits
+
+ ::setsid(); // Create a new process group
+
+ /*
+ for (i = ::getdtablesize() ; i > 0 ; i-- )
+ ::close(i); // Close all file descriptors
+ i = ::open("/dev/null", O_RDWR); // Stdin
+ ::dup(i); // stdout
+ ::dup(i); // stderr
+ */
+ ::close(0);
+ ::open("/dev/null", O_RDONLY); // Stdin
+
+// ::umask(027);
+ // ::chdir("/foo");
+
+ QString pidfile = QString("/var/run/%1.pid").arg(QFileInfo(progname).fileName());
+ int lfp = ::open(qPrintable(pidfile), O_RDWR|O_CREAT, 0640);
+ if (lfp<0)
+ qFatal("Cannot open pidfile %s\n", qPrintable(pidfile));
+ if (lockf(lfp, F_TLOCK, 0)<0)
+ qFatal("Can't get a lock on %s - another instance may be running\n", qPrintable(pidfile));
+ QByteArray ba = QByteArray::number(::getpid());
+ ::write(lfp, ba.constData(), ba.size());
+ ::close(lfp);
+
+ ::signal(SIGCHLD,SIG_IGN);
+ ::signal(SIGTSTP,SIG_IGN);
+ ::signal(SIGTTOU,SIG_IGN);
+ ::signal(SIGTTIN,SIG_IGN);
+}
+
+/***************************************************************************/
+
+using namespace std;
+
+static void usage()
+{
+ cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [FILENAME]" << endl
+ << endl
+#ifdef Q_OS_LINUX
+ << " -daemon Run as a daemon process" << endl
+#endif
+ << " -tcpPort port Specify a TCP port to listen on" << endl
+#ifndef QT_NO_DEBUG_OUTPUT
+ << " -debug" << endl
+ << " -debug-recovery" << endl
+#endif
+ << " -verbose" << endl
+ << " -clear Clear the database on startup" << endl
+ << " -performance-log Print timings of database operations" << endl
+ << " -pid pidfilename" << endl
+ << " -load file.json Load objects from a json file" << endl
+ << " -json" << endl
+ << " -reject-stale-updates" << endl
+ << " -validate-schemas Validate schemas of objects on create and update" << endl
+ << " -enforce-access-control " << endl
+ << " -limit megabytes" << endl
+ << endl
+ << "Arguments:" << endl
+ << " FILENAME If FILENAME not specified, use default in database.db in the current directory" << endl
+ << endl;
+ exit(0);
+}
+
+int main(int argc, char * argv[])
+{
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("jsondb");
+ QCoreApplication::setApplicationVersion("1.0");
+ QString arguments;
+ QStringList jsonFiles;
+ QString pidFileName;
+ quint16 port = 0;
+ bool clear = false;
+ rlim_t limit = 0;
+
+ QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+
+ progname = args.takeFirst();
+ while (args.size()) {
+ QString arg = args.at(0);
+ if (!arg.startsWith("-"))
+ break;
+ args.removeFirst();
+ if (arg == "-help") {
+ usage();
+ } else if (arg == "-tcpPort") {
+ if (!args.size())
+ usage();
+ port = args.takeFirst().toInt();
+ } else if (arg == "-limit") {
+ if (!args.size())
+ usage();
+ limit = args.takeFirst().toInt() * 1024*1024;
+ } else if (arg == "-pid") {
+ if (!args.size())
+ usage();
+ pidFileName = args.takeFirst();
+ } else if (arg == "-load") {
+ if (!args.size())
+ usage();
+ jsonFiles.append(args.takeFirst());
+#ifndef QT_NO_DEBUG_OUTPUT
+ } else if (arg == "-debug") {
+ gDebug = true;
+ } else if (arg == "-debug-recovery") {
+ gDebugRecovery = true;
+#endif
+#ifdef Q_OS_LINUX
+ } else if ( arg == "-daemon" ) {
+ daemonize();
+#endif
+ } else if (arg == "-validate-schemas") {
+ gValidateSchemas = true;
+ } else if (arg == "-no-validate-schemas") {
+ gValidateSchemas = false;
+ } else if (arg == "-reject-stale-updates") {
+ gRejectStaleUpdates = true;
+ } else if (arg == "-no-reject-stale-updates") {
+ gRejectStaleUpdates = false;
+ } else if (arg == "-enforce-access-control") {
+ gEnforceAccessControlPolicies = true;
+ } else if (arg == "-verbose") {
+ gVerbose = true;
+ } else if (arg == "-clear") {
+ clear = true;
+ } else if (arg == "-performance-log") {
+ gPerformanceLog = true;
+ } else {
+ cout << "Unknown argument " << qPrintable(arg) << endl << endl;
+ usage();
+ }
+ }
+
+ if (!pidFileName.isEmpty()) {
+ QFile pidFile(qPrintable(pidFileName));
+ pidFile.open(QIODevice::ReadWrite|QIODevice::Truncate);
+ QByteArray ba = QByteArray::number(::getpid());
+ pidFile.write(ba);
+ pidFile.close();
+ }
+
+ if (args.size() == 1)
+ arguments = args.takeFirst();
+ else if (!args.isEmpty())
+ usage();
+
+ DBServer server(arguments);
+ if (port)
+ server.setTcpServerPort(port);
+ Signals handler;
+ QObject::connect(&handler, SIGNAL(sigTerm()), &server, SLOT(sigTerm()));
+ QObject::connect(&handler, SIGNAL(sigHUP()), &server, SLOT(sigHUP()));
+ QObject::connect(&handler, SIGNAL(sigINT()), &server, SLOT(sigINT()));
+ handler.start();
+
+ if (limit) {
+ struct rlimit rlim;
+ getrlimit(RLIMIT_AS, &rlim);
+ qDebug() << "getrlimit" << "RLIMIT_DATA" << rlim.rlim_cur;
+ rlim.rlim_cur = limit;
+ rlim.rlim_max = limit;
+ int rc = setrlimit(RLIMIT_AS, &rlim);
+ if (rc)
+ qWarning() << "Failed to setrlimit" << errno;
+ }
+
+ if (clear)
+ server.clear();
+
+ if (!server.socket())
+ return -1;
+
+ cout << "Ready" << endl << flush;
+
+ if (!server.start())
+ return -2;
+
+ if (jsonFiles.size()) {
+ foreach (QString jsonFile, jsonFiles) {
+ server.load(jsonFile);
+ }
+ }
+ return app.exec();
+}
diff --git a/src/daemon/notification.cpp b/src/daemon/notification.cpp
new file mode 100644
index 00000000..f94fff78
--- /dev/null
+++ b/src/daemon/notification.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QList>
+#include <QMap>
+#include <QVariantList>
+#include <QString>
+
+#include "jsondb.h"
+#include "notification.h"
+
+#include "jsondb-strings.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+static QMap<QString,Notification*> sNotificationMap;
+
+Notification::Notification(const JsonDbOwner *owner, const QString &uuid, const QString& query, QStringList actions)
+ : mOwner(owner)
+ , mUuid(uuid)
+ , mQuery(query)
+ , mActions(None)
+{
+ foreach (QString s, actions) {
+ if (s == JsonDbString::kCreateStr)
+ mActions |= Create;
+ else if (s == JsonDbString::kUpdateStr)
+ mActions |= Update;
+ else if ((s == "delete") || (s == JsonDbString::kRemoveStr))
+ mActions |= Delete;
+ }
+}
+Notification::~Notification()
+{
+ if (mCompiledQuery) {
+ delete mCompiledQuery;
+ mCompiledQuery = 0;
+ }
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/notification.h b/src/daemon/notification.h
new file mode 100644
index 00000000..06f24197
--- /dev/null
+++ b/src/daemon/notification.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NOTIFICATION_H
+#define NOTIFICATION_H
+
+#include <QObject>
+#include <QJSValue>
+
+#include "jsondb-global.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+class JsonDbOwner;
+class JsonDbQuery;
+class Notification {
+public:
+ enum Action { None = 0x0000, Create = 0x0001, Update = 0x0002, Delete = 0x0004 };
+ Q_DECLARE_FLAGS(Actions, Action)
+
+ Notification(const JsonDbOwner *owner, const QString& uuid, const QString& query, QStringList actions);
+ ~Notification();
+
+ const JsonDbOwner *owner() const { return mOwner; }
+ const QString& uuid() const { return mUuid; }
+ const QString& query() const { return mQuery; }
+ Actions actions() const { return mActions; }
+ JsonDbQuery *parsedQuery() { return mCompiledQuery; }
+ void setCompiledQuery(JsonDbQuery *parsedQuery) { mCompiledQuery = parsedQuery; }
+
+private:
+
+ const JsonDbOwner *mOwner;
+ QString mUuid;
+ QString mQuery;
+ JsonDbQuery *mCompiledQuery;
+ Actions mActions;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QtAddOn::JsonDb::Notification::Actions)
+
+#endif
diff --git a/src/daemon/objectkey.h b/src/daemon/objectkey.h
new file mode 100644
index 00000000..32e17bd0
--- /dev/null
+++ b/src/daemon/objectkey.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECT_KEY_H
+#define OBJECT_KEY_H
+
+#include <qbytearray.h>
+#include <qendian.h>
+#include <qdebug.h>
+#include <quuid.h>
+
+#include "jsondb-global.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+class ObjectKey
+{
+public:
+ QUuid key; // object uuid
+
+ ObjectKey() {}
+ ObjectKey(const QUuid &uuid) : key(uuid) {}
+ ObjectKey(const QByteArray &uuid) : key(QUuid::fromRfc4122(uuid)) {}
+ inline bool isNull() const { return key.isNull(); }
+
+ inline QByteArray toByteArray() const
+ {
+ return key.toRfc4122();
+ }
+ inline bool operator==(const ObjectKey &rhs) const
+ { return key == rhs.key; }
+
+ inline bool operator < (const ObjectKey &rhs) const
+ { return key < rhs.key; }
+};
+
+inline QDebug &operator<<(QDebug &qdb, const ObjectKey &objectKey)
+{
+ qdb << objectKey.key.toString();
+ return qdb;
+}
+
+} } // end namespace QtAddOn::JsonDb
+
+template <> inline void qToBigEndian(QtAddOn::JsonDb::ObjectKey src, uchar *dest)
+{
+ //TODO: improve me
+ QByteArray key = src.key.toRfc4122();
+ memcpy(dest, key.constData(), key.size());
+}
+template <> inline QtAddOn::JsonDb::ObjectKey qFromBigEndian(const uchar *src)
+{
+ QtAddOn::JsonDb::ObjectKey key;
+ key.key = QUuid::fromRfc4122(QByteArray::fromRawData((const char *)src, 16));
+ return key;
+}
+
+#endif // OBJECT_KEY_H
diff --git a/src/daemon/objecttable.cpp b/src/daemon/objecttable.cpp
new file mode 100644
index 00000000..1edb3c2e
--- /dev/null
+++ b/src/daemon/objecttable.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QFileInfo>
+#include <QDir>
+
+#include <QtJsonDbQson/private/qson_p.h>
+#include <QtJsonDbQson/private/qsonparser_p.h>
+
+#include "jsondb-trace.h"
+#include "objecttable.h"
+#include "jsondb.h"
+#include "jsondbindex.h"
+#include "jsondb-strings.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+#ifndef QT_NO_DEBUG_OUTPUT
+extern bool gDebug;
+#define DBG() if (gDebug) qDebug() << Q_FUNC_INFO << __LINE__
+#else
+#define DBG() if (0) qDebug() << Q_FUNC_INFO
+#endif
+
+void makeStateKey(QByteArray &baStateKey, quint32 stateNumber)
+{
+ baStateKey.resize(5);
+ char *data = baStateKey.data();
+ data[4] = 'S';
+ qToBigEndian(stateNumber, (uchar *)baStateKey.data());
+}
+
+bool isStateKey(const QByteArray &baStateKey)
+{
+ return (baStateKey.size() == 5)
+ && (baStateKey.constData()[4] == 'S');
+}
+
+ObjectTable::ObjectTable(JsonDbBtreeStorage *storage)
+ : QObject(storage), mStorage(storage), mBdb(0), mInTransaction(false)
+{
+ mBdb = new AoDb();
+}
+
+ObjectTable::~ObjectTable()
+{
+ delete mBdb;
+ mBdb = 0;
+}
+
+bool ObjectTable::open(const QString&fileName, QFlags<AoDb::DbFlag> flags)
+{
+ mFilename = fileName;
+#if 0
+ if (!mBdb->setCmpFunc(objectKeyCmp, 0)) {
+ qCritical() << "mBdb->setCmpFunc" << mBdb->errorMessage();
+ return false;
+ }
+#endif
+ if (!mBdb->open(mFilename, flags)) {
+ qCritical() << "mBdb->open" << mBdb->errorMessage();
+ return false;
+ }
+ mStateNumber = mBdb->tag();
+ if (gDebugRecovery) qDebug() << "ObjectTable::open" << mStateNumber << mFilename;
+ return true;
+}
+
+void ObjectTable::close()
+{
+ mBdb->close();
+}
+
+bool ObjectTable::begin()
+{
+ Q_ASSERT(!mInTransaction);
+ mInTransaction = true;
+ bool ok = mBdb->begin();
+ Q_ASSERT(mBdbTransactions.isEmpty());
+ return ok;
+}
+
+bool ObjectTable::commit(quint32 tag)
+{
+ Q_ASSERT(mInTransaction);
+ //qDebug() << "ObjectTable::commit" << tag << mFilename;
+
+ QByteArray baStateKey(5, 0);
+ makeStateKey(baStateKey, tag);
+ bool ok = mBdb->put(baStateKey, mStateChanges);
+ if (!ok)
+ qDebug() << "putting statekey ok" << ok << "baStateKey" << baStateKey.toHex();
+ for (int i = 0; i < mStateObjectChanges.size(); ++i) {
+ QsonMap object = mStateObjectChanges.at(i);
+ bool ok = mBdb->put(baStateKey + object.uuid().toRfc4122(), object.data());
+ if (!ok) {
+ qDebug() << "putting state object ok" << ok << "baStateKey" << baStateKey.toHex()
+ << "object" << object;
+ }
+ }
+ mStateChanges.clear();
+ mStateObjectChanges.clear();
+ mStateNumber = tag;
+
+ bool ret = true;
+ for (int i = 0; i < mBdbTransactions.size(); i++) {
+ AoDb *bdb = mBdbTransactions.at(i);
+ if (!bdb->commit(tag)) {
+ qCritical() << __FILE__ << __LINE__ << bdb->errorMessage();
+ ret = false;
+ }
+ }
+ mBdbTransactions.clear();
+ mInTransaction = false;
+ return mBdb->commit(tag);
+}
+
+bool ObjectTable::abort()
+{
+ Q_ASSERT(mInTransaction);
+ mStateChanges.clear();
+ mStateObjectChanges.clear();
+ bool ret = true;
+ for (int i = 0; i < mBdbTransactions.size(); i++) {
+ AoDb *bdb = mBdbTransactions.at(i);
+ if (!bdb->abort()) {
+ qCritical() << __FILE__ << __LINE__ << bdb->errorMessage();
+ ret = false;
+ }
+ }
+ mBdbTransactions.clear();
+ mInTransaction = false;
+ return mBdb->abort();
+}
+
+bool ObjectTable::compact()
+{
+ for (QHash<QString,IndexSpec>::const_iterator it = mIndexes.begin();
+ it != mIndexes.end();
+ ++it) {
+ const IndexSpec &indexSpec = it.value();
+ if (!indexSpec.index->bdb()->compact())
+ return false;
+ }
+ return mBdb->compact();
+}
+
+IndexSpec *ObjectTable::indexSpec(const QString &fieldName)
+{
+ //qDebug() << "ObjectTable::indexSpec" << fieldName << mFilename << (mIndexes.contains(fieldName) ? "exists" : "missing") << (long)this << mIndexes.keys();
+ if (mIndexes.contains(fieldName))
+ return &mIndexes[fieldName];
+ else
+ return 0;
+}
+
+QsonObject ObjectTable::addIndex(const QString &fieldname, const QString &fieldType, const QString &objectType, bool lazy)
+{
+ //qDebug() << "ObjectTable::addIndex" << fieldname << mFilename << (mIndexes.contains(fieldname) ? "exists" : "to be created");
+ if (mIndexes.contains(fieldname))
+ return QsonObject();
+
+ //if (gVerbose) qDebug() << "ObjectTable::addIndex" << fieldname << mFilename;
+
+ QStringList path = fieldname.split('.');
+
+ IndexSpec &indexSpec = mIndexes[fieldname];
+ indexSpec.fieldName = fieldname;
+ indexSpec.path = path;
+ indexSpec.fieldType = fieldType;
+ indexSpec.objectType = objectType;
+ indexSpec.lazy = false; //lazy;
+ indexSpec.index = new JsonDbIndex(mFilename, fieldname, this);
+ indexSpec.index->open();
+
+ QsonMap indexObject;
+ indexObject.insert(JsonDbString::kTypeStr, kIndexTypeStr);
+ indexObject.insert(kFieldStr, fieldname);
+ indexObject.insert(kFieldTypeStr, fieldType);
+ indexObject.insert(kObjectTypeStr, objectType);
+ indexObject.insert("lazy", lazy);
+ Q_ASSERT(mIndexes.contains(fieldname));
+
+ QByteArray baIndexObject;
+ bool needsReindexing = false;
+ if (!mStorage->mBdbIndexes->get(fieldname.toLatin1(), baIndexObject)) {
+ baIndexObject = indexObject.data();
+ bool ok = mStorage->mBdbIndexes->put(fieldname.toLatin1(), baIndexObject);
+ if (gDebugRecovery) qDebug() << "Index" << fieldname << "is new" << "reindexing";
+ needsReindexing = true;
+ Q_ASSERT(ok);
+ } else if (fieldname == JsonDbString::kUuidStr) {
+ // nothing more to do
+ return QsonObject();
+ } else if (indexSpec.index->stateNumber() != mStateNumber) {
+ needsReindexing = true;
+ if (gDebugRecovery) qDebug() << "Index" << fieldname << "stateNumber" << indexSpec.index->stateNumber() << "objectTable.stateNumber" << mStateNumber << "reindexing" << "clearing";
+ indexSpec.index->clear();
+ }
+ if (needsReindexing)
+ reindexObjects(fieldname, path, stateNumber());
+
+ return QsonObject();
+}
+
+void ObjectTable::reindexObjects(const QString &fieldName, const QStringList &path, quint32 stateNumber, bool inTransaction)
+{
+ if (gDebugRecovery) qDebug() << "reindexObjects" << fieldName << "{";
+ if (fieldName == JsonDbString::kUuidStr) {
+ qCritical() << "} ObjectTable::reindexObject" << "no need to reindex _uuid";
+ return;
+ }
+
+ IndexSpec &indexSpec = mIndexes[fieldName];
+ JsonDbIndex *index = indexSpec.index;
+
+ AoDbCursor cursor(mBdb);
+ if (!inTransaction)
+ index->begin();
+ for (bool ok = cursor.first(); ok; ok = cursor.next()) {
+ QByteArray baKey, baObject;
+ bool ok = cursor.current(baKey, baObject);
+ Q_ASSERT(ok);
+ if (isStateKey(baKey))
+ continue;
+ ObjectKey objectKey(baKey);
+ QsonMap object = QsonParser::fromRawData(baObject);
+ if (object.valueBool(JsonDbString::kDeletedStr, false))
+ continue;
+ QVariant fieldValue = JsonDb::propertyLookup(object, path);
+ if (fieldValue.isValid()) {
+ index->indexObject(objectKey, object, stateNumber, true);
+ }
+ }
+ if (!inTransaction)
+ index->commit(stateNumber);
+ if (gDebugRecovery) qDebug() << "} reindexObjects";
+}
+
+void ObjectTable::indexObject(const ObjectKey &objectKey, QsonMap object, quint32 stateNumber)
+{
+ if (gDebug) qDebug() << "ObjectTable::indexObject" << objectKey << object.valueString(JsonDbString::kVersionStr) << endl << mIndexes.keys();
+ for (QHash<QString,IndexSpec>::const_iterator it = mIndexes.begin();
+ it != mIndexes.end();
+ ++it) {
+ Q_ASSERT(mInTransaction);
+ const IndexSpec &indexSpec = it.value();
+ if (indexSpec.fieldName == JsonDbString::kUuidStr)
+ continue;
+ if (indexSpec.lazy)
+ continue;
+ if (!mBdbTransactions.contains(indexSpec.index->bdb())) {
+ indexSpec.index->begin();
+ mBdbTransactions.append(indexSpec.index->bdb());
+ }
+ indexSpec.index->indexObject(objectKey, object, stateNumber, true);
+ }
+}
+
+void ObjectTable::deindexObject(const ObjectKey &objectKey, QsonMap object, quint32 stateNumber)
+{
+ if (gDebug) qDebug() << "ObjectTable::deindexObject" << objectKey << object.valueString(JsonDbString::kVersionStr) << endl << mIndexes.keys();
+
+ for (QHash<QString,IndexSpec>::const_iterator it = mIndexes.begin();
+ it != mIndexes.end();
+ ++it) {
+ const IndexSpec &indexSpec = it.value();
+ if (gDebug) qDebug() << "ObjectTable::deindexObject" << indexSpec.fieldName;
+ if (indexSpec.fieldName == JsonDbString::kUuidStr)
+ continue;
+ if (indexSpec.lazy)
+ continue;
+ Q_ASSERT(mInTransaction);
+ if (!mBdbTransactions.contains(indexSpec.index->bdb())) {
+ indexSpec.index->begin();
+ mBdbTransactions.append(indexSpec.index->bdb());
+ }
+ indexSpec.index->deindexObject(objectKey, object, stateNumber, true);
+ }
+}
+
+void ObjectTable::updateIndex(JsonDbIndex *index)
+{
+ quint32 indexStateNumber = qMax(1u, index->bdb()->tag());
+ if (indexStateNumber == stateNumber())
+ return;
+ QsonMap changes = changesSince(indexStateNumber).subObject("result");
+ quint32 count = changes.valueInt("count", 0);
+ QsonList changeList = changes.subList("changes");
+ if (!mInTransaction)
+ index->begin();
+ else if (!mBdbTransactions.contains(index->bdb())) {
+ index->begin();
+ mBdbTransactions.append(index->bdb());
+ }
+ for (quint32 i = 0; i < count; i++) {
+ QsonMap change = changeList.objectAt(i).toMap();
+ QsonMap before = change.subObject("before").toMap();
+ QsonMap after = change.subObject("after").toMap();
+ ObjectKey objectKey(after.uuid());
+ if (!before.isEmpty())
+ index->deindexObject(objectKey, before, stateNumber(), true);
+ if (!after.isEmpty())
+ index->indexObject(objectKey, after, stateNumber(), true);
+ }
+ if (!mInTransaction)
+ index->commit(stateNumber());
+}
+
+
+bool ObjectTable::get(const ObjectKey &objectKey, QsonObject &object)
+{
+ QByteArray baObjectKey(objectKey.toByteArray());
+ QByteArray baObject;
+ bool ok = mBdb->get(baObjectKey, baObject);
+ if (!ok)
+ return false;
+ object = QsonParser::fromRawData(baObject);
+ return true;
+}
+
+bool ObjectTable::put(const ObjectKey &objectKey, QsonObject &object)
+{
+ QByteArray baObjectKey(objectKey.toByteArray());
+ return mBdb->put(baObjectKey, object.data());
+}
+
+bool ObjectTable::remove(const ObjectKey &objectKey)
+{
+ QByteArray baObjectKey(objectKey.toByteArray());
+ return mBdb->remove(baObjectKey);
+}
+
+QString ObjectTable::errorMessage() const
+{
+ return mBdb->errorMessage();
+}
+
+QsonMap ObjectTable::lookupObject(const ObjectKey &objectKey) const
+{
+ //serializedKey.append(version);
+ QByteArray baObjectKey(objectKey.toByteArray());
+
+ QByteArray baObject;
+ bool ok = mBdb->get(baObjectKey, baObject);
+ if (ok) {
+ QsonMap map = QsonParser::fromRawData(baObject).toMap();
+ if (map.valueBool(JsonDbString::kDeletedStr, false))
+ return QsonMap();
+ else
+ return map;
+ } else {
+ return QsonMap();
+ }
+}
+
+QsonMap ObjectTable::getObject(const QString &keyName, const QVariant &keyValue, const QString &objectType)
+{
+ QsonMap resultmap;
+ QsonList objectList;
+ bool typeSpecified = !objectType.isEmpty();
+
+ if (keyName == JsonDbString::kUuidStr) {
+ ObjectKey objectKey(keyValue.toString());
+ QsonList objectList;
+ QsonObject object = lookupObject(objectKey);
+ if (!object.isEmpty())
+ objectList.append(object);
+ resultmap.insert(QByteArray("result"), objectList);
+ resultmap.insert(JsonDbString::kCountStr, objectList.size());
+ return resultmap;
+ }
+
+ if (!mIndexes.contains(keyName)) {
+ qDebug() << "ObjectTable::getObject" << "no index for" << keyName << mFilename;
+ resultmap.insert(JsonDbString::kCountStr, 0);
+ return resultmap;
+ }
+ const IndexSpec *indexSpec = &mIndexes[keyName];
+ QByteArray forwardKey(makeForwardKey(keyValue, ObjectKey()));
+ //fprintf(stderr, "getObject bdb=%p\n", indexSpec->index->bdb());
+ if (indexSpec->lazy)
+ updateIndex(indexSpec->index);
+ AoDbCursor cursor(indexSpec->index->bdb());
+ if (cursor.seekRange(forwardKey)) {
+ do {
+ QByteArray serializedObject;
+ QByteArray checkKey;
+ QByteArray forwardValue;
+ bool ok = cursor.current(checkKey, forwardValue);
+ QVariant checkValue;
+ forwardKeySplit(checkKey, checkValue);
+ if (checkValue != keyValue)
+ break;
+
+ ObjectKey objectKey;
+ forwardValueSplit(forwardValue, objectKey);
+ DBG() << "ok" << ok << "forwardValue" << forwardValue << "objectKey" << objectKey;
+
+ QsonObject object;
+ if (get(objectKey, object)) {
+ QsonMap map = object.toMap();
+ //qDebug() << "ObjectTable::getObject" << "deleted" << map.valueBool(JsonDbString::kDeletedStr, false);
+ if (map.contains(JsonDbString::kDeletedStr) && map.valueBool(JsonDbString::kDeletedStr, false))
+ continue;
+ if (typeSpecified && (object.toMap().valueString(JsonDbString::kTypeStr) != objectType))
+ continue;
+
+ objectList.append(object);
+ } else {
+ DBG() << "Failed to get object" << objectKey << errorMessage();
+ }
+ } while (cursor.next());
+ }
+
+ resultmap.insert(QByteArray("result"), objectList);
+ resultmap.insert(JsonDbString::kCountStr, objectList.size());
+ return resultmap;
+}
+
+quint32 ObjectTable::storeStateChange(const ObjectKey &key, ObjectChange::Action action, const QsonMap &oldObject)
+{
+ quint32 stateNumber = mStateNumber + 1;
+
+ int oldSize = mStateChanges.size();
+ mStateChanges.resize(oldSize + 20);
+ uchar *data = (uchar *)mStateChanges.data() + oldSize;
+
+ qToBigEndian(key, data);
+ qToBigEndian<quint32>(action, data+16);
+ if (!oldObject.isEmpty())
+ mStateObjectChanges.append(oldObject);
+ return stateNumber;
+}
+
+quint32 ObjectTable::storeStateChange(const QList<ObjectChange> &changes)
+{
+ quint32 stateNumber = mStateNumber + 1;
+ int oldSize = mStateChanges.size();
+ mStateChanges.resize(oldSize + changes.size() * 20);
+ uchar *data = (uchar *)mStateChanges.data() + oldSize;
+ foreach (const ObjectChange &change, changes) {
+ qToBigEndian(change.object, data);
+ qToBigEndian<quint32>(change.action, data+16);
+ data += 20;
+ if (!change.oldObject.isEmpty())
+ mStateObjectChanges.append(change.oldObject);
+ }
+ return stateNumber;
+}
+
+void ObjectTable::changesSince(quint32 stateNumber, QMap<quint32, QList<ObjectChange> > *changes)
+{
+ if (!changes)
+ return;
+ stateNumber = qMax(quint32(1), stateNumber+1);
+
+ AoDbCursor cursor(mBdb);
+ QByteArray baStateKey(5, 0);
+ makeStateKey(baStateKey, stateNumber);
+
+ if (cursor.seekRange(baStateKey)) {
+ do {
+ QByteArray baObject;
+ bool ok = cursor.current(baStateKey, baObject);
+ if (!ok)
+ break;
+
+ if (!isStateKey(baStateKey))
+ continue;
+ stateNumber = qFromBigEndian<quint32>((const uchar *)baStateKey.constData());
+
+ if (baObject.size() % 20 != 0) {
+ qWarning() << __FUNCTION__ << __LINE__ << "state size must be a multiplier 20"
+ << baObject.size() << baObject.toHex();
+ continue;
+ }
+
+ QList<ObjectChange> ch;
+ for (int i = 0; i < baObject.size() / 20; ++i) {
+ const uchar *data = (const uchar *)baObject.constData() + i*20;
+ ObjectKey objectKey = qFromBigEndian<ObjectKey>(data);
+ quint32 action = qFromBigEndian<quint32>(data + 16);
+ Q_ASSERT(action <= ObjectChange::LastAction);
+ QByteArray baValue;
+ QsonMap oldObject;
+ if (mBdb->get(baStateKey + objectKey.key.toRfc4122(), baValue)) {
+ oldObject = QsonParser::fromRawData(baValue);
+ Q_ASSERT(objectKey == ObjectKey(oldObject.uuid()));
+ }
+ ch.append(ObjectChange(objectKey, ObjectChange::Action(action), oldObject));
+ }
+ if (changes)
+ changes->insert(stateNumber, ch);
+ } while (cursor.next());
+ }
+}
+
+QsonMap ObjectTable::changesSince(quint32 stateNumber, const QSet<QString> &limitTypes)
+{
+ if (gVerbose)
+ qDebug() << "changesSince" << stateNumber << "current state" << this->stateNumber();
+
+ QsonList result;
+ int count = 0;
+
+ QMap<quint32, QList<ObjectChange> > changes;
+ changesSince(stateNumber, &changes);
+
+ QMap<quint32, QList<ObjectChange> >::const_iterator it, e;
+ for (it = changes.begin(), e = changes.end(); it != e; ++it) {
+ const QList<ObjectChange> &changes = it.value();
+ for (int i = 0; i < changes.size(); ++i) {
+ const ObjectChange &change = changes.at(i);
+ QsonMap before;
+ QsonMap after;
+ switch (change.action) {
+ case ObjectChange::Created:
+ after = lookupObject(change.object);
+ break;
+ case ObjectChange::Updated:
+ before = change.oldObject;
+ after = lookupObject(change.object);
+ break;
+ case ObjectChange::Deleted:
+ before = change.oldObject;
+ break;
+ }
+ if (!limitTypes.isEmpty()) {
+ QString type = (after.isEmpty() ? before : after).valueString(JsonDbString::kTypeStr);
+ if (!limitTypes.contains(type))
+ continue;
+ }
+ QsonMap res;
+ res.insert("before", before);
+ res.insert("after", after);
+ result.append(res);
+ ++count;
+ }
+ }
+ QsonMap resultmap, errormap;
+ resultmap.insert("count", count);
+ resultmap.insert("startingStateNumber", stateNumber);
+ resultmap.insert("currentStateNumber", this->stateNumber());
+ resultmap.insert("changes", result);
+ return JsonDb::makeResponse(resultmap, errormap);
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/daemon/objecttable.h b/src/daemon/objecttable.h
new file mode 100644
index 00000000..b1715ca8
--- /dev/null
+++ b/src/daemon/objecttable.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECT_TABLE_H
+#define OBJECT_TABLE_H
+
+#include <QObject>
+#include <QHash>
+#include <QList>
+#include <QPair>
+#include <QtEndian>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "aodb.h"
+
+#include "objectkey.h"
+
+class AoDb;
+
+namespace QtAddOn { namespace JsonDb {
+
+class IndexSpec;
+class JsonDbBtreeStorage;
+class JsonDbIndex;
+
+struct ObjectChange
+{
+ ObjectKey object;
+ enum Action {
+ Created,
+ Updated,
+ Deleted,
+ LastAction = Deleted
+ } action;
+ QsonMap oldObject;
+
+ inline ObjectChange(const ObjectKey &obj, Action act, const QsonMap &old = QsonMap())
+ : object(obj), action(act), oldObject(old)
+ {
+ }
+};
+
+inline QDebug &operator<<(QDebug &qdb, const ObjectChange &oc)
+{
+ qdb.nospace() << "ObjectChange(";
+ qdb.nospace() << oc.object;
+ qdb.nospace() << ", action = ";
+ switch (oc.action) {
+ case ObjectChange::Created: qdb.nospace() << "Created"; break;
+ case ObjectChange::Updated: qdb.nospace() << "Updated"; break;
+ case ObjectChange::Deleted: qdb.nospace() << "Deleted"; break;
+ }
+ if (oc.action != ObjectChange::Created)
+ qdb.nospace() << ", oldObject = " << oc.oldObject;
+ qdb.nospace() << ")";
+ return qdb;
+}
+
+
+class ObjectTable : public QObject
+{
+ Q_OBJECT
+public:
+ ObjectTable(JsonDbBtreeStorage *parent=0);
+ ~ObjectTable();
+
+ QString filename() const { return mFilename; }
+ bool open(const QString &filename, AoDb::DbFlags flags);
+ void close();
+ AoDb *bdb() const { return mBdb; }
+ bool begin();
+ bool commit(quint32);
+ bool abort();
+ bool compact();
+
+ quint32 stateNumber() const { return mStateNumber; }
+ quint32 storeStateChange(const ObjectKey &key1, ObjectChange::Action action, const QsonMap &old = QsonMap());
+ quint32 storeStateChange(const QList<ObjectChange> &stateChange);
+ void changesSince(quint32 stateNumber, QMap<quint32, QList<ObjectChange> > *changes);
+ QsonMap changesSince(quint32 stateNumber, const QSet<QString> &limitTypes = QSet<QString>());
+
+ IndexSpec *indexSpec(const QString &fieldName);
+ QsonObject addIndex(const QString &fieldName,
+ const QString &fieldType = QString("string"),
+ const QString &objectType = QString(),
+ bool lazy=true);
+ void reindexObjects(const QString &fieldName, const QStringList &path, quint32 stateNumber, bool inTransaction = false);
+ void indexObject(const ObjectKey & objectKey, QsonMap object, quint32 stateNumber);
+ void deindexObject(const ObjectKey &objectKey, QsonMap object, quint32 stateNumber);
+ void updateIndex(JsonDbIndex *index);
+
+ bool get(const ObjectKey &objectKey, QsonObject &object);
+ bool put(const ObjectKey &objectKey, QsonObject &object);
+ bool remove(const ObjectKey &objectKey);
+
+ QString errorMessage() const;
+
+ QsonMap lookupObject(const ObjectKey & objectKey) const;
+ QsonMap getObject(const QString &keyName, const QVariant &keyValue, const QString &objectType);
+
+
+private:
+ JsonDbBtreeStorage *mStorage;
+ QString mFilename;
+ AoDb *mBdb;
+ QHash<QString,IndexSpec> mIndexes; // indexed by full path, e.g., _type or _name.first
+ QVector<AoDb *> mBdbTransactions;
+ bool mInTransaction;
+
+ quint32 mStateNumber;
+
+ // intermediate state changes until the commit is called
+ QByteArray mStateChanges;
+ QList<QsonMap> mStateObjectChanges;
+};
+
+void makeStateKey(QByteArray &baStateKey, quint32 stateNumber);
+bool isStateKey(const QByteArray &baStateKey);
+
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif
diff --git a/src/daemon/qsonobjecttypes_impl_p.h b/src/daemon/qsonobjecttypes_impl_p.h
new file mode 100644
index 00000000..adbba4f8
--- /dev/null
+++ b/src/daemon/qsonobjecttypes_impl_p.h
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONOBJECTTYPES_IMPL_P_H
+#define QSONOBJECTTYPES_IMPL_P_H
+
+#include "jsondb-global.h"
+#include "qsonobjecttypes_p.h"
+#include "schemamanager_p.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+inline QsonObjectTypes::ValueList::ValueList(const QsonList list) : QsonList(list)
+{}
+
+inline uint QsonObjectTypes::ValueList::count() const
+{
+ return QsonList::count();
+}
+
+inline QsonObjectTypes::ValueList::const_iterator QsonObjectTypes::ValueList::constBegin() const
+{
+ return const_iterator(0, this);
+}
+
+inline QsonObjectTypes::ValueList::const_iterator QsonObjectTypes::ValueList::constEnd() const
+{
+ return const_iterator(count(), this);
+}
+
+inline QsonObjectTypes::ValueList::const_iterator::const_iterator()
+ : m_index(-1)
+ , m_list(0)
+{}
+
+inline QsonObjectTypes::Value QsonObjectTypes::ValueList::const_iterator::operator *() const
+{
+ Q_ASSERT(isValid());
+ return Value(m_index, *m_list);
+}
+
+inline bool QsonObjectTypes::ValueList::const_iterator::operator !=(const const_iterator &other) const
+{
+ return m_index != other.m_index || m_list != other.m_list;
+}
+
+inline QsonObjectTypes::ValueList::const_iterator& QsonObjectTypes::ValueList::const_iterator::operator ++()
+{
+ m_index++;
+ return *this;
+}
+
+inline QsonObjectTypes::ValueList::const_iterator::const_iterator(int begin, const QsonList *list)
+ : m_index(begin)
+ , m_list(list)
+{}
+
+inline bool QsonObjectTypes::ValueList::const_iterator::isValid() const
+{
+ return m_index != -1 && m_index < m_list->count();
+}
+
+inline QsonObjectTypes::Value::Value(Key propertyName, const QsonMap &map)
+ : m_index(-1)
+ , m_property(propertyName)
+ , m_object(map)
+ , m_type(propertyName.isEmpty() ? RootMap : Map)
+{}
+
+inline QsonObjectTypes::Value::Value(const int index, const QsonList &list)
+ : m_index(index)
+ , m_object(list)
+ , m_type(List)
+{}
+
+inline int QsonObjectTypes::Value::toInt(bool *ok) const
+{
+ if (m_intCache.isValid()) {
+ *ok = true;
+ return m_intCache.value();
+ }
+ int result;
+ QsonObject::Type type;
+ switch (m_type) {
+ case Map:
+ type = typeMap();
+ *ok = type == QsonObject::IntType || type == QsonObject::UIntType;
+ result = map()->valueInt(m_property);
+ m_intCache.set(*ok, result);
+ return result;
+ case List:
+ type = typeList();
+ *ok = type == QsonObject::IntType || type == QsonObject::UIntType;
+ result = list()->intAt(m_index);
+ m_intCache.set(*ok, result);
+ return result;
+ case RootMap:
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+ return -1;
+}
+
+inline double QsonObjectTypes::Value::toDouble(bool *ok) const
+{
+ if (m_doubleCache.isValid()) {
+ *ok = true;
+ return m_doubleCache.value();
+ }
+ double result;
+ QsonObject::Type type;
+ switch (m_type) {
+ case Map:
+ type = typeMap();
+ *ok = type == QsonObject::DoubleType
+ || type == QsonObject::IntType
+ || type == QsonObject::UIntType;
+ result = map()->valueDouble(m_property);
+ m_doubleCache.set(*ok, result);
+ return result;
+ case List:
+ type = typeList();
+ *ok = type == QsonObject::DoubleType
+ || type == QsonObject::IntType
+ || type == QsonObject::UIntType;
+ result = list()->doubleAt(m_index);
+ m_doubleCache.set(*ok, result);
+ return result;
+ case RootMap:
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+ return -1;
+}
+
+inline QsonObjectTypes::ValueList QsonObjectTypes::Value::toList(bool *ok) const
+{
+ *ok = true;
+ switch (m_type) {
+ case Map:
+ return map()->subList(m_property);
+ case List:
+ return list()->listAt(m_index);
+ case RootMap:
+ return m_object.toList();
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+ return ValueList(QsonList());
+}
+
+inline QString QsonObjectTypes::Value::toString(bool *ok) const
+{
+ switch (m_type) {
+ case Map:
+ *ok = typeMap() == QsonObject::StringType;
+ return map()->valueString(m_property);
+ case List:
+ *ok = typeList() == QsonObject::StringType;
+ return list()->stringAt(m_index);
+ case RootMap:
+ *ok = true;
+ return QString(); // useful for debugging
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+ return QString();
+}
+
+inline bool QsonObjectTypes::Value::toBoolean(bool *ok) const
+{
+ switch (m_type) {
+ case Map:
+ *ok = typeMap() == QsonObject::BoolType;
+ return map()->valueBool(m_property);
+ case List:
+ *ok = typeList() == QsonObject::BoolType;
+ return list()->boolAt(m_index);
+ case RootMap:
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+ return false;
+}
+
+inline void QsonObjectTypes::Value::toNull(bool *ok) const
+{
+ switch (m_type) {
+ case Map:
+ *ok = typeMap() == QsonObject::NullType;
+ case List:
+ *ok = typeList() == QsonObject::NullType;
+ case RootMap:
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+}
+
+inline QsonObjectTypes::Object QsonObjectTypes::Value::toObject(bool *ok) const
+{
+ switch (m_type) {
+ case Map:
+ *ok = typeMap() == QsonObject::MapType;
+ return map()->subObject(m_property);
+ case List:
+ *ok = typeList() == QsonObject::MapType;
+ return list()->objectAt(m_index);
+ case RootMap:
+ *ok = true;
+ Q_ASSERT_X(sizeof(Object) == sizeof(m_object), Q_FUNC_INFO, "We are assuming that Object and QsonObject has the same binary representation");
+ return static_cast<Object>(m_object);
+ default:
+ Q_ASSERT(false);
+ }
+ *ok = false;
+ return Object(QsonMap());
+}
+
+inline const QsonMap *QsonObjectTypes::Value::map() const
+{
+ Q_ASSERT(m_type == Map);
+ Q_ASSERT(!m_property.isEmpty());
+ Q_ASSERT_X(sizeof(QsonMap) == sizeof(m_object), Q_FUNC_INFO, "We are assuming that QsonMap and QsonObject has the same binary representation");
+ return static_cast<const QsonMap*>(&m_object);
+}
+
+inline const QsonList *QsonObjectTypes::Value::list() const
+{
+ Q_ASSERT(m_type == List);
+ Q_ASSERT(m_index >= 0);
+ Q_ASSERT_X(sizeof(QsonList) == sizeof(m_object), Q_FUNC_INFO, "We are assuming that QsonList and QsonObject has the same binary representation");
+ return static_cast<const QsonList*>(&m_object);
+}
+
+inline QsonObject::Type QsonObjectTypes::Value::typeMap() const
+{
+ if (m_qsonTypeCache.isValid())
+ return m_qsonTypeCache.value();
+ QsonObject::Type result = map()->valueType(m_property);
+ m_qsonTypeCache.set(true, result);
+ return result;
+}
+
+inline QsonObject::Type QsonObjectTypes::Value::typeList() const
+{
+ if (m_qsonTypeCache.isValid())
+ return m_qsonTypeCache.value();
+ QsonObject::Type result = list()->typeAt(m_index);
+ m_qsonTypeCache.set(true, result);
+ return result;
+}
+
+inline QsonObjectTypes::Object::Object()
+{}
+
+inline QsonObjectTypes::Object::Object(const QsonMap &map)
+ : QsonMap(map)
+{}
+
+inline QsonObjectTypes::Value QsonObjectTypes::Object::property(const QsonObjectTypes::Key& name) const
+{
+ return Value(name, *this);
+}
+
+inline QList<QsonObjectTypes::Key> QsonObjectTypes::Object::propertyNames() const { return QsonMap::keys(); }
+
+inline QsonObjectTypes::Service::Service(SchemaManager *schemas)
+ : m_schemas(schemas)
+{}
+
+inline QsonMap QsonObjectTypes::Service::error() const
+{
+ return m_errorMap;
+}
+
+inline void QsonObjectTypes::Service::setError(const QString &message)
+{
+ m_errorMap.insert(JsonDbString::kCodeStr, JsonDbError::FailedSchemaValidation);
+ m_errorMap.insert(JsonDbString::kMessageStr, message);
+}
+
+inline SchemaValidation::Schema<QsonObjectTypes> QsonObjectTypes::Service::loadSchema(const QString &schemaName)
+{
+ return m_schemas->schema(schemaName, this);
+}
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONOBJECTTYPES_IMPL_P_H
diff --git a/src/daemon/qsonobjecttypes_p.h b/src/daemon/qsonobjecttypes_p.h
new file mode 100644
index 00000000..25fa4bca
--- /dev/null
+++ b/src/daemon/qsonobjecttypes_p.h
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONOBJECTTYPES_P_H
+#define QSONOBJECTTYPES_P_H
+
+#include "jsondb-global.h"
+
+#include "jsondb-strings.h"
+#include <QtJsonDbQson/private/qsonmap_p.h>
+#include <QtJsonDbQson/private/qsonlist_p.h>
+#include <QtJsonDbQson/private/qsonobject_p.h>
+
+#include "schema-validation/object.h"
+
+#include <QPair>
+
+namespace QtAddOn { namespace JsonDb {
+
+class SchemaManager;
+
+/**
+ \internal
+ This is type definition for schema validation framework. It was created because of planed change
+ of data representation in jsondb (Bson -> Qson). Essentially schema validation is independent from
+ data representation. The performance cost of this indirection is about 0. We can consider removing
+ it in future or leave it and check different data representation (think about QJSValue).
+
+ These types define the simplest types in JSON.
+ */
+class QsonObjectTypes {
+public:
+ typedef QString Key;
+
+ class Value;
+ class ValueList : protected QsonList
+ {
+ public:
+ inline ValueList(const QsonList list);
+
+ // interface
+ class const_iterator;
+ inline uint count() const;
+ inline const_iterator constBegin() const;
+ inline const_iterator constEnd() const;
+ class const_iterator
+ {
+ friend class ValueList;
+ public:
+ inline const_iterator();
+ inline Value operator *() const;
+ inline bool operator !=(const const_iterator &other) const;
+ inline const_iterator& operator ++();
+
+ private:
+ inline const_iterator(int begin, const QsonList *list);
+ inline bool isValid() const;
+
+ int m_index;
+ const QsonList *m_list;
+ };
+ };
+
+ class Object;
+ class Value
+ {
+ enum Type {List, Map, RootMap};
+
+ template<class T>
+ class Cache : protected QPair<bool, T>
+ {
+ public:
+ Cache()
+ : QPair<bool, T>(false, T())
+ {}
+ bool isValid() const { return QPair<bool, T>::first; }
+ T value() const { Q_ASSERT(isValid()); return QPair<bool, T>::second; }
+ void set(const bool ok, const T &value) { QPair<bool, T>::first = ok; QPair<bool, T>::second = value; }
+ };
+
+ public:
+ inline Value(Key propertyName, const QsonMap &map);
+ inline Value(const int index, const QsonList &list);
+
+ // interface
+ inline int toInt(bool *ok) const;
+ inline double toDouble(bool *ok) const;
+ inline ValueList toList(bool *ok) const;
+ inline QString toString(bool *ok) const;
+ inline bool toBoolean(bool *ok) const;
+ inline void toNull(bool *ok) const;
+ inline Object toObject(bool *ok) const;
+
+ private:
+ inline const QsonMap *map() const;
+ inline const QsonList *list() const;
+ inline QsonObject::Type typeMap() const;
+ inline QsonObject::Type typeList() const;
+
+ const int m_index;
+ const Key m_property;
+
+ const QsonObject m_object;
+ const Type m_type;
+
+ mutable Cache<QsonObject::Type> m_qsonTypeCache;
+ mutable Cache<int> m_intCache;
+ mutable Cache<double> m_doubleCache;
+ };
+
+ class Object : public QsonMap
+ {
+ public:
+ inline Object(const QsonMap &map);
+
+ // interface
+ inline Object();
+ inline Value property(const Key& name) const;
+ inline QList<Key> propertyNames() const;
+ };
+
+ class Service {
+ public:
+ inline Service(SchemaManager *schemas);
+ inline QsonMap error() const;
+
+ // interface
+ inline void setError(const QString &message);
+ inline SchemaValidation::Schema<QsonObjectTypes> loadSchema(const QString &schemaName);
+
+ private:
+ SchemaManager *m_schemas;
+ QsonMap m_errorMap;
+ };
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONOBJECTTYPES_P_H
diff --git a/src/daemon/schema-validation/checkpoints.h b/src/daemon/schema-validation/checkpoints.h
new file mode 100644
index 00000000..7a9611c0
--- /dev/null
+++ b/src/daemon/schema-validation/checkpoints.h
@@ -0,0 +1,832 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qregexp.h>
+#include "object.h"
+
+#ifndef CHECKPOINTS_H
+#define CHECKPOINTS_H
+
+namespace SchemaValidation {
+
+/**
+ \internal
+ This template is used for hash computation for static latin1 strings.
+ */
+template<ushort C1 = 0, ushort C2 = 0, ushort C3 = 0, ushort C4 = 0, ushort C5 = 0,
+ ushort C6 = 0, ushort C7 = 0, ushort C8 = 0, ushort C9 = 0, ushort C10 = 0,
+ ushort C11 = 0, ushort C12 = 0, ushort C13 = 0, ushort C14 = 0, ushort C15 = 0,
+ ushort C16 = 0, ushort C17 = 0, ushort C18 = 0>
+struct QStaticStringHash
+{
+ typedef QStaticStringHash<C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18> Suffix;
+
+ const static int Hash = (C1 ^ Suffix::Hash) + 5;
+ //(C1 ^ ( (C2 ^ (...)) +5 )) +5
+};
+
+template<>
+struct QStaticStringHash<>
+{
+ typedef QStaticStringHash<> Suffix;
+ const static int Hash = 0;
+
+ /**
+ \internal
+ This function has to be align with qStringHash::Hash value
+ */
+ inline static int hash(const QString &string)
+ {
+ const ushort *str = reinterpret_cast<const ushort*>(string.constData());
+ return hash(str, 0, string.length());
+ }
+private:
+ inline static int hash(const ushort *str, const int index, const int length)
+ {
+ return index != length ? (str[index] ^ hash(str, index + 1, length)) + 5
+ : 0;
+ }
+};
+
+template<class T>
+class SchemaPrivate<T>::NullCheck : public Check {
+public:
+ NullCheck(SchemaPrivate *schema)
+ : Check(schema, "") // TODO
+ {}
+protected:
+ virtual bool doCheck(const Value&) { return true; }
+};
+
+// 5.1
+template<class T>
+class SchemaPrivate<T>::CheckType : public Check {
+ enum Type {StringType = 0x0001,
+ NumberType = 0x0002,
+ IntegerType = 0x0004,
+ BooleanType = 0x0008,
+ ObjectType = 0x0010,
+ ArrayType = 0x0020,
+ NullType = 0x0040,
+ AnyType = 0x0080,
+ UnknownType = 0};
+public:
+ CheckType(SchemaPrivate *schema, const Value& type)
+ : Check(schema, "Type check failed for %1")
+ , m_type(UnknownType)
+ {
+ bool ok;
+ QStringList typesName;
+
+ QString typeName = type.toString(&ok);
+ if (!ok) {
+ ValueList typesList = type.toList(&ok);
+ Q_ASSERT_X(ok, Q_FUNC_INFO, "Type is neither a string nor an array");
+ typename ValueList::const_iterator i;
+ for (i = typesList.constBegin(); i != typesList.constEnd(); ++i) {
+ typeName = (*i).toString(&ok);
+ if (ok) {
+ typesName << typeName;
+ }
+ }
+ } else {
+ typesName << typeName;
+ }
+ foreach (const QString &name, typesName) {
+ const int hash = QStaticStringHash<>::hash(name.toLower());
+
+ // FIXME there are chances of conflicts, do we care? What is chance for new types in JSON?
+ // FIXME we need to check only 2 chars. That would be faster.
+ // FIXME probably we want to support schemas here too.
+ switch (hash) {
+ case QStaticStringHash<'s','t','r','i','n','g'>::Hash:
+ m_type |= StringType;
+ break;
+ case QStaticStringHash<'n','u','m','b','e','r'>::Hash:
+ m_type |= NumberType;
+ m_type |= IntegerType; // an integer is also a number
+ break;
+ case QStaticStringHash<'i','n','t','e','g','e','r'>::Hash:
+ m_type |= IntegerType;
+ break;
+ case QStaticStringHash<'b','o','o','l','e','a','n'>::Hash:
+ m_type |= BooleanType;
+ break;
+ case QStaticStringHash<'o','b','j','e','c','t'>::Hash:
+ m_type |= ObjectType;
+ break;
+ case QStaticStringHash<'a','r','r','a','y'>::Hash:
+ m_type |= ArrayType;
+ break;
+ case QStaticStringHash<'a','n','y'>::Hash:
+ m_type |= AnyType;
+ break;
+ case QStaticStringHash<'n','u','l','l'>::Hash:
+ m_type |= NullType;
+ break;
+ default:
+ m_type |= UnknownType;
+ }
+ }
+
+// qDebug() << Q_FUNC_INFO << m_type << type.toString(&ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ if (m_type == UnknownType)
+ return true;
+
+ bool result = findType(value) & m_type;
+// bool ok;
+// qDebug() << Q_FUNC_INFO << findType(value) << m_type << value.toString(&ok) << result;
+ return result;
+ }
+
+private:
+ inline Type findType(const Value &value) const
+ {
+ bool ok;
+ // Lets assume that the value is valid.
+ switch (m_type) {
+ case StringType:
+ value.toString(&ok);
+ if (ok)
+ return StringType;
+ break;
+ case NumberType:
+ value.toDouble(&ok);
+ if (ok)
+ return NumberType;
+ break;
+ case IntegerType:
+ value.toInt(&ok);
+ if (ok)
+ return IntegerType;
+ break;
+ case BooleanType:
+ value.toBoolean(&ok);
+ if (ok)
+ return BooleanType;
+ break;
+ case ObjectType:
+ value.toObject(&ok);
+ if (ok)
+ return ObjectType;
+ break;
+ case NullType:
+ value.toNull(&ok);
+ if (ok)
+ return NullType;
+ break;
+ case AnyType:
+ return AnyType;
+ case UnknownType:
+ break;
+ default:
+ break;
+ };
+
+ //TODO FIXME it can be better
+ value.toInt(&ok);
+ if (ok)
+ return IntegerType;
+ value.toDouble(&ok);
+ if (ok)
+ return NumberType;
+ value.toObject(&ok);
+ if (ok)
+ return ObjectType;
+ value.toString(&ok);
+ if (ok)
+ return StringType;
+ value.toBoolean(&ok);
+ if (ok)
+ return BooleanType;
+ value.toList(&ok);
+ if (ok)
+ return ArrayType;
+ return AnyType;
+ }
+
+ uint m_type;
+};
+
+// 5.2
+template<class T>
+class SchemaPrivate<T>::CheckProperties : public Check {
+public:
+ CheckProperties(SchemaPrivate *schema, const Value &properties)
+ : Check(schema, "Properties check failed for %1")
+ {
+ bool ok;
+ const Object obj = properties.toObject(&ok);
+ Q_ASSERT(ok);
+
+ QList<Key> propertyNames = obj.propertyNames();
+// qDebug() << " propertyNames: " << propertyNames <<this;
+
+ m_checks.reserve(propertyNames.count());
+ foreach (const Key &propertyName, propertyNames) {
+ QVarLengthArray<Check *, 4> checks;
+ const Object propertyChecks = obj.property(propertyName).toObject(&ok);
+// qDebug() << " propertyChecks:" << propertyChecks;
+
+ Q_ASSERT(ok);
+ foreach (const Key &key, propertyChecks.propertyNames()) {
+// bool ok;
+// qDebug() << " key:" << key << this << propertyChecks.property(key).toString(&ok)<< propertyChecks.property(key).toInt(&ok);
+ checks.append(schema->createCheckPoint(key, propertyChecks.property(key)));
+ }
+ m_checks.insert(propertyName, checks);
+ }
+ }
+
+ ~CheckProperties()
+ {
+ typename QHash<const Key, QVarLengthArray<Check *, 4> >::const_iterator i;
+ for (i = m_checks.constBegin(); i != m_checks.constEnd(); ++i) {
+ typename QVarLengthArray<Check *, 4>::const_iterator j;
+ for (j = i.value().constBegin(); j != i.value().constEnd(); ++j){
+ delete *j;
+ }
+ }
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ Object object = value.toObject(&ok);
+ if (!ok)
+ return false;
+
+ //qDebug() << Q_FUNC_INFO;
+ foreach (const Key &key, object.propertyNames()) {
+ QVarLengthArray<Check *, 4> empty;
+ QVarLengthArray<Check *, 4> checks = m_checks.value(key, empty);
+ Value property = object.property(key);
+ foreach (Check *check, checks) {
+ //qDebug() <<"CHECKING:" << check;
+ if (!check->check(property)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+private:
+ QHash<const Key, QVarLengthArray<Check *, 4> > m_checks;
+};
+
+// 5.5
+template<class T>
+class SchemaPrivate<T>::CheckItems : public Check {
+public:
+ CheckItems(SchemaPrivate *schemap, const Value &schema)
+ : Check(schemap, "Items check failed for %1")
+ {
+ // qDebug() << Q_FUNC_INFO << this;
+ bool ok;
+ Object obj = schema.toObject(&ok);
+ Q_ASSERT(ok);
+ m_schema = Schema<T>(obj, schemap->m_callbacks);
+ }
+
+ virtual bool doCheck(const Value& value)
+ {
+ //qDebug() << Q_FUNC_INFO << this;
+ bool ok;
+ ValueList array = value.toList(&ok);
+ if (!ok)
+ return false;
+
+ typename ValueList::const_iterator i;
+ for (i = array.constBegin(); i != array.constEnd(); ++i) {
+ if (!m_schema.check(*i, Check::m_schema->m_callbacks)) {
+ return false;
+ }
+ }
+ return true;
+ }
+private:
+ Schema<T> m_schema;
+};
+
+// 5.7
+template<class T>
+class SchemaPrivate<T>::CheckRequired : public Check {
+public:
+ CheckRequired(SchemaPrivate *schema, const Value &required)
+ : Check(schema, "Check required field") // TODO what to do about Required ?
+ {
+ bool ok;
+ m_req = required.toBoolean(&ok);
+ if (!ok) {
+ // maybe someone used string instead of bool
+ QString value = required.toString(&ok).toLower();
+ if (value == QString::fromLatin1("false"))
+ m_req = false;
+ else if (value == QString::fromLatin1("true"))
+ m_req = true;
+ else
+ Q_ASSERT(false);
+
+ qWarning() << QString::fromLatin1("Wrong 'required' syntax found, instead of boolean type a string was used");
+ }
+ Q_ASSERT(ok);
+ if (m_req)
+ Check::m_schema->m_maxRequired++;
+ }
+
+ virtual bool doCheck(const Value&)
+ {
+ //qDebug() << Q_FUNC_INFO << m_schema << this;
+ if (m_req)
+ Check::m_schema->m_requiredCount++;
+ return true;
+ }
+private:
+ bool m_req;
+};
+
+// 5.9
+template<class T>
+class SchemaPrivate<T>::CheckMinimum : public Check {
+public:
+ CheckMinimum(SchemaPrivate *schema, const Value &minimum)
+ : Check(schema, "Minimum check failed for %1")
+ {
+ bool ok;
+ m_min = minimum.toDouble(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ return value.toDouble(&ok) >= m_min && ok;
+ }
+private:
+ double m_min;
+};
+
+// 5.10
+template<class T>
+class SchemaPrivate<T>::CheckMaximum : public Check {
+public:
+ CheckMaximum(SchemaPrivate *schema, const Value &maximum)
+ : Check(schema, "Maximum check failed for %1")
+ {
+ // qDebug() << Q_FUNC_INFO << this;
+ bool ok;
+ m_max = maximum.toDouble(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ //qDebug() << Q_FUNC_INFO << value << m_max << this;
+ bool ok;
+ return value.toDouble(&ok) <= m_max && ok;
+ }
+private:
+ double m_max;
+};
+
+
+// 5.11
+template<class T>
+class SchemaPrivate<T>::CheckExclusiveMinimum : public Check {
+public:
+ CheckExclusiveMinimum(SchemaPrivate *schema, const Value &minimum)
+ : Check(schema, "Exclusive minimum check failed for %1")
+ {
+ bool ok;
+ m_min = minimum.toDouble(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ return value.toDouble(&ok) > m_min && ok;
+ }
+private:
+ double m_min;
+};
+
+// 5.12
+template<class T>
+class SchemaPrivate<T>::CheckExclusiveMaximum : public Check {
+public:
+ CheckExclusiveMaximum(SchemaPrivate *schema, const Value &maximum)
+ : Check(schema, "Exclusive minimum check failed for %1")
+ {
+ bool ok;
+ m_max = maximum.toDouble(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ return value.toDouble(&ok) < m_max && ok;
+ }
+private:
+ double m_max;
+};
+
+// 5.13
+template<class T>
+class SchemaPrivate<T>::CheckMinItems : public Check {
+public:
+ CheckMinItems(SchemaPrivate *schema, const Value& minimum)
+ : Check(schema, "Minimum item count check failed for %1")
+ {
+ bool ok;
+ m_min = minimum.toInt(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ int count = value.toList(&ok).count();
+ return count >= m_min && ok;
+ }
+private:
+ int m_min;
+};
+
+// 5.14
+template<class T>
+class SchemaPrivate<T>::CheckMaxItems : public Check {
+public:
+ CheckMaxItems(SchemaPrivate *schema, const Value& maximum)
+ : Check(schema, "Maximum item count check failed for %1")
+ {
+ bool ok;
+ m_max = maximum.toInt(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ int count = value.toList(&ok).count();
+ return count <= m_max && ok;
+ }
+
+private:
+ int m_max;
+};
+
+// 5.16
+template<class T>
+class SchemaPrivate<T>::CheckPattern : public Check {
+public:
+ CheckPattern(SchemaPrivate *schema, const Value& patternValue)
+ : Check(schema, "Pattern check failed for %1")
+ {
+ bool ok;
+ QString patternString = patternValue.toString(&ok);
+ m_regexp.setPattern(patternString);
+ Q_ASSERT(ok && m_regexp.isValid());
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ QString str = value.toString(&ok);
+ if (!ok) {
+ // According to spec (5.15) we should check the value only when it exist and it is a string.
+ // It is a bit strange, but I think we have to return true here.
+ return true;
+ }
+ return m_regexp.exactMatch(str);
+ }
+private:
+ QRegExp m_regexp;
+};
+
+// 5.17
+template<class T>
+class SchemaPrivate<T>::CheckMinLength : public Check {
+public:
+ CheckMinLength(SchemaPrivate *schema, const Value& min)
+ : Check(schema, "Minimal string length check failed for %1")
+ {
+ bool ok;
+ m_min = min.toInt(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ QString str = value.toString(&ok);
+// qDebug() << Q_FUNC_INFO << str << ok;
+ if (!ok) {
+ // According to spec (5.16) we should check the value only when it exist and it is a string.
+ // It is a bit strange, but I think we have to return true here.
+ return true;
+ }
+ return str.length() >= m_min;
+ }
+private:
+ int m_min;
+};
+
+// 5.18
+template<class T>
+class SchemaPrivate<T>::CheckMaxLength : public Check {
+public:
+ CheckMaxLength(SchemaPrivate *schema, const Value& max)
+ : Check(schema, "Maximal string length check failed for %1")
+ {
+ bool ok;
+ m_max = max.toInt(&ok);
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ bool ok;
+ QString str = value.toString(&ok);
+// qDebug() << Q_FUNC_INFO << str << ok;
+ if (!ok) {
+ // According to spec (5.16) we should check the value only when it exist and it is a string.
+ // It is a bit strange, but I think we have to return true here.
+ return true;
+ }
+ return str.length() <= m_max;
+ }
+private:
+ int m_max;
+};
+
+// 5.26
+template<class T>
+class SchemaPrivate<T>::CheckExtends : public Check {
+public:
+ CheckExtends(SchemaPrivate *schema, const Value &value)
+ : Check(schema, "Extends check failed for %1")
+ {
+ // FIXME
+ // Keep in mind that there is a bug in spec. (internet draft 3).
+ // We should search for a schema not for a string here.
+ // Tests are using "string" syntax, so we need to support it for a while
+ bool ok;
+ Object obj = value.toObject(&ok);
+ if (!ok) {
+ QString schemaName = value.toString(&ok);
+ if (!ok || schemaName.length()) {
+ ValueList array = value.toList(&ok);
+ Q_ASSERT(ok);
+ typename ValueList::const_iterator i;
+ for (i = array.constBegin(); i != array.constEnd(); ++i) {
+ obj = (*i).toObject(&ok);
+ Q_ASSERT(ok);
+ m_extendedSchema.append(Schema<T>(obj, schema->m_callbacks));
+ }
+ } else {
+ qWarning() << QString::fromLatin1("Wrong 'extends' syntax found, instead of \"%1\" should be \"%2\"")
+ .arg(schemaName, QString::fromLatin1("{\"$ref\":\"%1\"}").arg(schemaName));
+ m_extendedSchema.append(schema->m_callbacks->loadSchema(schemaName));
+ }
+ } else {
+ m_extendedSchema.append(Schema<T>(obj, schema->m_callbacks));
+ }
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ for (int i = 0; i < m_extendedSchema.count(); ++i) {
+ if (!m_extendedSchema[i].check(value, Check::m_schema->m_callbacks))
+ return false;
+ }
+ return true;
+ }
+private:
+ QVarLengthArray<Schema<T>, 4> m_extendedSchema;
+};
+
+// 5.28
+template<class T>
+class SchemaPrivate<T>::CheckRef : public Check {
+public:
+ CheckRef(SchemaPrivate *schema, const Value &value)
+ : Check(schema, "$Ref check failed for %1")
+ {
+ // TODO according to spec we should replace existing check by this one
+ // I'm not sure what does it mean. Should we remove other checks?
+ // What if we have two $ref? Can it happen? For now, lets use magic of
+ // undefined bahaviour (without crashing of course).
+ bool ok;
+ QString schemaName = value.toString(&ok);
+ Q_ASSERT(ok);
+
+ m_newSchema = schema->m_callbacks->loadSchema(schemaName);
+ if (!m_newSchema.isValid()) {
+ // FIXME should we have current schema name?
+ const QString msg = QString::fromLatin1("Schema extends %1 but it is unknown.")
+ .arg(schemaName);
+ qWarning() << msg;
+ schema->m_callbacks->setError(msg);
+ }
+ }
+ virtual bool doCheck(const Value &value)
+ {
+ bool result = m_newSchema.check(value, Check::m_schema->m_callbacks);
+// qDebug() << Q_FUNC_INFO << result;
+ return result;
+ }
+private:
+ Schema<T> m_newSchema;
+};
+
+template<class T>
+class SchemaPrivate<T>::CheckDescription : public NullCheck {
+public:
+ CheckDescription(SchemaPrivate *schema)
+ : NullCheck(schema)
+ {}
+};
+
+template<class T>
+class SchemaPrivate<T>::CheckTitle : public NullCheck {
+public:
+ CheckTitle(SchemaPrivate *schema)
+ : NullCheck(schema)
+ {}
+};
+
+template<class T>
+typename SchemaPrivate<T>::Check *SchemaPrivate<T>::createCheckPoint(const Key &key, const Value &value)
+{
+ QString keyName = key;
+ keyName = keyName.toLower();
+
+ // This is a perfect hash. BUT spec, in future, can be enriched by new values, that we should just ignore.
+ // As we do not know about them we can't be sure that our perfect hash will be still perfect, therefore
+ // we have to do additional string comparison that confirm result hash function result.
+ int hash = QStaticStringHash<>::hash(keyName);
+ switch (hash) {
+ case QStaticStringHash<'r','e','q','u','i','r','e','d'>::Hash:
+ if (QString::fromLatin1("required") == keyName)
+ return new CheckRequired(this, value);
+ break;
+ case QStaticStringHash<'m','a','x','i','m','u','m'>::Hash:
+ if (QString::fromLatin1("maximum") == keyName)
+ return new CheckMaximum(this, value);
+ break;
+ case QStaticStringHash<'e','x','c','l','u','s','i','v','e','m','a','x','i','m','u','m'>::Hash:
+ if (QString::fromLatin1("exclusivemaximum") == keyName)
+ return new CheckExclusiveMaximum(this, value);
+ break;
+ case QStaticStringHash<'m','i','n','i','m','u','m'>::Hash:
+ if (QString::fromLatin1("minimum") == keyName)
+ return new CheckMinimum(this, value);
+ break;
+ case QStaticStringHash<'e','x','c','l','u','s','i','v','e','m','i','n','i','m','u','m'>::Hash:
+ if (QString::fromLatin1("exclusiveminimum") == keyName)
+ return new CheckExclusiveMinimum(this, value);
+ break;
+ case QStaticStringHash<'p','r','o','p','e','r','t','i','e','s'>::Hash:
+ if (QString::fromLatin1("properties") == keyName)
+ return new CheckProperties(this, value);
+ break;
+ case QStaticStringHash<'d','e','s','c','r','i','p','t','i','o','n'>::Hash:
+ if (QString::fromLatin1("description") == keyName)
+ return new CheckDescription(this);
+ break;
+ case QStaticStringHash<'t','i','t','l','e'>::Hash:
+ if (QString::fromLatin1("title") == keyName)
+ return new CheckTitle(this);
+ break;
+ case QStaticStringHash<'m','a','x','i','t','e','m','s'>::Hash:
+ if (QString::fromLatin1("maxitems") == keyName)
+ return new CheckMaxItems(this,value);
+ break;
+ case QStaticStringHash<'m','i','n','i','t','e','m','s'>::Hash:
+ if (QString::fromLatin1("minitems") == keyName)
+ return new CheckMinItems(this,value);
+ break;
+ case QStaticStringHash<'i','t','e','m','s'>::Hash:
+ if (QString::fromLatin1("items") == keyName)
+ return new CheckItems(this,value);
+ break;
+ case QStaticStringHash<'e','x','t','e','n','d','s'>::Hash:
+ if (QString::fromLatin1("extends") == keyName)
+ return new CheckExtends(this,value);
+ break;
+ case QStaticStringHash<'p','a','t','t','e','r','n'>::Hash:
+ if (QString::fromLatin1("pattern") == keyName)
+ return new CheckPattern(this, value);
+ break;
+ case QStaticStringHash<'m','i','n','l','e','n','g','t','h'>::Hash:
+ if (QString::fromLatin1("minlength") == keyName)
+ return new CheckMinLength(this, value);
+ break;
+ case QStaticStringHash<'m','a','x','l','e','n','g','t','h'>::Hash:
+ if (QString::fromLatin1("maxlength") == keyName)
+ return new CheckMaxLength(this, value);
+ break;
+ case QStaticStringHash<'$','r','e','f'>::Hash:
+ if (QString::fromLatin1("$ref") == keyName)
+ return new CheckRef(this, value);
+ break;
+ case QStaticStringHash<'t','y','p','e'>::Hash:
+ if (QString::fromLatin1("type") == keyName)
+ return new CheckType(this, value);
+ break;
+ default:
+// qDebug() << "NOT FOUND" << keyName;
+ return new NullCheck(this);
+ }
+
+// qDebug() << "FALLBACK" << keyName;
+// bool ok;
+// qCritical() << keyName << value.toString(&ok);
+ return new NullCheck(this);
+}
+
+template<class T>
+bool Schema<T>::check(const Value &value, Service *callbackToUseForCheck) const
+{
+ return d_ptr->check(value, callbackToUseForCheck);
+}
+
+template<class T>
+bool SchemaPrivate<T>::check(const Value &value, Service *callbackToUseForCheck) const
+{
+ //qDebug() << Q_FUNC_INFO << m_checks.count() << this;
+ Q_ASSERT(callbackToUseForCheck);
+ Q_ASSERT(!m_callbacks);
+
+ m_callbacks = callbackToUseForCheck;
+ bool result = check(value);
+ m_callbacks = 0;
+ return result;
+}
+
+template<class T>
+bool SchemaPrivate<T>::check(const Value &value) const
+{
+ Q_ASSERT(m_callbacks);
+
+ m_requiredCount = 0;
+ foreach (Check *check, m_checks) {
+ if (!check->check(value)) {
+ return false;
+ }
+ }
+ if (m_requiredCount != m_maxRequired) {
+ m_callbacks->setError(QString::fromLatin1("Schema validation error: Required field is missing"));
+ return false;
+ }
+ return true;
+}
+
+} // namespace SchemaValidation
+#endif // CHECKPOINTS_H
diff --git a/src/daemon/schema-validation/object.h b/src/daemon/schema-validation/object.h
new file mode 100644
index 00000000..f6a7f95a
--- /dev/null
+++ b/src/daemon/schema-validation/object.h
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qlist.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qshareddata.h>
+
+#ifndef OBJECT_H
+#define OBJECT_H
+
+namespace SchemaValidation {
+
+///**
+// Interface for object like classes. Instances of specialization for this class would be
+// used as input data for schema validation
+// \internal
+//*/
+//template<class T>
+//class Object
+//{
+//public:
+// /**
+// Should return value of a property with the given \a name
+// */
+// Value<T> property(const Key<T>& name) const;
+
+// /**
+// Should return list of all properties name
+// \todo replace to iterator syntax
+// */
+// QList<Key<T> > propertyNames() const;
+
+//};
+
+///**
+// Interface for value like classes. A value can be one of types defined types in JSON
+// \internal
+//*/
+//template<class T>
+//class Value {
+//public:
+// int toInt(bool *ok) const;
+// double toDouble(bool *ok) const;
+// ValueList toList(bool *ok) const;
+// QString toString(bool *ok) const;
+// bool toBool(bool *ok) const;
+// void toNull(bool *ok) const;
+// Object<T> toObject(bool *ok) const;
+//};
+// ValueList::count()
+// ValueList::constBegin()
+// ValueList::constEnd()
+// ValueList::const_iterator()
+//
+// void Service::setError(const QString &message)
+// Schema<T> Service::loadSchema(const QString &name)
+
+template<class T>
+class SchemaPrivate;
+
+template<class T>
+class Schema {
+ typedef typename T::Value Value;
+ typedef typename T::Key Key;
+ typedef typename T::Object Object;
+ typedef typename T::ValueList ValueList;
+ typedef typename T::Service Service;
+
+public:
+ inline bool check(const Value &value, Service *callbackToUseForCheck) const;
+
+ Schema()
+ : d_ptr(new SchemaPrivate<T>())
+ {}
+
+ Schema(const Object& schema, Service *callbacksToUseForCompilation)
+ : d_ptr(new SchemaPrivate<T>())
+ {
+ d_ptr->compile(schema, callbacksToUseForCompilation);
+ }
+
+ bool isValid() const
+ {
+ return d_ptr->isValid();
+ }
+private:
+
+ friend class SchemaPrivate<T>;
+ QExplicitlySharedDataPointer<SchemaPrivate<T> > d_ptr;
+};
+
+template<class T>
+class SchemaPrivate : public QSharedData
+{
+ typedef typename Schema<T>::Value Value;
+ typedef typename Schema<T>::Key Key;
+ typedef typename Schema<T>::Object Object;
+ typedef typename Schema<T>::ValueList ValueList;
+ typedef typename Schema<T>::Service Service;
+
+ class Check {
+ public:
+ Check(SchemaPrivate *schema, const char* errorMessage)
+ : m_schema(schema)
+ , m_errorMessage(errorMessage)
+ {
+ Q_ASSERT(schema);
+ Q_ASSERT(errorMessage);
+ }
+ virtual ~Check() {}
+ bool check(const Value& value)
+ {
+ bool result = doCheck(value);
+ if (!result) {
+ bool ok;
+ // TODO it is tricky, as we do not have access to source code of this schema.
+ // maybe we can set "additional, hidden " source property in each schema property, or some nice hash?
+ m_schema->m_callbacks->setError("Schema validation error: " + QString::fromLatin1(m_errorMessage).arg(value.toString(&ok)));
+ }
+ return result;
+ }
+
+ protected:
+ SchemaPrivate *m_schema;
+ // return true if it is ok
+ virtual bool doCheck(const Value&) = 0;
+ private:
+ const char *m_errorMessage;
+ };
+
+ // empty check
+ class NullCheck;
+ // 5.1
+ class CheckType;
+ // 5.2
+ class CheckProperties;
+ // 5.5
+ class CheckItems;
+ // 5.7
+ class CheckRequired;
+ // 5.9
+ class CheckMinimum;
+ // 5.10
+ class CheckMaximum;
+ // 5.11
+ class CheckExclusiveMinimum;
+ // 5.12
+ class CheckExclusiveMaximum;
+ // 5.13
+ class CheckMinItems;
+ // 5.14
+ class CheckMaxItems;
+ // 5.16
+ class CheckPattern;
+ // 5.17
+ class CheckMinLength;
+ // 5.18
+ class CheckMaxLength;
+ // 5.21
+ class CheckTitle;
+ // 5.26
+ class CheckExtends;
+ // 5.28
+ class CheckRef;
+ class CheckDescription;
+
+ inline Check *createCheckPoint(const Key &key, const Value &value);
+ inline bool check(const Value &value) const;
+
+public:
+ SchemaPrivate()
+ : m_maxRequired(0)
+ , m_requiredCount(0)
+ , m_callbacks(0)
+ {}
+ ~SchemaPrivate()
+ {
+ for (int i = 0; i < m_checks.count(); ++i)
+ delete m_checks.at(i);
+ }
+
+ inline bool check(const Value &value, Service *callbackToUseForCheck) const;
+ inline void compile(const Object &schema, Service *callbackToUseForCompile)
+ {
+ Q_ASSERT(callbackToUseForCompile);
+ m_callbacks = callbackToUseForCompile;
+ const QList<Key> checksKeys = schema.propertyNames();
+ m_checks.reserve(checksKeys.count());
+ foreach (const Key &key, checksKeys) {
+ m_checks.append(createCheckPoint(key, schema.property(key)));
+ }
+ m_callbacks = 0;
+ }
+
+ bool isValid() const
+ {
+ // we have some checks so it means that something got compiled.
+ return m_checks.size();
+ }
+
+private:
+ QVarLengthArray<Check *, 4> m_checks;
+ qint32 m_maxRequired;
+ mutable qint32 m_requiredCount;
+ mutable Service *m_callbacks;
+};
+
+}
+
+#include "checkpoints.h"
+
+#endif // OBJECT_H
diff --git a/src/daemon/schema/Capability.json b/src/daemon/schema/Capability.json
new file mode 100644
index 00000000..281648e3
--- /dev/null
+++ b/src/daemon/schema/Capability.json
@@ -0,0 +1,29 @@
+{
+ "type": "object",
+ "primaryKey": ["_type", "name"],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the capability"
+ },
+ "accessRules": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "A JsonDb query string. Objects matching this query will be allowed for this access type."
+ }
+ }
+ }
+ },
+ "quotas": {
+ "type": "object",
+ "storage": {
+ "type": "number",
+ "description": "Current only one in quotas."
+ }
+ }
+ }
+}
diff --git a/src/daemon/schema/Index.json b/src/daemon/schema/Index.json
new file mode 100644
index 00000000..081443fc
--- /dev/null
+++ b/src/daemon/schema/Index.json
@@ -0,0 +1,20 @@
+{
+ "type": "object",
+ "primaryKey": ["_type", "fieldName"],
+ "properties": {
+ "fieldName": {
+ "type": "string",
+ "required": true,
+ "description": "Property to index"
+ },
+ "fieldType": {
+ "type": "string",
+ "required": true,
+ "description": "Type of values stored in that property."
+ },
+ "objectType": {
+ "type": "string",
+ "description": "Object type to index. Optional."
+ }
+ }
+}
diff --git a/src/daemon/schema/RootCapability.json b/src/daemon/schema/RootCapability.json
new file mode 100644
index 00000000..b9072091
--- /dev/null
+++ b/src/daemon/schema/RootCapability.json
@@ -0,0 +1,14 @@
+{
+ "_type": "Capability",
+ "name": "root",
+ "accessRules": {
+ "all": {
+ "read": [".*"],
+ "write": [".*"],
+ "setOwner": [".*"]
+ }
+ },
+ "quotas": {
+ "storage": -1
+ }
+}
diff --git a/src/daemon/schema/View.json b/src/daemon/schema/View.json
new file mode 100644
index 00000000..6130fa33
--- /dev/null
+++ b/src/daemon/schema/View.json
@@ -0,0 +1,10 @@
+{
+ "type": "object",
+ "properties": {
+ "sourceUuids": {
+ "type": "array"
+ },
+ "key": {
+ }
+ }
+}
diff --git a/src/daemon/schema/notification.json b/src/daemon/schema/notification.json
new file mode 100644
index 00000000..360be3b2
--- /dev/null
+++ b/src/daemon/schema/notification.json
@@ -0,0 +1,12 @@
+{
+ "type": "object",
+ "ephemeral": "true",
+ "properties": {
+ "actions": {
+ "type": "array"
+ },
+ "query": {
+ "type": "string"
+ }
+ }
+}
diff --git a/src/daemon/schemamanager_impl_p.h b/src/daemon/schemamanager_impl_p.h
new file mode 100644
index 00000000..b0995c33
--- /dev/null
+++ b/src/daemon/schemamanager_impl_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCHEMAMANAGER_IMPL_P_H
+#define SCHEMAMANAGER_IMPL_P_H
+
+#include "schemamanager_p.h"
+#include "schema-validation/object.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+bool SchemaManager::contains(const QString &name) const
+{
+ return m_schemas.contains(name);
+}
+
+QsonMap SchemaManager::value(const QString &name) const
+{
+ return m_schemas.value(name).first;
+}
+
+SchemaValidation::Schema<QsonObjectTypes> SchemaManager::schema(const QString &schemaName, QsonObjectTypes::Service *service)
+{
+ QsonMapSchemaPair schemaPair = m_schemas.value(schemaName);
+ ensureCompiled(schemaName, &schemaPair, service);
+ return schemaPair.second;
+}
+
+QsonMap SchemaManager::take(const QString &name)
+{
+ return m_schemas.take(name).first;
+}
+
+QsonMap SchemaManager::insert(const QString &name, QsonMap &schema)
+{
+ m_schemas.insert(name, qMakePair(schema, SchemaValidation::Schema<QsonObjectTypes>()));
+ return QsonMap();
+}
+
+inline QsonMap SchemaManager::ensureCompiled(const QString &schemaName, QsonMapSchemaPair *pair, QsonObjectTypes::Service *callbacks)
+{
+ SchemaValidation::Schema<QsonObjectTypes> schema(pair->second);
+ if (!schema.isValid()) {
+ // Try to compile schema
+ QsonObjectTypes::Object schemaObject(pair->first);
+ SchemaValidation::Schema<QsonObjectTypes> compiledSchema(schemaObject, callbacks);
+ pair->second = compiledSchema;
+ m_schemas.insert(schemaName, *pair);
+ return callbacks->error();
+ }
+ return QsonMap();
+}
+
+inline QsonMap SchemaManager::validate(const QString &schemaName, QsonMap object)
+{
+ if (!contains(schemaName))
+ return QsonMap();
+
+ QsonObjectTypes::Service callbacks(this);
+ QsonMapSchemaPair schemaPair = m_schemas.value(schemaName);
+ ensureCompiled(schemaName, &schemaPair, &callbacks);
+ SchemaValidation::Schema<QsonObjectTypes> schema(schemaPair.second);
+ QsonObjectTypes::Value rootObject(QString(), object);
+ /*bool result = */ schema.check(rootObject, &callbacks);
+ return callbacks.error();
+}
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // SCHEMAMANAGER_IMPL_P_H
diff --git a/src/daemon/schemamanager_p.h b/src/daemon/schemamanager_p.h
new file mode 100644
index 00000000..0c7946ed
--- /dev/null
+++ b/src/daemon/schemamanager_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCHEMAMANAGER_P_H
+#define SCHEMAMANAGER_P_H
+
+#include "jsondb-global.h"
+
+#include <QtCore/qstring.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qmap.h>
+
+#include <QtJsonDbQson/private/qsonmap_p.h>
+
+#include "schema-validation/object.h"
+#include "qsonobjecttypes_p.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+//FIXME This can have better performance
+class SchemaManager
+{
+public:
+ inline bool contains(const QString &name) const;
+ inline QsonMap value(const QString &name) const;
+ inline SchemaValidation::Schema<QsonObjectTypes> schema(const QString &name, QsonObjectTypes::Service *service);
+ inline QsonMap take(const QString &name);
+ inline QsonMap insert(const QString &name, QsonMap &schema);
+
+ inline QsonMap validate(const QString &schemaName, QsonMap object);
+
+private:
+ typedef QPair<QsonMap, SchemaValidation::Schema<QsonObjectTypes> > QsonMapSchemaPair;
+ inline QsonMap ensureCompiled(const QString &schemaName, QsonMapSchemaPair *pair, QsonObjectTypes::Service *service);
+
+ QMap<QString, QsonMapSchemaPair> m_schemas;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // SCHEMAMANAGER_P_H
diff --git a/src/daemon/signals.cpp b/src/daemon/signals.cpp
new file mode 100644
index 00000000..c21557a0
--- /dev/null
+++ b/src/daemon/signals.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <signal.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <QSocketNotifier>
+#include <QDebug>
+#include "signals.h"
+
+int Signals::sSigFD[2];
+
+Signals::Signals( QObject *parent )
+ : QObject(parent)
+{
+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sSigFD))
+ qFatal("Unable to create signal socket pair");
+
+ mNotifier = new QSocketNotifier(sSigFD[1], QSocketNotifier::Read, this);
+ connect(mNotifier, SIGNAL(activated(int)), this, SLOT(handleSig()));
+}
+
+void Signals::start()
+{
+ struct sigaction action;
+
+ if (receivers(SIGNAL(sigTerm())) > 0) {
+ action.sa_handler = Signals::signalHandler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_flags |= SA_RESTART;
+
+ if (::sigaction(SIGTERM, &action, 0) < 0)
+ qFatal("Unable to set sigaction on TERM");
+ }
+
+ if (receivers(SIGNAL(sigHUP())) > 0) {
+ action.sa_handler = Signals::signalHandler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_flags |= SA_RESTART;
+
+ if (::sigaction(SIGHUP, &action, 0) < 0)
+ qFatal("Unable to set sigaction on HUP");
+ }
+
+ if (receivers(SIGNAL(sigINT())) > 0) {
+ action.sa_handler = Signals::signalHandler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_flags |= SA_RESTART;
+
+ if (::sigaction(SIGINT, &action, 0) < 0)
+ qFatal("Unable to set sigaction on INT");
+ }
+}
+
+void Signals::signalHandler(int number)
+{
+ int tmp = number;
+ ::write(sSigFD[0], &tmp, sizeof(tmp));
+}
+
+void Signals::handleSig()
+{
+ mNotifier->setEnabled(false);
+ int tmp;
+ ::read(sSigFD[1], &tmp, sizeof(tmp));
+ switch (tmp) {
+ case SIGTERM:
+ emit sigTerm();
+ break;
+ case SIGHUP:
+ emit sigHUP();
+ break;
+ case SIGINT:
+ emit sigINT();
+ break;
+ default:
+ break;
+ }
+ mNotifier->setEnabled(true);
+}
+
+
diff --git a/src/daemon/signals.h b/src/daemon/signals.h
new file mode 100644
index 00000000..47738547
--- /dev/null
+++ b/src/daemon/signals.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIGNALS_H
+#define SIGNALS_H
+
+#include <QObject>
+class QSocketNotifier;
+
+class Signals : public QObject
+{
+ Q_OBJECT
+public:
+ Signals( QObject *parent = 0);
+ void start();
+
+ static void signalHandler(int unused);
+
+signals:
+ void sigTerm();
+ void sigHUP();
+ void sigINT();
+
+private slots:
+ void handleSig();
+
+private:
+ static int sSigFD[2];
+ QSocketNotifier *mNotifier;
+};
+
+#endif // SIGNALS_H
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
new file mode 100644
index 00000000..c28b9e34
--- /dev/null
+++ b/src/imports/imports.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += jsondb-listmodel jsondb
+
diff --git a/src/imports/jsondb-listmodel/cuid.cpp b/src/imports/jsondb-listmodel/cuid.cpp
new file mode 100644
index 00000000..1c14766f
--- /dev/null
+++ b/src/imports/jsondb-listmodel/cuid.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "cuid.h"
+#include <QFile>
+#include <QCryptographicHash>
+
+Cuid::Cuid(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QString Cuid::intern(QString filename)
+{
+ QFile file(filename);
+ if (!file.exists())
+ return QString();
+ file.open(QIODevice::ReadOnly);
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ char data[4096];
+ while (!file.atEnd()) {
+ int nbytes = file.read(data, sizeof(data));
+ hash.addData(data, nbytes);
+ }
+ file.close();
+ return hash.result().toHex();
+}
diff --git a/src/imports/jsondb-listmodel/cuid.h b/src/imports/jsondb-listmodel/cuid.h
new file mode 100644
index 00000000..822dad2d
--- /dev/null
+++ b/src/imports/jsondb-listmodel/cuid.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CUID_H
+#define CUID_H
+
+#include <QObject>
+#include <QString>
+
+class Cuid : public QObject {
+ Q_OBJECT
+public:
+ Cuid(QObject *parent = 0);
+ Q_INVOKABLE QString intern(QString filename);
+};
+
+#endif
diff --git a/src/imports/jsondb-listmodel/javascript-listmodel.cpp b/src/imports/jsondb-listmodel/javascript-listmodel.cpp
new file mode 100644
index 00000000..d7663b17
--- /dev/null
+++ b/src/imports/jsondb-listmodel/javascript-listmodel.cpp
@@ -0,0 +1,323 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "javascript-listmodel.h"
+#include <QDebug>
+
+// #define DEBUG_LIST_MODEL
+
+#ifdef DEBUG_LIST_MODEL
+#define DEBUG() qDebug() << Q_FUNC_INFO
+#else
+#define DEBUG() if (0) qDebug()
+#endif
+
+/*!
+ \qmlclass JavaScriptListModel
+ \internal
+ \inqmlmodule QtAddOn.JsonDb 1
+ \inherits ListModel
+ \inherits ListModel
+ \since 1.x
+
+ The JavaScriptListModel provides a ListModel usable with views such as
+ ListView or GridView displaying data items matching a query.
+
+ \code
+ JavaScriptListModel {
+ id: contactsModel
+ query: "[?_type=\"Contact\"]"
+ roleNames: ["firstName", "lastName", "phoneNumber"]
+ }
+ ListView {
+ model: contactsModel
+ Row {
+ spacing: 10
+ Text {
+ text: firstName + " " + lastName
+ }
+ Text {
+ text: phoneNumber
+ }
+ }
+ }
+ \endcode
+
+ \sa ListView, GridView
+
+*/
+JavaScriptListModel::JavaScriptListModel(QObject *parent)
+ : QListModelInterface(parent)
+{
+ DEBUG();
+}
+
+JavaScriptListModel::~JavaScriptListModel()
+{
+}
+
+void JavaScriptListModel::classBegin()
+{
+}
+
+void JavaScriptListModel::componentComplete()
+{
+ mComponentComplete = true;
+}
+
+/*!
+ \qmlproperty int JavaScriptListModel::count
+
+ Returns the number of items in the model.
+*/
+int JavaScriptListModel::count() const
+{
+ //DEBUG() << mData.size();
+ //qDebug() << Q_FUNC_INFO << mList.size();
+ return mList.size();
+}
+
+static QVariant lookupProperty(const QVariant &item, const QStringList &propertyChain)
+{
+ QVariant result = item;
+ for (int i = 0; i < propertyChain.size(); i++) {
+ QString property = propertyChain[i];
+ QVariantMap map = result.toMap();
+ if (map.contains(property)) {
+ result = map.value(property);
+ } else {
+ DEBUG() << item << property << propertyChain;
+ return QVariant();
+ }
+ }
+ return result;
+}
+
+QHash<int,QVariant> JavaScriptListModel::data(int index, const QList<int>& roles) const
+{
+ QHash<int,QVariant> result;
+
+ QVariant item;
+ if ((index >= 0) && (index < mList.size()))
+ item = mList[index];
+ for (int i = 0; i < roles.size(); i++) {
+ int role = roles[i];
+
+ QString property = mRoleNames[i];
+
+ //qDebug() << Q_FUNC_INFO << index << property << lookupProperty(item, property.split('.'));
+
+ result.insert(role, lookupProperty(item, property.split('.')));
+ }
+
+ return result;
+}
+
+QVariant JavaScriptListModel::data(int index, int role) const
+{
+ QVariant item;
+
+ if ((index >= 0) && (index < mList.size()))
+ item = mList[index];
+ QVariant result;
+ QString property = mRoleNames[role];
+ result = lookupProperty(item, property.split('.'));
+
+ DEBUG() << index << role << result;
+ //qDebug() << Q_FUNC_INFO << index << role << result;
+
+ return result;
+}
+
+bool JavaScriptListModel::setData(int index, const QHash<int,QVariant>& newValues)
+{
+ QVariantMap object = mList[index].toMap();
+ QList<int> changedRoles;
+ for (QHash<int,QVariant>::const_iterator it = newValues.begin(); it != newValues.end(); ++it) {
+ int role = it.key();
+ QVariant newValue = it.value();
+ QVariant oldValue = object.value(mRoleNames[role]);
+
+ //qDebug() << Q_FUNC_INFO << index << role << mRoleNames[role] << oldValue << newValue;
+
+ if (oldValue != newValue)
+ changedRoles << role;
+ object.insert(mRoleNames[role], newValue);
+ }
+ mList[index] = object;
+ if (changedRoles.size())
+ emit itemsChanged(index, 1, changedRoles);
+
+ return true;
+}
+
+void JavaScriptListModel::setList(const QVariant &_newList)
+{
+ QVariantList newList;
+ if (_newList.isValid()) {
+ if (_newList.type() == QVariant::List)
+ newList = _newList.toList();
+ else if (_newList.type() == QVariant::Map)
+ newList << _newList;
+ }
+ int currentSize = mList.size();
+ int newSize = newList.size();
+ int minSize = qMin<int>(currentSize, newSize);
+ if (currentSize > newSize) {
+ emit itemsRemoved(newSize, currentSize - newSize);
+ }
+ for (int i = 0; i < minSize; i++) {
+ QList<int> changedRoles;
+ for (int j = 0; j < mRoles.size(); j++) {
+ QString roleName = mRoleNames[j];
+ if (mList[i].toMap().value(roleName) != newList[i].toMap().value(roleName))
+ changedRoles.append(j);
+ }
+ if (changedRoles.size())
+ emit itemsChanged(i, 1, changedRoles);
+ }
+ mList = newList;
+ if (currentSize < newSize) {
+ emit itemsInserted(currentSize, newSize - currentSize);
+ }
+ emit listChanged();
+ if (currentSize != newSize)
+ emit countChanged();
+}
+
+/*!
+ \qmlproperty string JavaScriptListModel::query
+
+ Returns the query used by the model to fetch items from the database.
+
+ In the following example, the \a JavaScriptListModel would contain all the objects with \a _type contains the value \a "CONTACT"
+
+ \code
+ JavaScriptListModel {
+ id: listModel
+ query: "[?_type=\"CONTACT\"]"
+ }
+ \endcode
+
+*/
+QVariant JavaScriptListModel::list() const
+{
+ return mList;
+}
+
+/*!
+ \qmlproperty ListOrObject JavaScriptListModel::roleNames
+
+ Controls which properties to expose from the objects matching the query.
+
+ Setting \a roleNames to a list of strings causes the model to fetch
+ those properties of the objects and expose them as roles to the
+ delegate for each item viewed.
+
+ \code
+ JavaScriptListModel {
+ query: "[?_type=\"MyType\"]"
+ roleNames: ['a', 'b']
+ }
+ ListView {
+ model: listModel
+ Text {
+ text: a + ":" + b
+ }
+ \endcode
+
+ Setting \a roleNames to a dictionary remaps properties in the object
+ to the specified roles in the model.
+
+ In the following example, role \a a would yield the value of
+ property \a aLongName in the objects. Role \a liftedProperty would
+ yield the value of \a o.nested.property for each matching object \a
+ o in the database.
+
+ \code
+ function makeRoleNames() {
+ return { 'a': 'aLongName', 'liftedProperty': 'nested.property' };
+ }
+ JavaScriptListModel {
+ id: listModel
+ query: "[?_type=\"MyType\"]"
+ roleNames: makeRoleNames()
+ }
+ ListView {
+ model: listModel
+ Text {
+ text: a + " " + liftedProperty
+ }
+ }
+ \endcode
+*/
+QStringList JavaScriptListModel::roleNames() const
+{
+ return mRoleNames;
+}
+
+void JavaScriptListModel::setRoleNames(const QStringList &roleNames)
+{
+ mRoleNames = roleNames;
+ mRoles.clear();
+ for (int i = 0; i < mRoleNames.size(); i++)
+ mRoles << i;
+ emit roleNamesChanged();
+}
+
+QList<int> JavaScriptListModel::roles() const
+{
+ //qDebug() << Q_FUNC_INFO << mRoles;
+ return mRoles;
+}
+
+QString JavaScriptListModel::toString(int role) const
+{
+ if ((role >= 0) && (role < mRoleNames.size())) {
+ QString name = mRoleNames[role];
+ //qDebug() << Q_FUNC_INFO << role << name;
+ return name;
+ } else
+ return QString();
+}
+
+//Q_EXPORT_STATIC_PLUGIN(JavaScriptListModelPlugin)
+//Q_EXPORT_PLUGIN2(jsondblistmodelplugin, JavaScriptListModelPlugin)
diff --git a/src/imports/jsondb-listmodel/javascript-listmodel.h b/src/imports/jsondb-listmodel/javascript-listmodel.h
new file mode 100644
index 00000000..d1e6f66e
--- /dev/null
+++ b/src/imports/jsondb-listmodel/javascript-listmodel.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JavaScriptListModel_H
+#define JavaScriptListModel_H
+
+#include <QDeclarativeParserStatus>
+#include <QStringList>
+#include <QObject>
+#include <QHash>
+
+#if (QT_VERSION == 0x040700)
+#include "qlistmodelinterface_p_4.7.0.h"
+#else
+#include "qlistmodelinterface_p.h"
+#endif
+#include "jsondb-client.h"
+#include "../jsondb/jsondb-component.h"
+#include "cuid.h"
+
+class JavaScriptListModel : public QListModelInterface, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+public:
+ JavaScriptListModel(QObject *parent = 0);
+ virtual ~JavaScriptListModel();
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(QVariant list READ list WRITE setList NOTIFY listChanged)
+ Q_PROPERTY(QStringList roleNames READ roleNames WRITE setRoleNames NOTIFY roleNamesChanged)
+
+ virtual void classBegin();
+ virtual void componentComplete();
+ virtual int count() const;
+ virtual QHash<int,QVariant> data(int index, const QList<int>& roles = QList<int>()) const;
+ virtual QVariant data(int index, int role) const;
+ virtual bool setData(int index, const QHash<int,QVariant>& values);
+
+ QVariant list() const;
+ void setList(const QVariant &newList);
+
+ QStringList roleNames() const;
+ void setRoleNames(const QStringList &roles);
+
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+
+ signals:
+ void countChanged();
+ void listChanged();
+ void roleNamesChanged();
+
+ private:
+ QVariantList mList;
+ QStringList mRoleNames;
+ QList<int> mRoles;
+ bool mComponentComplete;
+};
+
+#endif
diff --git a/src/imports/jsondb-listmodel/jsondb-listmodel.pro b/src/imports/jsondb-listmodel/jsondb-listmodel.pro
new file mode 100644
index 00000000..28789106
--- /dev/null
+++ b/src/imports/jsondb-listmodel/jsondb-listmodel.pro
@@ -0,0 +1,41 @@
+TARGET = jsondblistmodelplugin
+TARGETPATH = QtAddOn/JsonDb
+
+include(../qimportbase.pri)
+
+QT += network declarative jsondb-private jsondbqson-private
+
+DESTDIR = $$QT.jsondb.imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+INSTALLS += target qmldir
+
+VERSION = 1.0
+
+include(../../common/common.pri)
+
+HEADERS += \
+ ../jsondb/jsondb-listmodel.h \
+ ../jsondb/jsondb-listmodel_p.h \
+ javascript-listmodel.h \
+ jsondb-singletonwatcher.h \
+ jsondb-watcher.h \
+ ../jsondb/jsondb-component.h \
+ cuid.h \
+ plugin.h
+
+HEADERS += $$QSONCONVERSION_HEADERS
+
+SOURCES += \
+ ../jsondb/jsondb-listmodel.cpp \
+ javascript-listmodel.cpp \
+ jsondb-singletonwatcher.cpp \
+ jsondb-watcher.cpp \
+ ../jsondb/jsondb-component.cpp \
+ cuid.cpp \
+ plugin.cpp
+
+SOURCES += $$QSONCONVERSION_SOURCES
diff --git a/src/imports/jsondb-listmodel/jsondb-singletonwatcher.cpp b/src/imports/jsondb-listmodel/jsondb-singletonwatcher.cpp
new file mode 100644
index 00000000..decff78a
--- /dev/null
+++ b/src/imports/jsondb-listmodel/jsondb-singletonwatcher.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-singletonwatcher.h"
+#include "jsondb-watcher.h"
+
+#include <QTimer>
+
+
+JsonDbSingletonWatcher::JsonDbSingletonWatcher(QObject *parent) :
+ QObject(parent),
+ mComponentComplete(false)
+{
+ mWatcher = new JsonDbWatcher(this);
+ connect(mWatcher, SIGNAL(response(QVariant)),
+ this, SLOT(handleResponse(QVariant)));
+ connect(mWatcher, SIGNAL(disconnected()),
+ this, SIGNAL(disconnected()));
+}
+
+JsonDbSingletonWatcher::~JsonDbSingletonWatcher()
+{
+}
+
+QVariant JsonDbSingletonWatcher::value() const
+{
+ return mValue;
+}
+
+void JsonDbSingletonWatcher::setQuery(const QString &q)
+{
+ mQuery = q;
+ emit queryChanged();
+
+ if (mComponentComplete && !mQuery.isEmpty()) {
+ mWatcher->start(mQuery);
+ }
+}
+
+void JsonDbSingletonWatcher::setDefaultValue(const QVariant &val)
+{
+ mDefaultValue = val;
+ mWatcher->setDefault(val);
+ emit defaultValueChanged();
+}
+
+void JsonDbSingletonWatcher::classBegin()
+{
+}
+
+void JsonDbSingletonWatcher::componentComplete()
+{
+ mComponentComplete = true;
+
+ if (!mQuery.isEmpty()) {
+ // XXX shouldn't be necessary, but something inside of
+ // QDeclarativeComponent crashes if we don't wait.
+ QTimer::singleShot(0, this, SLOT(start()));
+ }
+}
+
+void JsonDbSingletonWatcher::start()
+{
+ if (!mQuery.isEmpty())
+ mWatcher->start(mQuery);
+}
+
+void JsonDbSingletonWatcher::handleResponse( const QVariant& object )
+{
+ mValue = object;
+ emit valueChanged();
+}
diff --git a/src/imports/jsondb-listmodel/jsondb-singletonwatcher.h b/src/imports/jsondb-listmodel/jsondb-singletonwatcher.h
new file mode 100644
index 00000000..fc314038
--- /dev/null
+++ b/src/imports/jsondb-listmodel/jsondb-singletonwatcher.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JsonDbSingletonWatcher_H
+#define JsonDbSingletonWatcher_H
+
+#include <QObject>
+#include <QVariant>
+#include <QDeclarativeParserStatus>
+
+class JsonDbWatcher;
+
+class JsonDbSingletonWatcher : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+
+ Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(QVariant value READ value NOTIFY valueChanged)
+ Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue NOTIFY defaultValueChanged)
+
+public:
+ JsonDbSingletonWatcher(QObject *parent = 0);
+ virtual ~JsonDbSingletonWatcher();
+
+ QString query() const
+ { return mQuery; }
+ QVariant value() const;
+ QVariant defaultValue() const
+ { return mDefaultValue; }
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+public slots:
+ void setQuery(const QString &query);
+ void setDefaultValue(const QVariant &val);
+
+signals:
+ void queryChanged();
+ void valueChanged();
+ void defaultValueChanged();
+ void disconnected();
+
+ protected slots:
+ void handleResponse( const QVariant& object );
+ void start();
+
+ private:
+ JsonDbWatcher *mWatcher;
+ QString mQuery;
+ QVariant mValue;
+ QVariant mDefaultValue;
+ bool mComponentComplete;
+};
+
+#endif
diff --git a/src/imports/jsondb-listmodel/jsondb-watcher.cpp b/src/imports/jsondb-listmodel/jsondb-watcher.cpp
new file mode 100644
index 00000000..5d03ccd5
--- /dev/null
+++ b/src/imports/jsondb-listmodel/jsondb-watcher.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-watcher.h"
+#include "private/jsondb-strings_p.h"
+
+/*!
+ \class JsonDbWatcher
+ \brief The JsonDbWatcher class monitors the state of a single JsonDb object.
+
+ The JsonDbWatcher class is used to monitor a single JsonDb object and
+ provide notifications when it changes its values.
+
+ The response() signal is when the watcher first connects to the JsonDb object
+ and subsequently each time the object changes. If there is no object or
+ if the object is deleted, the response() signal is sent with a null QVariant
+ object.
+
+ This class is designed to work with singleton database objects. If there
+ is more than one object in the database that matches the query, only the
+ first object found will be used.
+
+ */
+
+JsonDbWatcher::JsonDbWatcher(JsonDbConnection *connection, QObject *parent)
+ : QObject(parent),
+ mConnection(connection)
+{
+ Q_ASSERT(mConnection);
+ init();
+}
+
+JsonDbWatcher::JsonDbWatcher(Qt::ConnectionType type, QObject *parent)
+ : QObject(parent)
+{
+ mConnection = JsonDbConnection::instance();
+ init(type);
+}
+
+JsonDbWatcher::JsonDbWatcher(QObject *parent)
+ : QObject(parent)
+{
+ mConnection = JsonDbConnection::instance();
+ init();
+}
+
+/*!
+ Checks to see if the connection to the database is alive.
+ */
+
+bool JsonDbWatcher::connected() const
+{
+ Q_ASSERT(mConnection);
+ return mConnection->isConnected();
+}
+
+void JsonDbWatcher::init(Qt::ConnectionType type)
+{
+ connect(mConnection, SIGNAL(notified(QString,QVariant,QString)),
+ this, SLOT(handleNotification(QString,QVariant,QString)),type);
+ connect(mConnection, SIGNAL(response(int,QsonObject)),
+ this, SLOT(handleResponse(int,QsonObject)),type);
+ connect(mConnection, SIGNAL(error(int,int,QString)),
+ this, SLOT(handleError(int,int,QString)),type);
+ connect(mConnection, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+}
+
+void JsonDbWatcher::handleResponse( int id, const QsonObject& data )
+{
+ if ( mNotifyId == id )
+ mNotifyUuid = data.toMap().value(JsonDbString::kUuidStr, QString());
+}
+
+void JsonDbWatcher::handleError( int id, int code, const QString& message )
+{
+ if ( mNotifyId == id )
+ qWarning() << Q_FUNC_INFO << id << code << message;
+}
+
+void JsonDbWatcher::handleNotification( const QString& notify_uuid,
+ const QsonObject& object,
+ const QString& action )
+{
+ if (notify_uuid == mNotifyUuid)
+ emit response( action != JsonDbString::kRemoveStr ? qsonToVariant(object) : QVariant() );
+}
+
+/*!
+ Start monitoring a JsonDb object that responds to \a queryString.
+ The initial state of the object is retrieved synchronously with
+ this call, which means that the response() signal will be fired
+ immediately.
+
+ Returns false if there is no JsonDb connection.
+ */
+
+bool JsonDbWatcher::start( const QString& queryString)
+{
+ if (!mConnection || !mConnection->isConnected())
+ return false;
+
+ QVariant result;
+ QsonObject data = mConnection->sync(variantToQson(JsonDbConnection::makeQueryRequest(queryString)));
+ QsonList list = data.toMap().subList( JsonDbString::kDataStr );
+ if (list.size())
+ result = qsonToVariant(list.at<QsonElement>(0));
+
+ if (result.isNull() && !mDefault.isNull()) { // Attempt to construct a default object
+ QsonMap createResultMap = mConnection->sync(JsonDbConnection::makeCreateRequest(variantToQson(mDefault))).toMap();
+ qDebug() << "JsonDbWatcher::start" << "creating default" << createResultMap;
+ QVariantMap defaultMap = mDefault.toMap();
+ defaultMap.insert(JsonDbString::kUuidStr, createResultMap.value(JsonDbString::kUuidStr, QString()));
+ defaultMap.insert(JsonDbString::kVersionStr, createResultMap.value(JsonDbString::kVersionStr, QString()));
+ mDefault = defaultMap;
+ result = mDefault;
+ }
+
+ emit response(result);
+
+ QsonList actions;
+ actions.append(JsonDbString::kCreateStr);
+ actions.append(JsonDbString::kUpdateStr);
+ actions.append(JsonDbString::kRemoveStr);
+ QsonMap notify_object = JsonDbConnection::makeNotification(queryString, actions);
+ mNotifyId = mConnection->request(JsonDbConnection::makeCreateRequest(notify_object));
+ return true;
+}
+
+
+
+
diff --git a/src/imports/jsondb-listmodel/jsondb-watcher.h b/src/imports/jsondb-listmodel/jsondb-watcher.h
new file mode 100644
index 00000000..79ac41e4
--- /dev/null
+++ b/src/imports/jsondb-listmodel/jsondb-watcher.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_WATCHER_H
+#define JSONDB_WATCHER_H
+
+#include <QObject>
+#include <QVariant>
+#include <QList>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "private/jsondb-connection_p.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+class JsonDbWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ JsonDbWatcher(JsonDbConnection *connection, QObject *parent=0);
+ JsonDbWatcher(Qt::ConnectionType type, QObject *parent=0);
+ JsonDbWatcher(QObject *parent=0);
+
+public slots:
+ bool connected() const;
+ void setDefault(const QVariant& value) { mDefault = value; }
+ bool start(const QString& query);
+
+signals:
+ void response( const QVariant& object );
+ void disconnected();
+
+private slots:
+ void handleResponse( int id, const QsonObject& data );
+ void handleError( int id, int code, const QString& message );
+ void handleNotification( const QString& notify_uuid,
+ const QsonObject& object, const QString& action );
+
+private:
+ void init(Qt::ConnectionType type=Qt::AutoConnection);
+
+private:
+ JsonDbConnection *mConnection;
+ int mNotifyId;
+ QString mNotifyUuid;
+ QVariant mDefault;
+};
+
+#endif // JSONDB_WATCHER_H
diff --git a/src/imports/jsondb-listmodel/plugin.cpp b/src/imports/jsondb-listmodel/plugin.cpp
new file mode 100644
index 00000000..32c77490
--- /dev/null
+++ b/src/imports/jsondb-listmodel/plugin.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "plugin.h"
+
+#include "jsondb-client.h"
+#include "../jsondb/jsondb-component.h"
+#include "../jsondb/jsondb-listmodel.h"
+#include "javascript-listmodel.h"
+#include "cuid.h"
+#include "jsondb-singletonwatcher.h"
+
+Q_EXPORT_STATIC_PLUGIN(JsonDbListModelPlugin)
+Q_EXPORT_PLUGIN2(jsondblistmodelplugin, JsonDbListModelPlugin)
+
+void JsonDbListModelPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+}
+
+void JsonDbListModelPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(uri == QLatin1String("QtAddOn.JsonDb"));
+ qmlRegisterType<JsonDbListModel>(uri, 1, 0, "JsonDbListModel");
+ qmlRegisterType<JavaScriptListModel>(uri, 1, 0, "JavaScriptListModel");
+ qmlRegisterType<JsonDbComponent>(uri, 1, 0, "JsonDb");
+ qmlRegisterType<Cuid>(uri, 1, 0, "Cuid");
+ qmlRegisterType<JsonDbSingletonWatcher>(uri, 1, 0, "JsonDbSingletonWatcher");
+}
diff --git a/src/imports/jsondb-listmodel/plugin.h b/src/imports/jsondb-listmodel/plugin.h
new file mode 100644
index 00000000..07846971
--- /dev/null
+++ b/src/imports/jsondb-listmodel/plugin.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_PLUGIN_H
+#define JSONDB_PLUGIN_H
+
+#include <QDeclarativeExtensionPlugin>
+#include <QtDeclarative/qdeclarative.h>
+
+class JsonDbListModelPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+
+ public:
+
+ void initializeEngine(QDeclarativeEngine *engine, const char *uri);
+ void registerTypes(const char *uri);
+};
+
+#endif
diff --git a/src/imports/jsondb-listmodel/qlistmodelinterface_p.h b/src/imports/jsondb-listmodel/qlistmodelinterface_p.h
new file mode 100644
index 00000000..8c8ebb35
--- /dev/null
+++ b/src/imports/jsondb-listmodel/qlistmodelinterface_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLISTMODELINTERFACE_H
+#define QLISTMODELINTERFACE_H
+
+#include <QtCore/QHash>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QListModelInterface : public QObject
+{
+ Q_OBJECT
+ public:
+ QListModelInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~QListModelInterface() {}
+
+ virtual int count() const = 0;
+ virtual QVariant data(int index, int role) const = 0;
+
+ virtual QList<int> roles() const = 0;
+ virtual QString toString(int role) const = 0;
+
+ Q_SIGNALS:
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void itemsChanged(int index, int count, const QList<int> &roles);
+
+ protected:
+ QListModelInterface(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent) {}
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QTREEMODELINTERFACE_H
diff --git a/src/imports/jsondb-listmodel/qlistmodelinterface_p_4.7.0.h b/src/imports/jsondb-listmodel/qlistmodelinterface_p_4.7.0.h
new file mode 100644
index 00000000..07592ad5
--- /dev/null
+++ b/src/imports/jsondb-listmodel/qlistmodelinterface_p_4.7.0.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLISTMODELINTERFACE_H
+#define QLISTMODELINTERFACE_H
+
+#include <QtCore/QHash>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QListModelInterface : public QObject
+{
+ Q_OBJECT
+ public:
+ QListModelInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~QListModelInterface() {}
+
+ virtual int count() const = 0;
+ virtual QHash<int,QVariant> data(int index, const QList<int>& roles = QList<int>()) const = 0;
+ virtual QVariant data(int index, int role) const = 0;
+ virtual bool setData(int index, const QHash<int,QVariant>& values)
+ { Q_UNUSED(index); Q_UNUSED(values); return false; }
+
+ virtual QList<int> roles() const = 0;
+ virtual QString toString(int role) const = 0;
+
+ Q_SIGNALS:
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void itemsChanged(int index, int count, const QList<int> &roles);
+
+ protected:
+ QListModelInterface(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent) {}
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QTREEMODELINTERFACE_H
diff --git a/src/imports/jsondb-listmodel/qmldir b/src/imports/jsondb-listmodel/qmldir
new file mode 100644
index 00000000..8edb8dcb
--- /dev/null
+++ b/src/imports/jsondb-listmodel/qmldir
@@ -0,0 +1 @@
+plugin jsondblistmodelplugin
diff --git a/src/imports/jsondb-listmodel/qmldir_debug b/src/imports/jsondb-listmodel/qmldir_debug
new file mode 100644
index 00000000..f8487aee
--- /dev/null
+++ b/src/imports/jsondb-listmodel/qmldir_debug
@@ -0,0 +1 @@
+plugin jsondblistmodelplugin_debug
diff --git a/src/imports/jsondb/jsondb-component.cpp b/src/imports/jsondb/jsondb-component.cpp
new file mode 100644
index 00000000..420fe778
--- /dev/null
+++ b/src/imports/jsondb/jsondb-component.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QJSEngine>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "jsondb-component.h"
+#include "private/jsondb-strings_p.h"
+#include "jsondb-client.h"
+
+#include "qsonconversion.h"
+
+JsonDbNotification::JsonDbNotification(JsonDbComponent *repo)
+ : QObject(repo)
+ , mId(-1)
+{
+}
+
+JsonDbNotification::~JsonDbNotification()
+{
+ remove();
+}
+
+void JsonDbNotification::remove()
+{
+ if (!mUuid.isEmpty())
+ emit removed(mUuid); // the JsonDbComponent connects to this and does the real work.
+ else
+ emit removed(mId);
+}
+
+JsonDbNotificationHandle::JsonDbNotificationHandle(JsonDbNotification *notification)
+ : QObject(notification)
+ , mNotification(notification)
+{
+}
+
+JsonDbNotificationHandle::~JsonDbNotificationHandle()
+{
+}
+
+QString JsonDbNotificationHandle::uuid() const
+{
+ if (mNotification.isNull())
+ return QString();
+ else
+ return mNotification->mUuid;
+}
+
+void JsonDbNotificationHandle::remove()
+{
+ if (!mNotification.isNull())
+ mNotification->remove();
+}
+
+/*!
+ \qmlclass JsonDbComponent
+ \inqmlmodule QtAddOn.JsonDb
+ \since 1.x
+
+ The JsonDb element allows you find, create, update, or remove objects from JsonDb.
+ Most of the functions take script objects as parameters.
+ Those can have different values "query", "limit" and "offset"
+
+ Most of the functions take optional success and error callback functions. Those script
+ functions are called in case of an error (or succes)
+*/
+
+JsonDbComponent::JsonDbComponent(QObject *parent)
+ : QObject(parent)
+ , mDebugOutput(false)
+ , mJsonDb(new JsonDbClient(this))
+{
+ connect(mJsonDb, SIGNAL(response(int,QsonObject)),
+ this, SLOT(jsonDbResponse(int,QsonObject)),
+ Qt::QueuedConnection);
+ connect(mJsonDb, SIGNAL(error(int,int,QString)),
+ this, SLOT(jsonDbErrorResponse(int,int,QString)),
+ Qt::QueuedConnection);
+ connect(mJsonDb, SIGNAL(notified(QString,QsonObject,QString)),
+ this, SLOT(jsonDbNotified(QString,QsonObject,QString)),
+ Qt::QueuedConnection);
+}
+
+JsonDbComponent::~JsonDbComponent()
+{
+}
+
+/*!
+ \qmlsignal QtAddOn.JsonDb::JsonDb::onResponse()
+
+ This handler is called when the database responds to a request.
+*/
+
+/*!
+ \qmlsignal QtAddOn.JsonDb::JsonDb::onError()
+
+ This handler is called when there is an error in a database request.
+*/
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDb::create(object)
+
+ Creates the \a object in the database.
+ The \a object must not have a "_uuid" field.
+ On success, emits the response signal.
+ Returns the request uuid.
+*/
+int JsonDbComponent::create(const QJSValue &object,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] create:"<<object.toString();
+
+ return addRequestInfo(mJsonDb->create(jsValueToQson(object)), JsonDbComponent::Create, object, successCallback, errorCallback);
+}
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDb::update(object queryObject, object successFunction, object errorFunction)
+
+ Updates the database to match the new object.
+ The \a object must have a valid "uuid" field.
+ On success, emits the response signal.
+ Returns the request uuid.
+ */
+int JsonDbComponent::update(const QJSValue &object,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ return addRequestInfo(mJsonDb->update(jsValueToQson(object)), JsonDbComponent::Update, object, successCallback, errorCallback);
+}
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDb::remove(object queryObject, object successFunction, object errorFunction)
+
+ Removes the object from the database.
+ The \a object must have a valid "uuid" field.
+ On success, emits the response signal.
+ Returns the request uuid.
+ */
+int JsonDbComponent::remove(const QJSValue &object,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] remove:"<<object.toString();
+
+ return addRequestInfo(mJsonDb->remove(jsValueToQson(object)), JsonDbComponent::Remove, object, successCallback, errorCallback);
+}
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDb::find(string query, int limit, int offset)
+
+ Takes a JsonQuery string, a limit, and an offset, and issues a query to the database.
+ Returns the request uuid.
+ */
+int JsonDbComponent::find(const QJSValue &object,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] find:"<<object.toString();
+
+ return addRequestInfo(mJsonDb->find(jsValueToQson(object)), JsonDbComponent::Find, object, successCallback, errorCallback);
+}
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDb::query(string query)
+
+ Takes a JsonQuery string and issues a query to the database.
+ This function is a simple find function with no limit.
+*/
+int JsonDbComponent::query(const QJSValue &object,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ if (object.isString()) {
+ QJSValue request = object.engine()->newObject();
+ request.setProperty(JsonDbString::kQueryStr, object);
+ request.setProperty(JsonDbString::kLimitStr, -1);
+ request.setProperty(JsonDbString::kOffsetStr, 0);
+ return find(request, successCallback, errorCallback);
+ }
+
+ return find(object, successCallback, errorCallback);
+}
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDb::notification(object query, object actions, object callbackFunction, object errorFunction)
+
+ Takes a JsonQuery string and creates a notification object from it.
+ The callbackFunction will called every time the notification is triggered.
+ The errorFunction is called if the creation of the notification fails.
+*/
+QJSValue JsonDbComponent::notification(const QJSValue &object,
+ const QJSValue &actions,
+ const QJSValue &callback,
+ QJSValue errorCallback)
+{
+ // -- refuse to create notification without callback
+ if (!callback.isFunction()) {
+ qWarning() << "Refusing to create notification without callback.";
+ if (errorCallback.isFunction()) {
+ QJSValueList args;
+ errorCallback.call(QJSValue(), args);
+ }
+ return QJSValue();
+ }
+
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] notification:"<<object.toString();
+
+ int id;
+
+ if (object.isString()) {
+ QJSValue request = object.engine()->newObject();
+ request.setProperty(JsonDbString::kQueryStr, object);
+ request.setProperty(JsonDbString::kTypeStr,
+ JsonDbString::kNotificationTypeStr);
+ request.setProperty(JsonDbString::kActionsStr, actions);
+
+ id = addRequestInfo(mJsonDb->create(jsValueToQson(request)), JsonDbComponent::Notification, object, QJSValue(), errorCallback);
+
+ } else {
+ id = addRequestInfo(mJsonDb->create(jsValueToQson(object)), JsonDbComponent::Notification, object, QJSValue(), errorCallback);
+ }
+
+ if (id <= 0)
+ return QJSValue();
+
+ // -- create notification object
+ JsonDbNotification* notification = new JsonDbNotification(this);
+ notification->mId = id;
+ notification->mCallback = callback;
+ mPendingNotifications.insert(id, notification);
+
+ connect(notification, SIGNAL(removed(int)),
+ this, SLOT(notificationRemoved(int)),
+ Qt::QueuedConnection);
+ connect(notification, SIGNAL(removed(QString)),
+ this, SLOT(notificationRemoved(QString)),
+ Qt::QueuedConnection);
+
+ JsonDbNotificationHandle *handle = new JsonDbNotificationHandle(notification);
+ return callback.engine()->newQObject(handle);
+}
+
+
+void JsonDbComponent::jsonDbResponse(int id, const QsonObject &result)
+{
+ if (mRequests.contains(id)) {
+ JsonDbComponent::RequestInfo &info = mRequests[id];
+
+ QJSEngine *engine = info.object.engine();
+ QJSValue scriptResult = qsonToJSValue(result, engine);
+ if (scriptResult.property(JsonDbString::kUuidStr).isValid())
+ info.object.setProperty(JsonDbString::kUuidStr, scriptResult.property(JsonDbString::kUuidStr));
+ if (scriptResult.property(JsonDbString::kVersionStr).isValid())
+ info.object.setProperty(JsonDbString::kVersionStr, scriptResult.property(JsonDbString::kVersionStr));
+ if (scriptResult.property(JsonDbString::kOwnerStr).isValid())
+ info.object.setProperty(JsonDbString::kOwnerStr, scriptResult.property(JsonDbString::kOwnerStr));
+
+ emit response(scriptResult, id);
+
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] response:" << scriptResult.toString();
+
+ // -- creating the notification object was successfull
+ if (info.type == JsonDbComponent::Notification) {
+ if (mDebugOutput)
+ qDebug() << "successfull created notification with" << scriptResult.property(JsonDbString::kUuidStr).toString();
+
+ // -- finish the notification with the new uuid
+ JsonDbNotification* notification = mPendingNotifications.take(id);
+ if (notification) {
+ // - if the removal was requested before the actual success:
+ // note: at this state the notification object is already deleted
+ if (mKilledNotifications.contains(id)) {
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] kill notification again";
+ notificationRemoved(scriptResult.property(JsonDbString::kUuidStr).toString()); // remove it again
+ mKilledNotifications.remove(id);
+
+ } else {
+ notification->mId = -1;
+ notification->mUuid = scriptResult.property(JsonDbString::kUuidStr).toString();
+ if (mDebugOutput)
+ qDebug() << "finish notification"<<notification->mUuid;
+ mNotifications.insert(notification->mUuid, notification);
+ }
+
+ } else {
+ qWarning() << "Got response for notification that is not pending";
+ }
+ }
+
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] response:" << scriptResult.toString();
+
+ // -- call the success callback function
+ if (info.successCallback.isFunction()) {
+ QJSValueList args;
+ args << scriptResult << info.successCallback.engine()->toScriptValue(id);
+ info.successCallback.call(QJSValue(), args);
+ }
+
+ mRequests.remove(id);
+ }
+}
+void JsonDbComponent::jsonDbErrorResponse(int id, int code, const QString& message)
+{
+ Q_UNUSED(code);
+
+ if (mRequests.contains(id)) {
+ JsonDbComponent::RequestInfo &info = mRequests[id];
+
+ emit error(message, id);
+
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] error:" << message;
+
+ if (info.type == JsonDbComponent::Notification) {
+ // -- creating the notification object was successfull
+ qWarning() << "failed to create notification";
+ mPendingNotifications.remove(id);
+ }
+
+ // -- call the error callback function
+ if (info.errorCallback.isFunction()) {
+ QJSValueList args;
+ args << info.errorCallback.engine()->toScriptValue(message);
+ args << info.errorCallback.engine()->toScriptValue(code);
+ args << info.errorCallback.engine()->toScriptValue(id);
+ info.errorCallback.call(QJSValue(), args);
+ }
+
+ mRequests.remove(id);
+ }
+}
+
+void JsonDbComponent::jsonDbNotified(const QString& notify_uuid, const QsonObject& object, const QString& action)
+{
+ JsonDbNotification* notification = mNotifications.value(notify_uuid);
+ if (notification) {
+ QJSValueList args;
+ args << qsonToJSValue(object, notification->mCallback.engine());
+ args << notification->mCallback.engine()->toScriptValue(action);
+ notification->mCallback.call(QJSValue(), args);
+
+ if (mDebugOutput)
+ qDebug() << "[JSONDB] notification received, Id:" << notify_uuid << "Action : " << action;
+ }
+}
+
+void JsonDbComponent::notificationRemoved(int id)
+{
+ if (mDebugOutput)
+ qDebug() << "[JSONDB2] pending notification removed";
+
+ // ok, we have a pending notification
+ if (mPendingNotifications.contains(id))
+ mKilledNotifications.insert(id);
+}
+
+void JsonDbComponent::notificationRemoved(QString uuid)
+{
+ if (mDebugOutput)
+ qDebug() << "[JSONDB2] notification removed";
+
+ // remove a finished notification
+ QVariantMap arguments;
+ arguments.insert(JsonDbString::kUuidStr, uuid);
+ mJsonDb->remove(arguments);
+
+ mNotifications.remove(uuid);
+}
+
+int JsonDbComponent::addRequestInfo(int id, RequestType type, const QJSValue &object, const QJSValue &successCallback, const QJSValue &errorCallback)
+{
+ if (id < 0) {
+ qWarning() << "Missing database connection";
+ return id;
+ }
+ if (successCallback.isValid() && !successCallback.isFunction())
+ qWarning() << "Success callback parameter "<<successCallback.toString()<<"is not a function.";
+ if (errorCallback.isValid() && !errorCallback.isFunction())
+ qWarning() << "Error callback parameter "<<errorCallback.toString()<<"is not a function.";
+
+ JsonDbComponent::RequestInfo &info = mRequests[id];
+ info.type = type;
+ info.object = object;
+ info.successCallback = successCallback;
+ info.errorCallback = errorCallback;
+
+ return id;
+}
diff --git a/src/imports/jsondb/jsondb-component.h b/src/imports/jsondb/jsondb-component.h
new file mode 100644
index 00000000..cb7f0847
--- /dev/null
+++ b/src/imports/jsondb/jsondb-component.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JsonDbComponent_H
+#define JsonDbComponent_H
+
+#include <QMap>
+#include <QObject>
+#include <QPointer>
+#include <QJSValue>
+#include <QSet>
+
+#include "jsondb-client.h"
+
+class JsonDbComponent;
+class JsonDbNotificationHandle;
+
+Q_USE_JSONDB_NAMESPACE
+
+class JsonDbNotification: public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString uuid READ uuid)
+public:
+ ~JsonDbNotification();
+
+ QString uuid() const { return mUuid; }
+ Q_INVOKABLE void remove();
+
+signals:
+ void notify(const QJSValue& object, const QString& action);
+ void removed(int id);
+ void removed(QString uuid);
+
+private:
+ JsonDbNotification(JsonDbComponent *repo);
+
+ int mId; // the request id
+ QString mUuid; // for a fully created notification, this is the uuid of the db entry
+ QJSValue mCallback;
+
+ friend class JsonDbComponent;
+ friend class JsonDbNotificationHandle;
+};
+
+class JsonDbNotificationHandle: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString uuid READ uuid)
+public:
+ JsonDbNotificationHandle(JsonDbNotification *notification);
+ ~JsonDbNotificationHandle();
+
+ QString uuid() const;
+ Q_INVOKABLE void remove();
+private:
+ QPointer<JsonDbNotification> mNotification;
+};
+
+class JsonDbComponent : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool debug READ hasDebugOutput WRITE setDebugOutput)
+
+public:
+ JsonDbComponent(QObject *parent = 0);
+ virtual ~JsonDbComponent();
+
+ bool hasDebugOutput() const { return mDebugOutput; }
+ void setDebugOutput(bool value) { mDebugOutput = value; }
+
+ Q_INVOKABLE int create(const QJSValue &object,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+ Q_INVOKABLE int update(const QJSValue &object,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+ Q_INVOKABLE int remove(const QJSValue &object,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+ Q_INVOKABLE int find(const QJSValue &object,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+
+ Q_INVOKABLE int query(const QJSValue &object,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+
+ Q_INVOKABLE QJSValue notification(const QJSValue &object,
+ const QJSValue &actions,
+ const QJSValue &callback,
+ QJSValue errorCallback = QJSValue());
+
+ signals:
+ void response(QJSValue result, int id);
+ void error(const QString& message, int id);
+
+ protected slots:
+ void jsonDbResponse(int, const QsonObject &);
+ void jsonDbErrorResponse(int id, int code, const QString &message);
+ void jsonDbNotified(const QString& notify_uuid, const QsonObject& object, const QString& action);
+
+ void notificationRemoved(int id);
+ void notificationRemoved(QString uuid);
+
+ private:
+ enum RequestType { Find, Create, Update, Remove, Notification };
+
+ int addRequestInfo(int id, RequestType type, const QJSValue &object, const QJSValue &successCallback, const QJSValue &errorCallback);
+
+ bool mDebugOutput;
+ JsonDbClient *mJsonDb; // TODO: shouldn't this be a singleton?
+
+ struct RequestInfo {
+ RequestType type;
+ QJSValue object;
+ QJSValue successCallback;
+ QJSValue errorCallback;
+ };
+
+ QMap<int, RequestInfo> mRequests;
+ QMap<int, JsonDbNotification*> mPendingNotifications;
+ QSet<int> mKilledNotifications; // notifications that were removed before they were really created
+ QMap<QString, JsonDbNotification*> mNotifications;
+};
+
+#endif
diff --git a/src/imports/jsondb/jsondb-listmodel.cpp b/src/imports/jsondb/jsondb-listmodel.cpp
new file mode 100644
index 00000000..8add331f
--- /dev/null
+++ b/src/imports/jsondb/jsondb-listmodel.cpp
@@ -0,0 +1,1323 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsondb-listmodel.h"
+#include "jsondb-listmodel_p.h"
+#include "private/jsondb-strings_p.h"
+
+#include <QJSEngine>
+#include <QJSValueIterator>
+
+
+#undef DEBUG_LIST_MODEL
+
+#ifdef DEBUG_LIST_MODEL
+#define DEBUG() qDebug() << Q_FUNC_INFO
+#else
+#define DEBUG() if (0) qDebug() << QString("%1:%2").arg(__FUNCTION__).arg(__LINE__)
+#endif
+
+
+JsonDbListModelPrivate::JsonDbListModelPrivate(JsonDbListModel *q)
+ : q_ptr(q)
+ , chunkSize(40)
+ , lowWaterMark(10)
+ , maxCacheSize(0) // unlimited cache
+ , totalRowCount(0)
+ , cacheStart(0)
+ , cacheEnd(0)
+ , newChunkOffset(0)
+ , totalCountRequestId(-1)
+ , lastFetchedIndex(-1)
+ , requestInProgress(false)
+ , componentComplete(false)
+ , resetModel(true)
+ , updateRecieved(false)
+ , totalRowCountRecieved(false)
+ , state(None)
+ , jsonDbConnection(JsonDbConnection::instance())
+{
+}
+
+void JsonDbListModelPrivate::init()
+{
+ Q_Q(JsonDbListModel);
+ q->connect(&jsonDb, SIGNAL(response(int,QsonObject)),
+ q, SLOT(_q_jsonDbResponse(int,QsonObject)),
+ Qt::QueuedConnection);
+ q->connect(&jsonDb, SIGNAL(error(int,int,QString)),
+ q, SLOT(_q_jsonDbErrorResponse(int,int,QString)),
+ Qt::QueuedConnection);
+ q->connect(&jsonDb, SIGNAL(notified(QString,QsonObject,QString)),
+ q, SLOT(_q_jsonDbNotified(QString,QsonObject,QString)),
+ Qt::QueuedConnection);
+ q->connect(q, SIGNAL(needAnotherChunk(int)), q, SLOT(_q_requestAnotherChunk(int)), Qt::QueuedConnection);
+}
+
+JsonDbListModelPrivate::~JsonDbListModelPrivate()
+{
+ // Why do we need to do this while destroying the object
+ if (!notifyUuid.isEmpty()) {
+ QsonMap notificationObject;
+ notificationObject.insert("_uuid", notifyUuid);
+ jsonDb.remove(notificationObject);
+ }
+}
+
+void JsonDbListModelPrivate::clearCache(int newStart)
+{
+ cacheStart = newStart;
+ cacheEnd = newStart;
+ objectUuids.clear();
+ objectSortValues.clear();
+ data.clear();
+ cachedUuids.clear();
+ lastFetchedItem.clear();
+ lastFetchedIndex = -1;
+}
+
+int JsonDbListModelPrivate::makeSpaceFor(int count, int insertAt)
+{
+ int itemsToRemove = itemsInCache() + count - maxCacheSize;
+ // Check for unlimited cache
+ if (maxCacheSize <= 0)
+ itemsToRemove = 0;
+ int index = 0;
+ int newCacheStart = insertAt;
+ int newCacheEnd = newCacheStart + count;
+ if (newCacheStart == cacheEnd) {
+ // adding elements in the end.
+ } else if (newCacheEnd == cacheStart) {
+ // adding elements in the begining.
+ index = itemsInCache() - itemsToRemove;
+ } else if (newCacheStart >= cacheStart && newCacheEnd <= cacheEnd) {
+ // adding elements within the cached elements
+ // dont remove any, we should ignore duplicates.
+ return 0;
+ } else if (newCacheStart <= cacheStart && newCacheEnd >= cacheEnd) {
+ // new cache will include the current one, so skip it
+ return 0;
+ } else if (newCacheEnd < cacheStart || newCacheStart > cacheEnd) {
+ // we need to invalidate the cache, we only store elements in sequence.
+ itemsToRemove = itemsInCache();
+ clearCache(insertAt);
+ return itemsToRemove;
+ } else if (newCacheEnd < cacheEnd) {
+ // adding items in the begining, with overlap.
+ itemsToRemove -= (newCacheEnd - cacheStart);
+ index = itemsInCache() - itemsToRemove;
+ } else if (newCacheStart > cacheStart) {
+ // adding items towards the end, with overlap
+ itemsToRemove -= (cacheEnd - newCacheStart);
+ }
+ if (itemsToRemove <= 0)
+ return 0;
+ for (int i = 0; i < itemsToRemove; i++) {
+ const QString &uuid = cachedUuids.at(i+index);
+ Q_ASSERT(objectSortValues.contains(uuid));
+ const JsonDbSortKey &key = objectSortValues.value(uuid);
+ Q_ASSERT(objectUuids.contains(key, uuid));
+ objectUuids.remove(key, uuid);
+ objectSortValues.remove(uuid);
+ data.remove(uuid);
+ }
+ QList<QString>::iterator first = cachedUuids.begin()+index;
+ QList<QString>::iterator last = first+itemsToRemove;
+ cachedUuids.erase(first, last);
+
+ if (index > 0)
+ cacheEnd -= itemsToRemove;
+ else
+ cacheStart += itemsToRemove;
+ return itemsToRemove;
+}
+
+JsonDbSortKey JsonDbListModelPrivate::sortKey(const QsonMap &object)
+{
+ return JsonDbSortKey(object, orderDirections, orderPaths);
+}
+
+// removes an item from the cache
+void JsonDbListModelPrivate::removeItem(int index)
+{
+ if (cachedUuids.size() <= index) {
+ qWarning() << "removeItem index not in cache";
+ return;
+ }
+
+ const QString &uuid = cachedUuids[index];
+ const JsonDbSortKey &key = objectSortValues.value(uuid);
+ objectUuids.remove(key, uuid);
+ objectSortValues.remove(uuid);
+ data.remove(uuid);
+ cachedUuids.removeAt(index);
+ cacheEnd = qMax(cacheStart, cacheEnd-1);
+}
+
+// finds the object position within the cache limits
+int JsonDbListModelPrivate::findSortedPosition(const QString& uuid)
+{
+ int pos = 0;
+ QMap<JsonDbSortKey,QString>::const_iterator it;
+ QMap<JsonDbSortKey,QString>::const_iterator end = objectUuids.end();
+ for (it = objectUuids.begin(); it != end; it++, pos++) {
+ if (it.value() == uuid)
+ return pos;
+ }
+ // uuid not found in objectUuids
+ return -1;
+}
+
+// insert item notification handler
+void JsonDbListModelPrivate::insertItem(const QsonMap &item, bool emitSignals)
+{
+ Q_Q(JsonDbListModel);
+ Q_UNUSED(item);
+
+ lastFetchedItem.clear();
+ lastFetchedIndex = -1;
+ clearCache(cacheStart);
+ totalRowCount++;
+ if (emitSignals) {
+ // When a new item is added, the position of the item is not known
+ // to the model. We will clear the cache and notify that an item
+ // is added at the end + all data is changed.
+ QModelIndex parent;
+ q->beginInsertRows(parent, totalRowCount-1, totalRowCount-1);
+ q->endInsertRows();
+ emit q->countChanged();
+ emit q->rowCountChanged();
+ QModelIndex start = q->createIndex(0,0);
+ QModelIndex end = q->createIndex(totalRowCount-1, 0);
+ emit q->dataChanged(start, end);
+ }
+}
+
+// deleteitem notification handler
+void JsonDbListModelPrivate::deleteItem(const QsonMap &item, bool emitSignals)
+{
+ Q_Q(JsonDbListModel);
+
+ lastFetchedItem.clear();
+ lastFetchedIndex = -1;
+ const QString &uuid = item.value("_uuid", QString());
+ int index = cachedUuids.indexOf(uuid);
+ if (index != -1) {
+ // When item is in the cache emit signals using the exact position.
+ QModelIndex parent;
+ if (emitSignals)
+ q->beginRemoveRows(parent, cacheStart+index, cacheStart+index);
+ removeItem(index);
+ totalRowCount = qMax(0, totalRowCount -1);
+ if (emitSignals) {
+ q->endRemoveRows();
+ emit q->countChanged();
+ emit q->rowCountChanged();
+ }
+ } else {
+ // Model dosen't know the position from where the item is deleted.
+ // We will clear the cache and notify that an item is removed
+ // from the end + all data is changed.
+ QModelIndex parent;
+ if (emitSignals)
+ q->beginRemoveRows(parent, totalRowCount, totalRowCount);
+ clearCache(cacheStart);
+ totalRowCount = qMax(0, totalRowCount -1);
+ if (emitSignals) {
+ q->endRemoveRows();
+ emit q->countChanged();
+ emit q->rowCountChanged();
+ QModelIndex start = q->createIndex(0,0);
+ QModelIndex end = q->createIndex((totalRowCount ? totalRowCount-1 :0), 0);
+ emit q->dataChanged(start, end);
+ }
+ }
+}
+
+// updateitem notification handler
+void JsonDbListModelPrivate::updateItem(const QsonMap &item)
+{
+ Q_Q(JsonDbListModel);
+ lastFetchedItem.clear();
+ lastFetchedIndex = -1;
+ const QString &uuid = item.value("_uuid", QString());
+ // if item is currently in cache.
+ if (objectSortValues.contains(uuid)) {
+ int currentIndex = findSortedPosition(uuid);
+ deleteItem(item, false);
+ insertItem(item, false);
+ int newIndex = findSortedPosition(uuid);
+ if (currentIndex == newIndex) {
+ // emit signal for the changed item.
+ QModelIndex modelIndex = q->createIndex(newIndex, 0);
+ emit q->dataChanged(modelIndex, modelIndex);
+ return;
+ }
+ }
+ // We are not sure about the position of the updated item,
+ // clear the cache and notify that all data is changed.
+ clearCache(cacheStart);
+ QModelIndex start = q->createIndex(0,0);
+ QModelIndex end = q->createIndex((totalRowCount ? totalRowCount-1 :0), 0);
+ emit q->dataChanged(start, end);
+}
+
+void JsonDbListModelPrivate::_q_requestAnotherChunk(int offset)
+{
+ if (requestInProgress || query.isEmpty())
+ return;
+ int maxItemsToFetch = chunkSize;
+ if (offset < 0) {
+ maxItemsToFetch += offset;
+ offset = 0;
+ }
+ newChunkOffset = offset;
+ if (newChunkOffset >= cacheStart && newChunkOffset < cacheEnd)
+ newChunkOffset = cacheEnd;
+ // now fetch more
+ QsonMap request;
+ request.insert(JsonDbString::kQueryStr, query);
+ request.insert("offset", newChunkOffset);
+ request.insert("limit", maxItemsToFetch);
+ resetModel = false;
+ requestIds.insert(jsonDb.find(request));
+ requestInProgress = true;
+}
+
+void JsonDbListModelPrivate::fetchChunkSynchronous(int offset)
+{
+ // Ignore previous reqests
+ if (requestInProgress) {
+ requestIds.clear();
+ }
+ Q_ASSERT(!query.isEmpty());
+ int maxItemsToFetch = chunkSize;
+ if (offset < 0) {
+ maxItemsToFetch += offset;
+ offset = 0;
+ }
+ newChunkOffset = offset;
+ if (newChunkOffset >= cacheStart && newChunkOffset < cacheEnd)
+ newChunkOffset = cacheEnd;
+ // now fetch more
+ QsonMap request;
+ request.insert(JsonDbString::kQueryStr, query);
+ request.insert("offset", newChunkOffset);
+ request.insert("limit", maxItemsToFetch);
+ resetModel = false;
+ requestInProgress = true;
+ QsonObject v = jsonDbConnection->sync(JsonDbConnection::makeFindRequest(request));
+ requestInProgress = false;
+ updateCache(v);
+}
+
+void JsonDbListModelPrivate::populateModel()
+{
+ Q_Q(JsonDbListModel);
+ clearCache();
+ updateRecieved = false;
+ totalRowCountRecieved = false;
+ totalRowCount = 0;
+ // Request the total count
+ QsonMap requestCount;
+ QString countQuery = query+"[count]";
+ requestCount.insert(JsonDbString::kQueryStr, countQuery);
+
+ totalCountRequestId = jsonDb.find(requestCount);
+
+ QsonMap requestQuery;
+ //Request at least 2 chunks of data
+ requestQuery.insert(JsonDbString::kQueryStr, query);
+ requestQuery.insert("offset", newChunkOffset);
+ int itemsToGet = chunkSize*2;
+ if (maxCacheSize)
+ itemsToGet = qMin(itemsToGet, maxCacheSize);
+ requestQuery.insert("limit",itemsToGet);
+ resetModel = true;
+ requestIds.insert(jsonDb.find(requestQuery));
+ requestInProgress = true;
+ state = JsonDbListModelPrivate::Querying;
+ emit q->stateChanged();
+}
+
+QVariantMap JsonDbListModelPrivate::getItem(int index, bool handleCacheMiss, bool &cacheMiss)
+{
+ QVariantMap item;
+ if (index < 0 || index >= totalRowCount)
+ return item;
+ if (index < cacheStart || index >= cacheEnd) {
+ DEBUG()<<"Index "<< index<<"Out of Range, fetch more...."<<cacheStart<<cacheEnd;
+ // clear and fetch new set of items
+ if (handleCacheMiss) {
+ // clearing the cache is done by makeSpaceFor()
+ fetchChunkSynchronous(qMax(index-(chunkSize/2), 0));
+ } else {
+ cacheMiss = true;
+ return item;
+ }
+ }
+
+ if (cachedUuids.size() <= (index - cacheStart)) {
+ qWarning() << "Could not get Item";
+ return item;
+ }
+ QString uuid = cachedUuids[index - cacheStart];
+ item = data.value(uuid);
+ if ((lowWaterMark > 0) && (data.size() < totalRowCount)) {
+ if ((cacheEnd - index) < lowWaterMark) {
+ _q_requestAnotherChunk(cacheEnd);
+ } else if (cacheStart && (index - cacheStart) < lowWaterMark) {
+ _q_requestAnotherChunk(qMax(cacheStart-chunkSize, 0));
+ }
+ }
+ cacheMiss = false;
+ lastFetchedItem = item;
+ lastFetchedIndex = index;
+ return item;
+}
+
+QVariantMap JsonDbListModelPrivate::getItem(const QModelIndex &modelIndex, int role,
+ bool handleCacheMiss, bool &cacheMiss)
+{
+ Q_UNUSED(role);
+ return getItem(modelIndex.row(), handleCacheMiss, cacheMiss);
+}
+
+static QVariant lookupProperty(QVariantMap object, const QStringList &path)
+{
+ if (!path.size()) {
+ return QVariant();
+ }
+ QVariantMap emptyMap;
+ QVariantList emptyList;
+ QVariantList objectList;
+ for (int i = 0; i < path.size() - 1; i++) {
+ const QString &key = path.at(i);
+ // this part of the property is a list
+ if (!objectList.isEmpty()) {
+ bool ok = false;
+ int index = key.toInt(&ok);
+ if (ok && (index >= 0) && (objectList.count() > index)) {
+ if (objectList.at(index).type() == QVariant::List) {
+ objectList = objectList.at(index).toList();
+ object = emptyMap;
+ } else {
+ object = objectList.at(index).toMap();
+ objectList = emptyList;
+ }
+ continue;
+ }
+ }
+ // this part is a map
+ if (object.contains(key)) {
+ if (object.value(key).type() == QVariant::List) {
+ objectList = object.value(key).toList();
+ object = emptyMap;
+ } else {
+ object = object.value(key).toMap();
+ objectList = emptyList;
+ }
+ } else {
+ return QVariant();
+ }
+ }
+ const QString &key = path.last();
+ // get the last part from the list
+ if (!objectList.isEmpty()) {
+ bool ok = false;
+ int index = key.toInt(&ok);
+ if (ok && (index >= 0) && (objectList.count() > index)) {
+ return objectList.at(index);
+ }
+ }
+ // if the last part is in a map
+ return object.value(key);
+}
+
+static QVariant lookupProperty(QsonMap object, const QStringList &path)
+{
+ if (!path.size()) {
+ return QVariant();
+ }
+ QsonMap emptyMap;
+ QsonList emptyList;
+ QsonList objectList;
+ for (int i = 0; i < path.size() - 1; i++) {
+ const QString &key = path.at(i);
+ // this part of the property is a list
+ if (!objectList.isEmpty()) {
+ bool ok = false;
+ int index = key.toInt(&ok);
+ if (ok && (index >= 0) && (objectList.count() > index)) {
+ if (objectList.typeAt(index) == QsonObject::ListType) {
+ objectList = objectList.listAt(index);
+ object = emptyMap;
+ } else {
+ object = objectList.objectAt(index);
+ objectList = emptyList;
+ }
+ continue;
+ }
+ }
+ // this part is a map
+ if (object.contains(key)) {
+ if (object.valueType(key) == QsonObject::ListType) {
+ objectList = object.subList(key);
+ object = emptyMap;
+ } else {
+ object = object.subObject(key);
+ objectList = emptyList;
+ }
+ } else {
+ return QVariant();
+ }
+ }
+ const QString &key = path.last();
+ // get the last part from the list
+ if (!objectList.isEmpty()) {
+ bool ok = false;
+ int index = key.toInt(&ok);
+ if (ok && (index >= 0) && (objectList.count() > index)) {
+ if (objectList.typeAt(index) == QsonObject::ListType) {
+ return qsonToVariant(objectList.listAt(index));
+ } else {
+ return qsonToVariant(objectList.objectAt(index));
+ }
+ }
+ }
+ // if the last part is in a map
+ if (object.valueType(key) == QsonObject::ListType)
+ return qsonToVariant(object.subList(key));
+ else
+ return qsonToVariant(object.value<QsonElement>(key));
+}
+
+static QVariantMap updateProperty(QVariantMap item, const QStringList &propertyChain, QVariant value)
+{
+ if (propertyChain.size() < 1) {
+ qCritical() << "updateProperty" << "empty property chain" << item;
+ } else if (propertyChain.size() == 1) {
+ item.insert(propertyChain[0], value.toString());
+ } else {
+ QString property = propertyChain[0];
+ QVariant newChild = updateProperty(item.value(property).toMap(), propertyChain.mid(1), value);
+ item.insert(property, newChild);
+ }
+ return item;
+}
+
+/*!
+ \qmlmodule QtAddOn.JsonDb
+
+ QML interface to Json Database.
+*/
+
+/*!
+ \qmlclass JsonDbListModel
+ \ingroup qml-working-with-data
+ \inqmlmodule QtAddOn.JsonDb
+ \inherits ListModel
+ \since 1.x
+
+ The JsonDbListModel provides a ListModel usable with views such as
+ ListView or GridView displaying data items matching a query.
+
+ \code
+ JsonDbListModel {
+ id: contactsModel
+ query: "[?_type=\"Contact\"]"
+ roleNames: ["firstName", "lastName", "phoneNumber"]
+ }
+ ListView {
+ model: contactsModel
+ Row {
+ spacing: 10
+ Text {
+ text: firstName + " " + lastName
+ }
+ Text {
+ text: phoneNumber
+ }
+ }
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::rowCount
+
+ Returns the number of rows in the model.
+*/
+
+/*!
+ \qmlproperty string QtAddOn.JsonDb::JsonDbListModel::query
+
+ Returns the model's query.
+*/
+
+JsonDbListModel::JsonDbListModel(QObject *parent)
+ : QAbstractListModel(parent), d_ptr(new JsonDbListModelPrivate(this))
+{
+ Q_D(JsonDbListModel);
+ d->init();
+}
+
+JsonDbListModel::~JsonDbListModel()
+{
+}
+
+void JsonDbListModel::classBegin()
+{
+}
+
+void JsonDbListModel::componentComplete()
+{
+ Q_D(JsonDbListModel);
+ d->componentComplete = true;
+ if (!d->query.isEmpty()) {
+ d->populateModel();
+ }
+}
+
+void JsonDbListModelPrivate::createOrUpdateNotification()
+{
+ if (!notifyUuid.isEmpty()) {
+ QsonMap notificationObject;
+ notificationObject.insert("_uuid", notifyUuid);
+ jsonDb.remove(notificationObject);
+ notifyUuid.clear();
+ }
+
+ QsonMap notificationObject;
+ notificationObject.insert(JsonDbString::kTypeStr, JsonDbString::kNotificationTypeStr);
+ notificationObject.insert(JsonDbString::kQueryStr, query);
+ QsonList actions;
+ actions.append(JsonDbString::kCreateStr);
+ actions.append(JsonDbString::kUpdateStr);
+ actions.append(JsonDbString::kRemoveStr);
+ notificationObject.insert(JsonDbString::kActionsStr, actions);
+ notificationObjectRequestIds.insert(jsonDb.create(notificationObject));
+ DEBUG() << notificationObjectRequestIds;
+
+ DEBUG() << notificationObject;
+}
+
+/*!
+ \qmlmethod QtAddOn.JsonDb::JsonDbListModel::sectionIndex(section, successCallback, errorCallback)
+ */
+int JsonDbListModel::sectionIndex(const QString &section,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ Q_D(JsonDbListModel);
+ // Find the count of items "< section"
+ QString sectionCountQueryLT = d->queryWithoutSort+"[?"+d->orderProperties[0]+"<\""+section+"\"][count]";
+ QsonMap request;
+ request.insert(JsonDbString::kQueryStr, sectionCountQueryLT);
+ int id = d->jsonDb.find(request);
+ // Register any valid callbacks
+ CallbackInfo info;
+ if ((successCallback.isValid() && successCallback.isFunction())
+ || (errorCallback.isValid() && errorCallback.isFunction())) {
+ info.successCallback = successCallback;
+ info.errorCallback = errorCallback;
+ d->sectionIndexRequestIds.insert(id, info);
+ }
+ return id;
+}
+
+/*!
+ \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::count
+
+ Returns the number of items in the model.
+*/
+int JsonDbListModel::count() const
+{
+ Q_D(const JsonDbListModel);
+ return d->totalRowCount;
+}
+
+QModelIndex JsonDbListModel::index(int row, int , const QModelIndex &) const
+{
+ return createIndex(row, 0);
+}
+
+int JsonDbListModel::rowCount(const QModelIndex &) const
+{
+ Q_D(const JsonDbListModel);
+ return d->totalRowCount;
+}
+
+QVariant JsonDbListModel::data(const QModelIndex &modelIndex, int role) const
+{
+ Q_D(const JsonDbListModel);
+ QVariantMap item;
+ if (!(d->lastFetchedIndex == modelIndex.row()) || (d->lastFetchedIndex == -1)) {
+ JsonDbListModel * pThis = const_cast<JsonDbListModel *>(this);
+ bool cacheMiss = false;
+ item = pThis->d_func()->getItem(modelIndex, role, true, cacheMiss);
+ } else {
+ item = d->lastFetchedItem;
+ }
+
+ QVariant result;
+ QStringList property = d->properties[role];
+ result = lookupProperty(item, property);
+
+ return result;
+}
+
+void JsonDbListModel::set(int index, const QJSValue& valuemap,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ Q_D(JsonDbListModel);
+ d->set(index, valuemap, successCallback, errorCallback);
+}
+
+void JsonDbListModelPrivate::set(int index, const QJSValue& valuemap,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ Q_Q(JsonDbListModel);
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ qDebug() << q->tr("set: value is not an object");
+ return;
+ }
+ // supports only changing an exixting item.
+ if (index >= totalRowCount || index < 0) {
+ qDebug() << q->tr("set: index %1 out of range").arg(index);
+ return;
+ }
+
+ bool cacheMiss = false;
+ QVariantMap item = getItem(index, false, cacheMiss);
+ if (cacheMiss) {
+ fetchChunkSynchronous(qMax(index-(chunkSize/2), 0));
+ //TODO, do some error checking.
+ item = getItem(index, false, cacheMiss);
+ if (cacheMiss)
+ DEBUG() << "Could not fetch item at index : %1" << index;
+ }
+
+ QJSValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+ int role = q->roleFromString(name);
+ if (role == -1) {
+ qDebug() << q->tr("set: property %1 invalid").arg(name);
+ continue;
+ }
+ item = updateProperty(item, properties[role], v);
+ }
+
+ lastFetchedItem.clear();
+ lastFetchedIndex = -1;
+ // Item will be updated through the update notification
+ CallbackInfo info;
+ info.index = index;
+ int id = jsonDb.update(item); // possibly change to variantToQson(item)..
+ // Register any valid callbacks
+ if ((successCallback.isValid() && successCallback.isFunction())
+ || (errorCallback.isValid() && errorCallback.isFunction())) {
+ info.successCallback = successCallback;
+ info.errorCallback = errorCallback;
+ updateRequestIds.insert(id, info);
+ }
+}
+
+void JsonDbListModel::setProperty(int index, const QString& property, const QVariant& value,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ Q_D(JsonDbListModel);
+ d->setProperty(index, property, value, successCallback, errorCallback);
+}
+
+void JsonDbListModelPrivate::setProperty(int index, const QString& property, const QVariant& value,
+ const QJSValue &successCallback,
+ const QJSValue &errorCallback)
+{
+ Q_Q(JsonDbListModel);
+ // supports only changing an exixting item.
+ if (index >= totalRowCount || index < 0) {
+ qDebug() << q->tr("set: index %1 out of range").arg(index);
+ return;
+ }
+
+ bool cacheMiss = false;
+ QVariantMap item = getItem(index, false, cacheMiss);
+ if (cacheMiss) {
+ fetchChunkSynchronous(qMax(index-(chunkSize/2), 0));
+ //TODO, do some error checking.
+ item = getItem(index, false, cacheMiss);
+ if (cacheMiss)
+ DEBUG() << "Could not fetch item with index : " << index;
+ }
+
+ int role = q->roleFromString(property);
+ if (role == -1) {
+ qDebug() << q->tr("set: property %1 invalid").arg(property);
+ return;
+ }
+ item = updateProperty(item, properties[role], value);
+
+ lastFetchedItem.clear();
+ lastFetchedIndex = -1;
+
+ int id = jsonDb.update(item); // possibly change to variantToQson(item)..
+ // Register any valid callbacks
+ if ((successCallback.isValid() && successCallback.isFunction())
+ || (errorCallback.isValid() && errorCallback.isFunction())) {
+
+ // Item will be updated through the update notification
+ CallbackInfo info;
+ info.index = index;
+ info.successCallback = successCallback;
+ info.errorCallback = errorCallback;
+ updateRequestIds.insert(id, info);
+ }
+}
+
+void JsonDbListModel::fetchMore(const QModelIndex &)
+{
+ DEBUG() << endl;
+}
+
+bool JsonDbListModel::canFetchMore(const QModelIndex &) const
+{
+ DEBUG() << endl;
+ return false;
+}
+
+void JsonDbListModel::setQuery(const QString &newQuery)
+{
+ Q_D(JsonDbListModel);
+
+ const QString oldQuery = d->query;
+ d->query = newQuery;
+ d->state = JsonDbListModelPrivate::Querying;
+ emit stateChanged();
+ if (oldQuery != newQuery) {
+ d->findSortOrder();
+ }
+
+ if (!d->componentComplete)
+ return;
+
+ d->populateModel();
+}
+
+/*!
+ \qmlproperty string QtAddOn.JsonDb::JsonDbListModel::query
+
+ Returns the query used by the model to fetch items from the database.
+
+ In the following example, the \a JsonDbListModel would contain all the objects with \a _type contains the value \a "CONTACT"
+
+ \qml
+ JsonDbListModel {
+ id: listModel
+ query: "[?_type=\"CONTACT\"]"
+ }
+ \endqml
+
+*/
+QString JsonDbListModel::query() const
+{
+ Q_D(const JsonDbListModel);
+ return d->query;
+}
+
+void JsonDbListModel::setLimit(int newLimit)
+{
+ Q_D(JsonDbListModel);
+ d->maxCacheSize = newLimit;
+}
+
+/*!
+ \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::limit
+
+ The number of items to be cached.
+*/
+int JsonDbListModel::limit() const
+{
+ Q_D(const JsonDbListModel);
+ return d->maxCacheSize;
+}
+
+void JsonDbListModel::setChunkSize(int newChunkSize)
+{
+ Q_D(JsonDbListModel);
+ d->chunkSize = newChunkSize;
+}
+
+/*!
+ \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::chunkSize
+
+ The number of items to fetch at a time from the database.
+
+ The model uses a heuristic to fetch only as many items as needed by
+ the view. Each time it requests items it fetches \a chunkSize items.
+*/
+int JsonDbListModel::chunkSize() const
+{
+ Q_D(const JsonDbListModel);
+ return d->chunkSize;
+}
+
+void JsonDbListModel::setLowWaterMark(int newLowWaterMark)
+{
+ Q_D(JsonDbListModel);
+ d->lowWaterMark = newLowWaterMark;
+}
+
+/*!
+ \qmlproperty int QtAddOn.JsonDb::JsonDbListModel::lowWaterMark
+
+ Controls when to fetch more items from the database.
+
+ JsonDbListModel fetch \a chunkSize more items when the associated
+ view requests an item within \a lowWaterMark from the end of the
+ items previously fetched.
+*/
+int JsonDbListModel::lowWaterMark() const
+{
+ Q_D(const JsonDbListModel);
+ return d->lowWaterMark;
+}
+
+
+/*!
+ \qmlproperty ListOrObject QtAddOn.JsonDb::JsonDbListModel::roleNames
+
+ Controls which properties to expose from the objects matching the query.
+
+ Setting \a roleNames to a list of strings causes the model to fetch
+ those properties of the objects and expose them as roles to the
+ delegate for each item viewed.
+
+ \code
+ JsonDbListModel {
+ query: "[?_type=\"MyType\"]"
+ roleNames: ['a', 'b']
+ }
+ ListView {
+ model: listModel
+ Text {
+ text: a + ":" + b
+ }
+ \endcode
+
+ Setting \a roleNames to a dictionary remaps properties in the object
+ to the specified roles in the model.
+
+ In the following example, role \a a would yield the value of
+ property \a aLongName in the objects. Role \a liftedProperty would
+ yield the value of \a o.nested.property for each matching object \a
+ o in the database.
+
+ \code
+ function makeRoleNames() {
+ return { 'a': 'aLongName', 'liftedProperty': 'nested.property' };
+ }
+ JsonDbListModel {
+ id: listModel
+ query: "[?_type=\"MyType\"]"
+ roleNames: makeRoleNames()
+ }
+ ListView {
+ model: listModel
+ Text {
+ text: a + " " + liftedProperty
+ }
+ }
+ \endcode
+*/
+QVariant JsonDbListModel::roleNames() const
+{
+ Q_D(const JsonDbListModel);
+
+ DEBUG() << d->roleMap;
+ return d->roleMap;
+}
+
+QString removeArrayOperator(QString propertyName)
+{
+ propertyName.replace(QLatin1String("["), QLatin1String("."));
+ propertyName.remove(QLatin1Char(']'));
+ return propertyName;
+}
+
+void JsonDbListModel::setRoleNames(const QVariant &vroles)
+{
+ Q_D(JsonDbListModel);
+ d->properties.clear();
+ d->roleNames.clear();
+ if (vroles.type() == QVariant::Map) {
+ QVariantMap roles = vroles.toMap();
+ d->roleMap = roles;
+ int i = 0;
+ for (QVariantMap::const_iterator it = roles.begin(); it != roles.end(); ++it) {
+ d->roleNames.insert(i, it.key().toLatin1());
+ d->properties.insert(i, removeArrayOperator(it.value().toString()).split('.'));
+ i++;
+ }
+ } else {
+ QVariantList roleList = vroles.toList();
+ d->roleMap.clear();
+ for (int i = 0; i < roleList.size(); i++) {
+ QString role = roleList[i].toString();
+ d->roleMap[role] = role;
+ d->roleNames.insert(i, role.toLatin1());
+ d->properties.insert(i, removeArrayOperator(role).split('.'));
+ }
+ }
+ DEBUG() << d->roleNames;
+ QAbstractItemModel::setRoleNames(d->roleNames);
+}
+
+QString JsonDbListModel::state() const
+{
+ Q_D(const JsonDbListModel);
+ switch (d->state) {
+ case JsonDbListModelPrivate::None:
+ return QString("None");
+ case JsonDbListModelPrivate::Querying:
+ return QString("Querying");
+ case JsonDbListModelPrivate::Ready:
+ return QString("Ready");
+ default:
+ return QString("Error");
+ }
+}
+
+QString JsonDbListModel::toString(int role) const
+{
+ Q_D(const JsonDbListModel);
+ if (d->roleNames.contains(role))
+ return QString::fromLatin1(d->roleNames.value(role));
+ else
+ return QString();
+}
+
+int JsonDbListModel::roleFromString(const QString &roleName) const
+{
+ Q_D(const JsonDbListModel);
+ return d->roleNames.key(roleName.toLatin1(), -1);
+}
+
+void JsonDbListModelPrivate::updateCache(const QsonObject &v)
+{
+ Q_Q(JsonDbListModel);
+ QsonMap m = v.toMap();
+ if (m.contains("data")) {
+ QsonList items = m.subList("data");
+ int size = items.size();
+ int sizeAdded = 0;
+ if (size) {
+ DEBUG()<<"OLD Cache Start"<<cacheStart<<"Cache End:"<<cacheEnd;
+ if (resetModel)
+ q->beginResetModel();
+ makeSpaceFor(size, newChunkOffset);
+ bool appendToCache = (newChunkOffset >= cacheEnd) ? true : false;
+ int insertAt = appendToCache ? itemsInCache() : 0;
+ DEBUG()<<"INSERT AT :"<<insertAt<<"Elements Retrieved:"<<size<<"ChunkOffset:"<<newChunkOffset<<appendToCache << itemsInCache();
+ DEBUG()<<"Cache Start"<<cacheStart<<"Cache End:"<<cacheEnd<<"Total Rows = "<<totalRowCount;
+ // Add the new result to cache.
+ for (int i = 0; i < size; i++) {
+ QsonMap item = items.objectAt(i);
+ const QString &uuid = item.value(JsonDbString::kUuidStr, QString());
+ if (objectSortValues.contains(uuid)){
+ break;
+ }
+ JsonDbSortKey key = sortKey(item);
+ objectUuids.insert(key, uuid);
+ objectSortValues.insert(uuid, key);
+ data[uuid] = qsonToVariant(item).toMap();
+ cachedUuids.insert(insertAt++, uuid);
+ sizeAdded++;
+ }
+ DEBUG()<<"sizeAdded:"<<sizeAdded;
+ // Update the cache limits
+ if (!itemsInCache()) {
+ cacheStart = newChunkOffset;
+ cacheEnd = cacheStart + sizeAdded;
+ } else if (appendToCache) {
+ cacheEnd += sizeAdded;
+ } else {
+ cacheStart = qMax(0, cacheStart-sizeAdded);
+ }
+ Q_ASSERT(cachedUuids.count() == data.count());
+ }
+ if (resetModel && totalRowCountRecieved)
+ resetModelFinished();
+ else
+ updateRecieved = true;
+ }
+}
+
+void JsonDbListModelPrivate::_q_jsonDbResponse(int id, const QsonObject &v)
+{
+ if (requestIds.contains(id)) {
+ requestIds.remove(id);
+ requestInProgress = false;
+ updateCache(v);
+ } else if(totalCountRequestId == id) {
+ QsonMap m = v.toMap();
+ QsonList items = m.subList("data");
+ m = items.objectAt(0);
+ totalRowCount = m.valueInt("count");
+ totalRowCountRecieved = true;
+ if (updateRecieved)
+ resetModelFinished();
+ } else if (notificationObjectRequestIds.contains(id)) {
+ notificationObjectRequestIds.remove(id);
+ QsonMap o = v.toMap();
+ notifyUuid = o.value(JsonDbString::kUuidStr, QString());
+ } else if(updateRequestIds.constFind(id) != updateRequestIds.constEnd()) {
+ CallbackInfo info = updateRequestIds.value(id);
+ if (info.successCallback.isFunction()) {
+ QJSValueList args;
+ QJSValue scriptResult = info.successCallback.engine()->toScriptValue(id);
+ args << scriptResult;
+ scriptResult = info.successCallback.engine()->toScriptValue(info.index);
+ args << scriptResult;
+ info.successCallback.call(QJSValue(), args);
+ }
+ updateRequestIds.remove(id);
+ } else if(sectionIndexRequestIds.constFind(id) != sectionIndexRequestIds.constEnd()) {
+ CallbackInfo info = sectionIndexRequestIds.value(id);
+ if (info.successCallback.isFunction()) {
+ QsonMap m = v.toMap();
+ QsonList items = m.subList("data");
+ m = items.objectAt(0);
+ QJSValueList args;
+ QJSValue scriptResult = info.successCallback.engine()->toScriptValue(id);
+ args << scriptResult;
+ scriptResult = info.successCallback.engine()->toScriptValue(m.valueInt("count"));
+ args << scriptResult;
+ info.successCallback.call(QJSValue(), args);
+ }
+ sectionIndexRequestIds.remove(id);
+ }
+}
+
+void JsonDbListModelPrivate::resetModelFinished()
+{
+ Q_Q(JsonDbListModel);
+ q->endResetModel();
+ emit q->countChanged();
+ emit q->rowCountChanged();
+ state = Ready;
+ emit q->stateChanged();
+ resetModel = false;
+ pendingNotifications.clear();
+ createOrUpdateNotification();
+}
+
+bool operator<(const QVariant& a, const QVariant& b)
+{
+ if ((a.type() == QVariant::Int) && (b.type() == QVariant::Int))
+ return a.toInt() < b.toInt();
+ else if ((a.type() == QVariant::Double) && (b.type() == QVariant::Double))
+ return a.toFloat() < b.toFloat();
+ return (QString::compare( a.toString(), b.toString(), Qt::CaseInsensitive ) < 0);
+}
+
+bool operator>(const QVariant& a, const QVariant& b) { return b < a; }
+
+bool JsonDbListModelPrivate::findSortOrder()
+{
+ QRegExp orderMatch("\\[([/\\\\[\\]])[ ]*([^\\[\\]]+)[ ]*\\]");
+ orderDirections.clear();
+ orderProperties.clear();
+ orderPaths.clear();
+ int matchIndex = 0, firstMatch = -1;
+ DEBUG() << query;
+ while ((matchIndex = orderMatch.indexIn(query, matchIndex)) >= 0) {
+ orderDirections << orderMatch.cap(1);
+ orderProperties << orderMatch.cap(2);
+ orderPaths << orderMatch.cap(2).split('.');
+ DEBUG() << matchIndex;
+ if (firstMatch == -1)
+ firstMatch = matchIndex;
+ matchIndex += orderMatch.matchedLength();
+ }
+ queryWithoutSort = query.mid(0,firstMatch);
+ if (orderPaths.isEmpty()) {
+ orderDirections << "/";
+ orderProperties << "_uuid";
+ orderPaths << orderProperties[0].split('.');
+ }
+ DEBUG() << orderDirections << orderProperties << orderPaths;
+ return true;
+}
+
+void JsonDbListModelPrivate::_q_jsonDbNotified(const QString& currentNotifyUuid, const QsonObject &v, const QString &action)
+{
+ if (currentNotifyUuid != notifyUuid) {
+ return;
+ }
+ if (resetModel) {
+ // we have not received the first chunk, wait for it before processing notifications
+ NotifyItem pending;
+ pending.notifyUuid = currentNotifyUuid;
+ pending.item = v;
+ pending.action = action;
+ pendingNotifications.append(pending);
+ return;
+ }
+ const QsonMap &item = v.toMap();
+ if (action == JsonDbString::kCreateStr) {
+ insertItem(item);
+ return ;
+ } else if (action == JsonDbString::kRemoveStr) {
+ deleteItem(item);
+ return ;
+ } else if (action == JsonDbString::kUpdateStr) {
+ updateItem(item);
+ return ;
+ }
+
+}
+
+void JsonDbListModelPrivate::_q_jsonDbErrorResponse(int id, int code, const QString &message)
+{
+ if (requestIds.contains(id)) {
+ requestIds.remove(id);
+ qWarning() << QString("JsonDb error: %1 %2").arg(code).arg(message);
+ } else if(updateRequestIds.constFind(id) != updateRequestIds.constEnd()) {
+ CallbackInfo info = updateRequestIds.value(id);
+ if (info.errorCallback.isFunction()) {
+ QJSValueList args;
+ args << info.errorCallback.engine()->toScriptValue(id);
+ args << info.errorCallback.engine()->toScriptValue(info.index);
+ args << info.errorCallback.engine()->toScriptValue(code);
+ args << info.errorCallback.engine()->toScriptValue(message);
+ info.errorCallback.call(QJSValue(), args);
+ }
+ updateRequestIds.remove(id);
+ }
+}
+
+void JsonDbListModelPrivate::_q_jsonDbErrorResponse(int code, const QString &message)
+{
+ qWarning() << QString("JsonDb error: %1 %2").arg(code).arg(message);
+}
+
+/*!
+ \qmlmethod QVariant JsonDbListModel::get(int idx, const QString &property) const
+ \since 1.x
+*/
+QVariant JsonDbListModel::get(int idx, const QString &property) const
+{
+ int role = roleFromString(property);
+ if (role >= 0)
+ return data(index(idx, 0), role);
+ else
+ return QVariant();
+}
+
+
+class JsonDbSortKeyPrivate : public QSharedData {
+public:
+ JsonDbSortKeyPrivate(QStringList directions, QVariantList keys) : mDirections(directions), mKeys(keys) {}
+ const QStringList &directions() const { return mDirections; }
+ const QVariantList &keys() const { return mKeys; }
+private:
+ QStringList mDirections;
+ QVariantList mKeys;
+ JsonDbSortKeyPrivate(const JsonDbSortKeyPrivate&);
+};
+
+JsonDbSortKey::JsonDbSortKey()
+{
+}
+
+JsonDbSortKey::JsonDbSortKey(const QsonMap &object, const QStringList &directions, const QList<QStringList> &paths)
+{
+ QVariantList keys;
+ for (int i = 0; i < paths.size(); i++)
+ keys.append(lookupProperty(object, paths[i]));
+ d = new JsonDbSortKeyPrivate(directions, keys);
+}
+
+JsonDbSortKey::JsonDbSortKey(const JsonDbSortKey&other)
+ : d(other.d)
+{
+}
+
+const QVariantList &JsonDbSortKey::keys() const { return d->keys(); }
+const QStringList &JsonDbSortKey::directions() const { return d->directions(); }
+
+QString JsonDbSortKey::toString() const
+{
+ QStringList result;
+ for (int i = 0; i < d->keys().size(); i++) {
+ result.append(QString("%1%2")
+ .arg(d->directions()[i])
+ .arg(d->keys()[i].toString()));
+ }
+ return result.join(", ");
+}
+
+bool operator <(const JsonDbSortKey &a, const JsonDbSortKey &b)
+{
+ const QVariantList &akeys = a.keys();
+ const QVariantList &bkeys = b.keys();
+ const QStringList &adirs = a.directions();
+ for (int i = 0; i < akeys.size(); i++) {
+ const QVariant &akey = akeys[i];
+ const QVariant &bkey = bkeys[i];
+ if (akey != bkey) {
+ if (adirs[i] == "/")
+ return akey < bkey;
+ else
+ return akey > bkey;
+ }
+ }
+ return false;
+}
+
+#include "moc_jsondb-listmodel.cpp"
diff --git a/src/imports/jsondb/jsondb-listmodel.h b/src/imports/jsondb/jsondb-listmodel.h
new file mode 100644
index 00000000..370a8373
--- /dev/null
+++ b/src/imports/jsondb/jsondb-listmodel.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JsonDbListModel_H
+#define JsonDbListModel_H
+
+#include <QAbstractListModel>
+#include <QHash>
+#include <QMultiMap>
+#include <QSet>
+#include <QSharedDataPointer>
+#include <QStringList>
+#include <QDeclarativeParserStatus>
+#include <QJSValue>
+#include <QScopedPointer>
+
+#include "jsondb-global.h"
+
+namespace QtAddOn { namespace JsonDb {
+class QsonObject;
+class QsonMap;
+} } // end namespace QtAddOn::JsonDb
+
+Q_USE_JSONDB_NAMESPACE
+
+class JsonDbSortKeyPrivate;
+class JsonDbSortKey {
+public:
+ JsonDbSortKey();
+ JsonDbSortKey(const QsonMap &object, const QStringList &directions, const QList<QStringList> &paths);
+ JsonDbSortKey(const JsonDbSortKey&);
+
+ const QVariantList &keys() const;
+ const QStringList &directions() const;
+ QString toString() const;
+private:
+ QSharedDataPointer<JsonDbSortKeyPrivate> d;
+};
+bool operator <(const JsonDbSortKey &a, const JsonDbSortKey &b);
+
+class JsonDbListModelPrivate;
+
+class JsonDbListModel : public QAbstractListModel, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+public:
+ JsonDbListModel(QObject *parent = 0);
+ virtual ~JsonDbListModel();
+
+ Q_PROPERTY(QString state READ state NOTIFY stateChanged)
+ Q_PROPERTY(QString query READ query WRITE setQuery)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
+ Q_PROPERTY(int limit READ limit WRITE setLimit)
+ Q_PROPERTY(int chunkSize READ chunkSize WRITE setChunkSize)
+ Q_PROPERTY(int lowWaterMark READ lowWaterMark WRITE setLowWaterMark)
+ Q_PROPERTY(QVariant roleNames READ roleNames WRITE setRoleNames)
+
+ virtual void classBegin();
+ virtual void componentComplete();
+ virtual int count() const;
+ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ virtual void fetchMore(const QModelIndex &parent);
+ virtual bool canFetchMore(const QModelIndex &parent) const;
+
+ QVariant roleNames() const;
+ void setRoleNames(const QVariant &roles);
+
+ QString state() const;
+
+ virtual QString toString(int role) const;
+ int roleFromString(const QString &roleName) const;
+
+ QString query() const;
+ void setQuery(const QString &newQuery);
+
+ void setLimit(int newLimit);
+ int limit() const;
+
+ void setChunkSize(int newChunkSize);
+ int chunkSize() const;
+
+ void setLowWaterMark(int newLowWaterMark);
+ int lowWaterMark() const;
+
+ Q_INVOKABLE QVariant get(int idx, const QString &property) const;
+ Q_INVOKABLE void set(int index, const QJSValue &valuemap,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+ Q_INVOKABLE void setProperty(int index, const QString &property, const QVariant &value,
+ const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+ Q_INVOKABLE int sectionIndex(const QString &section, const QJSValue &successCallback = QJSValue(),
+ const QJSValue &errorCallback = QJSValue());
+
+signals:
+ void needAnotherChunk(int offset) const;
+ void stateChanged() const;
+ void countChanged() const;
+ void rowCountChanged() const;
+
+private:
+ Q_DISABLE_COPY(JsonDbListModel)
+ Q_DECLARE_PRIVATE(JsonDbListModel)
+ QScopedPointer<JsonDbListModelPrivate> d_ptr;
+ Q_PRIVATE_SLOT(d_func(), void _q_jsonDbResponse(int, const QsonObject&))
+ Q_PRIVATE_SLOT(d_func(), void _q_jsonDbErrorResponse(int, int, const QString&))
+ Q_PRIVATE_SLOT(d_func(), void _q_jsonDbErrorResponse(int, const QString&))
+ Q_PRIVATE_SLOT(d_func(), void _q_jsonDbNotified(const QString&, const QsonObject&, const QString&))
+ Q_PRIVATE_SLOT(d_func(), void _q_requestAnotherChunk(int))
+
+};
+#endif
diff --git a/src/imports/jsondb/jsondb-listmodel_p.h b/src/imports/jsondb/jsondb-listmodel_p.h
new file mode 100644
index 00000000..e0d13302
--- /dev/null
+++ b/src/imports/jsondb/jsondb-listmodel_p.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDBLISTMODEL_P_H
+#define JSONDBLISTMODEL_P_H
+
+#include <QHash>
+#include <QMultiMap>
+#include <QObject>
+#include <QSet>
+#include <QStringList>
+
+#include "jsondb-client.h"
+#include "private/jsondb-connection_p.h"
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+Q_USE_JSONDB_NAMESPACE
+
+struct CallbackInfo {
+ int index;
+ QJSValue successCallback;
+ QJSValue errorCallback;
+};
+
+struct NotifyItem {
+ QString notifyUuid;
+ QsonObject item;
+ QString action;
+};
+
+class JsonDbListModelPrivate
+{
+ Q_DECLARE_PUBLIC(JsonDbListModel)
+public:
+ JsonDbListModel *q_ptr;
+ int chunkSize;
+ int lowWaterMark;
+ int maxCacheSize;
+ int totalRowCount;
+ int cacheStart;
+ int cacheEnd;
+ int newChunkOffset;
+
+ QSet<int> requestIds;
+ QSet<int> notificationObjectRequestIds;
+ QMap<int, CallbackInfo> updateRequestIds;
+ QMap<int, CallbackInfo> sectionIndexRequestIds;
+ int totalCountRequestId;
+
+ QHash<QString,QVariantMap> data; // cache that holds all the items.
+ QMultiMap<JsonDbSortKey,QString> objectUuids; // sort value -> uuid
+ QMap<QString,JsonDbSortKey> objectSortValues; // uuid -> sort value
+ QList<QString> cachedUuids; // in the correct sort order.
+
+ QStringList orderDirections;
+ QStringList orderProperties;
+ QList<QStringList> orderPaths;
+ QString query;
+ QString queryWithoutSort;
+
+ QVariantMap lastFetchedItem;
+ int lastFetchedIndex;
+
+ bool requestInProgress;
+ bool componentComplete;
+ bool resetModel;
+ bool updateRecieved;
+ bool totalRowCountRecieved;
+
+ QString notifyUuid;
+ QVariantMap roleMap;
+
+ QHash<int,QByteArray> roleNames;
+ QHash<int,QStringList> properties;
+ QList<NotifyItem> pendingNotifications;
+
+ enum State {
+ None,
+ Querying,
+ Ready
+ };
+ State state;
+
+ JsonDbClient jsonDb;
+ JsonDbConnection *jsonDbConnection;
+
+public:
+ JsonDbListModelPrivate(JsonDbListModel *q);
+ ~JsonDbListModelPrivate();
+ void init();
+ void clearCache(int newStart = 0);
+ int makeSpaceFor(int count, int insertAt);
+ void removeItem(int index);
+ int findSortedPosition(const QString& uuid);
+ JsonDbSortKey sortKey(const QsonMap &object);
+ void insertItem(const QsonMap &item, bool emitCountChanged = true);
+ void deleteItem(const QsonMap &item, bool emitCountChanged = true);
+ void updateItem(const QsonMap &item);
+ QVariantMap getItem(int index, bool handleCacheMiss, bool &cacheMiss);
+ QVariantMap getItem(const QModelIndex &modelIndex, int role, bool handleCacheMiss, bool &cacheMiss);
+ void set(int index, const QJSValue& valuemap, const QJSValue &successCallback,
+ const QJSValue &errorCallback);
+ void setProperty(int index, const QString& property, const QVariant& value, const QJSValue &successCallback,
+ const QJSValue &errorCallback);
+
+ void fetchChunkSynchronous(int offset);
+ void updateCache(const QsonObject &v);
+ void resetModelFinished();
+
+ // private slots
+ void _q_jsonDbResponse(int , const QsonObject &);
+ void _q_jsonDbNotified(const QString&, const QsonObject &, const QString &);
+ void _q_jsonDbErrorResponse(int , int, const QString&);
+ void _q_jsonDbErrorResponse(int, const QString&);
+
+ void _q_requestAnotherChunk(int offset);
+
+ void populateModel();
+ void createOrUpdateNotification();
+ bool findSortOrder();
+
+ inline int itemsInCache() { return cacheEnd - cacheStart;}
+};
+
+#endif // JSONDBLISTMODEL_P_H
diff --git a/src/imports/jsondb/jsondb.pro b/src/imports/jsondb/jsondb.pro
new file mode 100644
index 00000000..c3a56a69
--- /dev/null
+++ b/src/imports/jsondb/jsondb.pro
@@ -0,0 +1,33 @@
+TARGET = jsondbplugin
+TARGETPATH = QtJsonDb
+
+include(../qimportbase.pri)
+
+QT += network declarative jsondb-private jsondbqson-private
+
+DESTDIR = $$QT.jsondb.imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+INSTALLS += target qmldir
+
+VERSION = 1.0
+
+include(../../common/common.pri)
+
+HEADERS += \
+ jsondb-listmodel.h \
+ jsondb-listmodel_p.h \
+ jsondb-component.h \
+ plugin.h
+
+HEADERS += $$QSONCONVERSION_HEADERS
+
+SOURCES += \
+ jsondb-listmodel.cpp \
+ jsondb-component.cpp \
+ plugin.cpp
+
+SOURCES += $$QSONCONVERSION_SOURCES
diff --git a/src/imports/jsondb/plugin.cpp b/src/imports/jsondb/plugin.cpp
new file mode 100644
index 00000000..6718477b
--- /dev/null
+++ b/src/imports/jsondb/plugin.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "plugin.h"
+
+#include "jsondb-component.h"
+#include "jsondb-listmodel.h"
+
+Q_EXPORT_PLUGIN2(jsondbplugin, JsonDbPlugin)
+
+static QObject *jsondb_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ JsonDbComponent *component = new JsonDbComponent();
+ return component;
+}
+
+void JsonDbPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+}
+
+void JsonDbPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(uri == QLatin1String("QtJsonDb"));
+ qmlRegisterModuleApi(uri, 1, 0, jsondb_module_api_provider);
+ qmlRegisterType<JsonDbListModel>(uri, 1, 0, "JsonDbListModel");
+ qmlRegisterType<JsonDbComponent>(uri, 1, 0, "JsonDatabase");
+
+}
diff --git a/src/imports/jsondb/plugin.h b/src/imports/jsondb/plugin.h
new file mode 100644
index 00000000..d4c0f7e6
--- /dev/null
+++ b/src/imports/jsondb/plugin.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSONDB_PLUGIN_H
+#define JSONDB_PLUGIN_H
+
+#include <QDeclarativeExtensionPlugin>
+#include <QtDeclarative/qdeclarative.h>
+
+class JsonDbPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+
+public:
+
+ void initializeEngine(QDeclarativeEngine *engine, const char *uri);
+ void registerTypes(const char *uri);
+};
+
+#endif
diff --git a/src/imports/jsondb/qmldir b/src/imports/jsondb/qmldir
new file mode 100644
index 00000000..3af26ba5
--- /dev/null
+++ b/src/imports/jsondb/qmldir
@@ -0,0 +1 @@
+plugin jsondbplugin
diff --git a/src/imports/jsondb/qmldir_debug b/src/imports/jsondb/qmldir_debug
new file mode 100644
index 00000000..b0d452c1
--- /dev/null
+++ b/src/imports/jsondb/qmldir_debug
@@ -0,0 +1 @@
+plugin jsondbplugin_debug
diff --git a/src/imports/qimportbase.pri b/src/imports/qimportbase.pri
new file mode 100644
index 00000000..a7b22870
--- /dev/null
+++ b/src/imports/qimportbase.pri
@@ -0,0 +1,37 @@
+load(qt_module)
+
+TEMPLATE = lib
+CONFIG += qt plugin
+
+win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release
+
+isEmpty(TARGETPATH) {
+ error("qimportbase.pri: You must provide a TARGETPATH!")
+}
+isEmpty(TARGET) {
+ error("qimportbase.pri: You must provide a TARGET!")
+}
+
+mac {
+ contains(CONFIG,debug) {
+ QMLDIRFILE = $${_PRO_FILE_PWD_}/qmldir_debug
+ } else {
+ QMLDIRFILE = $${_PRO_FILE_PWD_}/qmldir
+ }
+} else {
+ QMLDIRFILE = $${_PRO_FILE_PWD_}/qmldir
+}
+copy2build.input = QMLDIRFILE
+copy2build.output = $$QT.jsondb.imports/$$TARGETPATH/qmldir
+!contains(TEMPLATE_PREFIX, vc):copy2build.variable_out = PRE_TARGETDEPS
+copy2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+copy2build.name = COPY ${QMAKE_FILE_IN}
+copy2build.CONFIG += no_link
+# `clean' should leave the build in a runnable state, which means it shouldn't delete qmldir
+copy2build.CONFIG += no_clean
+QMAKE_EXTRA_COMPILERS += copy2build
+
+TARGET = $$qtLibraryTarget($$TARGET)
+contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
+
+CONFIG += qt_targets
diff --git a/src/qson/README.txt b/src/qson/README.txt
new file mode 100644
index 00000000..4e10dac8
--- /dev/null
+++ b/src/qson/README.txt
@@ -0,0 +1,194 @@
+QSON as serialization
+
+Design goals
+
+ * Provide a binary representation of JSON, including objects and arrays
+ * One data format for disk, wire, and memory
+ * Must be able to stream (i.e. a query should not be forced to wait for completion before data can be returned)
+ * Should be iterable (i.e. no complete deserialization necessary)
+ * Provide a document extension to objects to easy JsonDB's handling of such
+
+Core philosophy
+
+Everything is split into packets, there are fixed-sized packets and variable-sized packets
+
+FIXEDPACKET ::= "QSN" char(type) // fixed size implicitly defined by char(type)
+VARIABLEPACKET ::= "Q" char(type) uint16(totalSizeOfPacket) // variable size
+
+Either way, a packet is no more than 64k, the payload is limited to 64k-4bytes.
+
+The current implementation limits strings to 30000 utf-16 encoded characters (60000 bytes). The encoding is chosen to minimize data conversions in the common client-side use cases e.g. javascript and Qt which both use UTF-16 for strings. In the future we might also enforce normalization form.
+
+In the case of object attributes, key and value may be split across pages, where the
+limit applies to key and value individually.
+
+Qson Serialization
+
+The serialization is always little endian!
+
+DOCUMENT_HEADER ::=
+ "QSND"
+ version // storing the last version, 22 bytes
+ uuid // storing the documents UUID, 18 bytes
+
+DOCUMENT_FOOTER ::=
+ "QSNd"
+ version // storing the current version, 22 bytes
+
+OBJECT_HEADER ::=
+ "QSNO"
+
+OBJECT_FOOTER ::=
+ "QSNo"
+
+META_HEADER ::= // can only appear directly following a DOCUMENT_HEADER
+ "QSNM"
+
+META_FOOTER ::=
+ "QSNm"
+
+LIST_HEADER ::=
+ "QSNL"
+
+LIST_FOOTER ::=
+ "QSNl"
+
+ARRAY_VALUE ::=
+ "QA'
+ uint16(sizeofPacket > 4)
+ array
+
+KEY_VALUE ::=
+ "QV'
+ uint16(sizeofPacket > 4)
+ keyValuePairs
+
+value ::=
+ null
+ || false
+ || true
+ || double
+ || uint64
+ || int64
+ || string
+ || version // reported as string
+ || uuid // reported as string
+ || complex value // see next section
+
+null ::= "\x10\x00"
+false ::= "\x20\x00"
+true ::= "\x21\x00"
+double ::= "\x30\x00" IEEE 754-2008 (64bits)
+uint64 ::= "\x31\x00" unsigned 64bits
+int64 ::= "\x32\x00" 64bits
+string ::= "\x40\x00" ustring
+key ::= "\x41\x00" ustring
+version ::= "\x42\x00" unsigned 32bits (updateCount) bin128(md5 hash)
+uuid ::= "\x43\x00" bin128(uuid)
+
+ustring ::= uint16 UTF16 // must fit into one page
+array ::= value array || ""
+keyValuePairs ::= key value keyValuePairs || ""
+
+Complex values in arrays and objects
+
+ * JSON allows objects and arrays as values
+ * In Qson, they are added unmodified
+ * I.e. the previous page ends just before the complex value and is followed by the complex value's pages
+
+Example
+
+{ "hello": ["dear", "world"]}
+
+serializes to (spaces, returns, and " just for readability)
+
+"QSND" // object header
+"QV\x12\x00" // key value page, size=18
+"\x41\x00" "\x0a \x00" "h \x00 e \x00 l \x00 l \x00 o \x00" // key "hello"
+"QSNL" // list header
+ARRAY_VALUE (size = 31)
+"QA\x19\x00" // array value page, size=25
+"\x40\x00" "\x08 \x00" "d \x00 e \x00 a \x00 r \x00" // value "dear"
+"\x40\x00" "\x0a \x00" "w \x00 o \x00 \x00 l \x00 d \x00" // value "world"
+"QSNl" // list footer
+"QSNo" // object footer
+
+JsonDB Documents
+
+A document is an atomic value in JsonDB.
+
+A document is a JSON object, however some attributes have a special behavior.
+
+<verbatim>
+{
+ "_uuid": "" // unique identifier of object
+ "_lastVersion": "" // update count and md5 of last revision
+ "_version": "" // update count and md5 of this revision
+
+ "_meta": {
+ // non-persistent information, not part of the hash
+ // expected to be dropped before persisting in the database
+
+ // defined elements:
+ "ancestors": ["version1",...,"versionX"] // ancestor versions of this version
+ "conflicts": [{}, {}, {}] // conflicting version (i.e. introduced through replication)
+ }
+
+ // content
+}
+</verbatim>
+
+Consequently, the keys "_uuid", "_lastVersion", "_version", and "_meta" are reserved, they can only be present in a document.
+
+In Qson serialization, their values are at fixed positions and their keys are implied.
+
+Hashing algorithm of documents
+
+ * The documents header and footer are skipped
+ * The documents' meta object is skipped, i.e. it's existence and content does not modify the hash
+ * To allow this, the _meta object (if present) must be the very first page after the document's header
+ * The _meta object's key is implied by convention (otherwise a KEY_VALUE page would be required altering the hash)
+ * All other pages are hashed
+ * However ARRAY_VALUE and KEY_VALUE are hashed w/o the first 7 bytes to factor out different paging
+
+Versioning algorithm of documents
+
+ * Blank documents are created with update count and hash set to 0
+ * On computing a version, its hash is compared to the last version's hash
+ * If and only if they differ, the update count is increased by one.
+ * If the last version is blank, it is set to the version
+
+UUID generation algorithm
+
+ * If the document contains a string attribute "_id", a deterministic UUID version 3 is generated from it (see RFC 4122)
+ * "_id" is assumed to be a URI, but not enforced (see RFC 3305)
+ * The UUID version 3 namespace is 6ba7b811-9dad-11d1-80b4-00c04fd430c8 (as defined by RFC 4122)
+ * As same UUID implies same object, it is the user's responsibility to avoid clashes in the _id value
+ * Otherwise, a random UUID version 4 is generated. For slow machines, a version 1 is acceptable.
+
+Conflict management
+
+ * Documents are identified by their UUID, same UUID is *always* same document.
+ * Version numbers are deterministic (as described)
+ * Each document tracks its ancestors in doc._meta.ancestors[] // encoded as "version", not "ustring"
+ * Each document tracks known conflicts in doc._meta.conflicts[] // full objects, less _meta
+ * Versions can be totally ordered by comparing their update count, then string comparing their hash
+
+On merging two documents:
+
+ * Live versions are the two documents and all of their conflicts
+ * A version cannot be live, if its version is contained in the ancestor list of either document
+ * If no live version is left after removing the ancestors, it is considered an attack and the merge is refused
+ * The live version with the highest version number is considered the winner
+ * All losers are stripped of their _meta and put into winner._meta.conflicts[]
+ * All live _lastVersion are set to their respective version, all "lost" _lastVersion are added in winner._meta.ancestors[]
+ * If either winner._meta.ancestor or winner._meta.conflicts is empty, it should not be added
+ * "Deleting" a version is merging with a version where "_type" is set to "Tombstone" by convention
+ * A losing tombstone is removed from the conflict list
+ * Any document can be handed out without _meta included, expect in the case of replication (as its merged by the receiver)
+
+Schema Uniqueness
+
+Some schemas may define uniqueness for its instances. In JsonDB, this is mapped to UUID uniqueness. I.e. on writing such a document, the database will generate a deterministic UUID out of the unique attributes.
+
+Note: Ideally, this is implemented as generating and setting an "_id" value, as this would keep the UUID stable, even if any processor without schema awareness decides to generate a new UUID.
diff --git a/src/qson/qson.cpp b/src/qson/qson.cpp
new file mode 100644
index 00000000..7f12f27e
--- /dev/null
+++ b/src/qson/qson.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qson_p.h"
+
+#include "qvariant.h"
+
+#include "json.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+static int qsonobjectid = qRegisterMetaType<QsonObject>("QsonObject");
+static int qsonmapid = qRegisterMetaType<QsonMap>("QsonMap");
+
+QDebug operator<<(QDebug dbg, const QsonObject &obj)
+{
+ if (obj.type() == QsonObject::MapType) {
+ QsonMap map(obj);
+ if (map.isDocument()) {
+ dbg.nospace() << "QsonDocument(";
+ } else if (map.isMeta()) {
+ dbg.nospace() << "QsonMeta(";
+ } else {
+ dbg.nospace() << "QsonMap(";
+ }
+ } else if (obj.type() == QsonObject::ListType) {
+ dbg.nospace() << "QsonList(";
+ }
+
+ // TODO:
+ dbg << JsonWriter().toString(qsonToVariant(obj));
+
+ dbg.nospace() << ")";
+ return dbg;
+}
+
+static QVariant qsonListItemToVariant(const QsonList &list, int pos);
+static QVariant qsonMapItemToVariant(const QsonMap &map, const QString &key);
+
+static QVariantList qsonListToVariant(const QsonList &list)
+{
+ int count = list.count();
+ QVariantList result;
+ result.reserve(count);
+ for (int i = 0; i < count; ++i)
+ result.append(qsonListItemToVariant(list, i));
+ return result;
+}
+
+static QVariantMap qsonMapToVariant(const QsonMap &map)
+{
+ QVariantMap result;
+ QStringList keys = map.keys();
+ foreach (const QString &key, keys)
+ result.insert(key, qsonMapItemToVariant(map, key));
+ return result;
+}
+
+static QVariant qsonListItemToVariant(const QsonList &list, int pos)
+{
+ switch (list.typeAt(pos)) {
+ case QsonObject::NullType: return QVariant();
+ case QsonObject::BoolType: return list.at<bool>(pos);
+ case QsonObject::IntType: return list.at<qint64>(pos);
+ case QsonObject::UIntType: return list.at<quint64>(pos);
+ case QsonObject::DoubleType: return list.at<double>(pos);
+ case QsonObject::StringType: return list.at<QString>(pos);
+ case QsonObject::ListType: return qsonListToVariant(list.at<QsonList>(pos));
+ case QsonObject::MapType: return qsonMapToVariant(list.at<QsonMap>(pos));
+ default:
+ break;
+ }
+ return QVariant();
+}
+static QVariant qsonMapItemToVariant(const QsonMap &map, const QString &key)
+{
+ switch (map.valueType(key)) {
+ case QsonObject::NullType: return QVariant();
+ case QsonObject::BoolType: return map.value<bool>(key);
+ case QsonObject::IntType: return map.value<qint64>(key);
+ case QsonObject::UIntType: return map.value<quint64>(key);
+ case QsonObject::DoubleType: return map.value<double>(key);
+ case QsonObject::StringType: return map.value<QString>(key);
+ case QsonObject::ListType: return qsonListToVariant(map.value<QsonList>(key));
+ case QsonObject::MapType: return qsonMapToVariant(map.value<QsonMap>(key));
+ default:
+ break;
+ }
+ return QVariant();
+
+}
+
+QVariant qsonToVariant(const QsonObject &object)
+{
+ switch (object.type()) {
+ case QsonObject::ListType:
+ return qsonListToVariant(object.toList());
+ case QsonObject::MapType:
+ return qsonMapToVariant(object.toMap());
+ case QsonObject::StringType:
+ return QsonElement(object).value<QString>();
+ case QsonObject::DoubleType:
+ return QsonElement(object).value<double>();
+ case QsonObject::IntType:
+ return QsonElement(object).value<qint64>();
+ case QsonObject::UIntType:
+ return QsonElement(object).value<quint64>();
+ case QsonObject::BoolType:
+ return QsonElement(object).value<bool>();
+ case QsonObject::NullType:
+ return QVariant();
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+QsonObject variantToQson(const QVariant &object)
+{
+ switch (object.type()) {
+ case QVariant::Map: {
+ QsonMap result;
+ QVariantMap map = object.toMap();
+ foreach (const QString &key, map.keys()) {
+ QsonObject obj = variantToQson(map.value(key));
+ result.insert(key, obj);
+ }
+ return result;
+ }
+ case QVariant::List:
+ case QVariant::StringList: {
+ QsonList result;
+ foreach (const QVariant &v, object.toList()) {
+ QsonObject obj = variantToQson(v);
+ result.append(obj);
+ }
+ return result;
+ }
+ case QVariant::String: {
+ QsonElement result;
+ result.setValue(object.toString());
+ return result;
+ }
+ case QVariant::Double: {
+ QsonElement result;
+ result.setValue(object.toDouble());
+ return result;
+ }
+ case QVariant::LongLong:
+ case QVariant::Int: {
+ QsonElement result;
+ result.setValue(object.toLongLong());
+ return result;
+ }
+ case QVariant::ULongLong:
+ case QVariant::UInt: {
+ QsonElement result;
+ result.setValue(object.toULongLong());
+ return result;
+ }
+ case QVariant::Bool: {
+ QsonElement result;
+ result.setValue(object.toBool());
+ return result;
+ }
+ default:
+ break;
+ }
+ return QsonObject();
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qson.pro b/src/qson/qson.pro
new file mode 100644
index 00000000..f25c6986
--- /dev/null
+++ b/src/qson/qson.pro
@@ -0,0 +1,43 @@
+TEMPLATE = lib
+TARGET = $$QT.jsondbqson.name
+MODULE = jsondbqson
+
+load(qt_module)
+load(qt_module_config)
+
+DESTDIR = $$QT.jsondbqson.libs
+VERSION = $$QT.jsondbqson.VERSION
+DEFINES += QT_ADDON_JSONDB_QSON_LIB
+
+QT = core
+
+CONFIG += module create_prl
+MODULE_PRI = ../../modules/qt_jsondb_qson.pri
+
+include(../3rdparty/qjson/qjson.pri)
+
+HEADERS += \
+ qsonelement_p.h \
+ qson_p.h \
+ qsonlist_p.h \
+ qsonmap_p.h \
+ qsonobject_p.h \
+ qsonpage_p.h \
+ qsonparser_p.h \
+ qsonstrings_p.h \
+ qsonuuid_p.h \
+ qsonversion_p.h \
+
+SOURCES += \
+ qson.cpp \
+ qsonelement.cpp \
+ qsonlist.cpp \
+ qsonmap.cpp \
+ qsonobject.cpp \
+ qsonpage.cpp \
+ qsonparser.cpp \
+ qsonstrings.cpp \
+ qsonuuid.cpp \
+ qsonversion.cpp \
+
+mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$QT.jsondbqson.name
diff --git a/src/qson/qson_p.h b/src/qson/qson_p.h
new file mode 100644
index 00000000..abf2106b
--- /dev/null
+++ b/src/qson/qson_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSON_H
+#define QSON_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonobject_p.h>
+#include <QtJsonDbQson/private/qsonmap_p.h>
+#include <QtJsonDbQson/private/qsonlist_p.h>
+#include <QtJsonDbQson/private/qsonelement_p.h>
+#include <QtJsonDbQson/private/qsonstrings_p.h>
+
+#include <QDebug>
+
+namespace QtAddOn { namespace JsonDb {
+
+template <> inline QsonList QsonMap::value(const QString &key) const
+{ return subList(key); }
+
+template <> inline QsonElement QsonMap::value(const QString &key) const
+{
+ if ((mHeader->type() == QsonPage::DOCUMENT_HEADER_PAGE) && (key == QsonStrings::kLastVersionStr))
+ return QsonElement(QByteArray(mHeader->constData() + 4, 22));
+
+ QsonEntry entry = index()->value(key);
+ switch (entry.pageNumber) {
+ case -2: // QsonStrings::kUuidStr
+ return QsonElement(QByteArray(mHeader->constData() + 26, 18));
+ case -3: // QsonStrings::kVersionStr
+ return QsonElement(QByteArray(mFooter->constData() + 4, 22));
+ default:
+ return QsonElement(mBody, entry);
+ }
+}
+
+template <> inline QsonMap QsonList::at(int pos) const
+{ return objectAt(pos); }
+
+template <> inline QsonElement QsonList::at(int pos) const
+{ return QsonElement(mBody, index()->at(pos)); }
+
+template <> inline QsonMap QsonElement::value() const
+{ return QsonMap(*this); }
+
+template <> inline QsonList QsonElement::value() const
+{ return QsonList(*this); }
+
+Q_ADDON_JSONDB_QSON_EXPORT QDebug operator<<(QDebug debug, const QsonObject &obj);
+
+Q_ADDON_JSONDB_QSON_EXPORT QVariant qsonToVariant(const QsonObject &object);
+Q_ADDON_JSONDB_QSON_EXPORT QsonObject variantToQson(const QVariant &object);
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSON_H
diff --git a/src/qson/qsonelement.cpp b/src/qson/qsonelement.cpp
new file mode 100644
index 00000000..f2aa3987
--- /dev/null
+++ b/src/qson/qsonelement.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonelement_p.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+QsonElement::QsonElement(const QsonContent &body, const QsonEntry &entry)
+{
+ if (entry.pageNumber < 0) {
+ return;
+ }
+
+ if (entry.valueOffset == 0 && entry.valueLength >= 2) {
+ mHeader = body.at(entry.pageNumber);
+ mBody = body.mid(entry.pageNumber + 1, entry.valueLength - 2);
+ mFooter = body.at(entry.pageNumber + entry.valueLength - 1);
+ } else {
+ mBody.append(QsonPagePtr(new QsonPage(body.at(entry.pageNumber)->constData() + entry.valueOffset, entry.valueLength)));
+ }
+}
+
+QsonElement::QsonElement(const QByteArray &content)
+{
+ mBody.append(QsonPagePtr(new QsonPage(content.constData(), content.length())));
+}
+
+bool QsonElement::isNull() const
+{
+ return mBody.value(0)->readNull(0);
+}
+
+void QsonElement::setValue(QsonObject::Special value)
+{
+ if (value != QsonObject::NullValue)
+ return;
+ mBody.clear();
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::UNKNOWN_PAGE)));
+ mBody[0]->writeValue();
+}
+
+void QsonElement::setValue(bool value)
+{
+ mBody.clear();
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::UNKNOWN_PAGE)));
+ mBody[0]->writeValue(value);
+}
+void QsonElement::setValue(qint64 value)
+{
+ mBody.clear();
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::UNKNOWN_PAGE)));
+ mBody[0]->writeValue(value);
+}
+void QsonElement::setValue(quint64 value)
+{
+ mBody.clear();
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::UNKNOWN_PAGE)));
+ mBody[0]->writeValue(value);
+}
+void QsonElement::setValue(double value)
+{
+ mBody.clear();
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::UNKNOWN_PAGE)));
+ mBody[0]->writeValue(value);
+}
+void QsonElement::setValue(const QString &value)
+{
+ mBody.clear();
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::UNKNOWN_PAGE)));
+ mBody[0]->writeValue(value);
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonelement_p.h b/src/qson/qsonelement_p.h
new file mode 100644
index 00000000..aee4b8d1
--- /dev/null
+++ b/src/qson/qsonelement_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONELEMENT_H
+#define QSONELEMENT_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonobject_p.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonElement : public QsonObject
+{
+public:
+ QsonElement() { }
+ QsonElement(const QsonObject &object) : QsonObject(object) { } // ### removeme
+ QsonElement(const QsonContent &body, const QsonEntry &entry);
+ QsonElement(const QByteArray &content);
+
+ inline QsonObject::Type valueType() const
+ { return QsonObject::type(); }
+
+ template <typename T>
+ T value() const;
+
+ void setValue(QsonObject::Special value);
+ void setValue(bool value);
+ void setValue(qint64 value);
+ inline void setValue(qint32 value)
+ { setValue(qint64(value)); }
+ void setValue(quint64 value);
+ inline void setValue(quint32 value)
+ { setValue(quint64(value)); }
+ void setValue(double value);
+ void setValue(const QString &value);
+
+ // declared but not defined.
+ // This function is here only to disambiguate with setValue(quint64) overload
+ Q_DECL_DEPRECATED QsonMap& setValue(const char *value);
+
+ bool isNull() const;
+};
+
+template <> inline bool QsonElement::value() const
+{ return mBody.at(0)->readBool(0); }
+
+template <> inline qint64 QsonElement::value() const
+{ return mBody.at(0)->readInt(0, 0); }
+
+template <> inline quint64 QsonElement::value() const
+{ return mBody.at(0)->readUInt(0, 0); }
+
+template <> inline qint32 QsonElement::value() const
+{ return (qint32)mBody.at(0)->readInt(0, 0); }
+
+template <> inline quint32 QsonElement::value() const
+{ return (quint32)mBody.at(0)->readUInt(0, 0); }
+
+template <> inline double QsonElement::value() const
+{ return mBody.at(0)->readDouble(0, 0); }
+
+template <> inline QString QsonElement::value() const
+{ return mBody.at(0)->readString(0); }
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONELEMENT_H
diff --git a/src/qson/qsonglobal.h b/src/qson/qsonglobal.h
new file mode 100644
index 00000000..ad8c3fed
--- /dev/null
+++ b/src/qson/qsonglobal.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QSON_GLOBAL_H
+#define QSON_GLOBAL_H
+
+#include "qglobal.h"
+
+#if defined(QT_ADDON_JSONDB_QSON_LIB)
+# define Q_ADDON_JSONDB_QSON_EXPORT Q_DECL_EXPORT
+#else
+# define Q_ADDON_JSONDB_QSON_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // JSONDB_GLOBAL_H
diff --git a/src/qson/qsonlist.cpp b/src/qson/qsonlist.cpp
new file mode 100644
index 00000000..4f75bd3a
--- /dev/null
+++ b/src/qson/qsonlist.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonlist_p.h"
+#include "qsonmap_p.h"
+#include "qsonelement_p.h"
+#include "qsonstrings_p.h"
+
+#include <QDebug>
+
+namespace QtAddOn { namespace JsonDb {
+
+/*!
+ \class QtAddOn::JsonDb::QsonList
+ \brief The QsonList class provides methods for accessing the elements of a QsonObject array.
+ \sa QsonMap, QsonList
+*/
+
+QsonList::QsonList(const QsonObject &object)
+{
+ switch (object.type()) {
+ case ListType:
+ mHeader = object.mHeader;
+ mBody = object.mBody;
+ mFooter = object.mFooter;
+ break;
+ default:
+ mHeader = new QsonPage(QsonPage::LIST_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::LIST_FOOTER_PAGE);
+ break;
+ }
+}
+
+int QsonList::size() const
+{
+ return index()->size();
+}
+
+int QsonList::count() const
+{
+ return index()->size();
+}
+
+QsonObject::Type QsonList::typeAt(int pos) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1) {
+ return QsonObject::UnknownType; // should never happen (TM)
+ } else if (entry.valueOffset == 0) {
+ switch (mBody.at(entry.pageNumber)->type()) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ case QsonPage::META_HEADER_PAGE:
+ return QsonObject::MapType;
+ case QsonPage::LIST_HEADER_PAGE:
+ return QsonObject::ListType;
+ default:
+ return QsonObject::UnknownType; // should never happen (TM)
+ }
+ } else {
+ switch (mBody.at(entry.pageNumber)->constData()[entry.valueOffset]) {
+ case QsonPage::NULL_TYPE:
+ return QsonObject::NullType;
+ case QsonPage::TRUE_TYPE:
+ case QsonPage::FALSE_TYPE:
+ return QsonObject::BoolType;
+ case QsonPage::INT_TYPE:
+ return QsonObject::IntType;
+ case QsonPage::UINT_TYPE:
+ return QsonObject::UIntType;
+ case QsonPage::DOUBLE_TYPE:
+ return QsonObject::DoubleType;
+ case QsonPage::STRING_TYPE:
+ case QsonPage::KEY_TYPE:
+ case QsonPage::UUID_TYPE:
+ case QsonPage::VERSION_TYPE:
+ return QsonObject::StringType;
+ default:
+ return QsonObject::UnknownType; // should never happen (TM)
+ }
+ }
+}
+
+bool QsonList::isNull(int pos) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1) {
+ return true;
+ } else if (entry.valueOffset == 0) {
+ return false;
+ } else {
+ return mBody.at(entry.pageNumber)->readNull(entry.valueOffset);
+ }
+}
+
+bool QsonList::boolAt(int pos) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1) {
+ return false;
+ } else if (entry.valueOffset == 0) {
+ return true;
+ } else {
+ return mBody.at(entry.pageNumber)->readBool(entry.valueOffset);
+ }
+}
+
+quint64 QsonList::uintAt(int pos, quint64 fallback) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readUInt(entry.valueOffset, fallback);
+ }
+}
+
+qint64 QsonList::intAt(int pos, qint64 fallback) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readInt(entry.valueOffset, fallback);
+ }
+}
+
+double QsonList::doubleAt(int pos, double fallback) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readDouble(entry.valueOffset, fallback);
+ }
+}
+
+QString QsonList::stringAt(int pos) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return QString();
+ } else {
+ return mBody.at(entry.pageNumber)->readString(entry.valueOffset);
+ }
+}
+
+QStringList QsonList::toStringList() const
+{
+ QStringList result;
+ QsonObject::CachedIndex *idx = index();
+ for (CachedIndex::const_iterator i = idx->constBegin(); i != idx->constEnd(); ++i) {
+ const QsonEntry &entry = *i;
+ if (entry.pageNumber == -1 || entry.valueOffset == 0)
+ continue;
+
+ switch (mBody.at(entry.pageNumber)->constData()[entry.valueOffset]) {
+ case QsonPage::STRING_TYPE:
+ case QsonPage::KEY_TYPE:
+ case QsonPage::UUID_TYPE:
+ case QsonPage::VERSION_TYPE:
+ result.append(mBody.at(entry.pageNumber)->readString(entry.valueOffset));
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+QsonMap QsonList::objectAt(int pos) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1 || entry.valueOffset > 0) {
+ return QsonMap();
+ }
+
+ QsonPagePtr header = mBody.at(entry.pageNumber);
+ switch (header->type()) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ case QsonPage::META_HEADER_PAGE:
+ return QsonMap(mBody.mid(entry.pageNumber, entry.valueLength));
+ default:
+ return QsonMap();
+ }
+}
+
+QsonList QsonList::listAt(int pos) const
+{
+ QsonEntry entry = index()->at(pos);
+ if (entry.pageNumber == -1 || entry.valueOffset > 0) {
+ return QsonMap();
+ }
+
+ QsonPagePtr header = mBody.at(entry.pageNumber);
+ switch (header->type()) {
+ case QsonPage::LIST_HEADER_PAGE:
+ return QsonList(mBody.mid(entry.pageNumber, entry.valueLength));
+ default:
+ return QsonMap();
+ }
+}
+
+QsonList& QsonList::append(QsonObject::Special value)
+{
+ if (value != QsonObject::NullValue)
+ return *this;
+
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!mBody.last()->writeValue()) {
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ mBody.last()->writeValue();
+ }
+ return *this;
+}
+
+QsonList& QsonList::append(bool value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ return *this;
+}
+
+QsonList& QsonList::append(quint64 value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ return *this;
+}
+
+QsonList& QsonList::append(qint64 value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ return *this;
+}
+
+QsonList& QsonList::append(double value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ return *this;
+}
+
+QsonList& QsonList::append(const QString &value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ return *this;
+}
+
+QsonList& QsonList::append(const QsonObject &value)
+{
+ const QsonPage::PageType headerType = value.mHeader->type();
+
+ bool isMeta = (headerType == QsonPage::META_HEADER_PAGE);
+ bool isFullObject = (headerType != QsonPage::EMPTY_PAGE && headerType != QsonPage::UNKNOWN_PAGE);
+
+ CachedIndex::Cleaner cleaner(mIndex);
+ QsonObject::CachedIndex::Cleaner(value.mIndex);
+
+ if (isMeta)
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::OBJECT_HEADER_PAGE)));
+ else if (isFullObject)
+ mBody.append(value.mHeader);
+
+ switch (value.type()) {
+ case QsonObject::ListType:
+ case QsonObject::MapType:
+ mBody.append(value.mBody);
+ break;
+ case QsonObject::NullType:
+ append(QsonObject::NullValue);
+ break;
+ case QsonObject::BoolType:
+ append(QsonElement(value).value<bool>());
+ break;
+ case QsonObject::IntType:
+ append(QsonElement(value).value<qint64>());
+ break;
+ case QsonObject::UIntType:
+ append(QsonElement(value).value<quint64>());
+ break;
+ case QsonObject::DoubleType:
+ append(QsonElement(value).value<double>());
+ break;
+ case QsonObject::StringType:
+ append(QsonElement(value).value<QString>());
+ break;
+ default:
+ if (value.isNull()) {
+ append(QsonObject::NullValue);
+ }
+ break;
+ }
+
+ if (isMeta)
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::OBJECT_FOOTER_PAGE)));
+ else if (isFullObject)
+ mBody.append(value.mFooter);
+
+ return *this;
+}
+
+QsonObject::CachedIndex *QsonList::index() const
+{
+ if (!mIndex.isEmpty())
+ return const_cast<QsonObject::CachedIndex*>(&mIndex);
+
+ // FIXME probably we do not need to generate full index, in most cases we need only one QsonEntry
+ QList<QsonPage::PageType> stack;
+ QsonEntry currentEntry;
+
+ for (int ii = 0; ii < mBody.length(); ii++) {
+ const QsonPage &currentPage = *mBody.at(ii);
+ const QsonPage::PageType type = currentPage.type();
+ if (type == QsonPage::ARRAY_VALUE_PAGE) {
+ if (stack.isEmpty()) {
+ qson_size pageSize = currentPage.dataSize();
+ qson_size pageOffset = 4;
+ while (pageOffset < pageSize) {
+ int valueSize = currentPage.readSize(pageOffset, false);
+ if (valueSize == 0) {
+ qWarning() << "expected value not found in list" << ii << pageOffset << pageSize;
+ mIndex.clear();
+ return &mIndex;
+ } else {
+ currentEntry.pageNumber = ii;
+ currentEntry.valueOffset = pageOffset;
+ currentEntry.valueLength = valueSize;
+ mIndex.append(currentEntry);
+ pageOffset += valueSize;
+ }
+ }
+ } else if (stack.last() != QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << "unexpected array page in object";
+ mIndex.clear();
+ return &mIndex;
+ }
+ } else if (type == QsonPage::OBJECT_HEADER_PAGE) {
+ if (stack.isEmpty()) {
+ currentEntry.pageNumber = ii;
+ currentEntry.valueOffset = 0;
+ }
+ stack.push_back(type);
+ } else if (type == QsonPage::OBJECT_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::OBJECT_HEADER_PAGE) {
+ qWarning() << "unexpected object footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex.append(currentEntry);
+ }
+ } else if (type == QsonPage::LIST_HEADER_PAGE || type == QsonPage::DOCUMENT_HEADER_PAGE) {
+ if (stack.isEmpty()) {
+ currentEntry.pageNumber = ii;
+ currentEntry.valueOffset = 0;
+ }
+ stack.push_back(type);
+ } else if (type == QsonPage::LIST_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << "unexpected list footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex.append(currentEntry);
+ }
+ } else if (type == QsonPage::DOCUMENT_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::DOCUMENT_HEADER_PAGE) {
+ qWarning() << "unexpected document footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex.append(currentEntry);
+ }
+ } else if (type == QsonPage::META_HEADER_PAGE) {
+ if (stack.isEmpty()) {
+ qWarning() << "unexpected meta header in list";
+ mIndex.clear();
+ return &mIndex;
+ }
+ stack.push_back(type);
+ } else if (type == QsonPage::META_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::META_HEADER_PAGE) {
+ qWarning() << "unexpected meta footer in list";
+ }
+ } else if (type == QsonPage::KEY_VALUE_PAGE) {
+ if (stack.isEmpty() || stack.last() == QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << "unexpected key value page in list";
+ mIndex.clear();
+ return &mIndex;
+ }
+ } else {
+ qWarning() << "unexpected page";
+ mIndex.clear();
+ return &mIndex;
+ }
+ }
+
+ return &mIndex;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonlist_p.h b/src/qson/qsonlist_p.h
new file mode 100644
index 00000000..e56e8ed7
--- /dev/null
+++ b/src/qson/qsonlist_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONLIST_H
+#define QSONLIST_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonobject_p.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonList : public QsonObject
+{
+public:
+ QsonList() : QsonObject(QsonObject::ListType) { }
+ QsonList(const QsonObject &object); //### remove me
+
+protected:
+ QsonList(const QsonContent pages) : QsonObject(pages) {}
+
+public:
+ int size() const;
+ int count() const;
+
+ template<typename T>
+ T at(int pos) const;
+
+ QsonObject::Type typeAt(int pos) const;
+ bool isNull(int pos) const;
+ bool boolAt(int pos) const;
+ quint64 uintAt(int pos, quint64 fallback = 0) const;
+ qint64 intAt(int pos, qint64 fallback = 0) const;
+ double doubleAt(int pos, double fallback = 0) const;
+ QString stringAt(int pos) const;
+
+ QsonMap objectAt(int pos) const;
+ QsonList listAt(int pos) const;
+
+ QStringList toStringList() const;
+
+ QsonList& append(QsonObject::Special value);
+ QsonList& append(bool value);
+ QsonList& append(quint64 value);
+ inline QsonList& append(quint32 value)
+ { return append(quint64(value)); }
+ QsonList& append(qint64 value);
+ inline QsonList& append(qint32 value)
+ { return append(qint64(value)); }
+ QsonList& append(double value);
+ QsonList& append(const QString &value);
+ QsonList& append(const QsonObject &value);
+
+ // declared but not defined.
+ // This function is here only to disambiguate with append(quint64) overload
+ Q_DECL_DEPRECATED QsonList& append(const char *value);
+
+#ifndef QT_TESTLIB_LIB
+protected:
+#endif
+ QsonObject::CachedIndex *index() const;
+
+ friend class QsonMap;
+};
+
+template <> inline bool QsonList::at(int pos) const
+{ return boolAt(pos); }
+template <> inline quint64 QsonList::at(int pos) const
+{ return uintAt(pos); }
+template <> inline qint64 QsonList::at(int pos) const
+{ return intAt(pos); }
+template <> inline quint32 QsonList::at(int pos) const
+{ return (quint32)uintAt(pos); }
+template <> inline qint32 QsonList::at(int pos) const
+{ return (qint32)intAt(pos); }
+template <> inline double QsonList::at(int pos) const
+{ return doubleAt(pos); }
+template <> inline QString QsonList::at(int pos) const
+{ return stringAt(pos); }
+template <> inline QsonList QsonList::at(int pos) const
+{ return listAt(pos); }
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONLIST_H
diff --git a/src/qson/qsonmap.cpp b/src/qson/qsonmap.cpp
new file mode 100644
index 00000000..837402c1
--- /dev/null
+++ b/src/qson/qsonmap.cpp
@@ -0,0 +1,958 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonmap_p.h"
+#include "qsonlist_p.h"
+#include "qsonelement_p.h"
+#include "qsonstrings_p.h"
+#include "qsonuuid_p.h"
+#include "qsonversion_p.h"
+
+#include <QUuid>
+#include <QCryptographicHash>
+
+#include <QDebug>
+
+namespace QtAddOn { namespace JsonDb {
+
+/*!
+ \class QtAddOn::JsonDb::QsonMap
+ \brief The QsonMap class provides methods for accessing the elements of a QsonObject.
+ \sa QsonObject, QsonList
+*/
+
+QsonMap::QsonMap(const QsonObject &object)
+{
+ switch (object.type()) {
+ case MapType:
+ mHeader = object.mHeader;
+ mBody = object.mBody;
+ mFooter = object.mFooter;
+ break;
+ default:
+ mHeader = new QsonPage(QsonPage::OBJECT_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::OBJECT_FOOTER_PAGE);
+ break;
+ }
+}
+
+bool QsonMap::isDocument() const
+{
+ return mHeader->type() == QsonPage::DOCUMENT_HEADER_PAGE;
+}
+
+bool QsonMap::isMeta() const
+{
+ return mHeader->type() == QsonPage::META_HEADER_PAGE;
+}
+
+int QsonMap::size() const
+{
+ return index()->size();
+}
+
+QStringList QsonMap::keys() const
+{
+ return index()->keys();
+}
+
+bool QsonMap::contains(const QString &key) const
+{
+ return index()->contains(key);
+}
+
+QsonObject::Type QsonMap::valueType(const QString &key) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -1) {
+ return QsonObject::UnknownType;
+ } else if (entry.pageNumber < -1) {
+ return QsonObject::StringType;
+ } else if (entry.valueOffset == 0) {
+ switch (mBody.at(entry.pageNumber)->type()) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ case QsonPage::META_HEADER_PAGE:
+ return QsonObject::MapType;
+ case QsonPage::LIST_HEADER_PAGE:
+ return QsonObject::ListType;
+ default:
+ Q_ASSERT(false);
+ return QsonObject::UnknownType; // should never happen (TM)
+ }
+ } else {
+ switch (mBody.at(entry.pageNumber)->constData()[entry.valueOffset]) {
+ case QsonPage::NULL_TYPE:
+ return QsonObject::NullType;
+ case QsonPage::TRUE_TYPE:
+ case QsonPage::FALSE_TYPE:
+ return QsonObject::BoolType;
+ case QsonPage::INT_TYPE:
+ return QsonObject::IntType;
+ case QsonPage::UINT_TYPE:
+ return QsonObject::UIntType;
+ case QsonPage::DOUBLE_TYPE:
+ return QsonObject::DoubleType;
+ case QsonPage::STRING_TYPE:
+ case QsonPage::KEY_TYPE:
+ case QsonPage::UUID_TYPE:
+ case QsonPage::VERSION_TYPE:
+ return QsonObject::StringType;
+ default:
+ Q_ASSERT(false);
+ return QsonObject::UnknownType; // should never happen (TM)
+ }
+ }
+}
+
+bool QsonMap::isNull(const QString &key) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -1) {
+ return true;
+ } else if (entry.valueOffset == 0) {
+ return false;
+ } else {
+ return mBody.at(entry.pageNumber)->readNull(entry.valueOffset);
+ }
+}
+
+bool QsonMap::valueBool(const QString &key, bool fallback) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -1) {
+ return fallback;
+ } else if (entry.valueOffset == 0) {
+ return true;
+ } else {
+ return mBody.at(entry.pageNumber)->readBool(entry.valueOffset);
+ }
+}
+
+quint64 QsonMap::valueUInt(const QString &key, quint64 fallback) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -3) { // _version
+ return mFooter->readUInt(4, 0);
+ } else if (entry.pageNumber == -4) { // _lastVersion
+ return mHeader->readUInt(4, 0);
+ } else if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readUInt(entry.valueOffset, fallback);
+ }
+}
+
+qint64 QsonMap::valueInt(const QString &key, qint64 fallback) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -3) { // _version
+ return (qint64) mFooter->readUInt(4, 0);
+ } else if (entry.pageNumber == -4) { // _lastVersion
+ return (qint64) mHeader->readUInt(4, 0);
+ } else if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readInt(entry.valueOffset, fallback);
+ }
+}
+
+double QsonMap::valueDouble(const QString &key, double fallback) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readDouble(entry.valueOffset, fallback);
+ }
+}
+
+QString QsonMap::valueString(const QString &key, const QString &fallback) const
+{
+ if (isDocument() && key == QsonStrings::kLastVersionStr) // make sure we can always read it
+ return mHeader->readString(4);
+
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber == -2) { // _uuid
+ return mHeader->readString(26);
+ } else if (entry.pageNumber == -3) { // _version
+ return mFooter->readString(4);
+ } else if (entry.pageNumber == -4) { // _lastVersion
+ return mHeader->readString(4);
+ } else if (entry.pageNumber == -1 || entry.valueOffset == 0) {
+ return fallback;
+ } else {
+ return mBody.at(entry.pageNumber)->readString(entry.valueOffset);
+ }
+}
+
+QUuid QsonMap::uuid() const
+{
+ if (!isDocument())
+ return QUuid();
+ return mHeader->readUuid(26);
+}
+
+QsonMap QsonMap::subObject(const QString &key) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber < 0 || entry.valueOffset > 0) {
+ return QsonMap();
+ }
+
+ switch (mBody.at(entry.pageNumber)->type()) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ case QsonPage::META_HEADER_PAGE:
+ return QsonMap(mBody.mid(entry.pageNumber, entry.valueLength));
+ default:
+ return QsonMap();
+ }
+}
+
+QsonList QsonMap::subList(const QString &key) const
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber < 0 || entry.valueOffset > 0)
+ return QsonList();
+
+ switch (mBody.at(entry.pageNumber)->type()) {
+ case QsonPage::LIST_HEADER_PAGE:
+ return QsonList(mBody.mid(entry.pageNumber, entry.valueLength));
+ default:
+ return QsonList();
+ }
+}
+
+QsonMap& QsonMap::insert(const QString &key, QsonObject::Special value)
+{
+ if (value != QsonObject::NullValue)
+ return *this;
+
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+ if (!mBody.last()->writeValue()) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue();
+ }
+ }
+ return *this;
+}
+
+QsonMap& QsonMap::insert(const QString &key, bool value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ }
+ return *this;
+}
+
+QsonMap& QsonMap::insert(const QString &key, quint64 value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ }
+ return *this;
+}
+
+QsonMap& QsonMap::insert(const QString &key, qint64 value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ }
+
+ return *this;
+}
+
+QsonMap& QsonMap::insert(const QString &key, double value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ }
+ return *this;
+}
+
+QsonMap& QsonMap::insert(const QString &key, const QString &value)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key, &value)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ }
+ return *this;
+}
+
+QsonMap& QsonMap::insert(const QString &key, const QsonObject &value)
+{
+ if (value.isNull()) {
+ return insert(key, NullValue);
+ } else if (value.type() == QsonObject::StringType) {
+ return insert(key, QsonElement(value).value<QString>());
+ }
+
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!specialHandling(key)) {
+ remove(key);
+ ensurePage(QsonPage::KEY_VALUE_PAGE);
+ if (!mBody.last()->writeKey(key)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeKey(key);
+ }
+
+ const QsonPage::PageType headerType = value.mHeader->type();
+ bool isMeta = headerType == QsonPage::META_HEADER_PAGE;
+
+ if (isMeta)
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::OBJECT_HEADER_PAGE)));
+ else if (headerType != QsonPage::EMPTY_PAGE && headerType != QsonPage::UNKNOWN_PAGE)
+ mBody.append(value.mHeader);
+
+ switch (value.type()) {
+ case QsonObject::ListType:
+ case QsonObject::MapType:
+ mBody.append(value.mBody);
+ break;
+ case QsonObject::BoolType:
+ writeValue(QsonElement(value).value<bool>());
+ break;
+ case QsonObject::IntType:
+ writeValue(QsonElement(value).value<qint64>());
+ break;
+ case QsonObject::UIntType:
+ writeValue(QsonElement(value).value<quint64>());
+ break;
+ case QsonObject::DoubleType:
+ writeValue(QsonElement(value).value<double>());
+ break;
+ default:
+ break;
+ }
+
+ if (isMeta)
+ mBody.append(QsonPagePtr(new QsonPage(QsonPage::OBJECT_FOOTER_PAGE)));
+ else if (value.mFooter->type() != QsonPage::EMPTY_PAGE && value.mFooter->type() != QsonPage::UNKNOWN_PAGE)
+ mBody.append(value.mFooter);
+ } else if (key == QsonStrings::kMetaStr && value.type() == QsonObject::MapType) {
+ ensureDocument();
+ QsonEntry entry = index()->value(QsonStrings::kMetaStr);
+ QsonContent newBody;
+ if (value.mBody.size() > 0) { // only insert, if there is actually content
+ newBody.append(QsonPagePtr(new QsonPage(QsonPage::META_HEADER_PAGE)));
+ newBody.append(value.mBody);
+ newBody.append(QsonPagePtr(new QsonPage(QsonPage::META_FOOTER_PAGE)));
+ }
+ if (entry.pageNumber == -1) {
+ newBody.append(mBody);
+ } else {
+ newBody.append(mBody.mid(entry.valueLength));
+ }
+ mBody = newBody;
+ }
+ return *this;
+}
+
+QsonMap& QsonMap::remove(const QString &key)
+{
+ QsonEntry entry = index()->value(key);
+ if (entry.pageNumber < 0)
+ return *this;
+
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ bool keyInSamePage;
+ int keySize = 4 + (2 * qMin(30000, key.size()));
+
+ if (entry.valueOffset == 0) {
+ mBody.erase(mBody.begin()+entry.pageNumber, mBody.begin()+entry.pageNumber+entry.valueLength);
+ keyInSamePage = false;
+ } else {
+ if (entry.valueOffset-keySize >= 4) {
+ entry.valueOffset -= keySize;
+ entry.valueLength += keySize;
+ keyInSamePage = true;
+ } else {
+ keyInSamePage = false;
+ }
+
+ QsonPagePtr valuePage = mBody[entry.pageNumber];
+
+ if ((valuePage->mOffset - entry.valueLength) > 4) {
+ int cutFromPos = entry.valueOffset;
+ int cutToPos = cutFromPos + entry.valueLength;
+
+ if (cutToPos < valuePage->mOffset)
+ memmove(valuePage->data() + cutFromPos, valuePage->constData() + cutToPos, valuePage->mOffset - cutToPos);
+ valuePage->mOffset -= entry.valueLength;
+ valuePage->updateOffset();
+ mBody[entry.pageNumber] = valuePage;
+ } else {
+ mBody.removeAt(entry.pageNumber);
+ }
+ }
+
+ if (!keyInSamePage && (entry.pageNumber > 0)) { // _meta is page 0 w/o key
+ int keyPageNr = entry.pageNumber - 1;
+ QsonPagePtr keyPage = mBody[keyPageNr];
+ int newSize = keyPage->mOffset - keySize;
+
+ if (newSize == 4) {
+ mBody.removeAt(keyPageNr);
+ } else {
+ keyPage->mOffset = newSize;
+ keyPage->updateOffset();
+ mBody[keyPageNr] = keyPage;
+ }
+ }
+
+ return *this;
+}
+
+void QsonMap::generateUuid()
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (ensureDocument()) {
+ QByteArray uuid;
+ QsonEntry entry = index()->value(QsonStrings::kIdStr);
+ if (entry.pageNumber != -1 && entry.valueOffset > 0) {
+ uuid = QsonUUIDv3(mBody.at(entry.pageNumber)->readString(entry.valueOffset));
+ Q_ASSERT(uuid.size() == 16);
+ } else {
+ uuid = QUuid::createUuid().toRfc4122();
+ Q_ASSERT(uuid.size() == 16);
+ }
+ memcpy(mHeader->data() + 28, uuid.constData(), 16);
+ }
+}
+
+void QsonMap::computeVersion(bool increaseCount)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ ensureDocument();
+ QCryptographicHash md5(QCryptographicHash::Md5);
+
+ int metaCount = 0;
+ foreach (const QsonPagePtr &page, mBody) {
+ switch (page->type()) {
+ case QsonPage::KEY_VALUE_PAGE:
+ case QsonPage::ARRAY_VALUE_PAGE:
+ if (metaCount == 0) {
+ // do not take paging into account, i.e. cut page header off
+ md5.addData(page->constData() + 4, page->dataSize() - 4);
+ }
+ break;
+ case QsonPage::META_HEADER_PAGE:
+ metaCount++;
+ break;
+ case QsonPage::META_FOOTER_PAGE:
+ metaCount--;
+ break;
+ default:
+ if (metaCount == 0) {
+ // every other page needs to go into the hash
+ md5.addData(page->constData(), page->dataSize());
+ }
+ }
+ }
+
+ const char *header = mHeader->constData();
+ char *footer = mFooter->data();
+
+ QByteArray hash = md5.result();
+ QByteArray lastHash(header + 10, 16);
+
+ // write the hash
+ memcpy(footer + 10, hash.constData(), 16);
+
+ quint32 *lastCount = (quint32*) (header + 6);
+ quint32 *count = (quint32*) (footer + 6);
+
+ // increase the count if changed
+ *count = (*lastCount) + ((increaseCount && (hash != lastHash)) ? 1 : 0);
+
+ // make sure, we never generate a 0 version
+ if (*count == 0) {
+ *count = 1;
+ }
+
+ // if first version, set the _lastVersion to _version
+ if (*count == 1) {
+ // only detach now
+ memcpy(mHeader->data() + 6, footer + 6, 20);
+ }
+}
+
+bool QsonMap::mergeVersions(const QsonMap &other, bool isReplication)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+
+ if (!isDocument() || !other.isDocument()) {
+ qWarning() << "merging only supported for documents";
+ return false;
+ }
+ if (valueString(QsonStrings::kUuidStr) != other.valueString(QsonStrings::kUuidStr)) {
+ qWarning() << "merging only supported for matching uuids";
+ return false;
+ }
+
+ QsonVersion thisVersion = QsonVersion::version(*this);
+ QsonVersion otherVersion = QsonVersion::version(other);
+
+ if (!thisVersion.isValid() || !otherVersion.isValid()) {
+ qWarning() << "always make sure to call computeVersion() before mergeVersions()";
+ return false;
+ }
+
+ if (thisVersion == otherVersion) {
+ return false;
+ }
+
+ // make sure recreating a dead object results in a live one
+ if (!isReplication
+ && valueBool(QsonStrings::kDeleted)
+ && !other.valueBool(QsonStrings::kDeleted)
+ && other.valueInt(QsonStrings::kVersionStr) == 1)
+ otherVersion.setUpdateCount(1 + thisVersion.updateCount());
+
+ QsonVersionMap liveVersions;
+ QsonVersionSet ancestorVersions;
+
+ populateMerge(*this, thisVersion, liveVersions, ancestorVersions);
+
+ // let's check for replay
+ if (ancestorVersions.contains(otherVersion)) {
+ return false;
+ }
+ if (liveVersions.keys().contains(otherVersion)) {
+ return false;
+ }
+
+ populateMerge(other, otherVersion, liveVersions, ancestorVersions);
+
+ // remove everything we assume an ancestor
+ foreach (const QsonVersion ancestor, ancestorVersions) {
+ liveVersions.remove(ancestor);
+ }
+
+ // sanity check
+ if (liveVersions.size() == 0) {
+ qWarning() << "no live version left";
+ return false;
+ }
+
+ // select winner
+ QsonMap winner = liveVersions.take(liveVersions.keys().last());
+
+ // now remove all tombstones from conflicts
+ for (QsonVersionMap::iterator ii = liveVersions.begin(); ii != liveVersions.end(); ii++) {
+ if (ii->valueBool(QsonStrings::kDeleted)) {
+ // keep the tombstone only as an ancestor
+ ancestorVersions.insert(QsonVersion::version(*ii));
+ ii = liveVersions.erase(ii);
+ }
+ }
+
+ QsonMap meta;
+ // do we have conflicts?
+ if (liveVersions.size() > 0) {
+ QsonList conflicts;
+ for (QsonVersionMap::iterator ii = liveVersions.begin(); ii != liveVersions.end(); ii++) {
+ // make sure meta is empty in conflicts, TODO: removeMeta()
+ ii->insert(QsonStrings::kMetaStr, meta);
+ // add it to the resulting conflicts object
+ conflicts.append(*ii);
+ }
+ // stick conflicts into _meta
+ meta.insert(QsonStrings::kConflictsStr, conflicts);
+ }
+
+ // do we have ancestors?
+ if (ancestorVersions.size() > 0) {
+ QsonList ancestors;
+ foreach (const QsonVersion ancestor, ancestorVersions) {
+ // add them to the list
+ ancestors.ensurePage(QsonPage::ARRAY_VALUE_PAGE);
+ if (!ancestors.mBody.last()->writeVersion(ancestor)) {
+ ancestors.ensurePage(QsonPage::ARRAY_VALUE_PAGE, true);
+ ancestors.mBody.last()->writeVersion(ancestor);
+ }
+ }
+ // stick the ancestor list into _meta
+ meta.insert(QsonStrings::kAncestorsStr, ancestors);
+ }
+
+ // now stick _meta into the winner
+ winner.insert(QsonStrings::kMetaStr, meta);
+
+ // now we replace ourself by the winner
+ // returning winner is not an option, because return false is "nothing to do"
+ mHeader = winner.mHeader;
+ mBody = winner.mBody;
+ mFooter = winner.mFooter;
+
+ // increase last version, such that computeVersion() actually increases
+ memcpy(mHeader->data() + 6, mFooter->constData() + 6, 20);
+
+ return true;
+}
+
+void QsonMap::populateMerge(const QsonMap &document, const QsonVersion &version, QsonVersionMap &live, QsonVersionSet &ancestors)
+{
+ CachedIndex::Cleaner cleaner(mIndex);
+ QsonVersion lastVersion = QsonVersion::lastVersion(document);
+
+ if (version == QsonVersion::version(document)) {
+ live[version] = document;
+ if (version != lastVersion)
+ ancestors.insert(lastVersion);
+ } else {
+ QsonMap updatedDocument(document);
+ updatedDocument.insert(QsonStrings::kVersionStr, version.toString()); // TODO
+ live[version] = updatedDocument;
+ lastVersion = version;
+ }
+
+ QsonMap meta = document.subObject(QsonStrings::kMetaStr);
+
+ QsonList oldVersions = meta.subList(QsonStrings::kAncestorsStr);
+ QsonObject::CachedIndex *oldIdx = oldVersions.index();
+ CachedIndex::Cleaner cleanerOldIdx(*oldIdx);
+ foreach (const QsonEntry &oldEntry, *oldIdx) {
+ if (oldEntry.valueOffset > 0 && oldEntry.valueLength == 22) {
+ QsonVersion oldVersion(oldVersions.mBody[oldEntry.pageNumber]->constData() + oldEntry.valueOffset);
+ if (oldVersion.isValid())
+ ancestors.insert(oldVersion);
+ }
+ }
+
+ QsonList conflicts = meta.subList(QsonStrings::kConflictsStr);
+ QsonObject::CachedIndex *conflictIdx = conflicts.index();
+ CachedIndex::Cleaner cleanerConflictIdx(*conflictIdx);
+ foreach (const QsonEntry conflictEntry, *conflictIdx) {
+ if (conflictEntry.valueOffset == 0 && conflicts.mBody.at(conflictEntry.pageNumber)->type() == QsonPage::DOCUMENT_HEADER_PAGE) {
+ QsonMap conflictObj(conflicts.mBody.mid(conflictEntry.pageNumber, conflictEntry.valueLength));
+ QsonVersion conflictVersion = QsonVersion::version(conflictObj);
+ if (conflictVersion.isValid()) {
+ QsonVersion cLastVersion = QsonVersion::lastVersion(conflictObj);
+ QsonVersion cVersion = QsonVersion::lastVersion(conflictObj);
+ if (cVersion != cLastVersion) {
+ ancestors.insert(cLastVersion);
+ } else {
+ // make sure to increase the _lastVersion on conflicts
+ memcpy(conflictObj.mHeader->data() + 6, conflictObj.mFooter->constData() + 6, 20);
+ }
+ live[conflictVersion] = conflictObj;
+ }
+ }
+ }
+}
+
+bool QsonMap::ensureDocument()
+{
+ if (mHeader->type() != QsonPage::DOCUMENT_HEADER_PAGE) {
+ mHeader = new QsonPage(QsonPage::DOCUMENT_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::DOCUMENT_FOOTER_PAGE);
+ generateUuid();
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool QsonMap::specialHandling(const QString &key, const QString *value)
+{
+ if (!key.isEmpty() && key.at(0) == QChar::fromLatin1('_')) {
+ if (key == QsonStrings::kUuidStr) {
+ if (value) {
+ ensureDocument();
+ QByteArray uuid = QByteArray::fromHex(value->toLatin1()).leftJustified(16, 0, true);
+ memcpy(mHeader->data() + 28, uuid.constData(), 16);
+ } else {
+ qWarning() << QsonStrings::kUuidStr << "takes a string value, ignoring";
+ }
+ return true;
+ } else if (key == QsonStrings::kLastVersionStr) {
+ if (value) {
+ QsonVersion version = QsonVersion::fromLiteral(*value);
+ if (version.isValid()) {
+ ensureDocument();
+ memcpy(mHeader->data() + 4, version.content().constData(), version.content().size());
+ }
+ }
+ return true;
+ } else if (key == QsonStrings::kVersionStr) {
+ if (value) {
+ QsonVersion version = QsonVersion::fromLiteral(*value);
+ if (version.isValid()) {
+ ensureDocument();
+ // set both _version and _lastVersion
+ memcpy(mHeader->data() + 4, version.content().constData(), version.content().size());
+ memcpy(mFooter->data() + 4, version.content().constData(), version.content().size());
+ }
+ }
+ return true;
+ } else if (key == QsonStrings::kMetaStr) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QsonObject::CachedIndex *QsonMap::index() const
+{
+ if (!mIndex.isEmpty())
+ return const_cast<QsonObject::CachedIndex*>(&mIndex);
+
+ // FIXME probably we do not need to generate full index, in most cases we need only one QsonEntry
+ QList<QsonPage::PageType> stack;
+ bool keyNext = true;
+ QString currentKey;
+ QsonEntry currentEntry;
+
+ for (int ii = 0; ii < mBody.length(); ii++) {
+ const QsonPage &currentPage = *mBody.at(ii);
+ const QsonPage::PageType type = currentPage.type();
+
+ if (type == QsonPage::KEY_VALUE_PAGE) {
+ if (stack.isEmpty()) {
+ qson_size pageSize = currentPage.dataSize();
+ qson_size pageOffset = 4;
+ while (pageOffset < pageSize) {
+ if (keyNext) {
+ int keySize = currentPage.readSize(pageOffset, true);
+ if (keySize == 0) {
+ qWarning() << "expected key not found";
+ mIndex.clear();
+ return &mIndex;
+ } else {
+ currentKey = currentPage.readString(pageOffset);
+ pageOffset += keySize;
+ keyNext = false;
+ }
+ } else {
+ int valueSize = currentPage.readSize(pageOffset, false);
+ if (valueSize == 0) {
+ qWarning() << "expected value not found in map" << currentKey << ii << pageOffset << pageSize;
+ mIndex.clear();
+ return &mIndex;
+ } else {
+ currentEntry.pageNumber = ii;
+ currentEntry.valueOffset = pageOffset;
+ currentEntry.valueLength = valueSize;
+ mIndex[currentKey] = currentEntry;
+ pageOffset += valueSize;
+ keyNext = true;
+ }
+ }
+ }
+ } else if (stack.last() == QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << "unexpected keyvalue page in list";
+ mIndex.clear();
+ return &mIndex;
+ }
+ } else if (type == QsonPage::OBJECT_HEADER_PAGE) {
+ if (stack.isEmpty()) {
+ if (keyNext) {
+ qWarning() << "unexpected object header";
+ mIndex.clear();
+ return &mIndex;
+ } else {
+ currentEntry.pageNumber = ii;
+ currentEntry.valueOffset = 0;
+ }
+ }
+ stack.push_back(type);
+ } else if (type == QsonPage::OBJECT_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::OBJECT_HEADER_PAGE) {
+ qWarning() << "unexpected object footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex[currentKey] = currentEntry;
+ keyNext = true;
+ }
+ } else if (type == QsonPage::LIST_HEADER_PAGE || type == QsonPage::DOCUMENT_HEADER_PAGE) {
+ if (stack.isEmpty()) {
+ if (keyNext) {
+ qWarning() << "unexpected footer";
+ mIndex.clear();
+ return &mIndex;
+ } else {
+ currentEntry.pageNumber = ii;
+ currentEntry.valueOffset = 0;
+ }
+ }
+ stack.push_back(type);
+ } else if (type == QsonPage::LIST_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << "unexpected list footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex[currentKey] = currentEntry;
+ keyNext = true;
+ }
+ } else if (type == QsonPage::DOCUMENT_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::DOCUMENT_HEADER_PAGE) {
+ qWarning() << "unexpected document footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex[currentKey] = currentEntry;
+ keyNext = true;
+ }
+ } else if (type == QsonPage::META_HEADER_PAGE) {
+ if (stack.isEmpty()) {
+ if (ii == 0 && isDocument()) {
+ currentKey = QsonStrings::kMetaStr;
+ currentEntry.pageNumber = 0;
+ currentEntry.valueOffset = 0;
+ } else {
+ qWarning() << "unexpected meta header" << ii << isDocument();
+ mIndex.clear();
+ return &mIndex;
+ }
+ } else if (stack.last() != QsonPage::DOCUMENT_HEADER_PAGE) {
+ qWarning() << "unexpected meta header";
+ mIndex.clear();
+ return &mIndex;
+ }
+ stack.push_back(type);
+ } else if (type == QsonPage::META_FOOTER_PAGE) {
+ if (stack.isEmpty() || stack.takeLast() != QsonPage::META_HEADER_PAGE) {
+ qWarning() << "unexpected meta footer";
+ mIndex.clear();
+ return &mIndex;
+ } else if (stack.isEmpty()) {
+ currentEntry.valueLength = 1 + ii - currentEntry.pageNumber;
+ mIndex[QsonStrings::kMetaStr] = currentEntry;
+ keyNext = true;
+ }
+ } else if (type == QsonPage::ARRAY_VALUE_PAGE) {
+ if (stack.isEmpty() || stack.last() != QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << "unexpected array page in object";
+ mIndex.clear();
+ return &mIndex;
+ }
+ } else {
+ qWarning() << "unexpected page";
+ mIndex.clear();
+ return &mIndex;
+ }
+ }
+
+ if (isDocument()) {
+ mIndex[QsonStrings::kUuidStr] = QsonEntry(-2);
+ mIndex[QsonStrings::kVersionStr] = QsonEntry(-3);
+ quint32 *lastCount = (quint32*) (mHeader->constData() + 6);
+ if ((*lastCount > 0) && memcmp(mHeader->constData() + 10, mFooter->constData() + 10, 16))
+ mIndex[QsonStrings::kLastVersionStr] = QsonEntry(-4);
+ }
+
+ return &mIndex;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonmap_p.h b/src/qson/qsonmap_p.h
new file mode 100644
index 00000000..1de76f38
--- /dev/null
+++ b/src/qson/qsonmap_p.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONMAP_H
+#define QSONMAP_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonobject_p.h>
+#include <QtJsonDbQson/private/qsonversion_p.h>
+
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QMap>
+#include <QSet>
+
+namespace QtAddOn { namespace JsonDb {
+
+typedef QMap<QsonVersion, QsonMap> QsonVersionMap;
+typedef QSet<QsonVersion> QsonVersionSet;
+
+// api similar to QMap
+class Q_ADDON_JSONDB_QSON_EXPORT QsonMap : public QsonObject
+{
+public:
+ QsonMap() : QsonObject(QsonObject::MapType) { }
+ QsonMap(const QsonObject &object); // ### removeme
+
+protected:
+ QsonMap(const QsonContent pages) : QsonObject(pages) {}
+
+public:
+ bool isDocument() const;
+ bool isMeta() const;
+
+ int size() const;
+
+ QStringList keys() const;
+ bool contains(const QString &key) const;
+
+ QsonObject::Type valueType(const QString &key) const;
+ using QsonObject::isNull;
+ bool isNull(const QString &key) const;
+ bool valueBool(const QString &key, bool fallback = false) const;
+ quint64 valueUInt(const QString &key, quint64 fallback = 0) const;
+ qint64 valueInt(const QString &key, qint64 fallback = 0) const;
+ double valueDouble(const QString &key, double fallback = 0) const;
+ QString valueString(const QString &key, const QString &fallback = QString()) const;
+
+ QsonMap subObject(const QString &key) const;
+ QsonList subList(const QString &key) const;
+ template <typename T>
+ T value(const QString &key) const;
+ QUuid uuid() const;
+
+ inline quint64 value(const QString &key, quint64 fallback) const
+ { return valueUInt(key, fallback); }
+ inline qint64 value(const QString &key, qint64 fallback) const
+ { return valueInt(key, fallback); }
+ inline quint32 value(const QString &key, quint32 fallback) const
+ { return (quint32) valueUInt(key, quint64(fallback)); }
+ inline qint32 value(const QString &key, qint32 fallback) const
+ { return (qint32)valueInt(key, qint64(fallback)); }
+ inline double value(const QString &key, double fallback) const
+ { return valueDouble(key, fallback); }
+ inline QString value(const QString &key, const QString &fallback) const
+ { return valueString(key, fallback); }
+
+ QsonMap& insert(const QString &key, QsonObject::Special value);
+ QsonMap& insert(const QString &key, bool value);
+ QsonMap& insert(const QString &key, quint64 value);
+ inline QsonMap& insert(const QString &key, quint32 value)
+ { return insert(key, quint64(value)); }
+ QsonMap& insert(const QString &key, qint64 value);
+ inline QsonMap& insert(const QString &key, qint32 value)
+ { return insert(key, qint64(value)); }
+ QsonMap& insert(const QString &key, double value);
+ QsonMap& insert(const QString &key, const QString &value);
+ QsonMap& insert(const QString &key, const QsonObject &value);
+
+ QsonMap& remove(const QString &key);
+
+ // declared but not defined.
+ // This function is here only to disambiguate with insert(const QString &, quint64) overload
+ Q_DECL_DEPRECATED QsonMap& insert(const QString &key, const char *value);
+
+ bool ensureDocument();
+ void generateUuid();
+ void computeVersion(bool increaseCount = true);
+ bool mergeVersions(const QsonMap &other, bool isReplication = false);
+
+protected:
+ void populateMerge(const QsonMap &document, const QsonVersion &version, QsonVersionMap &live, QsonVersionSet &ancestors);
+ bool specialHandling(const QString &key, const QString *value = 0);
+
+ template<typename T>
+ inline void writeValue(T value)
+ {
+ if (!mBody.last()->writeValue(value)) {
+ ensurePage(QsonPage::KEY_VALUE_PAGE, true);
+ mBody.last()->writeValue(value);
+ }
+ }
+
+ QsonObject::CachedIndex *index() const;
+
+ friend class QsonList;
+ friend class QsonVersion;
+};
+
+template <> inline bool QsonMap::value(const QString &key) const
+{ return valueBool(key); }
+template <> inline quint64 QsonMap::value(const QString &key) const
+{ return valueUInt(key); }
+template <> inline qint64 QsonMap::value(const QString &key) const
+{ return valueInt(key); }
+template <> inline quint32 QsonMap::value(const QString &key) const
+{ return (quint32) valueUInt(key); }
+template <> inline qint32 QsonMap::value(const QString &key) const
+{ return (qint32)valueInt(key); }
+
+template <> inline double QsonMap::value(const QString &key) const
+{ return valueDouble(key); }
+template <> inline QString QsonMap::value(const QString &key) const
+{ return valueString(key); }
+template <> inline QsonMap QsonMap::value(const QString &key) const
+{ return subObject(key); }
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONMAP_H
diff --git a/src/qson/qsonobject.cpp b/src/qson/qsonobject.cpp
new file mode 100644
index 00000000..ac9cdb58
--- /dev/null
+++ b/src/qson/qsonobject.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonobject_p.h"
+#include "qsonmap_p.h"
+#include "qsonlist_p.h"
+
+#include <QDebug>
+
+namespace QtAddOn { namespace JsonDb {
+
+/*!
+ \class QtAddOn::JsonDb::QsonObject
+ \brief The QsonObject class provides binary representation of a JavaScript object.
+ \sa QsonMap, QsonList
+*/
+
+QsonObject::QsonObject() :
+ mHeader(new QsonPage(QsonPage::EMPTY_PAGE)),
+ mFooter(new QsonPage(QsonPage::EMPTY_PAGE))
+{
+}
+
+QsonObject::QsonObject(const QsonContent &pages)
+{
+ mBody = pages;
+ if (pages.size() >= 2) {
+ mHeader = mBody.takeFirst();
+ mFooter = mBody.takeLast();
+ } else {
+ qWarning() << "broken qsonobject";
+ }
+}
+
+QsonObject::QsonObject(Type type)
+{
+ switch (type) {
+ case MapType:
+ mHeader = new QsonPage(QsonPage::OBJECT_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::OBJECT_FOOTER_PAGE);
+ break;
+ case ListType:
+ mHeader = new QsonPage(QsonPage::LIST_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::LIST_FOOTER_PAGE);
+ break;
+ case DocumentType:
+ mHeader = new QsonPage(QsonPage::LIST_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::LIST_FOOTER_PAGE);
+ break;
+ case MetaType:
+ mHeader = new QsonPage(QsonPage::META_HEADER_PAGE);
+ mFooter = new QsonPage(QsonPage::META_FOOTER_PAGE);
+ break;
+ default:
+ mHeader = new QsonPage(QsonPage::EMPTY_PAGE);
+ mFooter = new QsonPage(QsonPage::EMPTY_PAGE);
+ break;
+ }
+}
+
+QsonObject::Type QsonObject::type() const
+{
+ switch (mHeader->type()) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ case QsonPage::META_HEADER_PAGE:
+ return QsonObject::MapType;
+ case QsonPage::LIST_HEADER_PAGE:
+ return QsonObject::ListType;
+ default:
+ if (mBody.size() == 1) {
+ switch (mBody.at(0)->constData()[0]) {
+ case QsonPage::NULL_TYPE:
+ return QsonObject::NullType;
+ case QsonPage::TRUE_TYPE:
+ case QsonPage::FALSE_TYPE:
+ return QsonObject::BoolType;
+ case QsonPage::INT_TYPE:
+ return QsonObject::IntType;
+ case QsonPage::UINT_TYPE:
+ return QsonObject::UIntType;
+ case QsonPage::DOUBLE_TYPE:
+ return QsonObject::DoubleType;
+ case QsonPage::STRING_TYPE:
+ case QsonPage::KEY_TYPE:
+ case QsonPage::UUID_TYPE:
+ case QsonPage::VERSION_TYPE:
+ return QsonObject::StringType;
+ default:
+ break;
+ }
+ }
+ return QsonObject::UnknownType;
+ }
+}
+
+QsonList QsonObject::toList() const
+{
+ return QsonList(*this);
+}
+
+QsonMap QsonObject::toMap() const
+{
+ return QsonMap(*this);
+}
+
+int QsonObject::dataSize() const
+{
+ int size = mHeader->dataSize() + mFooter->dataSize();
+ foreach (const QsonPagePtr &page, mBody)
+ size += page->dataSize();
+ return size;
+}
+
+QByteArray QsonObject::data() const
+{
+ QByteArray result;
+ result.append(mHeader->constData(), mHeader->dataSize());
+ foreach (const QsonPagePtr &page, mBody)
+ result.append(page->constData(), page->dataSize());
+ result.append(mFooter->constData(), mFooter->dataSize());
+ return result;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonobject_p.h b/src/qson/qsonobject_p.h
new file mode 100644
index 00000000..4f05b862
--- /dev/null
+++ b/src/qson/qsonobject_p.h
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONOBJECT_H
+#define QSONOBJECT_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonpage_p.h>
+
+#include <QString>
+#include <QHash>
+#include <QStringList>
+#include <QPair>
+
+namespace QtAddOn { namespace JsonDb {
+
+class QsonList;
+class QsonMap;
+class QsonElement;
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonEntry
+{
+public:
+ QsonEntry()
+ {
+ pageNumber = -1;
+ valueOffset = 0;
+ valueLength = 0;
+ }
+
+ QsonEntry(int special) {
+ pageNumber = special;
+ valueOffset = 0;
+ valueLength = 0;
+ }
+
+ int pageNumber;
+ qson_size valueOffset;
+ int valueLength;
+};
+
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonObject
+{
+#ifndef QT_TESTLIB_LIB
+protected:
+#else
+public:
+#endif
+ // FIXME QHash is not the best container for the cache
+ class CachedIndex : protected QHash<QPair<QString, int>, QsonEntry>
+ {
+ typedef QHash<QPair<QString, int>, QsonEntry> CacheImpl;
+ typedef QPair<QString, int> CacheKeyImpl;
+
+ public:
+ typedef CacheImpl::const_iterator const_iterator;
+ class Cleaner
+ {
+ public:
+ Cleaner(CachedIndex &index)
+ : m_index(index)
+ {}
+
+ ~Cleaner()
+ {
+ // FIXME not always we need to clean the cache. Maybe we should implement incremental
+ // udpates?
+ m_index.clear();
+ }
+ private:
+ CachedIndex &m_index;
+ };
+
+ CachedIndex() {}
+
+ const QsonEntry &at(int i)
+ {
+ Q_ASSERT(i < size());
+ return CacheImpl::operator [](CacheKeyImpl(QString(), i));
+ }
+
+ void clear()
+ {
+ // We use erase here, because it doesn't deallocate internal structures (as clear does)
+ // There is high chance that we will need to recreate this hash in future.
+ CacheImpl::iterator i = CacheImpl::begin();
+ while (i != CacheImpl::end())
+ i = CacheImpl::erase(i);
+ Q_ASSERT(!size());
+ }
+
+ int size() const
+ {
+ return CacheImpl::size();
+ }
+
+ bool isEmpty() const
+ {
+ return !size();
+ }
+
+ void append(const QsonEntry &entry)
+ {
+ Q_ASSERT_X(CacheImpl::isEmpty() || CacheImpl::contains(CacheKeyImpl(QString(), size() - 1))
+ , Q_FUNC_INFO
+ , "Inconsisty in cache detected, this can happen if CachedIndex hasn't been cleaned correctly");
+ CacheImpl::insert(CacheKeyImpl(QString(), size()), entry);
+ }
+
+ const_iterator constBegin() const
+ {
+ return CacheImpl::constBegin();
+ }
+
+ const_iterator begin() const
+ {
+ return CacheImpl::begin();
+ }
+
+ const_iterator constEnd() const
+ {
+ return CacheImpl::constEnd();
+ }
+
+ const_iterator end() const
+ {
+ return CacheImpl::end();
+ }
+
+ QStringList keys() const
+ {
+ QStringList result;
+ foreach (const CacheKeyImpl &key, CacheImpl::keys())
+ result.append(key.first);
+ return result;
+ }
+
+ bool contains(const QString &key) const
+ {
+ return CacheImpl::contains(CacheKeyImpl(key, -1));
+ }
+
+ const QsonEntry value(const QString &key) const
+ {
+ return CacheImpl::value(CacheKeyImpl(key, -1));
+ }
+
+ QsonEntry &operator[](const QString &key)
+ {
+ return CacheImpl::operator [](CacheKeyImpl(key, -1));
+ }
+ };
+
+public:
+ enum Type {
+ UnknownType,
+ ListType,
+ MapType,
+ DocumentType,
+ MetaType,
+
+ NullType,
+ BoolType,
+ IntType, // qint64
+ UIntType, // quint64
+ DoubleType,
+ StringType
+ };
+
+ QsonObject();
+ explicit QsonObject(Type type);
+
+ enum Special { NullValue = NullType }; // alias to NullType just to avoid typos
+
+protected:
+ QsonObject(const QsonContent &pages);
+
+public:
+ bool isNull() const
+ {
+ return mBody.isEmpty() && mHeader->type() == QsonPage::EMPTY_PAGE;
+ }
+ bool isEmpty() const
+ {
+ return mBody.isEmpty() && (mHeader->type() != QsonPage::DOCUMENT_HEADER_PAGE);
+ }
+
+ Type type() const;
+
+ QsonList toList() const;
+ QsonMap toMap() const;
+
+ int dataSize() const;
+ QByteArray data() const;
+
+ inline bool operator==(const QsonObject &other) const
+ {
+ if (*mHeader != *other.mHeader)
+ return false;
+ if (mBody.size() != other.mBody.size())
+ return false;
+ for (int i = 0; i < mBody.size(); ++i)
+ if (*mBody.at(i) != *other.mBody.at(i))
+ return false;
+ if (*mFooter != *other.mFooter)
+ return false;
+ return true;
+ }
+ inline bool operator!=(const QsonObject &other) const
+ {
+ return !operator==(other);
+ }
+
+#ifndef QT_TESTLIB_LIB
+protected:
+#endif
+ inline void ensurePage(QsonPage::PageType type, bool force = false)
+ {
+ if (mBody.isEmpty() || force || mBody.last()->type() != type) {
+ mBody.append(QsonPagePtr(new QsonPage(type)));
+ }
+ }
+
+ QSharedDataPointer<QsonPage> mHeader;
+ QsonContent mBody;
+ QSharedDataPointer<QsonPage> mFooter;
+ mutable CachedIndex mIndex;
+
+ friend class QsonList;
+ friend class QsonMap;
+ friend class QsonParser;
+ friend class QsonStream;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONOBJECT_H
diff --git a/src/qson/qsonpage.cpp b/src/qson/qsonpage.cpp
new file mode 100644
index 00000000..446a848b
--- /dev/null
+++ b/src/qson/qsonpage.cpp
@@ -0,0 +1,615 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonpage_p.h"
+
+#include <string.h>
+
+#include <QStringBuilder>
+#include <QDebug>
+#include <QUuid>
+#include <qendian.h>
+
+namespace QtAddOn { namespace JsonDb {
+
+QsonPage::QsonPage()
+ : mOwnsData(false)
+ , mMaxSize(0)
+ , mOffset(0)
+ , mPage(0)
+{}
+
+QsonPage::QsonPage(PageType type)
+ : mOwnsData(true)
+{
+ switch(type) {
+ case EMPTY_PAGE:
+ mMaxSize = 0;
+ mOffset = 0;
+ mPage = 0;
+ return;
+ case OBJECT_HEADER_PAGE:
+ case OBJECT_FOOTER_PAGE:
+ case LIST_HEADER_PAGE:
+ case LIST_FOOTER_PAGE:
+ mMaxSize = 4;
+ mOffset = mMaxSize;
+ break;
+ case DOCUMENT_FOOTER_PAGE:
+ mMaxSize = 26;
+ mOffset = mMaxSize;
+ break;
+ case DOCUMENT_HEADER_PAGE:
+ mMaxSize = 44;
+ mOffset = mMaxSize;
+ break;
+ default:
+ mMaxSize = 65535; // qson_size::max or something?
+ mOffset = 4;
+ }
+
+ // reserve memory
+ mPage = (char*) malloc(mMaxSize);
+
+ // initialize the page
+ switch (type) {
+ case UNKNOWN_PAGE:
+ mOffset = 0;
+ break;
+ case KEY_VALUE_PAGE:
+ case ARRAY_VALUE_PAGE:
+ mPage[0] = 'Q';
+ mPage[1] = type;
+ memcpy(mPage+2, &mOffset, 2);
+ break;
+ default:
+ memcpy(mPage, "QSN", 3);
+ mPage[3] = (char) type;
+ memset(mPage + 4, 0, mMaxSize - 4);
+ }
+ switch (type) {
+ case DOCUMENT_HEADER_PAGE:
+ mPage[26] = UUID_TYPE;
+ mPage[27] = 0;
+ // no break
+ case DOCUMENT_FOOTER_PAGE:
+ mPage[4] = VERSION_TYPE;
+ mPage[5] = 0;
+ default:
+ break;
+ }
+}
+
+QsonPage::QsonPage(const char* data, qson_size size)
+ : mOwnsData(true)
+ , mMaxSize(size)
+ , mPage((char*) malloc(size))
+{
+ memcpy(mPage, data, size);
+
+ switch (type()) {
+ case QsonPage::UNKNOWN_PAGE:
+ break;
+ case KEY_VALUE_PAGE:
+ case ARRAY_VALUE_PAGE:
+ memcpy(&mMaxSize, mPage + 2, 2);
+ if (mMaxSize > size) {
+ mMaxSize = size;
+ }
+ break;
+ case DOCUMENT_HEADER_PAGE:
+ mMaxSize = 44;
+ break;
+ case DOCUMENT_FOOTER_PAGE:
+ mMaxSize = 26;
+ break;
+ default:
+ mMaxSize = 4;
+ break;
+ }
+ mOffset = mMaxSize;
+}
+
+QsonPage::QsonPage(const QsonPage &copy)
+ : QSharedData(copy)
+ , mOwnsData(true)
+ , mMaxSize(copy.mMaxSize)
+ , mOffset(copy.mOffset)
+{
+ if (mMaxSize > 0) {
+ mPage = (char*) malloc(mMaxSize);
+ memcpy(mPage, copy.mPage, mMaxSize);
+ } else {
+ mPage = 0;
+ }
+}
+
+QsonPage::~QsonPage()
+{
+ if (mOwnsData) {
+ free(mPage);
+ }
+}
+
+QsonPage::PageType QsonPage::type() const
+{
+ if (mPage == 0) {
+ return QsonPage::EMPTY_PAGE;
+ }
+
+ if (mMaxSize < 4) {
+ return QsonPage::UNKNOWN_PAGE;
+ }
+
+ if (mPage[0] != 'Q') {
+ return QsonPage::UNKNOWN_PAGE;
+ }
+
+ switch (mPage[1]) {
+ case QsonPage::KEY_VALUE_PAGE:
+ return QsonPage::KEY_VALUE_PAGE;
+ case QsonPage::ARRAY_VALUE_PAGE:
+ return QsonPage::ARRAY_VALUE_PAGE;
+ case 'S':
+ break;
+ default:
+ return QsonPage::UNKNOWN_PAGE;
+ }
+
+ if (mPage[2] != 'N') {
+ return QsonPage::UNKNOWN_PAGE;
+ }
+
+ switch (mPage[3]) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ return QsonPage::OBJECT_HEADER_PAGE;
+ case QsonPage::OBJECT_FOOTER_PAGE:
+ return QsonPage::OBJECT_FOOTER_PAGE;
+ case QsonPage::LIST_HEADER_PAGE:
+ return QsonPage::LIST_HEADER_PAGE;
+ case QsonPage::LIST_FOOTER_PAGE:
+ return QsonPage::LIST_FOOTER_PAGE;
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ return QsonPage::DOCUMENT_HEADER_PAGE;
+ case QsonPage::DOCUMENT_FOOTER_PAGE:
+ return QsonPage::DOCUMENT_FOOTER_PAGE;
+ case QsonPage::META_HEADER_PAGE:
+ return QsonPage::META_HEADER_PAGE;
+ case QsonPage::META_FOOTER_PAGE:
+ return QsonPage::META_FOOTER_PAGE;
+ default:
+ return QsonPage::UNKNOWN_PAGE;
+ }
+}
+
+int QsonPage::dataSize() const
+{
+ return mOffset;
+}
+
+const char *QsonPage::constData() const
+{
+ return mPage;
+}
+
+char *QsonPage::data()
+{
+ return mPage;
+}
+
+bool QsonPage::writeKey(const QString& key)
+{
+ switch (type()) {
+ case KEY_VALUE_PAGE: {
+ if (mMaxSize - mOffset - 2 < stringSize(key)) {
+ return false;
+ }
+ mPage[mOffset] = QsonPage::KEY_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+
+ bool ret = writeString(key);
+ updateOffset();
+ return ret;
+ }
+ default:
+ return false;
+ }
+}
+
+bool QsonPage::writeVersion(const QsonVersion &version)
+{
+ int size = version.content().size();
+ if (version.isValid()) {
+ if (mMaxSize - mOffset < size) {
+ return false;
+ }
+ memcpy(mPage + mOffset, version.content().constData(), size);
+ mOffset += size;
+ updateOffset();
+ }
+ return true;
+}
+
+bool QsonPage::writeValue() // null
+{
+ if (mMaxSize - mOffset < 2) {
+ return false;
+ }
+ mPage[mOffset] = QsonPage::NULL_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+ updateOffset();
+ return true;
+}
+
+bool QsonPage::writeValue(const bool value)
+{
+ if (mMaxSize - mOffset < 2) {
+ return false;
+ }
+ mPage[mOffset] = value ? QsonPage::TRUE_TYPE : QsonPage::FALSE_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+ updateOffset();
+ return true;
+}
+
+bool QsonPage::writeValue(const qint64 value)
+{
+ if (mMaxSize - mOffset < 10) { // 10 bytes to store an int
+ return false;
+ }
+ mPage[mOffset] = QsonPage::INT_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+ uchar *target = (uchar *) (mPage + mOffset);
+ qToLittleEndian(value, target);
+ mOffset += sizeof(qint64);
+ updateOffset();
+ return true;
+}
+
+bool QsonPage::writeValue(const quint64 value)
+{
+ if (mMaxSize - mOffset < 10) { // 10 bytes to store an int
+ return false;
+ }
+ mPage[mOffset] = QsonPage::UINT_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+ uchar *target = (uchar *) (mPage + mOffset);
+ qToLittleEndian(value, target);
+ mOffset += sizeof(quint64);
+ updateOffset();
+ return true;
+}
+
+bool QsonPage::writeValue(const double value)
+{
+ if (mMaxSize - mOffset < 10) { // 10 bytes to store a double
+ return false;
+ }
+
+ mPage[mOffset] = QsonPage::DOUBLE_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+ uchar *target = (uchar *) (mPage + mOffset);
+ memcpy(target, &value, sizeof(value));
+ mOffset += sizeof(double);
+ updateOffset();
+ return true;
+}
+
+bool QsonPage::writeValue(const QString& value)
+{
+ qson_size size = stringSize(value);
+ if (mMaxSize - mOffset - 2 < size) {
+ return false;
+ }
+ mPage[mOffset] = QsonPage::STRING_TYPE;
+ mOffset += 1;
+ mPage[mOffset] = 0;
+ mOffset += 1;
+ bool ret = writeString(value);
+ updateOffset();
+ return ret;
+}
+
+int QsonPage::readSize(int offset, bool expectKey) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset > sanityCheck) {
+ if (mPage[sanityCheck] != 0) {
+ qWarning() << "sanity check failed" << sanityCheck;
+ return 0;
+ }
+ switch (mPage[offset]) {
+ case QsonPage::KEY_TYPE:
+ if (!expectKey) {
+ return 0;
+ }
+ case QsonPage::STRING_TYPE:
+ if (mOffset > (offset + 3)) {
+ qson_size *stringSize = (qson_size*) (mPage + offset + 2);
+ if (mOffset > (offset + 3 + *stringSize)) {
+ return 4 + *stringSize;
+ }
+ }
+ return 0;
+ case QsonPage::INT_TYPE:
+ case QsonPage::UINT_TYPE:
+ if (!expectKey && mOffset > (offset + 9)) {
+ return sizeof(quint64) + 2;
+ }
+ return 0;
+ case QsonPage::DOUBLE_TYPE:
+ if (!expectKey && mOffset > (offset + 9)) {
+ return 10;
+ }
+ return 0;
+ case QsonPage::NULL_TYPE:
+ case QsonPage::TRUE_TYPE:
+ case QsonPage::FALSE_TYPE:
+ return expectKey ? 0 : 2;
+ case QsonPage::UUID_TYPE:
+ if (!expectKey && mOffset > (offset + 17)) {
+ return 18;
+ }
+ return 0;
+ case QsonPage::VERSION_TYPE:
+ if (!expectKey && mOffset > (offset + 21)) {
+ return 22;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
+bool QsonPage::readNull(int offset) const
+{
+ if (mOffset > offset) {
+ char type = mPage[offset];
+ if (type == NULL_TYPE) {
+ return true;
+ } else if (type == NULL_TYPE || type == STRING_TYPE) {
+ return readString(offset).isEmpty();
+ }
+ }
+ return false;
+}
+
+bool QsonPage::readBool(int offset) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset > sanityCheck && mPage[sanityCheck] == 0) {
+ char type = mPage[offset];
+ switch (type) {
+ case FALSE_TYPE:
+ case NULL_TYPE:
+ return false;
+ case TRUE_TYPE:
+ return true;
+ case INT_TYPE:
+ case UINT_TYPE:
+ case DOUBLE_TYPE:
+ return readInt(offset, 0) != 0;
+ case STRING_TYPE:
+ case KEY_TYPE:
+ return !readString(offset).isEmpty();
+ default:
+ return true;
+ }
+ }
+ return false;
+}
+
+quint64 QsonPage::readUInt(int offset, quint64 fallback) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset > sanityCheck && mPage[sanityCheck] == 0) {
+ char type = mPage[offset];
+ if (type == QsonPage::UINT_TYPE && mOffset > (sanityCheck + sizeof(quint64))) {
+ const uchar *valuep = (const uchar *) (mPage + sanityCheck + 1);
+ return qFromLittleEndian<quint64>(valuep);
+ } else if (type == QsonPage::VERSION_TYPE && mOffset > (sanityCheck + sizeof(quint32))) {
+ const uchar *valuep = (const uchar *)(mPage + sanityCheck + 1);
+ quint32 value = qFromLittleEndian<quint32>(valuep);
+ return value;
+ } else if (type == QsonPage::INT_TYPE) {
+ return (quint64) readInt(offset, fallback);
+ } else if (type == QsonPage::DOUBLE_TYPE) {
+ return (quint64) readDouble(offset, fallback);
+ } else if (type == QsonPage::STRING_TYPE) {
+ bool ok;
+ quint64 result = readString(offset).toULongLong(&ok);
+ return ok ? result : fallback;
+ }
+ }
+ return fallback;
+}
+
+qint64 QsonPage::readInt(int offset, qint64 fallback) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset > sanityCheck && mPage[sanityCheck] == 0) {
+ char type = mPage[offset];
+ if (type == QsonPage::INT_TYPE && mOffset > (sanityCheck + sizeof(qint64))) {
+ const uchar *valuep = (const uchar *)(mPage + sanityCheck + 1);
+ return qFromLittleEndian<qint64>((const uchar *)valuep);
+ } else if (type == QsonPage::UINT_TYPE || type == QsonPage::VERSION_TYPE) {
+ return (qint64) readUInt(offset, fallback);
+ } else if (type == QsonPage::DOUBLE_TYPE) {
+ return (qint64) readDouble(offset, fallback);
+ } else if (type == QsonPage::STRING_TYPE) {
+ bool ok;
+ qint64 result = readString(offset).toLongLong(&ok);
+ return ok ? result : fallback;
+ }
+ }
+ return fallback;
+}
+
+double QsonPage::readDouble(int offset, double fallback) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset > sanityCheck && mPage[sanityCheck] == 0) {
+ char type = mPage[offset];
+ if (type == QsonPage::DOUBLE_TYPE && mOffset > (sanityCheck + 8)) {
+ const uchar *valuep = (const uchar *) (mPage + sanityCheck + 1);
+ double value;
+ // TODO: endian safe
+ memcpy((char *)&value, valuep, sizeof(value));
+ return value;
+ } else if (type == QsonPage::INT_TYPE) {
+ return (double) readInt(offset, fallback);
+ } else if (type == QsonPage::UINT_TYPE || type == QsonPage::VERSION_TYPE) {
+ return (double) readDouble(offset, fallback);
+ } else if (type == QsonPage::STRING_TYPE) {
+ bool ok;
+ double result = readString(offset).toDouble(&ok);
+ return ok ? result : fallback;
+ }
+ }
+ return fallback;
+}
+
+QString QsonPage::readString(int offset) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset < (offset + 4) || mPage[sanityCheck] != 0) {
+ return QString();
+ }
+
+ switch (mPage[offset]) {
+ case QsonPage::KEY_TYPE:
+ case QsonPage::STRING_TYPE: {
+ qson_size* stringSize = (qson_size*) (mPage + offset + 2);
+ if ((sanityCheck + 2 + *stringSize) < mOffset) {
+ QChar *value = (QChar*) (mPage + offset + 4);
+ return QString(value, *stringSize / 2);
+ }
+ break;
+ }
+ case QsonPage::VERSION_TYPE:
+ if (mOffset >= (offset + 22)) {
+ QsonVersion version(mPage + offset);
+ return version.toString();
+ }
+ break;
+ case QsonPage::UUID_TYPE:
+ if (mOffset >= (offset + 18)) {
+ QByteArray uuid(mPage + offset + 2, 16);
+ QByteArray hex = uuid.toHex();
+ return QLatin1Char('{')
+ % QString::fromLatin1(hex.left(8))
+ % QLatin1Char('-')
+ % QString::fromLatin1(hex.mid(8, 4))
+ % QLatin1Char('-')
+ % QString::fromLatin1(hex.mid(12, 4))
+ % QLatin1Char('-')
+ % QString::fromLatin1(hex.mid(16, 4))
+ % QLatin1Char('-')
+ % QString::fromLatin1(hex.mid(20, 12))
+ % QLatin1Char('}');
+ }
+ break;
+ default:
+ break;
+ }
+ return QString();
+}
+
+QUuid QsonPage::readUuid(int offset) const
+{
+ int sanityCheck = offset + 1;
+ if (mOffset < (offset + 4) || mPage[sanityCheck] != 0)
+ return QUuid();
+
+ switch (mPage[offset]) {
+ case QsonPage::UUID_TYPE:
+ if (mOffset >= (offset + 18))
+ return QUuid::fromRfc4122(QByteArray::fromRawData(mPage + offset + 2, 16));
+ break;
+ case QsonPage::STRING_TYPE: {
+ qson_size* stringSize = (qson_size*) (mPage + offset + 2);
+ if ((sanityCheck + 2 + *stringSize) < mOffset) {
+ QChar *value = (QChar*) (mPage + offset + 4);
+ return QUuid(QString::fromRawData(value, *stringSize / 2));
+ }
+ }
+ default:
+ break;
+ }
+ return QUuid();
+}
+
+inline qson_size QsonPage::stringSize(const QString &string) const
+{
+ return (2 * qMin(30000, string.size()));
+}
+
+bool QsonPage::writeString(const QString& string)
+{
+ qson_size size = stringSize(string);
+ if (mMaxSize - mOffset - 2 < size) {
+ return false;
+ }
+
+ memcpy(mPage + mOffset, &size, 2);
+ mOffset += 2;
+
+ memcpy(mPage + mOffset, string.constData(), size);
+ mOffset += size;
+
+ return true;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonpage_p.h b/src/qson/qsonpage_p.h
new file mode 100644
index 00000000..9e46b416
--- /dev/null
+++ b/src/qson/qsonpage_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONPAGE_H
+#define QSONPAGE_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonversion_p.h>
+
+#include <QList>
+#include <QString>
+#include <QSharedData>
+#include <QUuid>
+
+namespace QtAddOn { namespace JsonDb {
+
+typedef unsigned short qson_size;
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonPage : public QSharedData
+{
+public:
+ enum PageType {
+ LIST_HEADER_PAGE = 'L',
+ LIST_FOOTER_PAGE = 'l',
+
+ DOCUMENT_HEADER_PAGE = 'D',
+ DOCUMENT_FOOTER_PAGE = 'd',
+
+ OBJECT_HEADER_PAGE = 'O',
+ OBJECT_FOOTER_PAGE = 'o',
+
+ META_HEADER_PAGE = 'M',
+ META_FOOTER_PAGE = 'm',
+
+ ARRAY_VALUE_PAGE = 'a',
+ KEY_VALUE_PAGE = 'k',
+
+ EMPTY_PAGE = 1,
+ UNKNOWN_PAGE = 0
+ };
+
+ enum DataType {
+ UNKNOWN_DATA = 0,
+ NULL_TYPE = 0x10,
+ FALSE_TYPE = 0x20,
+ TRUE_TYPE = 0x21,
+ DOUBLE_TYPE = 0x30,
+ UINT_TYPE = 0x31,
+ INT_TYPE = 0x32,
+ STRING_TYPE = 0x40,
+ KEY_TYPE = 0x41,
+ VERSION_TYPE = 0x42,
+ UUID_TYPE = 0x43
+ };
+
+ QsonPage();
+ QsonPage(PageType type);
+ QsonPage(const char *data, qson_size size);
+ QsonPage(const QsonPage &copy);
+ ~QsonPage();
+
+ PageType type() const;
+ int dataSize() const;
+ const char *constData() const;
+ char *data();
+
+ bool writeKey(const QString &key);
+ bool writeVersion(const QsonVersion &version);
+
+ bool writeValue(); // null
+ bool writeValue(const bool value);
+ bool writeValue(const qint64 value);
+ bool writeValue(const quint64 value);
+ bool writeValue(const double value);
+ bool writeValue(const QString &value);
+
+ int readSize(int offset, bool expectKey) const;
+ bool readNull(int offset) const;
+ bool readBool(int offset) const;
+ quint64 readUInt(int offset, quint64 fallback) const;
+ qint64 readInt(int offset, qint64 fallback) const;
+ double readDouble(int offset, double fallback) const;
+ QString readString(int offset) const;
+ QUuid readUuid(int offset) const;
+
+ inline bool operator==(const QsonPage &other) const
+ {
+ if (mOffset != other.mOffset)
+ return false;
+ if (mPage == other.mPage)
+ return true;
+ return memcmp(mPage, other.mPage, mOffset) == 0;
+ }
+ inline bool operator!=(const QsonPage &other) const
+ {
+ return !operator==(other);
+ }
+private:
+ const bool mOwnsData;
+ qson_size mMaxSize;
+ qson_size mOffset;
+ char *mPage;
+
+ inline qson_size stringSize(const QString &string) const;
+ bool writeString(const QString &string);
+ inline void updateOffset()
+ {
+ if (type() == QsonPage::EMPTY_PAGE || type() == QsonPage::UNKNOWN_PAGE)
+ return;
+ memcpy(mPage + 2, &mOffset, 2);
+ }
+
+ friend class QsonMap;
+};
+
+typedef QSharedDataPointer<QsonPage> QsonPagePtr;
+typedef QList<QSharedDataPointer<QsonPage> > QsonContent;
+
+} } // end namespace QtAddOn::JsonDb
+
+template<> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<QtAddOn::JsonDb::QsonPage>, Q_MOVABLE_TYPE);
+
+#endif // QSONPAGE_H
diff --git a/src/qson/qsonparser.cpp b/src/qson/qsonparser.cpp
new file mode 100644
index 00000000..08d1b7eb
--- /dev/null
+++ b/src/qson/qsonparser.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonparser_p.h"
+
+#include <QDebug>
+
+namespace QtAddOn { namespace JsonDb {
+
+QsonParser::QsonParser(bool streamMode)
+{
+ mObjectReady = false;
+ mHasError = false;
+ mStreamMode = streamMode;
+ mStreamReady = false;
+ mStreamDone = false;
+}
+
+void QsonParser::append(const QByteArray &buffer)
+{
+ mBuffer.append(buffer);
+ if (!mHasError & !mObjectReady && !mStreamDone)
+ scanBuffer();
+}
+
+void QsonParser::append(const char *data, int size)
+{
+ mBuffer.append(data, size);
+ if (!mHasError && !mObjectReady && !mStreamDone)
+ scanBuffer();
+}
+
+bool QsonParser::hasError() const
+{
+ return mHasError;
+}
+
+bool QsonParser::recover()
+{
+ if (!mHasError)
+ return true;
+
+ int posOfReset = mBuffer.indexOf("QSNR");
+ if (posOfReset == -1)
+ return false;
+
+ mBuffer = mBuffer.mid(posOfReset + 4);
+ mObjectReady = false;
+ mHasError = false;
+ mStreamReady = false;
+ mStreamDone = false;
+ scanBuffer();
+ return mHasError;
+}
+
+bool QsonParser::isObjectReady() const
+{
+ return mObjectReady && !mHasError;
+}
+
+QsonObject QsonParser::getObject()
+{
+ if (mObjectReady) {
+ QsonObject result(mContent);
+ mContent.clear();
+ mObjectReady = false;
+ if (!mBuffer.isEmpty())
+ scanBuffer();
+ return result;
+ } else {
+ return QsonObject();
+ }
+}
+
+bool QsonParser::isStream() const
+{
+ return mStreamReady;
+}
+
+bool QsonParser::streamDone()
+{
+ bool result = mStreamDone;
+ mStreamDone = false;
+ if (result && !mBuffer.isEmpty())
+ scanBuffer();
+ return result;
+}
+
+int QsonParser::pageSize(const char *data, int maxSize)
+{
+ if (maxSize < 4)
+ return 0;
+ if (data[0] != 'Q') {
+ qWarning() << "magic fail at 0" << (quint8) data[0];
+ return -1;
+ }
+
+ switch (data[1]) {
+ case 'S':
+ break;
+ case QsonPage::KEY_VALUE_PAGE:
+ case QsonPage::ARRAY_VALUE_PAGE: {
+ qson_size *result = (qson_size*) (data + 2);
+ if (*result <= maxSize)
+ return *result;
+ else
+ return 0;
+ }
+ default:
+ qWarning() << "magic fail at 1" << (quint8) data[1];
+ return -1;
+ }
+
+ if (data[2] != 'N') {
+ qWarning() << "magic fail at 2" << (quint8) data[2];
+ return -1;
+ }
+
+ switch (data[3]) {
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::OBJECT_FOOTER_PAGE:
+ case QsonPage::LIST_HEADER_PAGE:
+ case QsonPage::LIST_FOOTER_PAGE:
+ case QsonPage::META_HEADER_PAGE:
+ case QsonPage::META_FOOTER_PAGE:
+ return 4;
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ return (maxSize >= 44) ? 44 : 0;
+ case QsonPage::DOCUMENT_FOOTER_PAGE:
+ return (maxSize >= 26) ? 26 : 0;
+ default:
+ qWarning() << "magic fail at 3" << (quint8) data[3];
+ return -1;
+ }
+}
+
+void QsonParser::scanBuffer()
+{
+ int nextPageSize = pageSize(mBuffer.constData(), mBuffer.size());
+
+ if (nextPageSize == -1) {
+ qWarning() << __FUNCTION__ << "unknown qsonpage";
+ mHasError = true;
+ } else if (!mHasError && nextPageSize > 0) {
+ QsonPagePtr page = QsonPagePtr(new QsonPage(mBuffer.constData(), nextPageSize));
+ QsonPage::PageType type = page->type();
+ mBuffer = mBuffer.mid(nextPageSize);
+
+ switch (type) {
+ case QsonPage::KEY_VALUE_PAGE:
+ if (mStack.isEmpty() || mStack.last() == QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << __FUNCTION__ << "key/value page in list";
+ mHasError = true;
+ } else {
+ mContent.append(page);
+ }
+ break;
+ case QsonPage::ARRAY_VALUE_PAGE:
+ if (mStack.isEmpty() || mStack.last() != QsonPage::LIST_HEADER_PAGE) {
+ qWarning() << __FUNCTION__ << "array page in object";
+ mHasError = true;
+ } else
+ mContent.append(page);
+ break;
+ case QsonPage::LIST_HEADER_PAGE:
+ if (mStreamMode && !mStreamReady && mStack.isEmpty()) {
+ mStreamReady = true;
+ break;
+ }
+ case QsonPage::OBJECT_HEADER_PAGE:
+ case QsonPage::DOCUMENT_HEADER_PAGE:
+ mContent.append(page);
+ mStack.append(type);
+ break;
+ case QsonPage::META_HEADER_PAGE:
+ if (mStack.isEmpty() || mContent.last()->type() != QsonPage::DOCUMENT_HEADER_PAGE) {
+ qWarning() << __FUNCTION__ << "unexpected meta header";
+ mHasError = true;
+ } else {
+ mContent.append(page);
+ mStack.append(type);
+ }
+ break;
+ case QsonPage::LIST_FOOTER_PAGE:
+ if (mStreamMode && mStreamReady && mStack.isEmpty()) {
+ mStreamReady = false;
+ mStreamDone = true;
+ break;
+ }
+ case QsonPage::OBJECT_FOOTER_PAGE:
+ case QsonPage::DOCUMENT_FOOTER_PAGE:
+ case QsonPage::META_FOOTER_PAGE:
+ if (mStack.isEmpty() || mStack.last() != headerFor(type)) {
+ qWarning() << __FUNCTION__ << "unexpected footer page";
+ mHasError = true;
+ } else {
+ mContent.append(page);
+ mStack.removeLast();
+ }
+ if (mHasError == false && mStack.isEmpty())
+ mObjectReady = true;
+ break;
+ default:
+ qWarning() << __FUNCTION__ << "unknown page type";
+ mHasError = true;
+ }
+
+ if (!mHasError && !mObjectReady && !mStreamDone)
+ return scanBuffer();
+ }
+
+ if (mHasError) {
+ mStack.clear();
+ mContent.clear();
+ }
+}
+
+QsonObject QsonParser::fromRawData(const QByteArray &buffer)
+{
+ // ### TODO: improve me
+ QsonParser parser;
+ parser.append(buffer);
+ return parser.isObjectReady() ? parser.getObject() : QsonObject();
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonparser_p.h b/src/qson/qsonparser_p.h
new file mode 100644
index 00000000..6847e234
--- /dev/null
+++ b/src/qson/qsonparser_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONPARSER_H
+#define QSONPARSER_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+#include <QtJsonDbQson/private/qsonobject_p.h>
+
+#include <QList>
+#include <QByteArray>
+
+namespace QtAddOn { namespace JsonDb {
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonParser
+{
+public:
+ QsonParser(bool streamMode = false);
+
+ void append(const QByteArray& buffer);
+ void append(const char *data, int size);
+
+ bool hasError() const;
+ bool recover();
+
+ bool isObjectReady() const;
+ QsonObject getObject();
+
+ bool isStream() const;
+ bool streamDone();
+
+ static int pageSize(const char *data, int maxSize);
+
+ static QsonObject fromRawData(const QByteArray &buffer);
+
+#ifndef QT_TESTLIB_LIB
+private:
+#endif
+ void scanBuffer();
+
+ inline QsonPage::PageType headerFor(QsonPage::PageType type) const
+ {
+ switch (type) {
+ case QsonPage::OBJECT_FOOTER_PAGE:
+ return QsonPage::OBJECT_HEADER_PAGE;
+ case QsonPage::DOCUMENT_FOOTER_PAGE:
+ return QsonPage::DOCUMENT_HEADER_PAGE;
+ case QsonPage::LIST_FOOTER_PAGE:
+ return QsonPage::LIST_HEADER_PAGE;
+ case QsonPage::META_FOOTER_PAGE:
+ return QsonPage::META_HEADER_PAGE;
+ default:
+ return QsonPage::UNKNOWN_PAGE;
+ }
+ }
+
+ QByteArray mBuffer;
+ QList<QsonPage::PageType> mStack;
+ QsonContent mContent;
+
+ bool mObjectReady;
+ bool mHasError;
+ bool mStreamMode;
+ bool mStreamReady;
+ bool mStreamDone;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONPARSER_H
diff --git a/src/qson/qsonstrings.cpp b/src/qson/qsonstrings.cpp
new file mode 100644
index 00000000..9c5a752d
--- /dev/null
+++ b/src/qson/qsonstrings.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonstrings_p.h"
+
+namespace QtAddOn { namespace JsonDb {
+
+const QString QsonStrings::kUuidStr = QString::fromLatin1("_uuid");
+const QString QsonStrings::kLastVersionStr = QString::fromLatin1("_lastVersion");
+const QString QsonStrings::kVersionStr = QString::fromLatin1("_version");
+const QString QsonStrings::kMetaStr = QString::fromLatin1("_meta");
+const QString QsonStrings::kAncestorsStr = QString::fromLatin1("ancestors");
+const QString QsonStrings::kConflictsStr = QString::fromLatin1("conflicts");
+const QString QsonStrings::kIdStr = QString::fromLatin1("_id");
+const QString QsonStrings::kDeleted = QString::fromLatin1("_deleted");
+
+const QByteArray QsonStrings::kBlankUUID = QByteArray(16, 0);
+const QByteArray QsonStrings::kQsonMagic = QByteArray("QSON");
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonstrings_p.h b/src/qson/qsonstrings_p.h
new file mode 100644
index 00000000..2c34c9f5
--- /dev/null
+++ b/src/qson/qsonstrings_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSONSTRINGS_H
+#define QSONSTRINGS_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+
+#include <QString>
+#include <QByteArray>
+
+namespace QtAddOn { namespace JsonDb {
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonStrings {
+ public:
+ static const QString kUuidStr;
+ static const QString kVersionStr;
+ static const QString kLastVersionStr;
+ static const QString kMetaStr;
+ static const QString kAncestorsStr;
+ static const QString kConflictsStr;
+ static const QString kIdStr;
+ static const QString kDeleted;
+
+ static const QByteArray kBlankUUID;
+ static const QByteArray kQsonMagic;
+};
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSONSTRINGS_H
diff --git a/src/qson/qsonuuid.cpp b/src/qson/qsonuuid.cpp
new file mode 100644
index 00000000..703d0e04
--- /dev/null
+++ b/src/qson/qsonuuid.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonuuid_p.h"
+
+#include <QString>
+#include <QByteArray>
+#include <QCryptographicHash>
+
+namespace QtAddOn { namespace JsonDb {
+
+qson_uuid_t QsonUuidNs = {
+ 0x6ba7b811,
+ 0x9dad,
+ 0x11d1,
+ 0x80,
+ 0xb4,
+ {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
+};
+
+QByteArray QsonUUIDv3(const QString &source) {
+ QCryptographicHash md5(QCryptographicHash::Md5);
+ md5.addData((char *) &QsonUuidNs, sizeof(QsonUuidNs));
+ md5.addData((char *) source.constData(), source.size() * 2);
+
+ QByteArray result = md5.result();
+
+ qson_uuid_t *uuid = (qson_uuid_t*) result.data();
+ uuid->time_hi_and_version &= 0x0FFF;
+ uuid->time_hi_and_version |= (3 << 12);
+ uuid->clock_seq_hi_and_reserved &= 0x3F;
+ uuid->clock_seq_hi_and_reserved |= 0x80;
+
+ return result;
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonuuid_p.h b/src/qson/qsonuuid_p.h
new file mode 100644
index 00000000..c42d4e7b
--- /dev/null
+++ b/src/qson/qsonuuid_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSON_UUID_H
+#define QSON_UUID_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+
+#include <QCryptographicHash>
+
+namespace QtAddOn { namespace JsonDb {
+
+typedef struct {
+ quint32 time_low;
+ quint16 time_mid;
+ quint16 time_hi_and_version;
+ quint8 clock_seq_hi_and_reserved;
+ quint8 clock_seq_low;
+ char node[6];
+} qson_uuid_t;
+
+Q_ADDON_JSONDB_QSON_EXPORT QByteArray QsonUUIDv3(const QString &source);
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSON_UUID_H
diff --git a/src/qson/qsonversion.cpp b/src/qson/qsonversion.cpp
new file mode 100644
index 00000000..797a66dc
--- /dev/null
+++ b/src/qson/qsonversion.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsonversion_p.h"
+#include "qsonmap_p.h"
+
+#include <stdio.h>
+#include <QStringBuilder>
+
+namespace QtAddOn { namespace JsonDb {
+
+QsonVersion::QsonVersion(const char *data)
+{
+ if (data[0] != QsonPage::VERSION_TYPE || data[1] != 0) {
+ mIsValid = false;
+ } else {
+ mContent = QByteArray(data, 22);
+ mIsValid = (mContent.at(0) == QsonPage::VERSION_TYPE)
+ && (mContent.at(1) == 0)
+ && (updateCount() > 0);
+ }
+}
+
+QsonVersion QsonVersion::version(const QsonMap &map)
+{
+ return QsonVersion(map.mFooter->constData() + 4);
+}
+
+QsonVersion QsonVersion::lastVersion(const QsonMap &map)
+{
+ return QsonVersion(map.mHeader->constData() + 4);
+}
+
+QsonVersion QsonVersion::fromLiteral(const QString &literal)
+{
+ QByteArray result;
+ QStringList parts = literal.split(QLatin1Char('-'));
+ if (parts.size() == 2) {
+ result.resize(2 + sizeof(quint32));
+ result[0] = QsonPage::VERSION_TYPE;
+ result[1] = 0;
+ quint32 updateCount = parts.at(0).toUInt();
+ memcpy(result.data() + 2, &updateCount, sizeof(quint32));
+ result.append(QByteArray::fromHex(parts.at(1).toLatin1()).leftJustified(16, 0, true));
+ } else {
+ result.fill(0, 22);
+ }
+
+ return QsonVersion(result.constData());
+}
+
+bool QsonVersion::operator<(const QsonVersion& other) const
+{
+ if (updateCount() < other.updateCount()) {
+ return true;
+ }
+ return mContent < other.mContent;
+}
+
+bool QsonVersion::operator==(const QsonVersion& other) const
+{
+ return mContent == other.mContent;
+}
+
+bool QsonVersion::operator!=(const QsonVersion& other) const
+{
+ return mContent != other.mContent;
+}
+
+bool QsonVersion::isValid() const
+{
+ return mIsValid;
+}
+
+quint32 QsonVersion::updateCount() const
+{
+ quint32 *count = (quint32*) (mContent.constData() + 2);
+ return *count;
+}
+
+void QsonVersion::setUpdateCount(quint32 newCount)
+{
+ quint32 *count = (quint32*) (mContent.constData() + 2);
+ *count = newCount;
+}
+
+QByteArray QsonVersion::hash() const
+{
+ return mContent.mid(2+sizeof(quint32));
+}
+
+QString QsonVersion::toString() const
+{
+ if (mIsValid)
+ return QString::number(updateCount()) % QLatin1Char('-') % QString::fromLatin1(hash().toHex());
+ return QString();
+}
+
+uint qHash(const QsonVersion &version)
+{
+ return qHash(version.content());
+}
+
+} } // end namespace QtAddOn::JsonDb
diff --git a/src/qson/qsonversion_p.h b/src/qson/qsonversion_p.h
new file mode 100644
index 00000000..ab639f12
--- /dev/null
+++ b/src/qson/qsonversion_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSON_VERSION_H
+#define QSON_VERSION_H
+
+#include <QtJsonDbQson/qsonglobal.h>
+
+#include <QMap>
+#include <QByteArray>
+
+namespace QtAddOn { namespace JsonDb {
+
+class QsonMap;
+
+class Q_ADDON_JSONDB_QSON_EXPORT QsonVersion
+{
+public:
+ QsonVersion(const char *data);
+ static QsonVersion version(const QsonMap &map);
+ static QsonVersion lastVersion(const QsonMap &map);
+ static QsonVersion fromLiteral(const QString &literal);
+
+ bool operator<(const QsonVersion& other) const;
+ bool operator==(const QsonVersion& other) const;
+ bool operator!=(const QsonVersion& other) const;
+
+ bool isValid() const;
+ quint32 updateCount() const;
+ void setUpdateCount(quint32 newCount);
+ QByteArray hash() const;
+ QString toString() const;
+
+
+ inline QByteArray content() const
+ {
+ return mContent;
+ }
+
+private:
+ bool mIsValid;
+ QByteArray mContent;
+};
+
+Q_ADDON_JSONDB_QSON_EXPORT uint qHash(const QsonVersion &version);
+
+} } // end namespace QtAddOn::JsonDb
+
+#endif // QSON_VERSION_H
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 00000000..dac41afa
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+SUBDIRS += 3rdparty qson daemon client imports
+
diff --git a/sync.profile b/sync.profile
new file mode 100644
index 00000000..15482eb9
--- /dev/null
+++ b/sync.profile
@@ -0,0 +1,29 @@
+%modules = ( # path to module name map
+ "QtAddOnJsonDb" => "$basedir/src/client",
+ "QtJsonDbQson" => "$basedir/src/qson",
+);
+%moduleheaders = ( # restrict the module headers to those found in relative path
+);
+%classnames = (
+ "qtaddonjsondbversion.h" => "QtAddOnJsonDbVersion",
+);
+%mastercontent = (
+ "core" => "#include <QtCore/QtCore>\n",
+ "network" => "#include <QtNetwork/QtNetwork>\n",
+);
+%modulepris = (
+ "QtAddOnJsonDb" => "$basedir/modules/qt_jsondb.pri",
+ "QtJsonDbQson" => "$basedir/modules/qt_jsondb_qson.pri",
+);
+# Module dependencies.
+# Every module that is required to build this module should have one entry.
+# Each of the module version specifiers can take one of the following values:
+# - A specific Git revision.
+# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch)
+#
+%dependencies = (
+ "qtbase" => "refs/heads/master",
+ "qtdeclarative" => "refs/heads/master",
+ "qtsvg" => "refs/heads/master",
+ "qtxmlpatterns" => "refs/heads/master",
+);
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
new file mode 100644
index 00000000..43c8456a
--- /dev/null
+++ b/tests/auto/auto.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+SUBDIRS = \
+ client \
+ daemon \
+ bdb \
+ jsondb-listmodel \
+ common \
+ qsonstream
diff --git a/tests/auto/bdb/bdb.pro b/tests/auto/bdb/bdb.pro
new file mode 100644
index 00000000..34b4cf21
--- /dev/null
+++ b/tests/auto/bdb/bdb.pro
@@ -0,0 +1,18 @@
+include($$PWD/../../../src/3rdparty/btree/btree.pri)
+
+TARGET = tst_bdb
+
+QT = network testlib
+CONFIG -= app_bundle
+CONFIG += debug
+
+INCLUDEPATH += $$PWD/../../../src/daemon
+LIBS += -lssl -lcrypto
+
+SOURCES += \
+ tst_jsondb_bdb.cpp \
+ ../../../src/daemon/aodb.cpp
+
+check.target = check
+check.commands = rm -f *.db* && QT_QPA_PLATFORM=xcb ./tst_bdb -xunitxml -silent > ../../../tst_bdb.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/auto/bdb/tst_jsondb_bdb.cpp b/tests/auto/bdb/tst_jsondb_bdb.cpp
new file mode 100644
index 00000000..5cdef65f
--- /dev/null
+++ b/tests/auto/bdb/tst_jsondb_bdb.cpp
@@ -0,0 +1,919 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QByteArray>
+#include <QFile>
+#include <QFileInfo>
+#include <QDir>
+#include <QTime>
+
+#include "aodb.h"
+#include "btree.h"
+
+class TestJsonDbBdb: public QObject
+{
+ Q_OBJECT
+public:
+ TestJsonDbBdb();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void create();
+ void last();
+ void lastMultiPage();
+ void firstMultiPage();
+ void prev();
+ void prev2();
+ void rollback();
+ void multipleRollbacks();
+ void createWithCmp();
+ void readAndWrite();
+ void variableSizeKeysAndData();
+ void transactionTag();
+ void compareSequenceOfVarLengthKeys();
+ void syncMarker();
+ void corruptedPage();
+ void tag();
+
+private:
+ AoDb *bdb;
+};
+
+TestJsonDbBdb::TestJsonDbBdb()
+ : bdb(NULL)
+{
+}
+
+static const char dbname[] = "tst_jsondb_bdb.db";
+
+void TestJsonDbBdb::initTestCase()
+{
+ QFile::remove(dbname);
+ bdb = new AoDb;
+ if (!bdb->open(dbname, AoDb::NoSync))
+ Q_ASSERT(false);
+}
+
+void TestJsonDbBdb::cleanupTestCase()
+{
+ delete bdb;
+ bdb = 0;
+ QFile::remove(dbname);
+}
+
+void TestJsonDbBdb::create()
+{
+ QByteArray key1("1");
+ QByteArray value1("foo");
+ QByteArray key2("2");
+ QByteArray value2("bar");
+
+ bool ok;
+ QByteArray result;
+
+ // write first entry
+ ok = bdb->put(key1, value1);
+ QVERIFY(ok);
+
+ // read it
+ ok = bdb->get(key1, result);
+ QVERIFY(ok);
+ QCOMPARE(value1, result);
+
+ // read non-existing entry
+ ok = bdb->get(key2, result);
+ QVERIFY(!ok);
+
+ // write second entry
+ ok = bdb->put(key2, value2);
+ QVERIFY(ok);
+
+ // read both entries
+ ok = bdb->get(key1, result);
+ QVERIFY(ok);
+ QCOMPARE(value1, result);
+
+ ok = bdb->get(key2, result);
+ QVERIFY(ok);
+ QCOMPARE(value2, result);
+}
+
+void TestJsonDbBdb::last()
+{
+ QByteArray key0("0");
+ QByteArray value0("baz");
+ QByteArray key1("1");
+ QByteArray value1("foo");
+ QByteArray key2("2");
+ QByteArray value2("bar");
+
+ bool ok;
+ QByteArray result;
+
+ ok = bdb->clear();
+ QVERIFY(ok);
+
+ // write first entry
+ ok = bdb->put(key1, value1);
+ QVERIFY(ok);
+
+ // test cursor->last()
+ AoDbCursor *cursor = bdb->cursor();
+ ok = cursor->last();
+ QVERIFY(ok);
+ QByteArray outkey1;
+ ok = cursor->currentKey(outkey1);
+ QVERIFY(ok);
+ QCOMPARE(key1, outkey1);
+ delete cursor;
+
+ // write second entry
+ ok = bdb->put(key2, value2);
+ QVERIFY(ok);
+
+ // test cursor->last()
+ cursor = bdb->cursor();
+ ok = cursor->last();
+ QVERIFY(ok);
+ QByteArray outkey2;
+ ok = cursor->currentKey(outkey2);
+ QVERIFY(ok);
+ QCOMPARE(key2, outkey2);
+ delete cursor;
+
+ // write zeroth entry
+ ok = bdb->put(key0, value0);
+ QVERIFY(ok);
+
+ // test cursor->last()
+ cursor = bdb->cursor();
+ ok = cursor->last();
+ QVERIFY(ok);
+ QByteArray outkey3;
+ ok = cursor->currentKey(outkey3);
+ QVERIFY(ok);
+ QCOMPARE(key2, outkey3);
+
+}
+
+void TestJsonDbBdb::lastMultiPage()
+{
+ QByteArray value0("baz");
+
+ bool ok;
+ QByteArray result;
+
+ ok = bdb->clear();
+ QVERIFY(ok);
+
+ for (int i = 0; i < 1024; i++) {
+ // write first entry
+ QByteArray baKey(4, 0);
+ qToBigEndian(i, (uchar *)baKey.data());
+ ok = bdb->begin();
+ QVERIFY(ok);
+ ok = bdb->put(baKey, value0);
+ QVERIFY(ok);
+ ok = bdb->commit(0);
+ QVERIFY(ok);
+
+ AoDbCursor *cursor = bdb->cursor();
+ ok = cursor->last();
+ QVERIFY(ok);
+ QByteArray outkey1;
+ ok = cursor->currentKey(outkey1);
+ QVERIFY(ok);
+ QCOMPARE(baKey, outkey1);
+ while (cursor->prev()) {
+ QByteArray outkey2;
+ cursor->currentKey(outkey2);
+ //qDebug() << outkey1.toHex() << outkey2.toHex();
+ QVERIFY(memcmp(outkey1.constData(), outkey2.constData(), outkey1.size()) > 0);
+ outkey1 = outkey2;
+ }
+ delete cursor;
+
+ }
+}
+
+void TestJsonDbBdb::firstMultiPage()
+{
+ QByteArray value0("baz");
+
+ bool ok;
+ QByteArray result;
+
+ ok = bdb->clear();
+ QVERIFY(ok);
+
+ for (int i = 1024; i > 0; i--) {
+ // write first entry
+ QByteArray baKey(4, 0);
+ qToBigEndian(i, (uchar *)baKey.data());
+ ok = bdb->begin();
+ QVERIFY(ok);
+ ok = bdb->put(baKey, value0);
+ QVERIFY(ok);
+ ok = bdb->commit(0);
+ QVERIFY(ok);
+
+ AoDbCursor *cursor = bdb->cursor();
+ ok = cursor->first();
+ QVERIFY(ok);
+ QByteArray outkey1;
+ ok = cursor->currentKey(outkey1);
+ QVERIFY(ok);
+ QCOMPARE(baKey, outkey1);
+ while (cursor->next()) {
+ QByteArray outkey2;
+ cursor->currentKey(outkey2);
+ //qDebug() << outkey1.toHex() << outkey2.toHex();
+ QVERIFY(memcmp(outkey1.constData(), outkey2.constData(), outkey1.size()) < 0);
+ outkey1 = outkey2;
+ }
+ delete cursor;
+
+ }
+}
+
+void TestJsonDbBdb::prev()
+{
+ QByteArray key0("0");
+ QByteArray value0("baz");
+ QByteArray key1("1");
+ QByteArray value1("foo");
+ QByteArray key2("2");
+ QByteArray value2("bar");
+
+ bool ok;
+ QByteArray result;
+
+ ok = bdb->clear();
+ QVERIFY(ok);
+
+ // write entries
+ ok = bdb->put(key0, value0);
+ QVERIFY(ok);
+ ok = bdb->put(key1, value1);
+ QVERIFY(ok);
+ ok = bdb->put(key2, value2);
+ QVERIFY(ok);
+
+ // go to end
+ AoDbCursor *cursor = bdb->cursor();
+ ok = cursor->last();
+ QVERIFY(ok);
+ // test prev
+ ok = cursor->prev();
+ QVERIFY(ok);
+ QByteArray outkey;
+ ok = cursor->currentKey(outkey);
+ QVERIFY(ok);
+ QCOMPARE(key1, outkey);
+ delete cursor;
+
+ cursor = bdb->cursor();
+ // test prev without initialization is same as last()
+ ok = cursor->prev();
+ QVERIFY(ok);
+ ok = cursor->currentKey(outkey);
+ QVERIFY(ok);
+ QCOMPARE(key2, outkey);
+
+ // prev to key1
+ ok = cursor->prev();
+ QVERIFY(ok);
+ ok = cursor->currentKey(outkey);
+ QVERIFY(ok);
+ QCOMPARE(key1, outkey);
+
+ // prev to key0
+ ok = cursor->prev();
+ QVERIFY(ok);
+ ok = cursor->currentKey(outkey);
+ QVERIFY(ok);
+ QCOMPARE(key0, outkey);
+
+ // prev to eof
+ ok = cursor->prev();
+ QVERIFY(!ok);
+
+ delete cursor;
+}
+
+
+void TestJsonDbBdb::prev2()
+{
+ bool ok = bdb->clear();
+ QVERIFY(ok);
+
+ QFile file(dbname);
+ int maxSize = file.size();
+
+ int amount = ::getenv("BENCHMARK_AMOUNT") ? ::atoi(::getenv("BENCHMARK_AMOUNT")) : 40000;
+ for (int i = 0; i < amount; ++i) {
+ QByteArray data = QUuid::createUuid().toRfc4122();
+ bool ok = bdb->put(data, QByteArray("value_")+QByteArray::number(i));
+ QVERIFY(ok);
+ int size = file.size();
+ if (size > maxSize)
+ maxSize = size;
+ if ((i % 1000) == 999) {
+ bdb->compact();
+ qDebug() << " compacted." << file.size();;
+ }
+ }
+
+ AoDbCursor *c = bdb->cursor();
+ QVERIFY(c->first());
+ int cnt = 1;
+ while (c->next()) ++cnt;
+ QCOMPARE(cnt, amount);
+ delete c;
+
+ AoDbCursor *r = bdb->cursor();
+ QVERIFY(r->last());
+ int rcnt = 1;
+ while (r->prev()) ++rcnt;
+
+ QCOMPARE(rcnt, amount);
+ delete r;
+ qDebug() << "maxSize" << maxSize << "amount" << amount;
+}
+
+int keyCmp(const char *aptr, size_t asiz, const char *bptr, size_t bsiz, void *)
+{
+ QString a((QChar *)aptr, asiz/2);
+ QString b((QChar *)bptr, bsiz/2);
+ qDebug() << "keyCmp" << a << b;
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ else
+ return 0;
+}
+
+void TestJsonDbBdb::createWithCmp()
+{
+ bdb->clear();
+ bdb->setCmpFunc(keyCmp);
+ QString str1("1");
+ QByteArray key1 = QByteArray::fromRawData((const char *)str1.data(), str1.size()*2);
+ QByteArray value1("foo");
+ QString str2("2");
+ QByteArray key2 = QByteArray::fromRawData((const char *)str2.data(), str2.size()*2);
+ QByteArray value2("bar");
+
+ bool ok;
+ QByteArray result;
+
+ // write first entry
+ ok = bdb->put(key1, value1);
+ QVERIFY(ok);
+
+ // read it
+ ok = bdb->get(key1, result);
+ QVERIFY(ok);
+ QCOMPARE(value1, result);
+
+ // read non-existing entry
+ ok = bdb->get(key2, result);
+ QVERIFY(!ok);
+
+ // write second entry
+ ok = bdb->put(key2, value2);
+ QVERIFY(ok);
+
+ // read both entries
+ ok = bdb->get(key1, result);
+ QVERIFY(ok);
+ QCOMPARE(value1, result);
+
+ ok = bdb->get(key2, result);
+ QVERIFY(ok);
+ QCOMPARE(value2, result);
+}
+
+void TestJsonDbBdb::rollback()
+{
+ QByteArray key1("22");
+ QByteArray value1("foo");
+ QByteArray key2("42");
+ QByteArray value2("bar");
+
+ bool ok;
+ QByteArray result;
+
+ // write first entry
+ ok = bdb->put(key1, value1);
+ QVERIFY(ok);
+
+ {
+ // start transaction
+ ok = bdb->begin();
+ QVERIFY(ok);
+
+ // re-write the first entry
+ ok = bdb->remove(key1);
+ QVERIFY(ok);
+
+ ok = bdb->put(key1, value2);
+ QVERIFY(ok);
+
+ // write second entry
+ ok = bdb->put(key2, value2);
+ QVERIFY(ok);
+
+ // abort the transaction
+ ok = bdb->abort();
+ QVERIFY(ok);
+ }
+
+ // read both entries
+ ok = bdb->get(key1, result);
+ QVERIFY(ok);
+ QCOMPARE(value1, result);
+
+ ok = bdb->get(key2, result);
+ QVERIFY(!ok);
+}
+
+void TestJsonDbBdb::multipleRollbacks()
+{
+ QByteArray key1("101");
+ QByteArray value1("foo");
+ QByteArray key2("102");
+ QByteArray value2("bar");
+
+ bool ok;
+ QByteArray result;
+
+ {
+ ok = bdb->begin();
+ QVERIFY(ok);
+ // write first entry
+ ok = bdb->put(key1, value1);
+ QVERIFY(ok);
+ ok = bdb->commit(0);
+ QVERIFY(ok);
+ }
+
+ {
+ // start transaction
+ ok = bdb->begin();
+ QVERIFY(ok);
+
+ // re-write the first entry
+ ok = bdb->remove(key1);
+ QVERIFY(ok);
+ ok = bdb->put(key1, value2);
+ QVERIFY(ok);
+
+ // abort the transaction
+ ok = bdb->abort();
+ QVERIFY(ok);
+ }
+
+ {
+ // start transaction
+ ok = bdb->begin();
+ QVERIFY(ok);
+
+ // write second entry
+ ok = bdb->put(key2, value2);
+ QVERIFY(ok);
+
+ // abort the transaction
+ ok = bdb->abort();
+ QVERIFY(ok);
+ }
+
+ // read both entries
+ ok = bdb->get(key1, result);
+ QVERIFY(ok);
+ QCOMPARE(value1, result);
+
+ ok = bdb->get(key2, result);
+ QVERIFY(!ok);
+}
+
+void TestJsonDbBdb::readAndWrite()
+{
+ static const char dbname[] = "readandwrite.db";
+ QFile::remove(dbname);
+
+ AoDb wdb;
+ bool ok = wdb.open(dbname, AoDb::Default);
+ QVERIFY(ok);
+
+ wdb.begin();
+ wdb.put(QByteArray("foo"), QByteArray("bar"));
+ wdb.put(QByteArray("bla"), QByteArray("bla"));
+ wdb.commit(1);
+
+ AoDb rdb1;
+ ok = rdb1.open(dbname, AoDb::ReadOnly);
+ QVERIFY(ok);
+
+ QByteArray value;
+ ok = rdb1.get("foo", value);
+ QVERIFY(ok);
+ QCOMPARE(value, QByteArray("bar"));
+ ok = rdb1.get("bla", value);
+ QVERIFY(ok);
+ QCOMPARE(value, QByteArray("bla"));
+
+ wdb.begin();
+ wdb.put(QByteArray("foo2"), QByteArray("bar2"));
+ wdb.put(QByteArray("bar"), QByteArray("baz"));
+ // do not commit yet
+
+ rdb1.beginRead();
+ ok = rdb1.get("foo2", value);
+ QVERIFY(!ok);
+
+ AoDb rdb2;
+ ok = rdb2.open(dbname, AoDb::ReadOnly);
+ QVERIFY(ok);
+
+ ok = rdb2.get("foo", value);
+ QVERIFY(ok);
+ ok = rdb2.get("foo2", value);
+ QVERIFY(!ok);
+
+ wdb.commit(2);
+
+ ok = rdb2.get("foo", value);
+ QVERIFY(ok);
+ ok = rdb2.get("foo2", value);
+ QVERIFY(ok);
+ QCOMPARE(value, QByteArray("bar2"));
+
+ ok = rdb1.get("foo", value);
+ QVERIFY(ok);
+ ok = rdb1.get("foo2", value);
+ QVERIFY(!ok);
+ rdb1.abort();
+}
+
+
+void TestJsonDbBdb::variableSizeKeysAndData()
+{
+ static const char dbname[] = "variablesize.db";
+ QFile::remove(dbname);
+
+ AoDb wdb;
+ bool ok = wdb.open(dbname, AoDb::NoSync);
+ QVERIFY(ok);
+
+ QByteArray keyPrefix[10] = {
+ QByteArray("0001234567890123456789"),
+ QByteArray("000123456789"),
+ QByteArray("00012345678"),
+ QByteArray("0001234567"),
+ QByteArray("000123456"),
+ QByteArray("00012345"),
+ QByteArray("0001234"),
+ QByteArray("000123"),
+ QByteArray("00012"),
+ QByteArray("1")};
+
+ ok = wdb.clear();
+ QVERIFY(ok);
+
+ /* initialize random seed: */
+ srand ( 0 ); //QDateTime::currentMSecsSinceEpoch() );
+
+ for (int i = 0; i < 1024; i++) {
+ // Create a key with one of the prefixes from above
+ // Start by selecting one of the key prefixes
+ QByteArray key = keyPrefix[rand()%10];
+ int length = rand() % 128 + 1;
+ QByteArray keyPostfix(length, ' ');
+ for (int j=0; j<length; j++) {
+ keyPostfix[j] = quint8(rand()%255);
+ }
+ key += keyPostfix;
+
+ length = rand() % 1024 + 1;
+ // Create a random length value with random bytes
+ QByteArray value(length, ' ');
+ for (int j=0; j<length; j++) {
+ value[j] = quint8(rand()%255);
+ }
+ ok = wdb.begin();
+ QVERIFY(ok);
+ ok = wdb.put(key, value);
+ QVERIFY(ok);
+ ok = wdb.commit(0);
+ QVERIFY(ok);
+ }
+
+ // Delete every second object
+ AoDbCursor *cursor = wdb.cursor();
+ ok = cursor->first();
+ QVERIFY(ok);
+ QByteArray key;
+ ok = cursor->currentKey(key);
+ QVERIFY(ok);
+ bool remove = true;
+ int counter = 0;
+ while (cursor->next()) {
+ counter++;
+ cursor->currentKey(key);
+ if (remove) {
+ remove = false;
+ ok = wdb.begin();
+ QVERIFY(ok);
+ ok = wdb.remove(key);
+ QVERIFY(ok);
+ ok = wdb.commit(0);
+ QVERIFY(ok);
+ }
+ else remove = true;
+ }
+ delete cursor;
+
+ wdb.close();
+}
+
+void TestJsonDbBdb::transactionTag()
+{
+ static const char dbname[] = "readandwrite.db";
+ QFile::remove(dbname);
+
+ AoDb wdb;
+ bool ok = wdb.open(dbname, AoDb::Default);
+ QVERIFY(ok);
+
+ ok = wdb.begin();
+ QVERIFY(ok);
+ ok = wdb.put(QByteArray("foo"), QByteArray("bar"));
+ QVERIFY(ok);
+ ok = wdb.put(QByteArray("bla"), QByteArray("bla"));
+ QVERIFY(ok);
+ ok = wdb.commit(1);
+ QVERIFY(ok);
+ QCOMPARE(wdb.tag(), quint32(1));
+
+ AoDb rdb;
+ ok = rdb.open(dbname, AoDb::ReadOnly);
+ QVERIFY(ok);
+ QCOMPARE(rdb.tag(), quint32(1));
+ rdb.beginRead();
+ QCOMPARE(rdb.tag(), quint32(1));
+
+ ok = wdb.begin();
+ QVERIFY(ok);
+ ok = wdb.put(QByteArray("foo"), QByteArray("bar"));
+ QVERIFY(ok);
+ ok = wdb.commit(2);
+ QVERIFY(ok);
+ QCOMPARE(wdb.tag(), quint32(2));
+
+ QCOMPARE(rdb.tag(), quint32(1));
+ rdb.abort();
+ rdb.beginRead();
+ QCOMPARE(rdb.tag(), quint32(2));
+ rdb.abort();
+}
+
+int findLongestSequenceOf(const char *a, size_t size, char x)
+{
+ int result = 0;
+ int count = 0;
+ for (size_t i = 0; i < size; ++i) {
+ if (count > result)
+ result = count;
+
+ if (count) {
+ if (a[i] == x)
+ count++;
+ else
+ count = 0;
+ continue;
+ }
+
+ count = a[i] == x ? 1 : 0;
+ }
+
+ if (count > result)
+ result = count;
+
+ return result;
+}
+
+int cmpVarLengthKeys(const char *aptr, size_t asize, const char *bptr, size_t bsize, void *)
+{
+
+ int acount = findLongestSequenceOf(aptr, asize, 'a');
+ int bcount = findLongestSequenceOf(bptr, bsize, 'a');
+
+ if (acount == bcount) {
+ return QString::compare(QString::fromAscii(aptr, asize), QString::fromAscii(bptr, bsize));
+ } else {
+ return (acount > bcount) ? 1 : ((acount < bcount) ? -1 : 0);
+ }
+}
+
+
+bool cmpVarLengthKeysForQVec(const QByteArray &a, const QByteArray &b)
+{
+ return cmpVarLengthKeys(a.constData(), a.size(), b.constData(), b.size(), 0) < 0;
+}
+
+int myRand(int r)
+{
+ return (int)(((float)qrand() / (float)RAND_MAX) * (float)r);
+}
+
+void TestJsonDbBdb::compareSequenceOfVarLengthKeys()
+{
+ const char sequenceChar = 'a';
+ const int numElements = 1000;
+ const int minKeyLength = 20;
+ const int maxKeyLength = 25;
+
+ // Create vector of variable length keys of sequenceChar
+ QVector<QByteArray> vec;
+ for (int i = 0; i < numElements; ++i) {
+ QByteArray k(minKeyLength + myRand(maxKeyLength - minKeyLength), sequenceChar);
+
+ // Change character at random indexed
+ for (int j = 0; j < k.size(); ++j) {
+ if (myRand(2) > 0)
+ k[j] = 'a' + myRand(26);
+ }
+ vec.append(k);
+ }
+
+ bool ok = bdb->clear();
+ QVERIFY(ok);
+
+ ok = bdb->setCmpFunc(cmpVarLengthKeys);
+ QVERIFY(ok);
+
+ for (int i = 0; i < vec.size(); ++i) {
+ int count = findLongestSequenceOf(vec[i].constData(), vec[i].size(), sequenceChar);
+ QByteArray value((const char*)&count, sizeof(count));
+ ok = bdb->put(vec[i], value);
+ QVERIFY(ok);
+ }
+
+ // Sort QVector to use as verification of bdb sort order
+ qSort(vec.begin(), vec.end(), cmpVarLengthKeysForQVec);
+
+ AoDbCursor *cursor = bdb->cursor();
+ QVERIFY(cursor != NULL);
+
+ QByteArray key;
+ QByteArray value;
+ int i = 0;
+ while (cursor->next()) {
+ ok = cursor->currentKey(key);
+ QVERIFY(ok);
+
+ ok = cursor->currentValue(value);
+ QVERIFY(ok);
+
+ QCOMPARE(key, vec[i++]);
+ }
+
+ delete cursor;
+}
+
+void TestJsonDbBdb::syncMarker()
+{
+ bdb->clear();
+
+ AoDb db;
+ bool ok = db.open(dbname, AoDb::NoSync | AoDb::UseSyncMarker);
+ QVERIFY(ok);
+
+ ok = db.begin();
+ QVERIFY(ok);
+ ok = db.put(QByteArray("foo"), QByteArray("123"));
+ QVERIFY(ok);
+ ok = db.commit(5);
+ QVERIFY(ok);
+ db.sync();
+
+ // now commit without explicit sync, i.e.without marker
+ ok = db.begin();
+ QVERIFY(ok);
+ ok = db.put(QByteArray("bar"), QByteArray("456"));
+ QVERIFY(ok);
+ ok = db.commit(6);
+ QVERIFY(ok);
+
+ AoDb db2;
+ ok = db2.open(dbname, AoDb::NoSync | AoDb::UseSyncMarker);
+ QVERIFY(ok);
+ QByteArray value;
+ ok = db2.get(QByteArray("foo"), value);
+ QVERIFY(ok);
+ QCOMPARE(value, QByteArray("123"));
+ ok = db2.get(QByteArray("bar"), value);
+ QVERIFY(!ok);
+}
+
+void TestJsonDbBdb::corruptedPage()
+{
+ bdb->clear();
+
+ QVERIFY(bdb->begin());
+ QVERIFY(bdb->put(QByteArray("foo"), QByteArray("123")));
+ QVERIFY(bdb->commit(42));
+
+ bdb->close();
+
+ QFile file(dbname);
+ QVERIFY(file.open(QFile::Append));
+ file.write(QByteArray(4096, 8)); // write one page of garbage
+ file.close();
+
+ QVERIFY(bdb->open(dbname, AoDb::NoSync));
+ QCOMPARE(bdb->tag(), 42u);
+ QByteArray value;
+ QVERIFY(bdb->get(QByteArray("foo"), value));
+ QCOMPARE(value, QByteArray("123"));
+}
+
+void TestJsonDbBdb::tag()
+{
+ bdb->clear();
+
+ QVERIFY(bdb->begin());
+ QVERIFY(bdb->put(QByteArray("foo"), QByteArray("123")));
+ QVERIFY(bdb->commit(42));
+
+ struct btree *bt = bdb->handle();
+ struct btree_txn *rwtxn = btree_txn_begin(bt, 0);
+ struct btval btkey, btvalue;
+ memset(&btkey, 0, sizeof(btkey));
+ memset(&btvalue, 0, sizeof(btvalue));
+ btkey.data = (void *)"foo";
+ btkey.size = 4;
+ btvalue.data = (void *)"123";
+ btvalue.size = 4;
+ QCOMPARE(btree_txn_put(bt, rwtxn, &btkey, &btvalue, 0), BT_SUCCESS);
+ btval_reset(&btkey);
+ btval_reset(&btvalue);
+ QCOMPARE(btree_txn_get_tag(rwtxn), 42u);
+
+ struct btree_txn *rotxn = btree_txn_begin(bt, 1);
+ QCOMPARE(btree_txn_get_tag(rotxn), 42u);
+
+ QCOMPARE(btree_txn_commit(rwtxn, 64, 0), BT_SUCCESS);
+ struct btree_txn *rotxn2 = btree_txn_begin(bt, 1);
+ QCOMPARE(btree_txn_get_tag(rotxn), 42u);
+ QCOMPARE(btree_txn_get_tag(rotxn2), 64u);
+ btree_txn_abort(rotxn);
+ btree_txn_abort(rotxn2);
+}
+
+QTEST_MAIN(TestJsonDbBdb)
+#include "tst_jsondb_bdb.moc"
diff --git a/tests/auto/client/.gitignore b/tests/auto/client/.gitignore
new file mode 100644
index 00000000..96385b36
--- /dev/null
+++ b/tests/auto/client/.gitignore
@@ -0,0 +1 @@
+test-libjsondb-client
diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro
new file mode 100644
index 00000000..7759cca9
--- /dev/null
+++ b/tests/auto/client/client.pro
@@ -0,0 +1,17 @@
+TARGET = tst_client
+
+QT = network testlib jsondb-private jsondbqson-private
+CONFIG -= app_bundle
+
+include($$PWD/../../shared/shared.pri)
+include($$PWD/../../../src/3rdparty/qjson/qjson.pri)
+
+DEFINES += JSONDB_DAEMON_BASE=\\\"$$QT.jsondb.bins\\\"
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+SOURCES += test-jsondb-client.cpp
+
+check.target = check
+check.commands = rm -f *.db* && LD_LIBRARY_PATH=$$PWD/../../../lib QT_QPA_PLATFORM=xcb ./tst_client -xunitxml -silent > ../../../tst_client.xml
+QMAKE_EXTRA_TARGETS = check
+
diff --git a/tests/auto/client/create-test.json b/tests/auto/client/create-test.json
new file mode 100644
index 00000000..ee107a9b
--- /dev/null
+++ b/tests/auto/client/create-test.json
@@ -0,0 +1,14 @@
+{
+ "type": "object",
+ "properties": {
+ "create-test": {
+ "type": "number",
+ "required": true
+ },
+ "another-field": {
+ "type": "string",
+ "format": "uri",
+ "required": true
+ }
+ }
+}
diff --git a/tests/auto/client/test-jsondb-client.cpp b/tests/auto/client/test-jsondb-client.cpp
new file mode 100644
index 00000000..c676ccb0
--- /dev/null
+++ b/tests/auto/client/test-jsondb-client.cpp
@@ -0,0 +1,1204 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QList>
+#include <QTest>
+#include <QFile>
+#include <QProcess>
+#include <QEventLoop>
+#include <QDebug>
+#include <QLocalSocket>
+#include <QTimer>
+#include <QDir>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "private/jsondb-strings_p.h"
+#include "private/jsondb-connection_p.h"
+
+#include "jsondb-client.h"
+#include "jsondb-error.h"
+
+#include "json.h"
+
+#include "util.h"
+#include "clientwrapper.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+// #define EXTRA_DEBUG
+
+// #define DONT_START_SERVER
+
+class TestJsonDbClient: public ClientWrapper
+{
+ Q_OBJECT
+public:
+ TestJsonDbClient();
+ ~TestJsonDbClient();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void create();
+ void createList();
+ void update();
+ void find();
+ void notify();
+ void notifyRemoveBatch();
+ void notifyMultiple();
+ void remove();
+ void schemaValidation();
+ void changesSince();
+ void capabilitiesAllowAll();
+ void capabilitiesReadOnly();
+ void capabilitiesTypeQuery();
+ void storageQuotas();
+ void requestWithSlot();
+ void testToken_data();
+ void testToken();
+ void connection_response(int, const QVariant&);
+ void connection_error(int, int, const QString&);
+
+private:
+#ifndef DONT_START_SERVER
+ QProcess *mProcess;
+#endif
+ bool failed;
+ void removeDbFiles();
+};
+
+#ifndef DONT_START_SERVER
+static const char dbfileprefix[] = "test-jsondb-client-";
+#endif
+
+class Handler : public QObject
+{
+ Q_OBJECT
+public slots:
+ void success(int id, const QsonObject &d)
+ {
+ requestId = id;
+ data = d;
+ ++successCount;
+ }
+ void error(int id, int code, const QString &message)
+ {
+ requestId = id;
+ errorCode = code;
+ errorMessage = message;
+ ++errorCount;
+ }
+ void notify(const QString &uuid, const QsonObject &d, const QString &a)
+ {
+ notifyUuid = uuid;
+ data = d;
+ notifyAction = a;
+ ++notifyCount;
+ }
+
+ void clear()
+ {
+ requestId = 0;
+ data = QsonObject();
+ errorCode = 0;
+ errorMessage = QString();
+ notifyUuid = QString();
+ notifyAction = QString();
+ successCount = errorCount = notifyCount = 0;
+ }
+
+public:
+ Handler() { clear(); }
+
+ int requestId;
+ QsonObject data;
+ int errorCode;
+ QString errorMessage;
+ QString notifyUuid;
+ QString notifyAction;
+ int successCount;
+ int errorCount;
+ int notifyCount;
+};
+
+TestJsonDbClient::TestJsonDbClient()
+ : mProcess(0)
+{
+#ifdef EXTRA_DEBUG
+ this->debug_output = true;
+#endif
+}
+
+TestJsonDbClient::~TestJsonDbClient()
+{
+}
+
+void TestJsonDbClient::removeDbFiles()
+{
+#ifndef DONT_START_SERVER
+ QStringList lst = QDir().entryList(QStringList() << QLatin1String("*.db"));
+ lst << "objectFile.bin" << "objectFile2.bin";
+ foreach (const QString &fileName, lst)
+ QFile::remove(fileName);
+#else
+ qDebug("Don't forget to clean database files before running the test!");
+#endif
+}
+
+void TestJsonDbClient::initTestCase()
+{
+ removeDbFiles();
+#ifndef DONT_START_SERVER
+ const QString filename = QString::fromLatin1(dbfileprefix);
+ QStringList arg_list = (QStringList()
+ << "-validate-schemas"
+ << "-enforce-access-control"
+ << filename);
+ mProcess = launchJsonDbDaemon(JSONDB_DAEMON_BASE, QString("testjsondb_%1").arg(getpid()), arg_list);
+#endif
+ connectToServer();
+}
+
+void TestJsonDbClient::cleanupTestCase()
+{
+ if (mClient) {
+ delete mClient;
+ mClient = NULL;
+ }
+
+#ifndef DONT_START_SERVER
+ if (mProcess) {
+ mProcess->kill();
+ mProcess->waitForFinished();
+ delete mProcess;
+ }
+ removeDbFiles();
+#endif
+}
+
+/*
+ * Create an item and remove it
+ */
+
+void TestJsonDbClient::create()
+{
+ QVERIFY(mClient);
+
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "create-test");
+ item.insert("create-test", 22);
+
+ // Create an item
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+ // Try to create the same item again (should fail)
+ item.insert("_uuid", uuid);
+ id = mClient->create(item);
+ waitForResponse2(id, JsonDbError::InvalidRequest);
+
+ // Attempt to remove it without supplying a _uuid
+ item.remove("_uuid");
+ id = mClient->remove(item);
+ waitForResponse2(id, JsonDbError::MissingQuery);
+
+ // Set the _uuid field and attempt to remove it again
+ item.insert("_uuid", uuid);
+ id = mClient->remove(item);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("count"));
+ QCOMPARE(mData.toMap().value("count").toInt(), 1);
+}
+
+
+/*
+ * Create an array of items and remove them
+ */
+
+static const char *names[] = { "Abe", "Beth", "Carlos", "Dwight", "Emu", "Francis", NULL };
+
+void TestJsonDbClient::createList()
+{
+ // Create a few items
+ QVariantList list;
+ int count;
+ for (count = 0 ; names[count] ; count++ ) {
+ QVariantMap item;
+ item.insert("_type", "create-list-test");
+ item.insert("name", names[count]);
+ list << item;
+ }
+
+ int id = mClient->create(list);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("count").toInt(), count);
+
+ // Retrieve the _uuids of the items
+ QVariantMap query;
+ query.insert("query", "[?_type=\"create-list-test\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), count);
+
+ // Extract the uuids and put into a separate list
+ QVariantList toDelete;
+ QVariantList resultList = mData.toMap().value("data").toList();
+ for (int i = 0; i < resultList.size(); i++) {
+ const QVariant& v = resultList.at(i);
+ QVariantMap map = list.at(i).toMap();
+ map.insert("_uuid", v.toMap().value("_uuid"));
+ toDelete << map;
+ }
+
+ id = mClient->remove(toDelete);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("count").toInt(), count);
+}
+
+/*
+ * Update item
+ */
+
+void TestJsonDbClient::update()
+{
+ QVERIFY(mClient);
+
+ QVariantMap item;
+ QVariantMap query;
+ int id = 0;
+
+ // Create a item
+ item.insert("_type", "update-test");
+ item.insert("name", names[0]);
+ id = mClient->create(item);
+ waitForResponse1(id);
+ QString uuid = mData.toMap().value("_uuid").toString();
+ QString version = mData.toMap().value("_version").toString();
+
+ // Check that it's there
+ query.insert("query", "[?_type=\"update-test\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("data").toList().first().toMap().value("name").toString(),
+ QString(names[0]));
+
+ // Change the item
+ item.insert("name", names[1]);
+ item.insert("_uuid", uuid);
+ item.insert("_version", version);
+ id = mClient->update(item);
+ waitForResponse1(id);
+
+ // Check that it's really changed
+ query.insert("query", "[?_type=\"update-test\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), 1);
+
+ QMap<QString, QVariant> obj = mData.toMap().value("data").toList().first().toMap();
+ QCOMPARE(obj.value("name").toString(), QString(names[1]));
+
+ // Check if _version has changed
+ QVERIFY(obj.value("_version").toString() != version);
+}
+
+/*
+ * Find items
+ */
+
+void TestJsonDbClient::find()
+{
+ QVERIFY(mClient);
+
+ QVariantMap item;
+ QVariantMap query;
+ int id = 0;
+ int count;
+
+ QStringList nameList;
+ // Create a few items
+ for (count = 0 ; names[count] ; count++ ) {
+ nameList << names[count];
+ item.insert("_type", "find-test");
+ item.insert("name", names[count]);
+ id = mClient->create(item);
+ waitForResponse1(id);
+ }
+
+ query.insert("query", "[?_type=\"find-test\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), count);
+ QVariantList answer = mData.toMap().value("data").toList();
+ QCOMPARE(answer.size(), count);
+ QStringList answerNames;
+ for (int i = 0; i < count; i++) {
+ QVERIFY(nameList.contains(answer.at(i).toMap().value("name").toString()));
+ }
+
+ // Find them, but limit it to just one
+ query.insert("query", "[?_type=\"find-test\"]");
+ query.insert("limit", 1);
+ id = mClient->find(query);
+ waitForResponse1(id);
+ answer = mData.toMap().value("data").toList();
+ QCOMPARE(answer.size(), 1);
+ QVERIFY(nameList.contains(answer.at(0).toMap().value("name").toString()));
+
+ // Find one, sorted in reverse alphabetical order
+ query = QVariantMap();
+ query.insert("query", "[?_type=\"find-test\"][\\name]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ answer = mData.toMap().value("data").toList();
+ QCOMPARE(answer.size(), count);
+ QCOMPARE(answer.at(0).toMap().value("name").toString(),
+ QString(names[count-1]));
+ answerNames.clear();
+ nameList.clear();
+ for (int i = 0; i < count; i++) {
+ answerNames << answer.at(i).toMap().value("name").toString();
+ nameList << names[count - i - 1];
+ }
+ QCOMPARE(answerNames, nameList);
+
+}
+
+void TestJsonDbClient::notify()
+{
+ int id = 400;
+ QVariantList actions;
+ QVariantMap notification;
+
+ // Create a notification object
+ actions << "create" << "remove" << "update";
+ notification.insert("_type", "notification");
+ notification.insert("query", "[?_type=\"notify-test\"]");
+ notification.insert("actions", actions);
+
+ id = mClient->create(notification);
+ waitForResponse1(id);
+ QString notifyUuid = mData.toMap().value("_uuid").toString();
+
+ // Create a notify-test object
+ QVariantMap object;
+ object.insert("_type","notify-test");
+ object.insert("name","test1");
+ id = mClient->create(object);
+ waitForResponse4(id, -1, notifyUuid, 1);
+ QVariant uuid = mData.toMap().value("_uuid");
+ QString version = mData.toMap().value("_version").toString();
+
+ QCOMPARE(mNotifications.size(), 1);
+ Notification n = mNotifications.takeFirst();
+ QCOMPARE(n.mNotifyUuid, notifyUuid);
+ QCOMPARE(n.mAction, QString("create"));
+
+ // Update the notify-test object
+ object.insert("_uuid",uuid);
+ object.insert("_version", version);
+ object.insert("name","test2");
+ id = mClient->update(object);
+ waitForResponse4(id, -1, notifyUuid, 1);
+
+ QCOMPARE(mNotifications.size(), 1);
+ n = mNotifications.takeFirst();
+ QCOMPARE(n.mNotifyUuid, notifyUuid);
+ QCOMPARE(n.mAction, QLatin1String("update"));
+
+ // Remove the notify-test object
+ id = mClient->remove(object);
+ waitForResponse4(id, -1, notifyUuid, 1);
+
+ QCOMPARE(mNotifications.size(), 1);
+ n = mNotifications.takeFirst();
+ QCOMPARE(n.mNotifyUuid, notifyUuid);
+ QCOMPARE(n.mAction, QLatin1String("remove"));
+
+ // Remove the notification object
+ notification.insert("_uuid", notifyUuid);
+ id = mClient->remove(notification);
+ waitForResponse1(id);
+}
+
+static const char *rbnames[] = { "Fred", "Joe", "Sam", NULL };
+
+void TestJsonDbClient::notifyRemoveBatch()
+{
+ int id = 400;
+ QVariantList actions;
+ QVariantMap notification;
+
+ // Create a notification object
+ actions << "remove";
+ notification.insert("_type", "notification");
+ notification.insert("query", "[?_type=\"notify-test-remove-batch\"]");
+ notification.insert("actions", actions);
+
+ id = mClient->create(notification);
+ waitForResponse1(id);
+ QString notifyUuid = mData.toMap().value("_uuid").toString();
+
+ // Create notify-test-remove-batch object
+ QVariantList list;
+ int count;
+ for (count = 0 ; rbnames[count] ; count++) {
+ QVariantMap object;
+ object.insert("_type","notify-test-remove-batch");
+ object.insert("name",rbnames[count]);
+ list << object;
+ }
+
+ id = mClient->create(list);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("count").toInt(), count);
+
+ // Retrieve the _uuids of the items
+ QVariantMap query;
+ query.insert("query", "[?_type=\"notify-test-remove-batch\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), count);
+ list = mData.toMap().value("data").toList();
+
+ // Make a list of the uuids returned
+ QVariantList uuidList;
+ foreach (const QVariant& v, mData.toMap().value("data").toList())
+ uuidList << v.toMap().value("_uuid");
+
+ // Remove the objects
+ id = mClient->remove(list);
+ waitForResponse4(id, -1, notifyUuid, count);
+
+ QCOMPARE(mNotifications.size(), count);
+ while (mNotifications.length()) {
+ Notification n = mNotifications.takeFirst();
+ QCOMPARE(n.mNotifyUuid, notifyUuid);
+ QCOMPARE(n.mAction, QLatin1String("remove"));
+ QVariant uuid = n.mObject.toMap().value("_uuid");
+ QVERIFY(uuidList.contains(uuid));
+ uuidList.removeOne(uuid);
+ }
+
+ // Remove the notification object
+ notification.insert("_uuid", notifyUuid);
+ id = mClient->remove(notification);
+ waitForResponse1(id);
+}
+
+void TestJsonDbClient::schemaValidation()
+{
+ QFile schemaFile(findFile(SRCDIR, "create-test.json"));
+ schemaFile.open(QIODevice::ReadOnly);
+ QByteArray json = schemaFile.readAll();
+ schemaFile.close();
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ QVERIFY2(ok, parser.errorString().toLocal8Bit());
+ QVariantMap schemaBody = parser.result().toMap();
+ //qDebug() << "schemaBody" << schemaBody;
+ QVariantMap schemaObject;
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", "SchemaTestObject");
+ schemaObject.insert("schema", schemaBody);
+ //qDebug() << "schemaObject" << schemaObject;
+
+ int id = mClient->create(schemaObject);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "SchemaTestObject");
+ item.insert("create-test", 22);
+ item.insert("another-field", "a string");
+
+ // Create an item that matches the schema
+ id = mClient->create(item);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+ // Create an item that does not match the schema
+
+ QVariantMap noncompliant;
+ noncompliant.insert(JsonDbString::kTypeStr, "SchemaTestObject");
+ noncompliant.insert("create-test", 22);
+ id = mClient->create(noncompliant);
+ waitForResponse2(id, JsonDbError::FailedSchemaValidation);
+}
+
+void TestJsonDbClient::remove()
+{
+ QVERIFY(mClient);
+
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "remove-test");
+
+ // Create an item
+ item.insert("foo", 42);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+ // create more items
+ item.insert("foo", 5);
+ id = mClient->create(item);
+ waitForResponse1(id);
+ item.insert("foo", 64);
+ id = mClient->create(item);
+ waitForResponse1(id);
+ item.insert("foo", 65);
+ id = mClient->create(item);
+ waitForResponse1(id);
+
+ // query and make sure there are four items
+ id = mClient->query(QLatin1String("[?_type=\"remove-test\"]"));
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), 4);
+
+ // Set the _uuid field and attempt to remove first item
+ item.insert("_uuid", uuid);
+ id = mClient->remove(item);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("count"));
+ QCOMPARE(mData.toMap().value("count").toInt(), 1);
+
+ // query and make sure there are only three items left
+ id = mClient->query(QLatin1String("[?_type=\"remove-test\"]"));
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("length"));
+ QCOMPARE(mData.toMap().value("length").toInt(), 3);
+
+ // Remove two items using query
+ id = mClient->remove(QString::fromLatin1("[?_type=\"remove-test\"][?foo >= 63]"));
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("count"));
+ QCOMPARE(mData.toMap().value("count").toInt(), 2);
+
+ // query and make sure there are only one item left
+ id = mClient->query(QLatin1String("[?_type=\"remove-test\"]"));
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("length"));
+ QCOMPARE(mData.toMap().value("length").toInt(), 1);
+ QVERIFY(mData.toMap().contains("data"));
+ QCOMPARE(mData.toMap().value("data").toList().size(), 1);
+ QVERIFY(mData.toMap().value("data").toList().at(0).toMap().contains("foo"));
+ QCOMPARE(mData.toMap().value("data").toList().at(0).toMap().value("foo").toInt(), 5);
+}
+
+void TestJsonDbClient::notifyMultiple()
+{
+ // notifications with multiple client connections
+ // Makes sure only the client that signed up for notifications gets them
+
+ // Create a notification object
+ QVariantList actions;
+ QVariantMap notification;
+ actions << "create" << "remove" << "update";
+ notification.insert("_type", "notification");
+ notification.insert("query", "[?_type=\"notify-test\"][?identifier=\"w1-identifier\"]");
+ notification.insert("actions", actions);
+
+ ClientWrapper w1; w1.connectToServer();
+ ClientWrapper w2; w2.connectToServer();
+
+ int id = w1.mClient->create(notification);
+ waitForResponse(w1.mEventLoop, &w1, id, -1, QVariant(), 0);
+ QString notifyUuid = w1.mData.toMap().value("_uuid").toString();
+
+ // Create a notify-test object
+ QVariantMap object;
+ object.insert("_type","notify-test");
+ object.insert("identifier","w1-identifier");
+ id = w1.mClient->create(object);
+ waitForResponse(w1.mEventLoop, &w1, id, -1, notifyUuid, 1);
+ QVariant uuid = w1.mData.toMap().value("_uuid");
+ QString version = w1.mData.toMap().value("_version").toString();
+ QCOMPARE(w1.mNotifications.size(), 1);
+
+ id = w2.mClient->create(object);
+ waitForResponse(w2.mEventLoop, &w2, id, -1, QVariant(), 0);
+ QCOMPARE(w2.mNotifications.size(), 0);
+ if (w1.mNotifications.size() != 2)
+ waitForResponse(w1.mEventLoop, &w1, -1, -1, notifyUuid, 1);
+ QCOMPARE(w1.mNotifications.size(), 2);
+
+ w1.mNotifications.clear();
+ w2.mNotifications.clear();
+ object.insert("identifier","not-w1-identifier");
+ id = w1.mClient->create(object);
+ waitForResponse(w1.mEventLoop, &w1, id, -1, QVariant(), 0);
+ QCOMPARE(w1.mNotifications.size(), 0);
+ QCOMPARE(w2.mNotifications.size(), 0);
+
+ id = w2.mClient->create(object);
+ waitForResponse(w2.mEventLoop, &w2, id, -1, QVariant(), 0);
+ QCOMPARE(w2.mNotifications.size(), 0);
+ QCOMPARE(w1.mNotifications.size(), 0);
+
+}
+
+void TestJsonDbClient::changesSince()
+{
+ QVERIFY(mClient);
+
+ int id = mClient->changesSince(0);
+ waitForResponse1(id);
+
+ int state = mData.toMap()["currentStateNumber"].toInt();
+
+ QVariantMap c1, c2;
+ c1["_type"] = c2["_type"] = "TestContact";
+ c1["firstName"] = "John";
+ c1["lastName"] = "Doe";
+ c2["firstName"] = "George";
+ c2["lastName"] = "Washington";
+
+ id = mClient->create(c1);
+ waitForResponse1(id);
+ id = mClient->create(c2);
+ waitForResponse1(id);
+
+ // changesSince returns changes after the specified state
+ id = mClient->changesSince(state);
+ waitForResponse1(id);
+
+ QVariantMap data(mData.toMap());
+ QCOMPARE(data["startingStateNumber"].toInt(), state);
+ QVERIFY(data["currentStateNumber"].toInt() > state);
+ QCOMPARE(data["count"].toInt(), 2);
+
+ QVariantList results(data["changes"].toList());
+ QCOMPARE(results.count(), 2);
+
+ JsonWriter writer;
+ qDebug() << writer.toByteArray(results);
+ QVERIFY(results[0].toMap()["before"].toMap().isEmpty());
+ QVERIFY(results[1].toMap()["before"].toMap().isEmpty());
+
+ QVariantMap r1(results[0].toMap()["after"].toMap());
+ QVariantMap r2(results[1].toMap()["after"].toMap());
+
+ QMapIterator<QString, QVariant> i(c1);
+ while (i.hasNext()) {
+ i.next();
+ QCOMPARE(i.value().toString(), r1[i.key()].toString());
+ }
+
+ i = QMapIterator<QString, QVariant>(c2);
+ while (i.hasNext()) {
+ i.next();
+ QCOMPARE(i.value().toString(), r2[i.key()].toString());
+ }
+}
+
+static QStringList stringList(QString s)
+{
+ return (QStringList() << s);
+}
+
+void TestJsonDbClient::capabilitiesAllowAll()
+{
+ QVERIFY(mClient);
+
+ // Create Security Object
+ QString jsondb_token = "testToken";
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "com.nokia.mp.core.Security");
+ item.insert(JsonDbString::kTokenStr, jsondb_token);
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ item.insert("pid", getpid());
+#endif
+ item.insert("domain", "testDomain");
+ item.insert("identifier", "TestJsonDbClient");
+ QVariantMap capability;
+ QStringList accessTypesAllowed;
+ accessTypesAllowed << "allAllowed";
+ capability.insert("AllAccess", accessTypesAllowed);
+ item.insert("capabilities", capability);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ // Create Capability Object
+ QVariantMap item2;
+ item2.insert(JsonDbString::kTypeStr, "Capability");
+ item2.insert("name", "AllAccess");
+ QVariantMap accessRules;
+ QVariantMap accessTypeTranslation;
+ accessTypeTranslation.insert("read", stringList(".*"));
+ accessTypeTranslation.insert("write", stringList(".*"));
+ accessRules.insert("allAllowed", accessTypeTranslation);
+ item2.insert("accessRules", accessRules);
+ id = mClient->create(item2);
+ waitForResponse1(id);
+
+ // Add an item to the db
+ QVariantMap item3;
+ item3.insert(JsonDbString::kTypeStr, "all-allowed-test");
+ item3.insert("number", 22);
+ id = mClient->create(item3);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+ // Set token in environment
+ JsonDbConnection connection;
+ connection.setToken(jsondb_token);
+ connection.connectToServer();
+ JsonDbClient tokenClient(&connection);
+ connect( &tokenClient, SIGNAL(notified(const QString&, const QVariant&, const QString&)),
+ this, SLOT(notified(const QString&, const QVariant&, const QString&)));
+ connect( &tokenClient, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(response(int, const QVariant&)));
+ connect( &tokenClient, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(error(int, int, const QString&)));
+
+ // Now try to update the item.
+ item3.insert("_uuid", uuid);
+ item3.insert("number", 46);
+ id = tokenClient.update(item3);
+ waitForResponse1(id);
+
+ // Check that it's really changed
+ QVariantMap query;
+ query.insert("query", "[?_type=\"all-allowed-test\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), 1);
+
+ QMap<QString, QVariant> obj = mData.toMap().value("data").toList().first().toMap();
+ QCOMPARE(obj.value("number").toInt(), 46);
+}
+
+void TestJsonDbClient::capabilitiesReadOnly()
+{
+ QVERIFY(mClient);
+
+ // Create Security Object
+ QString jsondb_token = "testToken2";
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "com.nokia.mp.core.Security");
+ item.insert(JsonDbString::kTokenStr, jsondb_token);
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ item.insert("pid", getpid());
+#endif
+ item.insert("domain", "testDomain");
+ item.insert("identifier", "TestJsonDbClient");
+ QVariantMap capability;
+ QStringList accessTypesAllowed;
+ accessTypesAllowed << "noWrite";
+ capability.insert("NoWrite", accessTypesAllowed);
+ item.insert("capabilities", capability);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ // Create Capability Object
+ QVariantMap item2;
+ item2.insert(JsonDbString::kTypeStr, "Capability");
+ item2.insert(JsonDbString::kNameStr, "NoWrite");
+ QVariantMap accessRules;
+ QVariantMap accessTypeTranslation;
+ accessTypeTranslation.insert("read", stringList(".*"));
+ accessRules.insert("noWrite", accessTypeTranslation);
+ item2.insert("accessRules", accessRules);
+ id = mClient->create(item2);
+ waitForResponse1(id);
+
+ // Add an item to the db
+ QVariantMap item3;
+ item3.insert(JsonDbString::kTypeStr, "read-only-test");
+ item3.insert("number", 22);
+ id = mClient->create(item3);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+ // Set token in environment
+ JsonDbConnection connection;
+ connection.setToken(jsondb_token);
+ connection.connectToServer();
+ JsonDbClient tokenClient(&connection);
+ connect( &tokenClient, SIGNAL(notified(const QString&, const QVariant&, const QString&)),
+ this, SLOT(notified(const QString&, const QVariant&, const QString&)));
+ connect( &tokenClient, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(response(int, const QVariant&)));
+ connect( &tokenClient, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(error(int, int, const QString&)));
+
+ // Now try to update the item.
+ item3.insert("_uuid", uuid);
+ item3.insert("number", 46);
+ id = tokenClient.update(item3);
+ waitForResponse2(id, JsonDbError::OperationNotPermitted);
+
+ // Check that it's not changed
+ QVariantMap query;
+ query.insert("query", "[?_type=\"read-only-test\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), 1);
+
+ QMap<QString, QVariant> obj = mData.toMap().value("data").toList().first().toMap();
+ QCOMPARE(obj.value("number").toInt(), 22);
+}
+
+void TestJsonDbClient::capabilitiesTypeQuery()
+{
+ QVERIFY(mClient);
+
+ // Create Security Object
+ QString jsondb_token = "testToken3";
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "com.nokia.mp.core.Security");
+ item.insert(JsonDbString::kTokenStr, jsondb_token);
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ item.insert("pid", getpid());
+#endif
+ item.insert("domain", "testDomain");
+ item.insert("identifier", "TestJsonDbClient");
+ QVariantMap capability;
+ QStringList accessTypesAllowed;
+ accessTypesAllowed << "onlyWlan";
+ capability.insert("allAccess", accessTypesAllowed);
+ item.insert("capabilities", capability);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ // Create Capability Object
+ QVariantMap item2;
+ item2.insert(JsonDbString::kTypeStr, "Capability");
+ item2.insert(JsonDbString::kNameStr, "allAccess");
+ QVariantMap accessRules;
+ QVariantMap accessTypeTranslation;
+ accessTypeTranslation.insert("read", stringList("[?_type=\"Wlan\"]"));
+ accessTypeTranslation.insert("write", stringList("[?_type=\"Wlan\"]"));
+ accessRules.insert("onlyWlan", accessTypeTranslation);
+ item2.insert("accessRules", accessRules);
+ id = mClient->create(item2);
+ waitForResponse1(id);
+
+ // Add an item on type Wlan to the db
+ QVariantMap item3;
+ item3.insert(JsonDbString::kTypeStr, "Wlan");
+ item3.insert("SSID", "NokiaWlan");
+ item3.insert("Encryption", "None");
+ item3.insert("SignalStrenght", 46);
+ id = mClient->create(item3);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+
+ // Add an item on type NoAccess to the db
+ QVariantMap item4;
+ item4.insert(JsonDbString::kTypeStr, "NoAccess");
+ item4.insert("Number", 46);
+ id = mClient->create(item4);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid2 = mData.toMap().value("_uuid");
+
+ // Set token in environment
+ JsonDbConnection connection;
+ connection.setToken(jsondb_token);
+ connection.connectToServer();
+ JsonDbClient tokenClient(&connection);
+ connect( &tokenClient, SIGNAL(notified(const QString&, const QVariant&, const QString&)),
+ this, SLOT(notified(const QString&, const QVariant&, const QString&)));
+ connect( &tokenClient, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(response(int, const QVariant&)));
+ connect( &tokenClient, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(error(int, int, const QString&)));
+
+ // Now try to update the Wlan item.
+ item3.insert("_uuid", uuid);
+ item3.insert("SSID", "NokiaWlan2");
+ item3.insert("SignalStrenght", 12);
+ id = tokenClient.update(item3);
+ waitForResponse1(id);
+
+ // Check that it changed
+ QVariantMap query;
+ query.insert("query", "[?_type=\"Wlan\"]");
+ id = mClient->find(query);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), 1);
+
+ QMap<QString, QVariant> obj = mData.toMap().value("data").toList().first().toMap();
+ QCOMPARE(obj.value("SSID").toString(), QString("NokiaWlan2"));
+ QCOMPARE(obj.value("SignalStrenght").toInt(), 12);
+
+ // Now try to update the NoAccess item.
+ item4.insert("_uuid", uuid2);
+ item4.insert("Number", 12);
+ id = tokenClient.update(item4);
+ waitForResponse2(id, JsonDbError::OperationNotPermitted);
+
+ // Check that it did not change
+ QVariantMap query2;
+ query2.insert("query", "[?_type=\"NoAccess\"]");
+ id = mClient->find(query2);
+ waitForResponse1(id);
+ QCOMPARE(mData.toMap().value("length").toInt(), 1);
+
+ QMap<QString, QVariant> obj2 = mData.toMap().value("data").toList().first().toMap();
+ QCOMPARE(obj2.value("Number").toInt(), 46);
+}
+
+void TestJsonDbClient::storageQuotas()
+{
+ QVERIFY(mClient);
+
+ // Create Security Object with storage quota
+ QString jsondb_token = "testToken4";
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "com.nokia.mp.core.Security");
+ item.insert(JsonDbString::kTokenStr, jsondb_token);
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ item.insert("pid", getpid());
+#endif
+ item.insert("domain", "testDomain");
+ item.insert("identifier", "TestJsonDbClient");
+ QVariantMap capability;
+ QStringList accessTypesAllowed;
+ accessTypesAllowed << "allAllowed";
+ capability.insert("AllAccess", accessTypesAllowed);
+ QVariantMap quotas;
+ quotas.insert("storage", int(1024));
+ capability.insert("quotas", quotas);
+ item.insert("capabilities", capability);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ // Create Capability Object
+ QVariantMap item2;
+ item2.insert(JsonDbString::kTypeStr, "Capability");
+ item2.insert("name", "AllAccess");
+ QVariantMap accessRules;
+ QVariantMap accessTypeTranslation;
+ accessTypeTranslation.insert("read", stringList(".*"));
+ accessTypeTranslation.insert("write", stringList(".*"));
+ accessRules.insert("allAllowed", accessTypeTranslation);
+ item2.insert("accessRules", accessRules);
+ id = mClient->create(item2);
+ waitForResponse1(id);
+
+
+ // Set token in environment
+ JsonDbConnection connection;
+ connection.setToken(jsondb_token);
+ connection.connectToServer();
+ JsonDbClient tokenClient(&connection);
+ connect( &tokenClient, SIGNAL(notified(const QString&, const QVariant&, const QString&)),
+ this, SLOT(notified(const QString&, const QVariant&, const QString&)));
+ connect( &tokenClient, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(response(int, const QVariant&)));
+ connect( &tokenClient, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(error(int, int, const QString&)));
+
+
+ // Add an item to the db
+ QVariantMap item3;
+ item3.insert(JsonDbString::kTypeStr, "storage-test");
+ item3.insert("storagedata", QString(256, 'a'));
+ item3.insert("number", 123);
+ id = tokenClient.create(item3);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QVariant uuid = mData.toMap().value("_uuid");
+
+ // This should be to large to fit the quota
+ QVariantMap item4;
+ item4.insert(JsonDbString::kTypeStr, "storage-test");
+ item4.insert("storagedata", QString(256, 'a'));
+ item4.insert("number", 123);
+ id = tokenClient.create(item4);
+ waitForResponse2(id, JsonDbError::QuotaExceeded);
+
+ // Remove the first item to make more space
+ item3.insert("_uuid", uuid);
+ id = tokenClient.remove(item3);
+ waitForResponse1(id);
+
+ // This time it should work to add the second item
+ id = tokenClient.create(item4);
+ waitForResponse1(id);
+
+ // Remove all items
+ QVERIFY(mData.toMap().contains("_uuid"));
+ uuid = mData.toMap().value("_uuid");
+ item4.insert("_uuid", uuid);
+ id = tokenClient.remove(item4);
+ waitForResponse1(id);
+
+
+ // Make sure that the storage does not increase
+ // by adding and removing objects.
+ for (int i = 0; i < 10; i++) {
+ // Add an item to the db
+ QVariantMap item5;
+ item5.insert(JsonDbString::kTypeStr, "storage-test");
+ item5.insert("storagedata", QString(256, 'a'));
+ item5.insert("number", 123);
+ id = tokenClient.create(item5);
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ uuid = mData.toMap().value("_uuid");
+
+ // Remove the item again
+ item5.insert("_uuid", uuid);
+ id = tokenClient.remove(item5);
+ waitForResponse1(id);
+ }
+}
+
+void TestJsonDbClient::requestWithSlot()
+{
+ Handler handler;
+
+ // create notification object
+ int id = mClient->notify(JsonDbClient::NotifyCreate, "[?_type=\"requestWithSlot\"]",
+ &handler, SLOT(notify(QString,QsonObject,QString)),
+ &handler, SLOT(success(int,QsonObject)), SLOT(error(int,int,QString)));
+ waitForResponse1(id);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QString notifyUuid = mData.toMap().value("_uuid").toString();
+ QCOMPARE(handler.errorCount, 0);
+ QCOMPARE(handler.successCount, 1);
+ handler.clear();
+
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("requestWithSlot"));
+ item.insert("create-test", 42);
+ id = mClient->create(item, &handler, SLOT(success(int,QsonObject)), SLOT(error(int,int,QString)));
+ waitForResponse4(id, -1, notifyUuid, 1);
+ QVERIFY(mData.toMap().contains("_uuid"));
+ QString uuid = mData.toMap().value("_uuid").toString();
+
+ QCOMPARE(handler.requestId, id);
+ QVERIFY(handler.data.toMap().contains("_uuid"));
+ QCOMPARE(handler.data.toMap().valueString("_uuid"), uuid);
+
+ QCOMPARE(handler.errorCount, 0);
+ QCOMPARE(handler.successCount, 1);
+ QCOMPARE(handler.notifyCount, 1);
+ QCOMPARE(handler.notifyUuid, notifyUuid);
+}
+
+void TestJsonDbClient::connection_response(int, const QVariant&)
+{
+ failed = false;
+ mEventLoop.quit();
+}
+
+void TestJsonDbClient::connection_error(int id, int code, const QString &message)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(code);
+ Q_UNUSED(message);
+ failed = true;
+ mEventLoop.quit();
+}
+
+
+void TestJsonDbClient::testToken_data()
+{
+ QTest::addColumn<pid_t>("pid");
+ QTest::addColumn<QString>("tokenString");
+ QTest::addColumn<bool>("willFail");
+
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ QTest::newRow("valid") << getpid() << "testToken_valid" << false;
+ QTest::newRow("invalid") << getpid()+1 << "testToken_invalid" << true;
+#else
+ QSKIP("Not supported on this platform", SkipAll);
+#endif
+}
+
+void TestJsonDbClient::testToken()
+{
+ QVERIFY(mClient);
+ QFETCH(pid_t, pid);
+ QFETCH(QString, tokenString);
+ QFETCH(bool, willFail);
+
+ // Create Security Object
+ QVariantMap item;
+ item.insert(JsonDbString::kTypeStr, "com.nokia.mp.core.Security");
+ item.insert(JsonDbString::kTokenStr, tokenString);
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
+ item.insert("pid", pid);
+#endif
+ item.insert("domain", "testDomain");
+ item.insert("identifier", "TestJsonDbClient");
+ QVariantMap capability;
+ QStringList accessTypesAllowed;
+ accessTypesAllowed << "allAllowed";
+ capability.insert("AllAccess", accessTypesAllowed);
+ item.insert("capabilities", capability);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ // Set token in environment
+ JsonDbConnection connection;
+ connect( &connection, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(connection_response(int, const QVariant&)));
+ connect( &connection, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(connection_error(int, int, const QString&)));
+
+ connection.setToken(tokenString);
+ connection.connectToServer();
+ mEventLoop.exec(QEventLoop::AllEvents);
+ QCOMPARE(failed, willFail);
+}
+
+QTEST_MAIN(TestJsonDbClient)
+
+#include "test-jsondb-client.moc"
diff --git a/tests/auto/common/common.pro b/tests/auto/common/common.pro
new file mode 100644
index 00000000..8bdef7cf
--- /dev/null
+++ b/tests/auto/common/common.pro
@@ -0,0 +1,17 @@
+TARGET = tst_common
+
+QT = declarative network testlib jsondbqson-private
+CONFIG -= app_bundle
+
+include($$PWD/../../../src/common/common.pri)
+
+HEADERS += \
+ $$QSONCONVERSION_HEADERS
+
+SOURCES += \
+ test-common.cpp \
+ $$QSONCONVERSION_SOURCES
+
+check.target = check
+check.commands = ./tst_common -xunitxml -silent > ../../../tst_common.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/auto/common/test-common.cpp b/tests/auto/common/test-common.cpp
new file mode 100644
index 00000000..7585bb16
--- /dev/null
+++ b/tests/auto/common/test-common.cpp
@@ -0,0 +1,1536 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtJsonDbQson/private/qson_p.h>
+#include <QtJsonDbQson/private/qsonpage_p.h>
+#include <QtJsonDbQson/private/qsonversion_p.h>
+#include <QtJsonDbQson/private/qsonparser_p.h>
+
+#include "qsonconversion.h"
+
+#include <QUuid>
+#include <QDebug>
+#include <QJSEngine>
+#include <QMap>
+
+#include <json.h>
+
+using namespace QtAddOn::JsonDb;
+
+namespace QTest {
+template<>
+bool qCompare<qint64, int>(qint64 const &t1, int const &t2,
+ const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return QTest::qCompare(t1, (qint64)t2, actual, expected, file, line);
+}
+template<>
+bool qCompare<quint64, unsigned int>(quint64 const &t1, unsigned int const &t2,
+ const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return QTest::qCompare(t1, (quint64)t2, actual, expected, file, line);
+}
+}
+
+class TestCommon: public QObject
+{
+ Q_OBJECT
+
+
+private slots:
+ void testQsonDocumentHeaderAndFooterPage();
+ void testQsonMap();
+ void testQsonMapAttributes();
+ void testQsonSubMap();
+ void testQsonList();
+ void testQsonSubList();
+ void testMeta();
+ void implicitSharing();
+ void testQsonVersion();
+ void testQsonVersionLiteral();
+ void testVersionList();
+ void testMerging();
+ void testRecreate();
+ void testQsonElement();
+ void testEquals();
+ void testQsonParser();
+ void testQsonParserStreaming();
+ void qsonParseDocument();
+ void testComplexElement();
+ void testInsertEmptyObject();
+ void testIsEmpty();
+ void testInsertUuid();
+ void testQsonToJSValue();
+ void testRemove();
+ void testDoubleInsert();
+
+private:
+ void validateHeader(const char* qson, QsonPage::PageType type, int size)
+ {
+ qson_size *actualSize;
+ QCOMPARE(*(qson+0), 'Q');
+ switch (type) {
+ case QsonPage::KEY_VALUE_PAGE:
+ case QsonPage::ARRAY_VALUE_PAGE:
+ QCOMPARE(*(qson+1), (char) type);
+ actualSize = (qson_size*) (qson + 2);
+ QCOMPARE(*actualSize, (qson_size) size);
+ break;
+ default:
+ QCOMPARE(*(qson+1), 'S');
+ QCOMPARE(*(qson+2), 'N');
+ QCOMPARE(*(qson+3), (char) type);
+ }
+
+ }
+
+ int qsizeAt(const QByteArray &bytes, int pos)
+ {
+ qson_size *value = (qson_size*) (bytes.constData() + pos);
+ return (int) *value;
+ }
+
+ qint32 int32At(const QByteArray &bytes, int pos)
+ {
+ qint32 *value = (qint32*) (bytes.constData() + pos);
+ return *value;
+ }
+
+ quint32 uint32At(const QByteArray &bytes, int pos)
+ {
+ quint32 *value = (quint32*) (bytes.constData() + pos);
+ return *value;
+ }
+
+ QString stringAt(const QByteArray &bytes, int pos)
+ {
+ int size = qsizeAt(bytes, pos);
+ QString result((QChar *) (bytes.constData() + pos + 2), size / 2);
+ return result;
+ }
+
+ double doubleAt(const QByteArray &bytes, int pos)
+ {
+ double *value = (double*) (bytes.constData() + pos);
+ return (double) *value;
+ }
+
+ bool typeAt(const QByteArray &bytes, int pos, QsonPage::DataType type)
+ {
+ char stored = bytes.constData()[pos];
+ char sanity = bytes.constData()[pos + 1];
+
+ if (stored == type && sanity == 0) {
+ return true;
+ } else {
+ qDebug() << "at" << pos << ": expected" << (quint8) type << ", found" << (quint8) stored;
+ qDebug() << "sanity bytes is" << (quint8) sanity;
+ return false;
+ }
+ }
+};
+
+void TestCommon::testQsonDocumentHeaderAndFooterPage()
+{
+ QsonPage documentHeader(QsonPage::DOCUMENT_HEADER_PAGE);
+ validateHeader(documentHeader.data(), QsonPage::DOCUMENT_HEADER_PAGE, 44);
+ QCOMPARE(documentHeader.data()[4], (char) QsonPage::VERSION_TYPE);
+ QCOMPARE(documentHeader.data()[5], '\x00');
+ QCOMPARE(documentHeader.data()[26], (char) QsonPage::UUID_TYPE);
+ QCOMPARE(documentHeader.data()[27], '\x00');
+ QCOMPARE(documentHeader.dataSize(), 44);
+
+ QsonPage documentFooter(QsonPage::DOCUMENT_FOOTER_PAGE);
+ validateHeader(documentFooter.data(), QsonPage::DOCUMENT_FOOTER_PAGE, 26);
+ QCOMPARE(documentHeader.data()[4], (char) QsonPage::VERSION_TYPE);
+ QCOMPARE(documentHeader.data()[5], '\x00');
+ QCOMPARE(documentFooter.dataSize(), 26);
+
+ QsonPage listHeader(QsonPage::LIST_HEADER_PAGE);
+ validateHeader(listHeader.data(), QsonPage::LIST_HEADER_PAGE, 4);
+ QCOMPARE(listHeader.dataSize(), 4);
+
+ QsonPage listFooter(QsonPage::LIST_FOOTER_PAGE);
+ validateHeader(listFooter.data(), QsonPage::LIST_FOOTER_PAGE, 4);
+ QCOMPARE(listFooter.dataSize(), 4);
+}
+
+void TestCommon::testQsonMap()
+{
+ QsonMap qson;
+ qson.insert(QString("hello"), QString("world"));
+
+ QByteArray bytes = qson.data();
+
+ QCOMPARE(qson.dataSize(), 40);
+ validateHeader(bytes.constData(), QsonPage::OBJECT_HEADER_PAGE, 4);
+ validateHeader(bytes.constData() + 4, QsonPage::KEY_VALUE_PAGE, 32);
+ QVERIFY(typeAt(bytes, 8, QsonPage::KEY_TYPE));
+ QCOMPARE(stringAt(bytes, 10), QString("hello"));
+ QVERIFY(typeAt(bytes, 22, QsonPage::STRING_TYPE));
+ QCOMPARE(stringAt(bytes, 24), QString("world"));
+ validateHeader(bytes.constData() + 36, QsonPage::OBJECT_FOOTER_PAGE, 4);
+
+ QStringList keys = qson.keys();
+ QCOMPARE(keys.size(), 1);
+ QCOMPARE(keys[0], QString("hello"));
+
+ QCOMPARE(qson.valueString("hello"), QString("world"));
+
+ qson.insert(QLatin1String("hello"), QLatin1String("foobar"));
+ QCOMPARE(qson.keys().size(), 1);
+ QCOMPARE(qson.keys().at(0), QLatin1String("hello"));
+ QCOMPARE(qson.valueString("hello"), QString("foobar"));
+}
+
+void TestCommon::testQsonMapAttributes()
+{
+ // insert each type
+ // read it immediately to make sure we can read at the end of a page
+
+ QsonMap qson;
+
+ qson.insert("null", QsonObject::NullValue);
+ QVERIFY(qson.contains("null"));
+ QCOMPARE(qson.valueType("null"), QsonObject::NullType);
+ QCOMPARE(qson.isNull("null"), true);
+
+ qson.insert("false", false);
+ QVERIFY(qson.contains("false"));
+ QCOMPARE(qson.valueType("false"), QsonObject::BoolType);
+ QCOMPARE(qson.valueBool("false"), false);
+
+ qson.insert("true", true);
+ QVERIFY(qson.contains("true"));
+ QCOMPARE(qson.valueType("true"), QsonObject::BoolType);
+ QCOMPARE(qson.valueBool("true"), true);
+
+ qson.insert("uint", (quint32) 1);
+ QVERIFY(qson.contains("uint"));
+ QCOMPARE(qson.valueType("uint"), QsonObject::UIntType);
+ QCOMPARE(qson.valueUInt("uint"), (quint32) 1);
+
+ qson.insert("int", (qint32) 2);
+ QVERIFY(qson.contains("int"));
+ QCOMPARE(qson.valueType("int"), QsonObject::IntType);
+ QCOMPARE(qson.valueInt("int"), (qint32) 2);
+
+ qson.insert("int64", (qint64) 1234567890123456789ll);
+ QVERIFY(qson.contains("int64"));
+ QCOMPARE(qson.valueType("int64"), QsonObject::IntType);
+ QCOMPARE(qson.valueInt("int64"), (qint64) 1234567890123456789ll);
+
+ qson.insert("uint64", (quint64) 18446744073709551615ull);
+ QVERIFY(qson.contains("uint64"));
+ QCOMPARE(qson.valueType("uint64"), QsonObject::UIntType);
+ QCOMPARE(qson.valueUInt("uint64"), (quint64) 18446744073709551615ull);
+
+ qson.insert("double", 1.2);
+ QVERIFY(qson.contains("double"));
+ QCOMPARE(qson.valueType("double"), QsonObject::DoubleType);
+ QCOMPARE(qson.valueDouble("double"), 1.2);
+
+ qson.insert(QLatin1String("char"), QLatin1String("value"));
+ QVERIFY(qson.contains("char"));
+ QCOMPARE(qson.valueType("char"), QsonObject::StringType);
+ QCOMPARE(qson.valueString("char"), QString("value"));
+
+ qson.insert(QLatin1String("string"), QLatin1String("qvalue"));
+ QVERIFY(qson.contains("string"));
+ QCOMPARE(qson.valueType("string"), QsonObject::StringType);
+ QCOMPARE(qson.valueString("string"), QString("qvalue"));
+}
+
+void TestCommon::testQsonSubMap()
+{
+ QsonMap child;
+ child.insert(QLatin1String("hello"), QLatin1String("world"));
+
+ QsonMap parent;
+ parent.insert("before", false);
+ parent.insert("child", child);
+ parent.insert("after", true);
+
+ QsonMap readChild = parent.subObject("child");
+ QCOMPARE(readChild.keys().length(), 1);
+ QVERIFY(readChild.contains("hello"));
+ QCOMPARE(readChild.valueString("hello"), QString("world"));
+}
+
+void TestCommon::testQsonList()
+{
+ QsonList list;
+ QCOMPARE(list.size(), 0);
+
+ list.append(QsonObject::NullValue);
+ QCOMPARE(list.size(), 1);
+ QCOMPARE(list.isNull(0), true);
+ QCOMPARE(list.typeAt(0), QsonObject::NullType);
+
+ list.append(true);
+ QCOMPARE(list.size(), 2);
+ QCOMPARE(list.boolAt(1), true);
+ QCOMPARE(list.typeAt(1), QsonObject::BoolType);
+
+ list.append((quint32) 1);
+ QCOMPARE(list.size(), 3);
+ QCOMPARE(list.uintAt(2), (quint32) 1);
+ QCOMPARE(list.typeAt(2), QsonObject::UIntType);
+
+ list.append((qint32) 2);
+ QCOMPARE(list.size(), 4);
+ QCOMPARE(list.intAt(3), 2);
+ QCOMPARE(list.typeAt(3), QsonObject::IntType);
+
+ list.append(1.2);
+ QCOMPARE(list.size(), 5);
+ QCOMPARE(list.doubleAt(4), 1.2);
+ QCOMPARE(list.typeAt(4), QsonObject::DoubleType);
+
+ list.append(QLatin1String("char"));
+ QCOMPARE(list.size(), 6);
+ QCOMPARE(list.stringAt(5), QString("char"));
+ QCOMPARE(list.typeAt(5), QsonObject::StringType);
+
+ list.append(QString("string"));
+ QCOMPARE(list.size(), 7);
+ QCOMPARE(list.stringAt(6), QString("string"));
+ QCOMPARE(list.typeAt(6), QsonObject::StringType);
+}
+
+void TestCommon::testQsonSubList()
+{
+ QsonMap qson;
+ qson.insert(QLatin1String("hello"), QLatin1String("world"));
+
+ QsonMap qson1;
+ qson1.insert(QLatin1String("yes"), QLatin1String("no"));
+
+ QsonList subList;
+ subList.append(qson);
+ subList.append(true);
+ subList.append(qson1);
+ subList.append(false);
+
+ QsonList list;
+ list.append(subList);
+
+ QsonMap container;
+ container.insert("list", list);
+
+ QCOMPARE(container.size(), 1);
+ QVERIFY(container.contains("list"));
+ QCOMPARE(container.valueType("list"), QsonObject::ListType);
+
+ QCOMPARE(container.subList("list").size(), 1);
+ QCOMPARE(container.subList("list").typeAt(0), QsonObject::ListType);
+ QCOMPARE(container.subList("list").listAt(0).size(), 4);
+ QCOMPARE(container.subList("list").listAt(0).typeAt(0), QsonObject::MapType);
+ QCOMPARE(container.subList("list").listAt(0).typeAt(1), QsonObject::BoolType);
+ QCOMPARE(container.subList("list").listAt(0).typeAt(2), QsonObject::MapType);
+ QCOMPARE(container.subList("list").listAt(0).typeAt(3), QsonObject::BoolType);
+
+ QCOMPARE(container.subList("list").listAt(0).objectAt(0).size(), 1);
+ QCOMPARE(container.subList("list").listAt(0).objectAt(0).valueString("hello"), QString("world"));
+ QCOMPARE(container.subList("list").listAt(0).objectAt(2).size(), 1);
+ QCOMPARE(container.subList("list").listAt(0).objectAt(2).valueString("yes"), QString("no"));
+}
+
+void TestCommon::testMeta()
+{
+ QsonMap meta;
+ meta.insert(QLatin1String("hello"), QLatin1String("world"));
+ QVERIFY(!meta.isMeta());
+
+ QsonMap qson;
+ QVERIFY(!qson.isDocument());
+ QVERIFY(!qson.isMeta());
+ qson.insert("_meta", meta);
+
+ QVERIFY(qson.isDocument());
+ qson.computeVersion();
+ QsonVersion version = QsonVersion::version(qson);
+ QVERIFY(version.isValid());
+ QCOMPARE(qson.valueString("_version"), version.toString());
+ QCOMPARE(qson.valueInt("_version"), 1);
+
+ QVERIFY(qson.isDocument());
+ QCOMPARE(qson.valueType("_meta"), QsonObject::MapType);
+ meta = qson.subObject("_meta");
+ QVERIFY(meta.isMeta());
+ QCOMPARE(meta.valueString("hello"), QString("world"));
+ meta.insert("yes", true);
+ qson.insert("_meta", meta);
+
+ // make sure, the version wasn't touched by inserting a modified meta
+ qson.computeVersion();
+ QCOMPARE(QsonVersion::version(qson), version);
+ QCOMPARE(QsonVersion::lastVersion(qson), version);
+}
+
+void TestCommon::implicitSharing()
+{
+ QsonMap bar;
+ bar.insert(QLatin1String("a"), QLatin1String("b"));
+ QCOMPARE(bar.mBody.size(), 1);
+ QCOMPARE(bar.mBody[0].constData()->ref.operator int(), 1);
+
+ QsonList list;
+ list.append(42);
+ list.append(QLatin1String("foobar"));
+ list.append(bar);
+
+ QCOMPARE(bar.mBody.size(), 1);
+ QCOMPARE(bar.mBody[0].constData()->ref.operator int(), 2);
+
+ bar.insert(QLatin1String("zoo"), QLatin1String("zebra")); // detaches
+
+ QCOMPARE(bar.mBody.size(), 1);
+ QCOMPARE(bar.mBody[0].constData()->ref.operator int(), 1);
+
+ QsonMap map;
+ map.insert(QLatin1String("hello"), QLatin1String("world"));
+ map.insert("foo", bar);
+ map.insert("list", list);
+
+ QCOMPARE(bar.mBody.size(), 1);
+ QCOMPARE(bar.mBody[0].constData()->ref.operator int(), 2);
+ bar.insert(QLatin1String("zzz"), QLatin1String("sleep")); // detaches
+ QCOMPARE(bar.mBody.size(), 1);
+ QCOMPARE(bar.mBody[0].constData()->ref.operator int(), 1);
+
+ list.append(4242); // detaches
+
+ QCOMPARE(list.size(), 4);
+ QCOMPARE(list.at<int>(0), 42);
+ QCOMPARE(list.at<QString>(1), QLatin1String("foobar"));
+ QCOMPARE(list.at<QsonMap>(2).keys().size(), 1);
+ QCOMPARE(list.at<QsonMap>(2).keys().at(0), QLatin1String("a"));
+ QCOMPARE(list.at<QsonMap>(2).value<QString>("a"), QLatin1String("b"));
+
+ QCOMPARE(bar.keys().size(), 3);
+ QCOMPARE(bar.value<QString>("a"), QLatin1String("b"));
+ QCOMPARE(bar.value<QString>("zoo"), QLatin1String("zebra"));
+ QCOMPARE(bar.value<QString>("zzz"), QLatin1String("sleep"));
+
+ QCOMPARE(map.keys().size(), 3);
+ QCOMPARE(map.value<QString>("hello"), QLatin1String("world"));
+ QCOMPARE(map.value<QsonMap>("foo").keys().size(), 2);
+ QCOMPARE(map.value<QsonMap>("foo").value<QString>("a"), QLatin1String("b"));
+ QCOMPARE(map.value<QsonMap>("foo").value<QString>("zoo"), QLatin1String("zebra"));
+
+ QCOMPARE(map.value<QsonList>("list").size(), 3);
+ QCOMPARE(map.value<QsonList>("list").at<int>(0), 42);
+ QCOMPARE(map.value<QsonList>("list").at<QString>(1), QLatin1String("foobar"));
+ QCOMPARE(map.value<QsonList>("list").at<QsonMap>(2).keys().size(), 1);
+ QCOMPARE(map.value<QsonList>("list").at<QsonMap>(2).keys().at(0), QLatin1String("a"));
+ QCOMPARE(map.value<QsonList>("list").at<QsonMap>(2).value<QString>("a"), QLatin1String("b"));
+}
+
+void TestCommon::testQsonVersion()
+{
+ QsonMap qson1;
+ qson1.generateUuid();
+ QsonMap qson2(qson1);
+
+ qson1.insert("hello", QString("World"));
+ qson1.computeVersion();
+
+ qson2.insert("hello", QString("world"));
+ qson2.computeVersion();
+
+ //QsonVersion lastVersion = QsonVersion::lastVersion(qson1);
+ //QVERIFY(!lastVersion.isValid());
+ QsonVersion version1 = QsonVersion::version(qson1);
+ QVERIFY(version1.isValid());
+ QsonVersion version2 = QsonVersion::version(qson2);
+ QVERIFY(version2.isValid());
+
+ QMap<QsonVersion, QsonMap> container;
+ container[version1] = qson1;
+ container[version2] = qson2;
+
+ QCOMPARE(container.size(), 2);
+ QList<QsonVersion> keys = container.keys();
+
+ QCOMPARE(keys[0], version2);
+ QCOMPARE(keys[1], version1);
+
+ QSet<QsonVersion> set;
+ set.insert(version1);
+ set.insert(version2);
+ set.insert(version1);
+
+ QCOMPARE(set.size(), 2);
+ QVERIFY(set.contains(version1));
+ QVERIFY(set.contains(version2));
+}
+
+void TestCommon::testQsonVersionLiteral()
+{
+ QsonMap map;
+ map.computeVersion();
+ map.insert("hello", QString("world"));
+ map.computeVersion();
+
+ QsonVersion source = QsonVersion::version(map);
+ QsonVersion target = QsonVersion::fromLiteral(source.toString());
+ QCOMPARE(target, source);
+
+ QsonMap test;
+ test.insert("_version", map.valueString("_version"));
+
+ QCOMPARE(QsonVersion::lastVersion(test), QsonVersion::version(map));
+ QCOMPARE(QsonVersion::version(test), QsonVersion::version(map));
+
+ test.insert("_lastVersion", map.valueString("_lastVersion"));
+
+ QCOMPARE(QsonVersion::lastVersion(test), QsonVersion::lastVersion(map));
+ QCOMPARE(QsonVersion::version(test), QsonVersion::version(map));
+}
+
+void TestCommon::testVersionList()
+{
+ QsonMap q1;
+ q1.insert("one", 1);
+ q1.computeVersion();
+
+ QsonMap q2;
+ q2.insert("two", 2);
+ q2.computeVersion();
+
+ QsonPagePtr page(new QsonPage(QsonPage::ARRAY_VALUE_PAGE));
+ page->writeVersion(QsonVersion::version(q1));
+ page->writeVersion(QsonVersion::version(q2));
+
+ QsonList list;
+ list.mBody.append(page);
+
+ QCOMPARE(list.size(), 2);
+ QCOMPARE(list.stringAt(0), QsonVersion::version(q1).toString());
+ QCOMPARE(list.stringAt(1), QsonVersion::version(q2).toString());
+
+ QsonObject::CachedIndex *idx = list.index();
+ QsonObject::CachedIndex::Cleaner cleanerIdx(*idx);
+ int count = 0;
+ foreach (const QsonEntry entry, *idx) {
+ count++;
+ }
+ QCOMPARE(count, 2);
+}
+
+void TestCommon::testMerging()
+{
+ QsonMap qson1;
+ qson1.computeVersion();
+ QsonVersion version1 = QsonVersion::version(qson1);
+ QCOMPARE(qson1.valueInt("_version"), 1);
+
+ // same version should not merge
+ QsonMap master(qson1);
+ QVERIFY(!master.mergeVersions(qson1));
+ QCOMPARE(QsonVersion::version(master), version1);
+
+ // recompute just to be sure
+ master.computeVersion();
+ QCOMPARE(QsonVersion::version(master), version1);
+
+ // non-document should not merge
+ QVERIFY(!master.mergeVersions(QsonMap()));
+ QCOMPARE(QsonVersion::version(master), version1);
+ // recompute just to be sure
+ master.computeVersion();
+ QCOMPARE(QsonVersion::version(master), version1);
+
+ // document with different uuid should not merge
+ QsonMap alien;
+ alien.generateUuid();
+ QVERIFY(alien.valueString("_uuid") != master.valueString("_uuid"));
+ QVERIFY(!master.mergeVersions(alien));
+ QCOMPARE(QsonVersion::version(master), version1);
+ // recompute just to be sure
+ master.computeVersion();
+ QCOMPARE(QsonVersion::version(master), version1);
+
+ // create an update
+ QsonMap qson2(qson1);
+ qson2.insert("hello", QString("world2"));
+ qson2.computeVersion();
+ QCOMPARE(qson2.valueInt("_version"), 2);
+
+ // create a conflicting update
+ QsonMap qson3(qson1);
+ qson3.insert("hello", QString("world3"));
+ qson3.computeVersion();
+ QCOMPARE(qson3.valueInt("_version"), 2);
+
+ QsonVersion version2 = QsonVersion::version(qson2);
+ QsonVersion version3 = QsonVersion::version(qson3);
+
+ // make sure they are different
+ QVERIFY(version2 != version3);
+
+ // merge qson2 in
+ QVERIFY(master.mergeVersions(qson2));
+
+ // master should now look like qson2
+ QCOMPARE(QsonVersion::version(master), version2);
+ QCOMPARE(QsonVersion::lastVersion(master), version2);
+
+ // master should now contain _meta information about the merge
+ QVERIFY(master.contains("_meta"));
+ QCOMPARE(master.valueType("_meta"), QsonObject::MapType);
+ QVERIFY(master.subObject("_meta").isMeta());
+ QCOMPARE(master.subObject("_meta").size(), 1);
+ QCOMPARE(master.subObject("_meta").subList("ancestors").size(), 1);
+ QCOMPARE(master.subObject("_meta").subList("ancestors").stringAt(0), version1.toString());
+ QVERIFY(!master.subObject("_meta").contains("conflicts"));
+
+ // make sure a computeVersion() doesn't change the version
+ master.computeVersion();
+ QCOMPARE(QsonVersion::lastVersion(master), QsonVersion::version(qson2));
+ QCOMPARE(QsonVersion::version(master), QsonVersion::version(qson2));
+
+ // let's keep a copy of master for later
+ QsonMap qson21(master);
+
+ // now we merge a conflict
+ QVERIFY(master.mergeVersions(qson3));
+
+ QCOMPARE(master.valueType("_meta"), QsonObject::MapType);
+ QVERIFY(master.subObject("_meta").isMeta());
+ QCOMPARE(master.subObject("_meta").size(), 2);
+ QVERIFY(master.subObject("_meta").contains("conflicts"));
+ QCOMPARE(master.subObject("_meta").valueType("conflicts"), QsonObject::ListType);
+ QCOMPARE(master.subObject("_meta").subList("conflicts").size(), 1);
+
+ QsonMap loser = master.subObject("_meta").subList("conflicts").objectAt(0);
+ QVERIFY(loser.isDocument());
+
+ // check the versions
+ QsonVersion versionM = QsonVersion::version(master);
+ QsonVersion versionL1 = QsonVersion::version(loser);
+
+ // make sure the last version is set to current one
+ QCOMPARE(QsonVersion::lastVersion(master), versionM);
+
+ // sanity check
+ QVERIFY(versionM.isValid());
+ QVERIFY(version1.isValid());
+ QVERIFY(version2.isValid());
+ QVERIFY(version3.isValid());
+ QVERIFY(versionL1.isValid());
+
+ // winner is only determined by compare function
+ if (version2 < version3) {
+ QCOMPARE(versionM, version3);
+ QCOMPARE(master.valueString("hello"), QString("world3"));
+ QCOMPARE(versionL1, version2);
+ QCOMPARE(loser.valueString("hello"), QString("world2"));
+ } else {
+ QFAIL("version2 should be less than version 3");
+ }
+
+ // check ancestors of winner
+ QSet<QString> expectedVersions;
+ expectedVersions.insert(version1.toString());
+ QCOMPARE(master.subObject("_meta").subList("ancestors").size(), 1);
+ QVERIFY(expectedVersions.contains(master.subObject("_meta").subList("ancestors").stringAt(0)));
+
+ // check ancestors
+ QVERIFY(!loser.contains("_meta"));
+ QCOMPARE(QsonVersion::lastVersion(loser), versionL1);
+
+ // let's create another conflict (from scratch)
+ QsonMap qson4;
+ qson4.insert("_uuid", master.valueString("_uuid"));
+ QCOMPARE(qson4.valueString("_uuid"), master.valueString("_uuid"));
+ qson4.insert("hello", QString("world4"));
+ qson4.computeVersion();
+ QsonVersion version4 = QsonVersion::version(qson4);
+
+ // merge it in, version4 *must* lose, because its count is less
+ QVERIFY(master.mergeVersions(qson4));
+ QCOMPARE(QsonVersion::version(master), version3);
+ QCOMPARE(QsonVersion::lastVersion(master), version3);
+ QVERIFY(!master.contains("_lastVersion"));
+
+ // check master's _meta
+ QCOMPARE(master.valueType("_meta"), QsonObject::MapType);
+ QVERIFY(master.subObject("_meta").isMeta());
+ QCOMPARE(master.subObject("_meta").size(), 2);
+ QVERIFY(master.subObject("_meta").contains("ancestors"));
+ QCOMPARE(master.subObject("_meta").valueType("ancestors"), QsonObject::ListType);
+ QVERIFY(master.subObject("_meta").contains("conflicts"));
+ QCOMPARE(master.subObject("_meta").valueType("conflicts"), QsonObject::ListType);
+
+ // check ancestors
+ QCOMPARE(master.subObject("_meta").subList("ancestors").size(), 1);
+ QVERIFY(expectedVersions.contains(master.subObject("_meta").subList("ancestors").stringAt(0)));
+
+ // check conflicts
+ QVERIFY(version4 < version2); // ensure sorting order
+ QsonList conflicts = master.subObject("_meta").subList("conflicts");
+ QCOMPARE(conflicts.size(), 2);
+ QsonMap conflict0 = conflicts.objectAt(0);
+ QCOMPARE(QsonVersion::version(conflict0), version4);
+ QCOMPARE(QsonVersion::lastVersion(conflict0), version4);
+ QCOMPARE(conflict0.valueString("hello"), QString("world4"));
+ QVERIFY(!conflict0.contains("_meta"));
+ QsonMap conflict1 = conflicts.objectAt(1);
+ QCOMPARE(QsonVersion::version(conflict1), version2);
+ QCOMPARE(QsonVersion::lastVersion(conflict1), version2);
+ QCOMPARE(conflict1.valueString("hello"), QString("world2"));
+ QVERIFY(!conflict1.contains("_meta"));
+
+ QsonMap beforeReplay(master);
+ // let's try a replay, not should merge
+ QVERIFY(!master.mergeVersions(qson1));
+ QVERIFY(!master.mergeVersions(qson2));
+ QVERIFY(!master.mergeVersions(qson3));
+ QVERIFY(!master.mergeVersions(qson4));
+ QCOMPARE(master, beforeReplay);
+
+ // let's try advancing a conflict
+ qson21.insert("advanced", true);
+ qson21.computeVersion();
+ QsonVersion version21 = QsonVersion::version(qson21);
+ QCOMPARE(QsonVersion::lastVersion(qson21), version2);
+ QVERIFY(version21 != version2);
+
+ // merge it in
+ QVERIFY(master.mergeVersions(qson21));
+
+ // ensure sorting order
+ QVERIFY(version4 < version3);
+ QVERIFY(version3 < version21);
+
+ QCOMPARE(QsonVersion::version(master), version21);
+ QCOMPARE(master.valueString("hello"), QString("world2"));
+ QCOMPARE(master.valueBool("advanced"), true);
+
+ // check master's _meta
+ QCOMPARE(master.valueType("_meta"), QsonObject::MapType);
+ QVERIFY(master.subObject("_meta").isMeta());
+ QCOMPARE(master.subObject("_meta").size(), 2);
+ QVERIFY(master.subObject("_meta").contains("ancestors"));
+ QCOMPARE(master.subObject("_meta").valueType("ancestors"), QsonObject::ListType);
+ QVERIFY(master.subObject("_meta").contains("conflicts"));
+ QCOMPARE(master.subObject("_meta").valueType("conflicts"), QsonObject::ListType);
+
+ // ensure conflicts
+ conflicts = master.subObject("_meta").subList("conflicts");
+ QCOMPARE(conflicts.size(), 2);
+ QCOMPARE(QsonVersion::version(conflicts.objectAt(0)), version4);
+ QCOMPARE(conflicts.objectAt(0).valueString("hello"), QString("world4"));
+ QCOMPARE(QsonVersion::version(conflicts.objectAt(1)), version3);
+ QCOMPARE(conflicts.objectAt(1).valueString("hello"), QString("world3"));
+
+ // ensure ancestors
+ expectedVersions.clear();
+ expectedVersions.insert(version1.toString());
+ expectedVersions.insert(version2.toString());
+ QsonList ancestors = master.subObject("_meta").subList("ancestors");
+ QCOMPARE(ancestors.size(), 2);
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(0)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(1)));
+ QCOMPARE(expectedVersions.size(), 0);
+
+ // let's try tombstoning a conflict
+ QsonMap tombStone3 = conflicts.objectAt(1); // version3
+ tombStone3.insert("_deleted", true);
+ tombStone3.computeVersion();
+ QVERIFY(master.mergeVersions(tombStone3));
+
+ QCOMPARE(QsonVersion::version(master), version21);
+ QCOMPARE(QsonVersion::lastVersion(master), version21);
+ QCOMPARE(master.valueString("hello"), QString("world2"));
+ QCOMPARE(master.valueBool("advanced"), true);
+
+ // check master's _meta
+ QCOMPARE(master.valueType("_meta"), QsonObject::MapType);
+ QVERIFY(master.subObject("_meta").isMeta());
+ QCOMPARE(master.subObject("_meta").size(), 2);
+ QVERIFY(master.subObject("_meta").contains("ancestors"));
+ QCOMPARE(master.subObject("_meta").valueType("ancestors"), QsonObject::ListType);
+ QVERIFY(master.subObject("_meta").contains("conflicts"));
+ QCOMPARE(master.subObject("_meta").valueType("conflicts"), QsonObject::ListType);
+
+ // ensure conflicts
+ conflicts = master.subObject("_meta").subList("conflicts");
+ QCOMPARE(conflicts.size(), 1);
+ QCOMPARE(QsonVersion::version(conflicts.objectAt(0)), version4);
+ QCOMPARE(conflicts.objectAt(0).valueString("hello"), QString("world4"));
+
+ // ensure ancestors
+ expectedVersions.clear();
+ expectedVersions.insert(version1.toString());
+ expectedVersions.insert(version2.toString());
+ expectedVersions.insert(version3.toString());
+ expectedVersions.insert(QsonVersion::version(tombStone3).toString());
+ ancestors = master.subObject("_meta").subList("ancestors");
+ QCOMPARE(ancestors.size(), 4);
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(0)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(1)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(2)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(3)));
+ QCOMPARE(expectedVersions.size(), 0);
+
+ // now we tombstone the master
+ QsonMap tombStone21(master);
+ tombStone21.insert("_deleted", true);
+ tombStone21.computeVersion();
+
+ // merge it in
+ master.mergeVersions(tombStone21);
+
+ // master should now be dead with a conflict (the tombstone is ahead of conflict)
+ QCOMPARE(QsonVersion::version(master), QsonVersion::version(tombStone21));
+ QCOMPARE(QsonVersion::lastVersion(master), QsonVersion::version(tombStone21));
+ QCOMPARE(master.valueBool("_deleted"), true);
+
+ // check master's _meta
+ QCOMPARE(master.valueType("_meta"), QsonObject::MapType);
+ QVERIFY(master.subObject("_meta").isMeta());
+ QCOMPARE(master.subObject("_meta").size(), 2);
+ QVERIFY(master.subObject("_meta").contains("ancestors"));
+ QCOMPARE(master.subObject("_meta").valueType("ancestors"), QsonObject::ListType);
+ QVERIFY(master.subObject("_meta").contains("conflicts"));
+ QCOMPARE(master.subObject("_meta").valueType("conflicts"), QsonObject::ListType);
+
+ // ensure conflicts
+ conflicts = master.subObject("_meta").subList("conflicts");
+ QCOMPARE(conflicts.size(), 1);
+ QCOMPARE(QsonVersion::version(conflicts.objectAt(0)), version4);
+ QCOMPARE(conflicts.objectAt(0).valueString("hello"), QString("world4"));
+
+ // ensure ancestors
+ expectedVersions.clear();
+ expectedVersions.insert(version1.toString());
+ expectedVersions.insert(version2.toString());
+ expectedVersions.insert(version3.toString());
+ expectedVersions.insert(QsonVersion::version(tombStone3).toString());
+ expectedVersions.insert(version21.toString());
+ ancestors = master.subObject("_meta").subList("ancestors");
+ QCOMPARE(ancestors.size(), 5);
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(0)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(1)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(2)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(3)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(4)));
+ QCOMPARE(expectedVersions.size(), 0);
+
+ // check that master is still serializable
+ QsonParser parser;
+ parser.append(master.data());
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QsonMap reread = parser.getObject();
+ QCOMPARE(reread, master);
+}
+
+void TestCommon::testRecreate()
+{
+ QSet<QString> expectedVersions;
+
+ QsonMap qson;
+ qson.insert("run", 1);
+ qson.computeVersion();
+ QCOMPARE(qson.valueInt("_version"), 1);
+ expectedVersions.insert(qson.valueString("_version"));
+
+ qson.insert("_deleted", true);
+ qson.insert("_lastVersion", qson.valueString("_version"));
+ qson.computeVersion();
+ QCOMPARE(qson.valueInt("_version"), 2);
+ expectedVersions.insert(qson.valueString("_version"));
+
+ QsonMap again;
+ again.insert("_uuid", qson.valueString("_uuid"));
+ again.insert("run", 2);
+ again.computeVersion();
+
+ // keep a copy for 2nd test
+ QsonMap replication(qson);
+
+ // let's test the recreate test
+ qson.mergeVersions(again);
+
+ QsonVersion mergedVersion = QsonVersion::version(qson);
+ QCOMPARE(mergedVersion.updateCount(), quint32(3));
+ QCOMPARE(mergedVersion.hash(), QsonVersion::version(again).hash());
+
+ QVERIFY(!qson.subObject("_meta").contains("conflicts"));
+
+ QsonList ancestors = qson.subObject("_meta").subList("ancestors");
+ QCOMPARE(ancestors.size(), 2);
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(0)));
+ QVERIFY(expectedVersions.remove(ancestors.stringAt(1)));
+ QCOMPARE(expectedVersions.size(), 0);
+
+ // make sure in replication mode we actually create a conflict
+ replication.mergeVersions(again, true);
+ QCOMPARE(!qson.subObject("_meta").subList("conflicts").size(), 1);
+}
+
+void TestCommon::testQsonElement()
+{
+ QsonMap qson;
+ qson.insert("null", QsonObject::NullValue);
+ QsonElement test = qson.value<QsonElement>("null");
+ QCOMPARE(test.type(), QsonObject::NullType);
+ QCOMPARE(test.isNull(), true);
+
+ qson.insert("false", false);
+ test = qson.value<QsonElement>("false");
+ QCOMPARE(test.type(), QsonObject::BoolType);
+ QCOMPARE(test.value<bool>(), false);
+
+ qson.insert("true", true);
+ test = qson.value<QsonElement>("true");
+ QCOMPARE(test.type(), QsonObject::BoolType);
+ QCOMPARE(test.value<bool>(), true);
+
+ qson.insert("uint", (quint32) 1);
+ test = qson.value<QsonElement>("uint");
+ QCOMPARE(test.type(), QsonObject::UIntType);
+ QCOMPARE(test.value<quint32>(), (quint32) 1);
+
+ qson.insert("int", (qint32) 2);
+ test = qson.value<QsonElement>("int");
+ QCOMPARE(test.type(), QsonObject::IntType);
+ QCOMPARE(test.value<qint32>(), (qint32) 2);
+
+ qson.insert("double", 1.2);
+ test = qson.value<QsonElement>("double");
+ QCOMPARE(test.type(), QsonObject::DoubleType);
+ QCOMPARE(test.value<double>(), 1.2);
+
+ qson.insert(QLatin1String("string"), QLatin1String("qvalue"));
+ test = qson.value<QsonElement>("string");
+ QCOMPARE(test.type(), QsonObject::StringType);
+ QCOMPARE(test.value<QString>(), QLatin1String("qvalue"));
+
+ // test map.insert
+ QsonMap map;
+ map.insert(QLatin1String("insert"), test);
+ QCOMPARE(map.size(), 1);
+ QCOMPARE(map.valueType("insert"), QsonObject::StringType);
+ QCOMPARE(map.value<QString>("insert"), QLatin1String("qvalue"));
+
+ // test list.insert
+ QsonList list;
+ list.append(test);
+ QCOMPARE(list.size(), 1);
+ QCOMPARE(list.typeAt(0), QsonObject::StringType);
+ QCOMPARE(list.at<QString>(0), QLatin1String("qvalue"));
+
+ list.append(qson);
+ QCOMPARE(list.size(), 2);
+ QCOMPARE(list.typeAt(0), QsonObject::StringType);
+ QCOMPARE(list.at<QString>(0), QLatin1String("qvalue"));
+ QCOMPARE(list.typeAt(1), QsonObject::MapType);
+ QCOMPARE(list.at<QsonMap>(1), qson);
+
+ {
+ // test set-functions
+ QsonList list;
+ QsonElement element;
+ element.setValue(QsonObject::NullValue);
+ list.append(element);
+ QVERIFY(element.isNull());
+ QCOMPARE(list.typeAt(0), QsonObject::NullType);
+
+ element.setValue(true);
+ QCOMPARE(element.value<bool>(), true);
+ list.append(element);
+ QCOMPARE(list.typeAt(1), QsonObject::BoolType);
+
+ element.setValue(42);
+ QCOMPARE(element.value<qint32>(), 42);
+ list.append(element);
+ QCOMPARE(list.typeAt(2), QsonObject::IntType);
+
+ element.setValue(42.42);
+ QCOMPARE(element.value<double>(), 42.42);
+ list.append(element);
+ QCOMPARE(list.typeAt(3), QsonObject::DoubleType);
+
+ element.setValue(QString::fromLatin1("foobar"));
+ QCOMPARE(element.value<QString>(), QLatin1String("foobar"));
+ list.append(element);
+ QCOMPARE(list.typeAt(4), QsonObject::StringType);
+ }
+}
+
+void TestCommon::testEquals()
+{
+ {
+ QsonMap map1;
+ QsonMap map2;
+ QVERIFY(map1 == map2);
+ QVERIFY(!(map1 != map2));
+
+ map2 = map1;
+ QVERIFY(map1 == map2);
+ QVERIFY(!(map1 != map2));
+
+ map1.insert(QLatin1String("foo"), QLatin1String("bar"));
+ QVERIFY(map1 != map2);
+ QVERIFY(!(map1 == map2));
+
+ map2 = map1;
+ QVERIFY(map1 == map2);
+ QVERIFY(!(map1 != map2));
+
+ QsonMap map3;
+ QVERIFY(map1 != map3);
+ QVERIFY(!(map1 == map3));
+ map3.insert(QLatin1String("foo"), QLatin1String("bar"));
+ QVERIFY(map1 == map3);
+ QVERIFY(!(map1 != map3));
+ }
+
+ {
+ QsonList list1;
+ QsonList list2;
+ QVERIFY(list1 == list2);
+ QVERIFY(!(list1 != list2));
+
+ list2 = list1;
+ QVERIFY(list1 == list2);
+ QVERIFY(!(list1 != list2));
+
+ list1.append(QLatin1String("foo"));
+ QVERIFY(list1 != list2);
+ QVERIFY(!(list1 == list2));
+
+ list2 = list1;
+ QVERIFY(list1 == list2);
+ QVERIFY(!(list1 != list2));
+ }
+
+ {
+ QsonMap map1;
+ QsonMap map2;
+
+ map1.insert(QLatin1String("foo"), QLatin1String("bar"));
+ map2.insert(QLatin1String("foo"), QLatin1String("bar"));
+
+ QsonElement element1 = map1.value<QsonElement>(QLatin1String("foo"));
+ QsonElement element2 = map2.value<QsonElement>(QLatin1String("foo"));
+ QVERIFY(element1 == element2);
+ QVERIFY(!(element1 != element2));
+
+ QsonList list;
+ list.append(42);
+ list.append(QLatin1String("bar"));
+ QsonElement element3 = list.at<QsonElement>(1);
+ QVERIFY(element1 == element3);
+ QVERIFY(!(element1 != element3));
+ }
+
+ QsonMap map;
+ QsonList list;
+ QVERIFY(map != list);
+ QVERIFY(!(map == list));
+ QsonMap m; m.insert(QLatin1String("foo"), 42);
+ QsonList l; l.append(42);
+}
+
+void TestCommon::testQsonParser()
+{
+ QsonMap qson;
+ qson.insert(QLatin1String("hello"), QLatin1String("world"));
+
+ QsonMap qson1;
+ qson1.insert(QLatin1String("yes"), QLatin1String("no"));
+
+ QsonList subList;
+ subList.append(qson);
+ subList.append(true);
+ subList.append(qson1);
+ subList.append(false);
+
+ QsonList list;
+ list.append(subList);
+
+ QsonMap container;
+ container.insert("list", list);
+
+ QByteArray raw = container.data();
+
+ QsonParser parser;
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+
+ // read once as a complete qbytearray
+ parser.append(raw);
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+
+ QsonMap reread = QsonMap(parser.getObject());
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+
+ QCOMPARE(reread.dataSize(), container.dataSize());
+ QCOMPARE(reread.size(), container.size());
+ QCOMPARE(reread.data(), container.data());
+ QCOMPARE(reread, container);
+
+ // read once as a complete char array
+ parser.append(raw.constData(), raw.size());
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+
+ reread = QsonMap(parser.getObject());
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+
+ QCOMPARE(reread.dataSize(), container.dataSize());
+ QCOMPARE(reread.size(), container.size());
+ QCOMPARE(reread.data(), container.data());
+ QCOMPARE(reread, container);
+
+ // read chunked
+ parser.append(raw.left(10));
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+
+ parser.append(raw.constData() + 10, 10);
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+
+ parser.append(raw.mid(20));
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+
+ reread = QsonMap(parser.getObject());
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+
+ QCOMPARE(reread.dataSize(), container.dataSize());
+ QCOMPARE(reread.size(), container.size());
+ QCOMPARE(reread.data(), container.data());
+ QCOMPARE(reread, container);
+}
+
+void TestCommon::testQsonParserStreaming()
+{
+ QsonMap qson;
+ qson.insert(QLatin1String("hello"), QLatin1String("world"));
+
+ QsonMap qson1;
+ qson1.insert(QLatin1String("yes"), QLatin1String("no"));
+
+ QsonList subList;
+ subList.append(qson);
+ subList.append(true);
+ subList.append(qson1);
+ subList.append(false);
+
+ QsonList list;
+ list.append(subList);
+ list.append(qson);
+ list.append(subList);
+ list.append(qson1);
+
+ QsonParser parser(true);
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+ QVERIFY(!parser.isStream());
+ QVERIFY(!parser.streamDone());
+
+ parser.append(qson.data());
+ parser.append(list.data());
+ parser.append(qson1.data());
+ parser.append(list.data());
+
+ // before stream, read qson
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(!parser.isStream());
+ QVERIFY(!parser.streamDone());
+ QsonObject reread = parser.getObject();
+ QCOMPARE(QsonMap(reread), qson);
+
+ // streaming list, read list[0]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonList(reread), subList);
+
+ // streaming list, read list[1]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonMap(reread), qson);
+
+ // streaming list, read list[2]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonList(reread), subList);
+
+ // streaming list, read list[3]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonMap(reread), qson1);
+
+ // after stream
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+ QVERIFY(!parser.isStream());
+ QVERIFY(parser.streamDone());
+
+ // read qson1
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(!parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonMap(reread), qson1);
+
+ // streaming list, read list[0]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonList(reread), subList);
+
+ // streaming list, read list[1]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonMap(reread), qson);
+
+ // streaming list, read list[2]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonList(reread), subList);
+
+ // streaming list, read list[3]
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QVERIFY(parser.isStream());
+ QVERIFY(!parser.streamDone());
+ reread = parser.getObject();
+ QCOMPARE(QsonMap(reread), qson1);
+
+ // after stream
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+ QVERIFY(!parser.isStream());
+ QVERIFY(parser.streamDone());
+
+ // no more data available
+ QVERIFY(!parser.hasError());
+ QVERIFY(!parser.isObjectReady());
+ QVERIFY(!parser.isStream());
+ QVERIFY(!parser.streamDone());
+}
+
+void TestCommon::qsonParseDocument()
+{
+ QsonMap document;
+ document.generateUuid();
+ QsonMap map;
+ map.insert(QLatin1String("error"), QsonObject::NullValue);
+ map.insert(QLatin1String("id"), 1);
+ map.insert(QLatin1String("result"), document);
+
+ QByteArray data = map.data();
+ QCOMPARE(map.dataSize(), data.size());
+
+ QsonParser parser;
+ parser.append(data);
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+ QsonObject result = parser.getObject();
+ QCOMPARE(result, static_cast<QsonObject>(map));
+
+ QsonList list;
+ list.append(42);
+ list.append(document);
+ list.append(64);
+ data = list.data();
+ QsonParser parser2;
+ parser2.append(data);
+ QVERIFY(!parser2.hasError());
+ QVERIFY(parser2.isObjectReady());
+ result = parser2.getObject();
+ QCOMPARE(result, static_cast<QsonObject>(list));
+}
+
+void TestCommon::testComplexElement()
+{
+ QString json = "{\"_type\":\"Contact\",\"displayName\":\"Joe Smith\",\"name\":{\"firstName\":\"joe\",\"lastName\":\"smith\"},\"phoneNumbers\":[{\"number\":\"+15555551212\",\"type\":\"mobile\"},{\"number\":\"+17812232323\",\"type\":\"work\"},{\"number\":\"+16174532300\",\"type\":\"home\"}],\"preferredNumber\":\"+15555551212\"}";
+ JsonReader jparser;
+ jparser.parse(json);
+ QsonMap qson = variantToQson(jparser.result());
+
+ QByteArray data = qson.data();
+
+ QsonParser parser;
+ parser.append(data);
+
+ QVERIFY(!parser.hasError());
+ QVERIFY(parser.isObjectReady());
+
+ QsonMap qson2 = parser.getObject();
+ QsonList list = qson2.subList("phoneNumbers");
+ QsonElement element = qson2.value<QsonElement>("phoneNumbers");
+
+ QCOMPARE(element.type(), list.type());
+ QCOMPARE(element.mBody.size(), list.mBody.size());
+
+ QsonList list2(element);
+
+ QVERIFY(element == list);
+ QVERIFY(list2 == list);
+
+ QsonList emptyList;
+ QsonMap map;
+ map.insert("empty", emptyList);
+ QsonElement emptyElement = map.value<QsonElement>("empty");
+ QsonElement emptyList2 = emptyElement.toList();
+
+ QCOMPARE(emptyElement.type(), emptyList.type());
+ QVERIFY(emptyElement == emptyList);
+ QVERIFY(emptyList2 == emptyList);
+}
+
+void TestCommon::testInsertEmptyObject()
+{
+ QsonMap qson;
+ qson.insert("hello", QString("world"));
+ qson.insert("null", QsonObject());
+ qson.insert("foo", QString("bar"));
+ QCOMPARE(qson.size(), 3);
+ QCOMPARE(qson.valueString("hello"), QString("world"));
+ QVERIFY(qson.isNull("null"));
+ QCOMPARE(qson.valueString("foo"), QString("bar"));
+
+ QsonList list;
+ list.append(QString("world"));
+ list.append(QsonObject());
+ list.append(QString("bar"));
+
+ QCOMPARE(list.size(), 3);
+ QCOMPARE(list.stringAt(0), QString("world"));
+ QVERIFY(list.isNull(1));
+ QCOMPARE(list.stringAt(2), QString("bar"));
+}
+
+void TestCommon::testIsEmpty()
+{
+ QsonMap qson;
+ QVERIFY(qson.isEmpty());
+ qson.insert("a", 1);
+ QVERIFY(!qson.isEmpty());
+
+ QsonMap doc;
+ QVERIFY(doc.isEmpty());
+ doc.computeVersion();
+ QVERIFY(!doc.isEmpty());
+}
+
+void TestCommon::testInsertUuid()
+{
+ QsonMap qson;
+ qson.ensureDocument();
+
+ QsonMap copy;
+ copy.insert("_uuid", qson.valueString("_uuid"));
+
+ QCOMPARE(copy.valueString("_uuid"), qson.valueString("_uuid"));
+ QCOMPARE(copy.valueString("_uuid").size(), 38);
+
+ QVERIFY(!QUuid(copy.valueString("_uuid")).isNull());
+ QCOMPARE((quint8) (QUuid(copy.valueString("_uuid")).version()), quint8(4));
+
+ copy.computeVersion();
+
+ QCOMPARE(copy.value<QsonElement>("_uuid").value<QString>(), copy.valueString("_uuid"));
+ QCOMPARE(copy.value<QsonElement>("_version").value<QString>(), copy.valueString("_version"));
+ QCOMPARE(copy.value<QsonElement>("_lastVersion").value<QString>(), copy.valueString("_lastVersion"));
+}
+
+void TestCommon::testQsonToJSValue()
+{
+ QsonMap qson;
+ QsonList values;
+ values.append(QString("Test1"));
+ values.append(QString("Test2"));
+ qson.insert("values", values);
+ QsonMap subObject;
+ subObject.insert("name", QString("John"));
+ qson.insert("sub", subObject);
+
+ QJSEngine *engine = new QJSEngine(this);
+ QJSValue jsv = qsonToJSValue(qson, engine);
+ QVERIFY(jsv.isObject());
+ QVERIFY(jsv.property("values").isArray());
+ QCOMPARE(jsv.property("values").property(0).toString(),QString("Test1"));
+ QCOMPARE(jsv.property("values").property(1).toString(), QString("Test2"));
+ QVERIFY(jsv.property("sub").isObject());
+ QCOMPARE(jsv.property("sub").property("name").toString(), QString("John"));
+
+}
+
+void TestCommon::testRemove()
+{
+ QsonMap qson;
+ QCOMPARE(qson.size(), 0);
+ QVERIFY(qson.isEmpty());
+
+ qson.insert("a", 1);
+ QCOMPARE(qson.size(), 1);
+ QVERIFY(!qson.isEmpty());
+
+ qson.remove("a");
+ QCOMPARE(qson.size(), 0);
+ QVERIFY(qson.isEmpty());
+
+ qson.insert("a", 1);
+ qson.insert("b", 2);
+ QCOMPARE(qson.size(), 2);
+ QVERIFY(!qson.isEmpty());
+
+ qson.remove("a");
+ QCOMPARE(qson.size(), 1);
+ QVERIFY(!qson.isEmpty());
+
+ QVERIFY(qson.contains("b"));
+ QCOMPARE(qson.valueInt("b"), 2);
+
+ QsonMap c;
+ c.insert("value", true);
+ qson.insert("c", c);
+ qson.insert("d", 3);
+
+ QCOMPARE(qson.size(), 3);
+ QVERIFY(!qson.isEmpty());
+
+ qson.remove("c");
+ QVERIFY(!qson.isEmpty());
+ QVERIFY(!qson.contains("c"));
+ QCOMPARE(qson.size(), 2);
+ QCOMPARE(qson.valueInt("b"), 2);
+ QCOMPARE(qson.valueInt("d"), 3);
+
+ QsonMap subObjectOnly;
+ subObjectOnly.insert("c", c);
+ subObjectOnly.remove("c");
+ QVERIFY(subObjectOnly.isEmpty());
+ QVERIFY(!subObjectOnly.contains("c"));
+ QCOMPARE(subObjectOnly.size(), 0);
+
+ QsonMap subObjectFirst;
+ subObjectFirst.insert("c", c);
+ subObjectFirst.insert("d", 3);
+ subObjectFirst.remove("c");
+ QVERIFY(!subObjectFirst.isEmpty());
+ QVERIFY(!subObjectFirst.contains("c"));
+ QVERIFY(subObjectFirst.contains("d"));
+ QCOMPARE(subObjectFirst.size(), 1);
+ QCOMPARE(subObjectFirst.valueInt("d"), 3);
+
+ // this will fail if page.updateOffset() is not called correctly
+ QsonMap checkSerialization;
+ checkSerialization.insert("a", 1);
+ checkSerialization.insert("b", 2);
+ checkSerialization.remove("b");
+ QsonMap reread = QsonParser::fromRawData(checkSerialization.data());
+ QCOMPARE(reread.size(), 1);
+ QCOMPARE(reread.valueInt("a"), 1);
+}
+
+void TestCommon::testDoubleInsert()
+{
+ QsonMap qson;
+ qson.insert("a", 1);
+
+ QsonMap b;
+ b.insert("value", false);
+ qson.insert("b", b);
+
+ qson.insert("a", 2);
+ b.insert("value", true);
+ qson.insert("b", b);
+
+ QsonMap replay;
+ replay.insert("a", 2);
+ QsonMap breplay;
+ breplay.insert("value", true);
+ replay.insert("b", breplay);
+
+ QCOMPARE(qson.dataSize(), replay.dataSize());
+ QCOMPARE(qson, replay);
+
+ qson.computeVersion();
+ replay.computeVersion();
+
+ QCOMPARE(QsonVersion::version(qson), QsonVersion::version(replay));
+}
+
+
+QTEST_MAIN(TestCommon)
+#include "test-common.moc"
diff --git a/tests/auto/daemon/array.json b/tests/auto/daemon/array.json
new file mode 100644
index 00000000..9eff59fa
--- /dev/null
+++ b/tests/auto/daemon/array.json
@@ -0,0 +1,116 @@
+[
+ {
+ "_type": "ContactInArray",
+ "displayName": "Joe Smith",
+ "name": {
+ "firstName": "joe",
+ "lastName": "smith"
+ },
+ "test": {
+ "45": "joe"
+ },
+ "test2": {
+ "56": {
+ "firstName": "joe"
+ }
+ },
+ "preferredNumber": "+15555551212",
+ "foo": [
+ [
+ { "bar": "val00" },
+ { "bar": "val01" },
+ { "bar": "val02" }
+ ],
+ [
+ { "bar": "val10" },
+ { "bar": "val11" },
+ { "bar": "val12" }
+ ]
+ ],
+ "phoneNumbers": [
+ {
+ "type": "mobile",
+ "number": "+15555551212",
+ "validTime": [
+ {
+ "timeFrom": "09:00",
+ "timeTo": "13:00"
+ },
+ {
+ "timeFrom": "16:00",
+ "timeTo": "20:00"
+ }
+ ]
+ },
+ {
+ "type": "work",
+ "number": "+17812232323",
+ "validTime": [
+ {
+ "timeFrom": "21:00",
+ "timeTo": "23:00"
+ }
+ ]
+ },
+ {
+ "type": "home",
+ "number": "+16174532300"
+ }
+ ]
+ },
+ {
+ "_type": "ContactInArray",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "doe"
+ },
+ "test": {
+ "45": "nancy"
+ },
+ "test2": {
+ "56": {
+ "firstName": "nancy"
+ }
+ },
+ "preferredNumber": "+14567891234",
+ "foo": [
+ [
+ { "bar": "val00" },
+ { "bar": "val01" },
+ { "bar": "val02" }
+ ],
+ [
+ { "bar": "val10" },
+ { "bar": "val11" },
+ { "bar": "val12" }
+ ]
+ ],
+ "phoneNumbers": [
+ {
+ "type": "mobile",
+ "number": "+14567891234",
+ "validTime": [
+ {
+ "timeFrom": "10:00",
+ "timeTo": "13:00"
+ },
+ {
+ "timeFrom": "16:00",
+ "timeTo": "20:00"
+ }
+ ]
+ },
+ {
+ "type": "home",
+ "number": "+16174532300",
+ "validTime": [
+ {
+ "timeFrom": "21:00",
+ "timeTo": "23:00"
+ }
+ ]
+ }
+ ]
+ }
+ ]
diff --git a/tests/auto/daemon/capabilities-test.json b/tests/auto/daemon/capabilities-test.json
new file mode 100644
index 00000000..be148873
--- /dev/null
+++ b/tests/auto/daemon/capabilities-test.json
@@ -0,0 +1,37 @@
+[
+ {
+ "_type": "Capability",
+ "name": "contacts",
+ "accessRules": {
+ "read": {
+ "read": ["[?_type=\"Contact\"]"]
+ },
+ "write": {
+ "write": ["[?_type=\"Contact\"]"]
+ }
+ }
+ },
+ {
+ "_type": "Capability",
+ "name": "email",
+ "accessRules": {
+ "read": {
+ "read": ["[?_type=\"Email\"]"]
+ },
+ "write": {
+ "write": ["[?_type=\"Email\"]"]
+ },
+ "send": {
+ "write": ["[?_type=\"OutgoingEmail\"]"]
+ }
+ }
+ },
+{
+ "_type": "CapabilitiesTest",
+ "identifier": "test1",
+ "capabilities": {
+ "email": ["send"],
+ "contacts": ["read", "write"]
+ }
+}
+]
diff --git a/tests/auto/daemon/daemon.pro b/tests/auto/daemon/daemon.pro
new file mode 100644
index 00000000..63852a15
--- /dev/null
+++ b/tests/auto/daemon/daemon.pro
@@ -0,0 +1,22 @@
+TARGET = tst_daemon
+
+QT = network declarative testlib jsondbqson-private
+CONFIG -= app_bundle
+CONFIG += debug
+
+INCLUDEPATH += $$PWD/../../../src/daemon
+LIBS += -L$$QT.jsondb.libs
+!mac:LIBS += -lssl -lcrypto
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include($$PWD/../../../src/daemon/daemon.pri)
+RESOURCES += json-validation.qrc
+
+SOURCES += \
+ testjsondb.cpp \
+
+
+check.target = check
+check.commands = rm -f *.db* && LD_LIBRARY_PATH=$$PWD/../../../lib QT_QPA_PLATFORM=xcb ./tst_daemon -xunitxml -silent > ../../../tst_server.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/auto/daemon/json-validation.qrc b/tests/auto/daemon/json-validation.qrc
new file mode 100644
index 00000000..5153c741
--- /dev/null
+++ b/tests/auto/daemon/json-validation.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>json-validation</file>
+</qresource>
+</RCC> \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-schema.json b/tests/auto/daemon/json-validation/array-boundaries-schema.json
new file mode 100644
index 00000000..59f001b9
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-schema.json
@@ -0,0 +1,12 @@
+{
+ "description": "Check an array items count",
+ "type": "object",
+ "properties": {
+ "twoOrLess": {
+ "maxItems": 2
+ },
+ "twoOrMore": {
+ "minItems": 2
+ }
+ }
+}
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-empty-valid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-empty-valid.json
new file mode 100644
index 00000000..0b99c24e
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-empty-valid.json
@@ -0,0 +1 @@
+{"twoOrLess":[]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-five-invalid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-five-invalid.json
new file mode 100644
index 00000000..93d0ec31
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-five-invalid.json
@@ -0,0 +1 @@
+{"twoOrLess":[1,2,3,4,5]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-two-valid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-two-valid.json
new file mode 100644
index 00000000..697c5bed
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrLess-two-valid.json
@@ -0,0 +1 @@
+{"twoOrLess":[1,2]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-empty-invalid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-empty-invalid.json
new file mode 100644
index 00000000..b5f2d19b
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-empty-invalid.json
@@ -0,0 +1 @@
+{"twoOrMore":[]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-five-valid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-five-valid.json
new file mode 100644
index 00000000..133961dd
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-five-valid.json
@@ -0,0 +1 @@
+{"twoOrMore":[1,2,3,4,5]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-one-invalid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-one-invalid.json
new file mode 100644
index 00000000..62a898f6
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-one-invalid.json
@@ -0,0 +1 @@
+{"twoOrMore":[1]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-two-valid.json b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-two-valid.json
new file mode 100644
index 00000000..4547d4cb
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-boundaries-twoOrMore-two-valid.json
@@ -0,0 +1 @@
+{"twoOrMore":[1,2]} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-empty-empty-valid.json b/tests/auto/daemon/json-validation/array-items-empty-empty-valid.json
new file mode 100644
index 00000000..49950992
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-empty-empty-valid.json
@@ -0,0 +1 @@
+{ "empty": [] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-empty-mixed-valid.json b/tests/auto/daemon/json-validation/array-items-empty-mixed-valid.json
new file mode 100644
index 00000000..e1a0d8f3
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-empty-mixed-valid.json
@@ -0,0 +1 @@
+{ "empty": [1, "foo", {"foo": 1}, 2, 3] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-empty-numbers-valid.json b/tests/auto/daemon/json-validation/array-items-empty-numbers-valid.json
new file mode 100644
index 00000000..712e146e
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-empty-numbers-valid.json
@@ -0,0 +1 @@
+{ "empty": [1,2,3] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-number-empty-valid.json b/tests/auto/daemon/json-validation/array-items-number-empty-valid.json
new file mode 100644
index 00000000..5ffae678
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-number-empty-valid.json
@@ -0,0 +1 @@
+{ "number": [] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-number-highnumbers-invalid.json b/tests/auto/daemon/json-validation/array-items-number-highnumbers-invalid.json
new file mode 100644
index 00000000..fc2347e4
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-number-highnumbers-invalid.json
@@ -0,0 +1 @@
+{ "number": [1, 2, 124123, 4] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-number-mixed-invalid.json b/tests/auto/daemon/json-validation/array-items-number-mixed-invalid.json
new file mode 100644
index 00000000..2b7d65e2
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-number-mixed-invalid.json
@@ -0,0 +1 @@
+{ "number": [1, "foo", {"a":"A"}, [1,2,4], 3] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-number-numbers-valid.json b/tests/auto/daemon/json-validation/array-items-number-numbers-valid.json
new file mode 100644
index 00000000..00986d93
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-number-numbers-valid.json
@@ -0,0 +1 @@
+{ "number": [1,2,3] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-number-object-invalid.json b/tests/auto/daemon/json-validation/array-items-number-object-invalid.json
new file mode 100644
index 00000000..3dd8b867
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-number-object-invalid.json
@@ -0,0 +1 @@
+{ "number": [{"string":1}] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-number-string-invalid.json b/tests/auto/daemon/json-validation/array-items-number-string-invalid.json
new file mode 100644
index 00000000..d5ccf425
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-number-string-invalid.json
@@ -0,0 +1 @@
+{ "number": ["string", 1] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-object-empty-valid.json b/tests/auto/daemon/json-validation/array-items-object-empty-valid.json
new file mode 100644
index 00000000..9a2f07d9
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-object-empty-valid.json
@@ -0,0 +1 @@
+{ "object": [ ] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-object-missingfoo-valid.json b/tests/auto/daemon/json-validation/array-items-object-missingfoo-valid.json
new file mode 100644
index 00000000..94ee005f
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-object-missingfoo-valid.json
@@ -0,0 +1,7 @@
+{ "object": [
+ { "id": 1, "foo": "pong!" },
+ { "id": 2 },
+ { "id": 3 },
+ { "id": 4, "foo": "pong!" }
+ ]
+} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-object-missingid-invalid.json b/tests/auto/daemon/json-validation/array-items-object-missingid-invalid.json
new file mode 100644
index 00000000..e1f13cdc
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-object-missingid-invalid.json
@@ -0,0 +1,7 @@
+{ "object": [
+ { "id": 1, "foo": "pong!" },
+ { "id": 2, "foo": "pong!" },
+ { "foo": "pong!" },
+ { "id": 4, "foo": "pong!" }
+ ]
+} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-object-numbers-invalid.json b/tests/auto/daemon/json-validation/array-items-object-numbers-invalid.json
new file mode 100644
index 00000000..98949560
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-object-numbers-invalid.json
@@ -0,0 +1 @@
+{ "object": [ 1, 5, 4] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-object-std-valid.json b/tests/auto/daemon/json-validation/array-items-object-std-valid.json
new file mode 100644
index 00000000..b8d3ffe2
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-object-std-valid.json
@@ -0,0 +1,7 @@
+{ "object": [
+ { "id": 1, "foo": "pong!" },
+ { "id": 2, "foo": "pong!" },
+ { "id": 3, "foo": "pong!" },
+ { "id": 4, "foo": "pong!" }
+ ]
+} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-object-strings-invalid.json b/tests/auto/daemon/json-validation/array-items-object-strings-invalid.json
new file mode 100644
index 00000000..35c1a0c4
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-object-strings-invalid.json
@@ -0,0 +1 @@
+{ "object": [ "id", "foo" ] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/array-items-schema.json b/tests/auto/daemon/json-validation/array-items-schema.json
new file mode 100644
index 00000000..c155ccd9
--- /dev/null
+++ b/tests/auto/daemon/json-validation/array-items-schema.json
@@ -0,0 +1,24 @@
+{
+ "description": "Check specification of array:items (5.5)",
+ "type": "object",
+ "properties": {
+ "empty": {
+ "description": "that is a stupid edge case, but it should work",
+ "items": {}
+ },
+ "number": {
+ "items": {
+ "type": "number",
+ "maximum": 10
+ }
+ },
+ "object": {
+ "items": {
+ "properties": {
+ "id": { "type": "integer", "required" : true },
+ "foo": { "type": "string"}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-one-invalid.json b/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-one-invalid.json
new file mode 100644
index 00000000..929d80a1
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-one-invalid.json
@@ -0,0 +1 @@
+{ "lessThenOne": 1 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-two-invalid.json b/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-two-invalid.json
new file mode 100644
index 00000000..fb694b0b
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-two-invalid.json
@@ -0,0 +1 @@
+{ "lessThenOne": 2 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-zero-valid.json b/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-zero-valid.json
new file mode 100644
index 00000000..8ab8beea
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-lessThenOne-zero-valid.json
@@ -0,0 +1 @@
+{ "lessThenOne": 0 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-one-invalid.json b/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-one-invalid.json
new file mode 100644
index 00000000..9197c7df
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-one-invalid.json
@@ -0,0 +1 @@
+{"moreThenOne":1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-two-valid.json b/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-two-valid.json
new file mode 100644
index 00000000..4eeb4bbc
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-two-valid.json
@@ -0,0 +1 @@
+{"moreThenOne":2} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-zero-invalid.json b/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-zero-invalid.json
new file mode 100644
index 00000000..c60214f4
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-moreThenOne-zero-invalid.json
@@ -0,0 +1 @@
+{"moreThenOne":0} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-one-valid.json b/tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-one-valid.json
new file mode 100644
index 00000000..c18da6ca
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-one-valid.json
@@ -0,0 +1 @@
+{ "oneOrLess": 1 }
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-two-invalid.json b/tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-two-invalid.json
new file mode 100644
index 00000000..27468647
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-oneOrLess-two-invalid.json
@@ -0,0 +1 @@
+{ "oneOrLess": 2 }
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-one-valid.json b/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-one-valid.json
new file mode 100644
index 00000000..1eecd48a
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-one-valid.json
@@ -0,0 +1 @@
+{"oneOrMore":1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-two-valid.json b/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-two-valid.json
new file mode 100644
index 00000000..e1bbfe04
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-two-valid.json
@@ -0,0 +1 @@
+{"oneOrMore":2} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-zero-invalid.json b/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-zero-invalid.json
new file mode 100644
index 00000000..848f6dc5
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-oneOrMore-zero-invalid.json
@@ -0,0 +1 @@
+{"oneOrMore":0} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/integer-boundaries-schema.json b/tests/auto/daemon/json-validation/integer-boundaries-schema.json
new file mode 100644
index 00000000..5575d28e
--- /dev/null
+++ b/tests/auto/daemon/json-validation/integer-boundaries-schema.json
@@ -0,0 +1,22 @@
+{
+ "description": "Check numbers boundaries",
+ "type": "object",
+ "properties": {
+ "oneOrLess": {
+ "type": "number",
+ "maximum": 1
+ },
+ "lessThenOne": {
+ "type": "number",
+ "exclusiveMaximum": 1
+ },
+ "oneOrMore": {
+ "type": "number",
+ "minimum": 1
+ },
+ "moreThenOne": {
+ "type": "number",
+ "exclusiveMinimum": 1
+ }
+ }
+}
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-one-invalid.json b/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-one-invalid.json
new file mode 100644
index 00000000..515feadc
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-one-invalid.json
@@ -0,0 +1 @@
+{ "lessThenOne": 1.1 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-two-invalid.json b/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-two-invalid.json
new file mode 100644
index 00000000..b353576e
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-two-invalid.json
@@ -0,0 +1 @@
+{ "lessThenOne": 2.1 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-zero-valid.json b/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-zero-valid.json
new file mode 100644
index 00000000..c3dc2ed0
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-lessThenOne-zero-valid.json
@@ -0,0 +1 @@
+{ "lessThenOne": 0.1 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-one-invalid.json b/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-one-invalid.json
new file mode 100644
index 00000000..16d07ce9
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-one-invalid.json
@@ -0,0 +1 @@
+{"moreThenOne":1.1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-two-valid.json b/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-two-valid.json
new file mode 100644
index 00000000..bdc4068f
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-two-valid.json
@@ -0,0 +1 @@
+{"moreThenOne":2.1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-zero-invalid.json b/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-zero-invalid.json
new file mode 100644
index 00000000..5e5d8962
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-moreThenOne-zero-invalid.json
@@ -0,0 +1 @@
+{"moreThenOne":0.1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-one-valid.json b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-one-valid.json
new file mode 100644
index 00000000..42600228
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-one-valid.json
@@ -0,0 +1 @@
+{ "oneOrLess": 1.1 }
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-two-invalid.json b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-two-invalid.json
new file mode 100644
index 00000000..2ebecfcf
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-two-invalid.json
@@ -0,0 +1 @@
+{ "oneOrLess": 2.1 }
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-zero-valid.json b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-zero-valid.json
new file mode 100644
index 00000000..e554507a
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrLess-zero-valid.json
@@ -0,0 +1 @@
+{ "oneOrLess": 0.1 }
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-one-valid.json b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-one-valid.json
new file mode 100644
index 00000000..f7ce9d88
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-one-valid.json
@@ -0,0 +1 @@
+{"oneOrMore":1.1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-two-valid.json b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-two-valid.json
new file mode 100644
index 00000000..5ef0d9e3
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-two-valid.json
@@ -0,0 +1 @@
+{"oneOrMore":2.1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-zero-invalid.json b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-zero-invalid.json
new file mode 100644
index 00000000..4730c400
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-oneOrMore-zero-invalid.json
@@ -0,0 +1 @@
+{"oneOrMore":0.1} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/numbers-boundaries-schema.json b/tests/auto/daemon/json-validation/numbers-boundaries-schema.json
new file mode 100644
index 00000000..74c02d96
--- /dev/null
+++ b/tests/auto/daemon/json-validation/numbers-boundaries-schema.json
@@ -0,0 +1,22 @@
+{
+ "description": "Check numbers boundaries",
+ "type": "object",
+ "properties": {
+ "oneOrLess": {
+ "type": "number",
+ "maximum": 1.1
+ },
+ "lessThenOne": {
+ "type": "number",
+ "exclusiveMaximum": 1.1
+ },
+ "oneOrMore": {
+ "type": "number",
+ "minimum": 1.1
+ },
+ "moreThenOne": {
+ "type": "number",
+ "exclusiveMinimum": 1.1
+ }
+ }
+}
diff --git a/tests/auto/daemon/json-validation/required-missing-invalid.json b/tests/auto/daemon/json-validation/required-missing-invalid.json
new file mode 100644
index 00000000..b4453061
--- /dev/null
+++ b/tests/auto/daemon/json-validation/required-missing-invalid.json
@@ -0,0 +1 @@
+{ "notSoImportant": 123 }
diff --git a/tests/auto/daemon/json-validation/required-nested-valid.json b/tests/auto/daemon/json-validation/required-nested-valid.json
new file mode 100644
index 00000000..f7571492
--- /dev/null
+++ b/tests/auto/daemon/json-validation/required-nested-valid.json
@@ -0,0 +1 @@
+{ "important": {"important": "important"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/required-notimportent-number-invalid.json b/tests/auto/daemon/json-validation/required-notimportent-number-invalid.json
new file mode 100644
index 00000000..a7325db0
--- /dev/null
+++ b/tests/auto/daemon/json-validation/required-notimportent-number-invalid.json
@@ -0,0 +1 @@
+{ "notimportant": 123 }
diff --git a/tests/auto/daemon/json-validation/required-number-valid.json b/tests/auto/daemon/json-validation/required-number-valid.json
new file mode 100644
index 00000000..78b039a7
--- /dev/null
+++ b/tests/auto/daemon/json-validation/required-number-valid.json
@@ -0,0 +1 @@
+{ "important": 123 }
diff --git a/tests/auto/daemon/json-validation/required-object-valid.json b/tests/auto/daemon/json-validation/required-object-valid.json
new file mode 100644
index 00000000..6acfbdc1
--- /dev/null
+++ b/tests/auto/daemon/json-validation/required-object-valid.json
@@ -0,0 +1 @@
+{ "important": {} }
diff --git a/tests/auto/daemon/json-validation/required-schema.json b/tests/auto/daemon/json-validation/required-schema.json
new file mode 100644
index 00000000..881e295b
--- /dev/null
+++ b/tests/auto/daemon/json-validation/required-schema.json
@@ -0,0 +1,12 @@
+{
+ "description": "check if a required property exists",
+ "type": "object",
+ "properties": {
+ "important": {
+ "required": true
+ },
+ "notimportant": {
+ "required": false
+ }
+ }
+}
diff --git a/tests/auto/daemon/json-validation/string-boundaries-max5chars-silo-valid.json b/tests/auto/daemon/json-validation/string-boundaries-max5chars-silo-valid.json
new file mode 100644
index 00000000..368f132f
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-max5chars-silo-valid.json
@@ -0,0 +1 @@
+{ "max5chars" : "silo" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-max5chars-silos-valid.json b/tests/auto/daemon/json-validation/string-boundaries-max5chars-silos-valid.json
new file mode 100644
index 00000000..d1c98da8
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-max5chars-silos-valid.json
@@ -0,0 +1 @@
+{ "max5chars" : "silos" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-max5chars-toolong-invalid.json b/tests/auto/daemon/json-validation/string-boundaries-max5chars-toolong-invalid.json
new file mode 100644
index 00000000..c7bdfe18
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-max5chars-toolong-invalid.json
@@ -0,0 +1 @@
+{ "max5chars" : "The rest is silence." } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-min5chars-silo-invalid.json b/tests/auto/daemon/json-validation/string-boundaries-min5chars-silo-invalid.json
new file mode 100644
index 00000000..dc085e9b
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-min5chars-silo-invalid.json
@@ -0,0 +1 @@
+{ "min5chars" : "silo" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-min5chars-silos-valid.json b/tests/auto/daemon/json-validation/string-boundaries-min5chars-silos-valid.json
new file mode 100644
index 00000000..6663c273
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-min5chars-silos-valid.json
@@ -0,0 +1 @@
+{ "min5chars" : "silos" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-min5chars-toolong-valid.json b/tests/auto/daemon/json-validation/string-boundaries-min5chars-toolong-valid.json
new file mode 100644
index 00000000..f1d60b45
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-min5chars-toolong-valid.json
@@ -0,0 +1 @@
+{ "min5chars" : "The rest is silence." } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-pattern-a-valid.json b/tests/auto/daemon/json-validation/string-boundaries-pattern-a-valid.json
new file mode 100644
index 00000000..1231c734
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-pattern-a-valid.json
@@ -0,0 +1 @@
+{ "regexpPattern" : "a" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-pattern-aaa-valid.json b/tests/auto/daemon/json-validation/string-boundaries-pattern-aaa-valid.json
new file mode 100644
index 00000000..8dc140af
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-pattern-aaa-valid.json
@@ -0,0 +1 @@
+{ "regexpPattern" : "aaa" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-pattern-ab-invalid.json b/tests/auto/daemon/json-validation/string-boundaries-pattern-ab-invalid.json
new file mode 100644
index 00000000..253168fd
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-pattern-ab-invalid.json
@@ -0,0 +1 @@
+{ "regexpPattern" : "ab" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/string-boundaries-schema.json b/tests/auto/daemon/json-validation/string-boundaries-schema.json
new file mode 100644
index 00000000..3aea2432
--- /dev/null
+++ b/tests/auto/daemon/json-validation/string-boundaries-schema.json
@@ -0,0 +1,19 @@
+{
+ "title": "Check string boundaries",
+ "description": "Checks for 5.16 - 5.18 points of spec",
+ "type": "object",
+ "properties": {
+ "max5chars": {
+ "type": "string",
+ "maxLength": 5
+ },
+ "min5chars": {
+ "type": "string",
+ "minLength": 5
+ },
+ "regexpPattern": {
+ "type": "string",
+ "pattern": "[a]+"
+ }
+ }
+}
diff --git a/tests/auto/daemon/json-validation/type-array-array-valid.json b/tests/auto/daemon/json-validation/type-array-array-valid.json
new file mode 100644
index 00000000..34425f30
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-array-array-valid.json
@@ -0,0 +1 @@
+{ "array": [1, 3, 5, 7, 11, 13] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-array-bool-invalid.json b/tests/auto/daemon/json-validation/type-array-bool-invalid.json
new file mode 100644
index 00000000..437a46bc
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-array-bool-invalid.json
@@ -0,0 +1 @@
+{ "array": false} \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-array-integer-invalid.json b/tests/auto/daemon/json-validation/type-array-integer-invalid.json
new file mode 100644
index 00000000..41f67e4b
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-array-integer-invalid.json
@@ -0,0 +1 @@
+{ "array": 123 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-array-number-invalid.json b/tests/auto/daemon/json-validation/type-array-number-invalid.json
new file mode 100644
index 00000000..15fca625
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-array-number-invalid.json
@@ -0,0 +1 @@
+{ "array": 1.23 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-array-object-invalid.json b/tests/auto/daemon/json-validation/type-array-object-invalid.json
new file mode 100644
index 00000000..af4ab14d
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-array-object-invalid.json
@@ -0,0 +1 @@
+{ "array": {"foo": 123 } } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-array-string-invalid.json b/tests/auto/daemon/json-validation/type-array-string-invalid.json
new file mode 100644
index 00000000..01fb9038
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-array-string-invalid.json
@@ -0,0 +1 @@
+{ "array": "sin(x)" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-array-invalid.json b/tests/auto/daemon/json-validation/type-bool-array-invalid.json
new file mode 100644
index 00000000..c9bb7920
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-array-invalid.json
@@ -0,0 +1 @@
+{ "boolean": [1, 1, 2, 3, 5, 8] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-false-valid.json b/tests/auto/daemon/json-validation/type-bool-false-valid.json
new file mode 100644
index 00000000..7f809e1a
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-false-valid.json
@@ -0,0 +1 @@
+{ "boolean": false } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-integer-invalid.json b/tests/auto/daemon/json-validation/type-bool-integer-invalid.json
new file mode 100644
index 00000000..1f6e88c5
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-integer-invalid.json
@@ -0,0 +1 @@
+{ "boolean": 12344 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-number-invalid.json b/tests/auto/daemon/json-validation/type-bool-number-invalid.json
new file mode 100644
index 00000000..2943012f
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-number-invalid.json
@@ -0,0 +1 @@
+{ "boolean": 123.44 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-object-invalid.json b/tests/auto/daemon/json-validation/type-bool-object-invalid.json
new file mode 100644
index 00000000..c763630d
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-object-invalid.json
@@ -0,0 +1 @@
+{ "boolean": {"three":"is a magic number"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-string-invalid.json b/tests/auto/daemon/json-validation/type-bool-string-invalid.json
new file mode 100644
index 00000000..678468c0
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-string-invalid.json
@@ -0,0 +1 @@
+{ "boolean": "true" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-bool-true-valid.json b/tests/auto/daemon/json-validation/type-bool-true-valid.json
new file mode 100644
index 00000000..a65bb225
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-bool-true-valid.json
@@ -0,0 +1 @@
+{ "boolean": true } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-integer-array-invalid.json b/tests/auto/daemon/json-validation/type-integer-array-invalid.json
new file mode 100644
index 00000000..75046728
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-integer-array-invalid.json
@@ -0,0 +1 @@
+{ "integer": ["foo","bar"] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-integer-bool-invalid.json b/tests/auto/daemon/json-validation/type-integer-bool-invalid.json
new file mode 100644
index 00000000..c5c25ed9
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-integer-bool-invalid.json
@@ -0,0 +1 @@
+{ "integer": true } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-integer-double-invalid.json b/tests/auto/daemon/json-validation/type-integer-double-invalid.json
new file mode 100644
index 00000000..50c93d7a
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-integer-double-invalid.json
@@ -0,0 +1 @@
+{ "integer": 40.4 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-integer-integer-valid.json b/tests/auto/daemon/json-validation/type-integer-integer-valid.json
new file mode 100644
index 00000000..f6922f01
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-integer-integer-valid.json
@@ -0,0 +1 @@
+{ "integer": 404 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-integer-object-invalid.json b/tests/auto/daemon/json-validation/type-integer-object-invalid.json
new file mode 100644
index 00000000..a3f1ee6a
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-integer-object-invalid.json
@@ -0,0 +1 @@
+{ "integer": {"foo":"bar"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-integer-string-invalid.json b/tests/auto/daemon/json-validation/type-integer-string-invalid.json
new file mode 100644
index 00000000..4fcdc391
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-integer-string-invalid.json
@@ -0,0 +1 @@
+{ "integer": "o radosci iskro bogow" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-mixed-array-invalid.json b/tests/auto/daemon/json-validation/type-mixed-array-invalid.json
new file mode 100644
index 00000000..0214a9bf
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-mixed-array-invalid.json
@@ -0,0 +1 @@
+{ "mixed": ["magic string", 3] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-mixed-double-invalid.json b/tests/auto/daemon/json-validation/type-mixed-double-invalid.json
new file mode 100644
index 00000000..98683900
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-mixed-double-invalid.json
@@ -0,0 +1 @@
+{ "mixed": 34.4 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-mixed-number-valid.json b/tests/auto/daemon/json-validation/type-mixed-number-valid.json
new file mode 100644
index 00000000..8a5ff6a7
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-mixed-number-valid.json
@@ -0,0 +1 @@
+{ "mixed": 3 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-mixed-object-invalid.json b/tests/auto/daemon/json-validation/type-mixed-object-invalid.json
new file mode 100644
index 00000000..87597e2d
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-mixed-object-invalid.json
@@ -0,0 +1 @@
+{ "mixed": {"say":"magic word"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-mixed-string-valid.json b/tests/auto/daemon/json-validation/type-mixed-string-valid.json
new file mode 100644
index 00000000..abc8f382
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-mixed-string-valid.json
@@ -0,0 +1 @@
+{ "mixed": "magic string" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-number-array-invalid.json b/tests/auto/daemon/json-validation/type-number-array-invalid.json
new file mode 100644
index 00000000..8afa6212
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-number-array-invalid.json
@@ -0,0 +1 @@
+{ "number": ["foo","bar"] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-number-bool-invalid.json b/tests/auto/daemon/json-validation/type-number-bool-invalid.json
new file mode 100644
index 00000000..f1407060
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-number-bool-invalid.json
@@ -0,0 +1 @@
+{ "number": false } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-number-double-valid.json b/tests/auto/daemon/json-validation/type-number-double-valid.json
new file mode 100644
index 00000000..74b549a2
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-number-double-valid.json
@@ -0,0 +1 @@
+{ "number": 40.4 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-number-number-valid.json b/tests/auto/daemon/json-validation/type-number-number-valid.json
new file mode 100644
index 00000000..27a667fa
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-number-number-valid.json
@@ -0,0 +1 @@
+{ "number": 404 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-number-object-invalid.json b/tests/auto/daemon/json-validation/type-number-object-invalid.json
new file mode 100644
index 00000000..68c2e512
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-number-object-invalid.json
@@ -0,0 +1 @@
+{ "number": {"foo":"bar"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-number-string-invalid.json b/tests/auto/daemon/json-validation/type-number-string-invalid.json
new file mode 100644
index 00000000..e19b9c88
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-number-string-invalid.json
@@ -0,0 +1 @@
+{ "number": "kartoflanka" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-object-array-invalid.json b/tests/auto/daemon/json-validation/type-object-array-invalid.json
new file mode 100644
index 00000000..69e69855
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-object-array-invalid.json
@@ -0,0 +1 @@
+{ "object": [123, "sin(x)"] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-object-bool-invalid.json b/tests/auto/daemon/json-validation/type-object-bool-invalid.json
new file mode 100644
index 00000000..1ee40176
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-object-bool-invalid.json
@@ -0,0 +1 @@
+{ "object": true } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-object-double-invalid.json b/tests/auto/daemon/json-validation/type-object-double-invalid.json
new file mode 100644
index 00000000..5728ac01
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-object-double-invalid.json
@@ -0,0 +1 @@
+{ "object": 12.3 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-object-number-invalid.json b/tests/auto/daemon/json-validation/type-object-number-invalid.json
new file mode 100644
index 00000000..bd527110
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-object-number-invalid.json
@@ -0,0 +1 @@
+{ "object": 123 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-object-object-valid.json b/tests/auto/daemon/json-validation/type-object-object-valid.json
new file mode 100644
index 00000000..f6b61530
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-object-object-valid.json
@@ -0,0 +1 @@
+{ "object": {"x":"sin(x)"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-object-string-invalid.json b/tests/auto/daemon/json-validation/type-object-string-invalid.json
new file mode 100644
index 00000000..7f5a952a
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-object-string-invalid.json
@@ -0,0 +1 @@
+{ "object": "sin(x)" } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-schema.json b/tests/auto/daemon/json-validation/type-schema.json
new file mode 100644
index 00000000..4aad2acd
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-schema.json
@@ -0,0 +1,33 @@
+{
+ "description": "check if a property type is correct",
+ "type": "object",
+ "properties": {
+ "string": {
+ "type": "string"
+ },
+ "number": {
+ "type": "number"
+ },
+ "integer": {
+ "type": "integer"
+ },
+ "boolean": {
+ "type": "boolean"
+ },
+ "object": {
+ "type": "object"
+ },
+ "array": {
+ "type": "array"
+ },
+ "null": {
+ "type": "null"
+ },
+ "any": {
+ "type": "any"
+ },
+ "mixed": {
+ "type": ["string", "integer"]
+ }
+ }
+}
diff --git a/tests/auto/daemon/json-validation/type-string-array-invalid.json b/tests/auto/daemon/json-validation/type-string-array-invalid.json
new file mode 100644
index 00000000..10c491d9
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-string-array-invalid.json
@@ -0,0 +1 @@
+{ "string": ["foo", "bar"] } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-string-bool-invalid.json b/tests/auto/daemon/json-validation/type-string-bool-invalid.json
new file mode 100644
index 00000000..d19d1048
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-string-bool-invalid.json
@@ -0,0 +1 @@
+{ "string": false } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-string-double-invalid.json b/tests/auto/daemon/json-validation/type-string-double-invalid.json
new file mode 100644
index 00000000..af4b6ed3
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-string-double-invalid.json
@@ -0,0 +1 @@
+{ "string":40.4 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-string-integer-invalid.json b/tests/auto/daemon/json-validation/type-string-integer-invalid.json
new file mode 100644
index 00000000..681e09b6
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-string-integer-invalid.json
@@ -0,0 +1 @@
+{ "string":404 } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-string-object-invalid.json b/tests/auto/daemon/json-validation/type-string-object-invalid.json
new file mode 100644
index 00000000..5f7702c5
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-string-object-invalid.json
@@ -0,0 +1 @@
+{ "string": {"foo":"bar"} } \ No newline at end of file
diff --git a/tests/auto/daemon/json-validation/type-string-string-valid.json b/tests/auto/daemon/json-validation/type-string-string-valid.json
new file mode 100644
index 00000000..5122b734
--- /dev/null
+++ b/tests/auto/daemon/json-validation/type-string-string-valid.json
@@ -0,0 +1 @@
+{ "string":"kartofel" } \ No newline at end of file
diff --git a/tests/auto/daemon/largeContactsTest.json b/tests/auto/daemon/largeContactsTest.json
new file mode 100644
index 00000000..7666c68f
--- /dev/null
+++ b/tests/auto/daemon/largeContactsTest.json
@@ -0,0 +1,1002 @@
+[
+{"name": "marcia d'arcy"},
+{"name": "jeffrey samuels"},
+{"name": "robert demmon"},
+{"name": "heidi motika"},
+{"name": "leslie pugh"},
+{"name": "ryan houlette"},
+{"name": "kenton kossan"},
+{"name": "connie goddard"},
+{"name": "andrew keopraseuth"},
+{"name": "charlie stern"},
+{"name": "alex free"},
+{"name": "glenn legros"},
+{"name": "sean joyce"},
+{"name": "bruce toth"},
+{"name": "amanda vaneffen"},
+{"name": "gary huss"},
+{"name": "stan young"},
+{"name": "jaclyn gregory"},
+{"name": "ryan sepulveda"},
+{"name": "thomas reim"},
+{"name": "matt ryan"},
+{"name": "matt muralt"},
+{"name": "jason lau"},
+{"name": "blake kewish"},
+{"name": "scott budge"},
+{"name": "keith archer"},
+{"name": "david hubb"},
+{"name": "joseph tsai"},
+{"name": "alla pimenov"},
+{"name": "marina albright"},
+{"name": "tim carver"},
+{"name": "rachel palomino"},
+{"name": "chris gaddis"},
+{"name": "ken boerman"},
+{"name": "annie kiang"},
+{"name": "allison aronne"},
+{"name": "jessica fritch"},
+{"name": "deb haffey"},
+{"name": "moshe shields"},
+{"name": "kyle thomas"},
+{"name": "becky hughes"},
+{"name": "dustin schneider"},
+{"name": "mary hardwick"},
+{"name": "andrew client"},
+{"name": "david conley"},
+{"name": "vicky lokis"},
+{"name": "cameron white"},
+{"name": "nicole rolland"},
+{"name": "jaime piazza"},
+{"name": "annetta cell"},
+{"name": "justin nay"},
+{"name": "terri guice"},
+{"name": "bobby wier"},
+{"name": "marc pollack"},
+{"name": "greg prather"},
+{"name": "mark shander"},
+{"name": "peter minko"},
+{"name": "dell support"},
+{"name": "martina yang"},
+{"name": "joan thomas"},
+{"name": "amanda kenny"},
+{"name": "rachel shane"},
+{"name": "herb kashmanian"},
+{"name": "tony plumber"},
+{"name": "stephanie aenchbacher"},
+{"name": "sue rassekh"},
+{"name": "thanh friend"},
+{"name": "alan olivera"},
+{"name": "joe alltel"},
+{"name": "greg locke"},
+{"name": "gary eckloff"},
+{"name": "jon lowey"},
+{"name": "susan mejia"},
+{"name": "jennifer joseph"},
+{"name": "lenny nie"},
+{"name": "joe mcdonald"},
+{"name": "pam whitworth"},
+{"name": "stephen manes"},
+{"name": "andrew hawkins"},
+{"name": "laurie cunningha"},
+{"name": "min springfield"},
+{"name": "jeffrey woods"},
+{"name": "joe rogers"},
+{"name": "josh okrent"},
+{"name": "carly buchman"},
+{"name": "robin phillips"},
+{"name": "brian ba"},
+{"name": "melissa manning"},
+{"name": "gina l"},
+{"name": "travis mcberny"},
+{"name": "casey phobest"},
+{"name": "cory dummer"},
+{"name": "jack petropoulos"},
+{"name": "jason mocha"},
+{"name": "nigel burns"},
+{"name": "bryan nava"},
+{"name": "kip larson"},
+{"name": "mike o'brien"},
+{"name": "chris tennis"},
+{"name": "roger stein"},
+{"name": "jim dolan"},
+{"name": "len donato"},
+{"name": "scott piercy"},
+{"name": "danielle baker"},
+{"name": "pete pgi"},
+{"name": "joel campos"},
+{"name": "burton drayer"},
+{"name": "jim trains"},
+{"name": "eugene suggs"},
+{"name": "darren cell"},
+{"name": "kevin reil"},
+{"name": "ryan horn"},
+{"name": "scott bednarke"},
+{"name": "bryce tirrell"},
+{"name": "gerald sharkey"},
+{"name": "joe terribilini"},
+{"name": "megan devey"},
+{"name": "greg teal"},
+{"name": "larry tonini"},
+{"name": "william boren"},
+{"name": "chris mora"},
+{"name": "carma allen"},
+{"name": "steve martin"},
+{"name": "martha buess"},
+{"name": "mitch williams"},
+{"name": "jen focus"},
+{"name": "dan price"},
+{"name": "debbie hobart"},
+{"name": "robert larson"},
+{"name": "todd murphy"},
+{"name": "columbus dispatcher"},
+{"name": "tami gunselman"},
+{"name": "aracely valle"},
+{"name": "craig lake"},
+{"name": "suzy chapman"},
+{"name": "brian sterk"},
+{"name": "stacy p"},
+{"name": "jacqueline o'brien"},
+{"name": "kelsie morrow"},
+{"name": "sean noel"},
+{"name": "roman wasylechko"},
+{"name": "golden tan"},
+{"name": "brooke schaum"},
+{"name": "chris sherman"},
+{"name": "brenda ryan"},
+{"name": "susan tipton"},
+{"name": "kevin graff"},
+{"name": "marvin khemorro"},
+{"name": "ruth garcia"},
+{"name": "tim cozzi"},
+{"name": "lydia michigan"},
+{"name": "brad miron"},
+{"name": "justin aharoni"},
+{"name": "sarah dulatre"},
+{"name": "david hollis"},
+{"name": "dave metrice"},
+{"name": "anthony vocare"},
+{"name": "fern acres"},
+{"name": "stephen casbon"},
+{"name": "bo basic"},
+{"name": "heath belser"},
+{"name": "pam reynolds"},
+{"name": "ryan copenhaver"},
+{"name": "crystal hutton"},
+{"name": "doug partlow"},
+{"name": "jackie b"},
+{"name": "eddie karim"},
+{"name": "ashley burlage"},
+{"name": "kevin mctaggert"},
+{"name": "karen therapist"},
+{"name": "kevin burket"},
+{"name": "kim olstad"},
+{"name": "steve smidley"},
+{"name": "frank olsthoorn"},
+{"name": "ann mackenzie"},
+{"name": "mike padgett"},
+{"name": "todd stenhouse"},
+{"name": "troy funnell"},
+{"name": "john lewin"},
+{"name": "matt baillie"},
+{"name": "ben opticians"},
+{"name": "nicole atkins"},
+{"name": "margie wallace"},
+{"name": "john weddle"},
+{"name": "cory kurtz"},
+{"name": "adam willie"},
+{"name": "william whitlow"},
+{"name": "john pantano"},
+{"name": "brandon cr"},
+{"name": "lindsey langer"},
+{"name": "marsha lochridge"},
+{"name": "dominic charles"},
+{"name": "kathy sweatt"},
+{"name": "brenda ups"},
+{"name": "gus mendoza"},
+{"name": "ray allen"},
+{"name": "randy stamper"},
+{"name": "jeffrey grandy"},
+{"name": "scott smit"},
+{"name": "jackie willis"},
+{"name": "stacey gardner"},
+{"name": "kim stumbaugh"},
+{"name": "rich beard"},
+{"name": "bob korutz"},
+{"name": "paul gay"},
+{"name": "kevin jacks"},
+{"name": "betty guzman"},
+{"name": "luke daugherty"},
+{"name": "diana simmons"},
+{"name": "doug dresser"},
+{"name": "mark charlinski"},
+{"name": "jen trollinger"},
+{"name": "taylor gay"},
+{"name": "john lach"},
+{"name": "kevin leidig"},
+{"name": "kim carmack"},
+{"name": "melissa chartrey"},
+{"name": "shawn williams"},
+{"name": "missy hunter"},
+{"name": "jennifer crowell"},
+{"name": "david salman"},
+{"name": "beatriz gonzales"},
+{"name": "eddy crazy"},
+{"name": "rob hamilton"},
+{"name": "mike bro"},
+{"name": "victor moy"},
+{"name": "jason wade"},
+{"name": "mike battaligni"},
+{"name": "ryan hemans"},
+{"name": "jason caron"},
+{"name": "virginia schneider"},
+{"name": "bill schranko"},
+{"name": "bob gilbertson"},
+{"name": "greg farrar"},
+{"name": "brooke silvas"},
+{"name": "mark leonard"},
+{"name": "david bond"},
+{"name": "jay livers"},
+{"name": "tim cares"},
+{"name": "tyrone peoples"},
+{"name": "lindsay cannaday"},
+{"name": "gayle linde"},
+{"name": "johnny hernandez"},
+{"name": "ramona new"},
+{"name": "jaimie youssef"},
+{"name": "regina weir"},
+{"name": "justin gillon"},
+{"name": "mike lampigino"},
+{"name": "barry ziskind"},
+{"name": "frankie suda"},
+{"name": "sandy akins"},
+{"name": "nathan smack"},
+{"name": "jeremy voit"},
+{"name": "summer goreham"},
+{"name": "john nixon"},
+{"name": "morgan willis"},
+{"name": "keith pressman"},
+{"name": "chris cuevas"},
+{"name": "kirsten baldwin"},
+{"name": "george neely"},
+{"name": "dustin f"},
+{"name": "deanne wilkes"},
+{"name": "tracy smithee"},
+{"name": "sammy furtado"},
+{"name": "april cummings"},
+{"name": "brian flora"},
+{"name": "mike scarborough"},
+{"name": "lynn mcalister"},
+{"name": "carl mciver"},
+{"name": "ryan rachas"},
+{"name": "paul cannan"},
+{"name": "mike scarlata"},
+{"name": "linda soccer"},
+{"name": "stuart jones"},
+{"name": "debra stein"},
+{"name": "jeff acton"},
+{"name": "daniel hansen"},
+{"name": "stanley ference"},
+{"name": "jasper lee"},
+{"name": "shawn castleberry"},
+{"name": "lindsey horner"},
+{"name": "ray catuogno"},
+{"name": "todd bugg"},
+{"name": "jeff meyers"},
+{"name": "ron conway"},
+{"name": "jessica lau"},
+{"name": "lindsay mckinnon"},
+{"name": "jo cangianelli"},
+{"name": "barbara frazier"},
+{"name": "kieth harr"},
+{"name": "jen home"},
+{"name": "shirley brown"},
+{"name": "kim moat"},
+{"name": "albert reeves"},
+{"name": "joe pino"},
+{"name": "larry hartnett"},
+{"name": "jessica hobbins"},
+{"name": "kevin gangi"},
+{"name": "gerard centioli"},
+{"name": "melanie palomares"},
+{"name": "graham tenney"},
+{"name": "eric chapman"},
+{"name": "eileen bennett"},
+{"name": "chris sheehan"},
+{"name": "ann laffaye"},
+{"name": "tony truong"},
+{"name": "lyndon romero"},
+{"name": "rodney outland"},
+{"name": "chris turnage"},
+{"name": "ben terry"},
+{"name": "roxanne ruzicka"},
+{"name": "ryan phillips"},
+{"name": "nicholas amuchastegui"},
+{"name": "david james"},
+{"name": "matthew gabrielse"},
+{"name": "matt vandervoort"},
+{"name": "henry yaste"},
+{"name": "javier perez"},
+{"name": "hal noble"},
+{"name": "tom sommers"},
+{"name": "carleen copping"},
+{"name": "alexander moon"},
+{"name": "melanie thrower"},
+{"name": "jason wells"},
+{"name": "jay fraser"},
+{"name": "gary stacey"},
+{"name": "jill barfield"},
+{"name": "rhonda woodard"},
+{"name": "julia grimes"},
+{"name": "eddie girardi"},
+{"name": "chad carringer"},
+{"name": "peter schmitz"},
+{"name": "david lott"},
+{"name": "tom bardwell"},
+{"name": "larry shulman"},
+{"name": "james westford"},
+{"name": "ken mcnealy"},
+{"name": "patrick franks"},
+{"name": "phil rosenthal"},
+{"name": "nick b"},
+{"name": "albert dotson"},
+{"name": "sean beattie"},
+{"name": "gustavo ba"},
+{"name": "julie john"},
+{"name": "steve marra"},
+{"name": "nelson starlyn"},
+{"name": "brian cuzo"},
+{"name": "elisa thomas"},
+{"name": "joe crowley"},
+{"name": "isaac avanti"},
+{"name": "mark apt"},
+{"name": "colin poole"},
+{"name": "eric allen"},
+{"name": "lady vanessa"},
+{"name": "mike dj"},
+{"name": "robert eveleigh"},
+{"name": "travis york"},
+{"name": "james beckman"},
+{"name": "dawn bilings"},
+{"name": "lance bauerly"},
+{"name": "bradley erickson"},
+{"name": "gina eldridge"},
+{"name": "jason goodin"},
+{"name": "robin jones"},
+{"name": "jim manganoni"},
+{"name": "melody brinkley"},
+{"name": "mike stein"},
+{"name": "jason villard"},
+{"name": "ian kjerskagaard"},
+{"name": "dwayne romanchuk"},
+{"name": "ashley college"},
+{"name": "williams ii"},
+{"name": "ralph soest"},
+{"name": "danny iverson"},
+{"name": "ernie courson"},
+{"name": "ron berala"},
+{"name": "catherine simmons"},
+{"name": "dennis goodrich"},
+{"name": "brian moskowitz"},
+{"name": "mike maksimovic"},
+{"name": "jimmy banks"},
+{"name": "kate m"},
+{"name": "eric heubel"},
+{"name": "larry peters"},
+{"name": "daniel cozza"},
+{"name": "matt denicola"},
+{"name": "david ni"},
+{"name": "letha decaires"},
+{"name": "kareen larsen"},
+{"name": "terry khols"},
+{"name": "randi phillips"},
+{"name": "jeff jnl"},
+{"name": "mickey branson"},
+{"name": "jeremy richards"},
+{"name": "cynthia jutras"},
+{"name": "tia childres"},
+{"name": "chelsea store"},
+{"name": "emily provansal"},
+{"name": "cruz bautista"},
+{"name": "clay scrivner"},
+{"name": "lori baker"},
+{"name": "greg trinidad"},
+{"name": "leon lyons"},
+{"name": "alyssa sankin"},
+{"name": "alan freema"},
+{"name": "peter vogl"},
+{"name": "jill aguado"},
+{"name": "jason foster"},
+{"name": "virginia everard"},
+{"name": "tracey jackson"},
+{"name": "tiffany blakey"},
+{"name": "liz wood"},
+{"name": "david dejesus"},
+{"name": "joe eidel"},
+{"name": "levi bridges"},
+{"name": "tom orris"},
+{"name": "jeff micsky"},
+{"name": "teresa smith"},
+{"name": "jose palma"},
+{"name": "erin larson"},
+{"name": "kim pitman"},
+{"name": "susan ramirez"},
+{"name": "sandra becerra"},
+{"name": "danny iori"},
+{"name": "rochelle ferris"},
+{"name": "rod oconnor"},
+{"name": "doug porter"},
+{"name": "joseph mahendran"},
+{"name": "joann fitzpatrick"},
+{"name": "jeremy hastings"},
+{"name": "lisa scott"},
+{"name": "juan pacheco"},
+{"name": "laura e"},
+{"name": "rebecca seligstein"},
+{"name": "stephan gemine"},
+{"name": "keith penny"},
+{"name": "alex weathersby"},
+{"name": "raul camaligan"},
+{"name": "eric clemmons"},
+{"name": "bob cheryl"},
+{"name": "bob freedman"},
+{"name": "gary carreon"},
+{"name": "charles laurey"},
+{"name": "james hudsinker"},
+{"name": "sergio russo"},
+{"name": "chuck kennedy"},
+{"name": "randy dean"},
+{"name": "bill motley"},
+{"name": "ryan krishke"},
+{"name": "frank security"},
+{"name": "kris egbert"},
+{"name": "elliot moskowitz"},
+{"name": "cristina romero"},
+{"name": "kim tucker"},
+{"name": "steve norfolk"},
+{"name": "april saline"},
+{"name": "leonard schneider"},
+{"name": "tami kanitz"},
+{"name": "nick motto"},
+{"name": "sheldon morrison"},
+{"name": "ken liken"},
+{"name": "porter casey"},
+{"name": "matt fur"},
+{"name": "kit sullivan"},
+{"name": "jay adkisson"},
+{"name": "russell darrington"},
+{"name": "mitchell house"},
+{"name": "ronnie walton"},
+{"name": "jenna light"},
+{"name": "amber meshberger"},
+{"name": "shannon treglown"},
+{"name": "nickie paulate"},
+{"name": "mike iunker"},
+{"name": "cliff barber"},
+{"name": "cierra baxter"},
+{"name": "anna saah"},
+{"name": "larue steward"},
+{"name": "josh mcmeechan"},
+{"name": "brad beelaert"},
+{"name": "aaron ollivier"},
+{"name": "john cavallo"},
+{"name": "christine duprez"},
+{"name": "charlie stellini"},
+{"name": "paul waits"},
+{"name": "boyd elgin"},
+{"name": "chuck knapp"},
+{"name": "kelly k"},
+{"name": "sherie frehner"},
+{"name": "britney burton"},
+{"name": "gigi work"},
+{"name": "elaine biancamano"},
+{"name": "vince buffa"},
+{"name": "mike coffey"},
+{"name": "doug w"},
+{"name": "dave long"},
+{"name": "roger terrell"},
+{"name": "krishna kashyap"},
+{"name": "harold rosenfeld"},
+{"name": "sonia piano"},
+{"name": "antonio tenorio"},
+{"name": "guy bruno"},
+{"name": "mark gittens"},
+{"name": "anya jogie"},
+{"name": "jill schnepf"},
+{"name": "larry mactee"},
+{"name": "derek barvoets"},
+{"name": "bill wheelock"},
+{"name": "lauren gilomen"},
+{"name": "david ninkovich"},
+{"name": "mike brey"},
+{"name": "danny buhdda"},
+{"name": "thomas mirsen"},
+{"name": "jodi brockington"},
+{"name": "burt levine"},
+{"name": "mike isom"},
+{"name": "jeff hanson"},
+{"name": "mark kocur"},
+{"name": "ronny freeman"},
+{"name": "lloyd moore"},
+{"name": "barbara shore"},
+{"name": "stephanie boyer"},
+{"name": "ron wood"},
+{"name": "brian weinstein"},
+{"name": "dustin harwell"},
+{"name": "alex nash"},
+{"name": "mary meyeda"},
+{"name": "andrea grim"},
+{"name": "keith brazil"},
+{"name": "charles tomek"},
+{"name": "will engel"},
+{"name": "tim whitley"},
+{"name": "elvis lawson"},
+{"name": "molly peters"},
+{"name": "sherwood glen"},
+{"name": "joe spaldingl"},
+{"name": "annmarie colasanti"},
+{"name": "tony nguyen"},
+{"name": "dennis pool"},
+{"name": "bill gilliand"},
+{"name": "james crum"},
+{"name": "joan dooley"},
+{"name": "sarah hoobler"},
+{"name": "peter brambl"},
+{"name": "jack young"},
+{"name": "stephan auerbach"},
+{"name": "liz tmo"},
+{"name": "kristen mccoy"},
+{"name": "billy j"},
+{"name": "amanda salzman"},
+{"name": "brian maldonado"},
+{"name": "dave gronceski"},
+{"name": "martine garcon"},
+{"name": "andy cockle"},
+{"name": "suzi thek"},
+{"name": "dan theovenman"},
+{"name": "james brager"},
+{"name": "gloria silver"},
+{"name": "willie b"},
+{"name": "ed soares"},
+{"name": "allan toledo"},
+{"name": "mike frei"},
+{"name": "paul lenagh"},
+{"name": "ryan onishi"},
+{"name": "jessica mayor"},
+{"name": "megan feusner"},
+{"name": "dario casa"},
+{"name": "mike abdullah"},
+{"name": "catherine tsuruoka"},
+{"name": "patty sailors"},
+{"name": "stuart gedal"},
+{"name": "rebecca keogh"},
+{"name": "chris santos"},
+{"name": "bill pics"},
+{"name": "harley jackson"},
+{"name": "caryn lee"},
+{"name": "jaime cunanan"},
+{"name": "ila biser"},
+{"name": "lorie webb"},
+{"name": "nadia chaudhry"},
+{"name": "joshua spencer"},
+{"name": "toni brooks"},
+{"name": "james sheppard"},
+{"name": "marcel mandroc"},
+{"name": "joe amio"},
+{"name": "dave roughton"},
+{"name": "raymond flores"},
+{"name": "brandy coote"},
+{"name": "gabriella novotny"},
+{"name": "micheal alvis"},
+{"name": "maria bustillos"},
+{"name": "kelly karole"},
+{"name": "kristy cox"},
+{"name": "stephanie pucin"},
+{"name": "robert richardson"},
+{"name": "bruno gerber"},
+{"name": "claude fortier"},
+{"name": "robert metter"},
+{"name": "nancy nardoni"},
+{"name": "paige lombardo"},
+{"name": "danny d"},
+{"name": "rachel cooke"},
+{"name": "sam bell"},
+{"name": "letty canals"},
+{"name": "andy zaleta"},
+{"name": "linda frankel"},
+{"name": "bunny james"},
+{"name": "bill d"},
+{"name": "patrick penner"},
+{"name": "vanessa faustino"},
+{"name": "meagan leis"},
+{"name": "ed chomik"},
+{"name": "tia jess"},
+{"name": "michael farlow"},
+{"name": "matt moore"},
+{"name": "john bleid"},
+{"name": "tim heidi"},
+{"name": "raymond thompson"},
+{"name": "howard kummer"},
+{"name": "eli karp"},
+{"name": "wallace howard"},
+{"name": "ryan circa"},
+{"name": "julie stout"},
+{"name": "jan press"},
+{"name": "mark t"},
+{"name": "greg mccormick"},
+{"name": "ed howell"},
+{"name": "joan soltan"},
+{"name": "raymond schiefen"},
+{"name": "margery shanoff"},
+{"name": "leo schrubb"},
+{"name": "cliff joyner"},
+{"name": "michael tang"},
+{"name": "phylis fitzpatrick"},
+{"name": "carole noel"},
+{"name": "debbie beardsley"},
+{"name": "paul kushner"},
+{"name": "steve wickes"},
+{"name": "min jones"},
+{"name": "raul laguna"},
+{"name": "luis morales"},
+{"name": "robert stanton"},
+{"name": "karla larumbe"},
+{"name": "janet jones"},
+{"name": "drew brooks"},
+{"name": "michael zibby"},
+{"name": "kaylee b"},
+{"name": "kevin d"},
+{"name": "laveta jarrett"},
+{"name": "betty ward"},
+{"name": "lauren carden"},
+{"name": "jane leverone"},
+{"name": "john rucker"},
+{"name": "john chalif"},
+{"name": "lynn hughes"},
+{"name": "jon eliassen"},
+{"name": "edward coffey"},
+{"name": "gracie williams"},
+{"name": "art sepulveda"},
+{"name": "jon severson"},
+{"name": "dan kondziela"},
+{"name": "ila silberstein"},
+{"name": "ted holcomb"},
+{"name": "natasha wilsom"},
+{"name": "karl price"},
+{"name": "jim steed"},
+{"name": "chris condit"},
+{"name": "steve wallock"},
+{"name": "kellie sawler"},
+{"name": "stephanie seiboth"},
+{"name": "shannon flathers"},
+{"name": "chris weathers"},
+{"name": "lana guzman"},
+{"name": "chris coke"},
+{"name": "brian hammond"},
+{"name": "jim deforest"},
+{"name": "johnny murphy"},
+{"name": "marvin rapaport"},
+{"name": "shirley ma"},
+{"name": "steve carver"},
+{"name": "mary allen"},
+{"name": "bob nightwalker"},
+{"name": "mike fireplace"},
+{"name": "ike sushi"},
+{"name": "steve cynar"},
+{"name": "andy barborak"},
+{"name": "steven radunzel"},
+{"name": "jerry reese"},
+{"name": "jess r"},
+{"name": "liz brownson"},
+{"name": "jesus balbastro"},
+{"name": "jennifer watt"},
+{"name": "carlos cabeza"},
+{"name": "le tenis"},
+{"name": "barbara anthony"},
+{"name": "brent tomlin"},
+{"name": "tony sidekick"},
+{"name": "paul hanley"},
+{"name": "keri dunning"},
+{"name": "paige randall"},
+{"name": "jean duffin"},
+{"name": "pa jeffry"},
+{"name": "jane hadley"},
+{"name": "susan kurland"},
+{"name": "jay lindemann"},
+{"name": "anthony tucker"},
+{"name": "rod v"},
+{"name": "abby la"},
+{"name": "chris gentles"},
+{"name": "steve podium"},
+{"name": "karen wixom"},
+{"name": "ricky stephens"},
+{"name": "nathan camp"},
+{"name": "jill hirayama"},
+{"name": "audrey hamik"},
+{"name": "jay owens"},
+{"name": "caitlin slavka"},
+{"name": "julia molina"},
+{"name": "kevin o'connell"},
+{"name": "john dimatteo"},
+{"name": "mike villers"},
+{"name": "david aragon"},
+{"name": "tara gee"},
+{"name": "denise fiore"},
+{"name": "sue byrd"},
+{"name": "melanie barkers"},
+{"name": "heather o"},
+{"name": "rocio perez"},
+{"name": "eddie vasquez"},
+{"name": "torrie griffin"},
+{"name": "keri schadler"},
+{"name": "dave suarez"},
+{"name": "isabel kallman"},
+{"name": "darryl clark"},
+{"name": "nick porneala"},
+{"name": "janessa cell"},
+{"name": "dana hunter"},
+{"name": "harry spencer"},
+{"name": "jerry vancook"},
+{"name": "ira phone"},
+{"name": "terese stanek"},
+{"name": "hayden plimmer"},
+{"name": "dick eastman"},
+{"name": "ron bushnell"},
+{"name": "robin chaffin"},
+{"name": "ron grady"},
+{"name": "nikki clay"},
+{"name": "jeffrey wylie"},
+{"name": "mark biggers"},
+{"name": "cameron powell"},
+{"name": "diana office"},
+{"name": "kyle harms"},
+{"name": "jong han"},
+{"name": "robby padilla"},
+{"name": "arlene cabalatazan"},
+{"name": "james fatta"},
+{"name": "susy weibe"},
+{"name": "terry way"},
+{"name": "justin koolas"},
+{"name": "jeannette o'connor"},
+{"name": "julie cevette"},
+{"name": "daniel santil"},
+{"name": "george pauline"},
+{"name": "imelda sandoval"},
+{"name": "ben mcknight"},
+{"name": "melissa chan"},
+{"name": "alonzo lamarque"},
+{"name": "jake salwolke"},
+{"name": "mark cox"},
+{"name": "carol hanson"},
+{"name": "fred carnero"},
+{"name": "jean stefano"},
+{"name": "demetria lucas"},
+{"name": "libby lehman"},
+{"name": "leslie cliffs"},
+{"name": "nancy sigmund"},
+{"name": "bill l"},
+{"name": "tiana breniesse"},
+{"name": "todd beane"},
+{"name": "stewart freger"},
+{"name": "jerry vrabic"},
+{"name": "matt pierz"},
+{"name": "mike primo"},
+{"name": "alan prather"},
+{"name": "james penn"},
+{"name": "michael arevalo"},
+{"name": "jackie macdonald"},
+{"name": "brandon raybourne"},
+{"name": "aaron chavez"},
+{"name": "tara more"},
+{"name": "anna zastrow"},
+{"name": "diane couch"},
+{"name": "joe shively"},
+{"name": "yolande jones"},
+{"name": "don dillion"},
+{"name": "emily truong"},
+{"name": "dave deel"},
+{"name": "talitha fremont"},
+{"name": "jennifer marciniak"},
+{"name": "bella smith"},
+{"name": "damon ousley"},
+{"name": "brandon lungren"},
+{"name": "ross website"},
+{"name": "scott parker"},
+{"name": "craig hines"},
+{"name": "wally hunter"},
+{"name": "melissa wesd"},
+{"name": "bryan p"},
+{"name": "tom giordano"},
+{"name": "margaret whitesi"},
+{"name": "chris lytle"},
+{"name": "victor samaha"},
+{"name": "mark coyote"},
+{"name": "jose bormey"},
+{"name": "ralph finch"},
+{"name": "rich rodriguez"},
+{"name": "hank horowitz"},
+{"name": "doug shmalzle"},
+{"name": "mark neal"},
+{"name": "davis current"},
+{"name": "kelly gedinsky"},
+{"name": "derrick arakelian"},
+{"name": "josh cates"},
+{"name": "daniel wong"},
+{"name": "sharon hagins"},
+{"name": "cynthia giles"},
+{"name": "greg morris"},
+{"name": "erin mcdonald"},
+{"name": "peter arkley"},
+{"name": "josh ireland"},
+{"name": "jeanette vinnys"},
+{"name": "jon hibbard"},
+{"name": "justin nassie"},
+{"name": "heather mychaylo"},
+{"name": "mark voight"},
+{"name": "laci x"},
+{"name": "thomas kemp"},
+{"name": "kendra carmichael"},
+{"name": "stephen winters"},
+{"name": "lee lofgren"},
+{"name": "avery cell"},
+{"name": "kathy ferrey"},
+{"name": "angelia fritter"},
+{"name": "ed ryan"},
+{"name": "dana garcia"},
+{"name": "mandy s"},
+{"name": "lachelle maxwell"},
+{"name": "andrew quigley"},
+{"name": "sandra roxy"},
+{"name": "nancy trujillo"},
+{"name": "lynne erickson"},
+{"name": "kyle soccer"},
+{"name": "deirdre bischoff"},
+{"name": "leigh nauman"},
+{"name": "amy hansen"},
+{"name": "debbie switzenbaum"},
+{"name": "steve gluck"},
+{"name": "fred kikuchi"},
+{"name": "michelle cooley"},
+{"name": "suzy johnson"},
+{"name": "joe cargill"},
+{"name": "jeff martin"},
+{"name": "ashley fowler"},
+{"name": "melisa k"},
+{"name": "genevieve davis"},
+{"name": "corey medaris"},
+{"name": "joanne eancone"},
+{"name": "mike frazier"},
+{"name": "adam noppen"},
+{"name": "kenneth booker"},
+{"name": "alix krey"},
+{"name": "chris soseman"},
+{"name": "juan alvarez"},
+{"name": "steve luker"},
+{"name": "laura caravello"},
+{"name": "rico guitar"},
+{"name": "randy ingalls"},
+{"name": "robert lemen"},
+{"name": "terrence giles"},
+{"name": "stacey corbin"},
+{"name": "brian hollingsworth"},
+{"name": "guy kapuscinsky"},
+{"name": "keven rachel"},
+{"name": "erica altenhoff"},
+{"name": "jackie aguilar"},
+{"name": "jamie hensley"},
+{"name": "jeff sayer"},
+{"name": "bradley midtlien"},
+{"name": "courtney kelso"},
+{"name": "randy balhorn"},
+{"name": "jason bigge"},
+{"name": "britany neal"},
+{"name": "lyndon byam"},
+{"name": "kelsey shultz"},
+{"name": "sarah lovell"},
+{"name": "ethan orpilla"},
+{"name": "trey chase"},
+{"name": "nick monti"},
+{"name": "kelli oar"},
+{"name": "scott kelley"},
+{"name": "dianne james"},
+{"name": "jennifer keeler"},
+{"name": "scott c"},
+{"name": "rachael franks"},
+{"name": "sal pascent"},
+{"name": "scott hallmeyer"},
+{"name": "harry gold"},
+{"name": "julie tran"},
+{"name": "justin goins"},
+{"name": "joe rice"},
+{"name": "deb beebe"},
+{"name": "brian gregg"},
+{"name": "denise c"},
+{"name": "peter bichler"},
+{"name": "brandon lacoste"},
+{"name": "warren nb"},
+{"name": "vanessa rolfe"},
+{"name": "yvonne gonzales"},
+{"name": "darrell truitt"},
+{"name": "anne brummel"},
+{"name": "jeri idso"},
+{"name": "brad shinaut"},
+{"name": "sylvia israel"},
+{"name": "christina oliveras"},
+{"name": "andrew cason"},
+{"name": "pamela smith"},
+{"name": "rhea valenzuela"},
+{"name": "taylor cell"},
+{"name": "marisa victory"},
+{"name": "brandon epstein"},
+{"name": "rebecca feldman"},
+{"name": "steven haddad"},
+{"name": "sarai paljetak"},
+{"name": "david bergeron"},
+{"name": "allison hooker"},
+{"name": "lauri duplessis"},
+{"name": "jill sturgeon"},
+{"name": "marc alvarez"},
+{"name": "roger shiltz"},
+{"name": "cary lemons"},
+{"name": "greg kessner"},
+{"name": "cindy hooker"},
+{"name": "neil zuccato"},
+{"name": "kate wheadon"},
+{"name": "jennifer valencia"},
+{"name": "heather jarsso"},
+{"name": "eric basketball"},
+{"name": "sandra mceachern"},
+{"name": "jessica jackson"},
+{"name": "heidi ambrosius"},
+{"name": "tom isabella"},
+{"name": "tasha bridges"},
+{"name": "james guanzon"},
+{"name": "matt broad"},
+{"name": "steve hanson"},
+{"name": "tony tuor"},
+{"name": "sasha st"},
+{"name": "wayne krietz"},
+{"name": "kim harris"},
+{"name": "willis horak"},
+{"name": "seth peterson"},
+{"name": "lynette wright"},
+{"name": "dawn trotter"},
+{"name": "kyle keyser"},
+{"name": "john shults"},
+{"name": "bryan pennington"},
+{"name": "mike lambert"},
+{"name": "will seret"},
+{"name": "matt duhnam"},
+{"name": "robert long"},
+{"name": "marcel puyk"},
+{"name": "hannah physics"},
+{"name": "dan mcarthy"},
+{"name": "nick smith"},
+{"name": "bonnie james"},
+{"name": "alejandra cuevas"},
+{"name": "jenna kashou"},
+{"name": "greg martayan"},
+{"name": "jonathan sooriash"},
+{"name": "janice kaniewski"},
+{"name": "rebecca cullen"},
+{"name": "gary mckee"},
+{"name": "ken burgess"},
+{"name": "raven simone"},
+{"name": "shane rhoades"},
+{"name": "glenn jelks"},
+{"name": "randy tieg"},
+{"name": "wilson rita"},
+{"name": "ashley genske"},
+{"name": "bill boehm"},
+{"name": "robyn zeller"},
+{"name": "jennifer berry"},
+{"name": "jin woo"},
+{"name": "jim brun"},
+{"name": "ashley mom"},
+{"name": "mike gallen"},
+{"name": "michael jay"},
+{"name": "scott kam"},
+{"name": "mary jensen"},
+{"name": "luke reinbolt"},
+{"name": "frank trout"}
+]
diff --git a/tests/auto/daemon/largeContactsTest10k.json b/tests/auto/daemon/largeContactsTest10k.json
new file mode 100644
index 00000000..bd9f91f0
--- /dev/null
+++ b/tests/auto/daemon/largeContactsTest10k.json
@@ -0,0 +1,10002 @@
+[
+{"name": "marcia d'arcy"},
+{"name": "jeffrey samuels"},
+{"name": "robert demmon"},
+{"name": "heidi motika"},
+{"name": "leslie pugh"},
+{"name": "ryan houlette"},
+{"name": "kenton kossan"},
+{"name": "connie goddard"},
+{"name": "andrew keopraseuth"},
+{"name": "charlie stern"},
+{"name": "alex free"},
+{"name": "glenn legros"},
+{"name": "sean joyce"},
+{"name": "bruce toth"},
+{"name": "amanda vaneffen"},
+{"name": "gary huss"},
+{"name": "stan young"},
+{"name": "jaclyn gregory"},
+{"name": "ryan sepulveda"},
+{"name": "thomas reim"},
+{"name": "matt ryan"},
+{"name": "matt muralt"},
+{"name": "jason lau"},
+{"name": "blake kewish"},
+{"name": "scott budge"},
+{"name": "keith archer"},
+{"name": "david hubb"},
+{"name": "joseph tsai"},
+{"name": "alla pimenov"},
+{"name": "marina albright"},
+{"name": "tim carver"},
+{"name": "rachel palomino"},
+{"name": "chris gaddis"},
+{"name": "ken boerman"},
+{"name": "annie kiang"},
+{"name": "allison aronne"},
+{"name": "jessica fritch"},
+{"name": "deb haffey"},
+{"name": "moshe shields"},
+{"name": "kyle thomas"},
+{"name": "becky hughes"},
+{"name": "dustin schneider"},
+{"name": "mary hardwick"},
+{"name": "andrew client"},
+{"name": "david conley"},
+{"name": "vicky lokis"},
+{"name": "cameron white"},
+{"name": "nicole rolland"},
+{"name": "jaime piazza"},
+{"name": "annetta cell"},
+{"name": "justin nay"},
+{"name": "terri guice"},
+{"name": "bobby wier"},
+{"name": "marc pollack"},
+{"name": "greg prather"},
+{"name": "mark shander"},
+{"name": "peter minko"},
+{"name": "dell support"},
+{"name": "martina yang"},
+{"name": "joan thomas"},
+{"name": "amanda kenny"},
+{"name": "rachel shane"},
+{"name": "herb kashmanian"},
+{"name": "tony plumber"},
+{"name": "stephanie aenchbacher"},
+{"name": "sue rassekh"},
+{"name": "thanh friend"},
+{"name": "alan olivera"},
+{"name": "joe alltel"},
+{"name": "greg locke"},
+{"name": "gary eckloff"},
+{"name": "jon lowey"},
+{"name": "susan mejia"},
+{"name": "jennifer joseph"},
+{"name": "lenny nie"},
+{"name": "joe mcdonald"},
+{"name": "pam whitworth"},
+{"name": "stephen manes"},
+{"name": "andrew hawkins"},
+{"name": "laurie cunningha"},
+{"name": "min springfield"},
+{"name": "jeffrey woods"},
+{"name": "joe rogers"},
+{"name": "josh okrent"},
+{"name": "carly buchman"},
+{"name": "robin phillips"},
+{"name": "brian ba"},
+{"name": "melissa manning"},
+{"name": "gina l"},
+{"name": "travis mcberny"},
+{"name": "casey phobest"},
+{"name": "cory dummer"},
+{"name": "jack petropoulos"},
+{"name": "jason mocha"},
+{"name": "nigel burns"},
+{"name": "bryan nava"},
+{"name": "kip larson"},
+{"name": "mike o'brien"},
+{"name": "chris tennis"},
+{"name": "roger stein"},
+{"name": "jim dolan"},
+{"name": "len donato"},
+{"name": "scott piercy"},
+{"name": "danielle baker"},
+{"name": "pete pgi"},
+{"name": "joel campos"},
+{"name": "burton drayer"},
+{"name": "jim trains"},
+{"name": "eugene suggs"},
+{"name": "darren cell"},
+{"name": "kevin reil"},
+{"name": "ryan horn"},
+{"name": "scott bednarke"},
+{"name": "bryce tirrell"},
+{"name": "gerald sharkey"},
+{"name": "joe terribilini"},
+{"name": "megan devey"},
+{"name": "greg teal"},
+{"name": "larry tonini"},
+{"name": "william boren"},
+{"name": "chris mora"},
+{"name": "carma allen"},
+{"name": "steve martin"},
+{"name": "martha buess"},
+{"name": "mitch williams"},
+{"name": "jen focus"},
+{"name": "dan price"},
+{"name": "debbie hobart"},
+{"name": "robert larson"},
+{"name": "todd murphy"},
+{"name": "columbus dispatcher"},
+{"name": "tami gunselman"},
+{"name": "aracely valle"},
+{"name": "craig lake"},
+{"name": "suzy chapman"},
+{"name": "brian sterk"},
+{"name": "stacy p"},
+{"name": "jacqueline o'brien"},
+{"name": "kelsie morrow"},
+{"name": "sean noel"},
+{"name": "roman wasylechko"},
+{"name": "golden tan"},
+{"name": "brooke schaum"},
+{"name": "chris sherman"},
+{"name": "brenda ryan"},
+{"name": "susan tipton"},
+{"name": "kevin graff"},
+{"name": "marvin khemorro"},
+{"name": "ruth garcia"},
+{"name": "tim cozzi"},
+{"name": "lydia michigan"},
+{"name": "brad miron"},
+{"name": "justin aharoni"},
+{"name": "sarah dulatre"},
+{"name": "david hollis"},
+{"name": "dave metrice"},
+{"name": "anthony vocare"},
+{"name": "fern acres"},
+{"name": "stephen casbon"},
+{"name": "bo basic"},
+{"name": "heath belser"},
+{"name": "pam reynolds"},
+{"name": "ryan copenhaver"},
+{"name": "crystal hutton"},
+{"name": "doug partlow"},
+{"name": "jackie b"},
+{"name": "eddie karim"},
+{"name": "ashley burlage"},
+{"name": "kevin mctaggert"},
+{"name": "karen therapist"},
+{"name": "kevin burket"},
+{"name": "kim olstad"},
+{"name": "steve smidley"},
+{"name": "frank olsthoorn"},
+{"name": "ann mackenzie"},
+{"name": "mike padgett"},
+{"name": "todd stenhouse"},
+{"name": "troy funnell"},
+{"name": "john lewin"},
+{"name": "matt baillie"},
+{"name": "ben opticians"},
+{"name": "nicole atkins"},
+{"name": "margie wallace"},
+{"name": "john weddle"},
+{"name": "cory kurtz"},
+{"name": "adam willie"},
+{"name": "william whitlow"},
+{"name": "john pantano"},
+{"name": "brandon cr"},
+{"name": "lindsey langer"},
+{"name": "marsha lochridge"},
+{"name": "dominic charles"},
+{"name": "kathy sweatt"},
+{"name": "brenda ups"},
+{"name": "gus mendoza"},
+{"name": "ray allen"},
+{"name": "randy stamper"},
+{"name": "jeffrey grandy"},
+{"name": "scott smit"},
+{"name": "jackie willis"},
+{"name": "stacey gardner"},
+{"name": "kim stumbaugh"},
+{"name": "rich beard"},
+{"name": "bob korutz"},
+{"name": "paul gay"},
+{"name": "kevin jacks"},
+{"name": "betty guzman"},
+{"name": "luke daugherty"},
+{"name": "diana simmons"},
+{"name": "doug dresser"},
+{"name": "mark charlinski"},
+{"name": "jen trollinger"},
+{"name": "taylor gay"},
+{"name": "john lach"},
+{"name": "kevin leidig"},
+{"name": "kim carmack"},
+{"name": "melissa chartrey"},
+{"name": "shawn williams"},
+{"name": "missy hunter"},
+{"name": "jennifer crowell"},
+{"name": "david salman"},
+{"name": "beatriz gonzales"},
+{"name": "eddy crazy"},
+{"name": "rob hamilton"},
+{"name": "mike bro"},
+{"name": "victor moy"},
+{"name": "jason wade"},
+{"name": "mike battaligni"},
+{"name": "ryan hemans"},
+{"name": "jason caron"},
+{"name": "virginia schneider"},
+{"name": "bill schranko"},
+{"name": "bob gilbertson"},
+{"name": "greg farrar"},
+{"name": "brooke silvas"},
+{"name": "mark leonard"},
+{"name": "david bond"},
+{"name": "jay livers"},
+{"name": "tim cares"},
+{"name": "tyrone peoples"},
+{"name": "lindsay cannaday"},
+{"name": "gayle linde"},
+{"name": "johnny hernandez"},
+{"name": "ramona new"},
+{"name": "jaimie youssef"},
+{"name": "regina weir"},
+{"name": "justin gillon"},
+{"name": "mike lampigino"},
+{"name": "barry ziskind"},
+{"name": "frankie suda"},
+{"name": "sandy akins"},
+{"name": "nathan smack"},
+{"name": "jeremy voit"},
+{"name": "summer goreham"},
+{"name": "john nixon"},
+{"name": "morgan willis"},
+{"name": "keith pressman"},
+{"name": "chris cuevas"},
+{"name": "kirsten baldwin"},
+{"name": "george neely"},
+{"name": "dustin f"},
+{"name": "deanne wilkes"},
+{"name": "tracy smithee"},
+{"name": "sammy furtado"},
+{"name": "april cummings"},
+{"name": "brian flora"},
+{"name": "mike scarborough"},
+{"name": "lynn mcalister"},
+{"name": "carl mciver"},
+{"name": "ryan rachas"},
+{"name": "paul cannan"},
+{"name": "mike scarlata"},
+{"name": "linda soccer"},
+{"name": "stuart jones"},
+{"name": "debra stein"},
+{"name": "jeff acton"},
+{"name": "daniel hansen"},
+{"name": "stanley ference"},
+{"name": "jasper lee"},
+{"name": "shawn castleberry"},
+{"name": "lindsey horner"},
+{"name": "ray catuogno"},
+{"name": "todd bugg"},
+{"name": "jeff meyers"},
+{"name": "ron conway"},
+{"name": "jessica lau"},
+{"name": "lindsay mckinnon"},
+{"name": "jo cangianelli"},
+{"name": "barbara frazier"},
+{"name": "kieth harr"},
+{"name": "jen home"},
+{"name": "shirley brown"},
+{"name": "kim moat"},
+{"name": "albert reeves"},
+{"name": "joe pino"},
+{"name": "larry hartnett"},
+{"name": "jessica hobbins"},
+{"name": "kevin gangi"},
+{"name": "gerard centioli"},
+{"name": "melanie palomares"},
+{"name": "graham tenney"},
+{"name": "eric chapman"},
+{"name": "eileen bennett"},
+{"name": "chris sheehan"},
+{"name": "ann laffaye"},
+{"name": "tony truong"},
+{"name": "lyndon romero"},
+{"name": "rodney outland"},
+{"name": "chris turnage"},
+{"name": "ben terry"},
+{"name": "roxanne ruzicka"},
+{"name": "ryan phillips"},
+{"name": "nicholas amuchastegui"},
+{"name": "david james"},
+{"name": "matthew gabrielse"},
+{"name": "matt vandervoort"},
+{"name": "henry yaste"},
+{"name": "javier perez"},
+{"name": "hal noble"},
+{"name": "tom sommers"},
+{"name": "carleen copping"},
+{"name": "alexander moon"},
+{"name": "melanie thrower"},
+{"name": "jason wells"},
+{"name": "jay fraser"},
+{"name": "gary stacey"},
+{"name": "jill barfield"},
+{"name": "rhonda woodard"},
+{"name": "julia grimes"},
+{"name": "eddie girardi"},
+{"name": "chad carringer"},
+{"name": "peter schmitz"},
+{"name": "david lott"},
+{"name": "tom bardwell"},
+{"name": "larry shulman"},
+{"name": "james westford"},
+{"name": "ken mcnealy"},
+{"name": "patrick franks"},
+{"name": "phil rosenthal"},
+{"name": "nick b"},
+{"name": "albert dotson"},
+{"name": "sean beattie"},
+{"name": "gustavo ba"},
+{"name": "julie john"},
+{"name": "steve marra"},
+{"name": "nelson starlyn"},
+{"name": "brian cuzo"},
+{"name": "elisa thomas"},
+{"name": "joe crowley"},
+{"name": "isaac avanti"},
+{"name": "mark apt"},
+{"name": "colin poole"},
+{"name": "eric allen"},
+{"name": "lady vanessa"},
+{"name": "mike dj"},
+{"name": "robert eveleigh"},
+{"name": "travis york"},
+{"name": "james beckman"},
+{"name": "dawn bilings"},
+{"name": "lance bauerly"},
+{"name": "bradley erickson"},
+{"name": "gina eldridge"},
+{"name": "jason goodin"},
+{"name": "robin jones"},
+{"name": "jim manganoni"},
+{"name": "melody brinkley"},
+{"name": "mike stein"},
+{"name": "jason villard"},
+{"name": "ian kjerskagaard"},
+{"name": "dwayne romanchuk"},
+{"name": "ashley college"},
+{"name": "williams ii"},
+{"name": "ralph soest"},
+{"name": "danny iverson"},
+{"name": "ernie courson"},
+{"name": "ron berala"},
+{"name": "catherine simmons"},
+{"name": "dennis goodrich"},
+{"name": "brian moskowitz"},
+{"name": "mike maksimovic"},
+{"name": "jimmy banks"},
+{"name": "kate m"},
+{"name": "eric heubel"},
+{"name": "larry peters"},
+{"name": "daniel cozza"},
+{"name": "matt denicola"},
+{"name": "david ni"},
+{"name": "letha decaires"},
+{"name": "kareen larsen"},
+{"name": "terry khols"},
+{"name": "randi phillips"},
+{"name": "jeff jnl"},
+{"name": "mickey branson"},
+{"name": "jeremy richards"},
+{"name": "cynthia jutras"},
+{"name": "tia childres"},
+{"name": "chelsea store"},
+{"name": "emily provansal"},
+{"name": "cruz bautista"},
+{"name": "clay scrivner"},
+{"name": "lori baker"},
+{"name": "greg trinidad"},
+{"name": "leon lyons"},
+{"name": "alyssa sankin"},
+{"name": "alan freema"},
+{"name": "peter vogl"},
+{"name": "jill aguado"},
+{"name": "jason foster"},
+{"name": "virginia everard"},
+{"name": "tracey jackson"},
+{"name": "tiffany blakey"},
+{"name": "liz wood"},
+{"name": "david dejesus"},
+{"name": "joe eidel"},
+{"name": "levi bridges"},
+{"name": "tom orris"},
+{"name": "jeff micsky"},
+{"name": "teresa smith"},
+{"name": "jose palma"},
+{"name": "erin larson"},
+{"name": "kim pitman"},
+{"name": "susan ramirez"},
+{"name": "sandra becerra"},
+{"name": "danny iori"},
+{"name": "rochelle ferris"},
+{"name": "rod oconnor"},
+{"name": "doug porter"},
+{"name": "joseph mahendran"},
+{"name": "joann fitzpatrick"},
+{"name": "jeremy hastings"},
+{"name": "lisa scott"},
+{"name": "juan pacheco"},
+{"name": "laura e"},
+{"name": "rebecca seligstein"},
+{"name": "stephan gemine"},
+{"name": "keith penny"},
+{"name": "alex weathersby"},
+{"name": "raul camaligan"},
+{"name": "eric clemmons"},
+{"name": "bob cheryl"},
+{"name": "bob freedman"},
+{"name": "gary carreon"},
+{"name": "charles laurey"},
+{"name": "james hudsinker"},
+{"name": "sergio russo"},
+{"name": "chuck kennedy"},
+{"name": "randy dean"},
+{"name": "bill motley"},
+{"name": "ryan krishke"},
+{"name": "frank security"},
+{"name": "kris egbert"},
+{"name": "elliot moskowitz"},
+{"name": "cristina romero"},
+{"name": "kim tucker"},
+{"name": "steve norfolk"},
+{"name": "april saline"},
+{"name": "leonard schneider"},
+{"name": "tami kanitz"},
+{"name": "nick motto"},
+{"name": "sheldon morrison"},
+{"name": "ken liken"},
+{"name": "porter casey"},
+{"name": "matt fur"},
+{"name": "kit sullivan"},
+{"name": "jay adkisson"},
+{"name": "russell darrington"},
+{"name": "mitchell house"},
+{"name": "ronnie walton"},
+{"name": "jenna light"},
+{"name": "amber meshberger"},
+{"name": "shannon treglown"},
+{"name": "nickie paulate"},
+{"name": "mike iunker"},
+{"name": "cliff barber"},
+{"name": "cierra baxter"},
+{"name": "anna saah"},
+{"name": "larue steward"},
+{"name": "josh mcmeechan"},
+{"name": "brad beelaert"},
+{"name": "aaron ollivier"},
+{"name": "john cavallo"},
+{"name": "christine duprez"},
+{"name": "charlie stellini"},
+{"name": "paul waits"},
+{"name": "boyd elgin"},
+{"name": "chuck knapp"},
+{"name": "kelly k"},
+{"name": "sherie frehner"},
+{"name": "britney burton"},
+{"name": "gigi work"},
+{"name": "elaine biancamano"},
+{"name": "vince buffa"},
+{"name": "mike coffey"},
+{"name": "doug w"},
+{"name": "dave long"},
+{"name": "roger terrell"},
+{"name": "krishna kashyap"},
+{"name": "harold rosenfeld"},
+{"name": "sonia piano"},
+{"name": "antonio tenorio"},
+{"name": "guy bruno"},
+{"name": "mark gittens"},
+{"name": "anya jogie"},
+{"name": "jill schnepf"},
+{"name": "larry mactee"},
+{"name": "derek barvoets"},
+{"name": "bill wheelock"},
+{"name": "lauren gilomen"},
+{"name": "david ninkovich"},
+{"name": "mike brey"},
+{"name": "danny buhdda"},
+{"name": "thomas mirsen"},
+{"name": "jodi brockington"},
+{"name": "burt levine"},
+{"name": "mike isom"},
+{"name": "jeff hanson"},
+{"name": "mark kocur"},
+{"name": "ronny freeman"},
+{"name": "lloyd moore"},
+{"name": "barbara shore"},
+{"name": "stephanie boyer"},
+{"name": "ron wood"},
+{"name": "brian weinstein"},
+{"name": "dustin harwell"},
+{"name": "alex nash"},
+{"name": "mary meyeda"},
+{"name": "andrea grim"},
+{"name": "keith brazil"},
+{"name": "charles tomek"},
+{"name": "will engel"},
+{"name": "tim whitley"},
+{"name": "elvis lawson"},
+{"name": "molly peters"},
+{"name": "sherwood glen"},
+{"name": "joe spaldingl"},
+{"name": "annmarie colasanti"},
+{"name": "tony nguyen"},
+{"name": "dennis pool"},
+{"name": "bill gilliand"},
+{"name": "james crum"},
+{"name": "joan dooley"},
+{"name": "sarah hoobler"},
+{"name": "peter brambl"},
+{"name": "jack young"},
+{"name": "stephan auerbach"},
+{"name": "liz tmo"},
+{"name": "kristen mccoy"},
+{"name": "billy j"},
+{"name": "amanda salzman"},
+{"name": "brian maldonado"},
+{"name": "dave gronceski"},
+{"name": "martine garcon"},
+{"name": "andy cockle"},
+{"name": "suzi thek"},
+{"name": "dan theovenman"},
+{"name": "james brager"},
+{"name": "gloria silver"},
+{"name": "willie b"},
+{"name": "ed soares"},
+{"name": "allan toledo"},
+{"name": "mike frei"},
+{"name": "paul lenagh"},
+{"name": "ryan onishi"},
+{"name": "jessica mayor"},
+{"name": "megan feusner"},
+{"name": "dario casa"},
+{"name": "mike abdullah"},
+{"name": "catherine tsuruoka"},
+{"name": "patty sailors"},
+{"name": "stuart gedal"},
+{"name": "rebecca keogh"},
+{"name": "chris santos"},
+{"name": "bill pics"},
+{"name": "harley jackson"},
+{"name": "caryn lee"},
+{"name": "jaime cunanan"},
+{"name": "ila biser"},
+{"name": "lorie webb"},
+{"name": "nadia chaudhry"},
+{"name": "joshua spencer"},
+{"name": "toni brooks"},
+{"name": "james sheppard"},
+{"name": "marcel mandroc"},
+{"name": "joe amio"},
+{"name": "dave roughton"},
+{"name": "raymond flores"},
+{"name": "brandy coote"},
+{"name": "gabriella novotny"},
+{"name": "micheal alvis"},
+{"name": "maria bustillos"},
+{"name": "kelly karole"},
+{"name": "kristy cox"},
+{"name": "stephanie pucin"},
+{"name": "robert richardson"},
+{"name": "bruno gerber"},
+{"name": "claude fortier"},
+{"name": "robert metter"},
+{"name": "nancy nardoni"},
+{"name": "paige lombardo"},
+{"name": "danny d"},
+{"name": "rachel cooke"},
+{"name": "sam bell"},
+{"name": "letty canals"},
+{"name": "andy zaleta"},
+{"name": "linda frankel"},
+{"name": "bunny james"},
+{"name": "bill d"},
+{"name": "patrick penner"},
+{"name": "vanessa faustino"},
+{"name": "meagan leis"},
+{"name": "ed chomik"},
+{"name": "tia jess"},
+{"name": "michael farlow"},
+{"name": "matt moore"},
+{"name": "john bleid"},
+{"name": "tim heidi"},
+{"name": "raymond thompson"},
+{"name": "howard kummer"},
+{"name": "eli karp"},
+{"name": "wallace howard"},
+{"name": "ryan circa"},
+{"name": "julie stout"},
+{"name": "jan press"},
+{"name": "mark t"},
+{"name": "greg mccormick"},
+{"name": "ed howell"},
+{"name": "joan soltan"},
+{"name": "raymond schiefen"},
+{"name": "margery shanoff"},
+{"name": "leo schrubb"},
+{"name": "cliff joyner"},
+{"name": "michael tang"},
+{"name": "phylis fitzpatrick"},
+{"name": "carole noel"},
+{"name": "debbie beardsley"},
+{"name": "paul kushner"},
+{"name": "steve wickes"},
+{"name": "min jones"},
+{"name": "raul laguna"},
+{"name": "luis morales"},
+{"name": "robert stanton"},
+{"name": "karla larumbe"},
+{"name": "janet jones"},
+{"name": "drew brooks"},
+{"name": "michael zibby"},
+{"name": "kaylee b"},
+{"name": "kevin d"},
+{"name": "laveta jarrett"},
+{"name": "betty ward"},
+{"name": "lauren carden"},
+{"name": "jane leverone"},
+{"name": "john rucker"},
+{"name": "john chalif"},
+{"name": "lynn hughes"},
+{"name": "jon eliassen"},
+{"name": "edward coffey"},
+{"name": "gracie williams"},
+{"name": "art sepulveda"},
+{"name": "jon severson"},
+{"name": "dan kondziela"},
+{"name": "ila silberstein"},
+{"name": "ted holcomb"},
+{"name": "natasha wilsom"},
+{"name": "karl price"},
+{"name": "jim steed"},
+{"name": "chris condit"},
+{"name": "steve wallock"},
+{"name": "kellie sawler"},
+{"name": "stephanie seiboth"},
+{"name": "shannon flathers"},
+{"name": "chris weathers"},
+{"name": "lana guzman"},
+{"name": "chris coke"},
+{"name": "brian hammond"},
+{"name": "jim deforest"},
+{"name": "johnny murphy"},
+{"name": "marvin rapaport"},
+{"name": "shirley ma"},
+{"name": "steve carver"},
+{"name": "mary allen"},
+{"name": "bob nightwalker"},
+{"name": "mike fireplace"},
+{"name": "ike sushi"},
+{"name": "steve cynar"},
+{"name": "andy barborak"},
+{"name": "steven radunzel"},
+{"name": "jerry reese"},
+{"name": "jess r"},
+{"name": "liz brownson"},
+{"name": "jesus balbastro"},
+{"name": "jennifer watt"},
+{"name": "carlos cabeza"},
+{"name": "le tenis"},
+{"name": "barbara anthony"},
+{"name": "brent tomlin"},
+{"name": "tony sidekick"},
+{"name": "paul hanley"},
+{"name": "keri dunning"},
+{"name": "paige randall"},
+{"name": "jean duffin"},
+{"name": "pa jeffry"},
+{"name": "jane hadley"},
+{"name": "susan kurland"},
+{"name": "jay lindemann"},
+{"name": "anthony tucker"},
+{"name": "rod v"},
+{"name": "abby la"},
+{"name": "chris gentles"},
+{"name": "steve podium"},
+{"name": "karen wixom"},
+{"name": "ricky stephens"},
+{"name": "nathan camp"},
+{"name": "jill hirayama"},
+{"name": "audrey hamik"},
+{"name": "jay owens"},
+{"name": "caitlin slavka"},
+{"name": "julia molina"},
+{"name": "kevin o'connell"},
+{"name": "john dimatteo"},
+{"name": "mike villers"},
+{"name": "david aragon"},
+{"name": "tara gee"},
+{"name": "denise fiore"},
+{"name": "sue byrd"},
+{"name": "melanie barkers"},
+{"name": "heather o"},
+{"name": "rocio perez"},
+{"name": "eddie vasquez"},
+{"name": "torrie griffin"},
+{"name": "keri schadler"},
+{"name": "dave suarez"},
+{"name": "isabel kallman"},
+{"name": "darryl clark"},
+{"name": "nick porneala"},
+{"name": "janessa cell"},
+{"name": "dana hunter"},
+{"name": "harry spencer"},
+{"name": "jerry vancook"},
+{"name": "ira phone"},
+{"name": "terese stanek"},
+{"name": "hayden plimmer"},
+{"name": "dick eastman"},
+{"name": "ron bushnell"},
+{"name": "robin chaffin"},
+{"name": "ron grady"},
+{"name": "nikki clay"},
+{"name": "jeffrey wylie"},
+{"name": "mark biggers"},
+{"name": "cameron powell"},
+{"name": "diana office"},
+{"name": "kyle harms"},
+{"name": "jong han"},
+{"name": "robby padilla"},
+{"name": "arlene cabalatazan"},
+{"name": "james fatta"},
+{"name": "susy weibe"},
+{"name": "terry way"},
+{"name": "justin koolas"},
+{"name": "jeannette o'connor"},
+{"name": "julie cevette"},
+{"name": "daniel santil"},
+{"name": "george pauline"},
+{"name": "imelda sandoval"},
+{"name": "ben mcknight"},
+{"name": "melissa chan"},
+{"name": "alonzo lamarque"},
+{"name": "jake salwolke"},
+{"name": "mark cox"},
+{"name": "carol hanson"},
+{"name": "fred carnero"},
+{"name": "jean stefano"},
+{"name": "demetria lucas"},
+{"name": "libby lehman"},
+{"name": "leslie cliffs"},
+{"name": "nancy sigmund"},
+{"name": "bill l"},
+{"name": "tiana breniesse"},
+{"name": "todd beane"},
+{"name": "stewart freger"},
+{"name": "jerry vrabic"},
+{"name": "matt pierz"},
+{"name": "mike primo"},
+{"name": "alan prather"},
+{"name": "james penn"},
+{"name": "michael arevalo"},
+{"name": "jackie macdonald"},
+{"name": "brandon raybourne"},
+{"name": "aaron chavez"},
+{"name": "tara more"},
+{"name": "anna zastrow"},
+{"name": "diane couch"},
+{"name": "joe shively"},
+{"name": "yolande jones"},
+{"name": "don dillion"},
+{"name": "emily truong"},
+{"name": "dave deel"},
+{"name": "talitha fremont"},
+{"name": "jennifer marciniak"},
+{"name": "bella smith"},
+{"name": "damon ousley"},
+{"name": "brandon lungren"},
+{"name": "ross website"},
+{"name": "scott parker"},
+{"name": "craig hines"},
+{"name": "wally hunter"},
+{"name": "melissa wesd"},
+{"name": "bryan p"},
+{"name": "tom giordano"},
+{"name": "margaret whitesi"},
+{"name": "chris lytle"},
+{"name": "victor samaha"},
+{"name": "mark coyote"},
+{"name": "jose bormey"},
+{"name": "ralph finch"},
+{"name": "rich rodriguez"},
+{"name": "hank horowitz"},
+{"name": "doug shmalzle"},
+{"name": "mark neal"},
+{"name": "davis current"},
+{"name": "kelly gedinsky"},
+{"name": "derrick arakelian"},
+{"name": "josh cates"},
+{"name": "daniel wong"},
+{"name": "sharon hagins"},
+{"name": "cynthia giles"},
+{"name": "greg morris"},
+{"name": "erin mcdonald"},
+{"name": "peter arkley"},
+{"name": "josh ireland"},
+{"name": "jeanette vinnys"},
+{"name": "jon hibbard"},
+{"name": "justin nassie"},
+{"name": "heather mychaylo"},
+{"name": "mark voight"},
+{"name": "laci x"},
+{"name": "thomas kemp"},
+{"name": "kendra carmichael"},
+{"name": "stephen winters"},
+{"name": "lee lofgren"},
+{"name": "avery cell"},
+{"name": "kathy ferrey"},
+{"name": "angelia fritter"},
+{"name": "ed ryan"},
+{"name": "dana garcia"},
+{"name": "mandy s"},
+{"name": "lachelle maxwell"},
+{"name": "andrew quigley"},
+{"name": "sandra roxy"},
+{"name": "nancy trujillo"},
+{"name": "lynne erickson"},
+{"name": "kyle soccer"},
+{"name": "deirdre bischoff"},
+{"name": "leigh nauman"},
+{"name": "amy hansen"},
+{"name": "debbie switzenbaum"},
+{"name": "steve gluck"},
+{"name": "fred kikuchi"},
+{"name": "michelle cooley"},
+{"name": "suzy johnson"},
+{"name": "joe cargill"},
+{"name": "jeff martin"},
+{"name": "ashley fowler"},
+{"name": "melisa k"},
+{"name": "genevieve davis"},
+{"name": "corey medaris"},
+{"name": "joanne eancone"},
+{"name": "mike frazier"},
+{"name": "adam noppen"},
+{"name": "kenneth booker"},
+{"name": "alix krey"},
+{"name": "chris soseman"},
+{"name": "juan alvarez"},
+{"name": "steve luker"},
+{"name": "laura caravello"},
+{"name": "rico guitar"},
+{"name": "randy ingalls"},
+{"name": "robert lemen"},
+{"name": "terrence giles"},
+{"name": "stacey corbin"},
+{"name": "brian hollingsworth"},
+{"name": "guy kapuscinsky"},
+{"name": "keven rachel"},
+{"name": "erica altenhoff"},
+{"name": "jackie aguilar"},
+{"name": "jamie hensley"},
+{"name": "jeff sayer"},
+{"name": "bradley midtlien"},
+{"name": "courtney kelso"},
+{"name": "randy balhorn"},
+{"name": "jason bigge"},
+{"name": "britany neal"},
+{"name": "lyndon byam"},
+{"name": "kelsey shultz"},
+{"name": "sarah lovell"},
+{"name": "ethan orpilla"},
+{"name": "trey chase"},
+{"name": "nick monti"},
+{"name": "kelli oar"},
+{"name": "scott kelley"},
+{"name": "dianne james"},
+{"name": "jennifer keeler"},
+{"name": "scott c"},
+{"name": "rachael franks"},
+{"name": "sal pascent"},
+{"name": "scott hallmeyer"},
+{"name": "harry gold"},
+{"name": "julie tran"},
+{"name": "justin goins"},
+{"name": "joe rice"},
+{"name": "deb beebe"},
+{"name": "brian gregg"},
+{"name": "denise c"},
+{"name": "peter bichler"},
+{"name": "brandon lacoste"},
+{"name": "warren nb"},
+{"name": "vanessa rolfe"},
+{"name": "yvonne gonzales"},
+{"name": "darrell truitt"},
+{"name": "anne brummel"},
+{"name": "jeri idso"},
+{"name": "brad shinaut"},
+{"name": "sylvia israel"},
+{"name": "christina oliveras"},
+{"name": "andrew cason"},
+{"name": "pamela smith"},
+{"name": "rhea valenzuela"},
+{"name": "taylor cell"},
+{"name": "marisa victory"},
+{"name": "brandon epstein"},
+{"name": "rebecca feldman"},
+{"name": "steven haddad"},
+{"name": "sarai paljetak"},
+{"name": "david bergeron"},
+{"name": "allison hooker"},
+{"name": "lauri duplessis"},
+{"name": "jill sturgeon"},
+{"name": "marc alvarez"},
+{"name": "roger shiltz"},
+{"name": "cary lemons"},
+{"name": "greg kessner"},
+{"name": "cindy hooker"},
+{"name": "neil zuccato"},
+{"name": "kate wheadon"},
+{"name": "jennifer valencia"},
+{"name": "heather jarsso"},
+{"name": "eric basketball"},
+{"name": "sandra mceachern"},
+{"name": "jessica jackson"},
+{"name": "heidi ambrosius"},
+{"name": "tom isabella"},
+{"name": "tasha bridges"},
+{"name": "james guanzon"},
+{"name": "matt broad"},
+{"name": "steve hanson"},
+{"name": "tony tuor"},
+{"name": "sasha st"},
+{"name": "wayne krietz"},
+{"name": "kim harris"},
+{"name": "willis horak"},
+{"name": "seth peterson"},
+{"name": "lynette wright"},
+{"name": "dawn trotter"},
+{"name": "kyle keyser"},
+{"name": "john shults"},
+{"name": "bryan pennington"},
+{"name": "mike lambert"},
+{"name": "will seret"},
+{"name": "matt duhnam"},
+{"name": "robert long"},
+{"name": "marcel puyk"},
+{"name": "hannah physics"},
+{"name": "dan mcarthy"},
+{"name": "nick smith"},
+{"name": "bonnie james"},
+{"name": "alejandra cuevas"},
+{"name": "jenna kashou"},
+{"name": "greg martayan"},
+{"name": "jonathan sooriash"},
+{"name": "janice kaniewski"},
+{"name": "rebecca cullen"},
+{"name": "gary mckee"},
+{"name": "ken burgess"},
+{"name": "raven simone"},
+{"name": "shane rhoades"},
+{"name": "glenn jelks"},
+{"name": "randy tieg"},
+{"name": "wilson rita"},
+{"name": "ashley genske"},
+{"name": "bill boehm"},
+{"name": "robyn zeller"},
+{"name": "jennifer berry"},
+{"name": "jin woo"},
+{"name": "jim brun"},
+{"name": "ashley mom"},
+{"name": "mike gallen"},
+{"name": "michael jay"},
+{"name": "scott kam"},
+{"name": "mary jensen"},
+{"name": "luke reinbolt"},
+{"name": "frank trout"},
+{"name": "nick palihnich"},
+{"name": "wendy harston"},
+{"name": "jon treiber"},
+{"name": "janie coombs"},
+{"name": "wilson nevin"},
+{"name": "perry diekhuis"},
+{"name": "anthony c"},
+{"name": "amanda jonas"},
+{"name": "donna cabanne"},
+{"name": "jake carse"},
+{"name": "debby klinkhammer"},
+{"name": "echo drugs"},
+{"name": "erin delgadio"},
+{"name": "bill wood"},
+{"name": "leslie hutchinson"},
+{"name": "marisa melendez"},
+{"name": "korey schow"},
+{"name": "carmela hernaez"},
+{"name": "ignacio munoz"},
+{"name": "alex baluta"},
+{"name": "steve ferry"},
+{"name": "dana banker"},
+{"name": "kristin blackburn"},
+{"name": "ashley wilson"},
+{"name": "jared overeem"},
+{"name": "roxanne lee"},
+{"name": "ana banana"},
+{"name": "matt kulin"},
+{"name": "devorah lisbon"},
+{"name": "ken webb"},
+{"name": "lynette flintcraft"},
+{"name": "america servicing"},
+{"name": "tim king"},
+{"name": "rich hardy"},
+{"name": "courtney cummings"},
+{"name": "jason bravo"},
+{"name": "adam cook"},
+{"name": "todd holzemer"},
+{"name": "jeff boi"},
+{"name": "mike carry"},
+{"name": "mike warman"},
+{"name": "keith snow"},
+{"name": "rick courtin"},
+{"name": "mike labossiere"},
+{"name": "reena george"},
+{"name": "gary morin"},
+{"name": "suzanne landers"},
+{"name": "lori simmons"},
+{"name": "jared crowder"},
+{"name": "david crocket"},
+{"name": "sharon martin"},
+{"name": "matt janes"},
+{"name": "micheal gould"},
+{"name": "kristen foley"},
+{"name": "pat bledsoe"},
+{"name": "mary warner"},
+{"name": "devin smith"},
+{"name": "rich cusanno"},
+{"name": "dan siu"},
+{"name": "roger huffman"},
+{"name": "jamie m"},
+{"name": "tom jones"},
+{"name": "kristyn cunningham"},
+{"name": "neal smith"},
+{"name": "dallas smith"},
+{"name": "chris bambino"},
+{"name": "roy filkoff"},
+{"name": "frances desimone"},
+{"name": "steven roberto"},
+{"name": "andrew rolin"},
+{"name": "fred perron"},
+{"name": "shawn govern"},
+{"name": "pete long"},
+{"name": "robert dickerson"},
+{"name": "joe palladino"},
+{"name": "rich d’amore"},
+{"name": "christina valcke"},
+{"name": "mark victoriano"},
+{"name": "maurice samra"},
+{"name": "chad gilfillan"},
+{"name": "arthur bosma"},
+{"name": "greg hohman"},
+{"name": "janice luggar"},
+{"name": "paul tobin"},
+{"name": "trisha kiliany"},
+{"name": "alex russian"},
+{"name": "john honts"},
+{"name": "ken sambuchi"},
+{"name": "ralph hardimon"},
+{"name": "nancy herdeman"},
+{"name": "marie apigo"},
+{"name": "tom workman"},
+{"name": "steve roseman"},
+{"name": "jerry stevenson"},
+{"name": "marty martinson"},
+{"name": "ken nale"},
+{"name": "sarah dhooge"},
+{"name": "eric freeman"},
+{"name": "sterling king"},
+{"name": "allie dad"},
+{"name": "brian hirsch"},
+{"name": "shane w"},
+{"name": "len roos"},
+{"name": "mike lopez"},
+{"name": "sara henderson"},
+{"name": "karen harlan"},
+{"name": "brittany home"},
+{"name": "kathy koniezko"},
+{"name": "alana giraldi"},
+{"name": "lesa black"},
+{"name": "pat mcgaughey"},
+{"name": "greg irwin"},
+{"name": "michael miller"},
+{"name": "chance tracy"},
+{"name": "julene kafusi"},
+{"name": "travis hagens"},
+{"name": "steve leggett"},
+{"name": "jerry caringi"},
+{"name": "charles mintz"},
+{"name": "clyde thomas"},
+{"name": "alysha erwin"},
+{"name": "ray hebert"},
+{"name": "jim mauldin"},
+{"name": "pierre cooley"},
+{"name": "cesar econo"},
+{"name": "teddy mann"},
+{"name": "shawn zimmerman"},
+{"name": "george coules"},
+{"name": "michael preisler"},
+{"name": "russell petty"},
+{"name": "chris red"},
+{"name": "jaime reser"},
+{"name": "danielle ambriz"},
+{"name": "dee sanders"},
+{"name": "irma manzo"},
+{"name": "chad welstad"},
+{"name": "alan norquist"},
+{"name": "hillary nauholz"},
+{"name": "david j"},
+{"name": "will garcia"},
+{"name": "kelly williamson"},
+{"name": "peter christie"},
+{"name": "andy roby"},
+{"name": "aaron stalzer"},
+{"name": "huong hr"},
+{"name": "russell proutt"},
+{"name": "brian horrigan"},
+{"name": "eric lyke"},
+{"name": "ed garcia"},
+{"name": "camille chen"},
+{"name": "stephen young"},
+{"name": "terry viligante"},
+{"name": "dee green"},
+{"name": "robert steed"},
+{"name": "matt edwards"},
+{"name": "scott hartshorn"},
+{"name": "rich hebbel"},
+{"name": "ernie wagner"},
+{"name": "nicholas pape"},
+{"name": "bulah walker"},
+{"name": "tina martinez"},
+{"name": "britt balkcom"},
+{"name": "aimee miller"},
+{"name": "dave bench"},
+{"name": "judy mcneal"},
+{"name": "virginia shelley"},
+{"name": "geoffrey alexander"},
+{"name": "jeffrey freidman"},
+{"name": "marie woodard"},
+{"name": "jacinto villanueva"},
+{"name": "ashley wiseman"},
+{"name": "joe morris"},
+{"name": "david martinelli"},
+{"name": "joey b"},
+{"name": "fairy kitts"},
+{"name": "neal davis"},
+{"name": "pablo gray"},
+{"name": "kenneth nicholson"},
+{"name": "chris meyer"},
+{"name": "ronald kirk"},
+{"name": "jonathan becker"},
+{"name": "steve buckridge"},
+{"name": "brook hesano"},
+{"name": "randy anderson"},
+{"name": "trevor henderson"},
+{"name": "megan gabaldon"},
+{"name": "jeff sweetland"},
+{"name": "reggie cooley"},
+{"name": "jackie dowd"},
+{"name": "barry staton"},
+{"name": "sue newton"},
+{"name": "robert kaplan"},
+{"name": "aaron michaels"},
+{"name": "michelle ilse"},
+{"name": "sharon segal"},
+{"name": "dara anderson"},
+{"name": "charles gordon"},
+{"name": "christy clark"},
+{"name": "josh roth"},
+{"name": "tammy longton"},
+{"name": "jim blair"},
+{"name": "tyler rollins"},
+{"name": "sam vzw"},
+{"name": "adam horning"},
+{"name": "alex harding"},
+{"name": "jimmy yee"},
+{"name": "stacey leibert"},
+{"name": "matthew cassells"},
+{"name": "bruce takasaki"},
+{"name": "bryon kibildis"},
+{"name": "gary deckerd"},
+{"name": "priscilla walker"},
+{"name": "emily raggs"},
+{"name": "dorian beany"},
+{"name": "lawrence norman"},
+{"name": "chris panala"},
+{"name": "amy ruby"},
+{"name": "ken comer"},
+{"name": "frederic pouliot"},
+{"name": "travis stienkraus"},
+{"name": "trent allsup"},
+{"name": "nick ottawa"},
+{"name": "lori vincent"},
+{"name": "helaine abramson"},
+{"name": "kim dean"},
+{"name": "eric schena"},
+{"name": "ruben mora"},
+{"name": "peter martinelli"},
+{"name": "jay fubar"},
+{"name": "james dad"},
+{"name": "james mcgillivray"},
+{"name": "rhona walker"},
+{"name": "chris ng"},
+{"name": "goldie gupta"},
+{"name": "noah daniels"},
+{"name": "jeff tilley"},
+{"name": "cameron uecker"},
+{"name": "travis carlton"},
+{"name": "travis merrill"},
+{"name": "ada bennett"},
+{"name": "mike graham"},
+{"name": "troy jeff"},
+{"name": "michael haremski"},
+{"name": "jon alva"},
+{"name": "anthony barnes"},
+{"name": "claudia lopez"},
+{"name": "mariah lybarger"},
+{"name": "mike knollmann"},
+{"name": "ron ortiz"},
+{"name": "jordan wirsz"},
+{"name": "kevin glick"},
+{"name": "chad anderson"},
+{"name": "daphine jackson"},
+{"name": "randy semadeni"},
+{"name": "emma rhodes"},
+{"name": "ted hendrixson"},
+{"name": "matt jones"},
+{"name": "silvia yanez"},
+{"name": "jean daniels"},
+{"name": "harmony elementary"},
+{"name": "phyllis burkett"},
+{"name": "kevin traigle"},
+{"name": "arielle goode"},
+{"name": "kathleen connely"},
+{"name": "keith cornell"},
+{"name": "danyell kennedy"},
+{"name": "jay eagan"},
+{"name": "natalie b"},
+{"name": "laura castaneda"},
+{"name": "jessica prince"},
+{"name": "greg funck"},
+{"name": "audrey labruna"},
+{"name": "joel chack"},
+{"name": "corey johnson"},
+{"name": "deedra cunningham"},
+{"name": "stephan schambach"},
+{"name": "marcus ward"},
+{"name": "maria castellanos"},
+{"name": "paul mignosa"},
+{"name": "jose barthel"},
+{"name": "erin finn"},
+{"name": "robert holmes"},
+{"name": "david star"},
+{"name": "matt spoken"},
+{"name": "grant jones"},
+{"name": "aaron keller"},
+{"name": "terry maher"},
+{"name": "rachel resnick"},
+{"name": "matt horwich"},
+{"name": "mike holbrook"},
+{"name": "nadine b"},
+{"name": "karen hooker"},
+{"name": "paul perkins"},
+{"name": "darby cell"},
+{"name": "kayla aguila"},
+{"name": "chad kims"},
+{"name": "cathy rogers"},
+{"name": "adam halford"},
+{"name": "brandon doman"},
+{"name": "douglas dobbins"},
+{"name": "doug monica"},
+{"name": "diane ruff"},
+{"name": "thomas isett"},
+{"name": "debbie aholt"},
+{"name": "jason colbeck"},
+{"name": "maria damato"},
+{"name": "oscar quality"},
+{"name": "tim lawrence"},
+{"name": "irving wolf"},
+{"name": "dan spurgeon"},
+{"name": "marcus cousin"},
+{"name": "frank kavenik"},
+{"name": "paul ptt"},
+{"name": "kiara grant"},
+{"name": "sharon starr"},
+{"name": "john buenz"},
+{"name": "johnny sullivan"},
+{"name": "patrick burke"},
+{"name": "wilson tsai"},
+{"name": "rachel shine"},
+{"name": "evelyn applewaite"},
+{"name": "katie dalton"},
+{"name": "kelly diasio"},
+{"name": "bob zeibig"},
+{"name": "patrick farshon"},
+{"name": "darin emons"},
+{"name": "brandy basset"},
+{"name": "maria valencia"},
+{"name": "grover jackson"},
+{"name": "mark martin"},
+{"name": "andrew makowski"},
+{"name": "randy brandt"},
+{"name": "rick grinnell"},
+{"name": "tracey angel"},
+{"name": "megan witala"},
+{"name": "stephanie panduro"},
+{"name": "steve paray"},
+{"name": "carol gitau"},
+{"name": "damon kronsberg"},
+{"name": "eugenia caballero"},
+{"name": "bruce neal"},
+{"name": "robert house"},
+{"name": "sandy gerson"},
+{"name": "amanda bancroft"},
+{"name": "tanya denise"},
+{"name": "ken tam"},
+{"name": "samantha hanna"},
+{"name": "tyler n"},
+{"name": "melissa trousdale"},
+{"name": "vera orsorva"},
+{"name": "taylor cobb"},
+{"name": "pam leech"},
+{"name": "derek b"},
+{"name": "nicky von"},
+{"name": "alyssa amidon"},
+{"name": "ben yang"},
+{"name": "kenny sentz"},
+{"name": "jeanne denman"},
+{"name": "alexa avila"},
+{"name": "carl pennington"},
+{"name": "mike sal"},
+{"name": "gerald dezenski"},
+{"name": "tim waurick"},
+{"name": "brian kane"},
+{"name": "theresa bows"},
+{"name": "steve kadash"},
+{"name": "jason akron"},
+{"name": "scott misenbaum"},
+{"name": "julie weitzberg"},
+{"name": "jeff bontraiger"},
+{"name": "bob kirk"},
+{"name": "julie lefkowitz"},
+{"name": "phil weatherford"},
+{"name": "pete campbell"},
+{"name": "chris hefty"},
+{"name": "edwin maryland"},
+{"name": "julie lyons"},
+{"name": "david bywater"},
+{"name": "jen marcario"},
+{"name": "jo smith"},
+{"name": "brian hernandez"},
+{"name": "teressa meuse"},
+{"name": "heather rodd"},
+{"name": "tom brannis"},
+{"name": "jeanette gaines"},
+{"name": "andy bell"},
+{"name": "pam wagner"},
+{"name": "ricky tran"},
+{"name": "joan smothers"},
+{"name": "sonia quintanilla"},
+{"name": "jerry king"},
+{"name": "kevin mitchell"},
+{"name": "patrick martin"},
+{"name": "randy kirch"},
+{"name": "barbara cervantes"},
+{"name": "peter forrester"},
+{"name": "andrew mcafee"},
+{"name": "jack bridenstine"},
+{"name": "christine ray"},
+{"name": "darrell gibson"},
+{"name": "marge cunningham"},
+{"name": "lindsey vance"},
+{"name": "lori meisinger"},
+{"name": "don hom"},
+{"name": "karen lubbock"},
+{"name": "charles lombino"},
+{"name": "michael lovelace"},
+{"name": "jamie allen"},
+{"name": "laurie mn"},
+{"name": "chris varley"},
+{"name": "anita rivera"},
+{"name": "jason mccormick"},
+{"name": "doug dillard"},
+{"name": "bruce balch"},
+{"name": "ken dreifach"},
+{"name": "curtis lee"},
+{"name": "charles dillingham"},
+{"name": "denyse barham"},
+{"name": "fred schmidgall"},
+{"name": "rich maziman"},
+{"name": "tim mccray"},
+{"name": "james white"},
+{"name": "les desi"},
+{"name": "gloria huff"},
+{"name": "steve o'connell"},
+{"name": "randi jen"},
+{"name": "jerry curre"},
+{"name": "mike chee"},
+{"name": "bill creech"},
+{"name": "ray cell"},
+{"name": "peter spennato"},
+{"name": "adam seessel"},
+{"name": "glenn bridges"},
+{"name": "scott hemphill"},
+{"name": "clint h"},
+{"name": "mike bandich"},
+{"name": "james mulholland"},
+{"name": "chris finton"},
+{"name": "mike luters"},
+{"name": "renee richardson"},
+{"name": "donnie williams"},
+{"name": "cleo nice"},
+{"name": "hanna theobald"},
+{"name": "brittney beauchamp"},
+{"name": "sean keel"},
+{"name": "andrea white"},
+{"name": "heidi swanson"},
+{"name": "thomas cluderay"},
+{"name": "nancy vallejo"},
+{"name": "jennifer wagner"},
+{"name": "kevin skinner"},
+{"name": "jose benavidez"},
+{"name": "mari cell"},
+{"name": "luis arevalo"},
+{"name": "tom lowder"},
+{"name": "chad £"},
+{"name": "marcus white"},
+{"name": "eddie lawson"},
+{"name": "emily alipio"},
+{"name": "brian walker"},
+{"name": "stephanie richardson"},
+{"name": "katy j"},
+{"name": "pam martin"},
+{"name": "bret kuntz"},
+{"name": "darryl b"},
+{"name": "sara christensen"},
+{"name": "peggy henderson"},
+{"name": "brooke price"},
+{"name": "barbara stevens"},
+{"name": "annie wootton"},
+{"name": "george allison"},
+{"name": "allison kendall"},
+{"name": "ken yamamoto"},
+{"name": "cory eikmeier"},
+{"name": "kristy robinson"},
+{"name": "kris mitchell"},
+{"name": "tammy impiccini"},
+{"name": "katie tucker"},
+{"name": "leah nuzum"},
+{"name": "mark adams"},
+{"name": "marcus a"},
+{"name": "jen corso"},
+{"name": "john mitchell"},
+{"name": "roger ramilion"},
+{"name": "jeff bruno"},
+{"name": "bruce lenon"},
+{"name": "kate russell"},
+{"name": "jaime todd"},
+{"name": "matt gains"},
+{"name": "ashley cerino"},
+{"name": "stuart nathan"},
+{"name": "dick gordon"},
+{"name": "patti cakes"},
+{"name": "idella bynum"},
+{"name": "jeanette vasquez"},
+{"name": "jackie yah"},
+{"name": "jenny kheele"},
+{"name": "angie tsang"},
+{"name": "susana canada"},
+{"name": "daniel silverman"},
+{"name": "carl buford"},
+{"name": "anthony desantis"},
+{"name": "carolyn gale"},
+{"name": "dennis salvatier"},
+{"name": "tatiana grace"},
+{"name": "john ala"},
+{"name": "jerry dicarlo"},
+{"name": "corey wilson"},
+{"name": "steve rogan"},
+{"name": "jennifer goslowski"},
+{"name": "jason lloyd"},
+{"name": "molly maids"},
+{"name": "gina martin"},
+{"name": "david loatman"},
+{"name": "chris collins"},
+{"name": "barbara dale"},
+{"name": "bryan schmitz"},
+{"name": "fernando gomez"},
+{"name": "alyssa w"},
+{"name": "dwight dionne"},
+{"name": "john puzneak"},
+{"name": "long wilcox"},
+{"name": "tracy england"},
+{"name": "cindy raichuk"},
+{"name": "katie privott"},
+{"name": "dave kraynack"},
+{"name": "jack posemsky"},
+{"name": "tony legree"},
+{"name": "cedric lewis"},
+{"name": "gary verdegan"},
+{"name": "david grantham"},
+{"name": "mike pariseau"},
+{"name": "lee hamilton"},
+{"name": "pat kirby"},
+{"name": "patrick g"},
+{"name": "marc levinson"},
+{"name": "jane artinian"},
+{"name": "tim weir"},
+{"name": "nicole wesley"},
+{"name": "chuck floberg"},
+{"name": "matt mckenna"},
+{"name": "mike chan"},
+{"name": "meredith turnquist"},
+{"name": "eric megaplex"},
+{"name": "mark john"},
+{"name": "ben lursen"},
+{"name": "brian higgins"},
+{"name": "graham colton"},
+{"name": "david slattery"},
+{"name": "craig stewart"},
+{"name": "hannah cable"},
+{"name": "carol neciuk"},
+{"name": "jacob mauldin"},
+{"name": "al mahlberg"},
+{"name": "sherman hall"},
+{"name": "rob brower"},
+{"name": "jon strauss"},
+{"name": "emily romero"},
+{"name": "karen lamberson"},
+{"name": "chester clardy"},
+{"name": "mike peppler"},
+{"name": "duane ritter"},
+{"name": "clint hartshorn"},
+{"name": "carmen flores"},
+{"name": "tom trainor"},
+{"name": "robert louis"},
+{"name": "denny potter"},
+{"name": "al inhoff"},
+{"name": "grant braswell"},
+{"name": "chad clement"},
+{"name": "mark monroy"},
+{"name": "jack wilson"},
+{"name": "rafael echeverria"},
+{"name": "jack neal"},
+{"name": "john okamoto"},
+{"name": "dung dcm"},
+{"name": "shane lai"},
+{"name": "earl lyons"},
+{"name": "marcie cates"},
+{"name": "tommy her"},
+{"name": "mike jernagin"},
+{"name": "dan shaffer"},
+{"name": "bill matingley"},
+{"name": "terry boyd"},
+{"name": "sean o'brien"},
+{"name": "tom rad"},
+{"name": "kevin meryll"},
+{"name": "mike humbert"},
+{"name": "steve buerkle"},
+{"name": "larry carrera"},
+{"name": "rita liazuk"},
+{"name": "farah ramsdell"},
+{"name": "stephanie lane"},
+{"name": "kay jin"},
+{"name": "james jr"},
+{"name": "holly bandera"},
+{"name": "emilio salvador"},
+{"name": "shawn jerkins"},
+{"name": "sheila petrillo"},
+{"name": "jeffrey schiller"},
+{"name": "terry doyle"},
+{"name": "jeffrey green"},
+{"name": "bill ames"},
+{"name": "justin nash"},
+{"name": "tod otown"},
+{"name": "bao hoang"},
+{"name": "carl fesler"},
+{"name": "stephanie seneff"},
+{"name": "cody stuart"},
+{"name": "kenny rivers"},
+{"name": "tim shaver"},
+{"name": "dave pilipovich"},
+{"name": "maris zvejnieks"},
+{"name": "hillary harris"},
+{"name": "heather harp"},
+{"name": "billy lewis"},
+{"name": "raymond gerena"},
+{"name": "alexandra o'sullivan"},
+{"name": "george turco"},
+{"name": "mimi tutihasi"},
+{"name": "michael webber"},
+{"name": "dennis grenier"},
+{"name": "scott perez"},
+{"name": "scot yount"},
+{"name": "jim bryant"},
+{"name": "amy talbot"},
+{"name": "sara dean"},
+{"name": "mark sterling"},
+{"name": "cory chi"},
+{"name": "bobby wrk"},
+{"name": "lon murata"},
+{"name": "bill burgess"},
+{"name": "craig karasin"},
+{"name": "morris baumgarten"},
+{"name": "justin gocke"},
+{"name": "dee adams"},
+{"name": "gary carlson"},
+{"name": "jay kimsey"},
+{"name": "yvette wolfe"},
+{"name": "jacquelyn wallace"},
+{"name": "george seager"},
+{"name": "nick materasso"},
+{"name": "mike prendergast"},
+{"name": "romeo nichols"},
+{"name": "kris manganon"},
+{"name": "lance lin"},
+{"name": "fernanda arruda"},
+{"name": "edgar folks"},
+{"name": "yolanda lane"},
+{"name": "ann black"},
+{"name": "daniel ostdiek"},
+{"name": "randy donaldson"},
+{"name": "aaron greenspan"},
+{"name": "raymond banks"},
+{"name": "stacey adelman"},
+{"name": "jay mixon"},
+{"name": "james jones"},
+{"name": "bernie electrician"},
+{"name": "brian coates"},
+{"name": "mike barrett"},
+{"name": "ted hamlin"},
+{"name": "jorge bro"},
+{"name": "bryan dominguez"},
+{"name": "kirsten white"},
+{"name": "mike barber"},
+{"name": "shelley toolson"},
+{"name": "ryan pham"},
+{"name": "duane meer"},
+{"name": "karen kleinberg"},
+{"name": "frank romero"},
+{"name": "carol rogers"},
+{"name": "todd armstrong"},
+{"name": "matthew skeel"},
+{"name": "candice goode"},
+{"name": "paul service"},
+{"name": "eileen hendrickson"},
+{"name": "kim holser"},
+{"name": "jamie dunkelberger"},
+{"name": "steve baule"},
+{"name": "anika stocks"},
+{"name": "bruce lindsay"},
+{"name": "steve way"},
+{"name": "joseph foley"},
+{"name": "justin girardi"},
+{"name": "lauren johnston"},
+{"name": "roberta wall"},
+{"name": "karen brooks"},
+{"name": "josephine powell"},
+{"name": "debra paulsen"},
+{"name": "andrea park"},
+{"name": "lindsey lewis"},
+{"name": "jared pennington"},
+{"name": "stacey mcnemar"},
+{"name": "kacey parker"},
+{"name": "matt pierson"},
+{"name": "lawrence lawyer"},
+{"name": "linda thorne"},
+{"name": "brad edgelow"},
+{"name": "curtis a"},
+{"name": "tara davis"},
+{"name": "rebecca snyder"},
+{"name": "mike meza"},
+{"name": "mike zapata"},
+{"name": "josh cook"},
+{"name": "victor babloo"},
+{"name": "alex emslie"},
+{"name": "roy goliday"},
+{"name": "karen palome"},
+{"name": "mike chilcutt"},
+{"name": "brandi kuhn"},
+{"name": "jon fahning"},
+{"name": "james bridges"},
+{"name": "hector a"},
+{"name": "ericka delegarza"},
+{"name": "taylor dinwoodey"},
+{"name": "may o"},
+{"name": "candace johnson"},
+{"name": "mary madison"},
+{"name": "tim lineweaver"},
+{"name": "nick gaskins"},
+{"name": "leann cummings"},
+{"name": "kelly harrington"},
+{"name": "marilyn alomar"},
+{"name": "sammy m"},
+{"name": "melissa kale"},
+{"name": "kit kittleson"},
+{"name": "timothy reid"},
+{"name": "jerry casidy"},
+{"name": "renae dimarco"},
+{"name": "cody rhandi"},
+{"name": "tony vanetta"},
+{"name": "tamara swearingen"},
+{"name": "paula e"},
+{"name": "faye lee"},
+{"name": "aletha bradley"},
+{"name": "mike legacy"},
+{"name": "carolyn hong"},
+{"name": "drew glaser"},
+{"name": "jarrett lambert"},
+{"name": "robert burian"},
+{"name": "matthew dudley"},
+{"name": "nan bassett"},
+{"name": "elayne suber"},
+{"name": "lori weed"},
+{"name": "veronica w"},
+{"name": "jo mama"},
+{"name": "adam neihamiah"},
+{"name": "chris howell"},
+{"name": "jimmy rush"},
+{"name": "craig duke"},
+{"name": "steve vickers"},
+{"name": "kristin rowlen"},
+{"name": "rick quandt"},
+{"name": "gabriel cop"},
+{"name": "jennifer horn"},
+{"name": "eric dany"},
+{"name": "bill norton"},
+{"name": "jacob maria"},
+{"name": "courtney elam"},
+{"name": "kevin chestnut"},
+{"name": "angie aguilera"},
+{"name": "allison inserra"},
+{"name": "jim osburn"},
+{"name": "carlos silva"},
+{"name": "tom nual"},
+{"name": "brian alves"},
+{"name": "vanessa zams"},
+{"name": "tonya jackson"},
+{"name": "mike hammond"},
+{"name": "gordon mcfarlane"},
+{"name": "omar rawlins"},
+{"name": "richard canaday"},
+{"name": "brian jaco"},
+{"name": "arthur kroeber"},
+{"name": "mike siska"},
+{"name": "candice christia"},
+{"name": "roy malone"},
+{"name": "eric dotson"},
+{"name": "susan g"},
+{"name": "sam frank"},
+{"name": "david urdiales"},
+{"name": "anthony cavazos"},
+{"name": "pat buttons"},
+{"name": "linda ciaccia"},
+{"name": "karl martin"},
+{"name": "chuck mcgovern"},
+{"name": "kristin bremberg"},
+{"name": "jerry warren"},
+{"name": "peter j"},
+{"name": "amy l"},
+{"name": "mike baldwin"},
+{"name": "carla michaleski"},
+{"name": "rod belford"},
+{"name": "michael wells"},
+{"name": "miguel pasofino"},
+{"name": "tiffany gathers"},
+{"name": "greg piferi"},
+{"name": "peter lowe"},
+{"name": "del mauro"},
+{"name": "bruno madore"},
+{"name": "mimi p"},
+{"name": "juan lascurain"},
+{"name": "molly brassfield"},
+{"name": "katherine christian"},
+{"name": "jenny cust"},
+{"name": "lou electric"},
+{"name": "john suzanne"},
+{"name": "chris boorman"},
+{"name": "andrea larreta"},
+{"name": "justin bromstead"},
+{"name": "ernie arrambide"},
+{"name": "david verklin"},
+{"name": "jonah house"},
+{"name": "rogelio rivera"},
+{"name": "karla rollin"},
+{"name": "allyson nixon"},
+{"name": "cory ang"},
+{"name": "caroline smith"},
+{"name": "gail guardia"},
+{"name": "alexa angel"},
+{"name": "sue underwood"},
+{"name": "nick dallas"},
+{"name": "brian weston"},
+{"name": "steven washburn"},
+{"name": "gary poetting"},
+{"name": "caroline o'neill"},
+{"name": "jared stauffer"},
+{"name": "david orso"},
+{"name": "michele a"},
+{"name": "blair bar"},
+{"name": "ron solomons"},
+{"name": "juan gomez"},
+{"name": "willy shideler"},
+{"name": "pierre belhadj"},
+{"name": "andy shanks"},
+{"name": "oliver griebl"},
+{"name": "jake leitwein"},
+{"name": "bill buchanan"},
+{"name": "jay price"},
+{"name": "jeannie sadler"},
+{"name": "renee cell"},
+{"name": "sam versteeg"},
+{"name": "sergio cadavid"},
+{"name": "tami hurley"},
+{"name": "micah manney"},
+{"name": "brian riggle"},
+{"name": "alan cribbs"},
+{"name": "stacey saltzman"},
+{"name": "bebe toya"},
+{"name": "rob montclair"},
+{"name": "ann helmick"},
+{"name": "rene cell"},
+{"name": "kelly gallant"},
+{"name": "barbara breanna"},
+{"name": "bryan white"},
+{"name": "gary shelton"},
+{"name": "juan fernandez"},
+{"name": "larry holmes"},
+{"name": "marie nest"},
+{"name": "misty parrish"},
+{"name": "chet blalock"},
+{"name": "genevieve perras"},
+{"name": "elsa marshall"},
+{"name": "tyler r"},
+{"name": "jon scherling"},
+{"name": "sun sales"},
+{"name": "omer soykan"},
+{"name": "barry hunt"},
+{"name": "jason berry"},
+{"name": "adam maynard"},
+{"name": "michael mccarty"},
+{"name": "bill greenberg"},
+{"name": "marty vilimek"},
+{"name": "ryan hatfield"},
+{"name": "virginia g"},
+{"name": "larry gress"},
+{"name": "karin klitzke"},
+{"name": "caroline may"},
+{"name": "phil litell"},
+{"name": "eunice galang"},
+{"name": "terry hickey"},
+{"name": "nora kirkland"},
+{"name": "larry bohn"},
+{"name": "debra nicol"},
+{"name": "nathan westbrook"},
+{"name": "rose cage"},
+{"name": "elizabeth maldonado"},
+{"name": "betty jackson"},
+{"name": "rhonda bass"},
+{"name": "david collins"},
+{"name": "angela kelly"},
+{"name": "bonnie philpot"},
+{"name": "luke llewellyn"},
+{"name": "lisa roulo"},
+{"name": "aaron nielsen"},
+{"name": "phillip smith"},
+{"name": "steve rule"},
+{"name": "jim liptak"},
+{"name": "hector castillo"},
+{"name": "marty gittos"},
+{"name": "jamie lee"},
+{"name": "yolonda danner"},
+{"name": "jim thebeau"},
+{"name": "anthony edwards"},
+{"name": "chuck sales"},
+{"name": "tim dean"},
+{"name": "roland e"},
+{"name": "christopher sacca"},
+{"name": "cami thurston"},
+{"name": "ron whitehair"},
+{"name": "erik delgado"},
+{"name": "david prentice"},
+{"name": "eric martinez"},
+{"name": "mark deibert"},
+{"name": "gary issacson"},
+{"name": "danny hoang"},
+{"name": "guy mueller"},
+{"name": "nick nakfour"},
+{"name": "sharon schwartz"},
+{"name": "tia del"},
+{"name": "steve steel"},
+{"name": "sylvia gemilyan"},
+{"name": "shannon cain"},
+{"name": "jared k"},
+{"name": "andrew valentine"},
+{"name": "phil lechman"},
+{"name": "larry crawley"},
+{"name": "bob cilk"},
+{"name": "ana m"},
+{"name": "candace flowers"},
+{"name": "shannon hanley"},
+{"name": "scott madura"},
+{"name": "brian barcomb"},
+{"name": "andrea b"},
+{"name": "jacqueline fitch"},
+{"name": "joanne rillera"},
+{"name": "kristen campbell"},
+{"name": "sarah refi"},
+{"name": "jimmie williams"},
+{"name": "jane bozek"},
+{"name": "dick johnson"},
+{"name": "david kirkland"},
+{"name": "liz cisneros"},
+{"name": "cheri jessup"},
+{"name": "tony swoops"},
+{"name": "terri boone"},
+{"name": "micah tovey"},
+{"name": "lashaun carr"},
+{"name": "chad betten"},
+{"name": "jonathan zimmerman"},
+{"name": "len mcghie"},
+{"name": "jeremiah reyna"},
+{"name": "kevin cambell"},
+{"name": "robert holt"},
+{"name": "steve hellweg"},
+{"name": "robin faulkner"},
+{"name": "bart kummer"},
+{"name": "greg nyce"},
+{"name": "glen bass"},
+{"name": "jay eastlund"},
+{"name": "diana frazier"},
+{"name": "michael mantey"},
+{"name": "david lank"},
+{"name": "ryan mactaggart"},
+{"name": "eileen pazmino"},
+{"name": "joyce jew"},
+{"name": "tisha barnslater"},
+{"name": "amanda stevens"},
+{"name": "arron fields"},
+{"name": "chad crawford"},
+{"name": "steve larson"},
+{"name": "maria romey"},
+{"name": "nella healy"},
+{"name": "kip wotanowicz"},
+{"name": "robert wilcox"},
+{"name": "chuck gould"},
+{"name": "chris nomura"},
+{"name": "jay sr"},
+{"name": "alan kimmery"},
+{"name": "patty hulsey"},
+{"name": "brandon b"},
+{"name": "brenda craig"},
+{"name": "matt banaszak"},
+{"name": "ken kukurudz"},
+{"name": "oscar arts"},
+{"name": "jennifer rogers"},
+{"name": "loren beck"},
+{"name": "rosita cortez"},
+{"name": "tina garcia"},
+{"name": "christina pasek"},
+{"name": "grace murray"},
+{"name": "holly labriola"},
+{"name": "steve jones"},
+{"name": "michael story"},
+{"name": "henry alvarez"},
+{"name": "sandy ellsworth"},
+{"name": "dave mccuskey"},
+{"name": "enrique egurrora"},
+{"name": "donny young"},
+{"name": "lisa karno"},
+{"name": "jodi lints"},
+{"name": "nikki reynolds"},
+{"name": "glenn creamer"},
+{"name": "hoa bui"},
+{"name": "jennifer raymond"},
+{"name": "alex norton"},
+{"name": "jo a"},
+{"name": "jeff robbins"},
+{"name": "dee robbins"},
+{"name": "justin shawley"},
+{"name": "bob pruit"},
+{"name": "laurie daniels"},
+{"name": "bryan thoryk"},
+{"name": "dayna montrose"},
+{"name": "robert stephens"},
+{"name": "joanna zelasko"},
+{"name": "andrew ryskamp"},
+{"name": "karen reed"},
+{"name": "jules renner"},
+{"name": "rob holzhauer"},
+{"name": "rachel dysarczyk"},
+{"name": "nancy barahona"},
+{"name": "holly fogle"},
+{"name": "ha chun"},
+{"name": "tim ochran"},
+{"name": "krista johnson"},
+{"name": "travis behrens"},
+{"name": "roy odgen"},
+{"name": "gloria carey"},
+{"name": "mike russulillo"},
+{"name": "frank kline"},
+{"name": "tim lennon"},
+{"name": "joyce yip"},
+{"name": "bob colt"},
+{"name": "greg etk"},
+{"name": "bill busey"},
+{"name": "paul geislinger"},
+{"name": "jeni harp"},
+{"name": "jennie bartlett"},
+{"name": "brian dwan"},
+{"name": "valerie valencia"},
+{"name": "samuel chang"},
+{"name": "raymond ortiz"},
+{"name": "michael bosik"},
+{"name": "krista erikson"},
+{"name": "stephanie macneil"},
+{"name": "renee pyzanos"},
+{"name": "jason applewhite"},
+{"name": "margaret lazo"},
+{"name": "rich lefurgy"},
+{"name": "bernetta draper"},
+{"name": "roger haddad"},
+{"name": "brian alvarez"},
+{"name": "nicole carlos"},
+{"name": "debbie wheeler"},
+{"name": "andy frey"},
+{"name": "patti genko"},
+{"name": "dan sakinin"},
+{"name": "trish friesen"},
+{"name": "andrew phipps"},
+{"name": "diane lee"},
+{"name": "gregory schultz"},
+{"name": "dick crisp"},
+{"name": "cynthia hiatt"},
+{"name": "shawn rahl"},
+{"name": "george graves"},
+{"name": "kara kim"},
+{"name": "janelle crosby"},
+{"name": "crystal starlight"},
+{"name": "jasmine trimble"},
+{"name": "eric lehmer"},
+{"name": "andre watts"},
+{"name": "bobby freeman"},
+{"name": "les murin"},
+{"name": "monique scott"},
+{"name": "greg schweitzer"},
+{"name": "frank castellucci"},
+{"name": "marcus brian"},
+{"name": "jen scott"},
+{"name": "kristi orchard"},
+{"name": "dean jewel"},
+{"name": "evan levow"},
+{"name": "shawn shi"},
+{"name": "mackenzie jackson"},
+{"name": "sal creams"},
+{"name": "diamond mandis"},
+{"name": "andy lorance"},
+{"name": "richard brady"},
+{"name": "lidia heyhurst"},
+{"name": "teresa lusney"},
+{"name": "martin beatty"},
+{"name": "greg dandeles"},
+{"name": "roderick brooks"},
+{"name": "janelle rosamond"},
+{"name": "tamiko keller"},
+{"name": "cristina wakiyama"},
+{"name": "jim whitmore"},
+{"name": "matt engler"},
+{"name": "bill brink"},
+{"name": "john waltman"},
+{"name": "patrick thompson"},
+{"name": "ashley edmondson"},
+{"name": "byron moving"},
+{"name": "wayne potter"},
+{"name": "justin lewis"},
+{"name": "raquel mullins"},
+{"name": "dave helfrich"},
+{"name": "alex peragine"},
+{"name": "steve bodman"},
+{"name": "stephen beckman"},
+{"name": "david golden"},
+{"name": "bill chamberlin"},
+{"name": "jason maruska"},
+{"name": "dave riordan"},
+{"name": "george cypress"},
+{"name": "jon mcpeters"},
+{"name": "victor shen"},
+{"name": "brian guenther"},
+{"name": "karen barrientos"},
+{"name": "danielle holmes"},
+{"name": "kristen holmstrand"},
+{"name": "christy work"},
+{"name": "kacie baker"},
+{"name": "stacy espejo"},
+{"name": "eric lommatsch"},
+{"name": "henry comm"},
+{"name": "rachael foster"},
+{"name": "dean kawamura"},
+{"name": "trey cotney"},
+{"name": "maribeth diaz"},
+{"name": "luigi f"},
+{"name": "ryan nelson"},
+{"name": "dana reason"},
+{"name": "gordon wilson"},
+{"name": "cheryl vallejo"},
+{"name": "william afeaki"},
+{"name": "melinda sue"},
+{"name": "diane sampson"},
+{"name": "rich paquette"},
+{"name": "crystal b"},
+{"name": "daniel felder"},
+{"name": "lynn willy"},
+{"name": "jenniffer plinio"},
+{"name": "ebony brown"},
+{"name": "elizabeth blanco"},
+{"name": "teddy dewitt"},
+{"name": "larry brown"},
+{"name": "sean mealock"},
+{"name": "mike nicolas"},
+{"name": "diane freeman"},
+{"name": "annie mak"},
+{"name": "brenda jolly"},
+{"name": "drew wahl"},
+{"name": "joanne day"},
+{"name": "mike ortayazmaciyan"},
+{"name": "jon albert"},
+{"name": "jan leighty"},
+{"name": "jean spirk"},
+{"name": "john rula"},
+{"name": "clair audi"},
+{"name": "martin deleon"},
+{"name": "ryan grafft"},
+{"name": "lindy milka"},
+{"name": "brad unique"},
+{"name": "dennis keogh"},
+{"name": "glenn conner"},
+{"name": "juan a"},
+{"name": "george hopkins"},
+{"name": "kenneth adler"},
+{"name": "colin photo"},
+{"name": "mike jewler"},
+{"name": "valerie bennett"},
+{"name": "adam rainey"},
+{"name": "dorothy hays"},
+{"name": "john brandes"},
+{"name": "alex zilbershteyn"},
+{"name": "peter kane"},
+{"name": "lecia langston"},
+{"name": "ana silva"},
+{"name": "corey samsara"},
+{"name": "kim magee"},
+{"name": "kelly bishop"},
+{"name": "reggie medford"},
+{"name": "kenny g"},
+{"name": "adam chavira"},
+{"name": "shelby tucker"},
+{"name": "rachel hs"},
+{"name": "tanya jenkins"},
+{"name": "christopher orne"},
+{"name": "irving keschner"},
+{"name": "chris lee"},
+{"name": "grant hawkins"},
+{"name": "ray epp"},
+{"name": "simon cell"},
+{"name": "michael pobar"},
+{"name": "nadine childress"},
+{"name": "david hoki"},
+{"name": "brad alkazin"},
+{"name": "connie penalver"},
+{"name": "jason belinski"},
+{"name": "bill bonsback"},
+{"name": "douglas meneely"},
+{"name": "spencer wheelwright"},
+{"name": "renita cox"},
+{"name": "barry shevick"},
+{"name": "carlos home"},
+{"name": "noel people"},
+{"name": "darren posh"},
+{"name": "gerry tissenbaum"},
+{"name": "blake jones"},
+{"name": "david lachowicz"},
+{"name": "carol evermen"},
+{"name": "jason pierce"},
+{"name": "amiee ball"},
+{"name": "johnny car"},
+{"name": "jeffrey bostic"},
+{"name": "steve adelman"},
+{"name": "lewis floyd"},
+{"name": "greg finton"},
+{"name": "nick nickerson"},
+{"name": "scott haitsuka"},
+{"name": "regine smet"},
+{"name": "tiffany ward"},
+{"name": "samuel brull"},
+{"name": "jared o'brien"},
+{"name": "chad v"},
+{"name": "amy salvo"},
+{"name": "tom baumbach"},
+{"name": "ken sjovolv"},
+{"name": "luis cardona"},
+{"name": "jesse lira"},
+{"name": "eric wilkerson"},
+{"name": "denis laflamme"},
+{"name": "adam stansberry"},
+{"name": "peter sells"},
+{"name": "alex labeaux"},
+{"name": "jim milliken"},
+{"name": "michael mysliwy"},
+{"name": "david goat"},
+{"name": "morris betton"},
+{"name": "jeff garrison"},
+{"name": "nancy foyt"},
+{"name": "christi wieler"},
+{"name": "ryan slack"},
+{"name": "mike linger"},
+{"name": "frank goluza"},
+{"name": "pat dugal"},
+{"name": "tim kolopus"},
+{"name": "david hernandez"},
+{"name": "brian boekel"},
+{"name": "randy denkers"},
+{"name": "sherry premo"},
+{"name": "jennifer hanks"},
+{"name": "katie bell"},
+{"name": "rodney mccall"},
+{"name": "sarah mather"},
+{"name": "jackie melendez"},
+{"name": "dave busters"},
+{"name": "seth drori"},
+{"name": "elizabeth jones"},
+{"name": "norman karen"},
+{"name": "tim lanigan"},
+{"name": "kim harsh"},
+{"name": "mike timmons"},
+{"name": "jason salvatierra"},
+{"name": "vickie fletcher"},
+{"name": "david heiss"},
+{"name": "bryan stanley"},
+{"name": "gary austin"},
+{"name": "kathleen wallace"},
+{"name": "andrea looker"},
+{"name": "ken pearson"},
+{"name": "keith sanders"},
+{"name": "cassie dyker"},
+{"name": "clayton christensen"},
+{"name": "james gall"},
+{"name": "jack larson"},
+{"name": "jackie hensley"},
+{"name": "susan schirman"},
+{"name": "fletcher graggs"},
+{"name": "candice meng"},
+{"name": "brenda linares"},
+{"name": "rob pary"},
+{"name": "peggy broch"},
+{"name": "jerome stoll"},
+{"name": "cris crib"},
+{"name": "steve bertreis"},
+{"name": "lisa bernstein"},
+{"name": "bridgett corbin"},
+{"name": "tara french"},
+{"name": "dave anderssen"},
+{"name": "james romero"},
+{"name": "joey garguilo"},
+{"name": "terry clark"},
+{"name": "joanna miller"},
+{"name": "luz mariela"},
+{"name": "allison hinley"},
+{"name": "denise jerry"},
+{"name": "scott corr"},
+{"name": "scott schumacher"},
+{"name": "shannon schmidt"},
+{"name": "noel acosta"},
+{"name": "nicola caiano"},
+{"name": "derek lyttle"},
+{"name": "kenny kilman"},
+{"name": "justin lindhorst"},
+{"name": "bertha mills"},
+{"name": "bill shaw"},
+{"name": "eric swanson"},
+{"name": "kelly king"},
+{"name": "brian fisher"},
+{"name": "ashley hasbrook"},
+{"name": "amanda rubin"},
+{"name": "megan mullinix"},
+{"name": "virgil watters"},
+{"name": "paul korber"},
+{"name": "april howell"},
+{"name": "geri newburge"},
+{"name": "jim chambers"},
+{"name": "robbie cell"},
+{"name": "emily guthrie"},
+{"name": "jenny leclaire"},
+{"name": "stephanie st"},
+{"name": "betty mirabal"},
+{"name": "thomas dr"},
+{"name": "tim anderson"},
+{"name": "angelika decker"},
+{"name": "jackie ho"},
+{"name": "molly sg"},
+{"name": "mark marin"},
+{"name": "jean blanchette"},
+{"name": "melody welch"},
+{"name": "nathan marchbank"},
+{"name": "edward porter"},
+{"name": "simon jennings"},
+{"name": "pablo ros"},
+{"name": "luella d"},
+{"name": "jerry farner"},
+{"name": "andy hartz"},
+{"name": "katie dillon"},
+{"name": "sonia cleaning"},
+{"name": "tamara tretter"},
+{"name": "brian wadell"},
+{"name": "earle teagarden"},
+{"name": "joe leduc"},
+{"name": "allison lanzallotti"},
+{"name": "cindy keese"},
+{"name": "elvira feng"},
+{"name": "chris manalastas"},
+{"name": "david moore"},
+{"name": "ellen lamp"},
+{"name": "val bellardo"},
+{"name": "johnson bank"},
+{"name": "cedric gaddy"},
+{"name": "todd reardon"},
+{"name": "tina burtelow"},
+{"name": "brittany scramuzzo"},
+{"name": "shawna macfarlane"},
+{"name": "betty charles"},
+{"name": "chris patrick"},
+{"name": "michael carus"},
+{"name": "joe magie"},
+{"name": "bob andrew"},
+{"name": "tim devine"},
+{"name": "jeremy banks"},
+{"name": "danny kf"},
+{"name": "carmen c"},
+{"name": "charles krusen"},
+{"name": "vanessa brown"},
+{"name": "deb olson"},
+{"name": "luis cruz"},
+{"name": "dawn strachan"},
+{"name": "doug lewis"},
+{"name": "steven thompson"},
+{"name": "annie zaborskis"},
+{"name": "john compaglia"},
+{"name": "mike price"},
+{"name": "nathan lim"},
+{"name": "tracie b"},
+{"name": "ryan moses"},
+{"name": "bob johnson"},
+{"name": "rich imb"},
+{"name": "harriet adelman"},
+{"name": "steven lindsay"},
+{"name": "karena puga"},
+{"name": "robert guzman"},
+{"name": "natalie defazio"},
+{"name": "mark spencer"},
+{"name": "frederic herrbach"},
+{"name": "chris cardin"},
+{"name": "brian boboli"},
+{"name": "joan chipser"},
+{"name": "janice fallago"},
+{"name": "sunny sachdev"},
+{"name": "karen loxton"},
+{"name": "lisa mccloughan"},
+{"name": "adam cortez"},
+{"name": "chris holstien"},
+{"name": "judy kampa"},
+{"name": "alison naidech"},
+{"name": "sally scott"},
+{"name": "molly mills"},
+{"name": "scott skager"},
+{"name": "gary martinez"},
+{"name": "wes camplin"},
+{"name": "steve x"},
+{"name": "erica la"},
+{"name": "john ekpenyoung"},
+{"name": "aaron desalle"},
+{"name": "louis bovasso"},
+{"name": "jonathan bailes"},
+{"name": "michelle williams"},
+{"name": "megan harvey"},
+{"name": "jonathan dakss"},
+{"name": "kenneth schambaro"},
+{"name": "brad wells"},
+{"name": "jack uncle"},
+{"name": "naomi matsumoto"},
+{"name": "janice woodruff"},
+{"name": "alisa ballesteros"},
+{"name": "tamara pienknagura"},
+{"name": "pamela zager"},
+{"name": "eric black"},
+{"name": "junior electric"},
+{"name": "kathy barquez"},
+{"name": "jean richardson"},
+{"name": "kathryn mcmahon"},
+{"name": "cindy saucedo"},
+{"name": "dave javorsky"},
+{"name": "greg lynch"},
+{"name": "mark cassel"},
+{"name": "alan zakaria"},
+{"name": "kelly blackwood"},
+{"name": "doris monsalve"},
+{"name": "mike wagener"},
+{"name": "tonya c"},
+{"name": "eric leland"},
+{"name": "emily hansen"},
+{"name": "dalton snyder"},
+{"name": "elizabeth harownsky"},
+{"name": "allen dobson"},
+{"name": "emily hooch"},
+{"name": "jose s"},
+{"name": "matt tang"},
+{"name": "alex geller"},
+{"name": "david davis"},
+{"name": "michael hebberoy"},
+{"name": "preston wolf"},
+{"name": "daria fitzgerard"},
+{"name": "thomas trujillo"},
+{"name": "sarah dennis"},
+{"name": "andrea turco"},
+{"name": "mark comstock"},
+{"name": "johnny bonding"},
+{"name": "gina chavez"},
+{"name": "jacque lazier"},
+{"name": "marion weeks"},
+{"name": "jill reynolds"},
+{"name": "rick samson"},
+{"name": "jim summers"},
+{"name": "william marek"},
+{"name": "shane ward"},
+{"name": "ronald ducasse"},
+{"name": "rhonda jones"},
+{"name": "tom donkle"},
+{"name": "bonnie spruill"},
+{"name": "christian vinas"},
+{"name": "jason i"},
+{"name": "shelly abraham"},
+{"name": "jillian rigwood"},
+{"name": "val neal"},
+{"name": "robert kupczak"},
+{"name": "arthur zilberberg"},
+{"name": "leah radley"},
+{"name": "ellie randall"},
+{"name": "jessica hendricks"},
+{"name": "greg mueller"},
+{"name": "denny johnston"},
+{"name": "joe bread"},
+{"name": "joanna clendenen"},
+{"name": "bruce johns"},
+{"name": "bret cullivan"},
+{"name": "cheri bear"},
+{"name": "john akers"},
+{"name": "donald norberg"},
+{"name": "blair constantine"},
+{"name": "rhoda debose"},
+{"name": "scott irvine"},
+{"name": "greg fletcher"},
+{"name": "allen brooks"},
+{"name": "dean fausett"},
+{"name": "dennis green"},
+{"name": "errol carlstrom"},
+{"name": "fern greg"},
+{"name": "debra pope"},
+{"name": "bobby weiss"},
+{"name": "carol rose"},
+{"name": "john rocconi"},
+{"name": "nicole euson"},
+{"name": "ana lisa"},
+{"name": "jeff acord"},
+{"name": "maggie nassif"},
+{"name": "chris medina"},
+{"name": "mike mendez"},
+{"name": "chris nugent"},
+{"name": "cheryl johnson"},
+{"name": "bill yoder"},
+{"name": "sam chueng"},
+{"name": "jamie wise"},
+{"name": "howard goldberg"},
+{"name": "chris woolcox"},
+{"name": "jackie frazier"},
+{"name": "joey bales"},
+{"name": "liza niss"},
+{"name": "dave goodwin"},
+{"name": "todd onore"},
+{"name": "scott ganson"},
+{"name": "michael franks"},
+{"name": "quinn li"},
+{"name": "pete hoffman"},
+{"name": "bob grondin"},
+{"name": "dick hogshire"},
+{"name": "danny green"},
+{"name": "raymond gomez"},
+{"name": "greg dungan"},
+{"name": "derrick metz"},
+{"name": "rita stoker"},
+{"name": "dick phillips"},
+{"name": "barry kea"},
+{"name": "jay mclauchlin"},
+{"name": "tanya haddock"},
+{"name": "ed dubar"},
+{"name": "jay sharon"},
+{"name": "matt kauppinen"},
+{"name": "jason bayless"},
+{"name": "tracy arrington"},
+{"name": "steve bailey"},
+{"name": "patricia locke"},
+{"name": "eric giambertone"},
+{"name": "evan wise"},
+{"name": "chara patterson"},
+{"name": "kim geater"},
+{"name": "kevin karlson"},
+{"name": "ben santiago"},
+{"name": "ryan conner"},
+{"name": "lyla scheihing"},
+{"name": "jesse huitt"},
+{"name": "molly maier"},
+{"name": "sid knable"},
+{"name": "terese scimecca"},
+{"name": "alex bernasconi"},
+{"name": "corina laborico"},
+{"name": "michael micone"},
+{"name": "joyce chen"},
+{"name": "frank oliva"},
+{"name": "doug michlink"},
+{"name": "victor silvestre"},
+{"name": "joey vzn"},
+{"name": "kelly mullaney"},
+{"name": "leo iliadis"},
+{"name": "mark neadle"},
+{"name": "misty cell"},
+{"name": "kate verbeek"},
+{"name": "bob woosley"},
+{"name": "mike theissen"},
+{"name": "jordan selhorst"},
+{"name": "fred gamel"},
+{"name": "carolyn dc"},
+{"name": "corie brown"},
+{"name": "cathy collens"},
+{"name": "pam kenney"},
+{"name": "gregg montgomery"},
+{"name": "jimmy rosenfield"},
+{"name": "peter panunzi"},
+{"name": "missy zimmerman"},
+{"name": "lorette peruch"},
+{"name": "josh sarratt"},
+{"name": "chris robl"},
+{"name": "joey yokum"},
+{"name": "andrew terrono"},
+{"name": "catherine trinh"},
+{"name": "keith davids"},
+{"name": "rachel powers"},
+{"name": "monique tanner"},
+{"name": "sarah becker"},
+{"name": "tricia boudreau"},
+{"name": "cameron farrer"},
+{"name": "justin ok"},
+{"name": "tania sauro"},
+{"name": "dennis russo"},
+{"name": "john hind"},
+{"name": "colin shaw"},
+{"name": "donnie bender"},
+{"name": "david ostfeld"},
+{"name": "bob young"},
+{"name": "brandon apuna"},
+{"name": "mary thune"},
+{"name": "floyd clarkson"},
+{"name": "mike waechter"},
+{"name": "gaye sanders"},
+{"name": "don snow"},
+{"name": "kevin andy"},
+{"name": "emily diaz"},
+{"name": "carolyn eli's"},
+{"name": "matt danni"},
+{"name": "dean everly"},
+{"name": "steve ambrose"},
+{"name": "jennifer banks"},
+{"name": "dennis knight"},
+{"name": "alex k"},
+{"name": "bill obrien"},
+{"name": "john jeffreies"},
+{"name": "george jagodzinski"},
+{"name": "greg chun"},
+{"name": "jen steward"},
+{"name": "catherine franklin"},
+{"name": "lisa patton"},
+{"name": "bob dewey"},
+{"name": "omar davis"},
+{"name": "emily patrick"},
+{"name": "erica lyxzen"},
+{"name": "joe hawkins"},
+{"name": "phuong trinh"},
+{"name": "ed schwalenberg"},
+{"name": "neil badders"},
+{"name": "allen mercer"},
+{"name": "bruce flint"},
+{"name": "dave reigert"},
+{"name": "fernando padilla"},
+{"name": "allen aikens"},
+{"name": "craig martin"},
+{"name": "tom shook"},
+{"name": "mindy cell"},
+{"name": "micheal graham"},
+{"name": "lily esparza"},
+{"name": "preston davis"},
+{"name": "brent mckay"},
+{"name": "jay williams"},
+{"name": "barb hunt"},
+{"name": "ray kada"},
+{"name": "ryan pierce"},
+{"name": "ryan adams"},
+{"name": "ryan burke"},
+{"name": "marilyn bettencourt"},
+{"name": "phil hess"},
+{"name": "shannon myric"},
+{"name": "jasmine arizmendi"},
+{"name": "chris grimes"},
+{"name": "nancy surgenor"},
+{"name": "andrew barkin"},
+{"name": "rob everhart"},
+{"name": "carl trim"},
+{"name": "jenny h"},
+{"name": "valerie koontz"},
+{"name": "ruby lin"},
+{"name": "eric hardesty"},
+{"name": "suzanne stevens"},
+{"name": "greg pavlick"},
+{"name": "brock strom"},
+{"name": "jason schubert"},
+{"name": "leslie brians"},
+{"name": "sam nimri"},
+{"name": "ann khalid"},
+{"name": "ron cheshire"},
+{"name": "becky higby"},
+{"name": "joe storm"},
+{"name": "nick chron"},
+{"name": "rob suh"},
+{"name": "bruce jackson"},
+{"name": "kanisha nsba"},
+{"name": "kenny boss"},
+{"name": "billy loecker"},
+{"name": "yasuko cook"},
+{"name": "john minor"},
+{"name": "morris garage"},
+{"name": "lovie harris"},
+{"name": "dave kasey"},
+{"name": "brad welch"},
+{"name": "tina marie"},
+{"name": "shayla hazelhurst"},
+{"name": "richard brodeur"},
+{"name": "pam lomeli"},
+{"name": "barry warren"},
+{"name": "melissa hogenson"},
+{"name": "sam bullock"},
+{"name": "diane aronowitz"},
+{"name": "raul luna"},
+{"name": "crystal moffat"},
+{"name": "todd rosenhagen"},
+{"name": "david klein"},
+{"name": "jack corry"},
+{"name": "elena brooks"},
+{"name": "katherine thon"},
+{"name": "denny dephillips"},
+{"name": "scott hammond"},
+{"name": "shelly biggs"},
+{"name": "elmer nixon"},
+{"name": "laurie peetree"},
+{"name": "ryan floth"},
+{"name": "steve gerard"},
+{"name": "lloyd peckner"},
+{"name": "elizabeth haglund"},
+{"name": "todd courtland"},
+{"name": "kevin dixion"},
+{"name": "mark dettor"},
+{"name": "tim handler"},
+{"name": "susanna filippone"},
+{"name": "cameron roy"},
+{"name": "steve paysinger"},
+{"name": "teresa ruiz"},
+{"name": "selena williams"},
+{"name": "joe poole"},
+{"name": "claire bele"},
+{"name": "roger bachman"},
+{"name": "christal cheng"},
+{"name": "tiny patton"},
+{"name": "jean wirth"},
+{"name": "maria mims"},
+{"name": "winona pless"},
+{"name": "ian soltan"},
+{"name": "miriam cell"},
+{"name": "elizabeth donovan"},
+{"name": "debbie bolves"},
+{"name": "michael garrett"},
+{"name": "sean o'day"},
+{"name": "jenny ryan"},
+{"name": "kelly barina"},
+{"name": "charles cin"},
+{"name": "steven tran"},
+{"name": "sharonda davis"},
+{"name": "justin sprowles"},
+{"name": "lisa ganfield"},
+{"name": "nisha purp"},
+{"name": "ralph erb"},
+{"name": "mari carmen"},
+{"name": "ned lynch"},
+{"name": "tim mcanany"},
+{"name": "amanda s"},
+{"name": "ed joiner"},
+{"name": "evan trestan"},
+{"name": "jake mansell"},
+{"name": "del monte"},
+{"name": "sean driggs"},
+{"name": "michelle marison"},
+{"name": "vickie atco"},
+{"name": "everett rhodes"},
+{"name": "jesse henstock"},
+{"name": "paul cain"},
+{"name": "jason henderson"},
+{"name": "larry braswell"},
+{"name": "merrie dorval"},
+{"name": "john crivaro"},
+{"name": "erin nguyen"},
+{"name": "rick spitler"},
+{"name": "john sample"},
+{"name": "brian wheelock"},
+{"name": "ken kiedrowicz"},
+{"name": "beatrice clark"},
+{"name": "marisa lam"},
+{"name": "jason bio"},
+{"name": "brian mccauley"},
+{"name": "lindsay kay"},
+{"name": "ellie barona"},
+{"name": "mark harle"},
+{"name": "roy schmucker"},
+{"name": "sherry wolf"},
+{"name": "michael giorgiani"},
+{"name": "tim boyd"},
+{"name": "rose warda"},
+{"name": "ann rogers"},
+{"name": "karl haberl"},
+{"name": "chuck brown"},
+{"name": "ryan simon"},
+{"name": "paul dergen"},
+{"name": "tyrone duffel"},
+{"name": "jim obrian"},
+{"name": "wendy snyder"},
+{"name": "frank brown"},
+{"name": "josh goodwin"},
+{"name": "brandon linn"},
+{"name": "jeff beyer"},
+{"name": "maryann gonzalez"},
+{"name": "fernando lujan"},
+{"name": "bret gorringe"},
+{"name": "hal braun"},
+{"name": "isabelle bovee"},
+{"name": "marva marx"},
+{"name": "kenny barneby"},
+{"name": "donna krumsiek"},
+{"name": "judi suski"},
+{"name": "michael goldmuntz"},
+{"name": "larry jackson"},
+{"name": "sue hoidal"},
+{"name": "courtney meyers"},
+{"name": "tony langston"},
+{"name": "ricardo rendon"},
+{"name": "karen hall"},
+{"name": "mary parsons"},
+{"name": "pat patillo"},
+{"name": "marty cronin"},
+{"name": "herb tousley"},
+{"name": "kathleen gallagher"},
+{"name": "adam wilfley"},
+{"name": "maria galvan"},
+{"name": "brandi cunningham"},
+{"name": "tracie eisenberg"},
+{"name": "jack barlage"},
+{"name": "mike middaugh"},
+{"name": "christine gangi"},
+{"name": "amanda hands"},
+{"name": "vincent tao"},
+{"name": "elena stojcevski"},
+{"name": "lindsay s"},
+{"name": "courtney feilmeier"},
+{"name": "renee culver"},
+{"name": "dean disandro"},
+{"name": "mark holland"},
+{"name": "terri vivian"},
+{"name": "roberto vilicana"},
+{"name": "katie sudduth"},
+{"name": "heather hensley"},
+{"name": "alvin roth"},
+{"name": "heather bennett"},
+{"name": "cliff whitehurst"},
+{"name": "trevor cates"},
+{"name": "tony hinsberger"},
+{"name": "jim day@hardy"},
+{"name": "bruce lan"},
+{"name": "mara sherkin"},
+{"name": "bryan grimm"},
+{"name": "chris weichel"},
+{"name": "shane hollingsworth"},
+{"name": "robert dennerlein"},
+{"name": "evan king"},
+{"name": "steve ragland"},
+{"name": "drew daire"},
+{"name": "rebecca landis"},
+{"name": "kathleen baca"},
+{"name": "jennifer allan"},
+{"name": "richard backus"},
+{"name": "vanessa fitch"},
+{"name": "dan stephens"},
+{"name": "janet abut"},
+{"name": "eric billman"},
+{"name": "dustin clampet"},
+{"name": "bryant dist"},
+{"name": "jessie elias"},
+{"name": "laurinda meetup"},
+{"name": "maria ferrari"},
+{"name": "larita larson"},
+{"name": "kevin keenan"},
+{"name": "jack sissons"},
+{"name": "mario testani"},
+{"name": "larry rogers"},
+{"name": "elizabeth keschner"},
+{"name": "kathy delgado"},
+{"name": "bryon krug"},
+{"name": "jake louwsma"},
+{"name": "jason chandra"},
+{"name": "kate saunders"},
+{"name": "chanda whitaker"},
+{"name": "dina lacatena"},
+{"name": "jason nackley"},
+{"name": "mark parker"},
+{"name": "david foks"},
+{"name": "linda carkner"},
+{"name": "michael supp"},
+{"name": "josh hoag"},
+{"name": "andrew cherwenka"},
+{"name": "justin steen"},
+{"name": "michael costa"},
+{"name": "peter saladino"},
+{"name": "ashley shedd"},
+{"name": "laura yates"},
+{"name": "pam courie"},
+{"name": "corey hutchins"},
+{"name": "amanda mullins"},
+{"name": "freeman mik"},
+{"name": "carroll morrow"},
+{"name": "robert griffith"},
+{"name": "michelle gorden"},
+{"name": "eboni cooper"},
+{"name": "roxie markkanen"},
+{"name": "terry sobkowiak"},
+{"name": "laura frankenfield"},
+{"name": "paula rangers"},
+{"name": "jennifer ma"},
+{"name": "misty early"},
+{"name": "joey hinojosa"},
+{"name": "michelle inn"},
+{"name": "frank numbers"},
+{"name": "lori brodsky"},
+{"name": "jennifer ring"},
+{"name": "curtis hendricks"},
+{"name": "claudia chavez"},
+{"name": "wayne logan"},
+{"name": "gregg tugya"},
+{"name": "mike elliot"},
+{"name": "gary mendelson"},
+{"name": "jodi stach"},
+{"name": "ben r"},
+{"name": "mark wines"},
+{"name": "denise m"},
+{"name": "tiana christoforids"},
+{"name": "marian pineda"},
+{"name": "matt anderson"},
+{"name": "lou santana"},
+{"name": "mitch bear"},
+{"name": "theresa wilkerson"},
+{"name": "sean baulch"},
+{"name": "rita carlisle"},
+{"name": "dale loucia"},
+{"name": "van fleet"},
+{"name": "teri gazzilli"},
+{"name": "gary neeleman"},
+{"name": "greg solomon"},
+{"name": "kate sheppard"},
+{"name": "nick shiplov"},
+{"name": "cindy ries"},
+{"name": "alvin spencer"},
+{"name": "sharon dass"},
+{"name": "lauren spratte"},
+{"name": "craig threlkeld"},
+{"name": "steve komperta"},
+{"name": "michael zurat"},
+{"name": "david scherfenberg"},
+{"name": "jen kahtz"},
+{"name": "kim metheny"},
+{"name": "phyllis knight"},
+{"name": "joe menousek"},
+{"name": "monica samuels"},
+{"name": "sara bennett"},
+{"name": "sheryl stewart"},
+{"name": "greg muholland"},
+{"name": "stephanie home"},
+{"name": "ed ezaki"},
+{"name": "derrick pittman"},
+{"name": "ivy washington"},
+{"name": "jerry namba"},
+{"name": "darin smith"},
+{"name": "brian goebel"},
+{"name": "doug silverman"},
+{"name": "george styles"},
+{"name": "valerie healey"},
+{"name": "carri smith"},
+{"name": "al monsta"},
+{"name": "brian buttermore"},
+{"name": "david claman"},
+{"name": "bob walker"},
+{"name": "liz melendez"},
+{"name": "amy woody"},
+{"name": "karen hull"},
+{"name": "doug lawson"},
+{"name": "laura elder"},
+{"name": "julia tracey"},
+{"name": "mark lemere"},
+{"name": "brian pake"},
+{"name": "jason klein"},
+{"name": "john meyer"},
+{"name": "matthew organ"},
+{"name": "john ko"},
+{"name": "brent brooks"},
+{"name": "jennifer hong"},
+{"name": "ashley robey"},
+{"name": "michael stassen"},
+{"name": "alec stone"},
+{"name": "david paiul"},
+{"name": "tony ball"},
+{"name": "jaclyn wright"},
+{"name": "jeff wellburn"},
+{"name": "kourtney hedden"},
+{"name": "josh dobbs"},
+{"name": "brandon oursler"},
+{"name": "emily york"},
+{"name": "amy sydlansky"},
+{"name": "haley steets"},
+{"name": "evan konc"},
+{"name": "kevin o'sulivan"},
+{"name": "becky sarita"},
+{"name": "stephen jenvey"},
+{"name": "matt behnke"},
+{"name": "brooke westall"},
+{"name": "chris arvin"},
+{"name": "john altava"},
+{"name": "jesse lp"},
+{"name": "ellen tamiyasu"},
+{"name": "john mendoza"},
+{"name": "barry holbert"},
+{"name": "heather kindness"},
+{"name": "kym anthony"},
+{"name": "wes dixon"},
+{"name": "gloria work"},
+{"name": "sonia lowe"},
+{"name": "jennifer moshier"},
+{"name": "alan reagan"},
+{"name": "troy holmes"},
+{"name": "paige oterbine"},
+{"name": "mathew booth"},
+{"name": "chris rollins"},
+{"name": "carlos hernandez"},
+{"name": "steve mcleod"},
+{"name": "jon wilcox"},
+{"name": "jeremy weiner"},
+{"name": "oscar ruiz"},
+{"name": "mark hambling"},
+{"name": "craig fowler"},
+{"name": "rick coombes"},
+{"name": "shannon mcc"},
+{"name": "jana beeman"},
+{"name": "doug hurt"},
+{"name": "mike daniels"},
+{"name": "jerry conklin"},
+{"name": "lori graham"},
+{"name": "jason vinson"},
+{"name": "natalia dousso"},
+{"name": "arthur treiman"},
+{"name": "brooke mooshagian"},
+{"name": "steve anichini"},
+{"name": "gerry deguizman"},
+{"name": "kim ward"},
+{"name": "isaac woodson"},
+{"name": "jay keyz"},
+{"name": "dianne roberg"},
+{"name": "keisha client"},
+{"name": "rick levels"},
+{"name": "jeff coronado"},
+{"name": "golden chopsticks"},
+{"name": "yesenia ruvalcaba"},
+{"name": "john moquin"},
+{"name": "melissa bodily"},
+{"name": "miki johnstone"},
+{"name": "josue melissa"},
+{"name": "jaime rivera"},
+{"name": "david orfao"},
+{"name": "rachel miller"},
+{"name": "anthony toma"},
+{"name": "bill thorup"},
+{"name": "ariel yochnan"},
+{"name": "michael ng"},
+{"name": "teresa ehrichs"},
+{"name": "troy tucker"},
+{"name": "todd a"},
+{"name": "erick vzw"},
+{"name": "tony cusumano"},
+{"name": "joshua kestner"},
+{"name": "may may"},
+{"name": "shanon blkstudtop"},
+{"name": "pete bocca"},
+{"name": "greg diamond"},
+{"name": "suzette dotson"},
+{"name": "marisa kline"},
+{"name": "adam davis"},
+{"name": "taylor tran"},
+{"name": "emily em"},
+{"name": "dyan ross"},
+{"name": "temple heights"},
+{"name": "deb ramirez"},
+{"name": "john crowley"},
+{"name": "mark depico"},
+{"name": "mike welch"},
+{"name": "armand columbie"},
+{"name": "steven smiles"},
+{"name": "eric goldfisher"},
+{"name": "julie mani"},
+{"name": "edgar aguirre"},
+{"name": "cary campbell"},
+{"name": "ronald williams"},
+{"name": "alex nevitt"},
+{"name": "ben tan"},
+{"name": "tiffany morton"},
+{"name": "dennis cline"},
+{"name": "cody marosy"},
+{"name": "don ferrell"},
+{"name": "david long"},
+{"name": "thaddeus gilmore"},
+{"name": "doug beasly"},
+{"name": "jerry patchen"},
+{"name": "claire morel"},
+{"name": "mark wheeler"},
+{"name": "mark mintz"},
+{"name": "zane finger"},
+{"name": "mark hoyt"},
+{"name": "marcus caballero"},
+{"name": "alicia gatto"},
+{"name": "derrick jack"},
+{"name": "lynda hood"},
+{"name": "shirley mcgillivray"},
+{"name": "mark cronin"},
+{"name": "dodie lineham"},
+{"name": "shirley coyle"},
+{"name": "mark rowe"},
+{"name": "mendy philo"},
+{"name": "betsy jasper"},
+{"name": "michelle saffon"},
+{"name": "denis cartright"},
+{"name": "scott ballard"},
+{"name": "tim mills"},
+{"name": "jessie riffey"},
+{"name": "ross gunnells"},
+{"name": "matilde guzman"},
+{"name": "tess rey"},
+{"name": "drew stanz"},
+{"name": "mike limatola"},
+{"name": "steve jijika"},
+{"name": "jen cornwall"},
+{"name": "john hd"},
+{"name": "luis garnica"},
+{"name": "nick beall"},
+{"name": "dave evans"},
+{"name": "reid galas"},
+{"name": "scott corno"},
+{"name": "jodi manager"},
+{"name": "lonnie havasu"},
+{"name": "stephanie buck"},
+{"name": "phillip harvey"},
+{"name": "sallie ss"},
+{"name": "john blair"},
+{"name": "jackie hitz"},
+{"name": "john tegeler"},
+{"name": "teresa weibley"},
+{"name": "nana tata"},
+{"name": "david shevock"},
+{"name": "shaunta boone"},
+{"name": "chris davila"},
+{"name": "kevin joyce"},
+{"name": "paul alekna"},
+{"name": "gary fineske"},
+{"name": "irene lau"},
+{"name": "jonathan haigh"},
+{"name": "charles deal"},
+{"name": "van runkle"},
+{"name": "jacob warren"},
+{"name": "william m"},
+{"name": "noel ballon"},
+{"name": "josh bohl"},
+{"name": "donna summit"},
+{"name": "rick sokolov"},
+{"name": "jack zencheck"},
+{"name": "paul pilo"},
+{"name": "mari seamstress"},
+{"name": "yadira cordova"},
+{"name": "anna flanagan"},
+{"name": "dan day"},
+{"name": "mei wong"},
+{"name": "paul schubert"},
+{"name": "mike scott"},
+{"name": "scott bauer"},
+{"name": "olga rogers"},
+{"name": "trey roller"},
+{"name": "andrea piaz"},
+{"name": "sandie reid"},
+{"name": "anthony chung"},
+{"name": "joshua freeland"},
+{"name": "jami kiser"},
+{"name": "harvey shapiro"},
+{"name": "ed cuevas"},
+{"name": "dixie minor"},
+{"name": "beth kaminkow"},
+{"name": "alex williams"},
+{"name": "andrew hazley"},
+{"name": "mike allain"},
+{"name": "peter botani"},
+{"name": "april newbauer"},
+{"name": "henry walters"},
+{"name": "vince akers"},
+{"name": "seth chambers"},
+{"name": "carl yankowski"},
+{"name": "scott sorgea"},
+{"name": "harold beveir"},
+{"name": "richard bonilla"},
+{"name": "donn waslif"},
+{"name": "noel mcdoughal"},
+{"name": "david rubeck"},
+{"name": "elmer sembly"},
+{"name": "mikel bohringer"},
+{"name": "kevin kosik"},
+{"name": "trudy kuefer"},
+{"name": "suzanne sanders"},
+{"name": "kerri persson"},
+{"name": "jacquie burch"},
+{"name": "leigh shanta"},
+{"name": "adrian zimmerli"},
+{"name": "sammy salinas"},
+{"name": "jason ament"},
+{"name": "katie budweiser"},
+{"name": "man tv"},
+{"name": "jay cel"},
+{"name": "garrett washington"},
+{"name": "johnny carino's"},
+{"name": "al stavola"},
+{"name": "renee vigil"},
+{"name": "will flicker"},
+{"name": "buddy rashbaum"},
+{"name": "ronald short"},
+{"name": "greg rusnell"},
+{"name": "rory beymer"},
+{"name": "jose nunez"},
+{"name": "laura beemiller"},
+{"name": "clayton mcclain"},
+{"name": "todd hazel"},
+{"name": "cindy overton"},
+{"name": "allison holstein"},
+{"name": "josh broderick"},
+{"name": "jose ortega"},
+{"name": "roger cottrell"},
+{"name": "morgan stinger"},
+{"name": "aaron chippie"},
+{"name": "sara skees"},
+{"name": "jean lockett"},
+{"name": "ramon machado"},
+{"name": "brooke blanchard"},
+{"name": "janet welch"},
+{"name": "chris latino"},
+{"name": "craig thompson"},
+{"name": "anna aurilio"},
+{"name": "chris chalmers"},
+{"name": "sam kent"},
+{"name": "sam campa"},
+{"name": "adam little"},
+{"name": "holly hill"},
+{"name": "chris vieira"},
+{"name": "steven seidel"},
+{"name": "harley foster"},
+{"name": "steve bralove"},
+{"name": "alan kaplan"},
+{"name": "mike gunnels"},
+{"name": "richard graham"},
+{"name": "jerry miller"},
+{"name": "cheryl solomon"},
+{"name": "christina lampley"},
+{"name": "megan williams"},
+{"name": "ronda gaither"},
+{"name": "adolfo vasquez"},
+{"name": "gary little"},
+{"name": "tom barwick"},
+{"name": "kelley o'connor"},
+{"name": "michael lamb"},
+{"name": "peter herbert"},
+{"name": "daniel greenberg"},
+{"name": "jim fox"},
+{"name": "amy christensen"},
+{"name": "clare vasterling"},
+{"name": "helen pshnier"},
+{"name": "larry drake"},
+{"name": "michael montemayor"},
+{"name": "patricia howe"},
+{"name": "leonard krulewich"},
+{"name": "george lodge"},
+{"name": "glenn williams"},
+{"name": "kymberly vasey"},
+{"name": "brittany miller"},
+{"name": "victor valdez"},
+{"name": "omer voss"},
+{"name": "mike appleby"},
+{"name": "wes boone"},
+{"name": "roger millis"},
+{"name": "fred schilling"},
+{"name": "shirley stewart"},
+{"name": "jacqueline pickering"},
+{"name": "chuck chrisco"},
+{"name": "bonnie bell"},
+{"name": "wes m"},
+{"name": "brandi buchanan"},
+{"name": "derek weber"},
+{"name": "yuri konyev"},
+{"name": "renee shiao"},
+{"name": "mike lindsey"},
+{"name": "greg baptist"},
+{"name": "mark mra"},
+{"name": "jason lowe"},
+{"name": "debbie coan"},
+{"name": "mike becsei"},
+{"name": "kevin reich"},
+{"name": "steven o"},
+{"name": "gladys malouf"},
+{"name": "bobby mn"},
+{"name": "joey white"},
+{"name": "bob prater"},
+{"name": "linda stowers"},
+{"name": "susan bullman"},
+{"name": "jeremy newton"},
+{"name": "clarence holmes"},
+{"name": "dana sauceda"},
+{"name": "dan hardee"},
+{"name": "erin schoen"},
+{"name": "brad martin"},
+{"name": "jake loahr"},
+{"name": "dan nadir"},
+{"name": "virginia dent"},
+{"name": "barb barton"},
+{"name": "nicole hardy"},
+{"name": "ivan tan"},
+{"name": "jeff kunins"},
+{"name": "david holtzman"},
+{"name": "meg gibson"},
+{"name": "robert hime"},
+{"name": "jason balaska"},
+{"name": "jim scarlett"},
+{"name": "ken kinsley"},
+{"name": "nick jensen"},
+{"name": "brandon martin"},
+{"name": "steven biasatti"},
+{"name": "mike weldy"},
+{"name": "alexandra davidson"},
+{"name": "will t"},
+{"name": "bobby pemberton"},
+{"name": "andrew hill"},
+{"name": "tamika morris"},
+{"name": "bev yac"},
+{"name": "bill millers"},
+{"name": "ian sison"},
+{"name": "veronica couzyn"},
+{"name": "susan hanna"},
+{"name": "mark braun"},
+{"name": "star financial"},
+{"name": "steve li"},
+{"name": "ian kraynak"},
+{"name": "bridget whipple"},
+{"name": "janet king"},
+{"name": "tiffany dst"},
+{"name": "susan stevens"},
+{"name": "sam milrod"},
+{"name": "natalie mindt"},
+{"name": "kenny clark"},
+{"name": "sabrina pascucci"},
+{"name": "joe songstad"},
+{"name": "john oppenheim"},
+{"name": "alex mcdow"},
+{"name": "jon richards"},
+{"name": "kyle shoemaker"},
+{"name": "kenneth cloward"},
+{"name": "sandy currie"},
+{"name": "troy sloat"},
+{"name": "ryan izzo"},
+{"name": "ryan avery"},
+{"name": "ron green"},
+{"name": "nick v"},
+{"name": "corrine yount"},
+{"name": "rosa carney"},
+{"name": "jeffrey wu"},
+{"name": "sharon mahoney"},
+{"name": "chris dinneen"},
+{"name": "erin e"},
+{"name": "rich peritz"},
+{"name": "jim causey"},
+{"name": "raul xxxxx"},
+{"name": "maggie mallety"},
+{"name": "dana walker"},
+{"name": "chu tu"},
+{"name": "debbie bartley"},
+{"name": "susanna cooper"},
+{"name": "john finklea"},
+{"name": "ted rowett"},
+{"name": "jack terry"},
+{"name": "jason jones"},
+{"name": "tom lyons"},
+{"name": "leland wells"},
+{"name": "justin mcdonald"},
+{"name": "lowell irwin"},
+{"name": "justin moaibito"},
+{"name": "chris slaughter"},
+{"name": "william noble"},
+{"name": "helen yuen"},
+{"name": "marjorie ritter"},
+{"name": "kelly stratford"},
+{"name": "megan racicot"},
+{"name": "jen niedzwiedzki"},
+{"name": "megan gags"},
+{"name": "lamont williams"},
+{"name": "barb krinn"},
+{"name": "barry mccullers"},
+{"name": "jake heibel"},
+{"name": "james keeline"},
+{"name": "martha rivera"},
+{"name": "tanya thompson"},
+{"name": "irving caribe"},
+{"name": "colin mcdermott"},
+{"name": "andy houtz"},
+{"name": "chris tattoos"},
+{"name": "greg hopkins"},
+{"name": "bonnie chu"},
+{"name": "justin jess"},
+{"name": "dave leon"},
+{"name": "henry fishcl"},
+{"name": "scott morgan"},
+{"name": "shay shay"},
+{"name": "troy vincent"},
+{"name": "christy durbin"},
+{"name": "dave pimpdog"},
+{"name": "victoria lorenzo"},
+{"name": "paul moret"},
+{"name": "antoinette ussery"},
+{"name": "eric griffin"},
+{"name": "mark k"},
+{"name": "dana bleifer"},
+{"name": "tania kucera"},
+{"name": "george villa"},
+{"name": "austin farnsworth"},
+{"name": "sara moss"},
+{"name": "adam sampson"},
+{"name": "pam iorio"},
+{"name": "amy miller"},
+{"name": "kenny t"},
+{"name": "robert selaiden"},
+{"name": "evelyn upham"},
+{"name": "mary harvey"},
+{"name": "amanda costa"},
+{"name": "jung hoon"},
+{"name": "jenni hinderer"},
+{"name": "mark taul"},
+{"name": "krystal rodriguez"},
+{"name": "federico amadeo"},
+{"name": "mike walker"},
+{"name": "anita hall"},
+{"name": "steve bhalla"},
+{"name": "keith canacci"},
+{"name": "nick narrin"},
+{"name": "jerry mansour"},
+{"name": "naomi alboleda"},
+{"name": "christine briones"},
+{"name": "dalene prout"},
+{"name": "nicole guard"},
+{"name": "dacia dr"},
+{"name": "kecia blount"},
+{"name": "fred toms"},
+{"name": "brian hale"},
+{"name": "john reed"},
+{"name": "dave dohn"},
+{"name": "linda kneece"},
+{"name": "tony spatola"},
+{"name": "mike zimmer"},
+{"name": "tony craig"},
+{"name": "patricia yarborough"},
+{"name": "lisa flynn"},
+{"name": "dalene quintana"},
+{"name": "tom home"},
+{"name": "don prioleau"},
+{"name": "ava seave"},
+{"name": "michael ahrens"},
+{"name": "tina gorter"},
+{"name": "ryan doke"},
+{"name": "kyle repetti"},
+{"name": "trish mcmillan"},
+{"name": "greg griggs"},
+{"name": "bambi omo"},
+{"name": "stanley chara"},
+{"name": "amanda moreno"},
+{"name": "lori e"},
+{"name": "brett hagin"},
+{"name": "sam seibert"},
+{"name": "tiffany henning"},
+{"name": "louis hunt"},
+{"name": "sara conn"},
+{"name": "patrick emmons"},
+{"name": "michael chiorean"},
+{"name": "sandy montenegro"},
+{"name": "galen scott"},
+{"name": "michelle gagnon"},
+{"name": "dan deist"},
+{"name": "jay shiel"},
+{"name": "chris contino"},
+{"name": "michael rickert"},
+{"name": "lou haen"},
+{"name": "rick wood"},
+{"name": "jeremy vzw"},
+{"name": "tracy jones"},
+{"name": "josh wheeler"},
+{"name": "melissa carter"},
+{"name": "keith lam"},
+{"name": "tony nardi"},
+{"name": "alex glassenberg"},
+{"name": "cathleen stagen"},
+{"name": "maggie castillo"},
+{"name": "yolanda green"},
+{"name": "joe ozuna"},
+{"name": "luis leon"},
+{"name": "matt brazil"},
+{"name": "teresa youngberg"},
+{"name": "andy ilg"},
+{"name": "tim wiza"},
+{"name": "kim fountain"},
+{"name": "van tran"},
+{"name": "sara reif"},
+{"name": "danielle diamond"},
+{"name": "kathryn darringer"},
+{"name": "vannessa strand"},
+{"name": "travis hall"},
+{"name": "steve findley"},
+{"name": "brandy slater"},
+{"name": "roberto martinez"},
+{"name": "cindy gold"},
+{"name": "george contractor"},
+{"name": "margie pruitt"},
+{"name": "dee dee"},
+{"name": "brian simon"},
+{"name": "jack hoke"},
+{"name": "kelle porter"},
+{"name": "james burton"},
+{"name": "craig vonberg"},
+{"name": "mike phillups"},
+{"name": "tam chewing"},
+{"name": "ian kim"},
+{"name": "tom lytle"},
+{"name": "terry ruffing"},
+{"name": "forrest ward"},
+{"name": "selma marable"},
+{"name": "alene gnyp"},
+{"name": "marie kovacs"},
+{"name": "kathlyn gemoya"},
+{"name": "carl woerner"},
+{"name": "jana tostrude"},
+{"name": "matt pierce"},
+{"name": "lori egler"},
+{"name": "dave fryer"},
+{"name": "alex zand"},
+{"name": "raymond chow"},
+{"name": "julie steelquist"},
+{"name": "jeanette ashley"},
+{"name": "ira topov"},
+{"name": "shauna wojdak"},
+{"name": "shanta huque"},
+{"name": "veronica torres"},
+{"name": "annette schwartz"},
+{"name": "kyle pupello"},
+{"name": "steve ott"},
+{"name": "bella andrawos"},
+{"name": "lisa buck"},
+{"name": "cindy bellet"},
+{"name": "danna garcia"},
+{"name": "bill bartlett"},
+{"name": "adam hartung"},
+{"name": "jessica nothnagel"},
+{"name": "lena dalbey"},
+{"name": "mark dieckhoff"},
+{"name": "charlie s"},
+{"name": "tom jackson"},
+{"name": "greg gonzalez"},
+{"name": "frank delaney"},
+{"name": "oliva romano"},
+{"name": "john reiff"},
+{"name": "hilda barrios"},
+{"name": "carl hasselbrink"},
+{"name": "corrie williams"},
+{"name": "albert hitchcock"},
+{"name": "bart bball"},
+{"name": "jack stewart"},
+{"name": "amy isaacson"},
+{"name": "daniel milikow"},
+{"name": "rebecca crouch"},
+{"name": "natasha richards"},
+{"name": "mark dirsa"},
+{"name": "amber cook"},
+{"name": "sean goodman"},
+{"name": "joe cosper"},
+{"name": "tom swygert"},
+{"name": "dani cook"},
+{"name": "victor carballo"},
+{"name": "larry thrasher"},
+{"name": "lora shogi"},
+{"name": "jeff m"},
+{"name": "bessie marin"},
+{"name": "patrick gentile"},
+{"name": "burton goldberg"},
+{"name": "sandy hanower"},
+{"name": "jamie rogers"},
+{"name": "jon marselis"},
+{"name": "roxanne whitfield"},
+{"name": "joe sims"},
+{"name": "jay basken"},
+{"name": "maria nashif"},
+{"name": "claire sievers"},
+{"name": "dale mills"},
+{"name": "gary slayton"},
+{"name": "chris randle"},
+{"name": "anne verboom"},
+{"name": "stephanie gower"},
+{"name": "van huynh"},
+{"name": "clay andrews"},
+{"name": "adam molloy"},
+{"name": "mike willis"},
+{"name": "dillon mclaughlin"},
+{"name": "sergio c"},
+{"name": "craig bass"},
+{"name": "stephen medina"},
+{"name": "lee long"},
+{"name": "ronald chapman"},
+{"name": "miriam cole"},
+{"name": "ken christensen"},
+{"name": "amanda t"},
+{"name": "jimmy crofts"},
+{"name": "richard morgan"},
+{"name": "sam knowles"},
+{"name": "howard wimmit"},
+{"name": "sally hand"},
+{"name": "chris bethel"},
+{"name": "mike flynn"},
+{"name": "misha rebec"},
+{"name": "mark galloway"},
+{"name": "paul mouridian"},
+{"name": "robert todd"},
+{"name": "betty pygram"},
+{"name": "matt duntz"},
+{"name": "caroline kay"},
+{"name": "andy pavelich"},
+{"name": "gary fontaine"},
+{"name": "lisa pappas"},
+{"name": "david koscheski"},
+{"name": "tammy hermann"},
+{"name": "henry wheat"},
+{"name": "isaac emmanuel"},
+{"name": "jennifer meyer"},
+{"name": "dorothy pleas"},
+{"name": "jose girl"},
+{"name": "patricia barnes"},
+{"name": "christine canfield"},
+{"name": "jessica bodner"},
+{"name": "kevin john"},
+{"name": "kenneth dembek"},
+{"name": "simon miller"},
+{"name": "michael henry"},
+{"name": "shirley starlings"},
+{"name": "bettye jackson"},
+{"name": "chandra ramsey"},
+{"name": "steve bjelich"},
+{"name": "christin meyer"},
+{"name": "casey black"},
+{"name": "james p"},
+{"name": "david saverino"},
+{"name": "kerry nelson"},
+{"name": "brad dolian"},
+{"name": "allen abbassi"},
+{"name": "marilyn town"},
+{"name": "leonard renier"},
+{"name": "jenna jordan"},
+{"name": "andy papadopoulos"},
+{"name": "paul harell"},
+{"name": "stacey rose"},
+{"name": "vanessa quintal"},
+{"name": "frank fama"},
+{"name": "vaughn schrotenboer"},
+{"name": "keith macdonald"},
+{"name": "liz prentice"},
+{"name": "bruce podgur"},
+{"name": "carlos g"},
+{"name": "mary shaw"},
+{"name": "linda vap"},
+{"name": "michael waxman"},
+{"name": "dana subcock"},
+{"name": "lindsay banta"},
+{"name": "nicole storman"},
+{"name": "herb vincent"},
+{"name": "charlie fitzsimmons"},
+{"name": "davis vision"},
+{"name": "carol klaus"},
+{"name": "alex benes"},
+{"name": "james grice"},
+{"name": "john mcdaniel"},
+{"name": "diana hassell"},
+{"name": "danielle lavigne"},
+{"name": "michael liang"},
+{"name": "pete pestello"},
+{"name": "elisabeth merkel"},
+{"name": "mike kao"},
+{"name": "judy aunt"},
+{"name": "michele mariscal"},
+{"name": "marty roberts"},
+{"name": "evan callaway"},
+{"name": "ian doberstein"},
+{"name": "kenny dunn"},
+{"name": "van hilsen"},
+{"name": "luis santamaria"},
+{"name": "jeff ajlouny"},
+{"name": "kris freed"},
+{"name": "patricia lynch"},
+{"name": "cleveland police"},
+{"name": "david segal"},
+{"name": "shawn odom"},
+{"name": "robert hugo"},
+{"name": "jonathan radcliffe"},
+{"name": "david kera"},
+{"name": "mark bast"},
+{"name": "faith kimball"},
+{"name": "kristie brown"},
+{"name": "lucina marsh"},
+{"name": "lenny o'donnell"},
+{"name": "tony williams"},
+{"name": "phil mcgrady"},
+{"name": "jeremiah velera"},
+{"name": "brian steinwurtzel"},
+{"name": "kristen counter"},
+{"name": "alise keil"},
+{"name": "carly figliulo"},
+{"name": "scott simeon"},
+{"name": "lora mertz"},
+{"name": "derek lawes"},
+{"name": "cheryl crelly"},
+{"name": "joe sumrall"},
+{"name": "ryan bland"},
+{"name": "paul cahill"},
+{"name": "rachael leb"},
+{"name": "tristan latino"},
+{"name": "kara derosa"},
+{"name": "michael eng"},
+{"name": "lauren taylor"},
+{"name": "annette ory"},
+{"name": "mike robinson"},
+{"name": "erik heart"},
+{"name": "sean selecta"},
+{"name": "jeremy lerwill"},
+{"name": "dani taylor"},
+{"name": "lucille fink"},
+{"name": "jamal anderson"},
+{"name": "elizabeth cuz"},
+{"name": "tommy chau"},
+{"name": "nick koenig"},
+{"name": "alejandro liontop"},
+{"name": "collette huskey"},
+{"name": "mia hoogheem"},
+{"name": "francis casey"},
+{"name": "nicole jenkins"},
+{"name": "suzanne israel"},
+{"name": "kylie plattsmouth"},
+{"name": "shelley cobian"},
+{"name": "tana kostic"},
+{"name": "katie doherty"},
+{"name": "archie griffin"},
+{"name": "trey p"},
+{"name": "sarah miracle"},
+{"name": "bob bishop"},
+{"name": "hector mendoza"},
+{"name": "bonita dental"},
+{"name": "peter dawkins"},
+{"name": "carlee cochrane"},
+{"name": "darius mom"},
+{"name": "rochelle martire"},
+{"name": "julie stillman"},
+{"name": "claire preice"},
+{"name": "devin dmacc"},
+{"name": "angelica aceves"},
+{"name": "joanna wool"},
+{"name": "evan constan"},
+{"name": "bob naum"},
+{"name": "deb conroy"},
+{"name": "nathan leung"},
+{"name": "doug barnette"},
+{"name": "rick walker"},
+{"name": "dave syck"},
+{"name": "joseph stakem"},
+{"name": "mark mccord"},
+{"name": "enrique enguidanos"},
+{"name": "joel pascual"},
+{"name": "stephan reynolds"},
+{"name": "sal concrete"},
+{"name": "dawn westbrook"},
+{"name": "rachel eastway"},
+{"name": "les dis"},
+{"name": "melanie schiemer"},
+{"name": "james blair"},
+{"name": "stacy d"},
+{"name": "carla martin"},
+{"name": "marla cell"},
+{"name": "randy russ"},
+{"name": "jim janson"},
+{"name": "melanie s"},
+{"name": "carrie needham"},
+{"name": "trish bradley"},
+{"name": "jana klavas"},
+{"name": "katie craig"},
+{"name": "bob vanklingren"},
+{"name": "jared alco"},
+{"name": "connie newman"},
+{"name": "annie schleicher"},
+{"name": "jeff collier"},
+{"name": "will deaton"},
+{"name": "yolande kay"},
+{"name": "daniel mccormack"},
+{"name": "lesa carmack"},
+{"name": "steve bivens"},
+{"name": "harry psilopoulos"},
+{"name": "jeff brambir"},
+{"name": "todd butler"},
+{"name": "rob stuart"},
+{"name": "sean tangen"},
+{"name": "sam parks"},
+{"name": "ken sha"},
+{"name": "trevor shedd"},
+{"name": "chad tilly"},
+{"name": "danny ainge"},
+{"name": "brian byer"},
+{"name": "columbus park"},
+{"name": "andrew estes"},
+{"name": "teresa mccarthy"},
+{"name": "gil blattner"},
+{"name": "adam o'keefe"},
+{"name": "sarah long"},
+{"name": "will kuntz"},
+{"name": "david bramon"},
+{"name": "melissa mariano"},
+{"name": "dwayne king"},
+{"name": "melissa gagnon"},
+{"name": "sari greenberg"},
+{"name": "michael paul"},
+{"name": "maria leos"},
+{"name": "archie cardwell"},
+{"name": "teri mccall"},
+{"name": "curt hauber"},
+{"name": "jeff mlodinoff"},
+{"name": "chris jersy"},
+{"name": "melinda gibson"},
+{"name": "peter rhee"},
+{"name": "kyle schwab"},
+{"name": "brad verona"},
+{"name": "scott hendrickson"},
+{"name": "tim mccreary"},
+{"name": "richard dr"},
+{"name": "chris kloep"},
+{"name": "ben knoop"},
+{"name": "nikki chick"},
+{"name": "mike heighbor"},
+{"name": "alan telefunken"},
+{"name": "mike mcgee"},
+{"name": "joe book"},
+{"name": "elizabeth l"},
+{"name": "nicholas grundei"},
+{"name": "scott romero"},
+{"name": "joan morgan"},
+{"name": "jan hillman"},
+{"name": "heather sg"},
+{"name": "roger ropp"},
+{"name": "lisa palazzo"},
+{"name": "tyler will"},
+{"name": "katie hacket"},
+{"name": "louise beaulieu"},
+{"name": "lydia henik"},
+{"name": "colin gebhard"},
+{"name": "dallas peterson"},
+{"name": "tommy eulberg"},
+{"name": "gregory gulia"},
+{"name": "doug dillon"},
+{"name": "andrea digdo"},
+{"name": "thomas s"},
+{"name": "susan paoli"},
+{"name": "margaret sherman"},
+{"name": "van acker"},
+{"name": "richard zverina"},
+{"name": "sophie b"},
+{"name": "michael fleisher"},
+{"name": "joe rodgers"},
+{"name": "dennis lynch"},
+{"name": "tim kelley"},
+{"name": "cherie watkins"},
+{"name": "frank palermo"},
+{"name": "lisa dave"},
+{"name": "amy nelson"},
+{"name": "charles fetzer"},
+{"name": "shelia reese"},
+{"name": "nannette wilkins"},
+{"name": "crystal lane"},
+{"name": "scott felgenhauer"},
+{"name": "kelly teds"},
+{"name": "shari rochester"},
+{"name": "ben bar"},
+{"name": "john pak"},
+{"name": "nancy reeves"},
+{"name": "lindsey b"},
+{"name": "chuck c"},
+{"name": "michael yvonne"},
+{"name": "christina smillie"},
+{"name": "june house"},
+{"name": "chris hudson"},
+{"name": "sarah jacobson"},
+{"name": "larry goldberg"},
+{"name": "michael dawkins"},
+{"name": "andrea mathieu"},
+{"name": "dave sedlacko"},
+{"name": "don glacy"},
+{"name": "douglas michie"},
+{"name": "cheryl knox"},
+{"name": "brian grant"},
+{"name": "leon beurde"},
+{"name": "beth alitt"},
+{"name": "lisa landau"},
+{"name": "clarence will"},
+{"name": "jessica winton"},
+{"name": "kyle opc"},
+{"name": "jill russ"},
+{"name": "wayne roy"},
+{"name": "chrissy baker"},
+{"name": "bill hoppes"},
+{"name": "miguel baeza"},
+{"name": "sarah young"},
+{"name": "shanna wilcoxen"},
+{"name": "shane o'neill"},
+{"name": "ray prigodich"},
+{"name": "tim sumera"},
+{"name": "rick gobio"},
+{"name": "laura chittenden"},
+{"name": "adam wilhite"},
+{"name": "kelsey schuette"},
+{"name": "ted moye"},
+{"name": "nancy vanasse"},
+{"name": "larry diran"},
+{"name": "david mack"},
+{"name": "johnny perez"},
+{"name": "dave dover"},
+{"name": "maurice nixon"},
+{"name": "tai food"},
+{"name": "kevin jensen"},
+{"name": "blake c"},
+{"name": "jason young"},
+{"name": "crystal azuara"},
+{"name": "matt quinlan"},
+{"name": "ken thomas"},
+{"name": "larry maguire"},
+{"name": "stacey battenfield"},
+{"name": "steve hartley"},
+{"name": "carlos lema"},
+{"name": "peter cairo"},
+{"name": "seth edm"},
+{"name": "beth geagley"},
+{"name": "sherrie shelley"},
+{"name": "peter campen"},
+{"name": "laura cellcom"},
+{"name": "van niekerk"},
+{"name": "mike gerth"},
+{"name": "janice mcmahon"},
+{"name": "nicole mustang"},
+{"name": "amanda fischer"},
+{"name": "lizette zuninga"},
+{"name": "johanna rowe"},
+{"name": "chris hamje"},
+{"name": "stacy robinson"},
+{"name": "dan campagna"},
+{"name": "lindsy l"},
+{"name": "jose barrera"},
+{"name": "robert faure"},
+{"name": "mac mac"},
+{"name": "john batz"},
+{"name": "jim livingston"},
+{"name": "laura masso"},
+{"name": "jacqueline henderson"},
+{"name": "beatriz cajade"},
+{"name": "brian sanderson"},
+{"name": "damian brawner"},
+{"name": "brett roeloffs"},
+{"name": "annamarie cell"},
+{"name": "marc garside"},
+{"name": "kim peck"},
+{"name": "amy schultz"},
+{"name": "barry gilardi"},
+{"name": "todd zivic"},
+{"name": "jim pigeon"},
+{"name": "melissa rios"},
+{"name": "richard strauss"},
+{"name": "dean spears"},
+{"name": "johnny liao"},
+{"name": "leah able"},
+{"name": "henry johnson"},
+{"name": "gary laib"},
+{"name": "kathleen mcgann"},
+{"name": "mercy north"},
+{"name": "gussie doucet"},
+{"name": "john geraghty"},
+{"name": "dennis sage"},
+{"name": "alex wulff"},
+{"name": "petra zamora"},
+{"name": "kelly gentry"},
+{"name": "joe wolfe"},
+{"name": "ed downs"},
+{"name": "brandon gmc"},
+{"name": "anthony bell"},
+{"name": "doug drennan"},
+{"name": "jeanine flemming"},
+{"name": "franklin arner"},
+{"name": "mary lester"},
+{"name": "shonda hosley"},
+{"name": "jermaine boltom"},
+{"name": "alan hritz"},
+{"name": "jo stribling"},
+{"name": "tricia mcmullen"},
+{"name": "juanita lyons"},
+{"name": "john sweigart"},
+{"name": "manuel camarena"},
+{"name": "mike brittingham"},
+{"name": "denise oberfoell"},
+{"name": "kyle hotface"},
+{"name": "thomas potter"},
+{"name": "bob glaser"},
+{"name": "pierre g"},
+{"name": "bruce bradford"},
+{"name": "mara aspinall"},
+{"name": "james chesson"},
+{"name": "randy legacy"},
+{"name": "bill mullin"},
+{"name": "tom porsche"},
+{"name": "laura bye"},
+{"name": "louis m"},
+{"name": "jennifer cell"},
+{"name": "margie contreras"},
+{"name": "chuck vogel"},
+{"name": "heather andrews"},
+{"name": "timothy worley"},
+{"name": "karen lane"},
+{"name": "andrea kimmell"},
+{"name": "phil wagers"},
+{"name": "holly beaton"},
+{"name": "donn dirckx"},
+{"name": "jodi burgess"},
+{"name": "grant vandyke"},
+{"name": "kristen gaetano"},
+{"name": "gina ruttenber"},
+{"name": "wade kids"},
+{"name": "mark pleis"},
+{"name": "mark chu"},
+{"name": "kris ehlert"},
+{"name": "tim starchman"},
+{"name": "jim warsaw"},
+{"name": "john piscitelli"},
+{"name": "krista adams"},
+{"name": "erica brown"},
+{"name": "nichole wilson"},
+{"name": "don miles"},
+{"name": "doris barnes"},
+{"name": "tammy sigler"},
+{"name": "dionne savage"},
+{"name": "erin party"},
+{"name": "sage massage"},
+{"name": "kyle j"},
+{"name": "delores gray"},
+{"name": "judy mcfarland"},
+{"name": "clint edwards"},
+{"name": "stephanie mistrel"},
+{"name": "willy velazquez"},
+{"name": "tim juillett"},
+{"name": "george ku"},
+{"name": "juan campos"},
+{"name": "tony paloto"},
+{"name": "ma taxi"},
+{"name": "nick griego"},
+{"name": "stephanie burton"},
+{"name": "reinaldo kingland"},
+{"name": "vince biancuzzo"},
+{"name": "regina michael"},
+{"name": "madeleine heal"},
+{"name": "andrew yaldo"},
+{"name": "steve cummins"},
+{"name": "jeff todd"},
+{"name": "rafael johnson"},
+{"name": "brian craig"},
+{"name": "cole lolo"},
+{"name": "kevin hotaling"},
+{"name": "allen karakosian"},
+{"name": "joanne lindsey"},
+{"name": "gordon soltan"},
+{"name": "rosalyn blount"},
+{"name": "charlie bonier"},
+{"name": "brock galvin"},
+{"name": "val astillero"},
+{"name": "matthew schulz"},
+{"name": "andy gainer"},
+{"name": "don cross"},
+{"name": "matt glab"},
+{"name": "jacques designs"},
+{"name": "emily thompson"},
+{"name": "thad engellenner"},
+{"name": "christina smith"},
+{"name": "brandon mejia"},
+{"name": "andres rael"},
+{"name": "marcus martin"},
+{"name": "lance home"},
+{"name": "michele mollica"},
+{"name": "dana namowicz"},
+{"name": "christian freshy"},
+{"name": "kelly stockhaus"},
+{"name": "brittney everhart"},
+{"name": "chris henrie"},
+{"name": "kristen abbondante"},
+{"name": "crystal mckellar"},
+{"name": "sandra reyes"},
+{"name": "john hayet"},
+{"name": "neil sikora"},
+{"name": "neal oppen"},
+{"name": "ray bradshaw"},
+{"name": "vicki venable"},
+{"name": "annette murray"},
+{"name": "anne posada"},
+{"name": "amy peele"},
+{"name": "tara morgan"},
+{"name": "max zollner"},
+{"name": "andy adams"},
+{"name": "dan lavalley"},
+{"name": "serena choi"},
+{"name": "mellissa s"},
+{"name": "pamela leidecker"},
+{"name": "brandon des"},
+{"name": "brian mez"},
+{"name": "timothy farrell"},
+{"name": "elaine chan"},
+{"name": "royal res"},
+{"name": "karen rakowski"},
+{"name": "korey skudder"},
+{"name": "ken leal"},
+{"name": "ali entwistle"},
+{"name": "shannon wenaas"},
+{"name": "gerry wilson"},
+{"name": "peter comeau"},
+{"name": "megan ortizzle"},
+{"name": "caitlyn mcneill"},
+{"name": "frank leonard"},
+{"name": "lisa jurgens"},
+{"name": "corey jones"},
+{"name": "beth aspinall"},
+{"name": "deana mayorga"},
+{"name": "rob pulver"},
+{"name": "preston pointe"},
+{"name": "matt biker"},
+{"name": "doug murray"},
+{"name": "janet rutherford"},
+{"name": "linda bryant"},
+{"name": "luis pinpin"},
+{"name": "clay covington"},
+{"name": "frank hunter"},
+{"name": "todd meek"},
+{"name": "randy colvin"},
+{"name": "mike koerner"},
+{"name": "dennis patterson"},
+{"name": "jon osterhout"},
+{"name": "marie begay"},
+{"name": "dennis cardoza"},
+{"name": "tatiana taylor"},
+{"name": "abraham friend"},
+{"name": "howard fitzpatrick"},
+{"name": "sara christianson"},
+{"name": "thelma carnero"},
+{"name": "mike wiggins"},
+{"name": "nathalie leblanc"},
+{"name": "mac duzer"},
+{"name": "jake conley"},
+{"name": "clifford harris"},
+{"name": "andy whitworth"},
+{"name": "rebecca milner"},
+{"name": "freeman cell"},
+{"name": "ned sirry"},
+{"name": "jon holland"},
+{"name": "scott davidson"},
+{"name": "brian schrumpf"},
+{"name": "george solano"},
+{"name": "marcia dover"},
+{"name": "andrew olvera"},
+{"name": "scott cmptr"},
+{"name": "ericka baca"},
+{"name": "stephen lim"},
+{"name": "iris talbot"},
+{"name": "aaron armstrong"},
+{"name": "rick zak"},
+{"name": "linda rita"},
+{"name": "pete kinnaman"},
+{"name": "richard ireland"},
+{"name": "scott vaughan"},
+{"name": "kay jackson"},
+{"name": "tom cortese"},
+{"name": "brad catlow"},
+{"name": "laura brooker"},
+{"name": "debra cameron"},
+{"name": "erik myford"},
+{"name": "chris lilly"},
+{"name": "daniel lammers"},
+{"name": "michael swanson"},
+{"name": "kirsten barber"},
+{"name": "nick christensen"},
+{"name": "scott reynolds"},
+{"name": "christopher o'rand"},
+{"name": "anna martin"},
+{"name": "dexter collins"},
+{"name": "doug hypnox"},
+{"name": "trevor y"},
+{"name": "dell moellenberg"},
+{"name": "dan cosentino"},
+{"name": "amy liberman"},
+{"name": "eva h"},
+{"name": "michael howarth"},
+{"name": "lynn snyder"},
+{"name": "freddy adams"},
+{"name": "beth gentry"},
+{"name": "nick molina"},
+{"name": "grant hackney"},
+{"name": "jan divito"},
+{"name": "mark eastley"},
+{"name": "barry stevens"},
+{"name": "rick hocking"},
+{"name": "brent schneider"},
+{"name": "eugene russia"},
+{"name": "eric lott"},
+{"name": "brenda endicott"},
+{"name": "andy whaley"},
+{"name": "aleshia foskett"},
+{"name": "jeff wong"},
+{"name": "lynn fugina"},
+{"name": "richard nield"},
+{"name": "joseph pannick"},
+{"name": "tim ladison"},
+{"name": "jeremy gaffrey"},
+{"name": "willie everette"},
+{"name": "brad holsworth"},
+{"name": "jerry burke"},
+{"name": "brent blumenthal"},
+{"name": "ron westphal"},
+{"name": "shane ching"},
+{"name": "linda tier"},
+{"name": "anthony scott"},
+{"name": "nancy tees"},
+{"name": "bruce bekkerus"},
+{"name": "bobby s"},
+{"name": "catherine consiglieri"},
+{"name": "alina ivanyk"},
+{"name": "molly crippen"},
+{"name": "johanna bennett"},
+{"name": "dan k"},
+{"name": "dee reeder"},
+{"name": "craig dubberstein"},
+{"name": "eric german"},
+{"name": "tuan post"},
+{"name": "jeff watchel"},
+{"name": "scott pickens"},
+{"name": "keiko clark"},
+{"name": "jeff dynasplint"},
+{"name": "brian o'keefe"},
+{"name": "mike nelson"},
+{"name": "matt legray"},
+{"name": "kate carroll"},
+{"name": "don slater"},
+{"name": "joanna nickels"},
+{"name": "tommie hart"},
+{"name": "liz smith"},
+{"name": "matt vw"},
+{"name": "ian lesley"},
+{"name": "kurt fleer"},
+{"name": "ryan forbes"},
+{"name": "curtis emory"},
+{"name": "hee lee"},
+{"name": "garret schaede"},
+{"name": "tasha barton"},
+{"name": "eric whimmer"},
+{"name": "laura doyle"},
+{"name": "julie erickson"},
+{"name": "denise mcken"},
+{"name": "tamara sebilian"},
+{"name": "so fong"},
+{"name": "karen costa"},
+{"name": "herb forsythe"},
+{"name": "mike clark"},
+{"name": "mia quinn"},
+{"name": "richard weiss"},
+{"name": "lee dilworth"},
+{"name": "dot jay"},
+{"name": "tony makue"},
+{"name": "pete perez"},
+{"name": "glenn valente"},
+{"name": "sheryl rowling"},
+{"name": "elizabeth chic"},
+{"name": "faith moore"},
+{"name": "courtney caplinger"},
+{"name": "david duarte"},
+{"name": "angel rcsc"},
+{"name": "greg taylor"},
+{"name": "blake baker"},
+{"name": "chad phillips"},
+{"name": "kim hornbeck"},
+{"name": "steve coleman"},
+{"name": "brian pace"},
+{"name": "shannon d"},
+{"name": "brian walowitz"},
+{"name": "scott furtney"},
+{"name": "alice lichtman"},
+{"name": "patti mehling"},
+{"name": "bob haines"},
+{"name": "david kats"},
+{"name": "steve wang"},
+{"name": "gary lau"},
+{"name": "john meyers"},
+{"name": "rose ihedigbo"},
+{"name": "angie carter"},
+{"name": "pete glee"},
+{"name": "robert kolenda"},
+{"name": "mike caputo"},
+{"name": "katie mclauchlin"},
+{"name": "jamie burton"},
+{"name": "tonya grantham"},
+{"name": "albert linderman"},
+{"name": "rich geiger"},
+{"name": "linda trigger"},
+{"name": "ty nightmare"},
+{"name": "ian schneidmiller"},
+{"name": "douglas treasurer"},
+{"name": "ed krieger"},
+{"name": "shawn murray"},
+{"name": "lillian wong"},
+{"name": "katie crowder"},
+{"name": "todd or"},
+{"name": "al bliss"},
+{"name": "georgina gonzalez"},
+{"name": "lauren elias"},
+{"name": "mike elmore"},
+{"name": "don epps"},
+{"name": "elijah kedzie"},
+{"name": "rich mast"},
+{"name": "dwayne mays"},
+{"name": "david bleaman"},
+{"name": "julie rivera"},
+{"name": "stella larreau"},
+{"name": "kerry roman"},
+{"name": "patricia mattos"},
+{"name": "jenny rivera"},
+{"name": "danielle burmylo"},
+{"name": "brett thomas"},
+{"name": "bethany beelan"},
+{"name": "stuart fesseden"},
+{"name": "ben dominguez"},
+{"name": "debbie deba"},
+{"name": "sonny huntley"},
+{"name": "megan chinook"},
+{"name": "laura allenbaugh"},
+{"name": "dena phillips"},
+{"name": "bobbie giuliano"},
+{"name": "jackie cowin"},
+{"name": "sue green"},
+{"name": "stephanie spiller"},
+{"name": "ross casner"},
+{"name": "alex russakovsky"},
+{"name": "libby louman"},
+{"name": "kurt terry"},
+{"name": "julie clark"},
+{"name": "philip georgious"},
+{"name": "mike goodson"},
+{"name": "pete eng"},
+{"name": "brooks king"},
+{"name": "charlie va"},
+{"name": "john pasqualetto"},
+{"name": "tracy johnson"},
+{"name": "keisha dunston"},
+{"name": "heather levy"},
+{"name": "susan kitamura"},
+{"name": "jason pin"},
+{"name": "donnie short"},
+{"name": "josh kelly"},
+{"name": "cathy payne"},
+{"name": "jose cubiche"},
+{"name": "esther o"},
+{"name": "luis villafan"},
+{"name": "melody tyson"},
+{"name": "angela teran"},
+{"name": "jan sanderlin"},
+{"name": "megan hull"},
+{"name": "tiffany bunting"},
+{"name": "joesph teeter"},
+{"name": "mitchell dinkin"},
+{"name": "jodi ferrell"},
+{"name": "philip fryers"},
+{"name": "megan stohner"},
+{"name": "benjamin loeb"},
+{"name": "robin yancey"},
+{"name": "scott lechanski"},
+{"name": "jackson cates"},
+{"name": "greg blaho"},
+{"name": "linda young"},
+{"name": "chris kellog"},
+{"name": "aaron dietrich"},
+{"name": "bill depalma"},
+{"name": "jordan murakami"},
+{"name": "mike ez"},
+{"name": "erica sullenburg"},
+{"name": "darla white"},
+{"name": "michael clark"},
+{"name": "mike hess"},
+{"name": "rocky mt"},
+{"name": "mark genx"},
+{"name": "mark gefroh"},
+{"name": "stephen phalen"},
+{"name": "travis nicol"},
+{"name": "gwen leake"},
+{"name": "austin patton"},
+{"name": "kyle cain"},
+{"name": "mike charvat"},
+{"name": "mike ziemba"},
+{"name": "nellie price"},
+{"name": "jeanne thompson"},
+{"name": "eric doerr"},
+{"name": "paul semak"},
+{"name": "ryan murill"},
+{"name": "jena ellis"},
+{"name": "paul powell"},
+{"name": "nathan h"},
+{"name": "sherri parker"},
+{"name": "collin riley"},
+{"name": "brenda mehringer"},
+{"name": "joey manuguid"},
+{"name": "alex adams"},
+{"name": "jonathan gonzalez"},
+{"name": "olivia yance"},
+{"name": "tobias j"},
+{"name": "les charles"},
+{"name": "shawnda hamilton"},
+{"name": "jim kordel"},
+{"name": "dave farmer"},
+{"name": "sallie bacher"},
+{"name": "will serette"},
+{"name": "aaron peterson"},
+{"name": "stephen stuart"},
+{"name": "tiffany glad"},
+{"name": "joseph d'amato"},
+{"name": "peter roberts"},
+{"name": "jason schutt"},
+{"name": "marie aguilar"},
+{"name": "lincoln cabs"},
+{"name": "walton emc"},
+{"name": "eric hippeau"},
+{"name": "thomas moukiman"},
+{"name": "nadine barth"},
+{"name": "barry kahn"},
+{"name": "jonathan ryskamp"},
+{"name": "crystal birns"},
+{"name": "sharon kerr"},
+{"name": "elizabeth davies"},
+{"name": "jeff bucknam"},
+{"name": "katrina dubinsky"},
+{"name": "rose steiner"},
+{"name": "sharon thompson"},
+{"name": "miss dale"},
+{"name": "ronald berna"},
+{"name": "deanna bing"},
+{"name": "mark kaufman"},
+{"name": "jean carrasquel"},
+{"name": "maria lopez"},
+{"name": "hunter motto"},
+{"name": "delta propane"},
+{"name": "sean bleiler"},
+{"name": "johnnie boy"},
+{"name": "alex vb"},
+{"name": "sandra cuz"},
+{"name": "richard moore"},
+{"name": "tim corey"},
+{"name": "jane elizabeth"},
+{"name": "joanne francisco"},
+{"name": "mary london"},
+{"name": "steve santich"},
+{"name": "anissa attard"},
+{"name": "steve nangle"},
+{"name": "robert golding"},
+{"name": "tom geiger"},
+{"name": "doug riddell"},
+{"name": "bobby laraway"},
+{"name": "jennifer collins"},
+{"name": "karl forste"},
+{"name": "rob kessler"},
+{"name": "lori altman"},
+{"name": "nia powers"},
+{"name": "harris magic"},
+{"name": "jason yarber"},
+{"name": "kathy lansberry"},
+{"name": "allison pace"},
+{"name": "whitney mk"},
+{"name": "chris const"},
+{"name": "mark russell"},
+{"name": "kim plumbley"},
+{"name": "danielle scognamiglio"},
+{"name": "brandy dempsy"},
+{"name": "monte kingstone"},
+{"name": "paola schifino"},
+{"name": "thomas howell"},
+{"name": "karl stelmaczonek"},
+{"name": "lacie payment"},
+{"name": "hope blake"},
+{"name": "genny voltan"},
+{"name": "brad ritthaler"},
+{"name": "art torres"},
+{"name": "michelle bradley"},
+{"name": "melissa neiderman"},
+{"name": "mari d'ambrosio"},
+{"name": "tiffany zejacs"},
+{"name": "james goldkamp"},
+{"name": "amelia estrella"},
+{"name": "allen pickett"},
+{"name": "nick valenziano"},
+{"name": "williams hospital"},
+{"name": "john knopf"},
+{"name": "nick thompson"},
+{"name": "helen mcinnis"},
+{"name": "cindy webb"},
+{"name": "chris jarbo"},
+{"name": "ed linaugh"},
+{"name": "esteban loaiza"},
+{"name": "jason owyang"},
+{"name": "courtney spiller"},
+{"name": "alan farmer"},
+{"name": "mike mundy"},
+{"name": "jim starin"},
+{"name": "valerie beattie"},
+{"name": "bryan rust"},
+{"name": "mike brice"},
+{"name": "dwight eaddy"},
+{"name": "bob pearl"},
+{"name": "james chi"},
+{"name": "jolynn leyderman"},
+{"name": "terri g"},
+{"name": "carlos souza"},
+{"name": "mark wright"},
+{"name": "clinton greyling"},
+{"name": "graham greenlee"},
+{"name": "bob strasser"},
+{"name": "catharine seward"},
+{"name": "kevin savoree"},
+{"name": "michele ayphassorho"},
+{"name": "william holt"},
+{"name": "joseph grossano"},
+{"name": "justin shephard"},
+{"name": "john kiser"},
+{"name": "vickie tidwell"},
+{"name": "cody l"},
+{"name": "joseph larky"},
+{"name": "jamie vedder"},
+{"name": "charlie ambroz"},
+{"name": "jazmin abdulmasih"},
+{"name": "france denk"},
+{"name": "david dunn"},
+{"name": "tim white"},
+{"name": "bob faris"},
+{"name": "selina ray"},
+{"name": "michelle rodeback"},
+{"name": "brian fitch"},
+{"name": "eric farrior"},
+{"name": "nick strombach"},
+{"name": "christina thompson"},
+{"name": "rafael gomez"},
+{"name": "kevin client"},
+{"name": "gary honings"},
+{"name": "blanca aldana"},
+{"name": "dave butters"},
+{"name": "sandy walker"},
+{"name": "mike benntt"},
+{"name": "amy cummins"},
+{"name": "beau hill"},
+{"name": "kevin ma"},
+{"name": "erin norton"},
+{"name": "adrianna delao"},
+{"name": "jody chimura"},
+{"name": "theresa morales"},
+{"name": "anthony s"},
+{"name": "john wendt"},
+{"name": "mike gesmundo"},
+{"name": "jim brouhard"},
+{"name": "leigh hudson"},
+{"name": "paul hunter"},
+{"name": "chris sparrow"},
+{"name": "lisa laznicka"},
+{"name": "daniel castillo"},
+{"name": "mark farmer"},
+{"name": "christine hugh"},
+{"name": "darryl boyd"},
+{"name": "jeanette biolab"},
+{"name": "yvette triana"},
+{"name": "grace kumamoto"},
+{"name": "jeff perry"},
+{"name": "justin burnham"},
+{"name": "robert valentino"},
+{"name": "brent hot"},
+{"name": "roger chen"},
+{"name": "angela bell"},
+{"name": "joyce aunt"},
+{"name": "larry parker"},
+{"name": "justin mcreynolds"},
+{"name": "robin torres"},
+{"name": "danny bolanio"},
+{"name": "rick gilmore"},
+{"name": "jon stock"},
+{"name": "jean ware"},
+{"name": "arnold jenkins"},
+{"name": "bob lee"},
+{"name": "kathleen gannett"},
+{"name": "diane mainville"},
+{"name": "van lear"},
+{"name": "frank nicolette"},
+{"name": "richard sabotino"},
+{"name": "gene deuchar"},
+{"name": "mike berno"},
+{"name": "carl sue"},
+{"name": "brent scoggins"},
+{"name": "grant holland"},
+{"name": "anna garcia"},
+{"name": "erik pof"},
+{"name": "matt grzech"},
+{"name": "bonnie powers"},
+{"name": "david niewood"},
+{"name": "chris lynch"},
+{"name": "katherine arbuckle"},
+{"name": "max simmons"},
+{"name": "nancy douglas"},
+{"name": "stormy haupt"},
+{"name": "andrew kent"},
+{"name": "jean kinkead"},
+{"name": "vince carr"},
+{"name": "bryan chang"},
+{"name": "darnell moore"},
+{"name": "jason birdwell"},
+{"name": "christy ball"},
+{"name": "pat kennedy"},
+{"name": "shane sobers"},
+{"name": "scott burgess"},
+{"name": "dave newbill"},
+{"name": "tim crabtree"},
+{"name": "alan pinel"},
+{"name": "kevin cook"},
+{"name": "erin cash"},
+{"name": "jacque wendel"},
+{"name": "marc castel"},
+{"name": "ramon lopez"},
+{"name": "shannon wells"},
+{"name": "taylor mclemore"},
+{"name": "michael westwood"},
+{"name": "eddie torres"},
+{"name": "julia barnes"},
+{"name": "abdul diallo"},
+{"name": "lilly ferrer"},
+{"name": "audra king"},
+{"name": "jason bourgeois"},
+{"name": "danny santos"},
+{"name": "ed osborne"},
+{"name": "craig lebouef"},
+{"name": "melissa cleaner"},
+{"name": "marx meetup"},
+{"name": "dennis anosike"},
+{"name": "molly o'rourke"},
+{"name": "ken woo"},
+{"name": "brian schawe"},
+{"name": "anne hendrickson"},
+{"name": "andy mitchell"},
+{"name": "charlie gardner"},
+{"name": "terry steele"},
+{"name": "rich exhaust"},
+{"name": "richard murton"},
+{"name": "nisha fufi"},
+{"name": "krystal vonk"},
+{"name": "brian haskins"},
+{"name": "crissy cox"},
+{"name": "cheryl bowden"},
+{"name": "carol desimone"},
+{"name": "andy calhart"},
+{"name": "doug gust"},
+{"name": "cynthia vee"},
+{"name": "marilyn diana"},
+{"name": "chase borum"},
+{"name": "victoria booker"},
+{"name": "mike prather"},
+{"name": "lindsey jordan"},
+{"name": "cassi santana"},
+{"name": "michiko shimura"},
+{"name": "amanda mae"},
+{"name": "kyle messick"},
+{"name": "latonya jackson"},
+{"name": "jonathan blattmachr"},
+{"name": "tina poli"},
+{"name": "chris good"},
+{"name": "charles karich"},
+{"name": "lisette lavella"},
+{"name": "austin mark"},
+{"name": "philip russo"},
+{"name": "stanley ruth"},
+{"name": "michelle meloy"},
+{"name": "john driedger"},
+{"name": "jessica woolsey"},
+{"name": "scott griffin"},
+{"name": "mike sales"},
+{"name": "mark barnreiter"},
+{"name": "joyce rowlands"},
+{"name": "chris sowden"},
+{"name": "jay curnin"},
+{"name": "emily kiely"},
+{"name": "corinna collaga"},
+{"name": "dan jaimie"},
+{"name": "jeff kulinski"},
+{"name": "ben pereira"},
+{"name": "chad akins"},
+{"name": "john wunder"},
+{"name": "tasha corderro"},
+{"name": "chris donahue"},
+{"name": "annette tanori"},
+{"name": "jenni catron"},
+{"name": "kathleen galvin"},
+{"name": "andy shanley"},
+{"name": "gail flynn"},
+{"name": "karen gedrose"},
+{"name": "corey woolley"},
+{"name": "kevin moran"},
+{"name": "brian bedoya"},
+{"name": "david tinkham"},
+{"name": "carmen awad"},
+{"name": "alexander bimman"},
+{"name": "emanuel franklin"},
+{"name": "jay torres"},
+{"name": "gail dixon"},
+{"name": "jerry gomez"},
+{"name": "mark taylor"},
+{"name": "leah waren"},
+{"name": "christian nosiglia"},
+{"name": "nicole iglesias"},
+{"name": "linda mcguire"},
+{"name": "michael house"},
+{"name": "greg palm"},
+{"name": "robin gross"},
+{"name": "jeremy acura"},
+{"name": "dominic lee"},
+{"name": "diane hoover"},
+{"name": "mike jill"},
+{"name": "justin beckwith"},
+{"name": "brooke s"},
+{"name": "phil korn"},
+{"name": "vincent tammaro"},
+{"name": "brian wall"},
+{"name": "jacob vincent"},
+{"name": "scott oh"},
+{"name": "michael bassik"},
+{"name": "ahmed aziz"},
+{"name": "mike cochran"},
+{"name": "marion zaugg"},
+{"name": "david rodela"},
+{"name": "kyle bunke"},
+{"name": "dan wise"},
+{"name": "barry rosenberg"},
+{"name": "juliann cell"},
+{"name": "donna cell"},
+{"name": "crystal miller"},
+{"name": "hailey chan"},
+{"name": "florentina buenaventura"},
+{"name": "james mares"},
+{"name": "sarah farnam"},
+{"name": "rob crain"},
+{"name": "jason tateishi"},
+{"name": "frank dejesus"},
+{"name": "kathy hamilton"},
+{"name": "vivian rintoul"},
+{"name": "bruce gregersen"},
+{"name": "lupe alanis"},
+{"name": "andre hamby"},
+{"name": "chris rybokowski"},
+{"name": "paul goldstein"},
+{"name": "ali m"},
+{"name": "clayton varner"},
+{"name": "ben cubitt"},
+{"name": "francine hoch"},
+{"name": "josh abehsera"},
+{"name": "ashley bell"},
+{"name": "larry lashley"},
+{"name": "bruce mann"},
+{"name": "maria austen"},
+{"name": "jeff d"},
+{"name": "mary newsom"},
+{"name": "tim ackerman"},
+{"name": "josh brother"},
+{"name": "louie parker"},
+{"name": "claudia marienau"},
+{"name": "pete snavely"},
+{"name": "brian quick"},
+{"name": "micaela tucker"},
+{"name": "hugo ramirez"},
+{"name": "craig dunford"},
+{"name": "chuck frazier"},
+{"name": "brenda wagner"},
+{"name": "sue gunaca"},
+{"name": "jenny duncan"},
+{"name": "ashley brain"},
+{"name": "tasha shaka"},
+{"name": "doug berwick"},
+{"name": "mike jacobs"},
+{"name": "elmer panganiban"},
+{"name": "bob buchan"},
+{"name": "barbara kimber"},
+{"name": "alisha mathis"},
+{"name": "hank mirrow"},
+{"name": "bessie williams"},
+{"name": "gil ernst"},
+{"name": "candace werts"},
+{"name": "ginny semora"},
+{"name": "barry taylor"},
+{"name": "jim langenhan"},
+{"name": "wilson white"},
+{"name": "bernadette aganza"},
+{"name": "nancy trost"},
+{"name": "marc schmidt"},
+{"name": "autumn kay"},
+{"name": "erin porszt"},
+{"name": "daniel oscar"},
+{"name": "annie lippert"},
+{"name": "burt dubois"},
+{"name": "donna hamblin"},
+{"name": "amanda glorioso"},
+{"name": "martin muncy"},
+{"name": "paul hatchet"},
+{"name": "andrea alvis"},
+{"name": "courtney schuett"},
+{"name": "sarah howard"},
+{"name": "alicia lopez"},
+{"name": "pat r"},
+{"name": "michael cardinal"},
+{"name": "stacey laitman"},
+{"name": "annie macnee"},
+{"name": "angie ilg"},
+{"name": "jared daniels"},
+{"name": "jodi stein"},
+{"name": "albert friedrich"},
+{"name": "cathy couch"},
+{"name": "brad koons"},
+{"name": "steve verduyn"},
+{"name": "patrick severson"},
+{"name": "janice sorensen"},
+{"name": "loretta hepburn"},
+{"name": "mike zara"},
+{"name": "paul messer"},
+{"name": "ron cell"},
+{"name": "palmer md"},
+{"name": "jason pate"},
+{"name": "joe montiel"},
+{"name": "cara birmingham"},
+{"name": "lesley bailey"},
+{"name": "dan sullivan"},
+{"name": "nathan webb"},
+{"name": "michelle d"},
+{"name": "shae ehlers"},
+{"name": "sonya dunham"},
+{"name": "sarah chicago"},
+{"name": "ja ja"},
+{"name": "michelle davis"},
+{"name": "phil totman"},
+{"name": "sari grebinar"},
+{"name": "ray max"},
+{"name": "chuck kevwich"},
+{"name": "billy kuhnel"},
+{"name": "aja reign"},
+{"name": "jeff cowell"},
+{"name": "ted faust"},
+{"name": "paul harrison"},
+{"name": "nick chitwood"},
+{"name": "ana gutierrez"},
+{"name": "raymond hairston"},
+{"name": "kate mcnally"},
+{"name": "monica simmons"},
+{"name": "steve waycott"},
+{"name": "lee raback"},
+{"name": "myles webster"},
+{"name": "jeff simmons"},
+{"name": "cynthia dashnaw"},
+{"name": "christine gerschel"},
+{"name": "chris tompkins"},
+{"name": "jon roberts"},
+{"name": "lynn beggy"},
+{"name": "brandon trs"},
+{"name": "carlos marcellus"},
+{"name": "austin schultz"},
+{"name": "kristen johnson"},
+{"name": "jeff woolard"},
+{"name": "matt smalley"},
+{"name": "nikki brumback"},
+{"name": "nidia malone"},
+{"name": "stacey armstrong"},
+{"name": "kathy wagener"},
+{"name": "scott sterne"},
+{"name": "brian bos"},
+{"name": "alison paulson"},
+{"name": "jay luebbe"},
+{"name": "brian isaac"},
+{"name": "pat perry"},
+{"name": "leslie bravo"},
+{"name": "jerry o"},
+{"name": "trish merlo"},
+{"name": "leonard ridilla"},
+{"name": "barry petrowsky"},
+{"name": "john sampuer"},
+{"name": "larry edwards"},
+{"name": "jon lawson"},
+{"name": "amy moiser"},
+{"name": "linda goodwin"},
+{"name": "matt porter"},
+{"name": "dan leyson"},
+{"name": "nancy denning"},
+{"name": "jerry raby"},
+{"name": "michael lew"},
+{"name": "jeffrey birth"},
+{"name": "austin kiser"},
+{"name": "steve wallace"},
+{"name": "andrew cate"},
+{"name": "ryan carter"},
+{"name": "john jenkins"},
+{"name": "carrie corcoran"},
+{"name": "laura brown"},
+{"name": "brian wood"},
+{"name": "elizabeth adomaitis"},
+{"name": "eric love"},
+{"name": "bob buckley"},
+{"name": "katie groshong"},
+{"name": "michael stork"},
+{"name": "ana guajardo"},
+{"name": "travis fox"},
+{"name": "christian lecates"},
+{"name": "yvonne littlejohn"},
+{"name": "steve wigginton"},
+{"name": "greg busch"},
+{"name": "breana lixey"},
+{"name": "amy mononi"},
+{"name": "robin kurkhill"},
+{"name": "albert ng"},
+{"name": "brian stall"},
+{"name": "tessa conners"},
+{"name": "dennis hackett"},
+{"name": "anna steg"},
+{"name": "maureen joyce"},
+{"name": "patsy newman"},
+{"name": "ryan kim"},
+{"name": "john g's"},
+{"name": "rhonda miller"},
+{"name": "jamie sudbeck"},
+{"name": "rana chaudhuri"},
+{"name": "allen sparks"},
+{"name": "monica straus"},
+{"name": "manual review"},
+{"name": "trey lewis"},
+{"name": "nona shepperd"},
+{"name": "cynthia carlton"},
+{"name": "laura legrande"},
+{"name": "bob newlands"},
+{"name": "bill frezza"},
+{"name": "lee mitsumori"},
+{"name": "christopher bopp"},
+{"name": "jeff kreiter"},
+{"name": "valerie hab"},
+{"name": "ariel markus"},
+{"name": "dan drumer"},
+{"name": "robert pitelka"},
+{"name": "janet campos"},
+{"name": "kimberly young"},
+{"name": "henry palazzo"},
+{"name": "mike pappas"},
+{"name": "nikki w"},
+{"name": "danny foods"},
+{"name": "jane riley"},
+{"name": "sharon lockwood"},
+{"name": "kim hermann"},
+{"name": "rick sanford"},
+{"name": "kristy laird"},
+{"name": "kevin ambrosini"},
+{"name": "ryan neuharth"},
+{"name": "otto lee"},
+{"name": "ron wingert"},
+{"name": "jasmine green"},
+{"name": "jeremy shirley"},
+{"name": "archie rabinowitz"},
+{"name": "joe west"},
+{"name": "jeff courtney"},
+{"name": "george cooney"},
+{"name": "katy productions"},
+{"name": "teresa french"},
+{"name": "george stahlin"},
+{"name": "susanne meno"},
+{"name": "patricia geil"},
+{"name": "dan doerner"},
+{"name": "taylor c"},
+{"name": "dan bryant"},
+{"name": "greg toal"},
+{"name": "jimmie purkey"},
+{"name": "jorge wimbley"},
+{"name": "sonya haggerty"},
+{"name": "will aldridge"},
+{"name": "chuck tam"},
+{"name": "greg farmer"},
+{"name": "megan pickler"},
+{"name": "judy jarmulr"},
+{"name": "steve jenks"},
+{"name": "bill rayborn"},
+{"name": "brent smith"},
+{"name": "joanna gaylord"},
+{"name": "laura grimmer"},
+{"name": "rebecca whitehead"},
+{"name": "michael seiler"},
+{"name": "mike cheatwood"},
+{"name": "greg kraus"},
+{"name": "audrey bar"},
+{"name": "mark furman"},
+{"name": "danny berkovits"},
+{"name": "brent wallin"},
+{"name": "judy torres"},
+{"name": "avis haddad"},
+{"name": "frankie work"},
+{"name": "brent reed"},
+{"name": "dora lucas"},
+{"name": "sharon niestorm"},
+{"name": "beau pierce"},
+{"name": "lara naruszewicz"},
+{"name": "allyson whitlock"},
+{"name": "stan plocker"},
+{"name": "daniel lindsey"},
+{"name": "sean morris"},
+{"name": "tim martonick"},
+{"name": "david fujimoto"},
+{"name": "cherise comstock"},
+{"name": "tom olvera"},
+{"name": "noel diaz"},
+{"name": "tom shifflet"},
+{"name": "david gipner"},
+{"name": "michele v"},
+{"name": "mike kuelbs"},
+{"name": "carol lotz"},
+{"name": "jordan nicholson"},
+{"name": "rita eckard"},
+{"name": "jessica marta"},
+{"name": "chi town"},
+{"name": "morgan chayer"},
+{"name": "tuan nhuyen"},
+{"name": "tony gilder"},
+{"name": "steve strange"},
+{"name": "howard burd"},
+{"name": "jose cuzo"},
+{"name": "sarah hancharik"},
+{"name": "jen dainels"},
+{"name": "jarred shalom"},
+{"name": "matt sitz"},
+{"name": "bill mcloughlin"},
+{"name": "katie livermore"},
+{"name": "donna branston"},
+{"name": "adriane wodey"},
+{"name": "mark mccool"},
+{"name": "kathy maalouf"},
+{"name": "kevin tschudi"},
+{"name": "young hospital"},
+{"name": "mike jr"},
+{"name": "devin knight"},
+{"name": "mindi w"},
+{"name": "jerrie edwards"},
+{"name": "stephanie bowen"},
+{"name": "tori bauer"},
+{"name": "laureen dawson"},
+{"name": "neil desimone"},
+{"name": "stephen edwards"},
+{"name": "jeff tao"},
+{"name": "eileen thurow"},
+{"name": "anna carter"},
+{"name": "ginger wisniewski"},
+{"name": "carol eckstrom"},
+{"name": "john fitzpatrick"},
+{"name": "steve hope"},
+{"name": "rosie logistic"},
+{"name": "greg sterling"},
+{"name": "josie david"},
+{"name": "jo belair"},
+{"name": "jake olin"},
+{"name": "shelly metje"},
+{"name": "corey olsen"},
+{"name": "fred moss"},
+{"name": "craig littlejohn"},
+{"name": "richie newman"},
+{"name": "jon labes"},
+{"name": "flo master"},
+{"name": "wesley phongsa"},
+{"name": "dean ford"},
+{"name": "brian saliba"},
+{"name": "barb friedman"},
+{"name": "lou larres"},
+{"name": "sarah boek"},
+{"name": "kenny anderson"},
+{"name": "alex ebc"},
+{"name": "tim kupetz"},
+{"name": "evan bumgardner"},
+{"name": "joe moran"},
+{"name": "kurt radkee"},
+{"name": "long hcm"},
+{"name": "catherine stokes"},
+{"name": "may chazez"},
+{"name": "sean franklin"},
+{"name": "barb berlyak"},
+{"name": "diego vanegas"},
+{"name": "carolyn barnett"},
+{"name": "david zimmerman"},
+{"name": "penny buffington"},
+{"name": "mira rinne"},
+{"name": "lucas nwaobi"},
+{"name": "joshua katz"},
+{"name": "garret d'ottavio"},
+{"name": "trinidad chacara"},
+{"name": "ellen chayet"},
+{"name": "nicola lacetera"},
+{"name": "jack beem"},
+{"name": "terry ocheltree"},
+{"name": "matt stoderd"},
+{"name": "jessie woman"},
+{"name": "delbert singleton"},
+{"name": "jay rolfson"},
+{"name": "hollie crowley"},
+{"name": "mark softball"},
+{"name": "nancy gust"},
+{"name": "jennifer estaris"},
+{"name": "karina fajardo"},
+{"name": "chuck lane"},
+{"name": "michelle carney"},
+{"name": "charlotte ruggeri"},
+{"name": "joey dunagan"},
+{"name": "susan wyllie"},
+{"name": "nichole tolliver"},
+{"name": "rosa kirkland"},
+{"name": "steve gcs"},
+{"name": "hope mathews"},
+{"name": "stephen socolof"},
+{"name": "andrew lin"},
+{"name": "brandon dunn"},
+{"name": "ruby n"},
+{"name": "josh taylor"},
+{"name": "ann therapist"},
+{"name": "tim fortier"},
+{"name": "jay graham"},
+{"name": "chris az"},
+{"name": "eli burkman"},
+{"name": "brooks finlinson"},
+{"name": "marianne gaviola"},
+{"name": "teri kim"},
+{"name": "paul ibmtle"},
+{"name": "karen ganguet"},
+{"name": "justin simo"},
+{"name": "stephanie klev"},
+{"name": "everett sargent"},
+{"name": "jeremy bloom"},
+{"name": "matt booth"},
+{"name": "andrea emery"},
+{"name": "brenda rideout"},
+{"name": "christina glass"},
+{"name": "cindy caditz"},
+{"name": "cesar arapahoe"},
+{"name": "laura golay"},
+{"name": "ron underwood"},
+{"name": "teresa kitchens"},
+{"name": "robert leal"},
+{"name": "ed dilworth"},
+{"name": "jay olson"},
+{"name": "steve knese"},
+{"name": "charley ebersall"},
+{"name": "glen williams"},
+{"name": "pat zohab"},
+{"name": "jim tivo"},
+{"name": "valerie shea"},
+{"name": "phillip dothedamnthang"},
+{"name": "kurt walker"},
+{"name": "lisa benton"},
+{"name": "matt cambell"},
+{"name": "cathy gallagher"},
+{"name": "garrett wagner"},
+{"name": "dave albright"},
+{"name": "alyssa bull"},
+{"name": "susan ady"},
+{"name": "jenny v"},
+{"name": "john boron"},
+{"name": "carter hendren"},
+{"name": "bill strass"},
+{"name": "gayle hage"},
+{"name": "ed alachniewicz"},
+{"name": "jimmy blake"},
+{"name": "larry kelner"},
+{"name": "deanna fletcher"},
+{"name": "jeffrey wright"},
+{"name": "angel jones"},
+{"name": "karina mendez"},
+{"name": "ilse joubert"},
+{"name": "tony vinyl"},
+{"name": "chase hinrich"},
+{"name": "judy wk"},
+{"name": "jackson star"},
+{"name": "cheryl bloom"},
+{"name": "audrey king"},
+{"name": "albert lo"},
+{"name": "deandre young"},
+{"name": "ben finney"},
+{"name": "carole winberg"},
+{"name": "kelly freemyer"},
+{"name": "melissa rash"},
+{"name": "dave russell"},
+{"name": "brian newman"},
+{"name": "winston king"},
+{"name": "todd ames"},
+{"name": "syreeta cysj"},
+{"name": "eric laurits"},
+{"name": "clarisa cell"},
+{"name": "simon rendak"},
+{"name": "pa pa"},
+{"name": "julian cell"},
+{"name": "lois segree"},
+{"name": "fiona walker"},
+{"name": "tony gobo"},
+{"name": "shannon o'neal"},
+{"name": "kim wilkens"},
+{"name": "tommy garcia"},
+{"name": "lili benjumea"},
+{"name": "chris sumner"},
+{"name": "craig forist"},
+{"name": "karla powelson"},
+{"name": "eric bonini"},
+{"name": "victoria martinez"},
+{"name": "charles drummer"},
+{"name": "anthony parker"},
+{"name": "dianna locke"},
+{"name": "patsy ebert"},
+{"name": "robert mann"},
+{"name": "mark mcclure"},
+{"name": "kristy johnson"},
+{"name": "erik hazen"},
+{"name": "trent cokley"},
+{"name": "marcus guynn"},
+{"name": "vernon peters"},
+{"name": "guy rinderknecht"},
+{"name": "tammy madsen"},
+{"name": "michael iceburg"},
+{"name": "john ducket"},
+{"name": "danielle garcia"},
+{"name": "brian park"},
+{"name": "lucy figueras"},
+{"name": "lauren green"},
+{"name": "kendall downing"},
+{"name": "herman depriest"},
+{"name": "samuel waller"},
+{"name": "christa orndoff"},
+{"name": "tyler mutchler"},
+{"name": "randall ziman"},
+{"name": "yvette allen"},
+{"name": "frank wingfield"},
+{"name": "john fortunato"},
+{"name": "rob stagliano"},
+{"name": "melissa diekema"},
+{"name": "james vail"},
+{"name": "chris mohrman"},
+{"name": "joey morales"},
+{"name": "john cp"},
+{"name": "angel monguziji"},
+{"name": "jean hatfield"},
+{"name": "linda ruggiere"},
+{"name": "eric perez"},
+{"name": "lawrence medina"},
+{"name": "tom rock"},
+{"name": "sergio ramos"},
+{"name": "lee byrd"},
+{"name": "leanna morag"},
+{"name": "nathan cell"},
+{"name": "stephen kozub"},
+{"name": "gerri fields"},
+{"name": "ebony j"},
+{"name": "greg honegger"},
+{"name": "mary gresko"},
+{"name": "michael stewart"},
+{"name": "codi dapper"},
+{"name": "amy aspseter"},
+{"name": "adina verson"},
+{"name": "david heche"},
+{"name": "dorothy chimel"},
+{"name": "bob schneider"},
+{"name": "tim broder"},
+{"name": "tom chaney"},
+{"name": "joan canonigo"},
+{"name": "ron derose"},
+{"name": "harold bordwin"},
+{"name": "kristy crab"},
+{"name": "kathryn gutierrez"},
+{"name": "kelli hopper"},
+{"name": "dan riahani"},
+{"name": "kate brett"},
+{"name": "jason adams"},
+{"name": "steve walters"},
+{"name": "laura lamm"},
+{"name": "john gingery"},
+{"name": "bert culha"},
+{"name": "jake david"},
+{"name": "carrie home"},
+{"name": "brittany g"},
+{"name": "glen bandiera"},
+{"name": "andrea wilcox"},
+{"name": "janeen hoffos"},
+{"name": "riley courtright"},
+{"name": "chris mccormick"},
+{"name": "rich bands"},
+{"name": "kelly swiatek"},
+{"name": "marilyn berson"},
+{"name": "eva flanagan"},
+{"name": "linda woodfield"},
+{"name": "hilary sundance"},
+{"name": "gary nova"},
+{"name": "dina matz"},
+{"name": "jessica iacono"},
+{"name": "scott co"},
+{"name": "mike sabo"},
+{"name": "mary singh"},
+{"name": "teri hartley"},
+{"name": "johnny wright"},
+{"name": "brandie boden"},
+{"name": "alex adolfi"},
+{"name": "brandon underwood"},
+{"name": "lauren petersen"},
+{"name": "jack borg"},
+{"name": "hazel boyd"},
+{"name": "craig waltman"},
+{"name": "steve nowlis"},
+{"name": "jason bridges"},
+{"name": "chris cupler"},
+{"name": "daniel sastic"},
+{"name": "tony volpone"},
+{"name": "andy shelton"},
+{"name": "gloria zuniga"},
+{"name": "mike delaney"},
+{"name": "nancy allen"},
+{"name": "jeane helms"},
+{"name": "casey mcginley"},
+{"name": "steven house"},
+{"name": "matthew m"},
+{"name": "stephanie anzures"},
+{"name": "vicente niece"},
+{"name": "jeff thelen"},
+{"name": "chris wheeler"},
+{"name": "ericka flowers"},
+{"name": "eddie stew"},
+{"name": "carol jean"},
+{"name": "christopher chen"},
+{"name": "simon lawler"},
+{"name": "jon smp"},
+{"name": "jerome cohen"},
+{"name": "reyes c"},
+{"name": "cindy hause"},
+{"name": "grant cunningham"},
+{"name": "david bressoud"},
+{"name": "patrick mccloskey"},
+{"name": "jay hickey"},
+{"name": "grace academy"},
+{"name": "michael gwilliam"},
+{"name": "alex j"},
+{"name": "matt mcauley"},
+{"name": "betsy cuthbertson"},
+{"name": "mary kelly"},
+{"name": "sasha cocron"},
+{"name": "christina sawwrii"},
+{"name": "dave burk"},
+{"name": "stanley morais"},
+{"name": "brady kent"},
+{"name": "mike kazakevitch"},
+{"name": "andrea andersen"},
+{"name": "jessica maranon"},
+{"name": "michael robl"},
+{"name": "peg andrew"},
+{"name": "angie stephen"},
+{"name": "chris vandenover"},
+{"name": "shirley weber"},
+{"name": "robin gomez"},
+{"name": "sarah ryan"},
+{"name": "andy koch"},
+{"name": "ben ballhorn"},
+{"name": "kevin glalway"},
+{"name": "kathie shaw"},
+{"name": "dana h"},
+{"name": "al caesar"},
+{"name": "judy wells"},
+{"name": "annie boswell"},
+{"name": "rich fernie"},
+{"name": "marcus french"},
+{"name": "kelly c"},
+{"name": "jeanne balmes"},
+{"name": "alice ny"},
+{"name": "darlene wright"},
+{"name": "ellie anderson"},
+{"name": "marty white"},
+{"name": "wayne henderson"},
+{"name": "don fritsch"},
+{"name": "james thue"},
+{"name": "ingrid harrison"},
+{"name": "lou malinatti's"},
+{"name": "nicky water"},
+{"name": "melanie burchard"},
+{"name": "sandy souderlund"},
+{"name": "sunshine davenport"},
+{"name": "dan keiser"},
+{"name": "rachel sear"},
+{"name": "wm payroll"},
+{"name": "kelvin frances"},
+{"name": "christine sunglass"},
+{"name": "pete aldassy"},
+{"name": "emily quinn"},
+{"name": "jeremy wing"},
+{"name": "sydney liptak"},
+{"name": "benjamin sheffner"},
+{"name": "kelly fogurty"},
+{"name": "kay hartman"},
+{"name": "tara hibbler"},
+{"name": "paul rehac"},
+{"name": "john bailey"},
+{"name": "kimberly klinke"},
+{"name": "alexis truax"},
+{"name": "lacey bray"},
+{"name": "karen horzen"},
+{"name": "scott nicholls"},
+{"name": "dave hayhurst"},
+{"name": "mike york"},
+{"name": "sarah phillips"},
+{"name": "kevin cederberg"},
+{"name": "greg orwoll"},
+{"name": "rick dickson"},
+{"name": "andrew drebit"},
+{"name": "forrest keeler"},
+{"name": "gregg martinez"},
+{"name": "jessica schnell"},
+{"name": "scotty barton"},
+{"name": "ann axtell"},
+{"name": "marilu magana"},
+{"name": "patti dean"},
+{"name": "john massaro"},
+{"name": "keith hupp"},
+{"name": "jorge diaz"},
+{"name": "holly firehouse"},
+{"name": "ricardo thomas"},
+{"name": "domenic pannaccio"},
+{"name": "michael hussain"},
+{"name": "william gutz"},
+{"name": "lee delmore"},
+{"name": "shanna habich"},
+{"name": "mark schneider"},
+{"name": "mike john"},
+{"name": "josh borstein"},
+{"name": "dean heubregste"},
+{"name": "brian pitson"},
+{"name": "sara broome"},
+{"name": "stefan buetow"},
+{"name": "shelby dad"},
+{"name": "rosalind holland"},
+{"name": "wade willis"},
+{"name": "deann takkinen"},
+{"name": "scott grif"},
+{"name": "brian kocher"},
+{"name": "mike tufts"},
+{"name": "mike rouch"},
+{"name": "martin wilson"},
+{"name": "robert alonzo"},
+{"name": "ken stellon"},
+{"name": "jerry jacobson"},
+{"name": "david defino"},
+{"name": "leila brauner"},
+{"name": "deborah sleeman"},
+{"name": "marlene theissen"},
+{"name": "guy chadrash"},
+{"name": "morgan payne"},
+{"name": "lee renzin"},
+{"name": "michael griffin"},
+{"name": "dan calgary"},
+{"name": "josh card"},
+{"name": "lindsay scottoline"},
+{"name": "adrienne erlick"},
+{"name": "jacob borton"},
+{"name": "dennis dumadag"},
+{"name": "mathew mekhayel"},
+{"name": "kristina mcdermott"},
+{"name": "alexander dunlap"},
+{"name": "connie kim"},
+{"name": "denise short"},
+{"name": "brian ct"},
+{"name": "al kay"},
+{"name": "george d'elia"},
+{"name": "earl morrison"},
+{"name": "dan heronemus"},
+{"name": "mark pelson"},
+{"name": "terrie thomas"},
+{"name": "jim minton"},
+{"name": "margot mcleod"},
+{"name": "tim krause"},
+{"name": "joe smith"},
+{"name": "cornelia cont"},
+{"name": "cathrine baker"},
+{"name": "bruce alexander"},
+{"name": "jackie stephens"},
+{"name": "john behlmann"},
+{"name": "josh salazar"},
+{"name": "joe bernhadt"},
+{"name": "kaitlyn nielson"},
+{"name": "amanda konc"},
+{"name": "tracy steiberger"},
+{"name": "cliff talley"},
+{"name": "chris roth"},
+{"name": "cary jan"},
+{"name": "josh brickford"},
+{"name": "dave gartner"},
+{"name": "kate work"},
+{"name": "lori dalton"},
+{"name": "christiane heyde"},
+{"name": "neil richey"},
+{"name": "mike kellman"},
+{"name": "tim bledsoe"},
+{"name": "cris hineline"},
+{"name": "fred rico"},
+{"name": "sara perez"},
+{"name": "max carlson"},
+{"name": "eric hendrickson"},
+{"name": "myra holmes"},
+{"name": "steve darnold"},
+{"name": "willie simmons"},
+{"name": "peter avellone"},
+{"name": "cathy white"},
+{"name": "sara edwards"},
+{"name": "christina phan"},
+{"name": "dustin grantham"},
+{"name": "luis garcia"},
+{"name": "carol richards"},
+{"name": "mark salisbery"},
+{"name": "alan napack"},
+{"name": "bob macnelly"},
+{"name": "steve sakoman"},
+{"name": "ronald walker"},
+{"name": "les busfield"},
+{"name": "eric ayten"},
+{"name": "ashley f"},
+{"name": "patrick pradia"},
+{"name": "mike braun"},
+{"name": "john tomaszewski"},
+{"name": "joseph cell"},
+{"name": "carrie lazorchak"},
+{"name": "jim tatum"},
+{"name": "phil black"},
+{"name": "nikki sifri"},
+{"name": "bo porter"},
+{"name": "steven meskin"},
+{"name": "mike mcguiness"},
+{"name": "rachel t"},
+{"name": "michelle derda"},
+{"name": "jane edmondson"},
+{"name": "meg evat"},
+{"name": "kate davelaar"},
+{"name": "travis arnold"},
+{"name": "michelle tillery"},
+{"name": "lucy giannelli"},
+{"name": "james trummer"},
+{"name": "jon quinn"},
+{"name": "joyce oliver"},
+{"name": "david evans"},
+{"name": "stephen novack"},
+{"name": "phillip eichner"},
+{"name": "dennis istre"},
+{"name": "dottie smith"},
+{"name": "derek zaba"},
+{"name": "hung home"},
+{"name": "mitch boyer"},
+{"name": "wayne lacourse"},
+{"name": "ann murray"},
+{"name": "al stevens"},
+{"name": "amanda ghourdjian"},
+{"name": "michael hardin"},
+{"name": "brandy maddox"},
+{"name": "austin roskamp"},
+{"name": "janeen segar"},
+{"name": "mechelle miller"},
+{"name": "jim weathers"},
+{"name": "lauren t"},
+{"name": "murray norris"},
+{"name": "sam gabbita"},
+{"name": "laura hevesi"},
+{"name": "michelle v"},
+{"name": "rob shaddock"},
+{"name": "pam johnston"},
+{"name": "mike tom"},
+{"name": "dan l"},
+{"name": "mike blanford"},
+{"name": "tom g"},
+{"name": "dean hill"},
+{"name": "david nevin"},
+{"name": "morgan seachris"},
+{"name": "forrest moye"},
+{"name": "kristin durant"},
+{"name": "audrey henderson"},
+{"name": "darrin homer"},
+{"name": "steven feys"},
+{"name": "courtney welsch"},
+{"name": "jean arseneau"},
+{"name": "howard lando"},
+{"name": "dale kline"},
+{"name": "luis southdade"},
+{"name": "melissa frank"},
+{"name": "robert collins"},
+{"name": "franklin moore"},
+{"name": "robert reinders"},
+{"name": "toni smith"},
+{"name": "phillip t"},
+{"name": "gail barker"},
+{"name": "eric gillespie"},
+{"name": "jesus figueroa"},
+{"name": "kimberly chiem"},
+{"name": "liz barsom"},
+{"name": "john colwell"},
+{"name": "craig king"},
+{"name": "martin ferguson"},
+{"name": "larry schmit"},
+{"name": "nicole pimentel"},
+{"name": "sharon marsh"},
+{"name": "greg finley"},
+{"name": "sandra gonzales"},
+{"name": "lee selmon"},
+{"name": "maria ezechukwu"},
+{"name": "timmy falke"},
+{"name": "bridget penrod"},
+{"name": "bob arnold"},
+{"name": "mary ockender"},
+{"name": "michelle helmer"},
+{"name": "amber c"},
+{"name": "tim dolan"},
+{"name": "robert cronholm"},
+{"name": "judy haack"},
+{"name": "richard yoo"},
+{"name": "mark venuti"},
+{"name": "brittney n"},
+{"name": "dianne rutledge"},
+{"name": "jeffrey fuller"},
+{"name": "jill baker"},
+{"name": "louis athanaselos"},
+{"name": "ken ball"},
+{"name": "john bresnahan"},
+{"name": "willie work"},
+{"name": "brad shreve"},
+{"name": "denise laguna"},
+{"name": "kathy vanveckoven"},
+{"name": "jo clean"},
+{"name": "stan owner"},
+{"name": "brian pounds"},
+{"name": "david yacoub"},
+{"name": "rob ellis"},
+{"name": "shawn herrick"},
+{"name": "michelle oh"},
+{"name": "steve yoo"},
+{"name": "ron skoglund"},
+{"name": "daniela bazo"},
+{"name": "mark irish"},
+{"name": "dana tattoos"},
+{"name": "mike palm"},
+{"name": "katherine skylar"},
+{"name": "brooks jill"},
+{"name": "michelle n"},
+{"name": "jo casper"},
+{"name": "wesley lewis"},
+{"name": "chloe boissonnault"},
+{"name": "wilson taylor"},
+{"name": "christina sirotta"},
+{"name": "oliver chris"},
+{"name": "jack milunsky"},
+{"name": "mark kornak"},
+{"name": "sarah radke"},
+{"name": "mike haley"},
+{"name": "daryl leazier"},
+{"name": "debra scott"},
+{"name": "benjamin lee"},
+{"name": "julie boucutt"},
+{"name": "larry harris"},
+{"name": "bonnie quarles"},
+{"name": "sylvester spa"},
+{"name": "brent hawes"},
+{"name": "kasey garthwaite"},
+{"name": "matt hubers"},
+{"name": "dick porto"},
+{"name": "leon zelechowski"},
+{"name": "ava bar"},
+{"name": "chris goff"},
+{"name": "coleman powersport"},
+{"name": "phil swift"},
+{"name": "melanie salas"},
+{"name": "wayne mangrum"},
+{"name": "shelby hboy"},
+{"name": "antonio hesano"},
+{"name": "drew milam"},
+{"name": "mi mama"},
+{"name": "matthew li"},
+{"name": "ariel weissberg"},
+{"name": "matt bloom"},
+{"name": "barbie calva"},
+{"name": "chuck esguerra"},
+{"name": "beverly bond"},
+{"name": "dominque nsba"},
+{"name": "erin wolken"},
+{"name": "graham kyle"},
+{"name": "bill yoon"},
+{"name": "larry cell"},
+{"name": "mark webb"},
+{"name": "linda randolph"},
+{"name": "nick weast"},
+{"name": "dwight aaron"},
+{"name": "dolores furtado"},
+{"name": "matthew day"},
+{"name": "felicia sigler"},
+{"name": "michelle moser"},
+{"name": "jann sheehy"},
+{"name": "dean atkinson"},
+{"name": "linda zidek"},
+{"name": "yolanda ramsey"},
+{"name": "sarah strout"},
+{"name": "diane walewski"},
+{"name": "linda joseph"},
+{"name": "reggie hyde"},
+{"name": "mike nicholas"},
+{"name": "edmund lara"},
+{"name": "angela swain"},
+{"name": "gabriella leonarid"},
+{"name": "aaron pope"},
+{"name": "jasmine serrano"},
+{"name": "larry santos"},
+{"name": "bonnie miller"},
+{"name": "alex ayers"},
+{"name": "brett ottawa"},
+{"name": "michael rocca"},
+{"name": "kyle harrison"},
+{"name": "king engel"},
+{"name": "art reed"},
+{"name": "karl schmidt"},
+{"name": "david farrar"},
+{"name": "tony north"},
+{"name": "jim melia"},
+{"name": "lance bryant"},
+{"name": "mark mocilan"},
+{"name": "ron buckhammer"},
+{"name": "chris airgas"},
+{"name": "george klotz"},
+{"name": "mary cs"},
+{"name": "tim collins"},
+{"name": "van quathem"},
+{"name": "derek worden"},
+{"name": "katie metzger"},
+{"name": "dan keen"},
+{"name": "henry hopkins"},
+{"name": "derrick garder"},
+{"name": "alberto rhenals"},
+{"name": "jason doren"},
+{"name": "tim crochet"},
+{"name": "allen kaye"},
+{"name": "william kovalchuk"},
+{"name": "shaun devine"},
+{"name": "bobbi west"},
+{"name": "omar cambo"},
+{"name": "brad seward"},
+{"name": "jeff mann"},
+{"name": "wendy dean"},
+{"name": "arlene siver"},
+{"name": "randall hutchings"},
+{"name": "kris aoki"},
+{"name": "joan streefkerk"},
+{"name": "jeffrey buckley"},
+{"name": "ana elizondo"},
+{"name": "bill carter"},
+{"name": "denice scott"},
+{"name": "debbie cregger"},
+{"name": "kristin troy"},
+{"name": "charles eric"},
+{"name": "charles vacarella"},
+{"name": "todd niemeyer"},
+{"name": "paul beyl"},
+{"name": "billy kirkby"},
+{"name": "josh hillary"},
+{"name": "luke pridgeon"},
+{"name": "colin cowboy"},
+{"name": "sharon hakimifefat"},
+{"name": "janey teacups"},
+{"name": "todd mack"},
+{"name": "deidra solomon"},
+{"name": "jerome harrington"},
+{"name": "james kushnerick"},
+{"name": "vera davis"},
+{"name": "ed babbie"},
+{"name": "tommy vose"},
+{"name": "rosa mcaurther"},
+{"name": "tom seiler"},
+{"name": "monty schilling"},
+{"name": "sara hutchinson"},
+{"name": "troy gilmore"},
+{"name": "bob urosevic"},
+{"name": "scott valois"},
+{"name": "eric vasqauls"},
+{"name": "mike tancsa"},
+{"name": "trista milanovich"},
+{"name": "barrett somdahl"},
+{"name": "christine guerra"},
+{"name": "rick deckbar"},
+{"name": "alan rothman"},
+{"name": "jennifer tanner"},
+{"name": "kelly knox"},
+{"name": "john brune"},
+{"name": "josh culumber"},
+{"name": "nathan garrison"},
+{"name": "karen sachs"},
+{"name": "paula ransom"},
+{"name": "andy stavro"},
+{"name": "andrew larrier"},
+{"name": "danielle burke"},
+{"name": "chris prock"},
+{"name": "gail mikel"},
+{"name": "samira panah"},
+{"name": "charlotte bobcats"},
+{"name": "david edwards"},
+{"name": "jim passey"},
+{"name": "terry magnunsun"},
+{"name": "tia rachel"},
+{"name": "kyle mclain"},
+{"name": "vince party"},
+{"name": "daryl redar"},
+{"name": "martha bodine"},
+{"name": "steven bellus"},
+{"name": "peter langbord"},
+{"name": "rebecca higgins"},
+{"name": "chris oboe"},
+{"name": "sara fletcher"},
+{"name": "michele goyette"},
+{"name": "brandon cracraft"},
+{"name": "denise bray"},
+{"name": "phillip petite"},
+{"name": "lynn kanakry"},
+{"name": "tom donovan"},
+{"name": "angela meadows"},
+{"name": "fred myrick"},
+{"name": "david moir"},
+{"name": "eric dremel"},
+{"name": "eric johanson"},
+{"name": "shawn austin"},
+{"name": "nick bilby"},
+{"name": "chris martinez"},
+{"name": "kathy south"},
+{"name": "rodney lui"},
+{"name": "donna leclerc"},
+{"name": "chris tandy"},
+{"name": "teri epper"},
+{"name": "bennett caren"},
+{"name": "keith montgomery"},
+{"name": "luis alba"},
+{"name": "marc jasso"},
+{"name": "timothy chi"},
+{"name": "jessie richard"},
+{"name": "austin walker"},
+{"name": "lori grudzien"},
+{"name": "sarah gruetze"},
+{"name": "floyd adams"},
+{"name": "dustin cell"},
+{"name": "john cappelletty"},
+{"name": "jeffrey star"},
+{"name": "leigh grossman"},
+{"name": "victor biscochito"},
+{"name": "jessica vanhord"},
+{"name": "melanie hastings"},
+{"name": "philip crown"},
+{"name": "matt warner"},
+{"name": "isaias guadarrama"},
+{"name": "dora borjas"},
+{"name": "kevin doud"},
+{"name": "jerry blueford"},
+{"name": "bobby buchalski"},
+{"name": "rob work"},
+{"name": "brittany hahn"},
+{"name": "genie soft"},
+{"name": "kyle elite"},
+{"name": "nick forde"},
+{"name": "joey callahan"},
+{"name": "melody metcalf"},
+{"name": "jon chang"},
+{"name": "justin taylor"},
+{"name": "eric cantele"},
+{"name": "susan lage"},
+{"name": "byron thompson"},
+{"name": "blake weirdo"},
+{"name": "dave mate"},
+{"name": "carl loodberg"},
+{"name": "lauren dillion"},
+{"name": "susan masten"},
+{"name": "ryan perkins"},
+{"name": "adam bowe"},
+{"name": "jim meetup"},
+{"name": "pauline hensley"},
+{"name": "peter swiderski"},
+{"name": "sammy lautenschlager"},
+{"name": "levi koch"},
+{"name": "nancy lopez"},
+{"name": "betsy hills"},
+{"name": "sara twin"},
+{"name": "matt hann"},
+{"name": "dave gonzalez"},
+{"name": "matt woodman"},
+{"name": "corey thomas"},
+{"name": "george munguia"},
+{"name": "bonnie yiu"},
+{"name": "terrance daye"},
+{"name": "christine nabisco"},
+{"name": "kelly decou"},
+{"name": "chad bongiovanni"},
+{"name": "jackie kelly"},
+{"name": "tara werger"},
+{"name": "tim youngard"},
+{"name": "barbara tuset"},
+{"name": "hal stephens"},
+{"name": "art zamora"},
+{"name": "todd welygan"},
+{"name": "kristen egan"},
+{"name": "eric albright"},
+{"name": "lois miskin"},
+{"name": "mike belt"},
+{"name": "evan rogers"},
+{"name": "brad letourneau"},
+{"name": "jay bojan"},
+{"name": "erin martin"},
+{"name": "thomas stephens"},
+{"name": "rob clegg"},
+{"name": "debbie ho"},
+{"name": "jennifer dalton"},
+{"name": "john doe"},
+{"name": "ray fung"},
+{"name": "phillip ybarrolaza"},
+{"name": "peter wriede"},
+{"name": "dave greer"},
+{"name": "robin cell"},
+{"name": "mike hoak"},
+{"name": "cheryl brackett"},
+{"name": "pat xxxx"},
+{"name": "matt connors"},
+{"name": "samuel tyszler"},
+{"name": "brad stepst"},
+{"name": "drew edmunds"},
+{"name": "linda beckham"},
+{"name": "pam neeley"},
+{"name": "courtney pittler"},
+{"name": "rafael valdez"},
+{"name": "kayla schober"},
+{"name": "carrie gottschalk"},
+{"name": "danny hockenberger"},
+{"name": "kara mendoza"},
+{"name": "rob scruftattmuscc"},
+{"name": "harold calkins"},
+{"name": "jeff ahern"},
+{"name": "jennifer killian"},
+{"name": "sean luna"},
+{"name": "sally yesian"},
+{"name": "ashley binkley"},
+{"name": "margaret mcgarry"},
+{"name": "diane williams"},
+{"name": "amanda jones"},
+{"name": "angie leatherwood"},
+{"name": "richard west"},
+{"name": "alex wardencki"},
+{"name": "lou kraemer"},
+{"name": "tom clarke"},
+{"name": "mauricio jimenez"},
+{"name": "sean mcnally"},
+{"name": "lauren h"},
+{"name": "joe directtv"},
+{"name": "stephanie renolds"},
+{"name": "tim maritzis"},
+{"name": "bob doherty"},
+{"name": "tori white"},
+{"name": "gene social"},
+{"name": "tim arnold"},
+{"name": "luke martin"},
+{"name": "james gildon"},
+{"name": "joe kesting"},
+{"name": "john two"},
+{"name": "yasmin rivera"},
+{"name": "joel klepal"},
+{"name": "joanne baker"},
+{"name": "javier abrego"},
+{"name": "liz buckley"},
+{"name": "courtney kinne"},
+{"name": "daniella mcchesney"},
+{"name": "delilah m"},
+{"name": "myrtle beach"},
+{"name": "scott hibner"},
+{"name": "betty chiu"},
+{"name": "jose cop"},
+{"name": "arnold wirick"},
+{"name": "tony battaglia"},
+{"name": "barbara lagazzele"},
+{"name": "patrick barry"},
+{"name": "kevin corio"},
+{"name": "terri desilva"},
+{"name": "rick modem"},
+{"name": "jason huso"},
+{"name": "charles cameron"},
+{"name": "jeff k"},
+{"name": "stacey baptista"},
+{"name": "ashley pfeifer"},
+{"name": "mary garcia"},
+{"name": "sam kasn"},
+{"name": "joe nava"},
+{"name": "andrew housley"},
+{"name": "mark zamuner"},
+{"name": "carol defrance"},
+{"name": "karen campbell"},
+{"name": "michelle arrant"},
+{"name": "donald fast"},
+{"name": "paul torres"},
+{"name": "jared green"},
+{"name": "hunter lots"},
+{"name": "todd rogers"},
+{"name": "dylan ireland"},
+{"name": "kerri brown"},
+{"name": "david kates"},
+{"name": "kim oden"},
+{"name": "stephanie wrk"},
+{"name": "armando flores"},
+{"name": "wallace cartwright"},
+{"name": "sarah may"},
+{"name": "frankie delgado"},
+{"name": "scotty gates"},
+{"name": "lewis macey"},
+{"name": "matthew rosenbaum"},
+{"name": "jeff dale"},
+{"name": "callie driggers"},
+{"name": "cortney hamiltom"},
+{"name": "steve hovdesven"},
+{"name": "josh mercier"},
+{"name": "jason pelletier"},
+{"name": "judy buffington"},
+{"name": "oscar mccloughan"},
+{"name": "jeremy mcewen"},
+{"name": "dennis valentino"},
+{"name": "norma devaul"},
+{"name": "kerry orr"},
+{"name": "cole paper"},
+{"name": "john chen"},
+{"name": "george joseph"},
+{"name": "mallie brewer"},
+{"name": "kevin choi"},
+{"name": "ken pope"},
+{"name": "patti teween"},
+{"name": "janet campbell"},
+{"name": "rae willis"},
+{"name": "tim goulart"},
+{"name": "ethel weir"},
+{"name": "katie s"},
+{"name": "chris leee"},
+{"name": "randy shacklford"},
+{"name": "thanh quy"},
+{"name": "patrick kester"},
+{"name": "chris kendrick"},
+{"name": "mike gregor"},
+{"name": "nicole manske"},
+{"name": "kate coulson"},
+{"name": "jay jensen"},
+{"name": "louisa porter"},
+{"name": "carolyn moore"},
+{"name": "scott bigham"},
+{"name": "tim cowan"},
+{"name": "nick pant"},
+{"name": "chelsey zinter"},
+{"name": "mike fink"},
+{"name": "steve craigslist"},
+{"name": "mitch fein"},
+{"name": "anne marlow"},
+{"name": "steve brandl"},
+{"name": "erin brophy"},
+{"name": "lowell lyon"},
+{"name": "bill hooper"},
+{"name": "christy clausen"},
+{"name": "regina lesesne"},
+{"name": "jimmy moses"},
+{"name": "rob chua"},
+{"name": "josh barclay"},
+{"name": "brian barit"},
+{"name": "steve barton"},
+{"name": "austin cooper"},
+{"name": "jesse abellar"},
+{"name": "lawerence tronet"},
+{"name": "sheryl busler"},
+{"name": "traci bruce"},
+{"name": "brent lockhart"},
+{"name": "mark morningstar"},
+{"name": "lauri s"},
+{"name": "andrea small"},
+{"name": "kathy cho"},
+{"name": "lee meetup"},
+{"name": "taylor mcadams"},
+{"name": "holly lawson"},
+{"name": "bruce hill"},
+{"name": "bob kreselmeir"},
+{"name": "cathy moffat"},
+{"name": "joyce lambton"},
+{"name": "greg schuh"},
+{"name": "stephen smith"},
+{"name": "kari brown"},
+{"name": "kathy crick"},
+{"name": "carolyn miller"},
+{"name": "lawrence forman"},
+{"name": "kelly lamb"},
+{"name": "mark flanagans"},
+{"name": "rhonda obradovich"},
+{"name": "barbara milmine"},
+{"name": "bruce simpson"},
+{"name": "larry piparo"},
+{"name": "jon fong"},
+{"name": "pablo manavello"},
+{"name": "josh glickman"},
+{"name": "charles chase"},
+{"name": "ed cho"},
+{"name": "doug grote"},
+{"name": "danielle strader"},
+{"name": "kelsey french"},
+{"name": "amy rodenkirk"},
+{"name": "andrew scott"},
+{"name": "mitchell goldstein"},
+{"name": "steve ebert"},
+{"name": "pamela reedstrom"},
+{"name": "misty orman"},
+{"name": "john henry"},
+{"name": "andrea libassi"},
+{"name": "dan hwang"},
+{"name": "maribel martins"},
+{"name": "stuart nelson"},
+{"name": "bill taylor"},
+{"name": "rebecca mcelroy"},
+{"name": "terry fielding"},
+{"name": "tanya reno"},
+{"name": "ed woznicki"},
+{"name": "ben falter"},
+{"name": "wade opsal"},
+{"name": "pam wood"},
+{"name": "craig deming"},
+{"name": "alicia south"},
+{"name": "daniel nicomedes"},
+{"name": "george davish"},
+{"name": "gene chiaro"},
+{"name": "jeff gauthier"},
+{"name": "gerald riley"},
+{"name": "tori stahl"},
+{"name": "cheryl toffel"},
+{"name": "trevor gosserand"},
+{"name": "mathew mathew"},
+{"name": "rob petrone"},
+{"name": "frank byrd"},
+{"name": "bryan may"},
+{"name": "harry herbert"},
+{"name": "alex mckenzie"},
+{"name": "debbie ahearn"},
+{"name": "alex d"},
+{"name": "joe matthews"},
+{"name": "brian dalton"},
+{"name": "colin cell"},
+{"name": "tara mcbennett"},
+{"name": "julie orbank"},
+{"name": "teresa ruelas"},
+{"name": "tim laren"},
+{"name": "stacey durbin"},
+{"name": "alex atchison"},
+{"name": "tom ryan"},
+{"name": "debbie ishikawa"},
+{"name": "mike agar"},
+{"name": "john shagoury"},
+{"name": "brittany trill"},
+{"name": "jon chase"},
+{"name": "lisa tom"},
+{"name": "melissa work"},
+{"name": "ben hodges"},
+{"name": "glen liddell"},
+{"name": "beverly volpe"},
+{"name": "lazaro kaz"},
+{"name": "tim engel"},
+{"name": "trevor jensen"},
+{"name": "doug talalla"},
+{"name": "mike boehner"},
+{"name": "mike wert"},
+{"name": "kevin petersen"},
+{"name": "greg ewing"},
+{"name": "joe furtado"},
+{"name": "linda bontrager"},
+{"name": "bob gallion"},
+{"name": "andrew allin"},
+{"name": "kyle tke"},
+{"name": "doug hylton"},
+{"name": "randy vest"},
+{"name": "connie bartolomeo"},
+{"name": "jordan umstatt"},
+{"name": "jessica berson"},
+{"name": "tim jolly"},
+{"name": "nick rosso"},
+{"name": "daniel hudak"},
+{"name": "ronda prioleau"},
+{"name": "jason rindler"},
+{"name": "vicki keohohou"},
+{"name": "jordan gonzales"},
+{"name": "michael christinziano"},
+{"name": "john mckotch"},
+{"name": "preston shea"},
+{"name": "gregory sachs"},
+{"name": "brian schreiner"},
+{"name": "jody sadler"},
+{"name": "holly nicholas"},
+{"name": "cathy reeves"},
+{"name": "tim raspin"},
+{"name": "amanda cross"},
+{"name": "caleb freeman"},
+{"name": "pat bathke"},
+{"name": "bob butka"},
+{"name": "curt schumacher"},
+{"name": "bill burnham"},
+{"name": "kevin best"},
+{"name": "chris snyder"},
+{"name": "jamie gast"},
+{"name": "karine hhc"},
+{"name": "mark nejame"},
+{"name": "stan carver"},
+{"name": "stephane k"},
+{"name": "rick hunt"},
+{"name": "rob painter"},
+{"name": "elaine snowden"},
+{"name": "tony lam"},
+{"name": "william byrd"},
+{"name": "pam robinson"},
+{"name": "eddie trice"},
+{"name": "steve geer"},
+{"name": "tony cruell"},
+{"name": "jack lambert"},
+{"name": "thomas bell"},
+{"name": "joey frailey"},
+{"name": "greg elton"},
+{"name": "suzanne hayes"},
+{"name": "angela merkle"},
+{"name": "derek rollins"},
+{"name": "eddie franco"},
+{"name": "ian waite"},
+{"name": "palmira jimenez"},
+{"name": "frank mizner"},
+{"name": "keith taylor"},
+{"name": "marguerite parker"},
+{"name": "sean malone"},
+{"name": "nick saccoe"},
+{"name": "bill millard"},
+{"name": "lee a"},
+{"name": "john stoehr"},
+{"name": "luis soto"},
+{"name": "zoe fine"},
+{"name": "jason felton"},
+{"name": "james lux"},
+{"name": "dawn mccarter"},
+{"name": "jay shade"},
+{"name": "dee daytona"},
+{"name": "doug schneider"},
+{"name": "carolina cues"},
+{"name": "kelly ho"},
+{"name": "valerie gibby"},
+{"name": "hayley brit"},
+{"name": "julie shafer"},
+{"name": "saul panduro"},
+{"name": "lori lawlor"},
+{"name": "jamie ocampo"},
+{"name": "winston chow"},
+{"name": "anne malloy"},
+{"name": "marie savel"},
+{"name": "paola alvarez"},
+{"name": "robert swor"},
+{"name": "thomas mcalea"},
+{"name": "john fiacco"},
+{"name": "jim rowland"},
+{"name": "sam singh"},
+{"name": "jess crawford"},
+{"name": "al loring"},
+{"name": "tony raley"},
+{"name": "paola guadarrama"},
+{"name": "dick skeers"},
+{"name": "chantelle adams"},
+{"name": "keith stark"},
+{"name": "carol simenson"},
+{"name": "david yau"},
+{"name": "sherry stewart"},
+{"name": "judy grubman"},
+{"name": "anita garza"},
+{"name": "barry mcdonald"},
+{"name": "sherilyn pang"},
+{"name": "katie trulson"},
+{"name": "jon turner"},
+{"name": "scott obel"},
+{"name": "larry swanson"},
+{"name": "kim sutton"},
+{"name": "loan specialist"},
+{"name": "peggy maytum"},
+{"name": "juan hernandez"},
+{"name": "george hk"},
+{"name": "lisa aguilar"},
+{"name": "cheryl tsang"},
+{"name": "brandy young"},
+{"name": "doug inman"},
+{"name": "paul ferradas"},
+{"name": "joey battaglia"},
+{"name": "luann lyons"},
+{"name": "angie bauer"},
+{"name": "viviana arboleda"},
+{"name": "tony nyguen"},
+{"name": "jamie mefford"},
+{"name": "kara email"},
+{"name": "jodie smith"},
+{"name": "mark gowetski"},
+{"name": "maria tsangaridou"},
+{"name": "nicole scott"},
+{"name": "gonzalo maravilla"},
+{"name": "lilian araujo"},
+{"name": "larry sullivan"},
+{"name": "stephen weinman"},
+{"name": "david ho"},
+{"name": "jeannette vestal"},
+{"name": "ann morgan"},
+{"name": "robert zimmer"},
+{"name": "alyssa toner"},
+{"name": "sandra phillips"},
+{"name": "keith zeitz"},
+{"name": "debbie n"},
+{"name": "simon kok"},
+{"name": "stacey crazy"},
+{"name": "lacey darnold"},
+{"name": "sue collins"},
+{"name": "david babakaiff"},
+{"name": "mike buff"},
+{"name": "jill wis"},
+{"name": "charles khuc"},
+{"name": "darrick king"},
+{"name": "tom mcnelis"},
+{"name": "ellen patt"},
+{"name": "lana seegan"},
+{"name": "ed fletcher"},
+{"name": "tom moran"},
+{"name": "brian allen"},
+{"name": "jim pool"},
+{"name": "bob tietz"},
+{"name": "joe plaksen"},
+{"name": "adam sprint"},
+{"name": "doug berl"},
+{"name": "ryan fyffe"},
+{"name": "tony lamantia"},
+{"name": "leigh cell"},
+{"name": "paula schetzle"},
+{"name": "thuy cao"},
+{"name": "devon house"},
+{"name": "wesley blackberry"},
+{"name": "clinton lawrence"},
+{"name": "marshall moll"},
+{"name": "ron meldrum"},
+{"name": "curt dahl"},
+{"name": "jerry cleaners"},
+{"name": "charley thomas"},
+{"name": "irina burilkova"},
+{"name": "mai baptista"},
+{"name": "annett darts"},
+{"name": "shane bridges"},
+{"name": "dave channey"},
+{"name": "tom kerkhoven"},
+{"name": "terrance hawk"},
+{"name": "miriam holmes"},
+{"name": "daniel wakelin"},
+{"name": "jane donahue"},
+{"name": "dan ryan"},
+{"name": "tom schulenberg"},
+{"name": "kathy bloom"},
+{"name": "jess harris"},
+{"name": "bo vela"},
+{"name": "jessica housain"},
+{"name": "ed liegey"},
+{"name": "lynn brenner"},
+{"name": "leah pears"},
+{"name": "bill griffin"},
+{"name": "michael delaney"},
+{"name": "tara mahtani"},
+{"name": "eden aquarium"},
+{"name": "jamie hepp"},
+{"name": "hillary gillespie"},
+{"name": "sandra harvey"},
+{"name": "roxane hipwell"},
+{"name": "melissa hair"},
+{"name": "craig fry"},
+{"name": "jackie desuza"},
+{"name": "missy tucker"},
+{"name": "reggie dance"},
+{"name": "stephanie angelo"},
+{"name": "bruce elman"},
+{"name": "ken carter"},
+{"name": "suzy cellphone"},
+{"name": "bill hurtt"},
+{"name": "charlie sumalong"},
+{"name": "courtney frey"},
+{"name": "alan prince"},
+{"name": "henry hernaez"},
+{"name": "kristina rudd"},
+{"name": "ann wood"},
+{"name": "melissa boyd"},
+{"name": "darren albertson"},
+{"name": "willie davis"},
+{"name": "kara cell"},
+{"name": "eric gmail"},
+{"name": "devon samuels"},
+{"name": "betsy hummel"},
+{"name": "matthew keese"},
+{"name": "pat v"},
+{"name": "andrew bro"},
+{"name": "bruce baily"},
+{"name": "sandra smith"},
+{"name": "cathy starnes"},
+{"name": "rachel knapp"},
+{"name": "jon land"},
+{"name": "mark vandaharr"},
+{"name": "cory livers"},
+{"name": "stan anderson"},
+{"name": "kevin vandike"},
+{"name": "rodger thomas"},
+{"name": "kenton ward"},
+{"name": "mona rodriguez"},
+{"name": "deb tabor"},
+{"name": "ed lalonde"},
+{"name": "nolan nicoll"},
+{"name": "mark myra"},
+{"name": "mel totah"},
+{"name": "cameron jensen"},
+{"name": "lisa pitt"},
+{"name": "lee hendrickson"},
+{"name": "ivan berkowitz"},
+{"name": "tyler prawitt"},
+{"name": "kathy hicks"},
+{"name": "alisha barrowcliff"},
+{"name": "sara garrett"},
+{"name": "don simpson"},
+{"name": "keith gurl"},
+{"name": "jeff kidder"},
+{"name": "trey bonner"},
+{"name": "mark leach"},
+{"name": "laura kit"},
+{"name": "anna bossa"},
+{"name": "alisha jackson"},
+{"name": "barry fitts"},
+{"name": "daria trawkowski"},
+{"name": "john burdick"},
+{"name": "tina fresno"},
+{"name": "sonia agar"},
+{"name": "patrick sutter"},
+{"name": "frank bullard"},
+{"name": "kristi mcgranahan"},
+{"name": "tom szatkowski"},
+{"name": "michael perez"},
+{"name": "molly big"},
+{"name": "sean harrel"},
+{"name": "francine beyer"},
+{"name": "pete crosby"},
+{"name": "diego loco"},
+{"name": "stanley yu"},
+{"name": "alex edington"},
+{"name": "ann waddell"},
+{"name": "bruce jr"},
+{"name": "bill phipps"},
+{"name": "larry cone"},
+{"name": "josh linam"},
+{"name": "bob gaither"},
+{"name": "camille herrera"},
+{"name": "jean hilliard"},
+{"name": "melinda cardona"},
+{"name": "mike barna"},
+{"name": "sally latife"},
+{"name": "barry swain"},
+{"name": "louis palos"},
+{"name": "kim zigler"},
+{"name": "jodi sherry"},
+{"name": "jamie parker"},
+{"name": "christopher saddler"},
+{"name": "james ringsrud"},
+{"name": "christina keck"},
+{"name": "cody griffin"},
+{"name": "laura bellinger"},
+{"name": "courtney tisch"},
+{"name": "roberto nm"},
+{"name": "brian hawken"},
+{"name": "fred tejkl"},
+{"name": "leslie anderson"},
+{"name": "catherine w"},
+{"name": "pam beadel"},
+{"name": "dan morgan"},
+{"name": "rachael ortiz"},
+{"name": "ted kraus"},
+{"name": "paris plumbing"},
+{"name": "mark kindy"},
+{"name": "kent lingenfelter"},
+{"name": "kenny z"},
+{"name": "john donahue"},
+{"name": "jake knickerbocker"},
+{"name": "george schumer"},
+{"name": "ok cafe"},
+{"name": "tommy kennedy"},
+{"name": "kristen stratton"},
+{"name": "michael keefe"},
+{"name": "rob barnuevo"},
+{"name": "steven wright"},
+{"name": "desiree nicols"},
+{"name": "jason kwan"},
+{"name": "sheryl sain"},
+{"name": "rick ducey"},
+{"name": "jess adobe"},
+{"name": "dave giuliano"},
+{"name": "dana burnell"},
+{"name": "don jacobs"},
+{"name": "lynn ritthaler"},
+{"name": "steven shapero"},
+{"name": "kevin wallace"},
+{"name": "michael l"},
+{"name": "alison kress"},
+{"name": "william wpb"},
+{"name": "mike kleke"},
+{"name": "anne sullivan"},
+{"name": "clara jimenez"},
+{"name": "evan salone"},
+{"name": "derrick lawson"},
+{"name": "chris house"},
+{"name": "jeff driscoll"},
+{"name": "cyndi workman"},
+{"name": "brian staples"},
+{"name": "moises valenzuela"},
+{"name": "bobbie crane"},
+{"name": "gabriel jose"},
+{"name": "tony mclaren"},
+{"name": "sommer setterstrom"},
+{"name": "lorna larson"},
+{"name": "barb prittchett"},
+{"name": "dave carson"},
+{"name": "lindsey taylor"},
+{"name": "boris bogatin"},
+{"name": "mike bovoso"},
+{"name": "steve piceno"},
+{"name": "paul champps"},
+{"name": "kirk d"},
+{"name": "lisa more"},
+{"name": "marsha garczewski"},
+{"name": "rosa gutierrez"},
+{"name": "claudine ryan"},
+{"name": "corey dennis"},
+{"name": "carol murphy"},
+{"name": "daniel lookadoo"},
+{"name": "sue muchowski"},
+{"name": "patrick mahar"},
+{"name": "joe amico"},
+{"name": "johnny lam"},
+{"name": "jerrold reilly"},
+{"name": "dudley wilson"},
+{"name": "art giuliano"},
+{"name": "todd roaten"},
+{"name": "debbie akbari"},
+{"name": "fernando solorzano"},
+{"name": "alexander kilhefner"},
+{"name": "paul surmay"},
+{"name": "judy marshall"},
+{"name": "coy lopez"},
+{"name": "jane birkholz"},
+{"name": "katie krivitz"},
+{"name": "seth griffiths"},
+{"name": "simon bee"},
+{"name": "malcolm maclean"},
+{"name": "doug chipman"},
+{"name": "cathy alesi"},
+{"name": "eric hutchcroft"},
+{"name": "patrick mccabe"},
+{"name": "jacqueline walker"},
+{"name": "jen paquet"},
+{"name": "theresa geary"},
+{"name": "kim boritz"},
+{"name": "dave takeuchi"},
+{"name": "mindy barton"},
+{"name": "simone hamm"},
+{"name": "megan clingman"},
+{"name": "brian rodgers"},
+{"name": "derek haddad"},
+{"name": "jen takamine"},
+{"name": "dave chastain"},
+{"name": "jessica elson"},
+{"name": "luke pietrzak"},
+{"name": "maggie yac"},
+{"name": "jackie corbet"},
+{"name": "rosa ray"},
+{"name": "kristen goodell"},
+{"name": "min check"},
+{"name": "mike norton"},
+{"name": "jim stalker"},
+{"name": "matt blumhart"},
+{"name": "mike olivia"},
+{"name": "jamie goren"},
+{"name": "shelly frias"},
+{"name": "stuart blatt"},
+{"name": "rebekah milhoan"},
+{"name": "mike henderson"},
+{"name": "bill millward"},
+{"name": "brian nelson"},
+{"name": "robert posthumus"},
+{"name": "joe chiseri"},
+{"name": "heather krystals"},
+{"name": "dee beasley"},
+{"name": "mark holesopple"},
+{"name": "mitchell hill"},
+{"name": "carol winter"},
+{"name": "aaron moon"},
+{"name": "mike follosco"},
+{"name": "dora griner"},
+{"name": "phil kreider"},
+{"name": "douglas fleming"},
+{"name": "chris schultz"},
+{"name": "albert willis"},
+{"name": "frank turek"},
+{"name": "jake dewitt"},
+{"name": "jeanne loewen"},
+{"name": "paul sorriento"},
+{"name": "jody branchcomb"},
+{"name": "ruthie car"},
+{"name": "roy maldonado"},
+{"name": "george becker"},
+{"name": "josh bc"},
+{"name": "cody becks"},
+{"name": "glen overton"},
+{"name": "steve smooth"},
+{"name": "brett carson"},
+{"name": "deborah siegel"},
+{"name": "chris class"},
+{"name": "cole johnson"},
+{"name": "brad nicholson"},
+{"name": "dominque saitil"},
+{"name": "tammy duffy"},
+{"name": "phil easton"},
+{"name": "ellie lastra"},
+{"name": "kim crystal"},
+{"name": "amy robertson"},
+{"name": "ginny mclaughlin"},
+{"name": "andy v"},
+{"name": "rick dykes"},
+{"name": "kevin poulsen"},
+{"name": "christa windley"},
+{"name": "steve mcally"},
+{"name": "cindy sprint"},
+{"name": "jennifer wildrick"},
+{"name": "doug miller"},
+{"name": "joe w"},
+{"name": "juan luis"},
+{"name": "louise logie"},
+{"name": "nicole baxter"},
+{"name": "colin nix"},
+{"name": "heather sweitzer"},
+{"name": "terri kowalski"},
+{"name": "chris steele"},
+{"name": "deb herrman"},
+{"name": "myron russell"},
+{"name": "herman nicolay"},
+{"name": "michael brownstein"},
+{"name": "pete lamb"},
+{"name": "daniel robinette"},
+{"name": "tyler caplinger"},
+{"name": "rob waddell"},
+{"name": "zachary smith"},
+{"name": "kesha htown"},
+{"name": "stanley barnes"},
+{"name": "amanda dado"},
+{"name": "megan kelley"},
+{"name": "paul haas"},
+{"name": "kristie holzworth"},
+{"name": "cheryl gunderson"},
+{"name": "jane laurent"},
+{"name": "ralph foston"},
+{"name": "liz zabetakis"},
+{"name": "chris noble"},
+{"name": "robin hunter"},
+{"name": "joe karmia"},
+{"name": "tom o'connor"},
+{"name": "patty oliden"},
+{"name": "guy faherty"},
+{"name": "sylvia kravitz"},
+{"name": "frank tapia"},
+{"name": "jamie bradford"},
+{"name": "ricardo thomason"},
+{"name": "jeremy shapiro"},
+{"name": "mike casey"},
+{"name": "debbie clough"},
+{"name": "martina anderson"},
+{"name": "omar turner"},
+{"name": "clarissa burns"},
+{"name": "chris agazaryan"},
+{"name": "sandra tozay"},
+{"name": "dante rome"},
+{"name": "john varela"},
+{"name": "vernon davis"},
+{"name": "kimberly mont"},
+{"name": "robin pariso"},
+{"name": "tony banks"},
+{"name": "daryl turko"},
+{"name": "mary manion"},
+{"name": "gina trost"},
+{"name": "erin abegglen"},
+{"name": "jack franklin"},
+{"name": "david cappone"},
+{"name": "julie jurica"},
+{"name": "ben escalante"},
+{"name": "donny leaderman"},
+{"name": "wally rosemont"},
+{"name": "dee narayanan"},
+{"name": "brad gunder"},
+{"name": "joshua laforce"},
+{"name": "rob lo"},
+{"name": "jen jason"},
+{"name": "larry simpson"},
+{"name": "rich slavin"},
+{"name": "kenny hairston"},
+{"name": "patrick chu"},
+{"name": "sean m"},
+{"name": "josh evette"},
+{"name": "rob bouse"},
+{"name": "tom albani"},
+{"name": "felipe conto"},
+{"name": "david donnelly"},
+{"name": "grant tancowny"},
+{"name": "leah dyrud"},
+{"name": "erin hudson"},
+{"name": "peggy hubbard"},
+{"name": "tony turner"},
+{"name": "james carnegie"},
+{"name": "tyler johnson"},
+{"name": "tony avila"},
+{"name": "randy new"},
+{"name": "christopher brooks"},
+{"name": "amy mcandree"},
+{"name": "pam anderson"},
+{"name": "donald collections"},
+{"name": "carl beke"},
+{"name": "kyle vangrol"},
+{"name": "elijah smith"},
+{"name": "rebecca zink"},
+{"name": "bruce green"},
+{"name": "aaron edelman"},
+{"name": "alan laguna"},
+{"name": "jonathan rodriguez"},
+{"name": "fred gehrig"},
+{"name": "barbra jean"},
+{"name": "nick rehab"},
+{"name": "shawn excaliber"},
+{"name": "russ mcginty"},
+{"name": "nina princesse"},
+{"name": "diane cell"},
+{"name": "art gibson"},
+{"name": "lyndon kately"},
+{"name": "tom burton"},
+{"name": "donovan pr"},
+{"name": "jesse twinkcersize"},
+{"name": "melissa danbury"},
+{"name": "ken hughes"},
+{"name": "alex defelice"},
+{"name": "john valerio"},
+{"name": "cassie silva"},
+{"name": "jamie wilson"},
+{"name": "tia elise"},
+{"name": "herman reality"},
+{"name": "scottie juneau"},
+{"name": "don m"},
+{"name": "kristine szmanda"},
+{"name": "cindy grassi"},
+{"name": "ron schrader"},
+{"name": "jason larson"},
+{"name": "gina hathorn"},
+{"name": "matt dirito"},
+{"name": "mike stine"},
+{"name": "dane jordan"},
+{"name": "lady forest"},
+{"name": "pat langer"},
+{"name": "rich cfo"},
+{"name": "quentin kingham"},
+{"name": "reed buderus"},
+{"name": "tammy ramlawi"},
+{"name": "john schrimsher"},
+{"name": "bruce cummings"},
+{"name": "tasha tripplett"},
+{"name": "michael profit"},
+{"name": "charles petitti"},
+{"name": "blaine welks"},
+{"name": "kelly macfarland"},
+{"name": "orlando bojorquez"},
+{"name": "robert stabile"},
+{"name": "mary storm"},
+{"name": "emma devine"},
+{"name": "tyler duellman"},
+{"name": "ron marion"},
+{"name": "francis esu"},
+{"name": "jennifer williams"},
+{"name": "zack martin"},
+{"name": "mark albert"},
+{"name": "tessa green"},
+{"name": "jeffrey hull"},
+{"name": "mary schafer"},
+{"name": "carlos ku"},
+{"name": "bill bizmeyer"},
+{"name": "steve hooper"},
+{"name": "laurie rothenberg"},
+{"name": "dan wk"},
+{"name": "dave brandeberry"},
+{"name": "joe harding"},
+{"name": "carolyn phillips"},
+{"name": "stan gilliland"},
+{"name": "amy betz"},
+{"name": "don sanfranek"},
+{"name": "bob feldmann"},
+{"name": "lee zejacs"},
+{"name": "josh otte"},
+{"name": "grace chong"},
+{"name": "michael fulton"},
+{"name": "beth lebow"},
+{"name": "frank fillipone"},
+{"name": "natasha akers"},
+{"name": "joel laird"},
+{"name": "glen hollinger"},
+{"name": "dave thompson"},
+{"name": "beverly xxxxx"},
+{"name": "bradley mcdevitt"},
+{"name": "lee weisman"},
+{"name": "amber gillette"},
+{"name": "kurt union"},
+{"name": "stewart alpert"},
+{"name": "mike lacosta"},
+{"name": "terry hodgkin"},
+{"name": "kyle hawkins"},
+{"name": "kenny barnes"},
+{"name": "larry ford"},
+{"name": "mary davidson"},
+{"name": "chad bryan"},
+{"name": "robert o'connell"},
+{"name": "ray kosiba"},
+{"name": "judy sis"},
+{"name": "will donaldson"},
+{"name": "tammy pryor"},
+{"name": "page boxing"},
+{"name": "stephanie bailey"},
+{"name": "ryan bareilles"},
+{"name": "eli lichtenstien"},
+{"name": "don roberts"},
+{"name": "james montoya"},
+{"name": "keith green"},
+{"name": "al thurmond"},
+{"name": "kelly coc"},
+{"name": "andrew riepe"},
+{"name": "nicole notmarried"},
+{"name": "brian treadway"},
+{"name": "alex gudenau"},
+{"name": "mike simpson"},
+{"name": "ronnie malone"},
+{"name": "jenny w"},
+{"name": "toby okenwa"},
+{"name": "matt mazgaj"},
+{"name": "carla isaias"},
+{"name": "andrea paul"},
+{"name": "matt baldes"},
+{"name": "simon varley"},
+{"name": "anthony mancini"},
+{"name": "jackie chen"},
+{"name": "sean duque"},
+{"name": "matt ware"},
+{"name": "paris reid"},
+{"name": "tiffany jackson"},
+{"name": "jon bingle"},
+{"name": "jess caufield"},
+{"name": "patti ryan"},
+{"name": "josephine vasquez"},
+{"name": "dan dineson"},
+{"name": "jose big"},
+{"name": "van meter"},
+{"name": "max schumaker"},
+{"name": "renee her"},
+{"name": "larry bean"},
+{"name": "louie prieto"},
+{"name": "marilyn lugo"},
+{"name": "stan schwartz"},
+{"name": "kenny navas"},
+{"name": "mark kowal"},
+{"name": "ryan wolfe"},
+{"name": "teddy holmes"},
+{"name": "darlene quinn"},
+{"name": "victor seveso"},
+{"name": "tom thumb"},
+{"name": "greg lawerence"},
+{"name": "janette stinnet"},
+{"name": "charlie berard"},
+{"name": "john pratt"},
+{"name": "phil evazkhani"},
+{"name": "val steinberg"},
+{"name": "terry pitzer"},
+{"name": "raquel navor"},
+{"name": "brandon dunaway"},
+{"name": "john lichtenstein"},
+{"name": "donald lyons"},
+{"name": "rubin rebecca"},
+{"name": "tim ross"},
+{"name": "sarah b"},
+{"name": "will schinagl"},
+{"name": "cheryl julcher"},
+{"name": "chris corr"},
+{"name": "beth shaw"},
+{"name": "chase disney"},
+{"name": "david kestner"},
+{"name": "al champagne"},
+{"name": "kelly harcus"},
+{"name": "susan quintyne"},
+{"name": "ken whiteside"},
+{"name": "amanda chan"},
+{"name": "marlo king"},
+{"name": "nick trevillian"},
+{"name": "nick wash"},
+{"name": "brian fredkin"},
+{"name": "van rental"},
+{"name": "erin olsen"},
+{"name": "emma reaves"},
+{"name": "robert lanenga"},
+{"name": "linda guzzetta"},
+{"name": "martin family"},
+{"name": "taylor tay"},
+{"name": "rick ross"},
+{"name": "deanne harper"},
+{"name": "shane topolovic"},
+{"name": "dave rudyk"},
+{"name": "george chickering"},
+{"name": "elise clemet"},
+{"name": "paul keeton"},
+{"name": "steven poloka"},
+{"name": "joann padilla"},
+{"name": "wilma brooks"},
+{"name": "art khnkoyan"},
+{"name": "shari lewis"},
+{"name": "mary keating"},
+{"name": "jutta jacobs"},
+{"name": "norma malagarie"},
+{"name": "dale abuel"},
+{"name": "ashley higham"},
+{"name": "beverly petty"},
+{"name": "jamie babbit"},
+{"name": "jason paisan"},
+{"name": "shelby sanders"},
+{"name": "jodi brothers"},
+{"name": "nicole mazzone"},
+{"name": "sharon sup"},
+{"name": "andrew taxes"},
+{"name": "jessie kramer"},
+{"name": "karyn grant"},
+{"name": "dina patel"},
+{"name": "jess parents"},
+{"name": "marcelo cavalcante"},
+{"name": "james palmer"},
+{"name": "lucia quiroz"},
+{"name": "craig kohler"},
+{"name": "jessica salisbury"},
+{"name": "nathan fisher"},
+{"name": "cheryl bell"},
+{"name": "jon work"},
+{"name": "darren gallegos"},
+{"name": "ryan stowe"},
+{"name": "gay jason"},
+{"name": "katie cervantes"},
+{"name": "jeremy ruppe"},
+{"name": "seth art"},
+{"name": "ken west"},
+{"name": "arianna schettino"},
+{"name": "geraldo orozco"},
+{"name": "scott osborne"},
+{"name": "bob riffner"},
+{"name": "tony romas"},
+{"name": "tony bud"},
+{"name": "douglas cabot"},
+{"name": "john lashell"},
+{"name": "tracy pulla"},
+{"name": "kira rabalais"},
+{"name": "sue curley"},
+{"name": "bob dubow"},
+{"name": "ginny gribble"},
+{"name": "josh shrager"},
+{"name": "levi colinas"},
+{"name": "shirley ingram"},
+{"name": "mike karaoke"},
+{"name": "toya brown"},
+{"name": "peter fleming"},
+{"name": "lowell smith"},
+{"name": "anna melamud"},
+{"name": "jim thompson"},
+{"name": "mindy culley"},
+{"name": "bill lederer"},
+{"name": "kelly paper"},
+{"name": "loren jones"},
+{"name": "carla wilcher"},
+{"name": "james cincotta"},
+{"name": "todd mumford"},
+{"name": "susie cohen"},
+{"name": "gabriel cell"},
+{"name": "edward ings"},
+{"name": "gary liggett"},
+{"name": "owen connelly"},
+{"name": "dan lanus"},
+{"name": "vicki bartlett"},
+{"name": "shawn streeter"},
+{"name": "corinne bernimoulin"},
+{"name": "steve edmiston"},
+{"name": "byron steele"},
+{"name": "gary lileikis"},
+{"name": "jacki klein"},
+{"name": "erik laver"},
+{"name": "kay fritzsche"},
+{"name": "nikole flores"},
+{"name": "ron harrell"},
+{"name": "darrel neff"},
+{"name": "rachael mcgee"},
+{"name": "allison garrett"},
+{"name": "terri blackmon"},
+{"name": "damon scheter"},
+{"name": "debbie turkanis"},
+{"name": "john boehmer"},
+{"name": "scott speakman"},
+{"name": "brenna frisbe"},
+{"name": "kathy russell"},
+{"name": "laura minjarez"},
+{"name": "gil williams"},
+{"name": "rob obrien"},
+{"name": "debra smith"},
+{"name": "david pankhurst"},
+{"name": "jay meltzer"},
+{"name": "glen floyd"},
+{"name": "caleb s"},
+{"name": "mike sigidel"},
+{"name": "darryl bruyns"},
+{"name": "holly tibbel"},
+{"name": "omar barral"},
+{"name": "luisa pessel"},
+{"name": "carl fischbach"},
+{"name": "melony ford"},
+{"name": "fiona luck"},
+{"name": "lloyd booker"},
+{"name": "craig louie"},
+{"name": "deon actn"},
+{"name": "jeff paul"},
+{"name": "alfonso cortez"},
+{"name": "shelly simpson"},
+{"name": "rob goodwin"},
+{"name": "richard hatt"},
+{"name": "gary myles"},
+{"name": "tom cush"},
+{"name": "brian ashley"},
+{"name": "gloria gott"},
+{"name": "al browning"},
+{"name": "alex flores"},
+{"name": "brittany koon"},
+{"name": "susan schumacher"},
+{"name": "stephanie condron"},
+{"name": "ann evans"},
+{"name": "andrew draper"},
+{"name": "jackie zook"},
+{"name": "della mckinney"},
+{"name": "ken argo"},
+{"name": "michael yardley"},
+{"name": "gail anderson"},
+{"name": "danielle berber"},
+{"name": "liz coko"},
+{"name": "shawn barreiro"},
+{"name": "harry issler"},
+{"name": "michael naeve"},
+{"name": "lorinda bruen"},
+{"name": "pam budenbender"},
+{"name": "steve younch"},
+{"name": "patrice vielpeau"},
+{"name": "mary h"},
+{"name": "luke gilbertson"},
+{"name": "lisa clayton"},
+{"name": "jim richardson"},
+{"name": "cassandra terwilliger"},
+{"name": "ruth smith"},
+{"name": "josh lewis"},
+{"name": "tama tenis"},
+{"name": "glen lakes"},
+{"name": "liz masterman"},
+{"name": "eric sapir"},
+{"name": "sue uptown"},
+{"name": "chris brixy"},
+{"name": "john nicon"},
+{"name": "sarah ritsko"},
+{"name": "andrew shuta"},
+{"name": "ashlee hughes"},
+{"name": "dee burgin"},
+{"name": "jen engel"},
+{"name": "shirley foster"},
+{"name": "hugh bartels"},
+{"name": "brain stanely"},
+{"name": "gail muniz"},
+{"name": "brooke ives"},
+{"name": "richard terry"},
+{"name": "matt trucco"},
+{"name": "michelle woznichak"},
+{"name": "ben naude"},
+{"name": "olivia stallard"},
+{"name": "rob walker"},
+{"name": "karen ramel"},
+{"name": "alex silverman"},
+{"name": "stan septic"},
+{"name": "tami vinzant"},
+{"name": "jen glen"},
+{"name": "donna franz"},
+{"name": "linda vark"},
+{"name": "lonnie king"},
+{"name": "clara brush"},
+{"name": "columbus police"},
+{"name": "jay parties"},
+{"name": "laura rehbehn"},
+{"name": "kimberly anderson"},
+{"name": "tai doan"},
+{"name": "andrew franklin"},
+{"name": "ann scott"},
+{"name": "alfonso villa"},
+{"name": "dominique harris"},
+{"name": "maria plantilla"},
+{"name": "winter construction"},
+{"name": "melissa maddox"},
+{"name": "brendon crossing"},
+{"name": "cathy allison"},
+{"name": "billy chew"},
+{"name": "damon weber"},
+{"name": "peter smul"},
+{"name": "dennis riege"},
+{"name": "andy weirzbicky"},
+{"name": "nelson oliver"},
+{"name": "kevin wsp"},
+{"name": "deb cornwell"},
+{"name": "colton eliasen"},
+{"name": "andrea guzinski"},
+{"name": "steven chic"},
+{"name": "joy mueller"},
+{"name": "yu ra"},
+{"name": "le montreaux"},
+{"name": "bridgette johnston"},
+{"name": "darryl simons"},
+{"name": "wilfred cosca"},
+{"name": "keith goldfeld"},
+{"name": "david bengtson"},
+{"name": "alisa katz"},
+{"name": "brian lawson"},
+{"name": "fred wolfe"},
+{"name": "jack claver"},
+{"name": "val pena"},
+{"name": "wally terry"},
+{"name": "allison tiefel"},
+{"name": "joe fagan"},
+{"name": "jon boyer"},
+{"name": "thomas bryan"},
+{"name": "steve yockel"},
+{"name": "beverly wilson"},
+{"name": "robbie chenault"},
+{"name": "sterling fletcher"},
+{"name": "renee keo"},
+{"name": "cindy l"},
+{"name": "joann willhite"},
+{"name": "brad w"},
+{"name": "al solting"},
+{"name": "frank cowan"},
+{"name": "barbara halle"},
+{"name": "meg healey"},
+{"name": "roger letalien"},
+{"name": "hillary hull"},
+{"name": "ashley mullin"},
+{"name": "bill sivick"},
+{"name": "jazmine conage"},
+{"name": "mary sues"},
+{"name": "tina ross"},
+{"name": "ethan smith"},
+{"name": "justin stafford"},
+{"name": "caroline krabach"},
+{"name": "chad hindolghter"},
+{"name": "richard tonioni"},
+{"name": "delta etl"},
+{"name": "ryan fortson"},
+{"name": "paula keating"},
+{"name": "jena naimi"},
+{"name": "nicole gipson"},
+{"name": "carla dawson"},
+{"name": "jim karabetsos"},
+{"name": "jim thune"},
+{"name": "joe a"},
+{"name": "melissa qazi"},
+{"name": "andrew kaufman"},
+{"name": "kyle brown"},
+{"name": "craig chapman"},
+{"name": "richard lechner"},
+{"name": "alex krasnov"},
+{"name": "dawn allendorf"},
+{"name": "mike o'reilly"},
+{"name": "tony q"},
+{"name": "ronni neeman"},
+{"name": "royce hylton"},
+{"name": "gary wells"},
+{"name": "phyllis catania"},
+{"name": "jayson carlyle"},
+{"name": "carl siegel"},
+{"name": "ned halle"},
+{"name": "jesse tuck"},
+{"name": "coy heaton"},
+{"name": "alena olaes"},
+{"name": "ryan big"},
+{"name": "rick pranitis"},
+{"name": "star client"},
+{"name": "darrell holmes"},
+{"name": "brandy huser"},
+{"name": "brett fifield"},
+{"name": "beth gonnering"},
+{"name": "steve brasington"},
+{"name": "chris stevens"},
+{"name": "brent wilson"},
+{"name": "david tobin"},
+{"name": "ben anderson"},
+{"name": "nancy terriquez"},
+{"name": "debra ramsay"},
+{"name": "corey roberts"},
+{"name": "cynthia luke"},
+{"name": "sasha osha"},
+{"name": "mary tunesen"},
+{"name": "tyler police"},
+{"name": "alexandria glispie"},
+{"name": "deja regala"},
+{"name": "fred gao"},
+{"name": "marlon deandrade"},
+{"name": "julie underwood"},
+{"name": "kellie swayne"},
+{"name": "rachael bearer"},
+{"name": "madeline house"},
+{"name": "david hawkins"},
+{"name": "bertha lansdown"},
+{"name": "jason stroud"},
+{"name": "kay lehmer"},
+{"name": "amy o'donnel"},
+{"name": "jessica kanakry"},
+{"name": "vince webb"},
+{"name": "cherie dell'anno"},
+{"name": "carroll realtor"},
+{"name": "rob shostak"},
+{"name": "mark wilkman"},
+{"name": "holly eby"},
+{"name": "justin townsend"},
+{"name": "kevin hall"},
+{"name": "robert daugherty"},
+{"name": "vince cannon"},
+{"name": "val shibley"},
+{"name": "alaina williams"},
+{"name": "lyn monticone"},
+{"name": "andrew bergen"},
+{"name": "ron huber"},
+{"name": "john royall"},
+{"name": "courtney sabb"},
+{"name": "doug knight"},
+{"name": "robert evers"},
+{"name": "sharon seiler"},
+{"name": "darlene chestnut"},
+{"name": "rob barbato"},
+{"name": "julie barber"},
+{"name": "joe gallivan"},
+{"name": "katie costello"},
+{"name": "danny rojas"},
+{"name": "tom talbot"},
+{"name": "xavier ramirez"},
+{"name": "wendy mervis"},
+{"name": "toby frandsen"},
+{"name": "jeff callaway"},
+{"name": "kris zawisza"},
+{"name": "manda shah"},
+{"name": "ingrid lx"},
+{"name": "sierra smith"},
+{"name": "carole charbonneau"},
+{"name": "heather mi"},
+{"name": "laura luttrell"},
+{"name": "carissa daly"},
+{"name": "jamie manzano"},
+{"name": "angela higgins"},
+{"name": "christian lui"},
+{"name": "kyle gleason"},
+{"name": "breana stockwell"},
+{"name": "rick welch"},
+{"name": "phil hugely"},
+{"name": "claudia caprilles"},
+{"name": "dirk ooijkaas"},
+{"name": "david lombardi"},
+{"name": "mike val"},
+{"name": "barbara mcdermott"},
+{"name": "robert maxwell"},
+{"name": "saundra hester"},
+{"name": "deborah ferrell"},
+{"name": "chuck hendsch"},
+{"name": "jen hilgenberg"},
+{"name": "mike sunderland"},
+{"name": "mark wheaton"},
+{"name": "lily heneisen"},
+{"name": "lee todd"},
+{"name": "geneva lee"},
+{"name": "lena mescall"},
+{"name": "jim nesbitt"},
+{"name": "lauren spencer"},
+{"name": "alonzo blockett"},
+{"name": "kayla thomas"},
+{"name": "will rose"},
+{"name": "gerald raines"},
+{"name": "lance morgan"},
+{"name": "mike soccer"},
+{"name": "kevin homerstein"},
+{"name": "mindy axid"},
+{"name": "tom hinshaw"},
+{"name": "rachel jordan"},
+{"name": "jen lloyd"},
+{"name": "becky hellerstien"},
+{"name": "brian maynard"},
+{"name": "sherri pendelton"},
+{"name": "eric callis"},
+{"name": "dave corning"},
+{"name": "chuck siegel"},
+{"name": "george tougias"},
+{"name": "danny klein"},
+{"name": "colleen p"},
+{"name": "robert musser"},
+{"name": "janet komoto"},
+{"name": "carmen reveron"},
+{"name": "jordan cook"},
+{"name": "jeff tottleben"},
+{"name": "rory kelliher"},
+{"name": "carlos egues"},
+{"name": "kim padova"},
+{"name": "lloyd goetz"},
+{"name": "jennifer snowden"},
+{"name": "rich sundin"},
+{"name": "tommy jones"},
+{"name": "josh spirit"},
+{"name": "norman yoshida"},
+{"name": "becky coburn"},
+{"name": "ben kurian"},
+{"name": "ron watts"},
+{"name": "scott g"},
+{"name": "jack jordan"},
+{"name": "james stiles"},
+{"name": "jeremy work"},
+{"name": "dave jeff"},
+{"name": "samantha marley"},
+{"name": "paul nousis"},
+{"name": "mario carrillo"},
+{"name": "garland steward"},
+{"name": "jason marvich"},
+{"name": "robert selby"},
+{"name": "bruce odette"},
+{"name": "ana rosa"},
+{"name": "dawn hankison"},
+{"name": "cindy anderson"},
+{"name": "dave budach"},
+{"name": "melissa gig"},
+{"name": "ashley mauer"},
+{"name": "peter imhof"},
+{"name": "sue premetz"},
+{"name": "cheryl kent"},
+{"name": "bob gronski"},
+{"name": "yan sjvc"},
+{"name": "peter gonyeau"},
+{"name": "steven sutherland"},
+{"name": "greg burkhardt"},
+{"name": "dean rathbun"},
+{"name": "tony monaco"},
+{"name": "jamie c"},
+{"name": "shane jones"},
+{"name": "jim brennan"},
+{"name": "lorena white"},
+{"name": "robert mansour"},
+{"name": "randy reyes"},
+{"name": "melissa lehman"},
+{"name": "aaron amato"},
+{"name": "alia ott"},
+{"name": "steve looney"},
+{"name": "ernest jefferson"},
+{"name": "lauren cromer"},
+{"name": "angela toribio"},
+{"name": "joselyn paulson"},
+{"name": "lamar johnson"},
+{"name": "joel silverfield"},
+{"name": "karen barone"},
+{"name": "samuel rogers"},
+{"name": "brian le"},
+{"name": "megan mclean"},
+{"name": "kirk oconnell"},
+{"name": "sam theven"},
+{"name": "mae ingles"},
+{"name": "jake richins"},
+{"name": "bryan vierow"},
+{"name": "ralph gallaugher"},
+{"name": "karen nanninga"},
+{"name": "john neumark"},
+{"name": "kevin thai"},
+{"name": "chris gall"},
+{"name": "al whitley"},
+{"name": "tracy bellamy"},
+{"name": "anne cookson"},
+{"name": "nick vriheas"},
+{"name": "john kasper"},
+{"name": "mike naranjo"},
+{"name": "roger walton"},
+{"name": "michelle franklin"},
+{"name": "casey jean"},
+{"name": "clarissa duron"},
+{"name": "linda roy"},
+{"name": "dan delaney"},
+{"name": "james minor"},
+{"name": "vern profitt"},
+{"name": "catherine perreault"},
+{"name": "james ware"},
+{"name": "david larson"},
+{"name": "mike joher"},
+{"name": "lori jamison"},
+{"name": "jerald hunsaker"},
+{"name": "dave wemke"},
+{"name": "pat bsc"},
+{"name": "chris plechy"},
+{"name": "steve bangs"},
+{"name": "crystal curiel"},
+{"name": "carol walter"},
+{"name": "sandra alvarez"},
+{"name": "jason rogne"},
+{"name": "dave wenberg"},
+{"name": "erick kauhini"},
+{"name": "sara schmoldt"},
+{"name": "sara doyle"},
+{"name": "melissa h"},
+{"name": "trevor bach"},
+{"name": "brenda giddings"},
+{"name": "diana emery"},
+{"name": "joe eagan"},
+{"name": "sophia payind"},
+{"name": "george lynch"},
+{"name": "ned matthews"},
+{"name": "andy armshlong"},
+{"name": "david good"},
+{"name": "sheila novak"},
+{"name": "brett denney"},
+{"name": "alice bozzi"},
+{"name": "megan carrigan"},
+{"name": "jen munoz"},
+{"name": "al cell"},
+{"name": "kim scardino"},
+{"name": "raymond knoll"},
+{"name": "theron mcmillon"},
+{"name": "elena sobolic"},
+{"name": "kelly doll"},
+{"name": "ken lin"},
+{"name": "karen huaulme"},
+{"name": "jim brock"},
+{"name": "skye new"},
+{"name": "robby miller"},
+{"name": "steve phelps"},
+{"name": "david umbenhaur"},
+{"name": "lynn verchere"},
+{"name": "mike crawford"},
+{"name": "jody madson"},
+{"name": "leslie shaw"},
+{"name": "jon keene"},
+{"name": "terry angstadt"},
+{"name": "george aguilar"},
+{"name": "sherron boardley"},
+{"name": "jeffrey hoosear"},
+{"name": "robin downing"},
+{"name": "tillie terrell"},
+{"name": "donald armour"},
+{"name": "jason loftus"},
+{"name": "debra pelegrin"},
+{"name": "cathy shields"},
+{"name": "randi elite"},
+{"name": "carli olmstead"},
+{"name": "adam tallent"},
+{"name": "hank thode"},
+{"name": "sergio trujillo"},
+{"name": "bob mcgowan"},
+{"name": "kris rowe"},
+{"name": "gerry hart"},
+{"name": "garrett ichimura"},
+{"name": "michele king"},
+{"name": "jeff sapp"},
+{"name": "rosanna jett"},
+{"name": "rich webber"},
+{"name": "jerry pearman"},
+{"name": "holly miner"},
+{"name": "lynn poole"},
+{"name": "mike v"},
+{"name": "george maamari"},
+{"name": "nicola saliendra"},
+{"name": "larry menedez"},
+{"name": "louis trepanier"},
+{"name": "stefanie lau"},
+{"name": "marc fuller"},
+{"name": "jennifer legree"},
+{"name": "doug boles"},
+{"name": "dan erwin"},
+{"name": "jimmy missuri"},
+{"name": "joseph nuccio"},
+{"name": "hillary model"},
+{"name": "brandon vassalotti"},
+{"name": "melanie lampa"},
+{"name": "garrett rosier"},
+{"name": "bob king"},
+{"name": "marilyn cheatham"},
+{"name": "gerald young"},
+{"name": "carolyn kellogg"},
+{"name": "noel hyde"},
+{"name": "frank hulskoetter"},
+{"name": "missy way"},
+{"name": "richard rose"},
+{"name": "melissa depot"},
+{"name": "kari r"},
+{"name": "tony piazza"},
+{"name": "tarah n"},
+{"name": "ben wurschmidt"},
+{"name": "denis dionne"},
+{"name": "morgan huttle"},
+{"name": "angela fallenbeck"},
+{"name": "tina locke"},
+{"name": "william steakhouse"},
+{"name": "megan riley"},
+{"name": "mariah bloom"},
+{"name": "michael warnecke"},
+{"name": "ramon nevarez"},
+{"name": "mike ress"},
+{"name": "bree v"},
+{"name": "bob conti"},
+{"name": "frank sisca"},
+{"name": "rob karl"},
+{"name": "bonnie jasso"},
+{"name": "eric criswell"},
+{"name": "samantha gregg"},
+{"name": "mike phelps"},
+{"name": "jane mitchell"},
+{"name": "nick arvizu"},
+{"name": "dana martin"},
+{"name": "michelle o'neil"},
+{"name": "john sly"},
+{"name": "martha alvarado"},
+{"name": "jay holiday"},
+{"name": "jaime eberhart"},
+{"name": "dennis geiser"},
+{"name": "kelsie cox"},
+{"name": "hector garceau"},
+{"name": "justin olson"},
+{"name": "marilyn pujols"},
+{"name": "shanna eichelberger"},
+{"name": "tony ellis"},
+{"name": "jason farrer"},
+{"name": "kent hammond"},
+{"name": "walker miller"},
+{"name": "alex moreno"},
+{"name": "john jacobi"},
+{"name": "melisa cin"},
+{"name": "patti christie"},
+{"name": "david causey"},
+{"name": "morris virginia"},
+{"name": "curt grandia"},
+{"name": "nancy dixon"},
+{"name": "tyler york"},
+{"name": "kristy akin"},
+{"name": "mel hosler"},
+{"name": "robert moore"},
+{"name": "albert gallo"},
+{"name": "jake c"},
+{"name": "justin acc"},
+{"name": "tony andres"},
+{"name": "karen boardman"},
+{"name": "jason lotton"},
+{"name": "lee ilse"},
+{"name": "nathan kreye"},
+{"name": "tony jurgens"},
+{"name": "jim cokato"},
+{"name": "jennifer overton"},
+{"name": "megan dittl"},
+{"name": "paul shawah"},
+{"name": "mike noble"},
+{"name": "julie zielinski"},
+{"name": "ryan k"},
+{"name": "jillian ravenscroft"},
+{"name": "dale gurley"},
+{"name": "heather norvell"},
+{"name": "elizabeth corvino"},
+{"name": "nick aspeslagh"},
+{"name": "derek gutter"},
+{"name": "ana hernandez"},
+{"name": "deborah deux"},
+{"name": "beau graffin"},
+{"name": "genevieve fausett"},
+{"name": "ruben cardenas"},
+{"name": "rob renfro"},
+{"name": "christopher liss"},
+{"name": "arturo arias"},
+{"name": "bruce langston"},
+{"name": "bill pc"},
+{"name": "eric feldman"},
+{"name": "zenaida flores"},
+{"name": "daryl delosreyes"},
+{"name": "august brown"},
+{"name": "michael mcguinness"},
+{"name": "anthony hoang"},
+{"name": "justin dounce"},
+{"name": "stephanie vacuna"},
+{"name": "bob jones"},
+{"name": "daniel oludemi"},
+{"name": "andrea daa"},
+{"name": "mark drescher"},
+{"name": "larry marvin"},
+{"name": "amanda bueno"},
+{"name": "elena shore"},
+{"name": "christine strube"},
+{"name": "glen buchner"},
+{"name": "greg wynne"},
+{"name": "anna sacripanti"},
+{"name": "megan misf"},
+{"name": "brandon woodland"},
+{"name": "ray hair"},
+{"name": "robert mintz"},
+{"name": "casey harvey"},
+{"name": "alex mangen"},
+{"name": "tim zoma"},
+{"name": "amy chung"},
+{"name": "david banner"},
+{"name": "brian chitwood"},
+{"name": "carlos pest"},
+{"name": "barry kryst"},
+{"name": "kevin broas"},
+{"name": "tami bruner"},
+{"name": "jason champps"},
+{"name": "tracie duggard"},
+{"name": "jose virgo"},
+{"name": "perry bro"},
+{"name": "tony saeteurn"},
+{"name": "jim pipolo"},
+{"name": "tim tran"},
+{"name": "tom o'brien"},
+{"name": "casey mac"},
+{"name": "anh nguyen"},
+{"name": "matt salinger"},
+{"name": "tommy poker"},
+{"name": "spencer waldman"},
+{"name": "mei king"},
+{"name": "tim wiltman"},
+{"name": "bill proctor"},
+{"name": "kevin snu"},
+{"name": "chanelle regoli"},
+{"name": "duane geiger"},
+{"name": "marcia nance"},
+{"name": "aaron lauterret"},
+{"name": "jon sum"},
+{"name": "charles tyler"},
+{"name": "kim campbell"},
+{"name": "john tallarico"},
+{"name": "arthur dietze"},
+{"name": "su sim"},
+{"name": "pat surgeon"},
+{"name": "charles mathis"},
+{"name": "laura kruse"},
+{"name": "justin moore"},
+{"name": "garry bettencourt"},
+{"name": "donna winters"},
+{"name": "bob stange"},
+{"name": "bruce deese"},
+{"name": "scott fitzpatrick"},
+{"name": "sam huston"},
+{"name": "george lafrance"},
+{"name": "thomas balcezak"},
+{"name": "robin canetella"},
+{"name": "porter mason"},
+{"name": "jennifer graff"},
+{"name": "chris smith"},
+{"name": "nick malcom"},
+{"name": "fred figeroa"},
+{"name": "andrew dueckman"},
+{"name": "john sharff"},
+{"name": "nichelle brown"},
+{"name": "todd simpson"},
+{"name": "boyd gilkey"},
+{"name": "bob palmer"},
+{"name": "laurence winter"},
+{"name": "judy tran"},
+{"name": "rick clifford"},
+{"name": "justin horvath"},
+{"name": "juan laserna"},
+{"name": "sheri shipman"},
+{"name": "amanda i"},
+{"name": "peggy darnell"},
+{"name": "david blackwell"},
+{"name": "kelly clark"},
+{"name": "tim forzley"},
+{"name": "tommy miller"},
+{"name": "david wu"},
+{"name": "jake estes"},
+{"name": "betsy starr"},
+{"name": "camille ebert"},
+{"name": "kacey fullington"},
+{"name": "eddie re"},
+{"name": "mike promoter"},
+{"name": "bob borgstrom"},
+{"name": "jesse riker"},
+{"name": "bill binford"},
+{"name": "brandy carr"},
+{"name": "ed kanabay"},
+{"name": "rusty legg"},
+{"name": "christian grimm"},
+{"name": "william heestand"},
+{"name": "sheron franklin"},
+{"name": "danny rubinshtein"},
+{"name": "jana keele"},
+{"name": "rich oldach"},
+{"name": "jonathan kile"},
+{"name": "charolette butler"},
+{"name": "teddy tossiant"},
+{"name": "mark mactaggart"},
+{"name": "james williams"},
+{"name": "elaine schoendorf"},
+{"name": "faye bramhall"},
+{"name": "chuck dickson"},
+{"name": "michael matthew"},
+{"name": "elliot cunningham"},
+{"name": "george stewart"},
+{"name": "rick lereaux"},
+{"name": "evan brownstein"},
+{"name": "elizabeth mall"},
+{"name": "john toppari"},
+{"name": "craig jaffrey"},
+{"name": "steven lieberman"},
+{"name": "john shedd"},
+{"name": "paul paluzzi"},
+{"name": "tina adkison"},
+{"name": "gisele wegleitner"},
+{"name": "gary oram"},
+{"name": "art murray"},
+{"name": "andrew stout"},
+{"name": "robert pudell"},
+{"name": "trang tran"},
+{"name": "beatriz giraldo"},
+{"name": "dave machika"},
+{"name": "josh rowe"},
+{"name": "joe grover"},
+{"name": "tom o'conner"},
+{"name": "paul o'rourke"},
+{"name": "janet engler"},
+{"name": "isabella argueso"},
+{"name": "don garner"},
+{"name": "ed port"},
+{"name": "james royal"},
+{"name": "george maguire"},
+{"name": "dan bowman"},
+{"name": "amber bantz"},
+{"name": "peter noble"},
+{"name": "layne hoote"},
+{"name": "misty martin"},
+{"name": "matthew stewart"},
+{"name": "marilyn schimdt"},
+{"name": "jean fehl"},
+{"name": "keri dugan"},
+{"name": "don schwartz"},
+{"name": "chad duncan"},
+{"name": "roseanne brandon"},
+{"name": "paul valentine"},
+{"name": "helen reingold"},
+{"name": "christine finnigan"},
+{"name": "dan bergmann"},
+{"name": "linda coleman"},
+{"name": "joel ehler"},
+{"name": "jacob linares"},
+{"name": "christy ragland"},
+{"name": "sarah mcging"},
+{"name": "frank mao"},
+{"name": "tammy rock"},
+{"name": "carlos malone"},
+{"name": "katie c"},
+{"name": "george gramaglia"},
+{"name": "ellen clean"},
+{"name": "jason hertlein"},
+{"name": "dean odegaard"},
+{"name": "robert kleck"},
+{"name": "lynn keller"},
+{"name": "chris bradley"},
+{"name": "megan vasu"},
+{"name": "michelle robertson"},
+{"name": "james mora"},
+{"name": "corey tucker"},
+{"name": "ann chou"},
+{"name": "kate anderson"},
+{"name": "jennifer guerera"},
+{"name": "bill ladouceur"},
+{"name": "nancy martinez"},
+{"name": "kirk nervis"},
+{"name": "dale heintze"},
+{"name": "marc moens"},
+{"name": "grant jarvis"},
+{"name": "brian linver"},
+{"name": "michael smedley"},
+{"name": "ashley dill"},
+{"name": "timmy rich"},
+{"name": "pat frazer"},
+{"name": "joey hardrock"},
+{"name": "sandra blackhawk"},
+{"name": "danielle pulido"},
+{"name": "gary lang"},
+{"name": "ed galvin"},
+{"name": "shawn dumas"},
+{"name": "jim wilber"},
+{"name": "bo cell"},
+{"name": "nicolette brown"},
+{"name": "lou shipley"},
+{"name": "patrick bartlett"},
+{"name": "julianna rivas"},
+{"name": "demetrius hollingsworth"},
+{"name": "justin grim"},
+{"name": "marc schwartz"},
+{"name": "tim rep"},
+{"name": "james dorfman"},
+{"name": "vickie woznick"},
+{"name": "mark deeulio"},
+{"name": "robert nagel"},
+{"name": "rafael egurrola"},
+{"name": "oliver morris"},
+{"name": "krishna rangarajan"},
+{"name": "stuart smith"},
+{"name": "jazmine washington"},
+{"name": "tom laborde"},
+{"name": "dennis bever"},
+{"name": "alba llanes"},
+{"name": "hollis booker"},
+{"name": "lynn werle"},
+{"name": "tony muniz"},
+{"name": "stanley louis"},
+{"name": "don ferguson"},
+{"name": "alicia dove"},
+{"name": "david hunt"},
+{"name": "kevin francis"},
+{"name": "natalya sobolova"},
+{"name": "marvin reid"},
+{"name": "robert hathorn"},
+{"name": "keith smith"},
+{"name": "patrica yanez"},
+{"name": "shannon glass"},
+{"name": "ginger brazil"},
+{"name": "jay davis"},
+{"name": "michael henschell"},
+{"name": "pearl rose"},
+{"name": "dana berardi"},
+{"name": "ronnie jaquez"},
+{"name": "margaret kwan"},
+{"name": "bibi work"},
+{"name": "sandi shadbolt"},
+{"name": "debi raphael"},
+{"name": "tamar quintana"},
+{"name": "grady er"},
+{"name": "leon ricks"},
+{"name": "marvin mcmillan"},
+{"name": "joseph albergo"},
+{"name": "milford exterminating"},
+{"name": "francisco angara"},
+{"name": "daniel parks"},
+{"name": "cliff sara"},
+{"name": "eric spelley"},
+{"name": "amy socha"},
+{"name": "angie defilippi"},
+{"name": "adam l"},
+{"name": "scott murphy"},
+{"name": "jill mccoy"},
+{"name": "matt michig"},
+{"name": "april murray"},
+{"name": "greg santowski"},
+{"name": "phil composer"},
+{"name": "johnny greek"},
+{"name": "carrie poe"},
+{"name": "shauna carlson"},
+{"name": "ron carli"},
+{"name": "todd davisson"},
+{"name": "janet cross"},
+{"name": "george hessenthaler"},
+{"name": "veronika galvez"},
+{"name": "sarah huyck"},
+{"name": "craig tyler"},
+{"name": "carol bryja"},
+{"name": "michael zerbel"},
+{"name": "sean quintana"},
+{"name": "mario faria"},
+{"name": "cheryl denoi"},
+{"name": "kurt reiper"},
+{"name": "david bloom"},
+{"name": "herman terry"},
+{"name": "renae sommers"},
+{"name": "wally lynn"},
+{"name": "chad waltman"},
+{"name": "heidi rios"},
+{"name": "don caldera"},
+{"name": "jackie reese"},
+{"name": "justin lin"},
+{"name": "ronald johnson"},
+{"name": "lindsey mockenhaupt"},
+{"name": "david korse"},
+{"name": "walter miller"},
+{"name": "danny bullock"},
+{"name": "brian shuman"},
+{"name": "darla cook"},
+{"name": "ashley green"},
+{"name": "rob press"},
+{"name": "art klok"},
+{"name": "derek roe"},
+{"name": "eric mmv"},
+{"name": "carline lubin"},
+{"name": "sarah downstairs"},
+{"name": "katrina j"},
+{"name": "mara higgins"},
+{"name": "chad tomaszewski"},
+{"name": "frank castanea"},
+{"name": "sara knoester"},
+{"name": "todd parids"},
+{"name": "jeff sieber"},
+{"name": "jim bennitt"},
+{"name": "david croom"},
+{"name": "bobby chianese"},
+{"name": "freddy king"},
+{"name": "kimberly allen"},
+{"name": "paul backstrom"},
+{"name": "larry matthews"},
+{"name": "ellen scurlock"},
+{"name": "john mccready"},
+{"name": "andy hoopengardner"},
+{"name": "shin shibata"},
+{"name": "nancy cuz"},
+{"name": "pat neff"},
+{"name": "greg tallman"},
+{"name": "omar buford"},
+{"name": "carlos reteria"},
+{"name": "ron hillbrand"},
+{"name": "charles breyer"},
+{"name": "bryan rodriguez"},
+{"name": "jenny wagner"},
+{"name": "lee mattson"},
+{"name": "scot rosendahl"},
+{"name": "scott herrick"},
+{"name": "janet wilson"},
+{"name": "nancy mcintire"},
+{"name": "alicia getchius"},
+{"name": "jeffery boborwitz"},
+{"name": "nancy gakere"},
+{"name": "doug sturges"},
+{"name": "clinton weckesser"},
+{"name": "charlotte cain"},
+{"name": "tyler harmon"},
+{"name": "marshall eric"},
+{"name": "latonya coats"},
+{"name": "phyllis shank"},
+{"name": "natalie lawson"},
+{"name": "tamara cell"},
+{"name": "gary lucas"},
+{"name": "dominic digiacomo"},
+{"name": "sheila cell"},
+{"name": "rachel dyer"},
+{"name": "irene alvarado"},
+{"name": "erika castaneda"},
+{"name": "casey brady"},
+{"name": "bruce robinson"},
+{"name": "jo rogers"},
+{"name": "brenda salyers"},
+{"name": "kevin lunsgarten"},
+{"name": "john mullens"},
+{"name": "steve beermann"},
+{"name": "john sawyer"},
+{"name": "shawn hines"},
+{"name": "jan bootcheck"},
+{"name": "andy cook"},
+{"name": "eddie r"},
+{"name": "chad gates"},
+{"name": "donna thompson"},
+{"name": "dena danz"},
+{"name": "jeff larose"},
+{"name": "diane phillips"},
+{"name": "tracy ryan"},
+{"name": "gil pritt"},
+{"name": "marc porterfield"},
+{"name": "angie phillippi"},
+{"name": "rhiannon fiocchi"},
+{"name": "judy chaffe"},
+{"name": "dave bolanzia"},
+{"name": "craig olive"},
+{"name": "kimberly mckinzey"},
+{"name": "lakeshia davis"},
+{"name": "mike wysocki"},
+{"name": "heidi rozein"},
+{"name": "james monmouth"},
+{"name": "kelly spaulding"},
+{"name": "jamie banks"},
+{"name": "angela cleveland"},
+{"name": "cassandra hoye"},
+{"name": "kristi tyree"},
+{"name": "louis g"},
+{"name": "pat meek"},
+{"name": "kylie muir"},
+{"name": "forrest bao"},
+{"name": "nicole stogner"},
+{"name": "jackie marshall"},
+{"name": "rico barnes"},
+{"name": "joe mills"},
+{"name": "michael stansbury"},
+{"name": "walter statler"},
+{"name": "jeni fortunato"},
+{"name": "vicki wong"},
+{"name": "ed hope"},
+{"name": "keith stansfeild"},
+{"name": "karyn hunsaker"},
+{"name": "jack peterson"},
+{"name": "josh stowe"},
+{"name": "george pager"},
+{"name": "star crawford"},
+{"name": "joan grayman"},
+{"name": "matt miller"},
+{"name": "ken keith"},
+{"name": "ruth printer"},
+{"name": "pamella elaine"},
+{"name": "william zhe"},
+{"name": "cynthia wiseman"},
+{"name": "curt maki"},
+{"name": "nikki knafulc"},
+{"name": "chris gaffney"},
+{"name": "pete almazan"},
+{"name": "karen hays"},
+{"name": "john mohamad"},
+{"name": "jim schrader"},
+{"name": "miguel ayala"},
+{"name": "marie hayakawa"},
+{"name": "jim greco"},
+{"name": "stan bostwick"},
+{"name": "ryan grav"},
+{"name": "jessika jennings"},
+{"name": "carly engelbart"},
+{"name": "charlie matteson"},
+{"name": "john jackson"},
+{"name": "john lipscomb"},
+{"name": "ronald laing"},
+{"name": "kimberly segovia"},
+{"name": "margaret jacobs"},
+{"name": "chad hart"},
+{"name": "hannah tran"},
+{"name": "bryan kruskol"},
+{"name": "bruce gundersen"},
+{"name": "tony phillip"},
+{"name": "brian ford"},
+{"name": "lynn monaghan"},
+{"name": "kevin byrne"},
+{"name": "amanda w"},
+{"name": "greg astle"},
+{"name": "ted stumpf"},
+{"name": "michael luther"},
+{"name": "jacque derksen"},
+{"name": "jo salvestrini"},
+{"name": "gordon inman"},
+{"name": "jim dair"},
+{"name": "peggy horton"},
+{"name": "marshall hancock"},
+{"name": "grant hay"},
+{"name": "marlene edwards"},
+{"name": "josh white"},
+{"name": "ara bang"},
+{"name": "duncan card"},
+{"name": "adam galeon"},
+{"name": "aaron hinkle"},
+{"name": "james client"},
+{"name": "mark vandersall"},
+{"name": "lance cowart"},
+{"name": "scott papineau"},
+{"name": "michelle harwood"},
+{"name": "chris wright"},
+{"name": "shane downey"},
+{"name": "beatriz vasconez"},
+{"name": "angela schmidt"},
+{"name": "tyrell hickman"},
+{"name": "gary bisel"},
+{"name": "ryan kelly"},
+{"name": "daniel belanger"},
+{"name": "ed cumming"},
+{"name": "karina alves"},
+{"name": "sam simmons"},
+{"name": "german castillo"},
+{"name": "james wharburton"},
+{"name": "alvin cheng"},
+{"name": "patrick lynich"},
+{"name": "betty peralta"},
+{"name": "jeff lockyer"},
+{"name": "colby campbell"},
+{"name": "jenna holt"},
+{"name": "alyssa h"},
+{"name": "joey payne"},
+{"name": "jessica trudell"},
+{"name": "paul thompson"},
+{"name": "shane tenhet"},
+{"name": "shane sommers"},
+{"name": "marshall ford"},
+{"name": "eddie u"},
+{"name": "alfred habash"},
+{"name": "gwen brooks"},
+{"name": "anne putnam"},
+{"name": "lori nelson"},
+{"name": "debbie cohen"},
+{"name": "lisa vickers"},
+{"name": "taylor miller"},
+{"name": "judy zellen"},
+{"name": "parthenia terrace"},
+{"name": "meghan m"},
+{"name": "carey alcott"},
+{"name": "phyllis lichtenstein"},
+{"name": "shelly bar"},
+{"name": "teresa grice"},
+{"name": "john carline"},
+{"name": "michael galloway"},
+{"name": "bill blount"},
+{"name": "nancy macek"},
+{"name": "wendy mcintyre"},
+{"name": "kristi davis"},
+{"name": "joe arndt"},
+{"name": "kim giles"},
+{"name": "jim andritsch"},
+{"name": "bell mobility"},
+{"name": "pat dougherty"},
+{"name": "bill mccoy"},
+{"name": "patrick kelly"},
+{"name": "debbie roeske"},
+{"name": "greg lang"},
+{"name": "marc lipkin"},
+{"name": "emily saunders"},
+{"name": "stacey lundquist"},
+{"name": "jonathan stuffer"},
+{"name": "tammy brackett"},
+{"name": "chantelle aders"},
+{"name": "susan hadley"},
+{"name": "brett mosher"},
+{"name": "joel kellumns"},
+{"name": "neil cox"},
+{"name": "thresa eason"},
+{"name": "carmen montez"},
+{"name": "virginia forney"},
+{"name": "stephanie hansen"},
+{"name": "kenneth weiss"},
+{"name": "neal oliver"},
+{"name": "jane burson"},
+{"name": "philip cole"},
+{"name": "niki mercer"},
+{"name": "ralph lindenblatt"},
+{"name": "ron gelet"},
+{"name": "terry pyper"},
+{"name": "lee kell"},
+{"name": "erma tyson"},
+{"name": "susan infantino"},
+{"name": "karen lloyd"},
+{"name": "micheal prill"},
+{"name": "grady florida"},
+{"name": "pete filion"},
+{"name": "marie jones"},
+{"name": "robert garza"},
+{"name": "chong yen"},
+{"name": "don clapper"},
+{"name": "charles jobe"},
+{"name": "tom feeley"},
+{"name": "mark las"},
+{"name": "bill sonnhalter"},
+{"name": "jimmy bugarin"},
+{"name": "paul marshal"},
+{"name": "shannon valcich"},
+{"name": "anita t"},
+{"name": "brenda lake"},
+{"name": "irma hernandez"},
+{"name": "angela inman"},
+{"name": "ann schwartz"},
+{"name": "danielle pittman"},
+{"name": "michael kong"},
+{"name": "jeff skeldon"},
+{"name": "rick audette"},
+{"name": "melina alvarado"},
+{"name": "tom erickson"},
+{"name": "bobby chavez"},
+{"name": "pete ww"},
+{"name": "ramona mitchell"},
+{"name": "randy gascoigne"},
+{"name": "devorah tradburks"},
+{"name": "daniel magnusson"},
+{"name": "wes hodgson"},
+{"name": "richard c"},
+{"name": "roy stearns"},
+{"name": "kelly wauchope"},
+{"name": "min chester"},
+{"name": "ernest white"},
+{"name": "cody bonds"},
+{"name": "zoe cabral"},
+{"name": "mike flames"},
+{"name": "richard grey"},
+{"name": "joe bolley"},
+{"name": "jennifer peacock"},
+{"name": "kate guppy"},
+{"name": "stephan swanson"},
+{"name": "sam schlesinger"},
+{"name": "ken eheart"},
+{"name": "kristine joson"},
+{"name": "andy sykes"},
+{"name": "kirk hobart"},
+{"name": "hanh hanoi"},
+{"name": "albert einstein"},
+{"name": "evangeline alcantara"},
+{"name": "chris laffey"},
+{"name": "hugh bello"},
+{"name": "erin c"},
+{"name": "jess smith"},
+{"name": "danielle dowling"},
+{"name": "charles hunter"},
+{"name": "mark schonbrod"},
+{"name": "mike hammerslug"},
+{"name": "kimberly kirchner"},
+{"name": "andy coblentz"},
+{"name": "jeanette flowers"},
+{"name": "dick mendres"},
+{"name": "tim mahan"},
+{"name": "vickie home"},
+{"name": "eric maybaum"},
+{"name": "peter saliba"},
+{"name": "beth earls"},
+{"name": "diane hawkins"},
+{"name": "joey mekhayel"},
+{"name": "john chicarella"},
+{"name": "sarah stitz"},
+{"name": "debi barber"},
+{"name": "rachael hopper"},
+{"name": "mike flick"},
+{"name": "freddy zarka"},
+{"name": "marylynn lavigna"},
+{"name": "lynette sharaz"},
+{"name": "tyler holly"},
+{"name": "mariah j"},
+{"name": "suzanne clay"},
+{"name": "lanny billings"},
+{"name": "brian dengler"},
+{"name": "katie schaub"},
+{"name": "greg cook"},
+{"name": "jenny manbeck"},
+{"name": "jeremy fna"},
+{"name": "jeremy shephard"},
+{"name": "david mckay"},
+{"name": "charles gottlieb"},
+{"name": "ann schleicher"},
+{"name": "john maloney"},
+{"name": "spencer kuttler"},
+{"name": "simone sibert"},
+{"name": "ellen bodkins"},
+{"name": "shauna bcbg"},
+{"name": "michael winer"},
+{"name": "larry camp"},
+{"name": "ross levi"},
+{"name": "david greene"},
+{"name": "dan olschwang"},
+{"name": "miss amazin"},
+{"name": "chris robers"},
+{"name": "norma treague"},
+{"name": "craig newton"},
+{"name": "cherry yates"},
+{"name": "hugh bryan"},
+{"name": "lawrence fabian"},
+{"name": "tiffany mitchell"},
+{"name": "alan mcelroy"},
+{"name": "bob hensley"},
+{"name": "karen vehlow"},
+{"name": "george shindo"},
+{"name": "darrell hersey"},
+{"name": "ciara roseville"},
+{"name": "brian yeh"},
+{"name": "sherri coffman"},
+{"name": "paul hahn"},
+{"name": "bob cullen"},
+{"name": "trudy mcculloch"},
+{"name": "jan smith"},
+{"name": "annette olivia"},
+{"name": "steve iwcc"},
+{"name": "isaiah harris"},
+{"name": "linda bender"},
+{"name": "john h"},
+{"name": "todd webber"},
+{"name": "adam fivenson"},
+{"name": "joe cole"},
+{"name": "mark cell"},
+{"name": "nelson chui"},
+{"name": "zack bar"},
+{"name": "jeffrey dallas"},
+{"name": "derick takamine"},
+{"name": "daniel n"},
+{"name": "whitney strain"},
+{"name": "jane cusack"},
+{"name": "donna gray"},
+{"name": "randy moallankamp"},
+{"name": "mary riso"},
+{"name": "mark pedroncelli"},
+{"name": "tom nolan"},
+{"name": "chris patulis"},
+{"name": "bonnie choi"},
+{"name": "brian mcelfresh"},
+{"name": "eric olsen"},
+{"name": "neil merchantson"},
+{"name": "brooke clark"},
+{"name": "rebecca hodgers"},
+{"name": "wes hayden"},
+{"name": "alise churchill"},
+{"name": "tiffany parsons"},
+{"name": "craig peters"},
+{"name": "kieth kling"},
+{"name": "joel evans"},
+{"name": "larry lacey"},
+{"name": "bruce coll"},
+{"name": "lauren ashley"},
+{"name": "erick mccallister"},
+{"name": "brigid macdonald"},
+{"name": "al jon"},
+{"name": "jeff tropple"},
+{"name": "billy matranga"},
+{"name": "tim kay"},
+{"name": "ryan mcdonalds"},
+{"name": "kieth kruger"},
+{"name": "berna regalado"},
+{"name": "chris singer"},
+{"name": "donna argall"},
+{"name": "mark decker"},
+{"name": "chris karajanis"},
+{"name": "jon folsom"},
+{"name": "joshua son"},
+{"name": "michael lambert"},
+{"name": "richard behmke"},
+{"name": "todd tintorri"},
+{"name": "abel rodriguez"},
+{"name": "jeff lowe"},
+{"name": "alex abogado"},
+{"name": "mary hughes"},
+{"name": "tom romeo"},
+{"name": "dennis brown"},
+{"name": "rhonda hedtke"},
+{"name": "pat mcmackin"},
+{"name": "will broker"},
+{"name": "andreas labrakis"},
+{"name": "barbara mcmanus"},
+{"name": "don warnet"},
+{"name": "crystal kerr"},
+{"name": "mike downey"},
+{"name": "noel nitinthorn"},
+{"name": "chris abbott"},
+{"name": "tara kenyon"},
+{"name": "julia brannan"},
+{"name": "jason philips"},
+{"name": "wes harris"},
+{"name": "john tucker"},
+{"name": "brandon alltel"},
+{"name": "noelle richards"},
+{"name": "jim adelsick"},
+{"name": "andy ludcus"},
+{"name": "sherry xxxxx"},
+{"name": "sean woodard"},
+{"name": "jim parrett"},
+{"name": "jillian christison"},
+{"name": "terry mostrom"},
+{"name": "eddy rumps"},
+{"name": "mike shiner"},
+{"name": "susan odem"},
+{"name": "taylor howell"},
+{"name": "ryan wildman"},
+{"name": "brook olson"},
+{"name": "derek best"},
+{"name": "alyssa kaufman"},
+{"name": "keith white"},
+{"name": "dave allway"},
+{"name": "tony level"},
+{"name": "katie home"},
+{"name": "trudy sidener"},
+{"name": "logan shidawara"},
+{"name": "don home"},
+{"name": "tom jordan"},
+{"name": "tyler aiken"},
+{"name": "john chatowski"},
+{"name": "jackie model"},
+{"name": "donnie bledsoe"},
+{"name": "ray ny"},
+{"name": "robert jameson"},
+{"name": "jessica g'gf"},
+{"name": "daniel dooley"},
+{"name": "susan goldberg"},
+{"name": "alec lanari"},
+{"name": "dee martin"},
+{"name": "david bartley"},
+{"name": "jim mcdaniel"},
+{"name": "john munsey"},
+{"name": "laura eck"},
+{"name": "blake mcneill"},
+{"name": "kate donaldson"},
+{"name": "cheri peterson"},
+{"name": "mark short"},
+{"name": "dave loomba"},
+{"name": "anthony t"},
+{"name": "arturo rosales"},
+{"name": "jonathan grahm"},
+{"name": "shelley nix"},
+{"name": "richie cohen"},
+{"name": "ian prosser"},
+{"name": "dan loyer"},
+{"name": "ann goggins"},
+{"name": "tom ta"},
+{"name": "leslie hill"},
+{"name": "alejandro reyes"},
+{"name": "dan decker"},
+{"name": "brittany puffer"},
+{"name": "josephine irlbacher"},
+{"name": "bill moore"},
+{"name": "pedro zamora"},
+{"name": "timmy remi"},
+{"name": "andrew haddad"},
+{"name": "charles matthews"},
+{"name": "kathryn theissen"},
+{"name": "michele thomas"},
+{"name": "andy burton"},
+{"name": "alisha williams"},
+{"name": "omar duran"},
+{"name": "thelma jenkins"},
+{"name": "sheila schaffer"},
+{"name": "lenard tyndell"},
+{"name": "eddie ryono"},
+{"name": "vanessa kato"},
+{"name": "jeanie hernandez"},
+{"name": "jeff pryor"},
+{"name": "michael parsons"},
+{"name": "holly ordway"},
+{"name": "charlie kisner"},
+{"name": "phil cuomo"},
+{"name": "alma meli"},
+{"name": "jason hilkey"},
+{"name": "john baumert"},
+{"name": "jodi gabl"},
+{"name": "brooks salon"},
+{"name": "georgina hill"},
+{"name": "dan acheson"},
+{"name": "ginny adams"},
+{"name": "erica cooper"},
+{"name": "andrew norton"},
+{"name": "tammy meeks"},
+{"name": "kenneth rose"},
+{"name": "brandon fields"},
+{"name": "amy cell"},
+{"name": "chris cooper"},
+{"name": "rebecca trujillo"},
+{"name": "charlie garcia"},
+{"name": "pete schulz"},
+{"name": "vince mira"},
+{"name": "beth ufc"},
+{"name": "laura segarra"},
+{"name": "steven penn"},
+{"name": "alex cabrerra"},
+{"name": "richard gelinas"},
+{"name": "cheryl trout"},
+{"name": "terry calvin"},
+{"name": "randy shoemaker"},
+{"name": "josh gould"},
+{"name": "dan howell"},
+{"name": "desiree macias"},
+{"name": "mike herbold"},
+{"name": "mai n"},
+{"name": "becky jenks"},
+{"name": "ashton kovacs"},
+{"name": "dick nowacki"},
+{"name": "aaron band"},
+{"name": "vince zalapi"},
+{"name": "doug lenhoff"},
+{"name": "patty encinas"},
+{"name": "carlo madia"},
+{"name": "joy scott"},
+{"name": "vickey nguyen"},
+{"name": "lynn hillard"},
+{"name": "jonathan robinson"},
+{"name": "jenny brantlee"},
+{"name": "nick teusch"},
+{"name": "mike danyi"},
+{"name": "brent v"},
+{"name": "laura cherry"},
+{"name": "rodney zooyork"},
+{"name": "liz kress"},
+{"name": "ann olson"},
+{"name": "james flannery"},
+{"name": "donna lamarre"},
+{"name": "nadia chaudry"},
+{"name": "mindy parsons"},
+{"name": "charles cornwell"},
+{"name": "jay howell"},
+{"name": "chris chivers"},
+{"name": "bob chianese"},
+{"name": "sha ba"},
+{"name": "danny bubbli"},
+{"name": "frank frydrych"},
+{"name": "tony guard"},
+{"name": "bob ibuilder"},
+{"name": "michael mclntyre"},
+{"name": "jayna marques"},
+{"name": "ed altemeier"},
+{"name": "anette goldman"},
+{"name": "julio lucero"},
+{"name": "mark pingry"},
+{"name": "warren ragsdale"},
+{"name": "brain work"},
+{"name": "john stogis"},
+{"name": "aaron nameless"},
+{"name": "jacob chernov"},
+{"name": "glen rupe"},
+{"name": "alex stikhilyas"},
+{"name": "ahmad hazouri"},
+{"name": "max sports"},
+{"name": "len sisk"},
+{"name": "eric marriott"},
+{"name": "alice clark"},
+{"name": "deborah hall"},
+{"name": "drew webber"},
+{"name": "jennifer waters"},
+{"name": "mary eidson"},
+{"name": "gary perl"},
+{"name": "michelle gaona"},
+{"name": "ross finke"},
+{"name": "matt xxxxx"},
+{"name": "jonathan whitcomb"},
+{"name": "cheryl aubuchon"},
+{"name": "matt sharuga"},
+{"name": "tammy venkler"},
+{"name": "melanie longworth"},
+{"name": "scott michael"},
+{"name": "steve peck"},
+{"name": "bob falzone"},
+{"name": "joe roberts"},
+{"name": "craig roberts"},
+{"name": "brian fow"},
+{"name": "marcela rojas"},
+{"name": "angela carney"},
+{"name": "valerie grinman"},
+{"name": "alicia greene"},
+{"name": "wendy spradlin"},
+{"name": "jessica ball"},
+{"name": "frank lomax"},
+{"name": "mike consoli"},
+{"name": "adam ziccardi"},
+{"name": "ashley heb"},
+{"name": "greg hardester"},
+{"name": "sergio asef"},
+{"name": "aaron adams"},
+{"name": "andrew sh"},
+{"name": "mike lanigan"},
+{"name": "sam meraw"},
+{"name": "sherry walker"},
+{"name": "neville brathwaite"},
+{"name": "brad carson"},
+{"name": "bryan price"},
+{"name": "percy weathington"},
+{"name": "carlo power"},
+{"name": "roy lippman"},
+{"name": "matt luongo"},
+{"name": "kris olstead"},
+{"name": "walter snook"},
+{"name": "terry pollick"},
+{"name": "keith bricklemyer"},
+{"name": "billy canipe"},
+{"name": "jeff cuteboy"},
+{"name": "joyce lee"},
+{"name": "timmy cell"},
+{"name": "carmen sanders"},
+{"name": "james hunt"},
+{"name": "david frederick"},
+{"name": "jennifer lau"},
+{"name": "matt dempsey"},
+{"name": "sheila mccorvey"},
+{"name": "isabel buzby"},
+{"name": "robert castro"},
+{"name": "janet barnes"},
+{"name": "robert lucisano"},
+{"name": "william barbier"},
+{"name": "brian marks"},
+{"name": "ann herzog"},
+{"name": "cliff showell"},
+{"name": "keli johnston"},
+{"name": "nick parilla"},
+{"name": "kelly deviney"},
+{"name": "steve phoenix"},
+{"name": "kim q"},
+{"name": "flo tech"},
+{"name": "debra ledsinger"},
+{"name": "megan malone"},
+{"name": "ray repairs"},
+{"name": "noah jacobson"},
+{"name": "pam cab"},
+{"name": "jeff schick"},
+{"name": "erin berenson"},
+{"name": "ed ward"},
+{"name": "miranda bydone"},
+{"name": "michael bonanno"},
+{"name": "karen williams"},
+{"name": "anne o'brien"},
+{"name": "scott brodrick"},
+{"name": "king cell"},
+{"name": "jessica samson"},
+{"name": "charles allgood"},
+{"name": "greg rankin"},
+{"name": "terry mcdermott"},
+{"name": "april vasquez"},
+{"name": "andy coventry"},
+{"name": "garry canmore"},
+{"name": "alisha info"},
+{"name": "susie kladko"},
+{"name": "nelson jurica"},
+{"name": "merle nishimura"},
+{"name": "patrick carroll"},
+{"name": "sharon ringier"},
+{"name": "adam stever"},
+{"name": "jessica powelcup"},
+{"name": "jon ho"},
+{"name": "jennifer arellano"},
+{"name": "janine kurnoff"},
+{"name": "natalie mack"},
+{"name": "jarrod larocco"},
+{"name": "marty diebold"},
+{"name": "carol barroso"},
+{"name": "bill berry"},
+{"name": "michael morant"},
+{"name": "ted ozuna"},
+{"name": "robert weenig"},
+{"name": "allen chen"},
+{"name": "ty christensen"},
+{"name": "bennett wright"},
+{"name": "becky hoffer"},
+{"name": "byron dentler"},
+{"name": "jim rinke"},
+{"name": "jake birkholtz"},
+{"name": "duane oxenham"},
+{"name": "cathy mcgau"},
+{"name": "caroline parent"},
+{"name": "alma rivera"},
+{"name": "gay brian"},
+{"name": "nancy vandergrift"},
+{"name": "bill parkerson"},
+{"name": "mark bonacci"},
+{"name": "ron cole"},
+{"name": "dina raniga"},
+{"name": "florence russell"},
+{"name": "david sommer"},
+{"name": "brandon ny"},
+{"name": "paul larsen"},
+{"name": "diego g"},
+{"name": "danielle korba"},
+{"name": "andy roberts"},
+{"name": "andrew vogt"},
+{"name": "sharron huffman"},
+{"name": "sam kiefer"},
+{"name": "mike toxic"},
+{"name": "nick weinart"},
+{"name": "laurie flynn"},
+{"name": "mary vallesteros"},
+{"name": "angelica garcia"},
+{"name": "donovan morrison"},
+{"name": "amy catlet"},
+{"name": "ralph peterson"},
+{"name": "lia hicks"},
+{"name": "angel gonzalez"},
+{"name": "tim dunleavy"},
+{"name": "tim heinze"},
+{"name": "john redstone"},
+{"name": "katie dorn"},
+{"name": "lorraine o'leary"},
+{"name": "steve vollhardt"},
+{"name": "dan brabec"},
+{"name": "sandra chaffin"},
+{"name": "cory skillern"},
+{"name": "dwayne blackamore"},
+{"name": "kathryn pendergast"},
+{"name": "glen thorne"},
+{"name": "brent jones"},
+{"name": "karen buck"},
+{"name": "richard gomberg"},
+{"name": "john copenhaver"},
+{"name": "zenobia ealey"},
+{"name": "george harrison"},
+{"name": "emilie paige"},
+{"name": "austin haye"},
+{"name": "peter mitrik"},
+{"name": "sue schwegler"},
+{"name": "jake hall"},
+{"name": "tom learman"},
+{"name": "julie bridge"},
+{"name": "don brodnansky"},
+{"name": "richard graber"},
+{"name": "mary treadway"},
+{"name": "ross ludwig"},
+{"name": "mark bornstein"},
+{"name": "cheryl bielema"},
+{"name": "dave spence"},
+{"name": "mary anna"},
+{"name": "darryl stamper"},
+{"name": "matt grove"},
+{"name": "kitty hailey"},
+{"name": "jo harris"},
+{"name": "joel johnson"},
+{"name": "katina ahrenholtz"},
+{"name": "julia robertson"},
+{"name": "anna ward"},
+{"name": "chris herndon"},
+{"name": "christine cummings"},
+{"name": "tommy iorizzo"},
+{"name": "dave ruelas"},
+{"name": "jayme rea"},
+{"name": "sue kinch"},
+{"name": "joe ocasio"},
+{"name": "jenni steel"},
+{"name": "grace simmons"},
+{"name": "charles estell"},
+{"name": "tammy almond"},
+{"name": "erika kirkland"},
+{"name": "scott hedrick"},
+{"name": "will att"},
+{"name": "christopher suknundun"},
+{"name": "elizabeth rybicki"},
+{"name": "karl shannon"},
+{"name": "dan karp"},
+{"name": "john kirk"},
+{"name": "mike bianco"},
+{"name": "ana sandoval"},
+{"name": "josh valk"},
+{"name": "martin glick"},
+{"name": "kaylee l"},
+{"name": "marvin estes"},
+{"name": "dudley beene"},
+{"name": "jennifer bianchini"},
+{"name": "ronnie burrough"},
+{"name": "joe lipman"},
+{"name": "leslie kight"},
+{"name": "bobby loco"},
+{"name": "wesley woods"},
+{"name": "eddie dulles"},
+{"name": "mary hunter"},
+{"name": "mark remey"},
+{"name": "henry ortega"},
+{"name": "robby overvliet"},
+{"name": "gary keller"},
+{"name": "peter schwartz"},
+{"name": "tony bouffard"},
+{"name": "paul doroshuk"},
+{"name": "moshe stutman"},
+{"name": "jessica stout"},
+{"name": "scott mcgill"},
+{"name": "kristi bitoff"},
+{"name": "todd peters"},
+{"name": "robert marples"},
+{"name": "matthew cannon"},
+{"name": "dianne kron"},
+{"name": "adam goldstien"},
+{"name": "todd wilkenson"},
+{"name": "grace balaoro"},
+{"name": "tyrone dipset"},
+{"name": "danny pentin"},
+{"name": "oliver lei"},
+{"name": "jerry schmeiling"},
+{"name": "charles clawson"},
+{"name": "matt pof"},
+{"name": "david wilkes"},
+{"name": "rob woolley"},
+{"name": "georgia strong"},
+{"name": "jennifer pearson"},
+{"name": "stan brown"},
+{"name": "kristen pensivy"},
+{"name": "john marovic"},
+{"name": "david stanton"},
+{"name": "steven copen"},
+{"name": "wade johnson"},
+{"name": "david drews"},
+{"name": "brent priday"},
+{"name": "carolyn zucker"},
+{"name": "tony saiz"},
+{"name": "andres rodriguez"},
+{"name": "bryan lederhouse"},
+{"name": "kit bruce"},
+{"name": "dannielle sidekick"},
+{"name": "bob klee"},
+{"name": "terry stepps"},
+{"name": "lana mareca"},
+{"name": "art landis"},
+{"name": "michael willet"},
+{"name": "jose felix"},
+{"name": "paul survival"},
+{"name": "bruce barnet"},
+{"name": "karla wynia"},
+{"name": "eddie vargas"},
+{"name": "anja eggenberger"},
+{"name": "tyler gma"},
+{"name": "kristen wilkes"},
+{"name": "jenna kootstra"},
+{"name": "glenda luft"},
+{"name": "cathy pierce"},
+{"name": "nicole stewart"},
+{"name": "carrie lynn"},
+{"name": "brian roe"},
+{"name": "kyle scott"},
+{"name": "michelle minchew"},
+{"name": "marvin brooks"},
+{"name": "richard sones"},
+{"name": "joseph dimaio"},
+{"name": "andrea wooten"},
+{"name": "ashley q"},
+{"name": "paul cuttingham"},
+{"name": "shelley smith"},
+{"name": "andre lane"},
+{"name": "marcia barkoff"},
+{"name": "carrie steele"},
+{"name": "paul callis"},
+{"name": "chin rodney"},
+{"name": "pauline david"},
+{"name": "devin marquez{v}"},
+{"name": "monique rush"},
+{"name": "kareem hudson"},
+{"name": "dean flowers"},
+{"name": "frank jones"},
+{"name": "jack henderson"},
+{"name": "mary leon"},
+{"name": "danny butler"},
+{"name": "jose mendosa"},
+{"name": "carolyn adler"},
+{"name": "robert reaney"},
+{"name": "steve barrys"},
+{"name": "debra marr"},
+{"name": "fred godinez"},
+{"name": "tim price"},
+{"name": "frank mirra"},
+{"name": "sarah matt"},
+{"name": "john cumpstone"},
+{"name": "linda msg"},
+{"name": "gene wheeler"},
+{"name": "john rudder"},
+{"name": "betty gordon"},
+{"name": "paul dottori"},
+{"name": "granville rocksolid"},
+{"name": "kevin lutz"},
+{"name": "jay keebler"},
+{"name": "larry laduke"},
+{"name": "john bilson"},
+{"name": "danny mercado"},
+{"name": "william tansey"},
+{"name": "rob cross"},
+{"name": "johnnie pike"},
+{"name": "joe cassin"},
+{"name": "phyllis pardue"},
+{"name": "mike potapov"},
+{"name": "sue marino"},
+{"name": "andrew steeves"},
+{"name": "graham best"},
+{"name": "john pentecost"},
+{"name": "patty facio"},
+{"name": "ada dentistry"},
+{"name": "dennis nowakowski"},
+{"name": "andrew potthoff"},
+{"name": "michael hernandez"},
+{"name": "eric lara"},
+{"name": "stephen welsh"},
+{"name": "sheila coleman"},
+{"name": "robin templeton"},
+{"name": "alvin paulino"},
+{"name": "dan cotherman"},
+{"name": "eric lorenz"},
+{"name": "pierre tremblay"},
+{"name": "amanda fox"},
+{"name": "ruth weldon"},
+{"name": "shawn boire"},
+{"name": "thomas dunphy"},
+{"name": "hannah jenkins"},
+{"name": "lucas driscoll"},
+{"name": "elizabeth bakanic"},
+{"name": "jason mateo"},
+{"name": "clayton stauss"},
+{"name": "steve zimmerman"},
+{"name": "winnie chung"},
+{"name": "jessica witt"},
+{"name": "anne boychuck"},
+{"name": "mike howard"},
+{"name": "julie yamauichi"},
+{"name": "alan whitley"},
+{"name": "viki gallentine"},
+{"name": "corrinne korzen"},
+{"name": "jesse mccormick"},
+{"name": "tracy stanford"},
+{"name": "joseph work"},
+{"name": "stephanie cuz"},
+{"name": "jake hodges"},
+{"name": "scotty mac"},
+{"name": "george kliavkoff"},
+{"name": "eugenia munoz"},
+{"name": "brady thomas"},
+{"name": "richard morehouse"},
+{"name": "terry klingerman"},
+{"name": "forrest brooks"},
+{"name": "andrew feinberg"},
+{"name": "rebecca muniz"},
+{"name": "john davenport"},
+{"name": "scott ulmer"},
+{"name": "stacy kroq"},
+{"name": "ashley holt"},
+{"name": "mark western"},
+{"name": "vicky ledoux"},
+{"name": "gordon blomgren"},
+{"name": "jan portage"},
+{"name": "blair r"},
+{"name": "james scanlan"},
+{"name": "kathy pang"},
+{"name": "judy lanyon"},
+{"name": "jill carson"},
+{"name": "jodi freeo"},
+{"name": "gail s"},
+{"name": "eric glick"},
+{"name": "dave garloff"},
+{"name": "noreen parrish"},
+{"name": "tom supr"},
+{"name": "david stalling"},
+{"name": "stan wardwell"},
+{"name": "eric schweighoffer"},
+{"name": "matt labow"},
+{"name": "esther lee"},
+{"name": "rick saskatchewan"},
+{"name": "william velez"},
+{"name": "charles cooper"},
+{"name": "paula purifoy"},
+{"name": "kacey picine"},
+{"name": "dave o'donnel"},
+{"name": "marti stanton"},
+{"name": "martina jecker"},
+{"name": "kori bernardino"},
+{"name": "betty flowers"},
+{"name": "anna newton"},
+{"name": "bonnie drake"},
+{"name": "caitlin dulles"},
+{"name": "jim padilla"},
+{"name": "jose campero"},
+{"name": "mike evans"},
+{"name": "steven lurie"},
+{"name": "alphonso sastre"},
+{"name": "lisa proveaux"},
+{"name": "jimmy mays"},
+{"name": "benny yisrael"},
+{"name": "autumn barrett"},
+{"name": "alicia bruce"},
+{"name": "mark effron"},
+{"name": "tim chutz"},
+{"name": "carlene simon"},
+{"name": "dan proctor"},
+{"name": "andy chicago"},
+{"name": "robin switzenbaum"},
+{"name": "crystal dickerson"},
+{"name": "delta flt"},
+{"name": "aldo difelice"},
+{"name": "gina torres"},
+{"name": "jenna yarborough"},
+{"name": "david friedman"},
+{"name": "peter wendell"},
+{"name": "david carr"},
+{"name": "bernie weston"},
+{"name": "drew echelson"},
+{"name": "melissa alves"},
+{"name": "crystal mtn"},
+{"name": "liz paternotte"},
+{"name": "tracey maier"},
+{"name": "rubin jeff"},
+{"name": "ben shalom"},
+{"name": "deborah horn"},
+{"name": "brian elko"},
+{"name": "kathleen schneider"},
+{"name": "hannah randoja"},
+{"name": "joel pollack"},
+{"name": "marcus barnes"},
+{"name": "corey carlson"},
+{"name": "matt perron"},
+{"name": "josh schema"},
+{"name": "jason deny"},
+{"name": "bob vanna"},
+{"name": "scott morse"},
+{"name": "jae lim"},
+{"name": "mary lindsey"},
+{"name": "brian rien"},
+{"name": "chris swanson"},
+{"name": "michelle windward"},
+{"name": "ed stalder"},
+{"name": "joe pearson"},
+{"name": "juanita small"},
+{"name": "alisha marie"},
+{"name": "allen martin"},
+{"name": "sean santore"},
+{"name": "amy johnson"},
+{"name": "henry scheiner"},
+{"name": "ellen alexander"},
+{"name": "chrissy wise"},
+{"name": "chris bjorklund"},
+{"name": "lisa garrison"},
+{"name": "mike hardrick"},
+{"name": "carlos segura"},
+{"name": "ann amaru"},
+{"name": "brad arnold"},
+{"name": "matt kronish"},
+{"name": "brian boll"},
+{"name": "paul buschur"},
+{"name": "jessica brett's"},
+{"name": "stephen medley"},
+{"name": "ted fitzpatrick"},
+{"name": "kelly oosbree"},
+{"name": "bailey hulin"},
+{"name": "steven lancaster"},
+{"name": "beth foose"},
+{"name": "john allgair"},
+{"name": "connie dunn"},
+{"name": "lori goracke"},
+{"name": "ashley kotch"},
+{"name": "mike liebel"},
+{"name": "robin davis"},
+{"name": "molly solbach"},
+{"name": "george group"},
+{"name": "ronald lindsay"},
+{"name": "nick bmw"},
+{"name": "chelsea hooters"},
+{"name": "michael besson"},
+{"name": "gordon lederman"},
+{"name": "kelly paine"},
+{"name": "chris sopithakul"},
+{"name": "patrick broxterman"},
+{"name": "kym gloff"},
+{"name": "kyle lucis"},
+{"name": "larry mchugh"},
+{"name": "dayna schuessler"},
+{"name": "neal hersh"},
+{"name": "kate bluralz"},
+{"name": "lori sorrells"},
+{"name": "john chavez"},
+{"name": "michelle birthwright"},
+{"name": "josh liang"},
+{"name": "helen sievers"},
+{"name": "will s"},
+{"name": "greg engbretson"},
+{"name": "dannie jenkins"},
+{"name": "ashley gonzalez"},
+{"name": "carmen uop"},
+{"name": "ben forer"},
+{"name": "linda chesney"},
+{"name": "vanessa work"},
+{"name": "daniel godbout"},
+{"name": "erin shewchuck"},
+{"name": "jeremy schmidt"},
+{"name": "don eastman"},
+{"name": "karen macintosh"},
+{"name": "richie mac"},
+{"name": "willy robinson"},
+{"name": "cathy harbottle"},
+{"name": "jamie tramp"},
+{"name": "dean swett"},
+{"name": "ryan caraballo"},
+{"name": "aaron ward"},
+{"name": "greg h"},
+{"name": "murray knecht"},
+{"name": "ariel richer"},
+{"name": "melissa chew"},
+{"name": "tony mazy"},
+{"name": "joe grimes"},
+{"name": "andre alston"},
+{"name": "maggie home"},
+{"name": "michael keith"},
+{"name": "greg film"},
+{"name": "nancy richardson"},
+{"name": "thomas jennings"},
+{"name": "brittany flug"},
+{"name": "sonya muzyca"},
+{"name": "tony huge"},
+{"name": "jeff letterman"},
+{"name": "rose roberts"},
+{"name": "laura miami"},
+{"name": "ruth carew"},
+{"name": "jann olsten"},
+{"name": "ken kawakami"},
+{"name": "matt aeschlimann"},
+{"name": "steve cooke"},
+{"name": "janice nice"},
+{"name": "cory roehl"},
+{"name": "gayle cost"},
+{"name": "chris mcfarland"},
+{"name": "wade armentrout"},
+{"name": "joy hastings"},
+{"name": "alyssa hollman"},
+{"name": "brad brooks"},
+{"name": "steve winick"},
+{"name": "don zucco"},
+{"name": "john ireland"},
+{"name": "scott meehan"},
+{"name": "gene mcelhaney"},
+{"name": "daniel solomon"},
+{"name": "vincent o'donnell"},
+{"name": "lilli hadselk"},
+{"name": "armand hhc"},
+{"name": "chuck cleary"},
+{"name": "angie kail"},
+{"name": "reggie susanto"},
+{"name": "jackson hardage"},
+{"name": "brent markham"},
+{"name": "larry arendt"},
+{"name": "ian adams"},
+{"name": "brian cournoyer"},
+{"name": "karen indiana"},
+{"name": "thomas bersani"},
+{"name": "logan wilcox"},
+{"name": "luis staples"},
+{"name": "john vzw"},
+{"name": "ron engleman"},
+{"name": "jennifer brauer"},
+{"name": "andy grill"},
+{"name": "carol franket"},
+{"name": "willie baily"},
+{"name": "roberto molina"},
+{"name": "richard whittaker"},
+{"name": "toni walker"},
+{"name": "crystal jones"},
+{"name": "rich gilmore"},
+{"name": "john ferris"},
+{"name": "howard kiem"},
+{"name": "britney monroe"},
+{"name": "corey smith"},
+{"name": "andrew meister"},
+{"name": "patrick anstaett"},
+{"name": "jennifer moreno"},
+{"name": "beth rush"},
+{"name": "ed mclarty"},
+{"name": "mark barry"},
+{"name": "kerri kuster"},
+{"name": "dave matre"},
+{"name": "farrah shyer"},
+{"name": "brenda henshaw"},
+{"name": "chad lyke"},
+{"name": "camille spitzer"},
+{"name": "heather orr"},
+{"name": "claudia zapata"},
+{"name": "rolland thomason"},
+{"name": "dallas bbq"},
+{"name": "lisa kranabetter"},
+{"name": "emily taylor"},
+{"name": "fred neville"},
+{"name": "patricia mohar"},
+{"name": "jennifer martin"},
+{"name": "ted dintersmith"},
+{"name": "sonny connell"},
+{"name": "eric tran"},
+{"name": "betty dowling"},
+{"name": "sara ambriz"},
+{"name": "kyle obrein"},
+{"name": "scott kershaw"},
+{"name": "linda fisher"},
+{"name": "michelle navarro"},
+{"name": "terry mendenhall"},
+{"name": "francine madera"},
+{"name": "chris giffen"},
+{"name": "joann lagman"},
+{"name": "heather meadows"},
+{"name": "elizabeth menius"},
+{"name": "tim hutchins"},
+{"name": "alex impala"},
+{"name": "scott tenhulzen"},
+{"name": "rosalba rios"},
+{"name": "ashley perkins"},
+{"name": "derrick hansford"},
+{"name": "jeffrey strahan"},
+{"name": "lindsey paschal"},
+{"name": "pete voss"},
+{"name": "milton agurs"},
+{"name": "julianna sanchez"},
+{"name": "chelsea k"},
+{"name": "catherine lifeso"},
+{"name": "joe gerez"},
+{"name": "tara price"},
+{"name": "steve liberty"},
+{"name": "gregg wolin"},
+{"name": "susan delgado"},
+{"name": "charles sims"},
+{"name": "rachael billingsly"},
+{"name": "matt yuhas"},
+{"name": "judson murray"},
+{"name": "sarah hersack"},
+{"name": "brett satterlee"},
+{"name": "daniel desimone"},
+{"name": "josh eisenstat"},
+{"name": "kim henderson"},
+{"name": "margie charles"},
+{"name": "lily liu"},
+{"name": "jeff herda"},
+{"name": "jeff christenson"},
+{"name": "lee lou"},
+{"name": "tina dahlquist"},
+{"name": "juan estrada"},
+{"name": "rachel porn"},
+{"name": "pat mcgowan"},
+{"name": "christina briana"},
+{"name": "billie sanchez"},
+{"name": "jessica stowell"},
+{"name": "kathy prince"},
+{"name": "jim courier"},
+{"name": "michael k"},
+{"name": "nick s"},
+{"name": "eleanor pemper"},
+{"name": "ben constance"},
+{"name": "jake dogeye"},
+{"name": "andrea ronderos"},
+{"name": "pedro valdez"},
+{"name": "karri mange"},
+{"name": "gene botto"},
+{"name": "peter kutrubes"},
+{"name": "yen do"},
+{"name": "jon muller"},
+{"name": "joan collins"},
+{"name": "michele solis"},
+{"name": "joseph naegle"},
+{"name": "peggy froloc"},
+{"name": "lorena d'gala"},
+{"name": "dave beers"},
+{"name": "andrew floyd"},
+{"name": "jaclyn oribello"},
+{"name": "dale stubblefield"},
+{"name": "nick vanderwal"},
+{"name": "shawn nicoll"},
+{"name": "clay cell"},
+{"name": "jill barella"},
+{"name": "tyrone humphrey"},
+{"name": "harry randoph"},
+{"name": "vivian sapirman"},
+{"name": "sarah mabey"},
+{"name": "shannon fink"},
+{"name": "kay maples"},
+{"name": "kenneth clyat"},
+{"name": "darrin joncas"},
+{"name": "jess baker"},
+{"name": "becky bishop"},
+{"name": "michael hildebrandt"},
+{"name": "summer m"},
+{"name": "rodney bruce"},
+{"name": "lino solis"},
+{"name": "joseph herzog"},
+{"name": "mike mannix"},
+{"name": "sara lee"},
+{"name": "lori groves"},
+{"name": "mickey trigilio"},
+{"name": "gail dorfman"},
+{"name": "matt noon"},
+{"name": "scott henry"},
+{"name": "wanda oakey"},
+{"name": "todd lutz"},
+{"name": "liz pomish"},
+{"name": "karen stallone"},
+{"name": "richard l"},
+{"name": "jacqueline winkler"},
+{"name": "rochel shields"},
+{"name": "wes brown"},
+{"name": "jerry fishing"},
+{"name": "dawn spale"},
+{"name": "paul talcott"},
+{"name": "aron rosen"},
+{"name": "john gilbaugh"},
+{"name": "james fastrak"},
+{"name": "lynn boiter"},
+{"name": "vincent rioux"},
+{"name": "claudia majestic"},
+{"name": "tammy hadley"},
+{"name": "richard pearce"},
+{"name": "mike guarino"},
+{"name": "carlos valdeblanquez"},
+{"name": "bobby coyle"},
+{"name": "kathy mabry"},
+{"name": "rachel grafstein"},
+{"name": "steven moody"},
+{"name": "david enid"},
+{"name": "lynn ledonois"},
+{"name": "tracy ferrier"},
+{"name": "pamela friedman"},
+{"name": "al rotker"},
+{"name": "joe joe"},
+{"name": "beth thompson"},
+{"name": "otha motha"},
+{"name": "gregory perrone"},
+{"name": "lori brooks"},
+{"name": "mike saenz"},
+{"name": "celeste mclaughlin"},
+{"name": "duane fulps"},
+{"name": "evelyn sharp"},
+{"name": "noel vega"},
+{"name": "julie lewis"},
+{"name": "mark olson"},
+{"name": "tom odell"},
+{"name": "andrea andrea"},
+{"name": "suzann brantner"},
+{"name": "steve maker"},
+{"name": "beth jardina"},
+{"name": "elise pratt"},
+{"name": "brad terk"},
+{"name": "shaina wiess"},
+{"name": "alice ribs"},
+{"name": "denny reed"},
+{"name": "steve oliver"},
+{"name": "molly johnson"},
+{"name": "lee parish"},
+{"name": "chang tnt"},
+{"name": "sierra med"},
+{"name": "sara caldeira"},
+{"name": "michael rueb"},
+{"name": "keri honda"},
+{"name": "genie gavenchack"},
+{"name": "sharon mclean"},
+{"name": "stacy macbeth"},
+{"name": "beth conley"},
+{"name": "ryan thune"},
+{"name": "mike raffell"},
+{"name": "karen jost"},
+{"name": "ron sauer"},
+{"name": "sarah patterson"},
+{"name": "harold harris"},
+{"name": "willie p"},
+{"name": "ruth lane"},
+{"name": "ron jennings"},
+{"name": "dawn schmitt"},
+{"name": "bradley fisher"},
+{"name": "phillip taylor"},
+{"name": "nikki l"},
+{"name": "mike gillespie"},
+{"name": "robert cotner"},
+{"name": "thomas dibiase"},
+{"name": "charles sr"},
+{"name": "melissa meyers"},
+{"name": "anna white"},
+{"name": "vanesa ayala"},
+{"name": "gene chandler"},
+{"name": "carlos montem"},
+{"name": "anita wieduwilt"},
+{"name": "nathan heald"},
+{"name": "antony uncle"},
+{"name": "steve falcon"},
+{"name": "lawrence d"},
+{"name": "jeremy ng"},
+{"name": "donna jaggers"},
+{"name": "harley rubin"},
+{"name": "daniel fernandez"},
+{"name": "ed pinegar"},
+{"name": "katy zanville"},
+{"name": "jon dimalante"},
+{"name": "jessica morales"},
+{"name": "lionel gracia"},
+{"name": "frank atwood"},
+{"name": "toney t"},
+{"name": "damon gammage"},
+{"name": "randy jones"},
+{"name": "matt rutherford"},
+{"name": "john dalfior"},
+{"name": "michele miyashiro"},
+{"name": "brenda k"},
+{"name": "greg bagley"},
+{"name": "doug boyles"},
+{"name": "alice wachol"},
+{"name": "kelly slow"},
+{"name": "frank hayes"},
+{"name": "joseph shamirizadi"},
+{"name": "rich martinez"},
+{"name": "john sinnott"},
+{"name": "sue witt"},
+{"name": "jin kim"},
+{"name": "bill so"},
+{"name": "karen wilcox"},
+{"name": "diane farrell"},
+{"name": "mark sawyer"},
+{"name": "mark beccue"},
+{"name": "amanda roe"},
+{"name": "andy hech"},
+{"name": "ian clement"},
+{"name": "sam ni"},
+{"name": "bob mcgough"},
+{"name": "brian mccomas"},
+{"name": "mary knobler"},
+{"name": "patrick angel"},
+{"name": "matt kury"},
+{"name": "niki brunswick"},
+{"name": "robert xxxxx"},
+{"name": "bernard lord"},
+{"name": "debra fuess"},
+{"name": "mike mccormick"},
+{"name": "david lezak"},
+{"name": "sarah hobbs"},
+{"name": "tim hudson"},
+{"name": "brad dittmer"},
+{"name": "peter worley"},
+{"name": "bo silvia"},
+{"name": "joe chin"},
+{"name": "richard ann"},
+{"name": "kenny ellis"},
+{"name": "mathew krause"},
+{"name": "keith stogdell"},
+{"name": "barb kayter"},
+{"name": "tom boyce"},
+{"name": "dwayne richardson"},
+{"name": "steve roper"},
+{"name": "heidi brooker"},
+{"name": "becky powell"},
+{"name": "erica andreski"},
+{"name": "melissa wallenbeck"},
+{"name": "mac report"},
+{"name": "paul hershiser"},
+{"name": "scott norris"},
+{"name": "christine utica"},
+{"name": "sean katz"},
+{"name": "john schumacher"},
+{"name": "nick carlson"},
+{"name": "gail bassett"},
+{"name": "john dolmage"},
+{"name": "joan francis"},
+{"name": "domenic maggio"},
+{"name": "pamela duncan"},
+{"name": "paul bessent"},
+{"name": "karl gotlieb"},
+{"name": "vincent mcclendon"},
+{"name": "richard zachar"},
+{"name": "glen weddell"},
+{"name": "rick shrotri"},
+{"name": "mike jingozian"},
+{"name": "ryan herbert"},
+{"name": "william batzkall"},
+{"name": "nancy mileikis"},
+{"name": "robin nicole"},
+{"name": "tim burkhead"},
+{"name": "martha johnson"},
+{"name": "phil machek"},
+{"name": "ami schwab"},
+{"name": "courtney leak"},
+{"name": "rachel goodman"},
+{"name": "robby cox"},
+{"name": "stephen laroco"},
+{"name": "sarah rocano"},
+{"name": "chris gioffre"},
+{"name": "katie webber"},
+{"name": "jamie kavalieros"},
+{"name": "scott packam"},
+{"name": "page jr"},
+{"name": "danny victoriano"},
+{"name": "kyle kinzy"},
+{"name": "neal takai"},
+{"name": "christian mendoza"},
+{"name": "kenneth heulitt"},
+{"name": "pat determan"},
+{"name": "tom malone"},
+{"name": "lou mussman"},
+{"name": "isaac gowon"},
+{"name": "peter browm"},
+{"name": "james marchesani"},
+{"name": "don troyer"},
+{"name": "theresa irwin"},
+{"name": "janice moore"},
+{"name": "rudy villalobos"},
+{"name": "karen modesitt"},
+{"name": "juan home"},
+{"name": "chris cramer"},
+{"name": "sam arcilla"},
+{"name": "sean gindo"},
+{"name": "marsha roniece"},
+{"name": "pat hines"},
+{"name": "joe bellio"},
+{"name": "carl casper"},
+{"name": "brandon bogue"},
+{"name": "nicola gandossi"},
+{"name": "michael durden"},
+{"name": "warren davis"},
+{"name": "john elias"},
+{"name": "mike pro"},
+{"name": "don griego"},
+{"name": "greg brenda"},
+{"name": "corey j"},
+{"name": "josh stephenson"},
+{"name": "dino chiesa"},
+{"name": "eric farber"},
+{"name": "alex nudell"},
+{"name": "anna mchargue"},
+{"name": "ron allchin"},
+{"name": "patrick symmester"},
+{"name": "tom karson"},
+{"name": "lee hirsch"},
+{"name": "charles shean"},
+{"name": "lana leslie"},
+{"name": "debi parker"},
+{"name": "bart cavanaugh"},
+{"name": "anna roberts"},
+{"name": "santo dodaro"},
+{"name": "bill herlihy"},
+{"name": "joella ellis"},
+{"name": "kenny tapahanoc"},
+{"name": "dwight mexico"},
+{"name": "adam younger"},
+{"name": "martin loewengart"},
+{"name": "cindy mackay"},
+{"name": "becky cottrell"},
+{"name": "don santoski"},
+{"name": "jim folkman"},
+{"name": "george bing"},
+{"name": "gwen larson"},
+{"name": "mariah burnett"},
+{"name": "nita cook"},
+{"name": "andre lalande"},
+{"name": "kim dyches"},
+{"name": "rosemary sanci"},
+{"name": "amy willis"},
+{"name": "paul minsky"},
+{"name": "robin sutherland"},
+{"name": "david kimbell"},
+{"name": "brooks marvin"},
+{"name": "chuck langley"},
+{"name": "ron cooper"},
+{"name": "richard stahl"},
+{"name": "nelson lee"},
+{"name": "krista cleary"},
+{"name": "tina garfolo"},
+{"name": "steve bechthold"},
+{"name": "cathy raffeto"},
+{"name": "willie iannucci"},
+{"name": "tanya gallegos"},
+{"name": "janie donaldson"},
+{"name": "cecil leffel"},
+{"name": "tim fugate"},
+{"name": "tony isaacs"},
+{"name": "chelsea moran"},
+{"name": "lee fortney"},
+{"name": "jackie hardy"},
+{"name": "jeff marks"},
+{"name": "christine hernandez"},
+{"name": "john kibble"},
+{"name": "sandra carson"},
+{"name": "lee caron"},
+{"name": "jimmy butch"},
+{"name": "pat wickenhauser"},
+{"name": "nathan traughber"},
+{"name": "floyd krengel"},
+{"name": "steve levenson"},
+{"name": "bernie parsons"},
+{"name": "cindy filipinas"},
+{"name": "john prickett"},
+{"name": "raphael phillips"},
+{"name": "john palmquist"},
+{"name": "margaret o'donnell"},
+{"name": "libby knudson"},
+{"name": "marc primo"},
+{"name": "rob howard"},
+{"name": "austin cook"},
+{"name": "shelley broader"},
+{"name": "ian goldston"},
+{"name": "jessica mckinley"},
+{"name": "teresa brian"},
+{"name": "catherine snow"},
+{"name": "leo heinert"},
+{"name": "jamie lindberg"},
+{"name": "larry shipley"},
+{"name": "lisa kissinger"},
+{"name": "santana dennis"},
+{"name": "jenny maccan"},
+{"name": "mike leplant"},
+{"name": "teri patrson"},
+{"name": "philip hampton"},
+{"name": "monique sanchez"},
+{"name": "bob downing"},
+{"name": "annette singletary"},
+{"name": "bill zhu"},
+{"name": "cheryl pollack"},
+{"name": "dan mcgowan"},
+{"name": "matt baker"},
+{"name": "darlene wilson"},
+{"name": "larissa blakley"},
+{"name": "jean weyandt"},
+{"name": "chelsea berryman"},
+{"name": "dave carpenter"},
+{"name": "zack hamideh"},
+{"name": "natalie havlina"},
+{"name": "kevin medina"},
+{"name": "carlo vitulano"},
+{"name": "ken converse"},
+{"name": "dustin lofdah"},
+{"name": "mike polvere"},
+{"name": "stefan gran"},
+{"name": "matt schaap"},
+{"name": "joe acoin"},
+{"name": "jarrod mcfarland"},
+{"name": "darlene mappin"},
+{"name": "oscar aceves"},
+{"name": "phyllis honey"},
+{"name": "mary hall"},
+{"name": "dave bonham"},
+{"name": "lenore weil"},
+{"name": "alexander donovan"},
+{"name": "christopher dux"},
+{"name": "devin kessler"},
+{"name": "mary jakubowski"},
+{"name": "carrie huerta"},
+{"name": "denise negro"},
+{"name": "tom schiemer"},
+{"name": "tony j"},
+{"name": "louis pabon"},
+{"name": "carla rondel"},
+{"name": "jenna stanley"},
+{"name": "ashley monicas"},
+{"name": "jimmy watts"},
+{"name": "josh jensen"},
+{"name": "tony delansky"},
+{"name": "karla tofte"},
+{"name": "arnold kalan"},
+{"name": "elena mclean"},
+{"name": "dawn hankin"},
+{"name": "donna kirk"},
+{"name": "matt wagaman"},
+{"name": "diane taylor"},
+{"name": "wendy hames"},
+{"name": "dave lint"},
+{"name": "david frazier"},
+{"name": "lynne abeshouse"},
+{"name": "bob stinson"},
+{"name": "leslie perez"},
+{"name": "nikki aponte"},
+{"name": "gary hubbard"},
+{"name": "vanessa sanborn"},
+{"name": "john deangelis"},
+{"name": "missy frye"},
+{"name": "kyle utz"},
+{"name": "trey richardson"},
+{"name": "robert schumacher"},
+{"name": "jeff stanley"},
+{"name": "doris belk"},
+{"name": "mark caruso"},
+{"name": "mike keith"},
+{"name": "brad schneider"},
+{"name": "robert bonney"},
+{"name": "laura usur"},
+{"name": "amy cutter"},
+{"name": "bryan teel"},
+{"name": "raquel andres"},
+{"name": "elaine morlock"},
+{"name": "john fenico"},
+{"name": "mark j"},
+{"name": "wendy spakes"},
+{"name": "crystal short"},
+{"name": "blake moore"},
+{"name": "joe lucchese"},
+{"name": "karen koonan"},
+{"name": "sue sitton"},
+{"name": "bob ford"},
+{"name": "kathy farmer"},
+{"name": "robert abernathy"},
+{"name": "jeff brandon"},
+{"name": "danny newman"},
+{"name": "rachel lawson"},
+{"name": "mike greenewald"},
+{"name": "dennis hui"},
+{"name": "dan holden"},
+{"name": "jessica ellegood"},
+{"name": "dean hayse"},
+{"name": "angela wagenaar"},
+{"name": "ursula clark"},
+{"name": "jonathan askin"},
+{"name": "john begley"},
+{"name": "jeff hechendorf"},
+{"name": "karen pettit"},
+{"name": "jimmy kalamaras"},
+{"name": "jim carriger"},
+{"name": "rodney washington"},
+{"name": "jason fedore"},
+{"name": "sam hood"},
+{"name": "sean francis"},
+{"name": "charles spence"},
+{"name": "william robinson"},
+{"name": "lee melnychuk"},
+{"name": "tyler petty"},
+{"name": "gustavo guerrero"},
+{"name": "bob norwood"},
+{"name": "jerry sacks"},
+{"name": "john freeman"},
+{"name": "chuck dipiazza"},
+{"name": "anthony vereyken"},
+{"name": "mary burch"},
+{"name": "linda greaver"},
+{"name": "sam white"},
+{"name": "jim streeter"},
+{"name": "christine lee"},
+{"name": "matt crow"},
+{"name": "cindy tinge"},
+{"name": "patricia alibutod"},
+{"name": "sandy oneal"},
+{"name": "allen goins"},
+{"name": "holly eyebrows"},
+{"name": "nancy b"},
+{"name": "spencer byrnes"},
+{"name": "alexis newman"},
+{"name": "don bollinger"},
+{"name": "stacia milne"},
+{"name": "dennis harrah"},
+{"name": "jacob higgins"},
+{"name": "lorie ann"},
+{"name": "pat lenzer"},
+{"name": "kendra hills"},
+{"name": "charlotte cambell"},
+{"name": "jim wefest"},
+{"name": "rita butherus"},
+{"name": "rob z"},
+{"name": "matt bailey"},
+{"name": "iris avellano"},
+{"name": "tom pasto"},
+{"name": "mark lockschmidt"},
+{"name": "john barnitz"},
+{"name": "ginger oliver"},
+{"name": "jerrod mackimoto"},
+{"name": "jarrod n"},
+{"name": "dave k"},
+{"name": "jennifer ferrante"},
+{"name": "dave harper"},
+{"name": "tammy trujillo"},
+{"name": "meredith work"},
+{"name": "kevin ht"},
+{"name": "brandon flack"},
+{"name": "spencer head"},
+{"name": "ariel elite"},
+{"name": "lisa allman"},
+{"name": "greg byrne"},
+{"name": "matt heeringa"},
+{"name": "cathy neben"},
+{"name": "janice heid"},
+{"name": "sarah borofsky"},
+{"name": "hazel vincoy"},
+{"name": "tony merkel"},
+{"name": "dario pintor"},
+{"name": "brett harris"},
+{"name": "richard bales"},
+{"name": "lorrie summers"},
+{"name": "beryl miller"},
+{"name": "dwight stewart"},
+{"name": "margaret drysdale"},
+{"name": "amy collins"},
+{"name": "jeremiah lasslett"},
+{"name": "heidi werner"},
+{"name": "todd h"},
+{"name": "june angel"},
+{"name": "chad fleck"},
+{"name": "ed gottheil"},
+{"name": "scott gardner"},
+{"name": "tom teixeira"},
+{"name": "betty clendenon"},
+{"name": "tad fbo"},
+{"name": "heather maccallum"},
+{"name": "jared knight"},
+{"name": "bob pablish"},
+{"name": "kayla willis"},
+{"name": "douglas salyers"},
+{"name": "bernie bregman"},
+{"name": "joe siau"},
+{"name": "paula gemora"},
+{"name": "angelo mendez"},
+{"name": "luke p"},
+{"name": "kenny kurtzman"},
+{"name": "aurora merida"},
+{"name": "glenna kassel"},
+{"name": "tina parker"},
+{"name": "jess johnson"},
+{"name": "kaitlyn kramer"},
+{"name": "allen ellison"},
+{"name": "barbara holgate"},
+{"name": "paula sellers"},
+{"name": "spencer i"},
+{"name": "jeff cummings"},
+{"name": "nikki harding"},
+{"name": "jose terrones"},
+{"name": "rose caruso"},
+{"name": "michelle challenger"},
+{"name": "brian lythgoe"},
+{"name": "sean griffin"},
+{"name": "anne maguire"},
+{"name": "clint long"},
+{"name": "seymour joffe"},
+{"name": "tricia kelly"},
+{"name": "emily nelson"},
+{"name": "karla neuweg"},
+{"name": "bud younts"},
+{"name": "mike slayden"},
+{"name": "karen powell"},
+{"name": "kathy gonzalez"},
+{"name": "charlie kelly"},
+{"name": "agnes stacia"},
+{"name": "sam holland"},
+{"name": "ena couriers"},
+{"name": "kathy abney"},
+{"name": "don lowe"},
+{"name": "stephanie kugel"},
+{"name": "matt headrick"},
+{"name": "lisa gaunt"},
+{"name": "james pridgen"},
+{"name": "steve g"},
+{"name": "daniel crowe"},
+{"name": "jake centeno"},
+{"name": "julia rose"},
+{"name": "heather johnstone"},
+{"name": "nick santoro"},
+{"name": "gary wicker"},
+{"name": "thelma patterson"},
+{"name": "patsy sanchez"},
+{"name": "kati cruger"},
+{"name": "michelle cole"},
+{"name": "tony uno"},
+{"name": "kay iozzo"},
+{"name": "chris alexander"},
+{"name": "john rorabaugh"},
+{"name": "shane salmari"},
+{"name": "brandon tentation"},
+{"name": "chris cali"},
+{"name": "rita liebelt"},
+{"name": "jennifer lamoureux"},
+{"name": "denny blew"},
+{"name": "jennifer logan"},
+{"name": "sheryl gillespie"},
+{"name": "jeff mumma"},
+{"name": "robert brunner"},
+{"name": "kimberly richburg"},
+{"name": "brandon hams"},
+{"name": "linda agnos"},
+{"name": "leda arguello"},
+{"name": "paul blanner"},
+{"name": "eric haggin"},
+{"name": "carmel m"},
+{"name": "christine choi"},
+{"name": "barbara nix"},
+{"name": "matt krywy"},
+{"name": "tony lumber"},
+{"name": "curt wada"},
+{"name": "eric huffman"},
+{"name": "kyle cell"},
+{"name": "terry riorden"},
+{"name": "evon whitley"},
+{"name": "cheyenne cyr"},
+{"name": "david lewis"},
+{"name": "david holdcroft"},
+{"name": "chris bassham"},
+{"name": "allen henderson"},
+{"name": "jason glass"},
+{"name": "bryan rr"},
+{"name": "norbert pools"},
+{"name": "jeremy martin"},
+{"name": "eric fisher"},
+{"name": "isaac redmay"},
+{"name": "heidi groth"},
+{"name": "daniella kassar"},
+{"name": "robyn coley"},
+{"name": "laura mcgees"},
+{"name": "gloria connors"},
+{"name": "sergio murillo"},
+{"name": "mark wiehl"},
+{"name": "augustine soundranayakam"},
+{"name": "lou alzate"},
+{"name": "don auld"},
+{"name": "carter morse"},
+{"name": "merrill lynch"},
+{"name": "thomas trumphour"},
+{"name": "brianna bostwick"},
+{"name": "greg lake"},
+{"name": "william song"},
+{"name": "joshua lin"},
+{"name": "robert fin"},
+{"name": "chris luu"},
+{"name": "michelle mckinney"},
+{"name": "claudia montrone"},
+{"name": "mike diamanths"},
+{"name": "dan lindell"},
+{"name": "neil smith"},
+{"name": "luis love"},
+{"name": "brandi jonse"},
+{"name": "kate wisnewski"},
+{"name": "ray dizon"},
+{"name": "jeanie blaylock"},
+{"name": "grady hanshaw"},
+{"name": "kristin murray"},
+{"name": "louis friedman"},
+{"name": "kathy rogers"},
+{"name": "chris majors"},
+{"name": "dave foster"},
+{"name": "ken zambelli"},
+{"name": "don barlow"},
+{"name": "jon home"},
+{"name": "barry draeger"},
+{"name": "john weaver"},
+{"name": "michelle lugo"},
+{"name": "kelsey reis"},
+{"name": "neil witherow"},
+{"name": "young cho"},
+{"name": "dan smeak"},
+{"name": "ken davidson"},
+{"name": "amy younger"},
+{"name": "penny olson"},
+{"name": "jennifer pastores"},
+{"name": "joel stocks"},
+{"name": "kent mcdowell"},
+{"name": "dennis d"},
+{"name": "tanya deavers"},
+{"name": "heather atler"},
+{"name": "sheila alvarez"},
+{"name": "chris sevil"},
+{"name": "mike pederson"},
+{"name": "bobbi fowler"},
+{"name": "jimmie reign"},
+{"name": "lloyd droller"},
+{"name": "rich pearson"},
+{"name": "matt gonzales"},
+{"name": "marvin house"},
+{"name": "kevin falk"},
+{"name": "yolanda williams"},
+{"name": "patricia suh"},
+{"name": "shirley gebert"},
+{"name": "pat c"},
+{"name": "daren manaco"},
+{"name": "kristen toponce"},
+{"name": "bailey whitehead"},
+{"name": "stacie ayala"},
+{"name": "drew tibbits"},
+{"name": "taylor moyer"},
+{"name": "ian holten"},
+{"name": "roger shanafelt"},
+{"name": "jeremy burt"},
+{"name": "raul martinez"},
+{"name": "sherry lasley"},
+{"name": "rick rummel"},
+{"name": "roger berke"},
+{"name": "erica work"},
+{"name": "jeff cressman"},
+{"name": "laura radford"},
+{"name": "nikki safady"},
+{"name": "ann menchetti"},
+{"name": "dedra trail"},
+{"name": "susie t"},
+{"name": "dennis goldstein"},
+{"name": "mark plecnik"},
+{"name": "van vaketis"},
+{"name": "ben richard"},
+{"name": "pat egan"},
+{"name": "andy grumbles"},
+{"name": "linda rogers"},
+{"name": "andrew selormey"},
+{"name": "tommy gun"},
+{"name": "jim peirce"},
+{"name": "linda deal"},
+{"name": "travis dunn"},
+{"name": "jon glusband"},
+{"name": "chris saurez"},
+{"name": "kathleen mais"},
+{"name": "lori rowland"},
+{"name": "andres villegas"},
+{"name": "josh adongay"},
+{"name": "ginny goss"},
+{"name": "ron bochenek"},
+{"name": "scott orr"},
+{"name": "stacey bomeli"},
+{"name": "valerie berry"},
+{"name": "coralee mitchell"},
+{"name": "devon prioleau"},
+{"name": "max j"},
+{"name": "dave harrah"},
+{"name": "royce foster"},
+{"name": "sharon sponslor"},
+{"name": "jim kc"},
+{"name": "blake hollister"},
+{"name": "danny lilly"},
+{"name": "scot griffith"},
+{"name": "jess g"},
+{"name": "ralph losey"},
+{"name": "louise haverman"},
+{"name": "andrea boyd"},
+{"name": "ann carlson"},
+{"name": "tyler miehm"},
+{"name": "jim dutra"},
+{"name": "chris banfield"},
+{"name": "denise reed"},
+{"name": "noel murphy"},
+{"name": "mindy zheng"},
+{"name": "brian viglione"},
+{"name": "don bennett"},
+{"name": "robin kreines"},
+{"name": "katie morrisey"},
+{"name": "emma jurado"},
+{"name": "shanna sabet"},
+{"name": "floyd dakil"},
+{"name": "chris shin"},
+{"name": "ryan ash"},
+{"name": "josh needelman"},
+{"name": "brett matthews"},
+{"name": "earl nicholson"},
+{"name": "roxanne ashe"},
+{"name": "adam storm"},
+{"name": "martha pozdyn"},
+{"name": "monique grech"},
+{"name": "robin bryan"},
+{"name": "edie rhea"},
+{"name": "hank boughner"},
+{"name": "kris markus"},
+{"name": "erika gutherz"},
+{"name": "joy engelberg"},
+{"name": "dennis sawyer"},
+{"name": "bill maestretti"},
+{"name": "cindy moses"},
+{"name": "rick henson"},
+{"name": "steve samaniego"},
+{"name": "ryan bordas"},
+{"name": "mary tobin"},
+{"name": "jonathan leitersdorf"},
+{"name": "luis ortiz"},
+{"name": "george washington"},
+{"name": "cynthia class"},
+{"name": "mark nolte"},
+{"name": "randy cell"},
+{"name": "susan mcvety"},
+{"name": "frank ackley"},
+{"name": "andrew perez"},
+{"name": "jaimee schmidt"},
+{"name": "dara gomshei"},
+{"name": "paul storch"},
+{"name": "matthew rohr"},
+{"name": "robert yankanin"},
+{"name": "chantal lepine"}
+]
diff --git a/tests/auto/daemon/largeContactsTest1k.json b/tests/auto/daemon/largeContactsTest1k.json
new file mode 100644
index 00000000..7666c68f
--- /dev/null
+++ b/tests/auto/daemon/largeContactsTest1k.json
@@ -0,0 +1,1002 @@
+[
+{"name": "marcia d'arcy"},
+{"name": "jeffrey samuels"},
+{"name": "robert demmon"},
+{"name": "heidi motika"},
+{"name": "leslie pugh"},
+{"name": "ryan houlette"},
+{"name": "kenton kossan"},
+{"name": "connie goddard"},
+{"name": "andrew keopraseuth"},
+{"name": "charlie stern"},
+{"name": "alex free"},
+{"name": "glenn legros"},
+{"name": "sean joyce"},
+{"name": "bruce toth"},
+{"name": "amanda vaneffen"},
+{"name": "gary huss"},
+{"name": "stan young"},
+{"name": "jaclyn gregory"},
+{"name": "ryan sepulveda"},
+{"name": "thomas reim"},
+{"name": "matt ryan"},
+{"name": "matt muralt"},
+{"name": "jason lau"},
+{"name": "blake kewish"},
+{"name": "scott budge"},
+{"name": "keith archer"},
+{"name": "david hubb"},
+{"name": "joseph tsai"},
+{"name": "alla pimenov"},
+{"name": "marina albright"},
+{"name": "tim carver"},
+{"name": "rachel palomino"},
+{"name": "chris gaddis"},
+{"name": "ken boerman"},
+{"name": "annie kiang"},
+{"name": "allison aronne"},
+{"name": "jessica fritch"},
+{"name": "deb haffey"},
+{"name": "moshe shields"},
+{"name": "kyle thomas"},
+{"name": "becky hughes"},
+{"name": "dustin schneider"},
+{"name": "mary hardwick"},
+{"name": "andrew client"},
+{"name": "david conley"},
+{"name": "vicky lokis"},
+{"name": "cameron white"},
+{"name": "nicole rolland"},
+{"name": "jaime piazza"},
+{"name": "annetta cell"},
+{"name": "justin nay"},
+{"name": "terri guice"},
+{"name": "bobby wier"},
+{"name": "marc pollack"},
+{"name": "greg prather"},
+{"name": "mark shander"},
+{"name": "peter minko"},
+{"name": "dell support"},
+{"name": "martina yang"},
+{"name": "joan thomas"},
+{"name": "amanda kenny"},
+{"name": "rachel shane"},
+{"name": "herb kashmanian"},
+{"name": "tony plumber"},
+{"name": "stephanie aenchbacher"},
+{"name": "sue rassekh"},
+{"name": "thanh friend"},
+{"name": "alan olivera"},
+{"name": "joe alltel"},
+{"name": "greg locke"},
+{"name": "gary eckloff"},
+{"name": "jon lowey"},
+{"name": "susan mejia"},
+{"name": "jennifer joseph"},
+{"name": "lenny nie"},
+{"name": "joe mcdonald"},
+{"name": "pam whitworth"},
+{"name": "stephen manes"},
+{"name": "andrew hawkins"},
+{"name": "laurie cunningha"},
+{"name": "min springfield"},
+{"name": "jeffrey woods"},
+{"name": "joe rogers"},
+{"name": "josh okrent"},
+{"name": "carly buchman"},
+{"name": "robin phillips"},
+{"name": "brian ba"},
+{"name": "melissa manning"},
+{"name": "gina l"},
+{"name": "travis mcberny"},
+{"name": "casey phobest"},
+{"name": "cory dummer"},
+{"name": "jack petropoulos"},
+{"name": "jason mocha"},
+{"name": "nigel burns"},
+{"name": "bryan nava"},
+{"name": "kip larson"},
+{"name": "mike o'brien"},
+{"name": "chris tennis"},
+{"name": "roger stein"},
+{"name": "jim dolan"},
+{"name": "len donato"},
+{"name": "scott piercy"},
+{"name": "danielle baker"},
+{"name": "pete pgi"},
+{"name": "joel campos"},
+{"name": "burton drayer"},
+{"name": "jim trains"},
+{"name": "eugene suggs"},
+{"name": "darren cell"},
+{"name": "kevin reil"},
+{"name": "ryan horn"},
+{"name": "scott bednarke"},
+{"name": "bryce tirrell"},
+{"name": "gerald sharkey"},
+{"name": "joe terribilini"},
+{"name": "megan devey"},
+{"name": "greg teal"},
+{"name": "larry tonini"},
+{"name": "william boren"},
+{"name": "chris mora"},
+{"name": "carma allen"},
+{"name": "steve martin"},
+{"name": "martha buess"},
+{"name": "mitch williams"},
+{"name": "jen focus"},
+{"name": "dan price"},
+{"name": "debbie hobart"},
+{"name": "robert larson"},
+{"name": "todd murphy"},
+{"name": "columbus dispatcher"},
+{"name": "tami gunselman"},
+{"name": "aracely valle"},
+{"name": "craig lake"},
+{"name": "suzy chapman"},
+{"name": "brian sterk"},
+{"name": "stacy p"},
+{"name": "jacqueline o'brien"},
+{"name": "kelsie morrow"},
+{"name": "sean noel"},
+{"name": "roman wasylechko"},
+{"name": "golden tan"},
+{"name": "brooke schaum"},
+{"name": "chris sherman"},
+{"name": "brenda ryan"},
+{"name": "susan tipton"},
+{"name": "kevin graff"},
+{"name": "marvin khemorro"},
+{"name": "ruth garcia"},
+{"name": "tim cozzi"},
+{"name": "lydia michigan"},
+{"name": "brad miron"},
+{"name": "justin aharoni"},
+{"name": "sarah dulatre"},
+{"name": "david hollis"},
+{"name": "dave metrice"},
+{"name": "anthony vocare"},
+{"name": "fern acres"},
+{"name": "stephen casbon"},
+{"name": "bo basic"},
+{"name": "heath belser"},
+{"name": "pam reynolds"},
+{"name": "ryan copenhaver"},
+{"name": "crystal hutton"},
+{"name": "doug partlow"},
+{"name": "jackie b"},
+{"name": "eddie karim"},
+{"name": "ashley burlage"},
+{"name": "kevin mctaggert"},
+{"name": "karen therapist"},
+{"name": "kevin burket"},
+{"name": "kim olstad"},
+{"name": "steve smidley"},
+{"name": "frank olsthoorn"},
+{"name": "ann mackenzie"},
+{"name": "mike padgett"},
+{"name": "todd stenhouse"},
+{"name": "troy funnell"},
+{"name": "john lewin"},
+{"name": "matt baillie"},
+{"name": "ben opticians"},
+{"name": "nicole atkins"},
+{"name": "margie wallace"},
+{"name": "john weddle"},
+{"name": "cory kurtz"},
+{"name": "adam willie"},
+{"name": "william whitlow"},
+{"name": "john pantano"},
+{"name": "brandon cr"},
+{"name": "lindsey langer"},
+{"name": "marsha lochridge"},
+{"name": "dominic charles"},
+{"name": "kathy sweatt"},
+{"name": "brenda ups"},
+{"name": "gus mendoza"},
+{"name": "ray allen"},
+{"name": "randy stamper"},
+{"name": "jeffrey grandy"},
+{"name": "scott smit"},
+{"name": "jackie willis"},
+{"name": "stacey gardner"},
+{"name": "kim stumbaugh"},
+{"name": "rich beard"},
+{"name": "bob korutz"},
+{"name": "paul gay"},
+{"name": "kevin jacks"},
+{"name": "betty guzman"},
+{"name": "luke daugherty"},
+{"name": "diana simmons"},
+{"name": "doug dresser"},
+{"name": "mark charlinski"},
+{"name": "jen trollinger"},
+{"name": "taylor gay"},
+{"name": "john lach"},
+{"name": "kevin leidig"},
+{"name": "kim carmack"},
+{"name": "melissa chartrey"},
+{"name": "shawn williams"},
+{"name": "missy hunter"},
+{"name": "jennifer crowell"},
+{"name": "david salman"},
+{"name": "beatriz gonzales"},
+{"name": "eddy crazy"},
+{"name": "rob hamilton"},
+{"name": "mike bro"},
+{"name": "victor moy"},
+{"name": "jason wade"},
+{"name": "mike battaligni"},
+{"name": "ryan hemans"},
+{"name": "jason caron"},
+{"name": "virginia schneider"},
+{"name": "bill schranko"},
+{"name": "bob gilbertson"},
+{"name": "greg farrar"},
+{"name": "brooke silvas"},
+{"name": "mark leonard"},
+{"name": "david bond"},
+{"name": "jay livers"},
+{"name": "tim cares"},
+{"name": "tyrone peoples"},
+{"name": "lindsay cannaday"},
+{"name": "gayle linde"},
+{"name": "johnny hernandez"},
+{"name": "ramona new"},
+{"name": "jaimie youssef"},
+{"name": "regina weir"},
+{"name": "justin gillon"},
+{"name": "mike lampigino"},
+{"name": "barry ziskind"},
+{"name": "frankie suda"},
+{"name": "sandy akins"},
+{"name": "nathan smack"},
+{"name": "jeremy voit"},
+{"name": "summer goreham"},
+{"name": "john nixon"},
+{"name": "morgan willis"},
+{"name": "keith pressman"},
+{"name": "chris cuevas"},
+{"name": "kirsten baldwin"},
+{"name": "george neely"},
+{"name": "dustin f"},
+{"name": "deanne wilkes"},
+{"name": "tracy smithee"},
+{"name": "sammy furtado"},
+{"name": "april cummings"},
+{"name": "brian flora"},
+{"name": "mike scarborough"},
+{"name": "lynn mcalister"},
+{"name": "carl mciver"},
+{"name": "ryan rachas"},
+{"name": "paul cannan"},
+{"name": "mike scarlata"},
+{"name": "linda soccer"},
+{"name": "stuart jones"},
+{"name": "debra stein"},
+{"name": "jeff acton"},
+{"name": "daniel hansen"},
+{"name": "stanley ference"},
+{"name": "jasper lee"},
+{"name": "shawn castleberry"},
+{"name": "lindsey horner"},
+{"name": "ray catuogno"},
+{"name": "todd bugg"},
+{"name": "jeff meyers"},
+{"name": "ron conway"},
+{"name": "jessica lau"},
+{"name": "lindsay mckinnon"},
+{"name": "jo cangianelli"},
+{"name": "barbara frazier"},
+{"name": "kieth harr"},
+{"name": "jen home"},
+{"name": "shirley brown"},
+{"name": "kim moat"},
+{"name": "albert reeves"},
+{"name": "joe pino"},
+{"name": "larry hartnett"},
+{"name": "jessica hobbins"},
+{"name": "kevin gangi"},
+{"name": "gerard centioli"},
+{"name": "melanie palomares"},
+{"name": "graham tenney"},
+{"name": "eric chapman"},
+{"name": "eileen bennett"},
+{"name": "chris sheehan"},
+{"name": "ann laffaye"},
+{"name": "tony truong"},
+{"name": "lyndon romero"},
+{"name": "rodney outland"},
+{"name": "chris turnage"},
+{"name": "ben terry"},
+{"name": "roxanne ruzicka"},
+{"name": "ryan phillips"},
+{"name": "nicholas amuchastegui"},
+{"name": "david james"},
+{"name": "matthew gabrielse"},
+{"name": "matt vandervoort"},
+{"name": "henry yaste"},
+{"name": "javier perez"},
+{"name": "hal noble"},
+{"name": "tom sommers"},
+{"name": "carleen copping"},
+{"name": "alexander moon"},
+{"name": "melanie thrower"},
+{"name": "jason wells"},
+{"name": "jay fraser"},
+{"name": "gary stacey"},
+{"name": "jill barfield"},
+{"name": "rhonda woodard"},
+{"name": "julia grimes"},
+{"name": "eddie girardi"},
+{"name": "chad carringer"},
+{"name": "peter schmitz"},
+{"name": "david lott"},
+{"name": "tom bardwell"},
+{"name": "larry shulman"},
+{"name": "james westford"},
+{"name": "ken mcnealy"},
+{"name": "patrick franks"},
+{"name": "phil rosenthal"},
+{"name": "nick b"},
+{"name": "albert dotson"},
+{"name": "sean beattie"},
+{"name": "gustavo ba"},
+{"name": "julie john"},
+{"name": "steve marra"},
+{"name": "nelson starlyn"},
+{"name": "brian cuzo"},
+{"name": "elisa thomas"},
+{"name": "joe crowley"},
+{"name": "isaac avanti"},
+{"name": "mark apt"},
+{"name": "colin poole"},
+{"name": "eric allen"},
+{"name": "lady vanessa"},
+{"name": "mike dj"},
+{"name": "robert eveleigh"},
+{"name": "travis york"},
+{"name": "james beckman"},
+{"name": "dawn bilings"},
+{"name": "lance bauerly"},
+{"name": "bradley erickson"},
+{"name": "gina eldridge"},
+{"name": "jason goodin"},
+{"name": "robin jones"},
+{"name": "jim manganoni"},
+{"name": "melody brinkley"},
+{"name": "mike stein"},
+{"name": "jason villard"},
+{"name": "ian kjerskagaard"},
+{"name": "dwayne romanchuk"},
+{"name": "ashley college"},
+{"name": "williams ii"},
+{"name": "ralph soest"},
+{"name": "danny iverson"},
+{"name": "ernie courson"},
+{"name": "ron berala"},
+{"name": "catherine simmons"},
+{"name": "dennis goodrich"},
+{"name": "brian moskowitz"},
+{"name": "mike maksimovic"},
+{"name": "jimmy banks"},
+{"name": "kate m"},
+{"name": "eric heubel"},
+{"name": "larry peters"},
+{"name": "daniel cozza"},
+{"name": "matt denicola"},
+{"name": "david ni"},
+{"name": "letha decaires"},
+{"name": "kareen larsen"},
+{"name": "terry khols"},
+{"name": "randi phillips"},
+{"name": "jeff jnl"},
+{"name": "mickey branson"},
+{"name": "jeremy richards"},
+{"name": "cynthia jutras"},
+{"name": "tia childres"},
+{"name": "chelsea store"},
+{"name": "emily provansal"},
+{"name": "cruz bautista"},
+{"name": "clay scrivner"},
+{"name": "lori baker"},
+{"name": "greg trinidad"},
+{"name": "leon lyons"},
+{"name": "alyssa sankin"},
+{"name": "alan freema"},
+{"name": "peter vogl"},
+{"name": "jill aguado"},
+{"name": "jason foster"},
+{"name": "virginia everard"},
+{"name": "tracey jackson"},
+{"name": "tiffany blakey"},
+{"name": "liz wood"},
+{"name": "david dejesus"},
+{"name": "joe eidel"},
+{"name": "levi bridges"},
+{"name": "tom orris"},
+{"name": "jeff micsky"},
+{"name": "teresa smith"},
+{"name": "jose palma"},
+{"name": "erin larson"},
+{"name": "kim pitman"},
+{"name": "susan ramirez"},
+{"name": "sandra becerra"},
+{"name": "danny iori"},
+{"name": "rochelle ferris"},
+{"name": "rod oconnor"},
+{"name": "doug porter"},
+{"name": "joseph mahendran"},
+{"name": "joann fitzpatrick"},
+{"name": "jeremy hastings"},
+{"name": "lisa scott"},
+{"name": "juan pacheco"},
+{"name": "laura e"},
+{"name": "rebecca seligstein"},
+{"name": "stephan gemine"},
+{"name": "keith penny"},
+{"name": "alex weathersby"},
+{"name": "raul camaligan"},
+{"name": "eric clemmons"},
+{"name": "bob cheryl"},
+{"name": "bob freedman"},
+{"name": "gary carreon"},
+{"name": "charles laurey"},
+{"name": "james hudsinker"},
+{"name": "sergio russo"},
+{"name": "chuck kennedy"},
+{"name": "randy dean"},
+{"name": "bill motley"},
+{"name": "ryan krishke"},
+{"name": "frank security"},
+{"name": "kris egbert"},
+{"name": "elliot moskowitz"},
+{"name": "cristina romero"},
+{"name": "kim tucker"},
+{"name": "steve norfolk"},
+{"name": "april saline"},
+{"name": "leonard schneider"},
+{"name": "tami kanitz"},
+{"name": "nick motto"},
+{"name": "sheldon morrison"},
+{"name": "ken liken"},
+{"name": "porter casey"},
+{"name": "matt fur"},
+{"name": "kit sullivan"},
+{"name": "jay adkisson"},
+{"name": "russell darrington"},
+{"name": "mitchell house"},
+{"name": "ronnie walton"},
+{"name": "jenna light"},
+{"name": "amber meshberger"},
+{"name": "shannon treglown"},
+{"name": "nickie paulate"},
+{"name": "mike iunker"},
+{"name": "cliff barber"},
+{"name": "cierra baxter"},
+{"name": "anna saah"},
+{"name": "larue steward"},
+{"name": "josh mcmeechan"},
+{"name": "brad beelaert"},
+{"name": "aaron ollivier"},
+{"name": "john cavallo"},
+{"name": "christine duprez"},
+{"name": "charlie stellini"},
+{"name": "paul waits"},
+{"name": "boyd elgin"},
+{"name": "chuck knapp"},
+{"name": "kelly k"},
+{"name": "sherie frehner"},
+{"name": "britney burton"},
+{"name": "gigi work"},
+{"name": "elaine biancamano"},
+{"name": "vince buffa"},
+{"name": "mike coffey"},
+{"name": "doug w"},
+{"name": "dave long"},
+{"name": "roger terrell"},
+{"name": "krishna kashyap"},
+{"name": "harold rosenfeld"},
+{"name": "sonia piano"},
+{"name": "antonio tenorio"},
+{"name": "guy bruno"},
+{"name": "mark gittens"},
+{"name": "anya jogie"},
+{"name": "jill schnepf"},
+{"name": "larry mactee"},
+{"name": "derek barvoets"},
+{"name": "bill wheelock"},
+{"name": "lauren gilomen"},
+{"name": "david ninkovich"},
+{"name": "mike brey"},
+{"name": "danny buhdda"},
+{"name": "thomas mirsen"},
+{"name": "jodi brockington"},
+{"name": "burt levine"},
+{"name": "mike isom"},
+{"name": "jeff hanson"},
+{"name": "mark kocur"},
+{"name": "ronny freeman"},
+{"name": "lloyd moore"},
+{"name": "barbara shore"},
+{"name": "stephanie boyer"},
+{"name": "ron wood"},
+{"name": "brian weinstein"},
+{"name": "dustin harwell"},
+{"name": "alex nash"},
+{"name": "mary meyeda"},
+{"name": "andrea grim"},
+{"name": "keith brazil"},
+{"name": "charles tomek"},
+{"name": "will engel"},
+{"name": "tim whitley"},
+{"name": "elvis lawson"},
+{"name": "molly peters"},
+{"name": "sherwood glen"},
+{"name": "joe spaldingl"},
+{"name": "annmarie colasanti"},
+{"name": "tony nguyen"},
+{"name": "dennis pool"},
+{"name": "bill gilliand"},
+{"name": "james crum"},
+{"name": "joan dooley"},
+{"name": "sarah hoobler"},
+{"name": "peter brambl"},
+{"name": "jack young"},
+{"name": "stephan auerbach"},
+{"name": "liz tmo"},
+{"name": "kristen mccoy"},
+{"name": "billy j"},
+{"name": "amanda salzman"},
+{"name": "brian maldonado"},
+{"name": "dave gronceski"},
+{"name": "martine garcon"},
+{"name": "andy cockle"},
+{"name": "suzi thek"},
+{"name": "dan theovenman"},
+{"name": "james brager"},
+{"name": "gloria silver"},
+{"name": "willie b"},
+{"name": "ed soares"},
+{"name": "allan toledo"},
+{"name": "mike frei"},
+{"name": "paul lenagh"},
+{"name": "ryan onishi"},
+{"name": "jessica mayor"},
+{"name": "megan feusner"},
+{"name": "dario casa"},
+{"name": "mike abdullah"},
+{"name": "catherine tsuruoka"},
+{"name": "patty sailors"},
+{"name": "stuart gedal"},
+{"name": "rebecca keogh"},
+{"name": "chris santos"},
+{"name": "bill pics"},
+{"name": "harley jackson"},
+{"name": "caryn lee"},
+{"name": "jaime cunanan"},
+{"name": "ila biser"},
+{"name": "lorie webb"},
+{"name": "nadia chaudhry"},
+{"name": "joshua spencer"},
+{"name": "toni brooks"},
+{"name": "james sheppard"},
+{"name": "marcel mandroc"},
+{"name": "joe amio"},
+{"name": "dave roughton"},
+{"name": "raymond flores"},
+{"name": "brandy coote"},
+{"name": "gabriella novotny"},
+{"name": "micheal alvis"},
+{"name": "maria bustillos"},
+{"name": "kelly karole"},
+{"name": "kristy cox"},
+{"name": "stephanie pucin"},
+{"name": "robert richardson"},
+{"name": "bruno gerber"},
+{"name": "claude fortier"},
+{"name": "robert metter"},
+{"name": "nancy nardoni"},
+{"name": "paige lombardo"},
+{"name": "danny d"},
+{"name": "rachel cooke"},
+{"name": "sam bell"},
+{"name": "letty canals"},
+{"name": "andy zaleta"},
+{"name": "linda frankel"},
+{"name": "bunny james"},
+{"name": "bill d"},
+{"name": "patrick penner"},
+{"name": "vanessa faustino"},
+{"name": "meagan leis"},
+{"name": "ed chomik"},
+{"name": "tia jess"},
+{"name": "michael farlow"},
+{"name": "matt moore"},
+{"name": "john bleid"},
+{"name": "tim heidi"},
+{"name": "raymond thompson"},
+{"name": "howard kummer"},
+{"name": "eli karp"},
+{"name": "wallace howard"},
+{"name": "ryan circa"},
+{"name": "julie stout"},
+{"name": "jan press"},
+{"name": "mark t"},
+{"name": "greg mccormick"},
+{"name": "ed howell"},
+{"name": "joan soltan"},
+{"name": "raymond schiefen"},
+{"name": "margery shanoff"},
+{"name": "leo schrubb"},
+{"name": "cliff joyner"},
+{"name": "michael tang"},
+{"name": "phylis fitzpatrick"},
+{"name": "carole noel"},
+{"name": "debbie beardsley"},
+{"name": "paul kushner"},
+{"name": "steve wickes"},
+{"name": "min jones"},
+{"name": "raul laguna"},
+{"name": "luis morales"},
+{"name": "robert stanton"},
+{"name": "karla larumbe"},
+{"name": "janet jones"},
+{"name": "drew brooks"},
+{"name": "michael zibby"},
+{"name": "kaylee b"},
+{"name": "kevin d"},
+{"name": "laveta jarrett"},
+{"name": "betty ward"},
+{"name": "lauren carden"},
+{"name": "jane leverone"},
+{"name": "john rucker"},
+{"name": "john chalif"},
+{"name": "lynn hughes"},
+{"name": "jon eliassen"},
+{"name": "edward coffey"},
+{"name": "gracie williams"},
+{"name": "art sepulveda"},
+{"name": "jon severson"},
+{"name": "dan kondziela"},
+{"name": "ila silberstein"},
+{"name": "ted holcomb"},
+{"name": "natasha wilsom"},
+{"name": "karl price"},
+{"name": "jim steed"},
+{"name": "chris condit"},
+{"name": "steve wallock"},
+{"name": "kellie sawler"},
+{"name": "stephanie seiboth"},
+{"name": "shannon flathers"},
+{"name": "chris weathers"},
+{"name": "lana guzman"},
+{"name": "chris coke"},
+{"name": "brian hammond"},
+{"name": "jim deforest"},
+{"name": "johnny murphy"},
+{"name": "marvin rapaport"},
+{"name": "shirley ma"},
+{"name": "steve carver"},
+{"name": "mary allen"},
+{"name": "bob nightwalker"},
+{"name": "mike fireplace"},
+{"name": "ike sushi"},
+{"name": "steve cynar"},
+{"name": "andy barborak"},
+{"name": "steven radunzel"},
+{"name": "jerry reese"},
+{"name": "jess r"},
+{"name": "liz brownson"},
+{"name": "jesus balbastro"},
+{"name": "jennifer watt"},
+{"name": "carlos cabeza"},
+{"name": "le tenis"},
+{"name": "barbara anthony"},
+{"name": "brent tomlin"},
+{"name": "tony sidekick"},
+{"name": "paul hanley"},
+{"name": "keri dunning"},
+{"name": "paige randall"},
+{"name": "jean duffin"},
+{"name": "pa jeffry"},
+{"name": "jane hadley"},
+{"name": "susan kurland"},
+{"name": "jay lindemann"},
+{"name": "anthony tucker"},
+{"name": "rod v"},
+{"name": "abby la"},
+{"name": "chris gentles"},
+{"name": "steve podium"},
+{"name": "karen wixom"},
+{"name": "ricky stephens"},
+{"name": "nathan camp"},
+{"name": "jill hirayama"},
+{"name": "audrey hamik"},
+{"name": "jay owens"},
+{"name": "caitlin slavka"},
+{"name": "julia molina"},
+{"name": "kevin o'connell"},
+{"name": "john dimatteo"},
+{"name": "mike villers"},
+{"name": "david aragon"},
+{"name": "tara gee"},
+{"name": "denise fiore"},
+{"name": "sue byrd"},
+{"name": "melanie barkers"},
+{"name": "heather o"},
+{"name": "rocio perez"},
+{"name": "eddie vasquez"},
+{"name": "torrie griffin"},
+{"name": "keri schadler"},
+{"name": "dave suarez"},
+{"name": "isabel kallman"},
+{"name": "darryl clark"},
+{"name": "nick porneala"},
+{"name": "janessa cell"},
+{"name": "dana hunter"},
+{"name": "harry spencer"},
+{"name": "jerry vancook"},
+{"name": "ira phone"},
+{"name": "terese stanek"},
+{"name": "hayden plimmer"},
+{"name": "dick eastman"},
+{"name": "ron bushnell"},
+{"name": "robin chaffin"},
+{"name": "ron grady"},
+{"name": "nikki clay"},
+{"name": "jeffrey wylie"},
+{"name": "mark biggers"},
+{"name": "cameron powell"},
+{"name": "diana office"},
+{"name": "kyle harms"},
+{"name": "jong han"},
+{"name": "robby padilla"},
+{"name": "arlene cabalatazan"},
+{"name": "james fatta"},
+{"name": "susy weibe"},
+{"name": "terry way"},
+{"name": "justin koolas"},
+{"name": "jeannette o'connor"},
+{"name": "julie cevette"},
+{"name": "daniel santil"},
+{"name": "george pauline"},
+{"name": "imelda sandoval"},
+{"name": "ben mcknight"},
+{"name": "melissa chan"},
+{"name": "alonzo lamarque"},
+{"name": "jake salwolke"},
+{"name": "mark cox"},
+{"name": "carol hanson"},
+{"name": "fred carnero"},
+{"name": "jean stefano"},
+{"name": "demetria lucas"},
+{"name": "libby lehman"},
+{"name": "leslie cliffs"},
+{"name": "nancy sigmund"},
+{"name": "bill l"},
+{"name": "tiana breniesse"},
+{"name": "todd beane"},
+{"name": "stewart freger"},
+{"name": "jerry vrabic"},
+{"name": "matt pierz"},
+{"name": "mike primo"},
+{"name": "alan prather"},
+{"name": "james penn"},
+{"name": "michael arevalo"},
+{"name": "jackie macdonald"},
+{"name": "brandon raybourne"},
+{"name": "aaron chavez"},
+{"name": "tara more"},
+{"name": "anna zastrow"},
+{"name": "diane couch"},
+{"name": "joe shively"},
+{"name": "yolande jones"},
+{"name": "don dillion"},
+{"name": "emily truong"},
+{"name": "dave deel"},
+{"name": "talitha fremont"},
+{"name": "jennifer marciniak"},
+{"name": "bella smith"},
+{"name": "damon ousley"},
+{"name": "brandon lungren"},
+{"name": "ross website"},
+{"name": "scott parker"},
+{"name": "craig hines"},
+{"name": "wally hunter"},
+{"name": "melissa wesd"},
+{"name": "bryan p"},
+{"name": "tom giordano"},
+{"name": "margaret whitesi"},
+{"name": "chris lytle"},
+{"name": "victor samaha"},
+{"name": "mark coyote"},
+{"name": "jose bormey"},
+{"name": "ralph finch"},
+{"name": "rich rodriguez"},
+{"name": "hank horowitz"},
+{"name": "doug shmalzle"},
+{"name": "mark neal"},
+{"name": "davis current"},
+{"name": "kelly gedinsky"},
+{"name": "derrick arakelian"},
+{"name": "josh cates"},
+{"name": "daniel wong"},
+{"name": "sharon hagins"},
+{"name": "cynthia giles"},
+{"name": "greg morris"},
+{"name": "erin mcdonald"},
+{"name": "peter arkley"},
+{"name": "josh ireland"},
+{"name": "jeanette vinnys"},
+{"name": "jon hibbard"},
+{"name": "justin nassie"},
+{"name": "heather mychaylo"},
+{"name": "mark voight"},
+{"name": "laci x"},
+{"name": "thomas kemp"},
+{"name": "kendra carmichael"},
+{"name": "stephen winters"},
+{"name": "lee lofgren"},
+{"name": "avery cell"},
+{"name": "kathy ferrey"},
+{"name": "angelia fritter"},
+{"name": "ed ryan"},
+{"name": "dana garcia"},
+{"name": "mandy s"},
+{"name": "lachelle maxwell"},
+{"name": "andrew quigley"},
+{"name": "sandra roxy"},
+{"name": "nancy trujillo"},
+{"name": "lynne erickson"},
+{"name": "kyle soccer"},
+{"name": "deirdre bischoff"},
+{"name": "leigh nauman"},
+{"name": "amy hansen"},
+{"name": "debbie switzenbaum"},
+{"name": "steve gluck"},
+{"name": "fred kikuchi"},
+{"name": "michelle cooley"},
+{"name": "suzy johnson"},
+{"name": "joe cargill"},
+{"name": "jeff martin"},
+{"name": "ashley fowler"},
+{"name": "melisa k"},
+{"name": "genevieve davis"},
+{"name": "corey medaris"},
+{"name": "joanne eancone"},
+{"name": "mike frazier"},
+{"name": "adam noppen"},
+{"name": "kenneth booker"},
+{"name": "alix krey"},
+{"name": "chris soseman"},
+{"name": "juan alvarez"},
+{"name": "steve luker"},
+{"name": "laura caravello"},
+{"name": "rico guitar"},
+{"name": "randy ingalls"},
+{"name": "robert lemen"},
+{"name": "terrence giles"},
+{"name": "stacey corbin"},
+{"name": "brian hollingsworth"},
+{"name": "guy kapuscinsky"},
+{"name": "keven rachel"},
+{"name": "erica altenhoff"},
+{"name": "jackie aguilar"},
+{"name": "jamie hensley"},
+{"name": "jeff sayer"},
+{"name": "bradley midtlien"},
+{"name": "courtney kelso"},
+{"name": "randy balhorn"},
+{"name": "jason bigge"},
+{"name": "britany neal"},
+{"name": "lyndon byam"},
+{"name": "kelsey shultz"},
+{"name": "sarah lovell"},
+{"name": "ethan orpilla"},
+{"name": "trey chase"},
+{"name": "nick monti"},
+{"name": "kelli oar"},
+{"name": "scott kelley"},
+{"name": "dianne james"},
+{"name": "jennifer keeler"},
+{"name": "scott c"},
+{"name": "rachael franks"},
+{"name": "sal pascent"},
+{"name": "scott hallmeyer"},
+{"name": "harry gold"},
+{"name": "julie tran"},
+{"name": "justin goins"},
+{"name": "joe rice"},
+{"name": "deb beebe"},
+{"name": "brian gregg"},
+{"name": "denise c"},
+{"name": "peter bichler"},
+{"name": "brandon lacoste"},
+{"name": "warren nb"},
+{"name": "vanessa rolfe"},
+{"name": "yvonne gonzales"},
+{"name": "darrell truitt"},
+{"name": "anne brummel"},
+{"name": "jeri idso"},
+{"name": "brad shinaut"},
+{"name": "sylvia israel"},
+{"name": "christina oliveras"},
+{"name": "andrew cason"},
+{"name": "pamela smith"},
+{"name": "rhea valenzuela"},
+{"name": "taylor cell"},
+{"name": "marisa victory"},
+{"name": "brandon epstein"},
+{"name": "rebecca feldman"},
+{"name": "steven haddad"},
+{"name": "sarai paljetak"},
+{"name": "david bergeron"},
+{"name": "allison hooker"},
+{"name": "lauri duplessis"},
+{"name": "jill sturgeon"},
+{"name": "marc alvarez"},
+{"name": "roger shiltz"},
+{"name": "cary lemons"},
+{"name": "greg kessner"},
+{"name": "cindy hooker"},
+{"name": "neil zuccato"},
+{"name": "kate wheadon"},
+{"name": "jennifer valencia"},
+{"name": "heather jarsso"},
+{"name": "eric basketball"},
+{"name": "sandra mceachern"},
+{"name": "jessica jackson"},
+{"name": "heidi ambrosius"},
+{"name": "tom isabella"},
+{"name": "tasha bridges"},
+{"name": "james guanzon"},
+{"name": "matt broad"},
+{"name": "steve hanson"},
+{"name": "tony tuor"},
+{"name": "sasha st"},
+{"name": "wayne krietz"},
+{"name": "kim harris"},
+{"name": "willis horak"},
+{"name": "seth peterson"},
+{"name": "lynette wright"},
+{"name": "dawn trotter"},
+{"name": "kyle keyser"},
+{"name": "john shults"},
+{"name": "bryan pennington"},
+{"name": "mike lambert"},
+{"name": "will seret"},
+{"name": "matt duhnam"},
+{"name": "robert long"},
+{"name": "marcel puyk"},
+{"name": "hannah physics"},
+{"name": "dan mcarthy"},
+{"name": "nick smith"},
+{"name": "bonnie james"},
+{"name": "alejandra cuevas"},
+{"name": "jenna kashou"},
+{"name": "greg martayan"},
+{"name": "jonathan sooriash"},
+{"name": "janice kaniewski"},
+{"name": "rebecca cullen"},
+{"name": "gary mckee"},
+{"name": "ken burgess"},
+{"name": "raven simone"},
+{"name": "shane rhoades"},
+{"name": "glenn jelks"},
+{"name": "randy tieg"},
+{"name": "wilson rita"},
+{"name": "ashley genske"},
+{"name": "bill boehm"},
+{"name": "robyn zeller"},
+{"name": "jennifer berry"},
+{"name": "jin woo"},
+{"name": "jim brun"},
+{"name": "ashley mom"},
+{"name": "mike gallen"},
+{"name": "michael jay"},
+{"name": "scott kam"},
+{"name": "mary jensen"},
+{"name": "luke reinbolt"},
+{"name": "frank trout"}
+]
diff --git a/tests/auto/daemon/largeContactsTest33k.json b/tests/auto/daemon/largeContactsTest33k.json
new file mode 100644
index 00000000..5c6d37b2
--- /dev/null
+++ b/tests/auto/daemon/largeContactsTest33k.json
@@ -0,0 +1,33290 @@
+[
+{"name": "marcia d'arcy"},
+{"name": "jeffrey samuels"},
+{"name": "robert demmon"},
+{"name": "heidi motika"},
+{"name": "leslie pugh"},
+{"name": "ryan houlette"},
+{"name": "kenton kossan"},
+{"name": "connie goddard"},
+{"name": "andrew keopraseuth"},
+{"name": "charlie stern"},
+{"name": "alex free"},
+{"name": "glenn legros"},
+{"name": "sean joyce"},
+{"name": "bruce toth"},
+{"name": "amanda vaneffen"},
+{"name": "gary huss"},
+{"name": "stan young"},
+{"name": "jaclyn gregory"},
+{"name": "ryan sepulveda"},
+{"name": "thomas reim"},
+{"name": "matt ryan"},
+{"name": "matt muralt"},
+{"name": "jason lau"},
+{"name": "blake kewish"},
+{"name": "scott budge"},
+{"name": "keith archer"},
+{"name": "david hubb"},
+{"name": "joseph tsai"},
+{"name": "alla pimenov"},
+{"name": "marina albright"},
+{"name": "tim carver"},
+{"name": "rachel palomino"},
+{"name": "chris gaddis"},
+{"name": "ken boerman"},
+{"name": "annie kiang"},
+{"name": "allison aronne"},
+{"name": "jessica fritch"},
+{"name": "deb haffey"},
+{"name": "moshe shields"},
+{"name": "kyle thomas"},
+{"name": "becky hughes"},
+{"name": "dustin schneider"},
+{"name": "mary hardwick"},
+{"name": "andrew client"},
+{"name": "david conley"},
+{"name": "vicky lokis"},
+{"name": "cameron white"},
+{"name": "nicole rolland"},
+{"name": "jaime piazza"},
+{"name": "annetta cell"},
+{"name": "justin nay"},
+{"name": "terri guice"},
+{"name": "bobby wier"},
+{"name": "marc pollack"},
+{"name": "greg prather"},
+{"name": "mark shander"},
+{"name": "peter minko"},
+{"name": "dell support"},
+{"name": "martina yang"},
+{"name": "joan thomas"},
+{"name": "amanda kenny"},
+{"name": "rachel shane"},
+{"name": "herb kashmanian"},
+{"name": "tony plumber"},
+{"name": "stephanie aenchbacher"},
+{"name": "sue rassekh"},
+{"name": "thanh friend"},
+{"name": "alan olivera"},
+{"name": "joe alltel"},
+{"name": "greg locke"},
+{"name": "gary eckloff"},
+{"name": "jon lowey"},
+{"name": "susan mejia"},
+{"name": "jennifer joseph"},
+{"name": "lenny nie"},
+{"name": "joe mcdonald"},
+{"name": "pam whitworth"},
+{"name": "stephen manes"},
+{"name": "andrew hawkins"},
+{"name": "laurie cunningha"},
+{"name": "min springfield"},
+{"name": "jeffrey woods"},
+{"name": "joe rogers"},
+{"name": "josh okrent"},
+{"name": "carly buchman"},
+{"name": "robin phillips"},
+{"name": "brian ba"},
+{"name": "melissa manning"},
+{"name": "gina l"},
+{"name": "travis mcberny"},
+{"name": "casey phobest"},
+{"name": "cory dummer"},
+{"name": "jack petropoulos"},
+{"name": "jason mocha"},
+{"name": "nigel burns"},
+{"name": "bryan nava"},
+{"name": "kip larson"},
+{"name": "mike o'brien"},
+{"name": "chris tennis"},
+{"name": "roger stein"},
+{"name": "jim dolan"},
+{"name": "len donato"},
+{"name": "scott piercy"},
+{"name": "danielle baker"},
+{"name": "pete pgi"},
+{"name": "joel campos"},
+{"name": "burton drayer"},
+{"name": "jim trains"},
+{"name": "eugene suggs"},
+{"name": "darren cell"},
+{"name": "kevin reil"},
+{"name": "ryan horn"},
+{"name": "scott bednarke"},
+{"name": "bryce tirrell"},
+{"name": "gerald sharkey"},
+{"name": "joe terribilini"},
+{"name": "megan devey"},
+{"name": "greg teal"},
+{"name": "larry tonini"},
+{"name": "william boren"},
+{"name": "chris mora"},
+{"name": "carma allen"},
+{"name": "steve martin"},
+{"name": "martha buess"},
+{"name": "mitch williams"},
+{"name": "jen focus"},
+{"name": "dan price"},
+{"name": "debbie hobart"},
+{"name": "robert larson"},
+{"name": "todd murphy"},
+{"name": "columbus dispatcher"},
+{"name": "tami gunselman"},
+{"name": "aracely valle"},
+{"name": "craig lake"},
+{"name": "suzy chapman"},
+{"name": "brian sterk"},
+{"name": "stacy p"},
+{"name": "jacqueline o'brien"},
+{"name": "kelsie morrow"},
+{"name": "sean noel"},
+{"name": "roman wasylechko"},
+{"name": "golden tan"},
+{"name": "brooke schaum"},
+{"name": "chris sherman"},
+{"name": "brenda ryan"},
+{"name": "susan tipton"},
+{"name": "kevin graff"},
+{"name": "marvin khemorro"},
+{"name": "ruth garcia"},
+{"name": "tim cozzi"},
+{"name": "lydia michigan"},
+{"name": "brad miron"},
+{"name": "justin aharoni"},
+{"name": "sarah dulatre"},
+{"name": "david hollis"},
+{"name": "dave metrice"},
+{"name": "anthony vocare"},
+{"name": "fern acres"},
+{"name": "stephen casbon"},
+{"name": "bo basic"},
+{"name": "heath belser"},
+{"name": "pam reynolds"},
+{"name": "ryan copenhaver"},
+{"name": "crystal hutton"},
+{"name": "doug partlow"},
+{"name": "jackie b"},
+{"name": "eddie karim"},
+{"name": "ashley burlage"},
+{"name": "kevin mctaggert"},
+{"name": "karen therapist"},
+{"name": "kevin burket"},
+{"name": "kim olstad"},
+{"name": "steve smidley"},
+{"name": "frank olsthoorn"},
+{"name": "ann mackenzie"},
+{"name": "mike padgett"},
+{"name": "todd stenhouse"},
+{"name": "troy funnell"},
+{"name": "john lewin"},
+{"name": "matt baillie"},
+{"name": "ben opticians"},
+{"name": "nicole atkins"},
+{"name": "margie wallace"},
+{"name": "john weddle"},
+{"name": "cory kurtz"},
+{"name": "adam willie"},
+{"name": "william whitlow"},
+{"name": "john pantano"},
+{"name": "brandon cr"},
+{"name": "lindsey langer"},
+{"name": "marsha lochridge"},
+{"name": "dominic charles"},
+{"name": "kathy sweatt"},
+{"name": "brenda ups"},
+{"name": "gus mendoza"},
+{"name": "ray allen"},
+{"name": "randy stamper"},
+{"name": "jeffrey grandy"},
+{"name": "scott smit"},
+{"name": "jackie willis"},
+{"name": "stacey gardner"},
+{"name": "kim stumbaugh"},
+{"name": "rich beard"},
+{"name": "bob korutz"},
+{"name": "paul gay"},
+{"name": "kevin jacks"},
+{"name": "betty guzman"},
+{"name": "luke daugherty"},
+{"name": "diana simmons"},
+{"name": "doug dresser"},
+{"name": "mark charlinski"},
+{"name": "jen trollinger"},
+{"name": "taylor gay"},
+{"name": "john lach"},
+{"name": "kevin leidig"},
+{"name": "kim carmack"},
+{"name": "melissa chartrey"},
+{"name": "shawn williams"},
+{"name": "missy hunter"},
+{"name": "jennifer crowell"},
+{"name": "david salman"},
+{"name": "beatriz gonzales"},
+{"name": "eddy crazy"},
+{"name": "rob hamilton"},
+{"name": "mike bro"},
+{"name": "victor moy"},
+{"name": "jason wade"},
+{"name": "mike battaligni"},
+{"name": "ryan hemans"},
+{"name": "jason caron"},
+{"name": "virginia schneider"},
+{"name": "bill schranko"},
+{"name": "bob gilbertson"},
+{"name": "greg farrar"},
+{"name": "brooke silvas"},
+{"name": "mark leonard"},
+{"name": "david bond"},
+{"name": "jay livers"},
+{"name": "tim cares"},
+{"name": "tyrone peoples"},
+{"name": "lindsay cannaday"},
+{"name": "gayle linde"},
+{"name": "johnny hernandez"},
+{"name": "ramona new"},
+{"name": "jaimie youssef"},
+{"name": "regina weir"},
+{"name": "justin gillon"},
+{"name": "mike lampigino"},
+{"name": "barry ziskind"},
+{"name": "frankie suda"},
+{"name": "sandy akins"},
+{"name": "nathan smack"},
+{"name": "jeremy voit"},
+{"name": "summer goreham"},
+{"name": "john nixon"},
+{"name": "morgan willis"},
+{"name": "keith pressman"},
+{"name": "chris cuevas"},
+{"name": "kirsten baldwin"},
+{"name": "george neely"},
+{"name": "dustin f"},
+{"name": "deanne wilkes"},
+{"name": "tracy smithee"},
+{"name": "sammy furtado"},
+{"name": "april cummings"},
+{"name": "brian flora"},
+{"name": "mike scarborough"},
+{"name": "lynn mcalister"},
+{"name": "carl mciver"},
+{"name": "ryan rachas"},
+{"name": "paul cannan"},
+{"name": "mike scarlata"},
+{"name": "linda soccer"},
+{"name": "stuart jones"},
+{"name": "debra stein"},
+{"name": "jeff acton"},
+{"name": "daniel hansen"},
+{"name": "stanley ference"},
+{"name": "jasper lee"},
+{"name": "shawn castleberry"},
+{"name": "lindsey horner"},
+{"name": "ray catuogno"},
+{"name": "todd bugg"},
+{"name": "jeff meyers"},
+{"name": "ron conway"},
+{"name": "jessica lau"},
+{"name": "lindsay mckinnon"},
+{"name": "jo cangianelli"},
+{"name": "barbara frazier"},
+{"name": "kieth harr"},
+{"name": "jen home"},
+{"name": "shirley brown"},
+{"name": "kim moat"},
+{"name": "albert reeves"},
+{"name": "joe pino"},
+{"name": "larry hartnett"},
+{"name": "jessica hobbins"},
+{"name": "kevin gangi"},
+{"name": "gerard centioli"},
+{"name": "melanie palomares"},
+{"name": "graham tenney"},
+{"name": "eric chapman"},
+{"name": "eileen bennett"},
+{"name": "chris sheehan"},
+{"name": "ann laffaye"},
+{"name": "tony truong"},
+{"name": "lyndon romero"},
+{"name": "rodney outland"},
+{"name": "chris turnage"},
+{"name": "ben terry"},
+{"name": "roxanne ruzicka"},
+{"name": "ryan phillips"},
+{"name": "nicholas amuchastegui"},
+{"name": "david james"},
+{"name": "matthew gabrielse"},
+{"name": "matt vandervoort"},
+{"name": "henry yaste"},
+{"name": "javier perez"},
+{"name": "hal noble"},
+{"name": "tom sommers"},
+{"name": "carleen copping"},
+{"name": "alexander moon"},
+{"name": "melanie thrower"},
+{"name": "jason wells"},
+{"name": "jay fraser"},
+{"name": "gary stacey"},
+{"name": "jill barfield"},
+{"name": "rhonda woodard"},
+{"name": "julia grimes"},
+{"name": "eddie girardi"},
+{"name": "chad carringer"},
+{"name": "peter schmitz"},
+{"name": "david lott"},
+{"name": "tom bardwell"},
+{"name": "larry shulman"},
+{"name": "james westford"},
+{"name": "ken mcnealy"},
+{"name": "patrick franks"},
+{"name": "phil rosenthal"},
+{"name": "nick b"},
+{"name": "albert dotson"},
+{"name": "sean beattie"},
+{"name": "gustavo ba"},
+{"name": "julie john"},
+{"name": "steve marra"},
+{"name": "nelson starlyn"},
+{"name": "brian cuzo"},
+{"name": "elisa thomas"},
+{"name": "joe crowley"},
+{"name": "isaac avanti"},
+{"name": "mark apt"},
+{"name": "colin poole"},
+{"name": "eric allen"},
+{"name": "lady vanessa"},
+{"name": "mike dj"},
+{"name": "robert eveleigh"},
+{"name": "travis york"},
+{"name": "james beckman"},
+{"name": "dawn bilings"},
+{"name": "lance bauerly"},
+{"name": "bradley erickson"},
+{"name": "gina eldridge"},
+{"name": "jason goodin"},
+{"name": "robin jones"},
+{"name": "jim manganoni"},
+{"name": "melody brinkley"},
+{"name": "mike stein"},
+{"name": "jason villard"},
+{"name": "ian kjerskagaard"},
+{"name": "dwayne romanchuk"},
+{"name": "ashley college"},
+{"name": "williams ii"},
+{"name": "ralph soest"},
+{"name": "danny iverson"},
+{"name": "ernie courson"},
+{"name": "ron berala"},
+{"name": "catherine simmons"},
+{"name": "dennis goodrich"},
+{"name": "brian moskowitz"},
+{"name": "mike maksimovic"},
+{"name": "jimmy banks"},
+{"name": "kate m"},
+{"name": "eric heubel"},
+{"name": "larry peters"},
+{"name": "daniel cozza"},
+{"name": "matt denicola"},
+{"name": "david ni"},
+{"name": "letha decaires"},
+{"name": "kareen larsen"},
+{"name": "terry khols"},
+{"name": "randi phillips"},
+{"name": "jeff jnl"},
+{"name": "mickey branson"},
+{"name": "jeremy richards"},
+{"name": "cynthia jutras"},
+{"name": "tia childres"},
+{"name": "chelsea store"},
+{"name": "emily provansal"},
+{"name": "cruz bautista"},
+{"name": "clay scrivner"},
+{"name": "lori baker"},
+{"name": "greg trinidad"},
+{"name": "leon lyons"},
+{"name": "alyssa sankin"},
+{"name": "alan freema"},
+{"name": "peter vogl"},
+{"name": "jill aguado"},
+{"name": "jason foster"},
+{"name": "virginia everard"},
+{"name": "tracey jackson"},
+{"name": "tiffany blakey"},
+{"name": "liz wood"},
+{"name": "david dejesus"},
+{"name": "joe eidel"},
+{"name": "levi bridges"},
+{"name": "tom orris"},
+{"name": "jeff micsky"},
+{"name": "teresa smith"},
+{"name": "jose palma"},
+{"name": "erin larson"},
+{"name": "kim pitman"},
+{"name": "susan ramirez"},
+{"name": "sandra becerra"},
+{"name": "danny iori"},
+{"name": "rochelle ferris"},
+{"name": "rod oconnor"},
+{"name": "doug porter"},
+{"name": "joseph mahendran"},
+{"name": "joann fitzpatrick"},
+{"name": "jeremy hastings"},
+{"name": "lisa scott"},
+{"name": "juan pacheco"},
+{"name": "laura e"},
+{"name": "rebecca seligstein"},
+{"name": "stephan gemine"},
+{"name": "keith penny"},
+{"name": "alex weathersby"},
+{"name": "raul camaligan"},
+{"name": "eric clemmons"},
+{"name": "bob cheryl"},
+{"name": "bob freedman"},
+{"name": "gary carreon"},
+{"name": "charles laurey"},
+{"name": "james hudsinker"},
+{"name": "sergio russo"},
+{"name": "chuck kennedy"},
+{"name": "randy dean"},
+{"name": "bill motley"},
+{"name": "ryan krishke"},
+{"name": "frank security"},
+{"name": "kris egbert"},
+{"name": "elliot moskowitz"},
+{"name": "cristina romero"},
+{"name": "kim tucker"},
+{"name": "steve norfolk"},
+{"name": "april saline"},
+{"name": "leonard schneider"},
+{"name": "tami kanitz"},
+{"name": "nick motto"},
+{"name": "sheldon morrison"},
+{"name": "ken liken"},
+{"name": "porter casey"},
+{"name": "matt fur"},
+{"name": "kit sullivan"},
+{"name": "jay adkisson"},
+{"name": "russell darrington"},
+{"name": "mitchell house"},
+{"name": "ronnie walton"},
+{"name": "jenna light"},
+{"name": "amber meshberger"},
+{"name": "shannon treglown"},
+{"name": "nickie paulate"},
+{"name": "mike iunker"},
+{"name": "cliff barber"},
+{"name": "cierra baxter"},
+{"name": "anna saah"},
+{"name": "larue steward"},
+{"name": "josh mcmeechan"},
+{"name": "brad beelaert"},
+{"name": "aaron ollivier"},
+{"name": "john cavallo"},
+{"name": "christine duprez"},
+{"name": "charlie stellini"},
+{"name": "paul waits"},
+{"name": "boyd elgin"},
+{"name": "chuck knapp"},
+{"name": "kelly k"},
+{"name": "sherie frehner"},
+{"name": "britney burton"},
+{"name": "gigi work"},
+{"name": "elaine biancamano"},
+{"name": "vince buffa"},
+{"name": "mike coffey"},
+{"name": "doug w"},
+{"name": "dave long"},
+{"name": "roger terrell"},
+{"name": "krishna kashyap"},
+{"name": "harold rosenfeld"},
+{"name": "sonia piano"},
+{"name": "antonio tenorio"},
+{"name": "guy bruno"},
+{"name": "mark gittens"},
+{"name": "anya jogie"},
+{"name": "jill schnepf"},
+{"name": "larry mactee"},
+{"name": "derek barvoets"},
+{"name": "bill wheelock"},
+{"name": "lauren gilomen"},
+{"name": "david ninkovich"},
+{"name": "mike brey"},
+{"name": "danny buhdda"},
+{"name": "thomas mirsen"},
+{"name": "jodi brockington"},
+{"name": "burt levine"},
+{"name": "mike isom"},
+{"name": "jeff hanson"},
+{"name": "mark kocur"},
+{"name": "ronny freeman"},
+{"name": "lloyd moore"},
+{"name": "barbara shore"},
+{"name": "stephanie boyer"},
+{"name": "ron wood"},
+{"name": "brian weinstein"},
+{"name": "dustin harwell"},
+{"name": "alex nash"},
+{"name": "mary meyeda"},
+{"name": "andrea grim"},
+{"name": "keith brazil"},
+{"name": "charles tomek"},
+{"name": "will engel"},
+{"name": "tim whitley"},
+{"name": "elvis lawson"},
+{"name": "molly peters"},
+{"name": "sherwood glen"},
+{"name": "joe spaldingl"},
+{"name": "annmarie colasanti"},
+{"name": "tony nguyen"},
+{"name": "dennis pool"},
+{"name": "bill gilliand"},
+{"name": "james crum"},
+{"name": "joan dooley"},
+{"name": "sarah hoobler"},
+{"name": "peter brambl"},
+{"name": "jack young"},
+{"name": "stephan auerbach"},
+{"name": "liz tmo"},
+{"name": "kristen mccoy"},
+{"name": "billy j"},
+{"name": "amanda salzman"},
+{"name": "brian maldonado"},
+{"name": "dave gronceski"},
+{"name": "martine garcon"},
+{"name": "andy cockle"},
+{"name": "suzi thek"},
+{"name": "dan theovenman"},
+{"name": "james brager"},
+{"name": "gloria silver"},
+{"name": "willie b"},
+{"name": "ed soares"},
+{"name": "allan toledo"},
+{"name": "mike frei"},
+{"name": "paul lenagh"},
+{"name": "ryan onishi"},
+{"name": "jessica mayor"},
+{"name": "megan feusner"},
+{"name": "dario casa"},
+{"name": "mike abdullah"},
+{"name": "catherine tsuruoka"},
+{"name": "patty sailors"},
+{"name": "stuart gedal"},
+{"name": "rebecca keogh"},
+{"name": "chris santos"},
+{"name": "bill pics"},
+{"name": "harley jackson"},
+{"name": "caryn lee"},
+{"name": "jaime cunanan"},
+{"name": "ila biser"},
+{"name": "lorie webb"},
+{"name": "nadia chaudhry"},
+{"name": "joshua spencer"},
+{"name": "toni brooks"},
+{"name": "james sheppard"},
+{"name": "marcel mandroc"},
+{"name": "joe amio"},
+{"name": "dave roughton"},
+{"name": "raymond flores"},
+{"name": "brandy coote"},
+{"name": "gabriella novotny"},
+{"name": "micheal alvis"},
+{"name": "maria bustillos"},
+{"name": "kelly karole"},
+{"name": "kristy cox"},
+{"name": "stephanie pucin"},
+{"name": "robert richardson"},
+{"name": "bruno gerber"},
+{"name": "claude fortier"},
+{"name": "robert metter"},
+{"name": "nancy nardoni"},
+{"name": "paige lombardo"},
+{"name": "danny d"},
+{"name": "rachel cooke"},
+{"name": "sam bell"},
+{"name": "letty canals"},
+{"name": "andy zaleta"},
+{"name": "linda frankel"},
+{"name": "bunny james"},
+{"name": "bill d"},
+{"name": "patrick penner"},
+{"name": "vanessa faustino"},
+{"name": "meagan leis"},
+{"name": "ed chomik"},
+{"name": "tia jess"},
+{"name": "michael farlow"},
+{"name": "matt moore"},
+{"name": "john bleid"},
+{"name": "tim heidi"},
+{"name": "raymond thompson"},
+{"name": "howard kummer"},
+{"name": "eli karp"},
+{"name": "wallace howard"},
+{"name": "ryan circa"},
+{"name": "julie stout"},
+{"name": "jan press"},
+{"name": "mark t"},
+{"name": "greg mccormick"},
+{"name": "ed howell"},
+{"name": "joan soltan"},
+{"name": "raymond schiefen"},
+{"name": "margery shanoff"},
+{"name": "leo schrubb"},
+{"name": "cliff joyner"},
+{"name": "michael tang"},
+{"name": "phylis fitzpatrick"},
+{"name": "carole noel"},
+{"name": "debbie beardsley"},
+{"name": "paul kushner"},
+{"name": "steve wickes"},
+{"name": "min jones"},
+{"name": "raul laguna"},
+{"name": "luis morales"},
+{"name": "robert stanton"},
+{"name": "karla larumbe"},
+{"name": "janet jones"},
+{"name": "drew brooks"},
+{"name": "michael zibby"},
+{"name": "kaylee b"},
+{"name": "kevin d"},
+{"name": "laveta jarrett"},
+{"name": "betty ward"},
+{"name": "lauren carden"},
+{"name": "jane leverone"},
+{"name": "john rucker"},
+{"name": "john chalif"},
+{"name": "lynn hughes"},
+{"name": "jon eliassen"},
+{"name": "edward coffey"},
+{"name": "gracie williams"},
+{"name": "art sepulveda"},
+{"name": "jon severson"},
+{"name": "dan kondziela"},
+{"name": "ila silberstein"},
+{"name": "ted holcomb"},
+{"name": "natasha wilsom"},
+{"name": "karl price"},
+{"name": "jim steed"},
+{"name": "chris condit"},
+{"name": "steve wallock"},
+{"name": "kellie sawler"},
+{"name": "stephanie seiboth"},
+{"name": "shannon flathers"},
+{"name": "chris weathers"},
+{"name": "lana guzman"},
+{"name": "chris coke"},
+{"name": "brian hammond"},
+{"name": "jim deforest"},
+{"name": "johnny murphy"},
+{"name": "marvin rapaport"},
+{"name": "shirley ma"},
+{"name": "steve carver"},
+{"name": "mary allen"},
+{"name": "bob nightwalker"},
+{"name": "mike fireplace"},
+{"name": "ike sushi"},
+{"name": "steve cynar"},
+{"name": "andy barborak"},
+{"name": "steven radunzel"},
+{"name": "jerry reese"},
+{"name": "jess r"},
+{"name": "liz brownson"},
+{"name": "jesus balbastro"},
+{"name": "jennifer watt"},
+{"name": "carlos cabeza"},
+{"name": "le tenis"},
+{"name": "barbara anthony"},
+{"name": "brent tomlin"},
+{"name": "tony sidekick"},
+{"name": "paul hanley"},
+{"name": "keri dunning"},
+{"name": "paige randall"},
+{"name": "jean duffin"},
+{"name": "pa jeffry"},
+{"name": "jane hadley"},
+{"name": "susan kurland"},
+{"name": "jay lindemann"},
+{"name": "anthony tucker"},
+{"name": "rod v"},
+{"name": "abby la"},
+{"name": "chris gentles"},
+{"name": "steve podium"},
+{"name": "karen wixom"},
+{"name": "ricky stephens"},
+{"name": "nathan camp"},
+{"name": "jill hirayama"},
+{"name": "audrey hamik"},
+{"name": "jay owens"},
+{"name": "caitlin slavka"},
+{"name": "julia molina"},
+{"name": "kevin o'connell"},
+{"name": "john dimatteo"},
+{"name": "mike villers"},
+{"name": "david aragon"},
+{"name": "tara gee"},
+{"name": "denise fiore"},
+{"name": "sue byrd"},
+{"name": "melanie barkers"},
+{"name": "heather o"},
+{"name": "rocio perez"},
+{"name": "eddie vasquez"},
+{"name": "torrie griffin"},
+{"name": "keri schadler"},
+{"name": "dave suarez"},
+{"name": "isabel kallman"},
+{"name": "darryl clark"},
+{"name": "nick porneala"},
+{"name": "janessa cell"},
+{"name": "dana hunter"},
+{"name": "harry spencer"},
+{"name": "jerry vancook"},
+{"name": "ira phone"},
+{"name": "terese stanek"},
+{"name": "hayden plimmer"},
+{"name": "dick eastman"},
+{"name": "ron bushnell"},
+{"name": "robin chaffin"},
+{"name": "ron grady"},
+{"name": "nikki clay"},
+{"name": "jeffrey wylie"},
+{"name": "mark biggers"},
+{"name": "cameron powell"},
+{"name": "diana office"},
+{"name": "kyle harms"},
+{"name": "jong han"},
+{"name": "robby padilla"},
+{"name": "arlene cabalatazan"},
+{"name": "james fatta"},
+{"name": "susy weibe"},
+{"name": "terry way"},
+{"name": "justin koolas"},
+{"name": "jeannette o'connor"},
+{"name": "julie cevette"},
+{"name": "daniel santil"},
+{"name": "george pauline"},
+{"name": "imelda sandoval"},
+{"name": "ben mcknight"},
+{"name": "melissa chan"},
+{"name": "alonzo lamarque"},
+{"name": "jake salwolke"},
+{"name": "mark cox"},
+{"name": "carol hanson"},
+{"name": "fred carnero"},
+{"name": "jean stefano"},
+{"name": "demetria lucas"},
+{"name": "libby lehman"},
+{"name": "leslie cliffs"},
+{"name": "nancy sigmund"},
+{"name": "bill l"},
+{"name": "tiana breniesse"},
+{"name": "todd beane"},
+{"name": "stewart freger"},
+{"name": "jerry vrabic"},
+{"name": "matt pierz"},
+{"name": "mike primo"},
+{"name": "alan prather"},
+{"name": "james penn"},
+{"name": "michael arevalo"},
+{"name": "jackie macdonald"},
+{"name": "brandon raybourne"},
+{"name": "aaron chavez"},
+{"name": "tara more"},
+{"name": "anna zastrow"},
+{"name": "diane couch"},
+{"name": "joe shively"},
+{"name": "yolande jones"},
+{"name": "don dillion"},
+{"name": "emily truong"},
+{"name": "dave deel"},
+{"name": "talitha fremont"},
+{"name": "jennifer marciniak"},
+{"name": "bella smith"},
+{"name": "damon ousley"},
+{"name": "brandon lungren"},
+{"name": "ross website"},
+{"name": "scott parker"},
+{"name": "craig hines"},
+{"name": "wally hunter"},
+{"name": "melissa wesd"},
+{"name": "bryan p"},
+{"name": "tom giordano"},
+{"name": "margaret whitesi"},
+{"name": "chris lytle"},
+{"name": "victor samaha"},
+{"name": "mark coyote"},
+{"name": "jose bormey"},
+{"name": "ralph finch"},
+{"name": "rich rodriguez"},
+{"name": "hank horowitz"},
+{"name": "doug shmalzle"},
+{"name": "mark neal"},
+{"name": "davis current"},
+{"name": "kelly gedinsky"},
+{"name": "derrick arakelian"},
+{"name": "josh cates"},
+{"name": "daniel wong"},
+{"name": "sharon hagins"},
+{"name": "cynthia giles"},
+{"name": "greg morris"},
+{"name": "erin mcdonald"},
+{"name": "peter arkley"},
+{"name": "josh ireland"},
+{"name": "jeanette vinnys"},
+{"name": "jon hibbard"},
+{"name": "justin nassie"},
+{"name": "heather mychaylo"},
+{"name": "mark voight"},
+{"name": "laci x"},
+{"name": "thomas kemp"},
+{"name": "kendra carmichael"},
+{"name": "stephen winters"},
+{"name": "lee lofgren"},
+{"name": "avery cell"},
+{"name": "kathy ferrey"},
+{"name": "angelia fritter"},
+{"name": "ed ryan"},
+{"name": "dana garcia"},
+{"name": "mandy s"},
+{"name": "lachelle maxwell"},
+{"name": "andrew quigley"},
+{"name": "sandra roxy"},
+{"name": "nancy trujillo"},
+{"name": "lynne erickson"},
+{"name": "kyle soccer"},
+{"name": "deirdre bischoff"},
+{"name": "leigh nauman"},
+{"name": "amy hansen"},
+{"name": "debbie switzenbaum"},
+{"name": "steve gluck"},
+{"name": "fred kikuchi"},
+{"name": "michelle cooley"},
+{"name": "suzy johnson"},
+{"name": "joe cargill"},
+{"name": "jeff martin"},
+{"name": "ashley fowler"},
+{"name": "melisa k"},
+{"name": "genevieve davis"},
+{"name": "corey medaris"},
+{"name": "joanne eancone"},
+{"name": "mike frazier"},
+{"name": "adam noppen"},
+{"name": "kenneth booker"},
+{"name": "alix krey"},
+{"name": "chris soseman"},
+{"name": "juan alvarez"},
+{"name": "steve luker"},
+{"name": "laura caravello"},
+{"name": "rico guitar"},
+{"name": "randy ingalls"},
+{"name": "robert lemen"},
+{"name": "terrence giles"},
+{"name": "stacey corbin"},
+{"name": "brian hollingsworth"},
+{"name": "guy kapuscinsky"},
+{"name": "keven rachel"},
+{"name": "erica altenhoff"},
+{"name": "jackie aguilar"},
+{"name": "jamie hensley"},
+{"name": "jeff sayer"},
+{"name": "bradley midtlien"},
+{"name": "courtney kelso"},
+{"name": "randy balhorn"},
+{"name": "jason bigge"},
+{"name": "britany neal"},
+{"name": "lyndon byam"},
+{"name": "kelsey shultz"},
+{"name": "sarah lovell"},
+{"name": "ethan orpilla"},
+{"name": "trey chase"},
+{"name": "nick monti"},
+{"name": "kelli oar"},
+{"name": "scott kelley"},
+{"name": "dianne james"},
+{"name": "jennifer keeler"},
+{"name": "scott c"},
+{"name": "rachael franks"},
+{"name": "sal pascent"},
+{"name": "scott hallmeyer"},
+{"name": "harry gold"},
+{"name": "julie tran"},
+{"name": "justin goins"},
+{"name": "joe rice"},
+{"name": "deb beebe"},
+{"name": "brian gregg"},
+{"name": "denise c"},
+{"name": "peter bichler"},
+{"name": "brandon lacoste"},
+{"name": "warren nb"},
+{"name": "vanessa rolfe"},
+{"name": "yvonne gonzales"},
+{"name": "darrell truitt"},
+{"name": "anne brummel"},
+{"name": "jeri idso"},
+{"name": "brad shinaut"},
+{"name": "sylvia israel"},
+{"name": "christina oliveras"},
+{"name": "andrew cason"},
+{"name": "pamela smith"},
+{"name": "rhea valenzuela"},
+{"name": "taylor cell"},
+{"name": "marisa victory"},
+{"name": "brandon epstein"},
+{"name": "rebecca feldman"},
+{"name": "steven haddad"},
+{"name": "sarai paljetak"},
+{"name": "david bergeron"},
+{"name": "allison hooker"},
+{"name": "lauri duplessis"},
+{"name": "jill sturgeon"},
+{"name": "marc alvarez"},
+{"name": "roger shiltz"},
+{"name": "cary lemons"},
+{"name": "greg kessner"},
+{"name": "cindy hooker"},
+{"name": "neil zuccato"},
+{"name": "kate wheadon"},
+{"name": "jennifer valencia"},
+{"name": "heather jarsso"},
+{"name": "eric basketball"},
+{"name": "sandra mceachern"},
+{"name": "jessica jackson"},
+{"name": "heidi ambrosius"},
+{"name": "tom isabella"},
+{"name": "tasha bridges"},
+{"name": "james guanzon"},
+{"name": "matt broad"},
+{"name": "steve hanson"},
+{"name": "tony tuor"},
+{"name": "sasha st"},
+{"name": "wayne krietz"},
+{"name": "kim harris"},
+{"name": "willis horak"},
+{"name": "seth peterson"},
+{"name": "lynette wright"},
+{"name": "dawn trotter"},
+{"name": "kyle keyser"},
+{"name": "john shults"},
+{"name": "bryan pennington"},
+{"name": "mike lambert"},
+{"name": "will seret"},
+{"name": "matt duhnam"},
+{"name": "robert long"},
+{"name": "marcel puyk"},
+{"name": "hannah physics"},
+{"name": "dan mcarthy"},
+{"name": "nick smith"},
+{"name": "bonnie james"},
+{"name": "alejandra cuevas"},
+{"name": "jenna kashou"},
+{"name": "greg martayan"},
+{"name": "jonathan sooriash"},
+{"name": "janice kaniewski"},
+{"name": "rebecca cullen"},
+{"name": "gary mckee"},
+{"name": "ken burgess"},
+{"name": "raven simone"},
+{"name": "shane rhoades"},
+{"name": "glenn jelks"},
+{"name": "randy tieg"},
+{"name": "wilson rita"},
+{"name": "ashley genske"},
+{"name": "bill boehm"},
+{"name": "robyn zeller"},
+{"name": "jennifer berry"},
+{"name": "jin woo"},
+{"name": "jim brun"},
+{"name": "ashley mom"},
+{"name": "mike gallen"},
+{"name": "michael jay"},
+{"name": "scott kam"},
+{"name": "mary jensen"},
+{"name": "luke reinbolt"},
+{"name": "frank trout"},
+{"name": "nick palihnich"},
+{"name": "wendy harston"},
+{"name": "jon treiber"},
+{"name": "janie coombs"},
+{"name": "wilson nevin"},
+{"name": "perry diekhuis"},
+{"name": "anthony c"},
+{"name": "amanda jonas"},
+{"name": "donna cabanne"},
+{"name": "jake carse"},
+{"name": "debby klinkhammer"},
+{"name": "echo drugs"},
+{"name": "erin delgadio"},
+{"name": "bill wood"},
+{"name": "leslie hutchinson"},
+{"name": "marisa melendez"},
+{"name": "korey schow"},
+{"name": "carmela hernaez"},
+{"name": "ignacio munoz"},
+{"name": "alex baluta"},
+{"name": "steve ferry"},
+{"name": "dana banker"},
+{"name": "kristin blackburn"},
+{"name": "ashley wilson"},
+{"name": "jared overeem"},
+{"name": "roxanne lee"},
+{"name": "ana banana"},
+{"name": "matt kulin"},
+{"name": "devorah lisbon"},
+{"name": "ken webb"},
+{"name": "lynette flintcraft"},
+{"name": "america servicing"},
+{"name": "tim king"},
+{"name": "rich hardy"},
+{"name": "courtney cummings"},
+{"name": "jason bravo"},
+{"name": "adam cook"},
+{"name": "todd holzemer"},
+{"name": "jeff boi"},
+{"name": "mike carry"},
+{"name": "mike warman"},
+{"name": "keith snow"},
+{"name": "rick courtin"},
+{"name": "mike labossiere"},
+{"name": "reena george"},
+{"name": "gary morin"},
+{"name": "suzanne landers"},
+{"name": "lori simmons"},
+{"name": "jared crowder"},
+{"name": "david crocket"},
+{"name": "sharon martin"},
+{"name": "matt janes"},
+{"name": "micheal gould"},
+{"name": "kristen foley"},
+{"name": "pat bledsoe"},
+{"name": "mary warner"},
+{"name": "devin smith"},
+{"name": "rich cusanno"},
+{"name": "dan siu"},
+{"name": "roger huffman"},
+{"name": "jamie m"},
+{"name": "tom jones"},
+{"name": "kristyn cunningham"},
+{"name": "neal smith"},
+{"name": "dallas smith"},
+{"name": "chris bambino"},
+{"name": "roy filkoff"},
+{"name": "frances desimone"},
+{"name": "steven roberto"},
+{"name": "andrew rolin"},
+{"name": "fred perron"},
+{"name": "shawn govern"},
+{"name": "pete long"},
+{"name": "robert dickerson"},
+{"name": "joe palladino"},
+{"name": "rich d’amore"},
+{"name": "christina valcke"},
+{"name": "mark victoriano"},
+{"name": "maurice samra"},
+{"name": "chad gilfillan"},
+{"name": "arthur bosma"},
+{"name": "greg hohman"},
+{"name": "janice luggar"},
+{"name": "paul tobin"},
+{"name": "trisha kiliany"},
+{"name": "alex russian"},
+{"name": "john honts"},
+{"name": "ken sambuchi"},
+{"name": "ralph hardimon"},
+{"name": "nancy herdeman"},
+{"name": "marie apigo"},
+{"name": "tom workman"},
+{"name": "steve roseman"},
+{"name": "jerry stevenson"},
+{"name": "marty martinson"},
+{"name": "ken nale"},
+{"name": "sarah dhooge"},
+{"name": "eric freeman"},
+{"name": "sterling king"},
+{"name": "allie dad"},
+{"name": "brian hirsch"},
+{"name": "shane w"},
+{"name": "len roos"},
+{"name": "mike lopez"},
+{"name": "sara henderson"},
+{"name": "karen harlan"},
+{"name": "brittany home"},
+{"name": "kathy koniezko"},
+{"name": "alana giraldi"},
+{"name": "lesa black"},
+{"name": "pat mcgaughey"},
+{"name": "greg irwin"},
+{"name": "michael miller"},
+{"name": "chance tracy"},
+{"name": "julene kafusi"},
+{"name": "travis hagens"},
+{"name": "steve leggett"},
+{"name": "jerry caringi"},
+{"name": "charles mintz"},
+{"name": "clyde thomas"},
+{"name": "alysha erwin"},
+{"name": "ray hebert"},
+{"name": "jim mauldin"},
+{"name": "pierre cooley"},
+{"name": "cesar econo"},
+{"name": "teddy mann"},
+{"name": "shawn zimmerman"},
+{"name": "george coules"},
+{"name": "michael preisler"},
+{"name": "russell petty"},
+{"name": "chris red"},
+{"name": "jaime reser"},
+{"name": "danielle ambriz"},
+{"name": "dee sanders"},
+{"name": "irma manzo"},
+{"name": "chad welstad"},
+{"name": "alan norquist"},
+{"name": "hillary nauholz"},
+{"name": "david j"},
+{"name": "will garcia"},
+{"name": "kelly williamson"},
+{"name": "peter christie"},
+{"name": "andy roby"},
+{"name": "aaron stalzer"},
+{"name": "huong hr"},
+{"name": "russell proutt"},
+{"name": "brian horrigan"},
+{"name": "eric lyke"},
+{"name": "ed garcia"},
+{"name": "camille chen"},
+{"name": "stephen young"},
+{"name": "terry viligante"},
+{"name": "dee green"},
+{"name": "robert steed"},
+{"name": "matt edwards"},
+{"name": "scott hartshorn"},
+{"name": "rich hebbel"},
+{"name": "ernie wagner"},
+{"name": "nicholas pape"},
+{"name": "bulah walker"},
+{"name": "tina martinez"},
+{"name": "britt balkcom"},
+{"name": "aimee miller"},
+{"name": "dave bench"},
+{"name": "judy mcneal"},
+{"name": "virginia shelley"},
+{"name": "geoffrey alexander"},
+{"name": "jeffrey freidman"},
+{"name": "marie woodard"},
+{"name": "jacinto villanueva"},
+{"name": "ashley wiseman"},
+{"name": "joe morris"},
+{"name": "david martinelli"},
+{"name": "joey b"},
+{"name": "fairy kitts"},
+{"name": "neal davis"},
+{"name": "pablo gray"},
+{"name": "kenneth nicholson"},
+{"name": "chris meyer"},
+{"name": "ronald kirk"},
+{"name": "jonathan becker"},
+{"name": "steve buckridge"},
+{"name": "brook hesano"},
+{"name": "randy anderson"},
+{"name": "trevor henderson"},
+{"name": "megan gabaldon"},
+{"name": "jeff sweetland"},
+{"name": "reggie cooley"},
+{"name": "jackie dowd"},
+{"name": "barry staton"},
+{"name": "sue newton"},
+{"name": "robert kaplan"},
+{"name": "aaron michaels"},
+{"name": "michelle ilse"},
+{"name": "sharon segal"},
+{"name": "dara anderson"},
+{"name": "charles gordon"},
+{"name": "christy clark"},
+{"name": "josh roth"},
+{"name": "tammy longton"},
+{"name": "jim blair"},
+{"name": "tyler rollins"},
+{"name": "sam vzw"},
+{"name": "adam horning"},
+{"name": "alex harding"},
+{"name": "jimmy yee"},
+{"name": "stacey leibert"},
+{"name": "matthew cassells"},
+{"name": "bruce takasaki"},
+{"name": "bryon kibildis"},
+{"name": "gary deckerd"},
+{"name": "priscilla walker"},
+{"name": "emily raggs"},
+{"name": "dorian beany"},
+{"name": "lawrence norman"},
+{"name": "chris panala"},
+{"name": "amy ruby"},
+{"name": "ken comer"},
+{"name": "frederic pouliot"},
+{"name": "travis stienkraus"},
+{"name": "trent allsup"},
+{"name": "nick ottawa"},
+{"name": "lori vincent"},
+{"name": "helaine abramson"},
+{"name": "kim dean"},
+{"name": "eric schena"},
+{"name": "ruben mora"},
+{"name": "peter martinelli"},
+{"name": "jay fubar"},
+{"name": "james dad"},
+{"name": "james mcgillivray"},
+{"name": "rhona walker"},
+{"name": "chris ng"},
+{"name": "goldie gupta"},
+{"name": "noah daniels"},
+{"name": "jeff tilley"},
+{"name": "cameron uecker"},
+{"name": "travis carlton"},
+{"name": "travis merrill"},
+{"name": "ada bennett"},
+{"name": "mike graham"},
+{"name": "troy jeff"},
+{"name": "michael haremski"},
+{"name": "jon alva"},
+{"name": "anthony barnes"},
+{"name": "claudia lopez"},
+{"name": "mariah lybarger"},
+{"name": "mike knollmann"},
+{"name": "ron ortiz"},
+{"name": "jordan wirsz"},
+{"name": "kevin glick"},
+{"name": "chad anderson"},
+{"name": "daphine jackson"},
+{"name": "randy semadeni"},
+{"name": "emma rhodes"},
+{"name": "ted hendrixson"},
+{"name": "matt jones"},
+{"name": "silvia yanez"},
+{"name": "jean daniels"},
+{"name": "harmony elementary"},
+{"name": "phyllis burkett"},
+{"name": "kevin traigle"},
+{"name": "arielle goode"},
+{"name": "kathleen connely"},
+{"name": "keith cornell"},
+{"name": "danyell kennedy"},
+{"name": "jay eagan"},
+{"name": "natalie b"},
+{"name": "laura castaneda"},
+{"name": "jessica prince"},
+{"name": "greg funck"},
+{"name": "audrey labruna"},
+{"name": "joel chack"},
+{"name": "corey johnson"},
+{"name": "deedra cunningham"},
+{"name": "stephan schambach"},
+{"name": "marcus ward"},
+{"name": "maria castellanos"},
+{"name": "paul mignosa"},
+{"name": "jose barthel"},
+{"name": "erin finn"},
+{"name": "robert holmes"},
+{"name": "david star"},
+{"name": "matt spoken"},
+{"name": "grant jones"},
+{"name": "aaron keller"},
+{"name": "terry maher"},
+{"name": "rachel resnick"},
+{"name": "matt horwich"},
+{"name": "mike holbrook"},
+{"name": "nadine b"},
+{"name": "karen hooker"},
+{"name": "paul perkins"},
+{"name": "darby cell"},
+{"name": "kayla aguila"},
+{"name": "chad kims"},
+{"name": "cathy rogers"},
+{"name": "adam halford"},
+{"name": "brandon doman"},
+{"name": "douglas dobbins"},
+{"name": "doug monica"},
+{"name": "diane ruff"},
+{"name": "thomas isett"},
+{"name": "debbie aholt"},
+{"name": "jason colbeck"},
+{"name": "maria damato"},
+{"name": "oscar quality"},
+{"name": "tim lawrence"},
+{"name": "irving wolf"},
+{"name": "dan spurgeon"},
+{"name": "marcus cousin"},
+{"name": "frank kavenik"},
+{"name": "paul ptt"},
+{"name": "kiara grant"},
+{"name": "sharon starr"},
+{"name": "john buenz"},
+{"name": "johnny sullivan"},
+{"name": "patrick burke"},
+{"name": "wilson tsai"},
+{"name": "rachel shine"},
+{"name": "evelyn applewaite"},
+{"name": "katie dalton"},
+{"name": "kelly diasio"},
+{"name": "bob zeibig"},
+{"name": "patrick farshon"},
+{"name": "darin emons"},
+{"name": "brandy basset"},
+{"name": "maria valencia"},
+{"name": "grover jackson"},
+{"name": "mark martin"},
+{"name": "andrew makowski"},
+{"name": "randy brandt"},
+{"name": "rick grinnell"},
+{"name": "tracey angel"},
+{"name": "megan witala"},
+{"name": "stephanie panduro"},
+{"name": "steve paray"},
+{"name": "carol gitau"},
+{"name": "damon kronsberg"},
+{"name": "eugenia caballero"},
+{"name": "bruce neal"},
+{"name": "robert house"},
+{"name": "sandy gerson"},
+{"name": "amanda bancroft"},
+{"name": "tanya denise"},
+{"name": "ken tam"},
+{"name": "samantha hanna"},
+{"name": "tyler n"},
+{"name": "melissa trousdale"},
+{"name": "vera orsorva"},
+{"name": "taylor cobb"},
+{"name": "pam leech"},
+{"name": "derek b"},
+{"name": "nicky von"},
+{"name": "alyssa amidon"},
+{"name": "ben yang"},
+{"name": "kenny sentz"},
+{"name": "jeanne denman"},
+{"name": "alexa avila"},
+{"name": "carl pennington"},
+{"name": "mike sal"},
+{"name": "gerald dezenski"},
+{"name": "tim waurick"},
+{"name": "brian kane"},
+{"name": "theresa bows"},
+{"name": "steve kadash"},
+{"name": "jason akron"},
+{"name": "scott misenbaum"},
+{"name": "julie weitzberg"},
+{"name": "jeff bontraiger"},
+{"name": "bob kirk"},
+{"name": "julie lefkowitz"},
+{"name": "phil weatherford"},
+{"name": "pete campbell"},
+{"name": "chris hefty"},
+{"name": "edwin maryland"},
+{"name": "julie lyons"},
+{"name": "david bywater"},
+{"name": "jen marcario"},
+{"name": "jo smith"},
+{"name": "brian hernandez"},
+{"name": "teressa meuse"},
+{"name": "heather rodd"},
+{"name": "tom brannis"},
+{"name": "jeanette gaines"},
+{"name": "andy bell"},
+{"name": "pam wagner"},
+{"name": "ricky tran"},
+{"name": "joan smothers"},
+{"name": "sonia quintanilla"},
+{"name": "jerry king"},
+{"name": "kevin mitchell"},
+{"name": "patrick martin"},
+{"name": "randy kirch"},
+{"name": "barbara cervantes"},
+{"name": "peter forrester"},
+{"name": "andrew mcafee"},
+{"name": "jack bridenstine"},
+{"name": "christine ray"},
+{"name": "darrell gibson"},
+{"name": "marge cunningham"},
+{"name": "lindsey vance"},
+{"name": "lori meisinger"},
+{"name": "don hom"},
+{"name": "karen lubbock"},
+{"name": "charles lombino"},
+{"name": "michael lovelace"},
+{"name": "jamie allen"},
+{"name": "laurie mn"},
+{"name": "chris varley"},
+{"name": "anita rivera"},
+{"name": "jason mccormick"},
+{"name": "doug dillard"},
+{"name": "bruce balch"},
+{"name": "ken dreifach"},
+{"name": "curtis lee"},
+{"name": "charles dillingham"},
+{"name": "denyse barham"},
+{"name": "fred schmidgall"},
+{"name": "rich maziman"},
+{"name": "tim mccray"},
+{"name": "james white"},
+{"name": "les desi"},
+{"name": "gloria huff"},
+{"name": "steve o'connell"},
+{"name": "randi jen"},
+{"name": "jerry curre"},
+{"name": "mike chee"},
+{"name": "bill creech"},
+{"name": "ray cell"},
+{"name": "peter spennato"},
+{"name": "adam seessel"},
+{"name": "glenn bridges"},
+{"name": "scott hemphill"},
+{"name": "clint h"},
+{"name": "mike bandich"},
+{"name": "james mulholland"},
+{"name": "chris finton"},
+{"name": "mike luters"},
+{"name": "renee richardson"},
+{"name": "donnie williams"},
+{"name": "cleo nice"},
+{"name": "hanna theobald"},
+{"name": "brittney beauchamp"},
+{"name": "sean keel"},
+{"name": "andrea white"},
+{"name": "heidi swanson"},
+{"name": "thomas cluderay"},
+{"name": "nancy vallejo"},
+{"name": "jennifer wagner"},
+{"name": "kevin skinner"},
+{"name": "jose benavidez"},
+{"name": "mari cell"},
+{"name": "luis arevalo"},
+{"name": "tom lowder"},
+{"name": "chad £"},
+{"name": "marcus white"},
+{"name": "eddie lawson"},
+{"name": "emily alipio"},
+{"name": "brian walker"},
+{"name": "stephanie richardson"},
+{"name": "katy j"},
+{"name": "pam martin"},
+{"name": "bret kuntz"},
+{"name": "darryl b"},
+{"name": "sara christensen"},
+{"name": "peggy henderson"},
+{"name": "brooke price"},
+{"name": "barbara stevens"},
+{"name": "annie wootton"},
+{"name": "george allison"},
+{"name": "allison kendall"},
+{"name": "ken yamamoto"},
+{"name": "cory eikmeier"},
+{"name": "kristy robinson"},
+{"name": "kris mitchell"},
+{"name": "tammy impiccini"},
+{"name": "katie tucker"},
+{"name": "leah nuzum"},
+{"name": "mark adams"},
+{"name": "marcus a"},
+{"name": "jen corso"},
+{"name": "john mitchell"},
+{"name": "roger ramilion"},
+{"name": "jeff bruno"},
+{"name": "bruce lenon"},
+{"name": "kate russell"},
+{"name": "jaime todd"},
+{"name": "matt gains"},
+{"name": "ashley cerino"},
+{"name": "stuart nathan"},
+{"name": "dick gordon"},
+{"name": "patti cakes"},
+{"name": "idella bynum"},
+{"name": "jeanette vasquez"},
+{"name": "jackie yah"},
+{"name": "jenny kheele"},
+{"name": "angie tsang"},
+{"name": "susana canada"},
+{"name": "daniel silverman"},
+{"name": "carl buford"},
+{"name": "anthony desantis"},
+{"name": "carolyn gale"},
+{"name": "dennis salvatier"},
+{"name": "tatiana grace"},
+{"name": "john ala"},
+{"name": "jerry dicarlo"},
+{"name": "corey wilson"},
+{"name": "steve rogan"},
+{"name": "jennifer goslowski"},
+{"name": "jason lloyd"},
+{"name": "molly maids"},
+{"name": "gina martin"},
+{"name": "david loatman"},
+{"name": "chris collins"},
+{"name": "barbara dale"},
+{"name": "bryan schmitz"},
+{"name": "fernando gomez"},
+{"name": "alyssa w"},
+{"name": "dwight dionne"},
+{"name": "john puzneak"},
+{"name": "long wilcox"},
+{"name": "tracy england"},
+{"name": "cindy raichuk"},
+{"name": "katie privott"},
+{"name": "dave kraynack"},
+{"name": "jack posemsky"},
+{"name": "tony legree"},
+{"name": "cedric lewis"},
+{"name": "gary verdegan"},
+{"name": "david grantham"},
+{"name": "mike pariseau"},
+{"name": "lee hamilton"},
+{"name": "pat kirby"},
+{"name": "patrick g"},
+{"name": "marc levinson"},
+{"name": "jane artinian"},
+{"name": "tim weir"},
+{"name": "nicole wesley"},
+{"name": "chuck floberg"},
+{"name": "matt mckenna"},
+{"name": "mike chan"},
+{"name": "meredith turnquist"},
+{"name": "eric megaplex"},
+{"name": "mark john"},
+{"name": "ben lursen"},
+{"name": "brian higgins"},
+{"name": "graham colton"},
+{"name": "david slattery"},
+{"name": "craig stewart"},
+{"name": "hannah cable"},
+{"name": "carol neciuk"},
+{"name": "jacob mauldin"},
+{"name": "al mahlberg"},
+{"name": "sherman hall"},
+{"name": "rob brower"},
+{"name": "jon strauss"},
+{"name": "emily romero"},
+{"name": "karen lamberson"},
+{"name": "chester clardy"},
+{"name": "mike peppler"},
+{"name": "duane ritter"},
+{"name": "clint hartshorn"},
+{"name": "carmen flores"},
+{"name": "tom trainor"},
+{"name": "robert louis"},
+{"name": "denny potter"},
+{"name": "al inhoff"},
+{"name": "grant braswell"},
+{"name": "chad clement"},
+{"name": "mark monroy"},
+{"name": "jack wilson"},
+{"name": "rafael echeverria"},
+{"name": "jack neal"},
+{"name": "john okamoto"},
+{"name": "dung dcm"},
+{"name": "shane lai"},
+{"name": "earl lyons"},
+{"name": "marcie cates"},
+{"name": "tommy her"},
+{"name": "mike jernagin"},
+{"name": "dan shaffer"},
+{"name": "bill matingley"},
+{"name": "terry boyd"},
+{"name": "sean o'brien"},
+{"name": "tom rad"},
+{"name": "kevin meryll"},
+{"name": "mike humbert"},
+{"name": "steve buerkle"},
+{"name": "larry carrera"},
+{"name": "rita liazuk"},
+{"name": "farah ramsdell"},
+{"name": "stephanie lane"},
+{"name": "kay jin"},
+{"name": "james jr"},
+{"name": "holly bandera"},
+{"name": "emilio salvador"},
+{"name": "shawn jerkins"},
+{"name": "sheila petrillo"},
+{"name": "jeffrey schiller"},
+{"name": "terry doyle"},
+{"name": "jeffrey green"},
+{"name": "bill ames"},
+{"name": "justin nash"},
+{"name": "tod otown"},
+{"name": "bao hoang"},
+{"name": "carl fesler"},
+{"name": "stephanie seneff"},
+{"name": "cody stuart"},
+{"name": "kenny rivers"},
+{"name": "tim shaver"},
+{"name": "dave pilipovich"},
+{"name": "maris zvejnieks"},
+{"name": "hillary harris"},
+{"name": "heather harp"},
+{"name": "billy lewis"},
+{"name": "raymond gerena"},
+{"name": "alexandra o'sullivan"},
+{"name": "george turco"},
+{"name": "mimi tutihasi"},
+{"name": "michael webber"},
+{"name": "dennis grenier"},
+{"name": "scott perez"},
+{"name": "scot yount"},
+{"name": "jim bryant"},
+{"name": "amy talbot"},
+{"name": "sara dean"},
+{"name": "mark sterling"},
+{"name": "cory chi"},
+{"name": "bobby wrk"},
+{"name": "lon murata"},
+{"name": "bill burgess"},
+{"name": "craig karasin"},
+{"name": "morris baumgarten"},
+{"name": "justin gocke"},
+{"name": "dee adams"},
+{"name": "gary carlson"},
+{"name": "jay kimsey"},
+{"name": "yvette wolfe"},
+{"name": "jacquelyn wallace"},
+{"name": "george seager"},
+{"name": "nick materasso"},
+{"name": "mike prendergast"},
+{"name": "romeo nichols"},
+{"name": "kris manganon"},
+{"name": "lance lin"},
+{"name": "fernanda arruda"},
+{"name": "edgar folks"},
+{"name": "yolanda lane"},
+{"name": "ann black"},
+{"name": "daniel ostdiek"},
+{"name": "randy donaldson"},
+{"name": "aaron greenspan"},
+{"name": "raymond banks"},
+{"name": "stacey adelman"},
+{"name": "jay mixon"},
+{"name": "james jones"},
+{"name": "bernie electrician"},
+{"name": "brian coates"},
+{"name": "mike barrett"},
+{"name": "ted hamlin"},
+{"name": "jorge bro"},
+{"name": "bryan dominguez"},
+{"name": "kirsten white"},
+{"name": "mike barber"},
+{"name": "shelley toolson"},
+{"name": "ryan pham"},
+{"name": "duane meer"},
+{"name": "karen kleinberg"},
+{"name": "frank romero"},
+{"name": "carol rogers"},
+{"name": "todd armstrong"},
+{"name": "matthew skeel"},
+{"name": "candice goode"},
+{"name": "paul service"},
+{"name": "eileen hendrickson"},
+{"name": "kim holser"},
+{"name": "jamie dunkelberger"},
+{"name": "steve baule"},
+{"name": "anika stocks"},
+{"name": "bruce lindsay"},
+{"name": "steve way"},
+{"name": "joseph foley"},
+{"name": "justin girardi"},
+{"name": "lauren johnston"},
+{"name": "roberta wall"},
+{"name": "karen brooks"},
+{"name": "josephine powell"},
+{"name": "debra paulsen"},
+{"name": "andrea park"},
+{"name": "lindsey lewis"},
+{"name": "jared pennington"},
+{"name": "stacey mcnemar"},
+{"name": "kacey parker"},
+{"name": "matt pierson"},
+{"name": "lawrence lawyer"},
+{"name": "linda thorne"},
+{"name": "brad edgelow"},
+{"name": "curtis a"},
+{"name": "tara davis"},
+{"name": "rebecca snyder"},
+{"name": "mike meza"},
+{"name": "mike zapata"},
+{"name": "josh cook"},
+{"name": "victor babloo"},
+{"name": "alex emslie"},
+{"name": "roy goliday"},
+{"name": "karen palome"},
+{"name": "mike chilcutt"},
+{"name": "brandi kuhn"},
+{"name": "jon fahning"},
+{"name": "james bridges"},
+{"name": "hector a"},
+{"name": "ericka delegarza"},
+{"name": "taylor dinwoodey"},
+{"name": "may o"},
+{"name": "candace johnson"},
+{"name": "mary madison"},
+{"name": "tim lineweaver"},
+{"name": "nick gaskins"},
+{"name": "leann cummings"},
+{"name": "kelly harrington"},
+{"name": "marilyn alomar"},
+{"name": "sammy m"},
+{"name": "melissa kale"},
+{"name": "kit kittleson"},
+{"name": "timothy reid"},
+{"name": "jerry casidy"},
+{"name": "renae dimarco"},
+{"name": "cody rhandi"},
+{"name": "tony vanetta"},
+{"name": "tamara swearingen"},
+{"name": "paula e"},
+{"name": "faye lee"},
+{"name": "aletha bradley"},
+{"name": "mike legacy"},
+{"name": "carolyn hong"},
+{"name": "drew glaser"},
+{"name": "jarrett lambert"},
+{"name": "robert burian"},
+{"name": "matthew dudley"},
+{"name": "nan bassett"},
+{"name": "elayne suber"},
+{"name": "lori weed"},
+{"name": "veronica w"},
+{"name": "jo mama"},
+{"name": "adam neihamiah"},
+{"name": "chris howell"},
+{"name": "jimmy rush"},
+{"name": "craig duke"},
+{"name": "steve vickers"},
+{"name": "kristin rowlen"},
+{"name": "rick quandt"},
+{"name": "gabriel cop"},
+{"name": "jennifer horn"},
+{"name": "eric dany"},
+{"name": "bill norton"},
+{"name": "jacob maria"},
+{"name": "courtney elam"},
+{"name": "kevin chestnut"},
+{"name": "angie aguilera"},
+{"name": "allison inserra"},
+{"name": "jim osburn"},
+{"name": "carlos silva"},
+{"name": "tom nual"},
+{"name": "brian alves"},
+{"name": "vanessa zams"},
+{"name": "tonya jackson"},
+{"name": "mike hammond"},
+{"name": "gordon mcfarlane"},
+{"name": "omar rawlins"},
+{"name": "richard canaday"},
+{"name": "brian jaco"},
+{"name": "arthur kroeber"},
+{"name": "mike siska"},
+{"name": "candice christia"},
+{"name": "roy malone"},
+{"name": "eric dotson"},
+{"name": "susan g"},
+{"name": "sam frank"},
+{"name": "david urdiales"},
+{"name": "anthony cavazos"},
+{"name": "pat buttons"},
+{"name": "linda ciaccia"},
+{"name": "karl martin"},
+{"name": "chuck mcgovern"},
+{"name": "kristin bremberg"},
+{"name": "jerry warren"},
+{"name": "peter j"},
+{"name": "amy l"},
+{"name": "mike baldwin"},
+{"name": "carla michaleski"},
+{"name": "rod belford"},
+{"name": "michael wells"},
+{"name": "miguel pasofino"},
+{"name": "tiffany gathers"},
+{"name": "greg piferi"},
+{"name": "peter lowe"},
+{"name": "del mauro"},
+{"name": "bruno madore"},
+{"name": "mimi p"},
+{"name": "juan lascurain"},
+{"name": "molly brassfield"},
+{"name": "katherine christian"},
+{"name": "jenny cust"},
+{"name": "lou electric"},
+{"name": "john suzanne"},
+{"name": "chris boorman"},
+{"name": "andrea larreta"},
+{"name": "justin bromstead"},
+{"name": "ernie arrambide"},
+{"name": "david verklin"},
+{"name": "jonah house"},
+{"name": "rogelio rivera"},
+{"name": "karla rollin"},
+{"name": "allyson nixon"},
+{"name": "cory ang"},
+{"name": "caroline smith"},
+{"name": "gail guardia"},
+{"name": "alexa angel"},
+{"name": "sue underwood"},
+{"name": "nick dallas"},
+{"name": "brian weston"},
+{"name": "steven washburn"},
+{"name": "gary poetting"},
+{"name": "caroline o'neill"},
+{"name": "jared stauffer"},
+{"name": "david orso"},
+{"name": "michele a"},
+{"name": "blair bar"},
+{"name": "ron solomons"},
+{"name": "juan gomez"},
+{"name": "willy shideler"},
+{"name": "pierre belhadj"},
+{"name": "andy shanks"},
+{"name": "oliver griebl"},
+{"name": "jake leitwein"},
+{"name": "bill buchanan"},
+{"name": "jay price"},
+{"name": "jeannie sadler"},
+{"name": "renee cell"},
+{"name": "sam versteeg"},
+{"name": "sergio cadavid"},
+{"name": "tami hurley"},
+{"name": "micah manney"},
+{"name": "brian riggle"},
+{"name": "alan cribbs"},
+{"name": "stacey saltzman"},
+{"name": "bebe toya"},
+{"name": "rob montclair"},
+{"name": "ann helmick"},
+{"name": "rene cell"},
+{"name": "kelly gallant"},
+{"name": "barbara breanna"},
+{"name": "bryan white"},
+{"name": "gary shelton"},
+{"name": "juan fernandez"},
+{"name": "larry holmes"},
+{"name": "marie nest"},
+{"name": "misty parrish"},
+{"name": "chet blalock"},
+{"name": "genevieve perras"},
+{"name": "elsa marshall"},
+{"name": "tyler r"},
+{"name": "jon scherling"},
+{"name": "sun sales"},
+{"name": "omer soykan"},
+{"name": "barry hunt"},
+{"name": "jason berry"},
+{"name": "adam maynard"},
+{"name": "michael mccarty"},
+{"name": "bill greenberg"},
+{"name": "marty vilimek"},
+{"name": "ryan hatfield"},
+{"name": "virginia g"},
+{"name": "larry gress"},
+{"name": "karin klitzke"},
+{"name": "caroline may"},
+{"name": "phil litell"},
+{"name": "eunice galang"},
+{"name": "terry hickey"},
+{"name": "nora kirkland"},
+{"name": "larry bohn"},
+{"name": "debra nicol"},
+{"name": "nathan westbrook"},
+{"name": "rose cage"},
+{"name": "elizabeth maldonado"},
+{"name": "betty jackson"},
+{"name": "rhonda bass"},
+{"name": "david collins"},
+{"name": "angela kelly"},
+{"name": "bonnie philpot"},
+{"name": "luke llewellyn"},
+{"name": "lisa roulo"},
+{"name": "aaron nielsen"},
+{"name": "phillip smith"},
+{"name": "steve rule"},
+{"name": "jim liptak"},
+{"name": "hector castillo"},
+{"name": "marty gittos"},
+{"name": "jamie lee"},
+{"name": "yolonda danner"},
+{"name": "jim thebeau"},
+{"name": "anthony edwards"},
+{"name": "chuck sales"},
+{"name": "tim dean"},
+{"name": "roland e"},
+{"name": "christopher sacca"},
+{"name": "cami thurston"},
+{"name": "ron whitehair"},
+{"name": "erik delgado"},
+{"name": "david prentice"},
+{"name": "eric martinez"},
+{"name": "mark deibert"},
+{"name": "gary issacson"},
+{"name": "danny hoang"},
+{"name": "guy mueller"},
+{"name": "nick nakfour"},
+{"name": "sharon schwartz"},
+{"name": "tia del"},
+{"name": "steve steel"},
+{"name": "sylvia gemilyan"},
+{"name": "shannon cain"},
+{"name": "jared k"},
+{"name": "andrew valentine"},
+{"name": "phil lechman"},
+{"name": "larry crawley"},
+{"name": "bob cilk"},
+{"name": "ana m"},
+{"name": "candace flowers"},
+{"name": "shannon hanley"},
+{"name": "scott madura"},
+{"name": "brian barcomb"},
+{"name": "andrea b"},
+{"name": "jacqueline fitch"},
+{"name": "joanne rillera"},
+{"name": "kristen campbell"},
+{"name": "sarah refi"},
+{"name": "jimmie williams"},
+{"name": "jane bozek"},
+{"name": "dick johnson"},
+{"name": "david kirkland"},
+{"name": "liz cisneros"},
+{"name": "cheri jessup"},
+{"name": "tony swoops"},
+{"name": "terri boone"},
+{"name": "micah tovey"},
+{"name": "lashaun carr"},
+{"name": "chad betten"},
+{"name": "jonathan zimmerman"},
+{"name": "len mcghie"},
+{"name": "jeremiah reyna"},
+{"name": "kevin cambell"},
+{"name": "robert holt"},
+{"name": "steve hellweg"},
+{"name": "robin faulkner"},
+{"name": "bart kummer"},
+{"name": "greg nyce"},
+{"name": "glen bass"},
+{"name": "jay eastlund"},
+{"name": "diana frazier"},
+{"name": "michael mantey"},
+{"name": "david lank"},
+{"name": "ryan mactaggart"},
+{"name": "eileen pazmino"},
+{"name": "joyce jew"},
+{"name": "tisha barnslater"},
+{"name": "amanda stevens"},
+{"name": "arron fields"},
+{"name": "chad crawford"},
+{"name": "steve larson"},
+{"name": "maria romey"},
+{"name": "nella healy"},
+{"name": "kip wotanowicz"},
+{"name": "robert wilcox"},
+{"name": "chuck gould"},
+{"name": "chris nomura"},
+{"name": "jay sr"},
+{"name": "alan kimmery"},
+{"name": "patty hulsey"},
+{"name": "brandon b"},
+{"name": "brenda craig"},
+{"name": "matt banaszak"},
+{"name": "ken kukurudz"},
+{"name": "oscar arts"},
+{"name": "jennifer rogers"},
+{"name": "loren beck"},
+{"name": "rosita cortez"},
+{"name": "tina garcia"},
+{"name": "christina pasek"},
+{"name": "grace murray"},
+{"name": "holly labriola"},
+{"name": "steve jones"},
+{"name": "michael story"},
+{"name": "henry alvarez"},
+{"name": "sandy ellsworth"},
+{"name": "dave mccuskey"},
+{"name": "enrique egurrora"},
+{"name": "donny young"},
+{"name": "lisa karno"},
+{"name": "jodi lints"},
+{"name": "nikki reynolds"},
+{"name": "glenn creamer"},
+{"name": "hoa bui"},
+{"name": "jennifer raymond"},
+{"name": "alex norton"},
+{"name": "jo a"},
+{"name": "jeff robbins"},
+{"name": "dee robbins"},
+{"name": "justin shawley"},
+{"name": "bob pruit"},
+{"name": "laurie daniels"},
+{"name": "bryan thoryk"},
+{"name": "dayna montrose"},
+{"name": "robert stephens"},
+{"name": "joanna zelasko"},
+{"name": "andrew ryskamp"},
+{"name": "karen reed"},
+{"name": "jules renner"},
+{"name": "rob holzhauer"},
+{"name": "rachel dysarczyk"},
+{"name": "nancy barahona"},
+{"name": "holly fogle"},
+{"name": "ha chun"},
+{"name": "tim ochran"},
+{"name": "krista johnson"},
+{"name": "travis behrens"},
+{"name": "roy odgen"},
+{"name": "gloria carey"},
+{"name": "mike russulillo"},
+{"name": "frank kline"},
+{"name": "tim lennon"},
+{"name": "joyce yip"},
+{"name": "bob colt"},
+{"name": "greg etk"},
+{"name": "bill busey"},
+{"name": "paul geislinger"},
+{"name": "jeni harp"},
+{"name": "jennie bartlett"},
+{"name": "brian dwan"},
+{"name": "valerie valencia"},
+{"name": "samuel chang"},
+{"name": "raymond ortiz"},
+{"name": "michael bosik"},
+{"name": "krista erikson"},
+{"name": "stephanie macneil"},
+{"name": "renee pyzanos"},
+{"name": "jason applewhite"},
+{"name": "margaret lazo"},
+{"name": "rich lefurgy"},
+{"name": "bernetta draper"},
+{"name": "roger haddad"},
+{"name": "brian alvarez"},
+{"name": "nicole carlos"},
+{"name": "debbie wheeler"},
+{"name": "andy frey"},
+{"name": "patti genko"},
+{"name": "dan sakinin"},
+{"name": "trish friesen"},
+{"name": "andrew phipps"},
+{"name": "diane lee"},
+{"name": "gregory schultz"},
+{"name": "dick crisp"},
+{"name": "cynthia hiatt"},
+{"name": "shawn rahl"},
+{"name": "george graves"},
+{"name": "kara kim"},
+{"name": "janelle crosby"},
+{"name": "crystal starlight"},
+{"name": "jasmine trimble"},
+{"name": "eric lehmer"},
+{"name": "andre watts"},
+{"name": "bobby freeman"},
+{"name": "les murin"},
+{"name": "monique scott"},
+{"name": "greg schweitzer"},
+{"name": "frank castellucci"},
+{"name": "marcus brian"},
+{"name": "jen scott"},
+{"name": "kristi orchard"},
+{"name": "dean jewel"},
+{"name": "evan levow"},
+{"name": "shawn shi"},
+{"name": "mackenzie jackson"},
+{"name": "sal creams"},
+{"name": "diamond mandis"},
+{"name": "andy lorance"},
+{"name": "richard brady"},
+{"name": "lidia heyhurst"},
+{"name": "teresa lusney"},
+{"name": "martin beatty"},
+{"name": "greg dandeles"},
+{"name": "roderick brooks"},
+{"name": "janelle rosamond"},
+{"name": "tamiko keller"},
+{"name": "cristina wakiyama"},
+{"name": "jim whitmore"},
+{"name": "matt engler"},
+{"name": "bill brink"},
+{"name": "john waltman"},
+{"name": "patrick thompson"},
+{"name": "ashley edmondson"},
+{"name": "byron moving"},
+{"name": "wayne potter"},
+{"name": "justin lewis"},
+{"name": "raquel mullins"},
+{"name": "dave helfrich"},
+{"name": "alex peragine"},
+{"name": "steve bodman"},
+{"name": "stephen beckman"},
+{"name": "david golden"},
+{"name": "bill chamberlin"},
+{"name": "jason maruska"},
+{"name": "dave riordan"},
+{"name": "george cypress"},
+{"name": "jon mcpeters"},
+{"name": "victor shen"},
+{"name": "brian guenther"},
+{"name": "karen barrientos"},
+{"name": "danielle holmes"},
+{"name": "kristen holmstrand"},
+{"name": "christy work"},
+{"name": "kacie baker"},
+{"name": "stacy espejo"},
+{"name": "eric lommatsch"},
+{"name": "henry comm"},
+{"name": "rachael foster"},
+{"name": "dean kawamura"},
+{"name": "trey cotney"},
+{"name": "maribeth diaz"},
+{"name": "luigi f"},
+{"name": "ryan nelson"},
+{"name": "dana reason"},
+{"name": "gordon wilson"},
+{"name": "cheryl vallejo"},
+{"name": "william afeaki"},
+{"name": "melinda sue"},
+{"name": "diane sampson"},
+{"name": "rich paquette"},
+{"name": "crystal b"},
+{"name": "daniel felder"},
+{"name": "lynn willy"},
+{"name": "jenniffer plinio"},
+{"name": "ebony brown"},
+{"name": "elizabeth blanco"},
+{"name": "teddy dewitt"},
+{"name": "larry brown"},
+{"name": "sean mealock"},
+{"name": "mike nicolas"},
+{"name": "diane freeman"},
+{"name": "annie mak"},
+{"name": "brenda jolly"},
+{"name": "drew wahl"},
+{"name": "joanne day"},
+{"name": "mike ortayazmaciyan"},
+{"name": "jon albert"},
+{"name": "jan leighty"},
+{"name": "jean spirk"},
+{"name": "john rula"},
+{"name": "clair audi"},
+{"name": "martin deleon"},
+{"name": "ryan grafft"},
+{"name": "lindy milka"},
+{"name": "brad unique"},
+{"name": "dennis keogh"},
+{"name": "glenn conner"},
+{"name": "juan a"},
+{"name": "george hopkins"},
+{"name": "kenneth adler"},
+{"name": "colin photo"},
+{"name": "mike jewler"},
+{"name": "valerie bennett"},
+{"name": "adam rainey"},
+{"name": "dorothy hays"},
+{"name": "john brandes"},
+{"name": "alex zilbershteyn"},
+{"name": "peter kane"},
+{"name": "lecia langston"},
+{"name": "ana silva"},
+{"name": "corey samsara"},
+{"name": "kim magee"},
+{"name": "kelly bishop"},
+{"name": "reggie medford"},
+{"name": "kenny g"},
+{"name": "adam chavira"},
+{"name": "shelby tucker"},
+{"name": "rachel hs"},
+{"name": "tanya jenkins"},
+{"name": "christopher orne"},
+{"name": "irving keschner"},
+{"name": "chris lee"},
+{"name": "grant hawkins"},
+{"name": "ray epp"},
+{"name": "simon cell"},
+{"name": "michael pobar"},
+{"name": "nadine childress"},
+{"name": "david hoki"},
+{"name": "brad alkazin"},
+{"name": "connie penalver"},
+{"name": "jason belinski"},
+{"name": "bill bonsback"},
+{"name": "douglas meneely"},
+{"name": "spencer wheelwright"},
+{"name": "renita cox"},
+{"name": "barry shevick"},
+{"name": "carlos home"},
+{"name": "noel people"},
+{"name": "darren posh"},
+{"name": "gerry tissenbaum"},
+{"name": "blake jones"},
+{"name": "david lachowicz"},
+{"name": "carol evermen"},
+{"name": "jason pierce"},
+{"name": "amiee ball"},
+{"name": "johnny car"},
+{"name": "jeffrey bostic"},
+{"name": "steve adelman"},
+{"name": "lewis floyd"},
+{"name": "greg finton"},
+{"name": "nick nickerson"},
+{"name": "scott haitsuka"},
+{"name": "regine smet"},
+{"name": "tiffany ward"},
+{"name": "samuel brull"},
+{"name": "jared o'brien"},
+{"name": "chad v"},
+{"name": "amy salvo"},
+{"name": "tom baumbach"},
+{"name": "ken sjovolv"},
+{"name": "luis cardona"},
+{"name": "jesse lira"},
+{"name": "eric wilkerson"},
+{"name": "denis laflamme"},
+{"name": "adam stansberry"},
+{"name": "peter sells"},
+{"name": "alex labeaux"},
+{"name": "jim milliken"},
+{"name": "michael mysliwy"},
+{"name": "david goat"},
+{"name": "morris betton"},
+{"name": "jeff garrison"},
+{"name": "nancy foyt"},
+{"name": "christi wieler"},
+{"name": "ryan slack"},
+{"name": "mike linger"},
+{"name": "frank goluza"},
+{"name": "pat dugal"},
+{"name": "tim kolopus"},
+{"name": "david hernandez"},
+{"name": "brian boekel"},
+{"name": "randy denkers"},
+{"name": "sherry premo"},
+{"name": "jennifer hanks"},
+{"name": "katie bell"},
+{"name": "rodney mccall"},
+{"name": "sarah mather"},
+{"name": "jackie melendez"},
+{"name": "dave busters"},
+{"name": "seth drori"},
+{"name": "elizabeth jones"},
+{"name": "norman karen"},
+{"name": "tim lanigan"},
+{"name": "kim harsh"},
+{"name": "mike timmons"},
+{"name": "jason salvatierra"},
+{"name": "vickie fletcher"},
+{"name": "david heiss"},
+{"name": "bryan stanley"},
+{"name": "gary austin"},
+{"name": "kathleen wallace"},
+{"name": "andrea looker"},
+{"name": "ken pearson"},
+{"name": "keith sanders"},
+{"name": "cassie dyker"},
+{"name": "clayton christensen"},
+{"name": "james gall"},
+{"name": "jack larson"},
+{"name": "jackie hensley"},
+{"name": "susan schirman"},
+{"name": "fletcher graggs"},
+{"name": "candice meng"},
+{"name": "brenda linares"},
+{"name": "rob pary"},
+{"name": "peggy broch"},
+{"name": "jerome stoll"},
+{"name": "cris crib"},
+{"name": "steve bertreis"},
+{"name": "lisa bernstein"},
+{"name": "bridgett corbin"},
+{"name": "tara french"},
+{"name": "dave anderssen"},
+{"name": "james romero"},
+{"name": "joey garguilo"},
+{"name": "terry clark"},
+{"name": "joanna miller"},
+{"name": "luz mariela"},
+{"name": "allison hinley"},
+{"name": "denise jerry"},
+{"name": "scott corr"},
+{"name": "scott schumacher"},
+{"name": "shannon schmidt"},
+{"name": "noel acosta"},
+{"name": "nicola caiano"},
+{"name": "derek lyttle"},
+{"name": "kenny kilman"},
+{"name": "justin lindhorst"},
+{"name": "bertha mills"},
+{"name": "bill shaw"},
+{"name": "eric swanson"},
+{"name": "kelly king"},
+{"name": "brian fisher"},
+{"name": "ashley hasbrook"},
+{"name": "amanda rubin"},
+{"name": "megan mullinix"},
+{"name": "virgil watters"},
+{"name": "paul korber"},
+{"name": "april howell"},
+{"name": "geri newburge"},
+{"name": "jim chambers"},
+{"name": "robbie cell"},
+{"name": "emily guthrie"},
+{"name": "jenny leclaire"},
+{"name": "stephanie st"},
+{"name": "betty mirabal"},
+{"name": "thomas dr"},
+{"name": "tim anderson"},
+{"name": "angelika decker"},
+{"name": "jackie ho"},
+{"name": "molly sg"},
+{"name": "mark marin"},
+{"name": "jean blanchette"},
+{"name": "melody welch"},
+{"name": "nathan marchbank"},
+{"name": "edward porter"},
+{"name": "simon jennings"},
+{"name": "pablo ros"},
+{"name": "luella d"},
+{"name": "jerry farner"},
+{"name": "andy hartz"},
+{"name": "katie dillon"},
+{"name": "sonia cleaning"},
+{"name": "tamara tretter"},
+{"name": "brian wadell"},
+{"name": "earle teagarden"},
+{"name": "joe leduc"},
+{"name": "allison lanzallotti"},
+{"name": "cindy keese"},
+{"name": "elvira feng"},
+{"name": "chris manalastas"},
+{"name": "david moore"},
+{"name": "ellen lamp"},
+{"name": "val bellardo"},
+{"name": "johnson bank"},
+{"name": "cedric gaddy"},
+{"name": "todd reardon"},
+{"name": "tina burtelow"},
+{"name": "brittany scramuzzo"},
+{"name": "shawna macfarlane"},
+{"name": "betty charles"},
+{"name": "chris patrick"},
+{"name": "michael carus"},
+{"name": "joe magie"},
+{"name": "bob andrew"},
+{"name": "tim devine"},
+{"name": "jeremy banks"},
+{"name": "danny kf"},
+{"name": "carmen c"},
+{"name": "charles krusen"},
+{"name": "vanessa brown"},
+{"name": "deb olson"},
+{"name": "luis cruz"},
+{"name": "dawn strachan"},
+{"name": "doug lewis"},
+{"name": "steven thompson"},
+{"name": "annie zaborskis"},
+{"name": "john compaglia"},
+{"name": "mike price"},
+{"name": "nathan lim"},
+{"name": "tracie b"},
+{"name": "ryan moses"},
+{"name": "bob johnson"},
+{"name": "rich imb"},
+{"name": "harriet adelman"},
+{"name": "steven lindsay"},
+{"name": "karena puga"},
+{"name": "robert guzman"},
+{"name": "natalie defazio"},
+{"name": "mark spencer"},
+{"name": "frederic herrbach"},
+{"name": "chris cardin"},
+{"name": "brian boboli"},
+{"name": "joan chipser"},
+{"name": "janice fallago"},
+{"name": "sunny sachdev"},
+{"name": "karen loxton"},
+{"name": "lisa mccloughan"},
+{"name": "adam cortez"},
+{"name": "chris holstien"},
+{"name": "judy kampa"},
+{"name": "alison naidech"},
+{"name": "sally scott"},
+{"name": "molly mills"},
+{"name": "scott skager"},
+{"name": "gary martinez"},
+{"name": "wes camplin"},
+{"name": "steve x"},
+{"name": "erica la"},
+{"name": "john ekpenyoung"},
+{"name": "aaron desalle"},
+{"name": "louis bovasso"},
+{"name": "jonathan bailes"},
+{"name": "michelle williams"},
+{"name": "megan harvey"},
+{"name": "jonathan dakss"},
+{"name": "kenneth schambaro"},
+{"name": "brad wells"},
+{"name": "jack uncle"},
+{"name": "naomi matsumoto"},
+{"name": "janice woodruff"},
+{"name": "alisa ballesteros"},
+{"name": "tamara pienknagura"},
+{"name": "pamela zager"},
+{"name": "eric black"},
+{"name": "junior electric"},
+{"name": "kathy barquez"},
+{"name": "jean richardson"},
+{"name": "kathryn mcmahon"},
+{"name": "cindy saucedo"},
+{"name": "dave javorsky"},
+{"name": "greg lynch"},
+{"name": "mark cassel"},
+{"name": "alan zakaria"},
+{"name": "kelly blackwood"},
+{"name": "doris monsalve"},
+{"name": "mike wagener"},
+{"name": "tonya c"},
+{"name": "eric leland"},
+{"name": "emily hansen"},
+{"name": "dalton snyder"},
+{"name": "elizabeth harownsky"},
+{"name": "allen dobson"},
+{"name": "emily hooch"},
+{"name": "jose s"},
+{"name": "matt tang"},
+{"name": "alex geller"},
+{"name": "david davis"},
+{"name": "michael hebberoy"},
+{"name": "preston wolf"},
+{"name": "daria fitzgerard"},
+{"name": "thomas trujillo"},
+{"name": "sarah dennis"},
+{"name": "andrea turco"},
+{"name": "mark comstock"},
+{"name": "johnny bonding"},
+{"name": "gina chavez"},
+{"name": "jacque lazier"},
+{"name": "marion weeks"},
+{"name": "jill reynolds"},
+{"name": "rick samson"},
+{"name": "jim summers"},
+{"name": "william marek"},
+{"name": "shane ward"},
+{"name": "ronald ducasse"},
+{"name": "rhonda jones"},
+{"name": "tom donkle"},
+{"name": "bonnie spruill"},
+{"name": "christian vinas"},
+{"name": "jason i"},
+{"name": "shelly abraham"},
+{"name": "jillian rigwood"},
+{"name": "val neal"},
+{"name": "robert kupczak"},
+{"name": "arthur zilberberg"},
+{"name": "leah radley"},
+{"name": "ellie randall"},
+{"name": "jessica hendricks"},
+{"name": "greg mueller"},
+{"name": "denny johnston"},
+{"name": "joe bread"},
+{"name": "joanna clendenen"},
+{"name": "bruce johns"},
+{"name": "bret cullivan"},
+{"name": "cheri bear"},
+{"name": "john akers"},
+{"name": "donald norberg"},
+{"name": "blair constantine"},
+{"name": "rhoda debose"},
+{"name": "scott irvine"},
+{"name": "greg fletcher"},
+{"name": "allen brooks"},
+{"name": "dean fausett"},
+{"name": "dennis green"},
+{"name": "errol carlstrom"},
+{"name": "fern greg"},
+{"name": "debra pope"},
+{"name": "bobby weiss"},
+{"name": "carol rose"},
+{"name": "john rocconi"},
+{"name": "nicole euson"},
+{"name": "ana lisa"},
+{"name": "jeff acord"},
+{"name": "maggie nassif"},
+{"name": "chris medina"},
+{"name": "mike mendez"},
+{"name": "chris nugent"},
+{"name": "cheryl johnson"},
+{"name": "bill yoder"},
+{"name": "sam chueng"},
+{"name": "jamie wise"},
+{"name": "howard goldberg"},
+{"name": "chris woolcox"},
+{"name": "jackie frazier"},
+{"name": "joey bales"},
+{"name": "liza niss"},
+{"name": "dave goodwin"},
+{"name": "todd onore"},
+{"name": "scott ganson"},
+{"name": "michael franks"},
+{"name": "quinn li"},
+{"name": "pete hoffman"},
+{"name": "bob grondin"},
+{"name": "dick hogshire"},
+{"name": "danny green"},
+{"name": "raymond gomez"},
+{"name": "greg dungan"},
+{"name": "derrick metz"},
+{"name": "rita stoker"},
+{"name": "dick phillips"},
+{"name": "barry kea"},
+{"name": "jay mclauchlin"},
+{"name": "tanya haddock"},
+{"name": "ed dubar"},
+{"name": "jay sharon"},
+{"name": "matt kauppinen"},
+{"name": "jason bayless"},
+{"name": "tracy arrington"},
+{"name": "steve bailey"},
+{"name": "patricia locke"},
+{"name": "eric giambertone"},
+{"name": "evan wise"},
+{"name": "chara patterson"},
+{"name": "kim geater"},
+{"name": "kevin karlson"},
+{"name": "ben santiago"},
+{"name": "ryan conner"},
+{"name": "lyla scheihing"},
+{"name": "jesse huitt"},
+{"name": "molly maier"},
+{"name": "sid knable"},
+{"name": "terese scimecca"},
+{"name": "alex bernasconi"},
+{"name": "corina laborico"},
+{"name": "michael micone"},
+{"name": "joyce chen"},
+{"name": "frank oliva"},
+{"name": "doug michlink"},
+{"name": "victor silvestre"},
+{"name": "joey vzn"},
+{"name": "kelly mullaney"},
+{"name": "leo iliadis"},
+{"name": "mark neadle"},
+{"name": "misty cell"},
+{"name": "kate verbeek"},
+{"name": "bob woosley"},
+{"name": "mike theissen"},
+{"name": "jordan selhorst"},
+{"name": "fred gamel"},
+{"name": "carolyn dc"},
+{"name": "corie brown"},
+{"name": "cathy collens"},
+{"name": "pam kenney"},
+{"name": "gregg montgomery"},
+{"name": "jimmy rosenfield"},
+{"name": "peter panunzi"},
+{"name": "missy zimmerman"},
+{"name": "lorette peruch"},
+{"name": "josh sarratt"},
+{"name": "chris robl"},
+{"name": "joey yokum"},
+{"name": "andrew terrono"},
+{"name": "catherine trinh"},
+{"name": "keith davids"},
+{"name": "rachel powers"},
+{"name": "monique tanner"},
+{"name": "sarah becker"},
+{"name": "tricia boudreau"},
+{"name": "cameron farrer"},
+{"name": "justin ok"},
+{"name": "tania sauro"},
+{"name": "dennis russo"},
+{"name": "john hind"},
+{"name": "colin shaw"},
+{"name": "donnie bender"},
+{"name": "david ostfeld"},
+{"name": "bob young"},
+{"name": "brandon apuna"},
+{"name": "mary thune"},
+{"name": "floyd clarkson"},
+{"name": "mike waechter"},
+{"name": "gaye sanders"},
+{"name": "don snow"},
+{"name": "kevin andy"},
+{"name": "emily diaz"},
+{"name": "carolyn eli's"},
+{"name": "matt danni"},
+{"name": "dean everly"},
+{"name": "steve ambrose"},
+{"name": "jennifer banks"},
+{"name": "dennis knight"},
+{"name": "alex k"},
+{"name": "bill obrien"},
+{"name": "john jeffreies"},
+{"name": "george jagodzinski"},
+{"name": "greg chun"},
+{"name": "jen steward"},
+{"name": "catherine franklin"},
+{"name": "lisa patton"},
+{"name": "bob dewey"},
+{"name": "omar davis"},
+{"name": "emily patrick"},
+{"name": "erica lyxzen"},
+{"name": "joe hawkins"},
+{"name": "phuong trinh"},
+{"name": "ed schwalenberg"},
+{"name": "neil badders"},
+{"name": "allen mercer"},
+{"name": "bruce flint"},
+{"name": "dave reigert"},
+{"name": "fernando padilla"},
+{"name": "allen aikens"},
+{"name": "craig martin"},
+{"name": "tom shook"},
+{"name": "mindy cell"},
+{"name": "micheal graham"},
+{"name": "lily esparza"},
+{"name": "preston davis"},
+{"name": "brent mckay"},
+{"name": "jay williams"},
+{"name": "barb hunt"},
+{"name": "ray kada"},
+{"name": "ryan pierce"},
+{"name": "ryan adams"},
+{"name": "ryan burke"},
+{"name": "marilyn bettencourt"},
+{"name": "phil hess"},
+{"name": "shannon myric"},
+{"name": "jasmine arizmendi"},
+{"name": "chris grimes"},
+{"name": "nancy surgenor"},
+{"name": "andrew barkin"},
+{"name": "rob everhart"},
+{"name": "carl trim"},
+{"name": "jenny h"},
+{"name": "valerie koontz"},
+{"name": "ruby lin"},
+{"name": "eric hardesty"},
+{"name": "suzanne stevens"},
+{"name": "greg pavlick"},
+{"name": "brock strom"},
+{"name": "jason schubert"},
+{"name": "leslie brians"},
+{"name": "sam nimri"},
+{"name": "ann khalid"},
+{"name": "ron cheshire"},
+{"name": "becky higby"},
+{"name": "joe storm"},
+{"name": "nick chron"},
+{"name": "rob suh"},
+{"name": "bruce jackson"},
+{"name": "kanisha nsba"},
+{"name": "kenny boss"},
+{"name": "billy loecker"},
+{"name": "yasuko cook"},
+{"name": "john minor"},
+{"name": "morris garage"},
+{"name": "lovie harris"},
+{"name": "dave kasey"},
+{"name": "brad welch"},
+{"name": "tina marie"},
+{"name": "shayla hazelhurst"},
+{"name": "richard brodeur"},
+{"name": "pam lomeli"},
+{"name": "barry warren"},
+{"name": "melissa hogenson"},
+{"name": "sam bullock"},
+{"name": "diane aronowitz"},
+{"name": "raul luna"},
+{"name": "crystal moffat"},
+{"name": "todd rosenhagen"},
+{"name": "david klein"},
+{"name": "jack corry"},
+{"name": "elena brooks"},
+{"name": "katherine thon"},
+{"name": "denny dephillips"},
+{"name": "scott hammond"},
+{"name": "shelly biggs"},
+{"name": "elmer nixon"},
+{"name": "laurie peetree"},
+{"name": "ryan floth"},
+{"name": "steve gerard"},
+{"name": "lloyd peckner"},
+{"name": "elizabeth haglund"},
+{"name": "todd courtland"},
+{"name": "kevin dixion"},
+{"name": "mark dettor"},
+{"name": "tim handler"},
+{"name": "susanna filippone"},
+{"name": "cameron roy"},
+{"name": "steve paysinger"},
+{"name": "teresa ruiz"},
+{"name": "selena williams"},
+{"name": "joe poole"},
+{"name": "claire bele"},
+{"name": "roger bachman"},
+{"name": "christal cheng"},
+{"name": "tiny patton"},
+{"name": "jean wirth"},
+{"name": "maria mims"},
+{"name": "winona pless"},
+{"name": "ian soltan"},
+{"name": "miriam cell"},
+{"name": "elizabeth donovan"},
+{"name": "debbie bolves"},
+{"name": "michael garrett"},
+{"name": "sean o'day"},
+{"name": "jenny ryan"},
+{"name": "kelly barina"},
+{"name": "charles cin"},
+{"name": "steven tran"},
+{"name": "sharonda davis"},
+{"name": "justin sprowles"},
+{"name": "lisa ganfield"},
+{"name": "nisha purp"},
+{"name": "ralph erb"},
+{"name": "mari carmen"},
+{"name": "ned lynch"},
+{"name": "tim mcanany"},
+{"name": "amanda s"},
+{"name": "ed joiner"},
+{"name": "evan trestan"},
+{"name": "jake mansell"},
+{"name": "del monte"},
+{"name": "sean driggs"},
+{"name": "michelle marison"},
+{"name": "vickie atco"},
+{"name": "everett rhodes"},
+{"name": "jesse henstock"},
+{"name": "paul cain"},
+{"name": "jason henderson"},
+{"name": "larry braswell"},
+{"name": "merrie dorval"},
+{"name": "john crivaro"},
+{"name": "erin nguyen"},
+{"name": "rick spitler"},
+{"name": "john sample"},
+{"name": "brian wheelock"},
+{"name": "ken kiedrowicz"},
+{"name": "beatrice clark"},
+{"name": "marisa lam"},
+{"name": "jason bio"},
+{"name": "brian mccauley"},
+{"name": "lindsay kay"},
+{"name": "ellie barona"},
+{"name": "mark harle"},
+{"name": "roy schmucker"},
+{"name": "sherry wolf"},
+{"name": "michael giorgiani"},
+{"name": "tim boyd"},
+{"name": "rose warda"},
+{"name": "ann rogers"},
+{"name": "karl haberl"},
+{"name": "chuck brown"},
+{"name": "ryan simon"},
+{"name": "paul dergen"},
+{"name": "tyrone duffel"},
+{"name": "jim obrian"},
+{"name": "wendy snyder"},
+{"name": "frank brown"},
+{"name": "josh goodwin"},
+{"name": "brandon linn"},
+{"name": "jeff beyer"},
+{"name": "maryann gonzalez"},
+{"name": "fernando lujan"},
+{"name": "bret gorringe"},
+{"name": "hal braun"},
+{"name": "isabelle bovee"},
+{"name": "marva marx"},
+{"name": "kenny barneby"},
+{"name": "donna krumsiek"},
+{"name": "judi suski"},
+{"name": "michael goldmuntz"},
+{"name": "larry jackson"},
+{"name": "sue hoidal"},
+{"name": "courtney meyers"},
+{"name": "tony langston"},
+{"name": "ricardo rendon"},
+{"name": "karen hall"},
+{"name": "mary parsons"},
+{"name": "pat patillo"},
+{"name": "marty cronin"},
+{"name": "herb tousley"},
+{"name": "kathleen gallagher"},
+{"name": "adam wilfley"},
+{"name": "maria galvan"},
+{"name": "brandi cunningham"},
+{"name": "tracie eisenberg"},
+{"name": "jack barlage"},
+{"name": "mike middaugh"},
+{"name": "christine gangi"},
+{"name": "amanda hands"},
+{"name": "vincent tao"},
+{"name": "elena stojcevski"},
+{"name": "lindsay s"},
+{"name": "courtney feilmeier"},
+{"name": "renee culver"},
+{"name": "dean disandro"},
+{"name": "mark holland"},
+{"name": "terri vivian"},
+{"name": "roberto vilicana"},
+{"name": "katie sudduth"},
+{"name": "heather hensley"},
+{"name": "alvin roth"},
+{"name": "heather bennett"},
+{"name": "cliff whitehurst"},
+{"name": "trevor cates"},
+{"name": "tony hinsberger"},
+{"name": "jim day@hardy"},
+{"name": "bruce lan"},
+{"name": "mara sherkin"},
+{"name": "bryan grimm"},
+{"name": "chris weichel"},
+{"name": "shane hollingsworth"},
+{"name": "robert dennerlein"},
+{"name": "evan king"},
+{"name": "steve ragland"},
+{"name": "drew daire"},
+{"name": "rebecca landis"},
+{"name": "kathleen baca"},
+{"name": "jennifer allan"},
+{"name": "richard backus"},
+{"name": "vanessa fitch"},
+{"name": "dan stephens"},
+{"name": "janet abut"},
+{"name": "eric billman"},
+{"name": "dustin clampet"},
+{"name": "bryant dist"},
+{"name": "jessie elias"},
+{"name": "laurinda meetup"},
+{"name": "maria ferrari"},
+{"name": "larita larson"},
+{"name": "kevin keenan"},
+{"name": "jack sissons"},
+{"name": "mario testani"},
+{"name": "larry rogers"},
+{"name": "elizabeth keschner"},
+{"name": "kathy delgado"},
+{"name": "bryon krug"},
+{"name": "jake louwsma"},
+{"name": "jason chandra"},
+{"name": "kate saunders"},
+{"name": "chanda whitaker"},
+{"name": "dina lacatena"},
+{"name": "jason nackley"},
+{"name": "mark parker"},
+{"name": "david foks"},
+{"name": "linda carkner"},
+{"name": "michael supp"},
+{"name": "josh hoag"},
+{"name": "andrew cherwenka"},
+{"name": "justin steen"},
+{"name": "michael costa"},
+{"name": "peter saladino"},
+{"name": "ashley shedd"},
+{"name": "laura yates"},
+{"name": "pam courie"},
+{"name": "corey hutchins"},
+{"name": "amanda mullins"},
+{"name": "freeman mik"},
+{"name": "carroll morrow"},
+{"name": "robert griffith"},
+{"name": "michelle gorden"},
+{"name": "eboni cooper"},
+{"name": "roxie markkanen"},
+{"name": "terry sobkowiak"},
+{"name": "laura frankenfield"},
+{"name": "paula rangers"},
+{"name": "jennifer ma"},
+{"name": "misty early"},
+{"name": "joey hinojosa"},
+{"name": "michelle inn"},
+{"name": "frank numbers"},
+{"name": "lori brodsky"},
+{"name": "jennifer ring"},
+{"name": "curtis hendricks"},
+{"name": "claudia chavez"},
+{"name": "wayne logan"},
+{"name": "gregg tugya"},
+{"name": "mike elliot"},
+{"name": "gary mendelson"},
+{"name": "jodi stach"},
+{"name": "ben r"},
+{"name": "mark wines"},
+{"name": "denise m"},
+{"name": "tiana christoforids"},
+{"name": "marian pineda"},
+{"name": "matt anderson"},
+{"name": "lou santana"},
+{"name": "mitch bear"},
+{"name": "theresa wilkerson"},
+{"name": "sean baulch"},
+{"name": "rita carlisle"},
+{"name": "dale loucia"},
+{"name": "van fleet"},
+{"name": "teri gazzilli"},
+{"name": "gary neeleman"},
+{"name": "greg solomon"},
+{"name": "kate sheppard"},
+{"name": "nick shiplov"},
+{"name": "cindy ries"},
+{"name": "alvin spencer"},
+{"name": "sharon dass"},
+{"name": "lauren spratte"},
+{"name": "craig threlkeld"},
+{"name": "steve komperta"},
+{"name": "michael zurat"},
+{"name": "david scherfenberg"},
+{"name": "jen kahtz"},
+{"name": "kim metheny"},
+{"name": "phyllis knight"},
+{"name": "joe menousek"},
+{"name": "monica samuels"},
+{"name": "sara bennett"},
+{"name": "sheryl stewart"},
+{"name": "greg muholland"},
+{"name": "stephanie home"},
+{"name": "ed ezaki"},
+{"name": "derrick pittman"},
+{"name": "ivy washington"},
+{"name": "jerry namba"},
+{"name": "darin smith"},
+{"name": "brian goebel"},
+{"name": "doug silverman"},
+{"name": "george styles"},
+{"name": "valerie healey"},
+{"name": "carri smith"},
+{"name": "al monsta"},
+{"name": "brian buttermore"},
+{"name": "david claman"},
+{"name": "bob walker"},
+{"name": "liz melendez"},
+{"name": "amy woody"},
+{"name": "karen hull"},
+{"name": "doug lawson"},
+{"name": "laura elder"},
+{"name": "julia tracey"},
+{"name": "mark lemere"},
+{"name": "brian pake"},
+{"name": "jason klein"},
+{"name": "john meyer"},
+{"name": "matthew organ"},
+{"name": "john ko"},
+{"name": "brent brooks"},
+{"name": "jennifer hong"},
+{"name": "ashley robey"},
+{"name": "michael stassen"},
+{"name": "alec stone"},
+{"name": "david paiul"},
+{"name": "tony ball"},
+{"name": "jaclyn wright"},
+{"name": "jeff wellburn"},
+{"name": "kourtney hedden"},
+{"name": "josh dobbs"},
+{"name": "brandon oursler"},
+{"name": "emily york"},
+{"name": "amy sydlansky"},
+{"name": "haley steets"},
+{"name": "evan konc"},
+{"name": "kevin o'sulivan"},
+{"name": "becky sarita"},
+{"name": "stephen jenvey"},
+{"name": "matt behnke"},
+{"name": "brooke westall"},
+{"name": "chris arvin"},
+{"name": "john altava"},
+{"name": "jesse lp"},
+{"name": "ellen tamiyasu"},
+{"name": "john mendoza"},
+{"name": "barry holbert"},
+{"name": "heather kindness"},
+{"name": "kym anthony"},
+{"name": "wes dixon"},
+{"name": "gloria work"},
+{"name": "sonia lowe"},
+{"name": "jennifer moshier"},
+{"name": "alan reagan"},
+{"name": "troy holmes"},
+{"name": "paige oterbine"},
+{"name": "mathew booth"},
+{"name": "chris rollins"},
+{"name": "carlos hernandez"},
+{"name": "steve mcleod"},
+{"name": "jon wilcox"},
+{"name": "jeremy weiner"},
+{"name": "oscar ruiz"},
+{"name": "mark hambling"},
+{"name": "craig fowler"},
+{"name": "rick coombes"},
+{"name": "shannon mcc"},
+{"name": "jana beeman"},
+{"name": "doug hurt"},
+{"name": "mike daniels"},
+{"name": "jerry conklin"},
+{"name": "lori graham"},
+{"name": "jason vinson"},
+{"name": "natalia dousso"},
+{"name": "arthur treiman"},
+{"name": "brooke mooshagian"},
+{"name": "steve anichini"},
+{"name": "gerry deguizman"},
+{"name": "kim ward"},
+{"name": "isaac woodson"},
+{"name": "jay keyz"},
+{"name": "dianne roberg"},
+{"name": "keisha client"},
+{"name": "rick levels"},
+{"name": "jeff coronado"},
+{"name": "golden chopsticks"},
+{"name": "yesenia ruvalcaba"},
+{"name": "john moquin"},
+{"name": "melissa bodily"},
+{"name": "miki johnstone"},
+{"name": "josue melissa"},
+{"name": "jaime rivera"},
+{"name": "david orfao"},
+{"name": "rachel miller"},
+{"name": "anthony toma"},
+{"name": "bill thorup"},
+{"name": "ariel yochnan"},
+{"name": "michael ng"},
+{"name": "teresa ehrichs"},
+{"name": "troy tucker"},
+{"name": "todd a"},
+{"name": "erick vzw"},
+{"name": "tony cusumano"},
+{"name": "joshua kestner"},
+{"name": "may may"},
+{"name": "shanon blkstudtop"},
+{"name": "pete bocca"},
+{"name": "greg diamond"},
+{"name": "suzette dotson"},
+{"name": "marisa kline"},
+{"name": "adam davis"},
+{"name": "taylor tran"},
+{"name": "emily em"},
+{"name": "dyan ross"},
+{"name": "temple heights"},
+{"name": "deb ramirez"},
+{"name": "john crowley"},
+{"name": "mark depico"},
+{"name": "mike welch"},
+{"name": "armand columbie"},
+{"name": "steven smiles"},
+{"name": "eric goldfisher"},
+{"name": "julie mani"},
+{"name": "edgar aguirre"},
+{"name": "cary campbell"},
+{"name": "ronald williams"},
+{"name": "alex nevitt"},
+{"name": "ben tan"},
+{"name": "tiffany morton"},
+{"name": "dennis cline"},
+{"name": "cody marosy"},
+{"name": "don ferrell"},
+{"name": "david long"},
+{"name": "thaddeus gilmore"},
+{"name": "doug beasly"},
+{"name": "jerry patchen"},
+{"name": "claire morel"},
+{"name": "mark wheeler"},
+{"name": "mark mintz"},
+{"name": "zane finger"},
+{"name": "mark hoyt"},
+{"name": "marcus caballero"},
+{"name": "alicia gatto"},
+{"name": "derrick jack"},
+{"name": "lynda hood"},
+{"name": "shirley mcgillivray"},
+{"name": "mark cronin"},
+{"name": "dodie lineham"},
+{"name": "shirley coyle"},
+{"name": "mark rowe"},
+{"name": "mendy philo"},
+{"name": "betsy jasper"},
+{"name": "michelle saffon"},
+{"name": "denis cartright"},
+{"name": "scott ballard"},
+{"name": "tim mills"},
+{"name": "jessie riffey"},
+{"name": "ross gunnells"},
+{"name": "matilde guzman"},
+{"name": "tess rey"},
+{"name": "drew stanz"},
+{"name": "mike limatola"},
+{"name": "steve jijika"},
+{"name": "jen cornwall"},
+{"name": "john hd"},
+{"name": "luis garnica"},
+{"name": "nick beall"},
+{"name": "dave evans"},
+{"name": "reid galas"},
+{"name": "scott corno"},
+{"name": "jodi manager"},
+{"name": "lonnie havasu"},
+{"name": "stephanie buck"},
+{"name": "phillip harvey"},
+{"name": "sallie ss"},
+{"name": "john blair"},
+{"name": "jackie hitz"},
+{"name": "john tegeler"},
+{"name": "teresa weibley"},
+{"name": "nana tata"},
+{"name": "david shevock"},
+{"name": "shaunta boone"},
+{"name": "chris davila"},
+{"name": "kevin joyce"},
+{"name": "paul alekna"},
+{"name": "gary fineske"},
+{"name": "irene lau"},
+{"name": "jonathan haigh"},
+{"name": "charles deal"},
+{"name": "van runkle"},
+{"name": "jacob warren"},
+{"name": "william m"},
+{"name": "noel ballon"},
+{"name": "josh bohl"},
+{"name": "donna summit"},
+{"name": "rick sokolov"},
+{"name": "jack zencheck"},
+{"name": "paul pilo"},
+{"name": "mari seamstress"},
+{"name": "yadira cordova"},
+{"name": "anna flanagan"},
+{"name": "dan day"},
+{"name": "mei wong"},
+{"name": "paul schubert"},
+{"name": "mike scott"},
+{"name": "scott bauer"},
+{"name": "olga rogers"},
+{"name": "trey roller"},
+{"name": "andrea piaz"},
+{"name": "sandie reid"},
+{"name": "anthony chung"},
+{"name": "joshua freeland"},
+{"name": "jami kiser"},
+{"name": "harvey shapiro"},
+{"name": "ed cuevas"},
+{"name": "dixie minor"},
+{"name": "beth kaminkow"},
+{"name": "alex williams"},
+{"name": "andrew hazley"},
+{"name": "mike allain"},
+{"name": "peter botani"},
+{"name": "april newbauer"},
+{"name": "henry walters"},
+{"name": "vince akers"},
+{"name": "seth chambers"},
+{"name": "carl yankowski"},
+{"name": "scott sorgea"},
+{"name": "harold beveir"},
+{"name": "richard bonilla"},
+{"name": "donn waslif"},
+{"name": "noel mcdoughal"},
+{"name": "david rubeck"},
+{"name": "elmer sembly"},
+{"name": "mikel bohringer"},
+{"name": "kevin kosik"},
+{"name": "trudy kuefer"},
+{"name": "suzanne sanders"},
+{"name": "kerri persson"},
+{"name": "jacquie burch"},
+{"name": "leigh shanta"},
+{"name": "adrian zimmerli"},
+{"name": "sammy salinas"},
+{"name": "jason ament"},
+{"name": "katie budweiser"},
+{"name": "man tv"},
+{"name": "jay cel"},
+{"name": "garrett washington"},
+{"name": "johnny carino's"},
+{"name": "al stavola"},
+{"name": "renee vigil"},
+{"name": "will flicker"},
+{"name": "buddy rashbaum"},
+{"name": "ronald short"},
+{"name": "greg rusnell"},
+{"name": "rory beymer"},
+{"name": "jose nunez"},
+{"name": "laura beemiller"},
+{"name": "clayton mcclain"},
+{"name": "todd hazel"},
+{"name": "cindy overton"},
+{"name": "allison holstein"},
+{"name": "josh broderick"},
+{"name": "jose ortega"},
+{"name": "roger cottrell"},
+{"name": "morgan stinger"},
+{"name": "aaron chippie"},
+{"name": "sara skees"},
+{"name": "jean lockett"},
+{"name": "ramon machado"},
+{"name": "brooke blanchard"},
+{"name": "janet welch"},
+{"name": "chris latino"},
+{"name": "craig thompson"},
+{"name": "anna aurilio"},
+{"name": "chris chalmers"},
+{"name": "sam kent"},
+{"name": "sam campa"},
+{"name": "adam little"},
+{"name": "holly hill"},
+{"name": "chris vieira"},
+{"name": "steven seidel"},
+{"name": "harley foster"},
+{"name": "steve bralove"},
+{"name": "alan kaplan"},
+{"name": "mike gunnels"},
+{"name": "richard graham"},
+{"name": "jerry miller"},
+{"name": "cheryl solomon"},
+{"name": "christina lampley"},
+{"name": "megan williams"},
+{"name": "ronda gaither"},
+{"name": "adolfo vasquez"},
+{"name": "gary little"},
+{"name": "tom barwick"},
+{"name": "kelley o'connor"},
+{"name": "michael lamb"},
+{"name": "peter herbert"},
+{"name": "daniel greenberg"},
+{"name": "jim fox"},
+{"name": "amy christensen"},
+{"name": "clare vasterling"},
+{"name": "helen pshnier"},
+{"name": "larry drake"},
+{"name": "michael montemayor"},
+{"name": "patricia howe"},
+{"name": "leonard krulewich"},
+{"name": "george lodge"},
+{"name": "glenn williams"},
+{"name": "kymberly vasey"},
+{"name": "brittany miller"},
+{"name": "victor valdez"},
+{"name": "omer voss"},
+{"name": "mike appleby"},
+{"name": "wes boone"},
+{"name": "roger millis"},
+{"name": "fred schilling"},
+{"name": "shirley stewart"},
+{"name": "jacqueline pickering"},
+{"name": "chuck chrisco"},
+{"name": "bonnie bell"},
+{"name": "wes m"},
+{"name": "brandi buchanan"},
+{"name": "derek weber"},
+{"name": "yuri konyev"},
+{"name": "renee shiao"},
+{"name": "mike lindsey"},
+{"name": "greg baptist"},
+{"name": "mark mra"},
+{"name": "jason lowe"},
+{"name": "debbie coan"},
+{"name": "mike becsei"},
+{"name": "kevin reich"},
+{"name": "steven o"},
+{"name": "gladys malouf"},
+{"name": "bobby mn"},
+{"name": "joey white"},
+{"name": "bob prater"},
+{"name": "linda stowers"},
+{"name": "susan bullman"},
+{"name": "jeremy newton"},
+{"name": "clarence holmes"},
+{"name": "dana sauceda"},
+{"name": "dan hardee"},
+{"name": "erin schoen"},
+{"name": "brad martin"},
+{"name": "jake loahr"},
+{"name": "dan nadir"},
+{"name": "virginia dent"},
+{"name": "barb barton"},
+{"name": "nicole hardy"},
+{"name": "ivan tan"},
+{"name": "jeff kunins"},
+{"name": "david holtzman"},
+{"name": "meg gibson"},
+{"name": "robert hime"},
+{"name": "jason balaska"},
+{"name": "jim scarlett"},
+{"name": "ken kinsley"},
+{"name": "nick jensen"},
+{"name": "brandon martin"},
+{"name": "steven biasatti"},
+{"name": "mike weldy"},
+{"name": "alexandra davidson"},
+{"name": "will t"},
+{"name": "bobby pemberton"},
+{"name": "andrew hill"},
+{"name": "tamika morris"},
+{"name": "bev yac"},
+{"name": "bill millers"},
+{"name": "ian sison"},
+{"name": "veronica couzyn"},
+{"name": "susan hanna"},
+{"name": "mark braun"},
+{"name": "star financial"},
+{"name": "steve li"},
+{"name": "ian kraynak"},
+{"name": "bridget whipple"},
+{"name": "janet king"},
+{"name": "tiffany dst"},
+{"name": "susan stevens"},
+{"name": "sam milrod"},
+{"name": "natalie mindt"},
+{"name": "kenny clark"},
+{"name": "sabrina pascucci"},
+{"name": "joe songstad"},
+{"name": "john oppenheim"},
+{"name": "alex mcdow"},
+{"name": "jon richards"},
+{"name": "kyle shoemaker"},
+{"name": "kenneth cloward"},
+{"name": "sandy currie"},
+{"name": "troy sloat"},
+{"name": "ryan izzo"},
+{"name": "ryan avery"},
+{"name": "ron green"},
+{"name": "nick v"},
+{"name": "corrine yount"},
+{"name": "rosa carney"},
+{"name": "jeffrey wu"},
+{"name": "sharon mahoney"},
+{"name": "chris dinneen"},
+{"name": "erin e"},
+{"name": "rich peritz"},
+{"name": "jim causey"},
+{"name": "raul xxxxx"},
+{"name": "maggie mallety"},
+{"name": "dana walker"},
+{"name": "chu tu"},
+{"name": "debbie bartley"},
+{"name": "susanna cooper"},
+{"name": "john finklea"},
+{"name": "ted rowett"},
+{"name": "jack terry"},
+{"name": "jason jones"},
+{"name": "tom lyons"},
+{"name": "leland wells"},
+{"name": "justin mcdonald"},
+{"name": "lowell irwin"},
+{"name": "justin moaibito"},
+{"name": "chris slaughter"},
+{"name": "william noble"},
+{"name": "helen yuen"},
+{"name": "marjorie ritter"},
+{"name": "kelly stratford"},
+{"name": "megan racicot"},
+{"name": "jen niedzwiedzki"},
+{"name": "megan gags"},
+{"name": "lamont williams"},
+{"name": "barb krinn"},
+{"name": "barry mccullers"},
+{"name": "jake heibel"},
+{"name": "james keeline"},
+{"name": "martha rivera"},
+{"name": "tanya thompson"},
+{"name": "irving caribe"},
+{"name": "colin mcdermott"},
+{"name": "andy houtz"},
+{"name": "chris tattoos"},
+{"name": "greg hopkins"},
+{"name": "bonnie chu"},
+{"name": "justin jess"},
+{"name": "dave leon"},
+{"name": "henry fishcl"},
+{"name": "scott morgan"},
+{"name": "shay shay"},
+{"name": "troy vincent"},
+{"name": "christy durbin"},
+{"name": "dave pimpdog"},
+{"name": "victoria lorenzo"},
+{"name": "paul moret"},
+{"name": "antoinette ussery"},
+{"name": "eric griffin"},
+{"name": "mark k"},
+{"name": "dana bleifer"},
+{"name": "tania kucera"},
+{"name": "george villa"},
+{"name": "austin farnsworth"},
+{"name": "sara moss"},
+{"name": "adam sampson"},
+{"name": "pam iorio"},
+{"name": "amy miller"},
+{"name": "kenny t"},
+{"name": "robert selaiden"},
+{"name": "evelyn upham"},
+{"name": "mary harvey"},
+{"name": "amanda costa"},
+{"name": "jung hoon"},
+{"name": "jenni hinderer"},
+{"name": "mark taul"},
+{"name": "krystal rodriguez"},
+{"name": "federico amadeo"},
+{"name": "mike walker"},
+{"name": "anita hall"},
+{"name": "steve bhalla"},
+{"name": "keith canacci"},
+{"name": "nick narrin"},
+{"name": "jerry mansour"},
+{"name": "naomi alboleda"},
+{"name": "christine briones"},
+{"name": "dalene prout"},
+{"name": "nicole guard"},
+{"name": "dacia dr"},
+{"name": "kecia blount"},
+{"name": "fred toms"},
+{"name": "brian hale"},
+{"name": "john reed"},
+{"name": "dave dohn"},
+{"name": "linda kneece"},
+{"name": "tony spatola"},
+{"name": "mike zimmer"},
+{"name": "tony craig"},
+{"name": "patricia yarborough"},
+{"name": "lisa flynn"},
+{"name": "dalene quintana"},
+{"name": "tom home"},
+{"name": "don prioleau"},
+{"name": "ava seave"},
+{"name": "michael ahrens"},
+{"name": "tina gorter"},
+{"name": "ryan doke"},
+{"name": "kyle repetti"},
+{"name": "trish mcmillan"},
+{"name": "greg griggs"},
+{"name": "bambi omo"},
+{"name": "stanley chara"},
+{"name": "amanda moreno"},
+{"name": "lori e"},
+{"name": "brett hagin"},
+{"name": "sam seibert"},
+{"name": "tiffany henning"},
+{"name": "louis hunt"},
+{"name": "sara conn"},
+{"name": "patrick emmons"},
+{"name": "michael chiorean"},
+{"name": "sandy montenegro"},
+{"name": "galen scott"},
+{"name": "michelle gagnon"},
+{"name": "dan deist"},
+{"name": "jay shiel"},
+{"name": "chris contino"},
+{"name": "michael rickert"},
+{"name": "lou haen"},
+{"name": "rick wood"},
+{"name": "jeremy vzw"},
+{"name": "tracy jones"},
+{"name": "josh wheeler"},
+{"name": "melissa carter"},
+{"name": "keith lam"},
+{"name": "tony nardi"},
+{"name": "alex glassenberg"},
+{"name": "cathleen stagen"},
+{"name": "maggie castillo"},
+{"name": "yolanda green"},
+{"name": "joe ozuna"},
+{"name": "luis leon"},
+{"name": "matt brazil"},
+{"name": "teresa youngberg"},
+{"name": "andy ilg"},
+{"name": "tim wiza"},
+{"name": "kim fountain"},
+{"name": "van tran"},
+{"name": "sara reif"},
+{"name": "danielle diamond"},
+{"name": "kathryn darringer"},
+{"name": "vannessa strand"},
+{"name": "travis hall"},
+{"name": "steve findley"},
+{"name": "brandy slater"},
+{"name": "roberto martinez"},
+{"name": "cindy gold"},
+{"name": "george contractor"},
+{"name": "margie pruitt"},
+{"name": "dee dee"},
+{"name": "brian simon"},
+{"name": "jack hoke"},
+{"name": "kelle porter"},
+{"name": "james burton"},
+{"name": "craig vonberg"},
+{"name": "mike phillups"},
+{"name": "tam chewing"},
+{"name": "ian kim"},
+{"name": "tom lytle"},
+{"name": "terry ruffing"},
+{"name": "forrest ward"},
+{"name": "selma marable"},
+{"name": "alene gnyp"},
+{"name": "marie kovacs"},
+{"name": "kathlyn gemoya"},
+{"name": "carl woerner"},
+{"name": "jana tostrude"},
+{"name": "matt pierce"},
+{"name": "lori egler"},
+{"name": "dave fryer"},
+{"name": "alex zand"},
+{"name": "raymond chow"},
+{"name": "julie steelquist"},
+{"name": "jeanette ashley"},
+{"name": "ira topov"},
+{"name": "shauna wojdak"},
+{"name": "shanta huque"},
+{"name": "veronica torres"},
+{"name": "annette schwartz"},
+{"name": "kyle pupello"},
+{"name": "steve ott"},
+{"name": "bella andrawos"},
+{"name": "lisa buck"},
+{"name": "cindy bellet"},
+{"name": "danna garcia"},
+{"name": "bill bartlett"},
+{"name": "adam hartung"},
+{"name": "jessica nothnagel"},
+{"name": "lena dalbey"},
+{"name": "mark dieckhoff"},
+{"name": "charlie s"},
+{"name": "tom jackson"},
+{"name": "greg gonzalez"},
+{"name": "frank delaney"},
+{"name": "oliva romano"},
+{"name": "john reiff"},
+{"name": "hilda barrios"},
+{"name": "carl hasselbrink"},
+{"name": "corrie williams"},
+{"name": "albert hitchcock"},
+{"name": "bart bball"},
+{"name": "jack stewart"},
+{"name": "amy isaacson"},
+{"name": "daniel milikow"},
+{"name": "rebecca crouch"},
+{"name": "natasha richards"},
+{"name": "mark dirsa"},
+{"name": "amber cook"},
+{"name": "sean goodman"},
+{"name": "joe cosper"},
+{"name": "tom swygert"},
+{"name": "dani cook"},
+{"name": "victor carballo"},
+{"name": "larry thrasher"},
+{"name": "lora shogi"},
+{"name": "jeff m"},
+{"name": "bessie marin"},
+{"name": "patrick gentile"},
+{"name": "burton goldberg"},
+{"name": "sandy hanower"},
+{"name": "jamie rogers"},
+{"name": "jon marselis"},
+{"name": "roxanne whitfield"},
+{"name": "joe sims"},
+{"name": "jay basken"},
+{"name": "maria nashif"},
+{"name": "claire sievers"},
+{"name": "dale mills"},
+{"name": "gary slayton"},
+{"name": "chris randle"},
+{"name": "anne verboom"},
+{"name": "stephanie gower"},
+{"name": "van huynh"},
+{"name": "clay andrews"},
+{"name": "adam molloy"},
+{"name": "mike willis"},
+{"name": "dillon mclaughlin"},
+{"name": "sergio c"},
+{"name": "craig bass"},
+{"name": "stephen medina"},
+{"name": "lee long"},
+{"name": "ronald chapman"},
+{"name": "miriam cole"},
+{"name": "ken christensen"},
+{"name": "amanda t"},
+{"name": "jimmy crofts"},
+{"name": "richard morgan"},
+{"name": "sam knowles"},
+{"name": "howard wimmit"},
+{"name": "sally hand"},
+{"name": "chris bethel"},
+{"name": "mike flynn"},
+{"name": "misha rebec"},
+{"name": "mark galloway"},
+{"name": "paul mouridian"},
+{"name": "robert todd"},
+{"name": "betty pygram"},
+{"name": "matt duntz"},
+{"name": "caroline kay"},
+{"name": "andy pavelich"},
+{"name": "gary fontaine"},
+{"name": "lisa pappas"},
+{"name": "david koscheski"},
+{"name": "tammy hermann"},
+{"name": "henry wheat"},
+{"name": "isaac emmanuel"},
+{"name": "jennifer meyer"},
+{"name": "dorothy pleas"},
+{"name": "jose girl"},
+{"name": "patricia barnes"},
+{"name": "christine canfield"},
+{"name": "jessica bodner"},
+{"name": "kevin john"},
+{"name": "kenneth dembek"},
+{"name": "simon miller"},
+{"name": "michael henry"},
+{"name": "shirley starlings"},
+{"name": "bettye jackson"},
+{"name": "chandra ramsey"},
+{"name": "steve bjelich"},
+{"name": "christin meyer"},
+{"name": "casey black"},
+{"name": "james p"},
+{"name": "david saverino"},
+{"name": "kerry nelson"},
+{"name": "brad dolian"},
+{"name": "allen abbassi"},
+{"name": "marilyn town"},
+{"name": "leonard renier"},
+{"name": "jenna jordan"},
+{"name": "andy papadopoulos"},
+{"name": "paul harell"},
+{"name": "stacey rose"},
+{"name": "vanessa quintal"},
+{"name": "frank fama"},
+{"name": "vaughn schrotenboer"},
+{"name": "keith macdonald"},
+{"name": "liz prentice"},
+{"name": "bruce podgur"},
+{"name": "carlos g"},
+{"name": "mary shaw"},
+{"name": "linda vap"},
+{"name": "michael waxman"},
+{"name": "dana subcock"},
+{"name": "lindsay banta"},
+{"name": "nicole storman"},
+{"name": "herb vincent"},
+{"name": "charlie fitzsimmons"},
+{"name": "davis vision"},
+{"name": "carol klaus"},
+{"name": "alex benes"},
+{"name": "james grice"},
+{"name": "john mcdaniel"},
+{"name": "diana hassell"},
+{"name": "danielle lavigne"},
+{"name": "michael liang"},
+{"name": "pete pestello"},
+{"name": "elisabeth merkel"},
+{"name": "mike kao"},
+{"name": "judy aunt"},
+{"name": "michele mariscal"},
+{"name": "marty roberts"},
+{"name": "evan callaway"},
+{"name": "ian doberstein"},
+{"name": "kenny dunn"},
+{"name": "van hilsen"},
+{"name": "luis santamaria"},
+{"name": "jeff ajlouny"},
+{"name": "kris freed"},
+{"name": "patricia lynch"},
+{"name": "cleveland police"},
+{"name": "david segal"},
+{"name": "shawn odom"},
+{"name": "robert hugo"},
+{"name": "jonathan radcliffe"},
+{"name": "david kera"},
+{"name": "mark bast"},
+{"name": "faith kimball"},
+{"name": "kristie brown"},
+{"name": "lucina marsh"},
+{"name": "lenny o'donnell"},
+{"name": "tony williams"},
+{"name": "phil mcgrady"},
+{"name": "jeremiah velera"},
+{"name": "brian steinwurtzel"},
+{"name": "kristen counter"},
+{"name": "alise keil"},
+{"name": "carly figliulo"},
+{"name": "scott simeon"},
+{"name": "lora mertz"},
+{"name": "derek lawes"},
+{"name": "cheryl crelly"},
+{"name": "joe sumrall"},
+{"name": "ryan bland"},
+{"name": "paul cahill"},
+{"name": "rachael leb"},
+{"name": "tristan latino"},
+{"name": "kara derosa"},
+{"name": "michael eng"},
+{"name": "lauren taylor"},
+{"name": "annette ory"},
+{"name": "mike robinson"},
+{"name": "erik heart"},
+{"name": "sean selecta"},
+{"name": "jeremy lerwill"},
+{"name": "dani taylor"},
+{"name": "lucille fink"},
+{"name": "jamal anderson"},
+{"name": "elizabeth cuz"},
+{"name": "tommy chau"},
+{"name": "nick koenig"},
+{"name": "alejandro liontop"},
+{"name": "collette huskey"},
+{"name": "mia hoogheem"},
+{"name": "francis casey"},
+{"name": "nicole jenkins"},
+{"name": "suzanne israel"},
+{"name": "kylie plattsmouth"},
+{"name": "shelley cobian"},
+{"name": "tana kostic"},
+{"name": "katie doherty"},
+{"name": "archie griffin"},
+{"name": "trey p"},
+{"name": "sarah miracle"},
+{"name": "bob bishop"},
+{"name": "hector mendoza"},
+{"name": "bonita dental"},
+{"name": "peter dawkins"},
+{"name": "carlee cochrane"},
+{"name": "darius mom"},
+{"name": "rochelle martire"},
+{"name": "julie stillman"},
+{"name": "claire preice"},
+{"name": "devin dmacc"},
+{"name": "angelica aceves"},
+{"name": "joanna wool"},
+{"name": "evan constan"},
+{"name": "bob naum"},
+{"name": "deb conroy"},
+{"name": "nathan leung"},
+{"name": "doug barnette"},
+{"name": "rick walker"},
+{"name": "dave syck"},
+{"name": "joseph stakem"},
+{"name": "mark mccord"},
+{"name": "enrique enguidanos"},
+{"name": "joel pascual"},
+{"name": "stephan reynolds"},
+{"name": "sal concrete"},
+{"name": "dawn westbrook"},
+{"name": "rachel eastway"},
+{"name": "les dis"},
+{"name": "melanie schiemer"},
+{"name": "james blair"},
+{"name": "stacy d"},
+{"name": "carla martin"},
+{"name": "marla cell"},
+{"name": "randy russ"},
+{"name": "jim janson"},
+{"name": "melanie s"},
+{"name": "carrie needham"},
+{"name": "trish bradley"},
+{"name": "jana klavas"},
+{"name": "katie craig"},
+{"name": "bob vanklingren"},
+{"name": "jared alco"},
+{"name": "connie newman"},
+{"name": "annie schleicher"},
+{"name": "jeff collier"},
+{"name": "will deaton"},
+{"name": "yolande kay"},
+{"name": "daniel mccormack"},
+{"name": "lesa carmack"},
+{"name": "steve bivens"},
+{"name": "harry psilopoulos"},
+{"name": "jeff brambir"},
+{"name": "todd butler"},
+{"name": "rob stuart"},
+{"name": "sean tangen"},
+{"name": "sam parks"},
+{"name": "ken sha"},
+{"name": "trevor shedd"},
+{"name": "chad tilly"},
+{"name": "danny ainge"},
+{"name": "brian byer"},
+{"name": "columbus park"},
+{"name": "andrew estes"},
+{"name": "teresa mccarthy"},
+{"name": "gil blattner"},
+{"name": "adam o'keefe"},
+{"name": "sarah long"},
+{"name": "will kuntz"},
+{"name": "david bramon"},
+{"name": "melissa mariano"},
+{"name": "dwayne king"},
+{"name": "melissa gagnon"},
+{"name": "sari greenberg"},
+{"name": "michael paul"},
+{"name": "maria leos"},
+{"name": "archie cardwell"},
+{"name": "teri mccall"},
+{"name": "curt hauber"},
+{"name": "jeff mlodinoff"},
+{"name": "chris jersy"},
+{"name": "melinda gibson"},
+{"name": "peter rhee"},
+{"name": "kyle schwab"},
+{"name": "brad verona"},
+{"name": "scott hendrickson"},
+{"name": "tim mccreary"},
+{"name": "richard dr"},
+{"name": "chris kloep"},
+{"name": "ben knoop"},
+{"name": "nikki chick"},
+{"name": "mike heighbor"},
+{"name": "alan telefunken"},
+{"name": "mike mcgee"},
+{"name": "joe book"},
+{"name": "elizabeth l"},
+{"name": "nicholas grundei"},
+{"name": "scott romero"},
+{"name": "joan morgan"},
+{"name": "jan hillman"},
+{"name": "heather sg"},
+{"name": "roger ropp"},
+{"name": "lisa palazzo"},
+{"name": "tyler will"},
+{"name": "katie hacket"},
+{"name": "louise beaulieu"},
+{"name": "lydia henik"},
+{"name": "colin gebhard"},
+{"name": "dallas peterson"},
+{"name": "tommy eulberg"},
+{"name": "gregory gulia"},
+{"name": "doug dillon"},
+{"name": "andrea digdo"},
+{"name": "thomas s"},
+{"name": "susan paoli"},
+{"name": "margaret sherman"},
+{"name": "van acker"},
+{"name": "richard zverina"},
+{"name": "sophie b"},
+{"name": "michael fleisher"},
+{"name": "joe rodgers"},
+{"name": "dennis lynch"},
+{"name": "tim kelley"},
+{"name": "cherie watkins"},
+{"name": "frank palermo"},
+{"name": "lisa dave"},
+{"name": "amy nelson"},
+{"name": "charles fetzer"},
+{"name": "shelia reese"},
+{"name": "nannette wilkins"},
+{"name": "crystal lane"},
+{"name": "scott felgenhauer"},
+{"name": "kelly teds"},
+{"name": "shari rochester"},
+{"name": "ben bar"},
+{"name": "john pak"},
+{"name": "nancy reeves"},
+{"name": "lindsey b"},
+{"name": "chuck c"},
+{"name": "michael yvonne"},
+{"name": "christina smillie"},
+{"name": "june house"},
+{"name": "chris hudson"},
+{"name": "sarah jacobson"},
+{"name": "larry goldberg"},
+{"name": "michael dawkins"},
+{"name": "andrea mathieu"},
+{"name": "dave sedlacko"},
+{"name": "don glacy"},
+{"name": "douglas michie"},
+{"name": "cheryl knox"},
+{"name": "brian grant"},
+{"name": "leon beurde"},
+{"name": "beth alitt"},
+{"name": "lisa landau"},
+{"name": "clarence will"},
+{"name": "jessica winton"},
+{"name": "kyle opc"},
+{"name": "jill russ"},
+{"name": "wayne roy"},
+{"name": "chrissy baker"},
+{"name": "bill hoppes"},
+{"name": "miguel baeza"},
+{"name": "sarah young"},
+{"name": "shanna wilcoxen"},
+{"name": "shane o'neill"},
+{"name": "ray prigodich"},
+{"name": "tim sumera"},
+{"name": "rick gobio"},
+{"name": "laura chittenden"},
+{"name": "adam wilhite"},
+{"name": "kelsey schuette"},
+{"name": "ted moye"},
+{"name": "nancy vanasse"},
+{"name": "larry diran"},
+{"name": "david mack"},
+{"name": "johnny perez"},
+{"name": "dave dover"},
+{"name": "maurice nixon"},
+{"name": "tai food"},
+{"name": "kevin jensen"},
+{"name": "blake c"},
+{"name": "jason young"},
+{"name": "crystal azuara"},
+{"name": "matt quinlan"},
+{"name": "ken thomas"},
+{"name": "larry maguire"},
+{"name": "stacey battenfield"},
+{"name": "steve hartley"},
+{"name": "carlos lema"},
+{"name": "peter cairo"},
+{"name": "seth edm"},
+{"name": "beth geagley"},
+{"name": "sherrie shelley"},
+{"name": "peter campen"},
+{"name": "laura cellcom"},
+{"name": "van niekerk"},
+{"name": "mike gerth"},
+{"name": "janice mcmahon"},
+{"name": "nicole mustang"},
+{"name": "amanda fischer"},
+{"name": "lizette zuninga"},
+{"name": "johanna rowe"},
+{"name": "chris hamje"},
+{"name": "stacy robinson"},
+{"name": "dan campagna"},
+{"name": "lindsy l"},
+{"name": "jose barrera"},
+{"name": "robert faure"},
+{"name": "mac mac"},
+{"name": "john batz"},
+{"name": "jim livingston"},
+{"name": "laura masso"},
+{"name": "jacqueline henderson"},
+{"name": "beatriz cajade"},
+{"name": "brian sanderson"},
+{"name": "damian brawner"},
+{"name": "brett roeloffs"},
+{"name": "annamarie cell"},
+{"name": "marc garside"},
+{"name": "kim peck"},
+{"name": "amy schultz"},
+{"name": "barry gilardi"},
+{"name": "todd zivic"},
+{"name": "jim pigeon"},
+{"name": "melissa rios"},
+{"name": "richard strauss"},
+{"name": "dean spears"},
+{"name": "johnny liao"},
+{"name": "leah able"},
+{"name": "henry johnson"},
+{"name": "gary laib"},
+{"name": "kathleen mcgann"},
+{"name": "mercy north"},
+{"name": "gussie doucet"},
+{"name": "john geraghty"},
+{"name": "dennis sage"},
+{"name": "alex wulff"},
+{"name": "petra zamora"},
+{"name": "kelly gentry"},
+{"name": "joe wolfe"},
+{"name": "ed downs"},
+{"name": "brandon gmc"},
+{"name": "anthony bell"},
+{"name": "doug drennan"},
+{"name": "jeanine flemming"},
+{"name": "franklin arner"},
+{"name": "mary lester"},
+{"name": "shonda hosley"},
+{"name": "jermaine boltom"},
+{"name": "alan hritz"},
+{"name": "jo stribling"},
+{"name": "tricia mcmullen"},
+{"name": "juanita lyons"},
+{"name": "john sweigart"},
+{"name": "manuel camarena"},
+{"name": "mike brittingham"},
+{"name": "denise oberfoell"},
+{"name": "kyle hotface"},
+{"name": "thomas potter"},
+{"name": "bob glaser"},
+{"name": "pierre g"},
+{"name": "bruce bradford"},
+{"name": "mara aspinall"},
+{"name": "james chesson"},
+{"name": "randy legacy"},
+{"name": "bill mullin"},
+{"name": "tom porsche"},
+{"name": "laura bye"},
+{"name": "louis m"},
+{"name": "jennifer cell"},
+{"name": "margie contreras"},
+{"name": "chuck vogel"},
+{"name": "heather andrews"},
+{"name": "timothy worley"},
+{"name": "karen lane"},
+{"name": "andrea kimmell"},
+{"name": "phil wagers"},
+{"name": "holly beaton"},
+{"name": "donn dirckx"},
+{"name": "jodi burgess"},
+{"name": "grant vandyke"},
+{"name": "kristen gaetano"},
+{"name": "gina ruttenber"},
+{"name": "wade kids"},
+{"name": "mark pleis"},
+{"name": "mark chu"},
+{"name": "kris ehlert"},
+{"name": "tim starchman"},
+{"name": "jim warsaw"},
+{"name": "john piscitelli"},
+{"name": "krista adams"},
+{"name": "erica brown"},
+{"name": "nichole wilson"},
+{"name": "don miles"},
+{"name": "doris barnes"},
+{"name": "tammy sigler"},
+{"name": "dionne savage"},
+{"name": "erin party"},
+{"name": "sage massage"},
+{"name": "kyle j"},
+{"name": "delores gray"},
+{"name": "judy mcfarland"},
+{"name": "clint edwards"},
+{"name": "stephanie mistrel"},
+{"name": "willy velazquez"},
+{"name": "tim juillett"},
+{"name": "george ku"},
+{"name": "juan campos"},
+{"name": "tony paloto"},
+{"name": "ma taxi"},
+{"name": "nick griego"},
+{"name": "stephanie burton"},
+{"name": "reinaldo kingland"},
+{"name": "vince biancuzzo"},
+{"name": "regina michael"},
+{"name": "madeleine heal"},
+{"name": "andrew yaldo"},
+{"name": "steve cummins"},
+{"name": "jeff todd"},
+{"name": "rafael johnson"},
+{"name": "brian craig"},
+{"name": "cole lolo"},
+{"name": "kevin hotaling"},
+{"name": "allen karakosian"},
+{"name": "joanne lindsey"},
+{"name": "gordon soltan"},
+{"name": "rosalyn blount"},
+{"name": "charlie bonier"},
+{"name": "brock galvin"},
+{"name": "val astillero"},
+{"name": "matthew schulz"},
+{"name": "andy gainer"},
+{"name": "don cross"},
+{"name": "matt glab"},
+{"name": "jacques designs"},
+{"name": "emily thompson"},
+{"name": "thad engellenner"},
+{"name": "christina smith"},
+{"name": "brandon mejia"},
+{"name": "andres rael"},
+{"name": "marcus martin"},
+{"name": "lance home"},
+{"name": "michele mollica"},
+{"name": "dana namowicz"},
+{"name": "christian freshy"},
+{"name": "kelly stockhaus"},
+{"name": "brittney everhart"},
+{"name": "chris henrie"},
+{"name": "kristen abbondante"},
+{"name": "crystal mckellar"},
+{"name": "sandra reyes"},
+{"name": "john hayet"},
+{"name": "neil sikora"},
+{"name": "neal oppen"},
+{"name": "ray bradshaw"},
+{"name": "vicki venable"},
+{"name": "annette murray"},
+{"name": "anne posada"},
+{"name": "amy peele"},
+{"name": "tara morgan"},
+{"name": "max zollner"},
+{"name": "andy adams"},
+{"name": "dan lavalley"},
+{"name": "serena choi"},
+{"name": "mellissa s"},
+{"name": "pamela leidecker"},
+{"name": "brandon des"},
+{"name": "brian mez"},
+{"name": "timothy farrell"},
+{"name": "elaine chan"},
+{"name": "royal res"},
+{"name": "karen rakowski"},
+{"name": "korey skudder"},
+{"name": "ken leal"},
+{"name": "ali entwistle"},
+{"name": "shannon wenaas"},
+{"name": "gerry wilson"},
+{"name": "peter comeau"},
+{"name": "megan ortizzle"},
+{"name": "caitlyn mcneill"},
+{"name": "frank leonard"},
+{"name": "lisa jurgens"},
+{"name": "corey jones"},
+{"name": "beth aspinall"},
+{"name": "deana mayorga"},
+{"name": "rob pulver"},
+{"name": "preston pointe"},
+{"name": "matt biker"},
+{"name": "doug murray"},
+{"name": "janet rutherford"},
+{"name": "linda bryant"},
+{"name": "luis pinpin"},
+{"name": "clay covington"},
+{"name": "frank hunter"},
+{"name": "todd meek"},
+{"name": "randy colvin"},
+{"name": "mike koerner"},
+{"name": "dennis patterson"},
+{"name": "jon osterhout"},
+{"name": "marie begay"},
+{"name": "dennis cardoza"},
+{"name": "tatiana taylor"},
+{"name": "abraham friend"},
+{"name": "howard fitzpatrick"},
+{"name": "sara christianson"},
+{"name": "thelma carnero"},
+{"name": "mike wiggins"},
+{"name": "nathalie leblanc"},
+{"name": "mac duzer"},
+{"name": "jake conley"},
+{"name": "clifford harris"},
+{"name": "andy whitworth"},
+{"name": "rebecca milner"},
+{"name": "freeman cell"},
+{"name": "ned sirry"},
+{"name": "jon holland"},
+{"name": "scott davidson"},
+{"name": "brian schrumpf"},
+{"name": "george solano"},
+{"name": "marcia dover"},
+{"name": "andrew olvera"},
+{"name": "scott cmptr"},
+{"name": "ericka baca"},
+{"name": "stephen lim"},
+{"name": "iris talbot"},
+{"name": "aaron armstrong"},
+{"name": "rick zak"},
+{"name": "linda rita"},
+{"name": "pete kinnaman"},
+{"name": "richard ireland"},
+{"name": "scott vaughan"},
+{"name": "kay jackson"},
+{"name": "tom cortese"},
+{"name": "brad catlow"},
+{"name": "laura brooker"},
+{"name": "debra cameron"},
+{"name": "erik myford"},
+{"name": "chris lilly"},
+{"name": "daniel lammers"},
+{"name": "michael swanson"},
+{"name": "kirsten barber"},
+{"name": "nick christensen"},
+{"name": "scott reynolds"},
+{"name": "christopher o'rand"},
+{"name": "anna martin"},
+{"name": "dexter collins"},
+{"name": "doug hypnox"},
+{"name": "trevor y"},
+{"name": "dell moellenberg"},
+{"name": "dan cosentino"},
+{"name": "amy liberman"},
+{"name": "eva h"},
+{"name": "michael howarth"},
+{"name": "lynn snyder"},
+{"name": "freddy adams"},
+{"name": "beth gentry"},
+{"name": "nick molina"},
+{"name": "grant hackney"},
+{"name": "jan divito"},
+{"name": "mark eastley"},
+{"name": "barry stevens"},
+{"name": "rick hocking"},
+{"name": "brent schneider"},
+{"name": "eugene russia"},
+{"name": "eric lott"},
+{"name": "brenda endicott"},
+{"name": "andy whaley"},
+{"name": "aleshia foskett"},
+{"name": "jeff wong"},
+{"name": "lynn fugina"},
+{"name": "richard nield"},
+{"name": "joseph pannick"},
+{"name": "tim ladison"},
+{"name": "jeremy gaffrey"},
+{"name": "willie everette"},
+{"name": "brad holsworth"},
+{"name": "jerry burke"},
+{"name": "brent blumenthal"},
+{"name": "ron westphal"},
+{"name": "shane ching"},
+{"name": "linda tier"},
+{"name": "anthony scott"},
+{"name": "nancy tees"},
+{"name": "bruce bekkerus"},
+{"name": "bobby s"},
+{"name": "catherine consiglieri"},
+{"name": "alina ivanyk"},
+{"name": "molly crippen"},
+{"name": "johanna bennett"},
+{"name": "dan k"},
+{"name": "dee reeder"},
+{"name": "craig dubberstein"},
+{"name": "eric german"},
+{"name": "tuan post"},
+{"name": "jeff watchel"},
+{"name": "scott pickens"},
+{"name": "keiko clark"},
+{"name": "jeff dynasplint"},
+{"name": "brian o'keefe"},
+{"name": "mike nelson"},
+{"name": "matt legray"},
+{"name": "kate carroll"},
+{"name": "don slater"},
+{"name": "joanna nickels"},
+{"name": "tommie hart"},
+{"name": "liz smith"},
+{"name": "matt vw"},
+{"name": "ian lesley"},
+{"name": "kurt fleer"},
+{"name": "ryan forbes"},
+{"name": "curtis emory"},
+{"name": "hee lee"},
+{"name": "garret schaede"},
+{"name": "tasha barton"},
+{"name": "eric whimmer"},
+{"name": "laura doyle"},
+{"name": "julie erickson"},
+{"name": "denise mcken"},
+{"name": "tamara sebilian"},
+{"name": "so fong"},
+{"name": "karen costa"},
+{"name": "herb forsythe"},
+{"name": "mike clark"},
+{"name": "mia quinn"},
+{"name": "richard weiss"},
+{"name": "lee dilworth"},
+{"name": "dot jay"},
+{"name": "tony makue"},
+{"name": "pete perez"},
+{"name": "glenn valente"},
+{"name": "sheryl rowling"},
+{"name": "elizabeth chic"},
+{"name": "faith moore"},
+{"name": "courtney caplinger"},
+{"name": "david duarte"},
+{"name": "angel rcsc"},
+{"name": "greg taylor"},
+{"name": "blake baker"},
+{"name": "chad phillips"},
+{"name": "kim hornbeck"},
+{"name": "steve coleman"},
+{"name": "brian pace"},
+{"name": "shannon d"},
+{"name": "brian walowitz"},
+{"name": "scott furtney"},
+{"name": "alice lichtman"},
+{"name": "patti mehling"},
+{"name": "bob haines"},
+{"name": "david kats"},
+{"name": "steve wang"},
+{"name": "gary lau"},
+{"name": "john meyers"},
+{"name": "rose ihedigbo"},
+{"name": "angie carter"},
+{"name": "pete glee"},
+{"name": "robert kolenda"},
+{"name": "mike caputo"},
+{"name": "katie mclauchlin"},
+{"name": "jamie burton"},
+{"name": "tonya grantham"},
+{"name": "albert linderman"},
+{"name": "rich geiger"},
+{"name": "linda trigger"},
+{"name": "ty nightmare"},
+{"name": "ian schneidmiller"},
+{"name": "douglas treasurer"},
+{"name": "ed krieger"},
+{"name": "shawn murray"},
+{"name": "lillian wong"},
+{"name": "katie crowder"},
+{"name": "todd or"},
+{"name": "al bliss"},
+{"name": "georgina gonzalez"},
+{"name": "lauren elias"},
+{"name": "mike elmore"},
+{"name": "don epps"},
+{"name": "elijah kedzie"},
+{"name": "rich mast"},
+{"name": "dwayne mays"},
+{"name": "david bleaman"},
+{"name": "julie rivera"},
+{"name": "stella larreau"},
+{"name": "kerry roman"},
+{"name": "patricia mattos"},
+{"name": "jenny rivera"},
+{"name": "danielle burmylo"},
+{"name": "brett thomas"},
+{"name": "bethany beelan"},
+{"name": "stuart fesseden"},
+{"name": "ben dominguez"},
+{"name": "debbie deba"},
+{"name": "sonny huntley"},
+{"name": "megan chinook"},
+{"name": "laura allenbaugh"},
+{"name": "dena phillips"},
+{"name": "bobbie giuliano"},
+{"name": "jackie cowin"},
+{"name": "sue green"},
+{"name": "stephanie spiller"},
+{"name": "ross casner"},
+{"name": "alex russakovsky"},
+{"name": "libby louman"},
+{"name": "kurt terry"},
+{"name": "julie clark"},
+{"name": "philip georgious"},
+{"name": "mike goodson"},
+{"name": "pete eng"},
+{"name": "brooks king"},
+{"name": "charlie va"},
+{"name": "john pasqualetto"},
+{"name": "tracy johnson"},
+{"name": "keisha dunston"},
+{"name": "heather levy"},
+{"name": "susan kitamura"},
+{"name": "jason pin"},
+{"name": "donnie short"},
+{"name": "josh kelly"},
+{"name": "cathy payne"},
+{"name": "jose cubiche"},
+{"name": "esther o"},
+{"name": "luis villafan"},
+{"name": "melody tyson"},
+{"name": "angela teran"},
+{"name": "jan sanderlin"},
+{"name": "megan hull"},
+{"name": "tiffany bunting"},
+{"name": "joesph teeter"},
+{"name": "mitchell dinkin"},
+{"name": "jodi ferrell"},
+{"name": "philip fryers"},
+{"name": "megan stohner"},
+{"name": "benjamin loeb"},
+{"name": "robin yancey"},
+{"name": "scott lechanski"},
+{"name": "jackson cates"},
+{"name": "greg blaho"},
+{"name": "linda young"},
+{"name": "chris kellog"},
+{"name": "aaron dietrich"},
+{"name": "bill depalma"},
+{"name": "jordan murakami"},
+{"name": "mike ez"},
+{"name": "erica sullenburg"},
+{"name": "darla white"},
+{"name": "michael clark"},
+{"name": "mike hess"},
+{"name": "rocky mt"},
+{"name": "mark genx"},
+{"name": "mark gefroh"},
+{"name": "stephen phalen"},
+{"name": "travis nicol"},
+{"name": "gwen leake"},
+{"name": "austin patton"},
+{"name": "kyle cain"},
+{"name": "mike charvat"},
+{"name": "mike ziemba"},
+{"name": "nellie price"},
+{"name": "jeanne thompson"},
+{"name": "eric doerr"},
+{"name": "paul semak"},
+{"name": "ryan murill"},
+{"name": "jena ellis"},
+{"name": "paul powell"},
+{"name": "nathan h"},
+{"name": "sherri parker"},
+{"name": "collin riley"},
+{"name": "brenda mehringer"},
+{"name": "joey manuguid"},
+{"name": "alex adams"},
+{"name": "jonathan gonzalez"},
+{"name": "olivia yance"},
+{"name": "tobias j"},
+{"name": "les charles"},
+{"name": "shawnda hamilton"},
+{"name": "jim kordel"},
+{"name": "dave farmer"},
+{"name": "sallie bacher"},
+{"name": "will serette"},
+{"name": "aaron peterson"},
+{"name": "stephen stuart"},
+{"name": "tiffany glad"},
+{"name": "joseph d'amato"},
+{"name": "peter roberts"},
+{"name": "jason schutt"},
+{"name": "marie aguilar"},
+{"name": "lincoln cabs"},
+{"name": "walton emc"},
+{"name": "eric hippeau"},
+{"name": "thomas moukiman"},
+{"name": "nadine barth"},
+{"name": "barry kahn"},
+{"name": "jonathan ryskamp"},
+{"name": "crystal birns"},
+{"name": "sharon kerr"},
+{"name": "elizabeth davies"},
+{"name": "jeff bucknam"},
+{"name": "katrina dubinsky"},
+{"name": "rose steiner"},
+{"name": "sharon thompson"},
+{"name": "miss dale"},
+{"name": "ronald berna"},
+{"name": "deanna bing"},
+{"name": "mark kaufman"},
+{"name": "jean carrasquel"},
+{"name": "maria lopez"},
+{"name": "hunter motto"},
+{"name": "delta propane"},
+{"name": "sean bleiler"},
+{"name": "johnnie boy"},
+{"name": "alex vb"},
+{"name": "sandra cuz"},
+{"name": "richard moore"},
+{"name": "tim corey"},
+{"name": "jane elizabeth"},
+{"name": "joanne francisco"},
+{"name": "mary london"},
+{"name": "steve santich"},
+{"name": "anissa attard"},
+{"name": "steve nangle"},
+{"name": "robert golding"},
+{"name": "tom geiger"},
+{"name": "doug riddell"},
+{"name": "bobby laraway"},
+{"name": "jennifer collins"},
+{"name": "karl forste"},
+{"name": "rob kessler"},
+{"name": "lori altman"},
+{"name": "nia powers"},
+{"name": "harris magic"},
+{"name": "jason yarber"},
+{"name": "kathy lansberry"},
+{"name": "allison pace"},
+{"name": "whitney mk"},
+{"name": "chris const"},
+{"name": "mark russell"},
+{"name": "kim plumbley"},
+{"name": "danielle scognamiglio"},
+{"name": "brandy dempsy"},
+{"name": "monte kingstone"},
+{"name": "paola schifino"},
+{"name": "thomas howell"},
+{"name": "karl stelmaczonek"},
+{"name": "lacie payment"},
+{"name": "hope blake"},
+{"name": "genny voltan"},
+{"name": "brad ritthaler"},
+{"name": "art torres"},
+{"name": "michelle bradley"},
+{"name": "melissa neiderman"},
+{"name": "mari d'ambrosio"},
+{"name": "tiffany zejacs"},
+{"name": "james goldkamp"},
+{"name": "amelia estrella"},
+{"name": "allen pickett"},
+{"name": "nick valenziano"},
+{"name": "williams hospital"},
+{"name": "john knopf"},
+{"name": "nick thompson"},
+{"name": "helen mcinnis"},
+{"name": "cindy webb"},
+{"name": "chris jarbo"},
+{"name": "ed linaugh"},
+{"name": "esteban loaiza"},
+{"name": "jason owyang"},
+{"name": "courtney spiller"},
+{"name": "alan farmer"},
+{"name": "mike mundy"},
+{"name": "jim starin"},
+{"name": "valerie beattie"},
+{"name": "bryan rust"},
+{"name": "mike brice"},
+{"name": "dwight eaddy"},
+{"name": "bob pearl"},
+{"name": "james chi"},
+{"name": "jolynn leyderman"},
+{"name": "terri g"},
+{"name": "carlos souza"},
+{"name": "mark wright"},
+{"name": "clinton greyling"},
+{"name": "graham greenlee"},
+{"name": "bob strasser"},
+{"name": "catharine seward"},
+{"name": "kevin savoree"},
+{"name": "michele ayphassorho"},
+{"name": "william holt"},
+{"name": "joseph grossano"},
+{"name": "justin shephard"},
+{"name": "john kiser"},
+{"name": "vickie tidwell"},
+{"name": "cody l"},
+{"name": "joseph larky"},
+{"name": "jamie vedder"},
+{"name": "charlie ambroz"},
+{"name": "jazmin abdulmasih"},
+{"name": "france denk"},
+{"name": "david dunn"},
+{"name": "tim white"},
+{"name": "bob faris"},
+{"name": "selina ray"},
+{"name": "michelle rodeback"},
+{"name": "brian fitch"},
+{"name": "eric farrior"},
+{"name": "nick strombach"},
+{"name": "christina thompson"},
+{"name": "rafael gomez"},
+{"name": "kevin client"},
+{"name": "gary honings"},
+{"name": "blanca aldana"},
+{"name": "dave butters"},
+{"name": "sandy walker"},
+{"name": "mike benntt"},
+{"name": "amy cummins"},
+{"name": "beau hill"},
+{"name": "kevin ma"},
+{"name": "erin norton"},
+{"name": "adrianna delao"},
+{"name": "jody chimura"},
+{"name": "theresa morales"},
+{"name": "anthony s"},
+{"name": "john wendt"},
+{"name": "mike gesmundo"},
+{"name": "jim brouhard"},
+{"name": "leigh hudson"},
+{"name": "paul hunter"},
+{"name": "chris sparrow"},
+{"name": "lisa laznicka"},
+{"name": "daniel castillo"},
+{"name": "mark farmer"},
+{"name": "christine hugh"},
+{"name": "darryl boyd"},
+{"name": "jeanette biolab"},
+{"name": "yvette triana"},
+{"name": "grace kumamoto"},
+{"name": "jeff perry"},
+{"name": "justin burnham"},
+{"name": "robert valentino"},
+{"name": "brent hot"},
+{"name": "roger chen"},
+{"name": "angela bell"},
+{"name": "joyce aunt"},
+{"name": "larry parker"},
+{"name": "justin mcreynolds"},
+{"name": "robin torres"},
+{"name": "danny bolanio"},
+{"name": "rick gilmore"},
+{"name": "jon stock"},
+{"name": "jean ware"},
+{"name": "arnold jenkins"},
+{"name": "bob lee"},
+{"name": "kathleen gannett"},
+{"name": "diane mainville"},
+{"name": "van lear"},
+{"name": "frank nicolette"},
+{"name": "richard sabotino"},
+{"name": "gene deuchar"},
+{"name": "mike berno"},
+{"name": "carl sue"},
+{"name": "brent scoggins"},
+{"name": "grant holland"},
+{"name": "anna garcia"},
+{"name": "erik pof"},
+{"name": "matt grzech"},
+{"name": "bonnie powers"},
+{"name": "david niewood"},
+{"name": "chris lynch"},
+{"name": "katherine arbuckle"},
+{"name": "max simmons"},
+{"name": "nancy douglas"},
+{"name": "stormy haupt"},
+{"name": "andrew kent"},
+{"name": "jean kinkead"},
+{"name": "vince carr"},
+{"name": "bryan chang"},
+{"name": "darnell moore"},
+{"name": "jason birdwell"},
+{"name": "christy ball"},
+{"name": "pat kennedy"},
+{"name": "shane sobers"},
+{"name": "scott burgess"},
+{"name": "dave newbill"},
+{"name": "tim crabtree"},
+{"name": "alan pinel"},
+{"name": "kevin cook"},
+{"name": "erin cash"},
+{"name": "jacque wendel"},
+{"name": "marc castel"},
+{"name": "ramon lopez"},
+{"name": "shannon wells"},
+{"name": "taylor mclemore"},
+{"name": "michael westwood"},
+{"name": "eddie torres"},
+{"name": "julia barnes"},
+{"name": "abdul diallo"},
+{"name": "lilly ferrer"},
+{"name": "audra king"},
+{"name": "jason bourgeois"},
+{"name": "danny santos"},
+{"name": "ed osborne"},
+{"name": "craig lebouef"},
+{"name": "melissa cleaner"},
+{"name": "marx meetup"},
+{"name": "dennis anosike"},
+{"name": "molly o'rourke"},
+{"name": "ken woo"},
+{"name": "brian schawe"},
+{"name": "anne hendrickson"},
+{"name": "andy mitchell"},
+{"name": "charlie gardner"},
+{"name": "terry steele"},
+{"name": "rich exhaust"},
+{"name": "richard murton"},
+{"name": "nisha fufi"},
+{"name": "krystal vonk"},
+{"name": "brian haskins"},
+{"name": "crissy cox"},
+{"name": "cheryl bowden"},
+{"name": "carol desimone"},
+{"name": "andy calhart"},
+{"name": "doug gust"},
+{"name": "cynthia vee"},
+{"name": "marilyn diana"},
+{"name": "chase borum"},
+{"name": "victoria booker"},
+{"name": "mike prather"},
+{"name": "lindsey jordan"},
+{"name": "cassi santana"},
+{"name": "michiko shimura"},
+{"name": "amanda mae"},
+{"name": "kyle messick"},
+{"name": "latonya jackson"},
+{"name": "jonathan blattmachr"},
+{"name": "tina poli"},
+{"name": "chris good"},
+{"name": "charles karich"},
+{"name": "lisette lavella"},
+{"name": "austin mark"},
+{"name": "philip russo"},
+{"name": "stanley ruth"},
+{"name": "michelle meloy"},
+{"name": "john driedger"},
+{"name": "jessica woolsey"},
+{"name": "scott griffin"},
+{"name": "mike sales"},
+{"name": "mark barnreiter"},
+{"name": "joyce rowlands"},
+{"name": "chris sowden"},
+{"name": "jay curnin"},
+{"name": "emily kiely"},
+{"name": "corinna collaga"},
+{"name": "dan jaimie"},
+{"name": "jeff kulinski"},
+{"name": "ben pereira"},
+{"name": "chad akins"},
+{"name": "john wunder"},
+{"name": "tasha corderro"},
+{"name": "chris donahue"},
+{"name": "annette tanori"},
+{"name": "jenni catron"},
+{"name": "kathleen galvin"},
+{"name": "andy shanley"},
+{"name": "gail flynn"},
+{"name": "karen gedrose"},
+{"name": "corey woolley"},
+{"name": "kevin moran"},
+{"name": "brian bedoya"},
+{"name": "david tinkham"},
+{"name": "carmen awad"},
+{"name": "alexander bimman"},
+{"name": "emanuel franklin"},
+{"name": "jay torres"},
+{"name": "gail dixon"},
+{"name": "jerry gomez"},
+{"name": "mark taylor"},
+{"name": "leah waren"},
+{"name": "christian nosiglia"},
+{"name": "nicole iglesias"},
+{"name": "linda mcguire"},
+{"name": "michael house"},
+{"name": "greg palm"},
+{"name": "robin gross"},
+{"name": "jeremy acura"},
+{"name": "dominic lee"},
+{"name": "diane hoover"},
+{"name": "mike jill"},
+{"name": "justin beckwith"},
+{"name": "brooke s"},
+{"name": "phil korn"},
+{"name": "vincent tammaro"},
+{"name": "brian wall"},
+{"name": "jacob vincent"},
+{"name": "scott oh"},
+{"name": "michael bassik"},
+{"name": "ahmed aziz"},
+{"name": "mike cochran"},
+{"name": "marion zaugg"},
+{"name": "david rodela"},
+{"name": "kyle bunke"},
+{"name": "dan wise"},
+{"name": "barry rosenberg"},
+{"name": "juliann cell"},
+{"name": "donna cell"},
+{"name": "crystal miller"},
+{"name": "hailey chan"},
+{"name": "florentina buenaventura"},
+{"name": "james mares"},
+{"name": "sarah farnam"},
+{"name": "rob crain"},
+{"name": "jason tateishi"},
+{"name": "frank dejesus"},
+{"name": "kathy hamilton"},
+{"name": "vivian rintoul"},
+{"name": "bruce gregersen"},
+{"name": "lupe alanis"},
+{"name": "andre hamby"},
+{"name": "chris rybokowski"},
+{"name": "paul goldstein"},
+{"name": "ali m"},
+{"name": "clayton varner"},
+{"name": "ben cubitt"},
+{"name": "francine hoch"},
+{"name": "josh abehsera"},
+{"name": "ashley bell"},
+{"name": "larry lashley"},
+{"name": "bruce mann"},
+{"name": "maria austen"},
+{"name": "jeff d"},
+{"name": "mary newsom"},
+{"name": "tim ackerman"},
+{"name": "josh brother"},
+{"name": "louie parker"},
+{"name": "claudia marienau"},
+{"name": "pete snavely"},
+{"name": "brian quick"},
+{"name": "micaela tucker"},
+{"name": "hugo ramirez"},
+{"name": "craig dunford"},
+{"name": "chuck frazier"},
+{"name": "brenda wagner"},
+{"name": "sue gunaca"},
+{"name": "jenny duncan"},
+{"name": "ashley brain"},
+{"name": "tasha shaka"},
+{"name": "doug berwick"},
+{"name": "mike jacobs"},
+{"name": "elmer panganiban"},
+{"name": "bob buchan"},
+{"name": "barbara kimber"},
+{"name": "alisha mathis"},
+{"name": "hank mirrow"},
+{"name": "bessie williams"},
+{"name": "gil ernst"},
+{"name": "candace werts"},
+{"name": "ginny semora"},
+{"name": "barry taylor"},
+{"name": "jim langenhan"},
+{"name": "wilson white"},
+{"name": "bernadette aganza"},
+{"name": "nancy trost"},
+{"name": "marc schmidt"},
+{"name": "autumn kay"},
+{"name": "erin porszt"},
+{"name": "daniel oscar"},
+{"name": "annie lippert"},
+{"name": "burt dubois"},
+{"name": "donna hamblin"},
+{"name": "amanda glorioso"},
+{"name": "martin muncy"},
+{"name": "paul hatchet"},
+{"name": "andrea alvis"},
+{"name": "courtney schuett"},
+{"name": "sarah howard"},
+{"name": "alicia lopez"},
+{"name": "pat r"},
+{"name": "michael cardinal"},
+{"name": "stacey laitman"},
+{"name": "annie macnee"},
+{"name": "angie ilg"},
+{"name": "jared daniels"},
+{"name": "jodi stein"},
+{"name": "albert friedrich"},
+{"name": "cathy couch"},
+{"name": "brad koons"},
+{"name": "steve verduyn"},
+{"name": "patrick severson"},
+{"name": "janice sorensen"},
+{"name": "loretta hepburn"},
+{"name": "mike zara"},
+{"name": "paul messer"},
+{"name": "ron cell"},
+{"name": "palmer md"},
+{"name": "jason pate"},
+{"name": "joe montiel"},
+{"name": "cara birmingham"},
+{"name": "lesley bailey"},
+{"name": "dan sullivan"},
+{"name": "nathan webb"},
+{"name": "michelle d"},
+{"name": "shae ehlers"},
+{"name": "sonya dunham"},
+{"name": "sarah chicago"},
+{"name": "ja ja"},
+{"name": "michelle davis"},
+{"name": "phil totman"},
+{"name": "sari grebinar"},
+{"name": "ray max"},
+{"name": "chuck kevwich"},
+{"name": "billy kuhnel"},
+{"name": "aja reign"},
+{"name": "jeff cowell"},
+{"name": "ted faust"},
+{"name": "paul harrison"},
+{"name": "nick chitwood"},
+{"name": "ana gutierrez"},
+{"name": "raymond hairston"},
+{"name": "kate mcnally"},
+{"name": "monica simmons"},
+{"name": "steve waycott"},
+{"name": "lee raback"},
+{"name": "myles webster"},
+{"name": "jeff simmons"},
+{"name": "cynthia dashnaw"},
+{"name": "christine gerschel"},
+{"name": "chris tompkins"},
+{"name": "jon roberts"},
+{"name": "lynn beggy"},
+{"name": "brandon trs"},
+{"name": "carlos marcellus"},
+{"name": "austin schultz"},
+{"name": "kristen johnson"},
+{"name": "jeff woolard"},
+{"name": "matt smalley"},
+{"name": "nikki brumback"},
+{"name": "nidia malone"},
+{"name": "stacey armstrong"},
+{"name": "kathy wagener"},
+{"name": "scott sterne"},
+{"name": "brian bos"},
+{"name": "alison paulson"},
+{"name": "jay luebbe"},
+{"name": "brian isaac"},
+{"name": "pat perry"},
+{"name": "leslie bravo"},
+{"name": "jerry o"},
+{"name": "trish merlo"},
+{"name": "leonard ridilla"},
+{"name": "barry petrowsky"},
+{"name": "john sampuer"},
+{"name": "larry edwards"},
+{"name": "jon lawson"},
+{"name": "amy moiser"},
+{"name": "linda goodwin"},
+{"name": "matt porter"},
+{"name": "dan leyson"},
+{"name": "nancy denning"},
+{"name": "jerry raby"},
+{"name": "michael lew"},
+{"name": "jeffrey birth"},
+{"name": "austin kiser"},
+{"name": "steve wallace"},
+{"name": "andrew cate"},
+{"name": "ryan carter"},
+{"name": "john jenkins"},
+{"name": "carrie corcoran"},
+{"name": "laura brown"},
+{"name": "brian wood"},
+{"name": "elizabeth adomaitis"},
+{"name": "eric love"},
+{"name": "bob buckley"},
+{"name": "katie groshong"},
+{"name": "michael stork"},
+{"name": "ana guajardo"},
+{"name": "travis fox"},
+{"name": "christian lecates"},
+{"name": "yvonne littlejohn"},
+{"name": "steve wigginton"},
+{"name": "greg busch"},
+{"name": "breana lixey"},
+{"name": "amy mononi"},
+{"name": "robin kurkhill"},
+{"name": "albert ng"},
+{"name": "brian stall"},
+{"name": "tessa conners"},
+{"name": "dennis hackett"},
+{"name": "anna steg"},
+{"name": "maureen joyce"},
+{"name": "patsy newman"},
+{"name": "ryan kim"},
+{"name": "john g's"},
+{"name": "rhonda miller"},
+{"name": "jamie sudbeck"},
+{"name": "rana chaudhuri"},
+{"name": "allen sparks"},
+{"name": "monica straus"},
+{"name": "manual review"},
+{"name": "trey lewis"},
+{"name": "nona shepperd"},
+{"name": "cynthia carlton"},
+{"name": "laura legrande"},
+{"name": "bob newlands"},
+{"name": "bill frezza"},
+{"name": "lee mitsumori"},
+{"name": "christopher bopp"},
+{"name": "jeff kreiter"},
+{"name": "valerie hab"},
+{"name": "ariel markus"},
+{"name": "dan drumer"},
+{"name": "robert pitelka"},
+{"name": "janet campos"},
+{"name": "kimberly young"},
+{"name": "henry palazzo"},
+{"name": "mike pappas"},
+{"name": "nikki w"},
+{"name": "danny foods"},
+{"name": "jane riley"},
+{"name": "sharon lockwood"},
+{"name": "kim hermann"},
+{"name": "rick sanford"},
+{"name": "kristy laird"},
+{"name": "kevin ambrosini"},
+{"name": "ryan neuharth"},
+{"name": "otto lee"},
+{"name": "ron wingert"},
+{"name": "jasmine green"},
+{"name": "jeremy shirley"},
+{"name": "archie rabinowitz"},
+{"name": "joe west"},
+{"name": "jeff courtney"},
+{"name": "george cooney"},
+{"name": "katy productions"},
+{"name": "teresa french"},
+{"name": "george stahlin"},
+{"name": "susanne meno"},
+{"name": "patricia geil"},
+{"name": "dan doerner"},
+{"name": "taylor c"},
+{"name": "dan bryant"},
+{"name": "greg toal"},
+{"name": "jimmie purkey"},
+{"name": "jorge wimbley"},
+{"name": "sonya haggerty"},
+{"name": "will aldridge"},
+{"name": "chuck tam"},
+{"name": "greg farmer"},
+{"name": "megan pickler"},
+{"name": "judy jarmulr"},
+{"name": "steve jenks"},
+{"name": "bill rayborn"},
+{"name": "brent smith"},
+{"name": "joanna gaylord"},
+{"name": "laura grimmer"},
+{"name": "rebecca whitehead"},
+{"name": "michael seiler"},
+{"name": "mike cheatwood"},
+{"name": "greg kraus"},
+{"name": "audrey bar"},
+{"name": "mark furman"},
+{"name": "danny berkovits"},
+{"name": "brent wallin"},
+{"name": "judy torres"},
+{"name": "avis haddad"},
+{"name": "frankie work"},
+{"name": "brent reed"},
+{"name": "dora lucas"},
+{"name": "sharon niestorm"},
+{"name": "beau pierce"},
+{"name": "lara naruszewicz"},
+{"name": "allyson whitlock"},
+{"name": "stan plocker"},
+{"name": "daniel lindsey"},
+{"name": "sean morris"},
+{"name": "tim martonick"},
+{"name": "david fujimoto"},
+{"name": "cherise comstock"},
+{"name": "tom olvera"},
+{"name": "noel diaz"},
+{"name": "tom shifflet"},
+{"name": "david gipner"},
+{"name": "michele v"},
+{"name": "mike kuelbs"},
+{"name": "carol lotz"},
+{"name": "jordan nicholson"},
+{"name": "rita eckard"},
+{"name": "jessica marta"},
+{"name": "chi town"},
+{"name": "morgan chayer"},
+{"name": "tuan nhuyen"},
+{"name": "tony gilder"},
+{"name": "steve strange"},
+{"name": "howard burd"},
+{"name": "jose cuzo"},
+{"name": "sarah hancharik"},
+{"name": "jen dainels"},
+{"name": "jarred shalom"},
+{"name": "matt sitz"},
+{"name": "bill mcloughlin"},
+{"name": "katie livermore"},
+{"name": "donna branston"},
+{"name": "adriane wodey"},
+{"name": "mark mccool"},
+{"name": "kathy maalouf"},
+{"name": "kevin tschudi"},
+{"name": "young hospital"},
+{"name": "mike jr"},
+{"name": "devin knight"},
+{"name": "mindi w"},
+{"name": "jerrie edwards"},
+{"name": "stephanie bowen"},
+{"name": "tori bauer"},
+{"name": "laureen dawson"},
+{"name": "neil desimone"},
+{"name": "stephen edwards"},
+{"name": "jeff tao"},
+{"name": "eileen thurow"},
+{"name": "anna carter"},
+{"name": "ginger wisniewski"},
+{"name": "carol eckstrom"},
+{"name": "john fitzpatrick"},
+{"name": "steve hope"},
+{"name": "rosie logistic"},
+{"name": "greg sterling"},
+{"name": "josie david"},
+{"name": "jo belair"},
+{"name": "jake olin"},
+{"name": "shelly metje"},
+{"name": "corey olsen"},
+{"name": "fred moss"},
+{"name": "craig littlejohn"},
+{"name": "richie newman"},
+{"name": "jon labes"},
+{"name": "flo master"},
+{"name": "wesley phongsa"},
+{"name": "dean ford"},
+{"name": "brian saliba"},
+{"name": "barb friedman"},
+{"name": "lou larres"},
+{"name": "sarah boek"},
+{"name": "kenny anderson"},
+{"name": "alex ebc"},
+{"name": "tim kupetz"},
+{"name": "evan bumgardner"},
+{"name": "joe moran"},
+{"name": "kurt radkee"},
+{"name": "long hcm"},
+{"name": "catherine stokes"},
+{"name": "may chazez"},
+{"name": "sean franklin"},
+{"name": "barb berlyak"},
+{"name": "diego vanegas"},
+{"name": "carolyn barnett"},
+{"name": "david zimmerman"},
+{"name": "penny buffington"},
+{"name": "mira rinne"},
+{"name": "lucas nwaobi"},
+{"name": "joshua katz"},
+{"name": "garret d'ottavio"},
+{"name": "trinidad chacara"},
+{"name": "ellen chayet"},
+{"name": "nicola lacetera"},
+{"name": "jack beem"},
+{"name": "terry ocheltree"},
+{"name": "matt stoderd"},
+{"name": "jessie woman"},
+{"name": "delbert singleton"},
+{"name": "jay rolfson"},
+{"name": "hollie crowley"},
+{"name": "mark softball"},
+{"name": "nancy gust"},
+{"name": "jennifer estaris"},
+{"name": "karina fajardo"},
+{"name": "chuck lane"},
+{"name": "michelle carney"},
+{"name": "charlotte ruggeri"},
+{"name": "joey dunagan"},
+{"name": "susan wyllie"},
+{"name": "nichole tolliver"},
+{"name": "rosa kirkland"},
+{"name": "steve gcs"},
+{"name": "hope mathews"},
+{"name": "stephen socolof"},
+{"name": "andrew lin"},
+{"name": "brandon dunn"},
+{"name": "ruby n"},
+{"name": "josh taylor"},
+{"name": "ann therapist"},
+{"name": "tim fortier"},
+{"name": "jay graham"},
+{"name": "chris az"},
+{"name": "eli burkman"},
+{"name": "brooks finlinson"},
+{"name": "marianne gaviola"},
+{"name": "teri kim"},
+{"name": "paul ibmtle"},
+{"name": "karen ganguet"},
+{"name": "justin simo"},
+{"name": "stephanie klev"},
+{"name": "everett sargent"},
+{"name": "jeremy bloom"},
+{"name": "matt booth"},
+{"name": "andrea emery"},
+{"name": "brenda rideout"},
+{"name": "christina glass"},
+{"name": "cindy caditz"},
+{"name": "cesar arapahoe"},
+{"name": "laura golay"},
+{"name": "ron underwood"},
+{"name": "teresa kitchens"},
+{"name": "robert leal"},
+{"name": "ed dilworth"},
+{"name": "jay olson"},
+{"name": "steve knese"},
+{"name": "charley ebersall"},
+{"name": "glen williams"},
+{"name": "pat zohab"},
+{"name": "jim tivo"},
+{"name": "valerie shea"},
+{"name": "phillip dothedamnthang"},
+{"name": "kurt walker"},
+{"name": "lisa benton"},
+{"name": "matt cambell"},
+{"name": "cathy gallagher"},
+{"name": "garrett wagner"},
+{"name": "dave albright"},
+{"name": "alyssa bull"},
+{"name": "susan ady"},
+{"name": "jenny v"},
+{"name": "john boron"},
+{"name": "carter hendren"},
+{"name": "bill strass"},
+{"name": "gayle hage"},
+{"name": "ed alachniewicz"},
+{"name": "jimmy blake"},
+{"name": "larry kelner"},
+{"name": "deanna fletcher"},
+{"name": "jeffrey wright"},
+{"name": "angel jones"},
+{"name": "karina mendez"},
+{"name": "ilse joubert"},
+{"name": "tony vinyl"},
+{"name": "chase hinrich"},
+{"name": "judy wk"},
+{"name": "jackson star"},
+{"name": "cheryl bloom"},
+{"name": "audrey king"},
+{"name": "albert lo"},
+{"name": "deandre young"},
+{"name": "ben finney"},
+{"name": "carole winberg"},
+{"name": "kelly freemyer"},
+{"name": "melissa rash"},
+{"name": "dave russell"},
+{"name": "brian newman"},
+{"name": "winston king"},
+{"name": "todd ames"},
+{"name": "syreeta cysj"},
+{"name": "eric laurits"},
+{"name": "clarisa cell"},
+{"name": "simon rendak"},
+{"name": "pa pa"},
+{"name": "julian cell"},
+{"name": "lois segree"},
+{"name": "fiona walker"},
+{"name": "tony gobo"},
+{"name": "shannon o'neal"},
+{"name": "kim wilkens"},
+{"name": "tommy garcia"},
+{"name": "lili benjumea"},
+{"name": "chris sumner"},
+{"name": "craig forist"},
+{"name": "karla powelson"},
+{"name": "eric bonini"},
+{"name": "victoria martinez"},
+{"name": "charles drummer"},
+{"name": "anthony parker"},
+{"name": "dianna locke"},
+{"name": "patsy ebert"},
+{"name": "robert mann"},
+{"name": "mark mcclure"},
+{"name": "kristy johnson"},
+{"name": "erik hazen"},
+{"name": "trent cokley"},
+{"name": "marcus guynn"},
+{"name": "vernon peters"},
+{"name": "guy rinderknecht"},
+{"name": "tammy madsen"},
+{"name": "michael iceburg"},
+{"name": "john ducket"},
+{"name": "danielle garcia"},
+{"name": "brian park"},
+{"name": "lucy figueras"},
+{"name": "lauren green"},
+{"name": "kendall downing"},
+{"name": "herman depriest"},
+{"name": "samuel waller"},
+{"name": "christa orndoff"},
+{"name": "tyler mutchler"},
+{"name": "randall ziman"},
+{"name": "yvette allen"},
+{"name": "frank wingfield"},
+{"name": "john fortunato"},
+{"name": "rob stagliano"},
+{"name": "melissa diekema"},
+{"name": "james vail"},
+{"name": "chris mohrman"},
+{"name": "joey morales"},
+{"name": "john cp"},
+{"name": "angel monguziji"},
+{"name": "jean hatfield"},
+{"name": "linda ruggiere"},
+{"name": "eric perez"},
+{"name": "lawrence medina"},
+{"name": "tom rock"},
+{"name": "sergio ramos"},
+{"name": "lee byrd"},
+{"name": "leanna morag"},
+{"name": "nathan cell"},
+{"name": "stephen kozub"},
+{"name": "gerri fields"},
+{"name": "ebony j"},
+{"name": "greg honegger"},
+{"name": "mary gresko"},
+{"name": "michael stewart"},
+{"name": "codi dapper"},
+{"name": "amy aspseter"},
+{"name": "adina verson"},
+{"name": "david heche"},
+{"name": "dorothy chimel"},
+{"name": "bob schneider"},
+{"name": "tim broder"},
+{"name": "tom chaney"},
+{"name": "joan canonigo"},
+{"name": "ron derose"},
+{"name": "harold bordwin"},
+{"name": "kristy crab"},
+{"name": "kathryn gutierrez"},
+{"name": "kelli hopper"},
+{"name": "dan riahani"},
+{"name": "kate brett"},
+{"name": "jason adams"},
+{"name": "steve walters"},
+{"name": "laura lamm"},
+{"name": "john gingery"},
+{"name": "bert culha"},
+{"name": "jake david"},
+{"name": "carrie home"},
+{"name": "brittany g"},
+{"name": "glen bandiera"},
+{"name": "andrea wilcox"},
+{"name": "janeen hoffos"},
+{"name": "riley courtright"},
+{"name": "chris mccormick"},
+{"name": "rich bands"},
+{"name": "kelly swiatek"},
+{"name": "marilyn berson"},
+{"name": "eva flanagan"},
+{"name": "linda woodfield"},
+{"name": "hilary sundance"},
+{"name": "gary nova"},
+{"name": "dina matz"},
+{"name": "jessica iacono"},
+{"name": "scott co"},
+{"name": "mike sabo"},
+{"name": "mary singh"},
+{"name": "teri hartley"},
+{"name": "johnny wright"},
+{"name": "brandie boden"},
+{"name": "alex adolfi"},
+{"name": "brandon underwood"},
+{"name": "lauren petersen"},
+{"name": "jack borg"},
+{"name": "hazel boyd"},
+{"name": "craig waltman"},
+{"name": "steve nowlis"},
+{"name": "jason bridges"},
+{"name": "chris cupler"},
+{"name": "daniel sastic"},
+{"name": "tony volpone"},
+{"name": "andy shelton"},
+{"name": "gloria zuniga"},
+{"name": "mike delaney"},
+{"name": "nancy allen"},
+{"name": "jeane helms"},
+{"name": "casey mcginley"},
+{"name": "steven house"},
+{"name": "matthew m"},
+{"name": "stephanie anzures"},
+{"name": "vicente niece"},
+{"name": "jeff thelen"},
+{"name": "chris wheeler"},
+{"name": "ericka flowers"},
+{"name": "eddie stew"},
+{"name": "carol jean"},
+{"name": "christopher chen"},
+{"name": "simon lawler"},
+{"name": "jon smp"},
+{"name": "jerome cohen"},
+{"name": "reyes c"},
+{"name": "cindy hause"},
+{"name": "grant cunningham"},
+{"name": "david bressoud"},
+{"name": "patrick mccloskey"},
+{"name": "jay hickey"},
+{"name": "grace academy"},
+{"name": "michael gwilliam"},
+{"name": "alex j"},
+{"name": "matt mcauley"},
+{"name": "betsy cuthbertson"},
+{"name": "mary kelly"},
+{"name": "sasha cocron"},
+{"name": "christina sawwrii"},
+{"name": "dave burk"},
+{"name": "stanley morais"},
+{"name": "brady kent"},
+{"name": "mike kazakevitch"},
+{"name": "andrea andersen"},
+{"name": "jessica maranon"},
+{"name": "michael robl"},
+{"name": "peg andrew"},
+{"name": "angie stephen"},
+{"name": "chris vandenover"},
+{"name": "shirley weber"},
+{"name": "robin gomez"},
+{"name": "sarah ryan"},
+{"name": "andy koch"},
+{"name": "ben ballhorn"},
+{"name": "kevin glalway"},
+{"name": "kathie shaw"},
+{"name": "dana h"},
+{"name": "al caesar"},
+{"name": "judy wells"},
+{"name": "annie boswell"},
+{"name": "rich fernie"},
+{"name": "marcus french"},
+{"name": "kelly c"},
+{"name": "jeanne balmes"},
+{"name": "alice ny"},
+{"name": "darlene wright"},
+{"name": "ellie anderson"},
+{"name": "marty white"},
+{"name": "wayne henderson"},
+{"name": "don fritsch"},
+{"name": "james thue"},
+{"name": "ingrid harrison"},
+{"name": "lou malinatti's"},
+{"name": "nicky water"},
+{"name": "melanie burchard"},
+{"name": "sandy souderlund"},
+{"name": "sunshine davenport"},
+{"name": "dan keiser"},
+{"name": "rachel sear"},
+{"name": "wm payroll"},
+{"name": "kelvin frances"},
+{"name": "christine sunglass"},
+{"name": "pete aldassy"},
+{"name": "emily quinn"},
+{"name": "jeremy wing"},
+{"name": "sydney liptak"},
+{"name": "benjamin sheffner"},
+{"name": "kelly fogurty"},
+{"name": "kay hartman"},
+{"name": "tara hibbler"},
+{"name": "paul rehac"},
+{"name": "john bailey"},
+{"name": "kimberly klinke"},
+{"name": "alexis truax"},
+{"name": "lacey bray"},
+{"name": "karen horzen"},
+{"name": "scott nicholls"},
+{"name": "dave hayhurst"},
+{"name": "mike york"},
+{"name": "sarah phillips"},
+{"name": "kevin cederberg"},
+{"name": "greg orwoll"},
+{"name": "rick dickson"},
+{"name": "andrew drebit"},
+{"name": "forrest keeler"},
+{"name": "gregg martinez"},
+{"name": "jessica schnell"},
+{"name": "scotty barton"},
+{"name": "ann axtell"},
+{"name": "marilu magana"},
+{"name": "patti dean"},
+{"name": "john massaro"},
+{"name": "keith hupp"},
+{"name": "jorge diaz"},
+{"name": "holly firehouse"},
+{"name": "ricardo thomas"},
+{"name": "domenic pannaccio"},
+{"name": "michael hussain"},
+{"name": "william gutz"},
+{"name": "lee delmore"},
+{"name": "shanna habich"},
+{"name": "mark schneider"},
+{"name": "mike john"},
+{"name": "josh borstein"},
+{"name": "dean heubregste"},
+{"name": "brian pitson"},
+{"name": "sara broome"},
+{"name": "stefan buetow"},
+{"name": "shelby dad"},
+{"name": "rosalind holland"},
+{"name": "wade willis"},
+{"name": "deann takkinen"},
+{"name": "scott grif"},
+{"name": "brian kocher"},
+{"name": "mike tufts"},
+{"name": "mike rouch"},
+{"name": "martin wilson"},
+{"name": "robert alonzo"},
+{"name": "ken stellon"},
+{"name": "jerry jacobson"},
+{"name": "david defino"},
+{"name": "leila brauner"},
+{"name": "deborah sleeman"},
+{"name": "marlene theissen"},
+{"name": "guy chadrash"},
+{"name": "morgan payne"},
+{"name": "lee renzin"},
+{"name": "michael griffin"},
+{"name": "dan calgary"},
+{"name": "josh card"},
+{"name": "lindsay scottoline"},
+{"name": "adrienne erlick"},
+{"name": "jacob borton"},
+{"name": "dennis dumadag"},
+{"name": "mathew mekhayel"},
+{"name": "kristina mcdermott"},
+{"name": "alexander dunlap"},
+{"name": "connie kim"},
+{"name": "denise short"},
+{"name": "brian ct"},
+{"name": "al kay"},
+{"name": "george d'elia"},
+{"name": "earl morrison"},
+{"name": "dan heronemus"},
+{"name": "mark pelson"},
+{"name": "terrie thomas"},
+{"name": "jim minton"},
+{"name": "margot mcleod"},
+{"name": "tim krause"},
+{"name": "joe smith"},
+{"name": "cornelia cont"},
+{"name": "cathrine baker"},
+{"name": "bruce alexander"},
+{"name": "jackie stephens"},
+{"name": "john behlmann"},
+{"name": "josh salazar"},
+{"name": "joe bernhadt"},
+{"name": "kaitlyn nielson"},
+{"name": "amanda konc"},
+{"name": "tracy steiberger"},
+{"name": "cliff talley"},
+{"name": "chris roth"},
+{"name": "cary jan"},
+{"name": "josh brickford"},
+{"name": "dave gartner"},
+{"name": "kate work"},
+{"name": "lori dalton"},
+{"name": "christiane heyde"},
+{"name": "neil richey"},
+{"name": "mike kellman"},
+{"name": "tim bledsoe"},
+{"name": "cris hineline"},
+{"name": "fred rico"},
+{"name": "sara perez"},
+{"name": "max carlson"},
+{"name": "eric hendrickson"},
+{"name": "myra holmes"},
+{"name": "steve darnold"},
+{"name": "willie simmons"},
+{"name": "peter avellone"},
+{"name": "cathy white"},
+{"name": "sara edwards"},
+{"name": "christina phan"},
+{"name": "dustin grantham"},
+{"name": "luis garcia"},
+{"name": "carol richards"},
+{"name": "mark salisbery"},
+{"name": "alan napack"},
+{"name": "bob macnelly"},
+{"name": "steve sakoman"},
+{"name": "ronald walker"},
+{"name": "les busfield"},
+{"name": "eric ayten"},
+{"name": "ashley f"},
+{"name": "patrick pradia"},
+{"name": "mike braun"},
+{"name": "john tomaszewski"},
+{"name": "joseph cell"},
+{"name": "carrie lazorchak"},
+{"name": "jim tatum"},
+{"name": "phil black"},
+{"name": "nikki sifri"},
+{"name": "bo porter"},
+{"name": "steven meskin"},
+{"name": "mike mcguiness"},
+{"name": "rachel t"},
+{"name": "michelle derda"},
+{"name": "jane edmondson"},
+{"name": "meg evat"},
+{"name": "kate davelaar"},
+{"name": "travis arnold"},
+{"name": "michelle tillery"},
+{"name": "lucy giannelli"},
+{"name": "james trummer"},
+{"name": "jon quinn"},
+{"name": "joyce oliver"},
+{"name": "david evans"},
+{"name": "stephen novack"},
+{"name": "phillip eichner"},
+{"name": "dennis istre"},
+{"name": "dottie smith"},
+{"name": "derek zaba"},
+{"name": "hung home"},
+{"name": "mitch boyer"},
+{"name": "wayne lacourse"},
+{"name": "ann murray"},
+{"name": "al stevens"},
+{"name": "amanda ghourdjian"},
+{"name": "michael hardin"},
+{"name": "brandy maddox"},
+{"name": "austin roskamp"},
+{"name": "janeen segar"},
+{"name": "mechelle miller"},
+{"name": "jim weathers"},
+{"name": "lauren t"},
+{"name": "murray norris"},
+{"name": "sam gabbita"},
+{"name": "laura hevesi"},
+{"name": "michelle v"},
+{"name": "rob shaddock"},
+{"name": "pam johnston"},
+{"name": "mike tom"},
+{"name": "dan l"},
+{"name": "mike blanford"},
+{"name": "tom g"},
+{"name": "dean hill"},
+{"name": "david nevin"},
+{"name": "morgan seachris"},
+{"name": "forrest moye"},
+{"name": "kristin durant"},
+{"name": "audrey henderson"},
+{"name": "darrin homer"},
+{"name": "steven feys"},
+{"name": "courtney welsch"},
+{"name": "jean arseneau"},
+{"name": "howard lando"},
+{"name": "dale kline"},
+{"name": "luis southdade"},
+{"name": "melissa frank"},
+{"name": "robert collins"},
+{"name": "franklin moore"},
+{"name": "robert reinders"},
+{"name": "toni smith"},
+{"name": "phillip t"},
+{"name": "gail barker"},
+{"name": "eric gillespie"},
+{"name": "jesus figueroa"},
+{"name": "kimberly chiem"},
+{"name": "liz barsom"},
+{"name": "john colwell"},
+{"name": "craig king"},
+{"name": "martin ferguson"},
+{"name": "larry schmit"},
+{"name": "nicole pimentel"},
+{"name": "sharon marsh"},
+{"name": "greg finley"},
+{"name": "sandra gonzales"},
+{"name": "lee selmon"},
+{"name": "maria ezechukwu"},
+{"name": "timmy falke"},
+{"name": "bridget penrod"},
+{"name": "bob arnold"},
+{"name": "mary ockender"},
+{"name": "michelle helmer"},
+{"name": "amber c"},
+{"name": "tim dolan"},
+{"name": "robert cronholm"},
+{"name": "judy haack"},
+{"name": "richard yoo"},
+{"name": "mark venuti"},
+{"name": "brittney n"},
+{"name": "dianne rutledge"},
+{"name": "jeffrey fuller"},
+{"name": "jill baker"},
+{"name": "louis athanaselos"},
+{"name": "ken ball"},
+{"name": "john bresnahan"},
+{"name": "willie work"},
+{"name": "brad shreve"},
+{"name": "denise laguna"},
+{"name": "kathy vanveckoven"},
+{"name": "jo clean"},
+{"name": "stan owner"},
+{"name": "brian pounds"},
+{"name": "david yacoub"},
+{"name": "rob ellis"},
+{"name": "shawn herrick"},
+{"name": "michelle oh"},
+{"name": "steve yoo"},
+{"name": "ron skoglund"},
+{"name": "daniela bazo"},
+{"name": "mark irish"},
+{"name": "dana tattoos"},
+{"name": "mike palm"},
+{"name": "katherine skylar"},
+{"name": "brooks jill"},
+{"name": "michelle n"},
+{"name": "jo casper"},
+{"name": "wesley lewis"},
+{"name": "chloe boissonnault"},
+{"name": "wilson taylor"},
+{"name": "christina sirotta"},
+{"name": "oliver chris"},
+{"name": "jack milunsky"},
+{"name": "mark kornak"},
+{"name": "sarah radke"},
+{"name": "mike haley"},
+{"name": "daryl leazier"},
+{"name": "debra scott"},
+{"name": "benjamin lee"},
+{"name": "julie boucutt"},
+{"name": "larry harris"},
+{"name": "bonnie quarles"},
+{"name": "sylvester spa"},
+{"name": "brent hawes"},
+{"name": "kasey garthwaite"},
+{"name": "matt hubers"},
+{"name": "dick porto"},
+{"name": "leon zelechowski"},
+{"name": "ava bar"},
+{"name": "chris goff"},
+{"name": "coleman powersport"},
+{"name": "phil swift"},
+{"name": "melanie salas"},
+{"name": "wayne mangrum"},
+{"name": "shelby hboy"},
+{"name": "antonio hesano"},
+{"name": "drew milam"},
+{"name": "mi mama"},
+{"name": "matthew li"},
+{"name": "ariel weissberg"},
+{"name": "matt bloom"},
+{"name": "barbie calva"},
+{"name": "chuck esguerra"},
+{"name": "beverly bond"},
+{"name": "dominque nsba"},
+{"name": "erin wolken"},
+{"name": "graham kyle"},
+{"name": "bill yoon"},
+{"name": "larry cell"},
+{"name": "mark webb"},
+{"name": "linda randolph"},
+{"name": "nick weast"},
+{"name": "dwight aaron"},
+{"name": "dolores furtado"},
+{"name": "matthew day"},
+{"name": "felicia sigler"},
+{"name": "michelle moser"},
+{"name": "jann sheehy"},
+{"name": "dean atkinson"},
+{"name": "linda zidek"},
+{"name": "yolanda ramsey"},
+{"name": "sarah strout"},
+{"name": "diane walewski"},
+{"name": "linda joseph"},
+{"name": "reggie hyde"},
+{"name": "mike nicholas"},
+{"name": "edmund lara"},
+{"name": "angela swain"},
+{"name": "gabriella leonarid"},
+{"name": "aaron pope"},
+{"name": "jasmine serrano"},
+{"name": "larry santos"},
+{"name": "bonnie miller"},
+{"name": "alex ayers"},
+{"name": "brett ottawa"},
+{"name": "michael rocca"},
+{"name": "kyle harrison"},
+{"name": "king engel"},
+{"name": "art reed"},
+{"name": "karl schmidt"},
+{"name": "david farrar"},
+{"name": "tony north"},
+{"name": "jim melia"},
+{"name": "lance bryant"},
+{"name": "mark mocilan"},
+{"name": "ron buckhammer"},
+{"name": "chris airgas"},
+{"name": "george klotz"},
+{"name": "mary cs"},
+{"name": "tim collins"},
+{"name": "van quathem"},
+{"name": "derek worden"},
+{"name": "katie metzger"},
+{"name": "dan keen"},
+{"name": "henry hopkins"},
+{"name": "derrick garder"},
+{"name": "alberto rhenals"},
+{"name": "jason doren"},
+{"name": "tim crochet"},
+{"name": "allen kaye"},
+{"name": "william kovalchuk"},
+{"name": "shaun devine"},
+{"name": "bobbi west"},
+{"name": "omar cambo"},
+{"name": "brad seward"},
+{"name": "jeff mann"},
+{"name": "wendy dean"},
+{"name": "arlene siver"},
+{"name": "randall hutchings"},
+{"name": "kris aoki"},
+{"name": "joan streefkerk"},
+{"name": "jeffrey buckley"},
+{"name": "ana elizondo"},
+{"name": "bill carter"},
+{"name": "denice scott"},
+{"name": "debbie cregger"},
+{"name": "kristin troy"},
+{"name": "charles eric"},
+{"name": "charles vacarella"},
+{"name": "todd niemeyer"},
+{"name": "paul beyl"},
+{"name": "billy kirkby"},
+{"name": "josh hillary"},
+{"name": "luke pridgeon"},
+{"name": "colin cowboy"},
+{"name": "sharon hakimifefat"},
+{"name": "janey teacups"},
+{"name": "todd mack"},
+{"name": "deidra solomon"},
+{"name": "jerome harrington"},
+{"name": "james kushnerick"},
+{"name": "vera davis"},
+{"name": "ed babbie"},
+{"name": "tommy vose"},
+{"name": "rosa mcaurther"},
+{"name": "tom seiler"},
+{"name": "monty schilling"},
+{"name": "sara hutchinson"},
+{"name": "troy gilmore"},
+{"name": "bob urosevic"},
+{"name": "scott valois"},
+{"name": "eric vasqauls"},
+{"name": "mike tancsa"},
+{"name": "trista milanovich"},
+{"name": "barrett somdahl"},
+{"name": "christine guerra"},
+{"name": "rick deckbar"},
+{"name": "alan rothman"},
+{"name": "jennifer tanner"},
+{"name": "kelly knox"},
+{"name": "john brune"},
+{"name": "josh culumber"},
+{"name": "nathan garrison"},
+{"name": "karen sachs"},
+{"name": "paula ransom"},
+{"name": "andy stavro"},
+{"name": "andrew larrier"},
+{"name": "danielle burke"},
+{"name": "chris prock"},
+{"name": "gail mikel"},
+{"name": "samira panah"},
+{"name": "charlotte bobcats"},
+{"name": "david edwards"},
+{"name": "jim passey"},
+{"name": "terry magnunsun"},
+{"name": "tia rachel"},
+{"name": "kyle mclain"},
+{"name": "vince party"},
+{"name": "daryl redar"},
+{"name": "martha bodine"},
+{"name": "steven bellus"},
+{"name": "peter langbord"},
+{"name": "rebecca higgins"},
+{"name": "chris oboe"},
+{"name": "sara fletcher"},
+{"name": "michele goyette"},
+{"name": "brandon cracraft"},
+{"name": "denise bray"},
+{"name": "phillip petite"},
+{"name": "lynn kanakry"},
+{"name": "tom donovan"},
+{"name": "angela meadows"},
+{"name": "fred myrick"},
+{"name": "david moir"},
+{"name": "eric dremel"},
+{"name": "eric johanson"},
+{"name": "shawn austin"},
+{"name": "nick bilby"},
+{"name": "chris martinez"},
+{"name": "kathy south"},
+{"name": "rodney lui"},
+{"name": "donna leclerc"},
+{"name": "chris tandy"},
+{"name": "teri epper"},
+{"name": "bennett caren"},
+{"name": "keith montgomery"},
+{"name": "luis alba"},
+{"name": "marc jasso"},
+{"name": "timothy chi"},
+{"name": "jessie richard"},
+{"name": "austin walker"},
+{"name": "lori grudzien"},
+{"name": "sarah gruetze"},
+{"name": "floyd adams"},
+{"name": "dustin cell"},
+{"name": "john cappelletty"},
+{"name": "jeffrey star"},
+{"name": "leigh grossman"},
+{"name": "victor biscochito"},
+{"name": "jessica vanhord"},
+{"name": "melanie hastings"},
+{"name": "philip crown"},
+{"name": "matt warner"},
+{"name": "isaias guadarrama"},
+{"name": "dora borjas"},
+{"name": "kevin doud"},
+{"name": "jerry blueford"},
+{"name": "bobby buchalski"},
+{"name": "rob work"},
+{"name": "brittany hahn"},
+{"name": "genie soft"},
+{"name": "kyle elite"},
+{"name": "nick forde"},
+{"name": "joey callahan"},
+{"name": "melody metcalf"},
+{"name": "jon chang"},
+{"name": "justin taylor"},
+{"name": "eric cantele"},
+{"name": "susan lage"},
+{"name": "byron thompson"},
+{"name": "blake weirdo"},
+{"name": "dave mate"},
+{"name": "carl loodberg"},
+{"name": "lauren dillion"},
+{"name": "susan masten"},
+{"name": "ryan perkins"},
+{"name": "adam bowe"},
+{"name": "jim meetup"},
+{"name": "pauline hensley"},
+{"name": "peter swiderski"},
+{"name": "sammy lautenschlager"},
+{"name": "levi koch"},
+{"name": "nancy lopez"},
+{"name": "betsy hills"},
+{"name": "sara twin"},
+{"name": "matt hann"},
+{"name": "dave gonzalez"},
+{"name": "matt woodman"},
+{"name": "corey thomas"},
+{"name": "george munguia"},
+{"name": "bonnie yiu"},
+{"name": "terrance daye"},
+{"name": "christine nabisco"},
+{"name": "kelly decou"},
+{"name": "chad bongiovanni"},
+{"name": "jackie kelly"},
+{"name": "tara werger"},
+{"name": "tim youngard"},
+{"name": "barbara tuset"},
+{"name": "hal stephens"},
+{"name": "art zamora"},
+{"name": "todd welygan"},
+{"name": "kristen egan"},
+{"name": "eric albright"},
+{"name": "lois miskin"},
+{"name": "mike belt"},
+{"name": "evan rogers"},
+{"name": "brad letourneau"},
+{"name": "jay bojan"},
+{"name": "erin martin"},
+{"name": "thomas stephens"},
+{"name": "rob clegg"},
+{"name": "debbie ho"},
+{"name": "jennifer dalton"},
+{"name": "john doe"},
+{"name": "ray fung"},
+{"name": "phillip ybarrolaza"},
+{"name": "peter wriede"},
+{"name": "dave greer"},
+{"name": "robin cell"},
+{"name": "mike hoak"},
+{"name": "cheryl brackett"},
+{"name": "pat xxxx"},
+{"name": "matt connors"},
+{"name": "samuel tyszler"},
+{"name": "brad stepst"},
+{"name": "drew edmunds"},
+{"name": "linda beckham"},
+{"name": "pam neeley"},
+{"name": "courtney pittler"},
+{"name": "rafael valdez"},
+{"name": "kayla schober"},
+{"name": "carrie gottschalk"},
+{"name": "danny hockenberger"},
+{"name": "kara mendoza"},
+{"name": "rob scruftattmuscc"},
+{"name": "harold calkins"},
+{"name": "jeff ahern"},
+{"name": "jennifer killian"},
+{"name": "sean luna"},
+{"name": "sally yesian"},
+{"name": "ashley binkley"},
+{"name": "margaret mcgarry"},
+{"name": "diane williams"},
+{"name": "amanda jones"},
+{"name": "angie leatherwood"},
+{"name": "richard west"},
+{"name": "alex wardencki"},
+{"name": "lou kraemer"},
+{"name": "tom clarke"},
+{"name": "mauricio jimenez"},
+{"name": "sean mcnally"},
+{"name": "lauren h"},
+{"name": "joe directtv"},
+{"name": "stephanie renolds"},
+{"name": "tim maritzis"},
+{"name": "bob doherty"},
+{"name": "tori white"},
+{"name": "gene social"},
+{"name": "tim arnold"},
+{"name": "luke martin"},
+{"name": "james gildon"},
+{"name": "joe kesting"},
+{"name": "john two"},
+{"name": "yasmin rivera"},
+{"name": "joel klepal"},
+{"name": "joanne baker"},
+{"name": "javier abrego"},
+{"name": "liz buckley"},
+{"name": "courtney kinne"},
+{"name": "daniella mcchesney"},
+{"name": "delilah m"},
+{"name": "myrtle beach"},
+{"name": "scott hibner"},
+{"name": "betty chiu"},
+{"name": "jose cop"},
+{"name": "arnold wirick"},
+{"name": "tony battaglia"},
+{"name": "barbara lagazzele"},
+{"name": "patrick barry"},
+{"name": "kevin corio"},
+{"name": "terri desilva"},
+{"name": "rick modem"},
+{"name": "jason huso"},
+{"name": "charles cameron"},
+{"name": "jeff k"},
+{"name": "stacey baptista"},
+{"name": "ashley pfeifer"},
+{"name": "mary garcia"},
+{"name": "sam kasn"},
+{"name": "joe nava"},
+{"name": "andrew housley"},
+{"name": "mark zamuner"},
+{"name": "carol defrance"},
+{"name": "karen campbell"},
+{"name": "michelle arrant"},
+{"name": "donald fast"},
+{"name": "paul torres"},
+{"name": "jared green"},
+{"name": "hunter lots"},
+{"name": "todd rogers"},
+{"name": "dylan ireland"},
+{"name": "kerri brown"},
+{"name": "david kates"},
+{"name": "kim oden"},
+{"name": "stephanie wrk"},
+{"name": "armando flores"},
+{"name": "wallace cartwright"},
+{"name": "sarah may"},
+{"name": "frankie delgado"},
+{"name": "scotty gates"},
+{"name": "lewis macey"},
+{"name": "matthew rosenbaum"},
+{"name": "jeff dale"},
+{"name": "callie driggers"},
+{"name": "cortney hamiltom"},
+{"name": "steve hovdesven"},
+{"name": "josh mercier"},
+{"name": "jason pelletier"},
+{"name": "judy buffington"},
+{"name": "oscar mccloughan"},
+{"name": "jeremy mcewen"},
+{"name": "dennis valentino"},
+{"name": "norma devaul"},
+{"name": "kerry orr"},
+{"name": "cole paper"},
+{"name": "john chen"},
+{"name": "george joseph"},
+{"name": "mallie brewer"},
+{"name": "kevin choi"},
+{"name": "ken pope"},
+{"name": "patti teween"},
+{"name": "janet campbell"},
+{"name": "rae willis"},
+{"name": "tim goulart"},
+{"name": "ethel weir"},
+{"name": "katie s"},
+{"name": "chris leee"},
+{"name": "randy shacklford"},
+{"name": "thanh quy"},
+{"name": "patrick kester"},
+{"name": "chris kendrick"},
+{"name": "mike gregor"},
+{"name": "nicole manske"},
+{"name": "kate coulson"},
+{"name": "jay jensen"},
+{"name": "louisa porter"},
+{"name": "carolyn moore"},
+{"name": "scott bigham"},
+{"name": "tim cowan"},
+{"name": "nick pant"},
+{"name": "chelsey zinter"},
+{"name": "mike fink"},
+{"name": "steve craigslist"},
+{"name": "mitch fein"},
+{"name": "anne marlow"},
+{"name": "steve brandl"},
+{"name": "erin brophy"},
+{"name": "lowell lyon"},
+{"name": "bill hooper"},
+{"name": "christy clausen"},
+{"name": "regina lesesne"},
+{"name": "jimmy moses"},
+{"name": "rob chua"},
+{"name": "josh barclay"},
+{"name": "brian barit"},
+{"name": "steve barton"},
+{"name": "austin cooper"},
+{"name": "jesse abellar"},
+{"name": "lawerence tronet"},
+{"name": "sheryl busler"},
+{"name": "traci bruce"},
+{"name": "brent lockhart"},
+{"name": "mark morningstar"},
+{"name": "lauri s"},
+{"name": "andrea small"},
+{"name": "kathy cho"},
+{"name": "lee meetup"},
+{"name": "taylor mcadams"},
+{"name": "holly lawson"},
+{"name": "bruce hill"},
+{"name": "bob kreselmeir"},
+{"name": "cathy moffat"},
+{"name": "joyce lambton"},
+{"name": "greg schuh"},
+{"name": "stephen smith"},
+{"name": "kari brown"},
+{"name": "kathy crick"},
+{"name": "carolyn miller"},
+{"name": "lawrence forman"},
+{"name": "kelly lamb"},
+{"name": "mark flanagans"},
+{"name": "rhonda obradovich"},
+{"name": "barbara milmine"},
+{"name": "bruce simpson"},
+{"name": "larry piparo"},
+{"name": "jon fong"},
+{"name": "pablo manavello"},
+{"name": "josh glickman"},
+{"name": "charles chase"},
+{"name": "ed cho"},
+{"name": "doug grote"},
+{"name": "danielle strader"},
+{"name": "kelsey french"},
+{"name": "amy rodenkirk"},
+{"name": "andrew scott"},
+{"name": "mitchell goldstein"},
+{"name": "steve ebert"},
+{"name": "pamela reedstrom"},
+{"name": "misty orman"},
+{"name": "john henry"},
+{"name": "andrea libassi"},
+{"name": "dan hwang"},
+{"name": "maribel martins"},
+{"name": "stuart nelson"},
+{"name": "bill taylor"},
+{"name": "rebecca mcelroy"},
+{"name": "terry fielding"},
+{"name": "tanya reno"},
+{"name": "ed woznicki"},
+{"name": "ben falter"},
+{"name": "wade opsal"},
+{"name": "pam wood"},
+{"name": "craig deming"},
+{"name": "alicia south"},
+{"name": "daniel nicomedes"},
+{"name": "george davish"},
+{"name": "gene chiaro"},
+{"name": "jeff gauthier"},
+{"name": "gerald riley"},
+{"name": "tori stahl"},
+{"name": "cheryl toffel"},
+{"name": "trevor gosserand"},
+{"name": "mathew mathew"},
+{"name": "rob petrone"},
+{"name": "frank byrd"},
+{"name": "bryan may"},
+{"name": "harry herbert"},
+{"name": "alex mckenzie"},
+{"name": "debbie ahearn"},
+{"name": "alex d"},
+{"name": "joe matthews"},
+{"name": "brian dalton"},
+{"name": "colin cell"},
+{"name": "tara mcbennett"},
+{"name": "julie orbank"},
+{"name": "teresa ruelas"},
+{"name": "tim laren"},
+{"name": "stacey durbin"},
+{"name": "alex atchison"},
+{"name": "tom ryan"},
+{"name": "debbie ishikawa"},
+{"name": "mike agar"},
+{"name": "john shagoury"},
+{"name": "brittany trill"},
+{"name": "jon chase"},
+{"name": "lisa tom"},
+{"name": "melissa work"},
+{"name": "ben hodges"},
+{"name": "glen liddell"},
+{"name": "beverly volpe"},
+{"name": "lazaro kaz"},
+{"name": "tim engel"},
+{"name": "trevor jensen"},
+{"name": "doug talalla"},
+{"name": "mike boehner"},
+{"name": "mike wert"},
+{"name": "kevin petersen"},
+{"name": "greg ewing"},
+{"name": "joe furtado"},
+{"name": "linda bontrager"},
+{"name": "bob gallion"},
+{"name": "andrew allin"},
+{"name": "kyle tke"},
+{"name": "doug hylton"},
+{"name": "randy vest"},
+{"name": "connie bartolomeo"},
+{"name": "jordan umstatt"},
+{"name": "jessica berson"},
+{"name": "tim jolly"},
+{"name": "nick rosso"},
+{"name": "daniel hudak"},
+{"name": "ronda prioleau"},
+{"name": "jason rindler"},
+{"name": "vicki keohohou"},
+{"name": "jordan gonzales"},
+{"name": "michael christinziano"},
+{"name": "john mckotch"},
+{"name": "preston shea"},
+{"name": "gregory sachs"},
+{"name": "brian schreiner"},
+{"name": "jody sadler"},
+{"name": "holly nicholas"},
+{"name": "cathy reeves"},
+{"name": "tim raspin"},
+{"name": "amanda cross"},
+{"name": "caleb freeman"},
+{"name": "pat bathke"},
+{"name": "bob butka"},
+{"name": "curt schumacher"},
+{"name": "bill burnham"},
+{"name": "kevin best"},
+{"name": "chris snyder"},
+{"name": "jamie gast"},
+{"name": "karine hhc"},
+{"name": "mark nejame"},
+{"name": "stan carver"},
+{"name": "stephane k"},
+{"name": "rick hunt"},
+{"name": "rob painter"},
+{"name": "elaine snowden"},
+{"name": "tony lam"},
+{"name": "william byrd"},
+{"name": "pam robinson"},
+{"name": "eddie trice"},
+{"name": "steve geer"},
+{"name": "tony cruell"},
+{"name": "jack lambert"},
+{"name": "thomas bell"},
+{"name": "joey frailey"},
+{"name": "greg elton"},
+{"name": "suzanne hayes"},
+{"name": "angela merkle"},
+{"name": "derek rollins"},
+{"name": "eddie franco"},
+{"name": "ian waite"},
+{"name": "palmira jimenez"},
+{"name": "frank mizner"},
+{"name": "keith taylor"},
+{"name": "marguerite parker"},
+{"name": "sean malone"},
+{"name": "nick saccoe"},
+{"name": "bill millard"},
+{"name": "lee a"},
+{"name": "john stoehr"},
+{"name": "luis soto"},
+{"name": "zoe fine"},
+{"name": "jason felton"},
+{"name": "james lux"},
+{"name": "dawn mccarter"},
+{"name": "jay shade"},
+{"name": "dee daytona"},
+{"name": "doug schneider"},
+{"name": "carolina cues"},
+{"name": "kelly ho"},
+{"name": "valerie gibby"},
+{"name": "hayley brit"},
+{"name": "julie shafer"},
+{"name": "saul panduro"},
+{"name": "lori lawlor"},
+{"name": "jamie ocampo"},
+{"name": "winston chow"},
+{"name": "anne malloy"},
+{"name": "marie savel"},
+{"name": "paola alvarez"},
+{"name": "robert swor"},
+{"name": "thomas mcalea"},
+{"name": "john fiacco"},
+{"name": "jim rowland"},
+{"name": "sam singh"},
+{"name": "jess crawford"},
+{"name": "al loring"},
+{"name": "tony raley"},
+{"name": "paola guadarrama"},
+{"name": "dick skeers"},
+{"name": "chantelle adams"},
+{"name": "keith stark"},
+{"name": "carol simenson"},
+{"name": "david yau"},
+{"name": "sherry stewart"},
+{"name": "judy grubman"},
+{"name": "anita garza"},
+{"name": "barry mcdonald"},
+{"name": "sherilyn pang"},
+{"name": "katie trulson"},
+{"name": "jon turner"},
+{"name": "scott obel"},
+{"name": "larry swanson"},
+{"name": "kim sutton"},
+{"name": "loan specialist"},
+{"name": "peggy maytum"},
+{"name": "juan hernandez"},
+{"name": "george hk"},
+{"name": "lisa aguilar"},
+{"name": "cheryl tsang"},
+{"name": "brandy young"},
+{"name": "doug inman"},
+{"name": "paul ferradas"},
+{"name": "joey battaglia"},
+{"name": "luann lyons"},
+{"name": "angie bauer"},
+{"name": "viviana arboleda"},
+{"name": "tony nyguen"},
+{"name": "jamie mefford"},
+{"name": "kara email"},
+{"name": "jodie smith"},
+{"name": "mark gowetski"},
+{"name": "maria tsangaridou"},
+{"name": "nicole scott"},
+{"name": "gonzalo maravilla"},
+{"name": "lilian araujo"},
+{"name": "larry sullivan"},
+{"name": "stephen weinman"},
+{"name": "david ho"},
+{"name": "jeannette vestal"},
+{"name": "ann morgan"},
+{"name": "robert zimmer"},
+{"name": "alyssa toner"},
+{"name": "sandra phillips"},
+{"name": "keith zeitz"},
+{"name": "debbie n"},
+{"name": "simon kok"},
+{"name": "stacey crazy"},
+{"name": "lacey darnold"},
+{"name": "sue collins"},
+{"name": "david babakaiff"},
+{"name": "mike buff"},
+{"name": "jill wis"},
+{"name": "charles khuc"},
+{"name": "darrick king"},
+{"name": "tom mcnelis"},
+{"name": "ellen patt"},
+{"name": "lana seegan"},
+{"name": "ed fletcher"},
+{"name": "tom moran"},
+{"name": "brian allen"},
+{"name": "jim pool"},
+{"name": "bob tietz"},
+{"name": "joe plaksen"},
+{"name": "adam sprint"},
+{"name": "doug berl"},
+{"name": "ryan fyffe"},
+{"name": "tony lamantia"},
+{"name": "leigh cell"},
+{"name": "paula schetzle"},
+{"name": "thuy cao"},
+{"name": "devon house"},
+{"name": "wesley blackberry"},
+{"name": "clinton lawrence"},
+{"name": "marshall moll"},
+{"name": "ron meldrum"},
+{"name": "curt dahl"},
+{"name": "jerry cleaners"},
+{"name": "charley thomas"},
+{"name": "irina burilkova"},
+{"name": "mai baptista"},
+{"name": "annett darts"},
+{"name": "shane bridges"},
+{"name": "dave channey"},
+{"name": "tom kerkhoven"},
+{"name": "terrance hawk"},
+{"name": "miriam holmes"},
+{"name": "daniel wakelin"},
+{"name": "jane donahue"},
+{"name": "dan ryan"},
+{"name": "tom schulenberg"},
+{"name": "kathy bloom"},
+{"name": "jess harris"},
+{"name": "bo vela"},
+{"name": "jessica housain"},
+{"name": "ed liegey"},
+{"name": "lynn brenner"},
+{"name": "leah pears"},
+{"name": "bill griffin"},
+{"name": "michael delaney"},
+{"name": "tara mahtani"},
+{"name": "eden aquarium"},
+{"name": "jamie hepp"},
+{"name": "hillary gillespie"},
+{"name": "sandra harvey"},
+{"name": "roxane hipwell"},
+{"name": "melissa hair"},
+{"name": "craig fry"},
+{"name": "jackie desuza"},
+{"name": "missy tucker"},
+{"name": "reggie dance"},
+{"name": "stephanie angelo"},
+{"name": "bruce elman"},
+{"name": "ken carter"},
+{"name": "suzy cellphone"},
+{"name": "bill hurtt"},
+{"name": "charlie sumalong"},
+{"name": "courtney frey"},
+{"name": "alan prince"},
+{"name": "henry hernaez"},
+{"name": "kristina rudd"},
+{"name": "ann wood"},
+{"name": "melissa boyd"},
+{"name": "darren albertson"},
+{"name": "willie davis"},
+{"name": "kara cell"},
+{"name": "eric gmail"},
+{"name": "devon samuels"},
+{"name": "betsy hummel"},
+{"name": "matthew keese"},
+{"name": "pat v"},
+{"name": "andrew bro"},
+{"name": "bruce baily"},
+{"name": "sandra smith"},
+{"name": "cathy starnes"},
+{"name": "rachel knapp"},
+{"name": "jon land"},
+{"name": "mark vandaharr"},
+{"name": "cory livers"},
+{"name": "stan anderson"},
+{"name": "kevin vandike"},
+{"name": "rodger thomas"},
+{"name": "kenton ward"},
+{"name": "mona rodriguez"},
+{"name": "deb tabor"},
+{"name": "ed lalonde"},
+{"name": "nolan nicoll"},
+{"name": "mark myra"},
+{"name": "mel totah"},
+{"name": "cameron jensen"},
+{"name": "lisa pitt"},
+{"name": "lee hendrickson"},
+{"name": "ivan berkowitz"},
+{"name": "tyler prawitt"},
+{"name": "kathy hicks"},
+{"name": "alisha barrowcliff"},
+{"name": "sara garrett"},
+{"name": "don simpson"},
+{"name": "keith gurl"},
+{"name": "jeff kidder"},
+{"name": "trey bonner"},
+{"name": "mark leach"},
+{"name": "laura kit"},
+{"name": "anna bossa"},
+{"name": "alisha jackson"},
+{"name": "barry fitts"},
+{"name": "daria trawkowski"},
+{"name": "john burdick"},
+{"name": "tina fresno"},
+{"name": "sonia agar"},
+{"name": "patrick sutter"},
+{"name": "frank bullard"},
+{"name": "kristi mcgranahan"},
+{"name": "tom szatkowski"},
+{"name": "michael perez"},
+{"name": "molly big"},
+{"name": "sean harrel"},
+{"name": "francine beyer"},
+{"name": "pete crosby"},
+{"name": "diego loco"},
+{"name": "stanley yu"},
+{"name": "alex edington"},
+{"name": "ann waddell"},
+{"name": "bruce jr"},
+{"name": "bill phipps"},
+{"name": "larry cone"},
+{"name": "josh linam"},
+{"name": "bob gaither"},
+{"name": "camille herrera"},
+{"name": "jean hilliard"},
+{"name": "melinda cardona"},
+{"name": "mike barna"},
+{"name": "sally latife"},
+{"name": "barry swain"},
+{"name": "louis palos"},
+{"name": "kim zigler"},
+{"name": "jodi sherry"},
+{"name": "jamie parker"},
+{"name": "christopher saddler"},
+{"name": "james ringsrud"},
+{"name": "christina keck"},
+{"name": "cody griffin"},
+{"name": "laura bellinger"},
+{"name": "courtney tisch"},
+{"name": "roberto nm"},
+{"name": "brian hawken"},
+{"name": "fred tejkl"},
+{"name": "leslie anderson"},
+{"name": "catherine w"},
+{"name": "pam beadel"},
+{"name": "dan morgan"},
+{"name": "rachael ortiz"},
+{"name": "ted kraus"},
+{"name": "paris plumbing"},
+{"name": "mark kindy"},
+{"name": "kent lingenfelter"},
+{"name": "kenny z"},
+{"name": "john donahue"},
+{"name": "jake knickerbocker"},
+{"name": "george schumer"},
+{"name": "ok cafe"},
+{"name": "tommy kennedy"},
+{"name": "kristen stratton"},
+{"name": "michael keefe"},
+{"name": "rob barnuevo"},
+{"name": "steven wright"},
+{"name": "desiree nicols"},
+{"name": "jason kwan"},
+{"name": "sheryl sain"},
+{"name": "rick ducey"},
+{"name": "jess adobe"},
+{"name": "dave giuliano"},
+{"name": "dana burnell"},
+{"name": "don jacobs"},
+{"name": "lynn ritthaler"},
+{"name": "steven shapero"},
+{"name": "kevin wallace"},
+{"name": "michael l"},
+{"name": "alison kress"},
+{"name": "william wpb"},
+{"name": "mike kleke"},
+{"name": "anne sullivan"},
+{"name": "clara jimenez"},
+{"name": "evan salone"},
+{"name": "derrick lawson"},
+{"name": "chris house"},
+{"name": "jeff driscoll"},
+{"name": "cyndi workman"},
+{"name": "brian staples"},
+{"name": "moises valenzuela"},
+{"name": "bobbie crane"},
+{"name": "gabriel jose"},
+{"name": "tony mclaren"},
+{"name": "sommer setterstrom"},
+{"name": "lorna larson"},
+{"name": "barb prittchett"},
+{"name": "dave carson"},
+{"name": "lindsey taylor"},
+{"name": "boris bogatin"},
+{"name": "mike bovoso"},
+{"name": "steve piceno"},
+{"name": "paul champps"},
+{"name": "kirk d"},
+{"name": "lisa more"},
+{"name": "marsha garczewski"},
+{"name": "rosa gutierrez"},
+{"name": "claudine ryan"},
+{"name": "corey dennis"},
+{"name": "carol murphy"},
+{"name": "daniel lookadoo"},
+{"name": "sue muchowski"},
+{"name": "patrick mahar"},
+{"name": "joe amico"},
+{"name": "johnny lam"},
+{"name": "jerrold reilly"},
+{"name": "dudley wilson"},
+{"name": "art giuliano"},
+{"name": "todd roaten"},
+{"name": "debbie akbari"},
+{"name": "fernando solorzano"},
+{"name": "alexander kilhefner"},
+{"name": "paul surmay"},
+{"name": "judy marshall"},
+{"name": "coy lopez"},
+{"name": "jane birkholz"},
+{"name": "katie krivitz"},
+{"name": "seth griffiths"},
+{"name": "simon bee"},
+{"name": "malcolm maclean"},
+{"name": "doug chipman"},
+{"name": "cathy alesi"},
+{"name": "eric hutchcroft"},
+{"name": "patrick mccabe"},
+{"name": "jacqueline walker"},
+{"name": "jen paquet"},
+{"name": "theresa geary"},
+{"name": "kim boritz"},
+{"name": "dave takeuchi"},
+{"name": "mindy barton"},
+{"name": "simone hamm"},
+{"name": "megan clingman"},
+{"name": "brian rodgers"},
+{"name": "derek haddad"},
+{"name": "jen takamine"},
+{"name": "dave chastain"},
+{"name": "jessica elson"},
+{"name": "luke pietrzak"},
+{"name": "maggie yac"},
+{"name": "jackie corbet"},
+{"name": "rosa ray"},
+{"name": "kristen goodell"},
+{"name": "min check"},
+{"name": "mike norton"},
+{"name": "jim stalker"},
+{"name": "matt blumhart"},
+{"name": "mike olivia"},
+{"name": "jamie goren"},
+{"name": "shelly frias"},
+{"name": "stuart blatt"},
+{"name": "rebekah milhoan"},
+{"name": "mike henderson"},
+{"name": "bill millward"},
+{"name": "brian nelson"},
+{"name": "robert posthumus"},
+{"name": "joe chiseri"},
+{"name": "heather krystals"},
+{"name": "dee beasley"},
+{"name": "mark holesopple"},
+{"name": "mitchell hill"},
+{"name": "carol winter"},
+{"name": "aaron moon"},
+{"name": "mike follosco"},
+{"name": "dora griner"},
+{"name": "phil kreider"},
+{"name": "douglas fleming"},
+{"name": "chris schultz"},
+{"name": "albert willis"},
+{"name": "frank turek"},
+{"name": "jake dewitt"},
+{"name": "jeanne loewen"},
+{"name": "paul sorriento"},
+{"name": "jody branchcomb"},
+{"name": "ruthie car"},
+{"name": "roy maldonado"},
+{"name": "george becker"},
+{"name": "josh bc"},
+{"name": "cody becks"},
+{"name": "glen overton"},
+{"name": "steve smooth"},
+{"name": "brett carson"},
+{"name": "deborah siegel"},
+{"name": "chris class"},
+{"name": "cole johnson"},
+{"name": "brad nicholson"},
+{"name": "dominque saitil"},
+{"name": "tammy duffy"},
+{"name": "phil easton"},
+{"name": "ellie lastra"},
+{"name": "kim crystal"},
+{"name": "amy robertson"},
+{"name": "ginny mclaughlin"},
+{"name": "andy v"},
+{"name": "rick dykes"},
+{"name": "kevin poulsen"},
+{"name": "christa windley"},
+{"name": "steve mcally"},
+{"name": "cindy sprint"},
+{"name": "jennifer wildrick"},
+{"name": "doug miller"},
+{"name": "joe w"},
+{"name": "juan luis"},
+{"name": "louise logie"},
+{"name": "nicole baxter"},
+{"name": "colin nix"},
+{"name": "heather sweitzer"},
+{"name": "terri kowalski"},
+{"name": "chris steele"},
+{"name": "deb herrman"},
+{"name": "myron russell"},
+{"name": "herman nicolay"},
+{"name": "michael brownstein"},
+{"name": "pete lamb"},
+{"name": "daniel robinette"},
+{"name": "tyler caplinger"},
+{"name": "rob waddell"},
+{"name": "zachary smith"},
+{"name": "kesha htown"},
+{"name": "stanley barnes"},
+{"name": "amanda dado"},
+{"name": "megan kelley"},
+{"name": "paul haas"},
+{"name": "kristie holzworth"},
+{"name": "cheryl gunderson"},
+{"name": "jane laurent"},
+{"name": "ralph foston"},
+{"name": "liz zabetakis"},
+{"name": "chris noble"},
+{"name": "robin hunter"},
+{"name": "joe karmia"},
+{"name": "tom o'connor"},
+{"name": "patty oliden"},
+{"name": "guy faherty"},
+{"name": "sylvia kravitz"},
+{"name": "frank tapia"},
+{"name": "jamie bradford"},
+{"name": "ricardo thomason"},
+{"name": "jeremy shapiro"},
+{"name": "mike casey"},
+{"name": "debbie clough"},
+{"name": "martina anderson"},
+{"name": "omar turner"},
+{"name": "clarissa burns"},
+{"name": "chris agazaryan"},
+{"name": "sandra tozay"},
+{"name": "dante rome"},
+{"name": "john varela"},
+{"name": "vernon davis"},
+{"name": "kimberly mont"},
+{"name": "robin pariso"},
+{"name": "tony banks"},
+{"name": "daryl turko"},
+{"name": "mary manion"},
+{"name": "gina trost"},
+{"name": "erin abegglen"},
+{"name": "jack franklin"},
+{"name": "david cappone"},
+{"name": "julie jurica"},
+{"name": "ben escalante"},
+{"name": "donny leaderman"},
+{"name": "wally rosemont"},
+{"name": "dee narayanan"},
+{"name": "brad gunder"},
+{"name": "joshua laforce"},
+{"name": "rob lo"},
+{"name": "jen jason"},
+{"name": "larry simpson"},
+{"name": "rich slavin"},
+{"name": "kenny hairston"},
+{"name": "patrick chu"},
+{"name": "sean m"},
+{"name": "josh evette"},
+{"name": "rob bouse"},
+{"name": "tom albani"},
+{"name": "felipe conto"},
+{"name": "david donnelly"},
+{"name": "grant tancowny"},
+{"name": "leah dyrud"},
+{"name": "erin hudson"},
+{"name": "peggy hubbard"},
+{"name": "tony turner"},
+{"name": "james carnegie"},
+{"name": "tyler johnson"},
+{"name": "tony avila"},
+{"name": "randy new"},
+{"name": "christopher brooks"},
+{"name": "amy mcandree"},
+{"name": "pam anderson"},
+{"name": "donald collections"},
+{"name": "carl beke"},
+{"name": "kyle vangrol"},
+{"name": "elijah smith"},
+{"name": "rebecca zink"},
+{"name": "bruce green"},
+{"name": "aaron edelman"},
+{"name": "alan laguna"},
+{"name": "jonathan rodriguez"},
+{"name": "fred gehrig"},
+{"name": "barbra jean"},
+{"name": "nick rehab"},
+{"name": "shawn excaliber"},
+{"name": "russ mcginty"},
+{"name": "nina princesse"},
+{"name": "diane cell"},
+{"name": "art gibson"},
+{"name": "lyndon kately"},
+{"name": "tom burton"},
+{"name": "donovan pr"},
+{"name": "jesse twinkcersize"},
+{"name": "melissa danbury"},
+{"name": "ken hughes"},
+{"name": "alex defelice"},
+{"name": "john valerio"},
+{"name": "cassie silva"},
+{"name": "jamie wilson"},
+{"name": "tia elise"},
+{"name": "herman reality"},
+{"name": "scottie juneau"},
+{"name": "don m"},
+{"name": "kristine szmanda"},
+{"name": "cindy grassi"},
+{"name": "ron schrader"},
+{"name": "jason larson"},
+{"name": "gina hathorn"},
+{"name": "matt dirito"},
+{"name": "mike stine"},
+{"name": "dane jordan"},
+{"name": "lady forest"},
+{"name": "pat langer"},
+{"name": "rich cfo"},
+{"name": "quentin kingham"},
+{"name": "reed buderus"},
+{"name": "tammy ramlawi"},
+{"name": "john schrimsher"},
+{"name": "bruce cummings"},
+{"name": "tasha tripplett"},
+{"name": "michael profit"},
+{"name": "charles petitti"},
+{"name": "blaine welks"},
+{"name": "kelly macfarland"},
+{"name": "orlando bojorquez"},
+{"name": "robert stabile"},
+{"name": "mary storm"},
+{"name": "emma devine"},
+{"name": "tyler duellman"},
+{"name": "ron marion"},
+{"name": "francis esu"},
+{"name": "jennifer williams"},
+{"name": "zack martin"},
+{"name": "mark albert"},
+{"name": "tessa green"},
+{"name": "jeffrey hull"},
+{"name": "mary schafer"},
+{"name": "carlos ku"},
+{"name": "bill bizmeyer"},
+{"name": "steve hooper"},
+{"name": "laurie rothenberg"},
+{"name": "dan wk"},
+{"name": "dave brandeberry"},
+{"name": "joe harding"},
+{"name": "carolyn phillips"},
+{"name": "stan gilliland"},
+{"name": "amy betz"},
+{"name": "don sanfranek"},
+{"name": "bob feldmann"},
+{"name": "lee zejacs"},
+{"name": "josh otte"},
+{"name": "grace chong"},
+{"name": "michael fulton"},
+{"name": "beth lebow"},
+{"name": "frank fillipone"},
+{"name": "natasha akers"},
+{"name": "joel laird"},
+{"name": "glen hollinger"},
+{"name": "dave thompson"},
+{"name": "beverly xxxxx"},
+{"name": "bradley mcdevitt"},
+{"name": "lee weisman"},
+{"name": "amber gillette"},
+{"name": "kurt union"},
+{"name": "stewart alpert"},
+{"name": "mike lacosta"},
+{"name": "terry hodgkin"},
+{"name": "kyle hawkins"},
+{"name": "kenny barnes"},
+{"name": "larry ford"},
+{"name": "mary davidson"},
+{"name": "chad bryan"},
+{"name": "robert o'connell"},
+{"name": "ray kosiba"},
+{"name": "judy sis"},
+{"name": "will donaldson"},
+{"name": "tammy pryor"},
+{"name": "page boxing"},
+{"name": "stephanie bailey"},
+{"name": "ryan bareilles"},
+{"name": "eli lichtenstien"},
+{"name": "don roberts"},
+{"name": "james montoya"},
+{"name": "keith green"},
+{"name": "al thurmond"},
+{"name": "kelly coc"},
+{"name": "andrew riepe"},
+{"name": "nicole notmarried"},
+{"name": "brian treadway"},
+{"name": "alex gudenau"},
+{"name": "mike simpson"},
+{"name": "ronnie malone"},
+{"name": "jenny w"},
+{"name": "toby okenwa"},
+{"name": "matt mazgaj"},
+{"name": "carla isaias"},
+{"name": "andrea paul"},
+{"name": "matt baldes"},
+{"name": "simon varley"},
+{"name": "anthony mancini"},
+{"name": "jackie chen"},
+{"name": "sean duque"},
+{"name": "matt ware"},
+{"name": "paris reid"},
+{"name": "tiffany jackson"},
+{"name": "jon bingle"},
+{"name": "jess caufield"},
+{"name": "patti ryan"},
+{"name": "josephine vasquez"},
+{"name": "dan dineson"},
+{"name": "jose big"},
+{"name": "van meter"},
+{"name": "max schumaker"},
+{"name": "renee her"},
+{"name": "larry bean"},
+{"name": "louie prieto"},
+{"name": "marilyn lugo"},
+{"name": "stan schwartz"},
+{"name": "kenny navas"},
+{"name": "mark kowal"},
+{"name": "ryan wolfe"},
+{"name": "teddy holmes"},
+{"name": "darlene quinn"},
+{"name": "victor seveso"},
+{"name": "tom thumb"},
+{"name": "greg lawerence"},
+{"name": "janette stinnet"},
+{"name": "charlie berard"},
+{"name": "john pratt"},
+{"name": "phil evazkhani"},
+{"name": "val steinberg"},
+{"name": "terry pitzer"},
+{"name": "raquel navor"},
+{"name": "brandon dunaway"},
+{"name": "john lichtenstein"},
+{"name": "donald lyons"},
+{"name": "rubin rebecca"},
+{"name": "tim ross"},
+{"name": "sarah b"},
+{"name": "will schinagl"},
+{"name": "cheryl julcher"},
+{"name": "chris corr"},
+{"name": "beth shaw"},
+{"name": "chase disney"},
+{"name": "david kestner"},
+{"name": "al champagne"},
+{"name": "kelly harcus"},
+{"name": "susan quintyne"},
+{"name": "ken whiteside"},
+{"name": "amanda chan"},
+{"name": "marlo king"},
+{"name": "nick trevillian"},
+{"name": "nick wash"},
+{"name": "brian fredkin"},
+{"name": "van rental"},
+{"name": "erin olsen"},
+{"name": "emma reaves"},
+{"name": "robert lanenga"},
+{"name": "linda guzzetta"},
+{"name": "martin family"},
+{"name": "taylor tay"},
+{"name": "rick ross"},
+{"name": "deanne harper"},
+{"name": "shane topolovic"},
+{"name": "dave rudyk"},
+{"name": "george chickering"},
+{"name": "elise clemet"},
+{"name": "paul keeton"},
+{"name": "steven poloka"},
+{"name": "joann padilla"},
+{"name": "wilma brooks"},
+{"name": "art khnkoyan"},
+{"name": "shari lewis"},
+{"name": "mary keating"},
+{"name": "jutta jacobs"},
+{"name": "norma malagarie"},
+{"name": "dale abuel"},
+{"name": "ashley higham"},
+{"name": "beverly petty"},
+{"name": "jamie babbit"},
+{"name": "jason paisan"},
+{"name": "shelby sanders"},
+{"name": "jodi brothers"},
+{"name": "nicole mazzone"},
+{"name": "sharon sup"},
+{"name": "andrew taxes"},
+{"name": "jessie kramer"},
+{"name": "karyn grant"},
+{"name": "dina patel"},
+{"name": "jess parents"},
+{"name": "marcelo cavalcante"},
+{"name": "james palmer"},
+{"name": "lucia quiroz"},
+{"name": "craig kohler"},
+{"name": "jessica salisbury"},
+{"name": "nathan fisher"},
+{"name": "cheryl bell"},
+{"name": "jon work"},
+{"name": "darren gallegos"},
+{"name": "ryan stowe"},
+{"name": "gay jason"},
+{"name": "katie cervantes"},
+{"name": "jeremy ruppe"},
+{"name": "seth art"},
+{"name": "ken west"},
+{"name": "arianna schettino"},
+{"name": "geraldo orozco"},
+{"name": "scott osborne"},
+{"name": "bob riffner"},
+{"name": "tony romas"},
+{"name": "tony bud"},
+{"name": "douglas cabot"},
+{"name": "john lashell"},
+{"name": "tracy pulla"},
+{"name": "kira rabalais"},
+{"name": "sue curley"},
+{"name": "bob dubow"},
+{"name": "ginny gribble"},
+{"name": "josh shrager"},
+{"name": "levi colinas"},
+{"name": "shirley ingram"},
+{"name": "mike karaoke"},
+{"name": "toya brown"},
+{"name": "peter fleming"},
+{"name": "lowell smith"},
+{"name": "anna melamud"},
+{"name": "jim thompson"},
+{"name": "mindy culley"},
+{"name": "bill lederer"},
+{"name": "kelly paper"},
+{"name": "loren jones"},
+{"name": "carla wilcher"},
+{"name": "james cincotta"},
+{"name": "todd mumford"},
+{"name": "susie cohen"},
+{"name": "gabriel cell"},
+{"name": "edward ings"},
+{"name": "gary liggett"},
+{"name": "owen connelly"},
+{"name": "dan lanus"},
+{"name": "vicki bartlett"},
+{"name": "shawn streeter"},
+{"name": "corinne bernimoulin"},
+{"name": "steve edmiston"},
+{"name": "byron steele"},
+{"name": "gary lileikis"},
+{"name": "jacki klein"},
+{"name": "erik laver"},
+{"name": "kay fritzsche"},
+{"name": "nikole flores"},
+{"name": "ron harrell"},
+{"name": "darrel neff"},
+{"name": "rachael mcgee"},
+{"name": "allison garrett"},
+{"name": "terri blackmon"},
+{"name": "damon scheter"},
+{"name": "debbie turkanis"},
+{"name": "john boehmer"},
+{"name": "scott speakman"},
+{"name": "brenna frisbe"},
+{"name": "kathy russell"},
+{"name": "laura minjarez"},
+{"name": "gil williams"},
+{"name": "rob obrien"},
+{"name": "debra smith"},
+{"name": "david pankhurst"},
+{"name": "jay meltzer"},
+{"name": "glen floyd"},
+{"name": "caleb s"},
+{"name": "mike sigidel"},
+{"name": "darryl bruyns"},
+{"name": "holly tibbel"},
+{"name": "omar barral"},
+{"name": "luisa pessel"},
+{"name": "carl fischbach"},
+{"name": "melony ford"},
+{"name": "fiona luck"},
+{"name": "lloyd booker"},
+{"name": "craig louie"},
+{"name": "deon actn"},
+{"name": "jeff paul"},
+{"name": "alfonso cortez"},
+{"name": "shelly simpson"},
+{"name": "rob goodwin"},
+{"name": "richard hatt"},
+{"name": "gary myles"},
+{"name": "tom cush"},
+{"name": "brian ashley"},
+{"name": "gloria gott"},
+{"name": "al browning"},
+{"name": "alex flores"},
+{"name": "brittany koon"},
+{"name": "susan schumacher"},
+{"name": "stephanie condron"},
+{"name": "ann evans"},
+{"name": "andrew draper"},
+{"name": "jackie zook"},
+{"name": "della mckinney"},
+{"name": "ken argo"},
+{"name": "michael yardley"},
+{"name": "gail anderson"},
+{"name": "danielle berber"},
+{"name": "liz coko"},
+{"name": "shawn barreiro"},
+{"name": "harry issler"},
+{"name": "michael naeve"},
+{"name": "lorinda bruen"},
+{"name": "pam budenbender"},
+{"name": "steve younch"},
+{"name": "patrice vielpeau"},
+{"name": "mary h"},
+{"name": "luke gilbertson"},
+{"name": "lisa clayton"},
+{"name": "jim richardson"},
+{"name": "cassandra terwilliger"},
+{"name": "ruth smith"},
+{"name": "josh lewis"},
+{"name": "tama tenis"},
+{"name": "glen lakes"},
+{"name": "liz masterman"},
+{"name": "eric sapir"},
+{"name": "sue uptown"},
+{"name": "chris brixy"},
+{"name": "john nicon"},
+{"name": "sarah ritsko"},
+{"name": "andrew shuta"},
+{"name": "ashlee hughes"},
+{"name": "dee burgin"},
+{"name": "jen engel"},
+{"name": "shirley foster"},
+{"name": "hugh bartels"},
+{"name": "brain stanely"},
+{"name": "gail muniz"},
+{"name": "brooke ives"},
+{"name": "richard terry"},
+{"name": "matt trucco"},
+{"name": "michelle woznichak"},
+{"name": "ben naude"},
+{"name": "olivia stallard"},
+{"name": "rob walker"},
+{"name": "karen ramel"},
+{"name": "alex silverman"},
+{"name": "stan septic"},
+{"name": "tami vinzant"},
+{"name": "jen glen"},
+{"name": "donna franz"},
+{"name": "linda vark"},
+{"name": "lonnie king"},
+{"name": "clara brush"},
+{"name": "columbus police"},
+{"name": "jay parties"},
+{"name": "laura rehbehn"},
+{"name": "kimberly anderson"},
+{"name": "tai doan"},
+{"name": "andrew franklin"},
+{"name": "ann scott"},
+{"name": "alfonso villa"},
+{"name": "dominique harris"},
+{"name": "maria plantilla"},
+{"name": "winter construction"},
+{"name": "melissa maddox"},
+{"name": "brendon crossing"},
+{"name": "cathy allison"},
+{"name": "billy chew"},
+{"name": "damon weber"},
+{"name": "peter smul"},
+{"name": "dennis riege"},
+{"name": "andy weirzbicky"},
+{"name": "nelson oliver"},
+{"name": "kevin wsp"},
+{"name": "deb cornwell"},
+{"name": "colton eliasen"},
+{"name": "andrea guzinski"},
+{"name": "steven chic"},
+{"name": "joy mueller"},
+{"name": "yu ra"},
+{"name": "le montreaux"},
+{"name": "bridgette johnston"},
+{"name": "darryl simons"},
+{"name": "wilfred cosca"},
+{"name": "keith goldfeld"},
+{"name": "david bengtson"},
+{"name": "alisa katz"},
+{"name": "brian lawson"},
+{"name": "fred wolfe"},
+{"name": "jack claver"},
+{"name": "val pena"},
+{"name": "wally terry"},
+{"name": "allison tiefel"},
+{"name": "joe fagan"},
+{"name": "jon boyer"},
+{"name": "thomas bryan"},
+{"name": "steve yockel"},
+{"name": "beverly wilson"},
+{"name": "robbie chenault"},
+{"name": "sterling fletcher"},
+{"name": "renee keo"},
+{"name": "cindy l"},
+{"name": "joann willhite"},
+{"name": "brad w"},
+{"name": "al solting"},
+{"name": "frank cowan"},
+{"name": "barbara halle"},
+{"name": "meg healey"},
+{"name": "roger letalien"},
+{"name": "hillary hull"},
+{"name": "ashley mullin"},
+{"name": "bill sivick"},
+{"name": "jazmine conage"},
+{"name": "mary sues"},
+{"name": "tina ross"},
+{"name": "ethan smith"},
+{"name": "justin stafford"},
+{"name": "caroline krabach"},
+{"name": "chad hindolghter"},
+{"name": "richard tonioni"},
+{"name": "delta etl"},
+{"name": "ryan fortson"},
+{"name": "paula keating"},
+{"name": "jena naimi"},
+{"name": "nicole gipson"},
+{"name": "carla dawson"},
+{"name": "jim karabetsos"},
+{"name": "jim thune"},
+{"name": "joe a"},
+{"name": "melissa qazi"},
+{"name": "andrew kaufman"},
+{"name": "kyle brown"},
+{"name": "craig chapman"},
+{"name": "richard lechner"},
+{"name": "alex krasnov"},
+{"name": "dawn allendorf"},
+{"name": "mike o'reilly"},
+{"name": "tony q"},
+{"name": "ronni neeman"},
+{"name": "royce hylton"},
+{"name": "gary wells"},
+{"name": "phyllis catania"},
+{"name": "jayson carlyle"},
+{"name": "carl siegel"},
+{"name": "ned halle"},
+{"name": "jesse tuck"},
+{"name": "coy heaton"},
+{"name": "alena olaes"},
+{"name": "ryan big"},
+{"name": "rick pranitis"},
+{"name": "star client"},
+{"name": "darrell holmes"},
+{"name": "brandy huser"},
+{"name": "brett fifield"},
+{"name": "beth gonnering"},
+{"name": "steve brasington"},
+{"name": "chris stevens"},
+{"name": "brent wilson"},
+{"name": "david tobin"},
+{"name": "ben anderson"},
+{"name": "nancy terriquez"},
+{"name": "debra ramsay"},
+{"name": "corey roberts"},
+{"name": "cynthia luke"},
+{"name": "sasha osha"},
+{"name": "mary tunesen"},
+{"name": "tyler police"},
+{"name": "alexandria glispie"},
+{"name": "deja regala"},
+{"name": "fred gao"},
+{"name": "marlon deandrade"},
+{"name": "julie underwood"},
+{"name": "kellie swayne"},
+{"name": "rachael bearer"},
+{"name": "madeline house"},
+{"name": "david hawkins"},
+{"name": "bertha lansdown"},
+{"name": "jason stroud"},
+{"name": "kay lehmer"},
+{"name": "amy o'donnel"},
+{"name": "jessica kanakry"},
+{"name": "vince webb"},
+{"name": "cherie dell'anno"},
+{"name": "carroll realtor"},
+{"name": "rob shostak"},
+{"name": "mark wilkman"},
+{"name": "holly eby"},
+{"name": "justin townsend"},
+{"name": "kevin hall"},
+{"name": "robert daugherty"},
+{"name": "vince cannon"},
+{"name": "val shibley"},
+{"name": "alaina williams"},
+{"name": "lyn monticone"},
+{"name": "andrew bergen"},
+{"name": "ron huber"},
+{"name": "john royall"},
+{"name": "courtney sabb"},
+{"name": "doug knight"},
+{"name": "robert evers"},
+{"name": "sharon seiler"},
+{"name": "darlene chestnut"},
+{"name": "rob barbato"},
+{"name": "julie barber"},
+{"name": "joe gallivan"},
+{"name": "katie costello"},
+{"name": "danny rojas"},
+{"name": "tom talbot"},
+{"name": "xavier ramirez"},
+{"name": "wendy mervis"},
+{"name": "toby frandsen"},
+{"name": "jeff callaway"},
+{"name": "kris zawisza"},
+{"name": "manda shah"},
+{"name": "ingrid lx"},
+{"name": "sierra smith"},
+{"name": "carole charbonneau"},
+{"name": "heather mi"},
+{"name": "laura luttrell"},
+{"name": "carissa daly"},
+{"name": "jamie manzano"},
+{"name": "angela higgins"},
+{"name": "christian lui"},
+{"name": "kyle gleason"},
+{"name": "breana stockwell"},
+{"name": "rick welch"},
+{"name": "phil hugely"},
+{"name": "claudia caprilles"},
+{"name": "dirk ooijkaas"},
+{"name": "david lombardi"},
+{"name": "mike val"},
+{"name": "barbara mcdermott"},
+{"name": "robert maxwell"},
+{"name": "saundra hester"},
+{"name": "deborah ferrell"},
+{"name": "chuck hendsch"},
+{"name": "jen hilgenberg"},
+{"name": "mike sunderland"},
+{"name": "mark wheaton"},
+{"name": "lily heneisen"},
+{"name": "lee todd"},
+{"name": "geneva lee"},
+{"name": "lena mescall"},
+{"name": "jim nesbitt"},
+{"name": "lauren spencer"},
+{"name": "alonzo blockett"},
+{"name": "kayla thomas"},
+{"name": "will rose"},
+{"name": "gerald raines"},
+{"name": "lance morgan"},
+{"name": "mike soccer"},
+{"name": "kevin homerstein"},
+{"name": "mindy axid"},
+{"name": "tom hinshaw"},
+{"name": "rachel jordan"},
+{"name": "jen lloyd"},
+{"name": "becky hellerstien"},
+{"name": "brian maynard"},
+{"name": "sherri pendelton"},
+{"name": "eric callis"},
+{"name": "dave corning"},
+{"name": "chuck siegel"},
+{"name": "george tougias"},
+{"name": "danny klein"},
+{"name": "colleen p"},
+{"name": "robert musser"},
+{"name": "janet komoto"},
+{"name": "carmen reveron"},
+{"name": "jordan cook"},
+{"name": "jeff tottleben"},
+{"name": "rory kelliher"},
+{"name": "carlos egues"},
+{"name": "kim padova"},
+{"name": "lloyd goetz"},
+{"name": "jennifer snowden"},
+{"name": "rich sundin"},
+{"name": "tommy jones"},
+{"name": "josh spirit"},
+{"name": "norman yoshida"},
+{"name": "becky coburn"},
+{"name": "ben kurian"},
+{"name": "ron watts"},
+{"name": "scott g"},
+{"name": "jack jordan"},
+{"name": "james stiles"},
+{"name": "jeremy work"},
+{"name": "dave jeff"},
+{"name": "samantha marley"},
+{"name": "paul nousis"},
+{"name": "mario carrillo"},
+{"name": "garland steward"},
+{"name": "jason marvich"},
+{"name": "robert selby"},
+{"name": "bruce odette"},
+{"name": "ana rosa"},
+{"name": "dawn hankison"},
+{"name": "cindy anderson"},
+{"name": "dave budach"},
+{"name": "melissa gig"},
+{"name": "ashley mauer"},
+{"name": "peter imhof"},
+{"name": "sue premetz"},
+{"name": "cheryl kent"},
+{"name": "bob gronski"},
+{"name": "yan sjvc"},
+{"name": "peter gonyeau"},
+{"name": "steven sutherland"},
+{"name": "greg burkhardt"},
+{"name": "dean rathbun"},
+{"name": "tony monaco"},
+{"name": "jamie c"},
+{"name": "shane jones"},
+{"name": "jim brennan"},
+{"name": "lorena white"},
+{"name": "robert mansour"},
+{"name": "randy reyes"},
+{"name": "melissa lehman"},
+{"name": "aaron amato"},
+{"name": "alia ott"},
+{"name": "steve looney"},
+{"name": "ernest jefferson"},
+{"name": "lauren cromer"},
+{"name": "angela toribio"},
+{"name": "joselyn paulson"},
+{"name": "lamar johnson"},
+{"name": "joel silverfield"},
+{"name": "karen barone"},
+{"name": "samuel rogers"},
+{"name": "brian le"},
+{"name": "megan mclean"},
+{"name": "kirk oconnell"},
+{"name": "sam theven"},
+{"name": "mae ingles"},
+{"name": "jake richins"},
+{"name": "bryan vierow"},
+{"name": "ralph gallaugher"},
+{"name": "karen nanninga"},
+{"name": "john neumark"},
+{"name": "kevin thai"},
+{"name": "chris gall"},
+{"name": "al whitley"},
+{"name": "tracy bellamy"},
+{"name": "anne cookson"},
+{"name": "nick vriheas"},
+{"name": "john kasper"},
+{"name": "mike naranjo"},
+{"name": "roger walton"},
+{"name": "michelle franklin"},
+{"name": "casey jean"},
+{"name": "clarissa duron"},
+{"name": "linda roy"},
+{"name": "dan delaney"},
+{"name": "james minor"},
+{"name": "vern profitt"},
+{"name": "catherine perreault"},
+{"name": "james ware"},
+{"name": "david larson"},
+{"name": "mike joher"},
+{"name": "lori jamison"},
+{"name": "jerald hunsaker"},
+{"name": "dave wemke"},
+{"name": "pat bsc"},
+{"name": "chris plechy"},
+{"name": "steve bangs"},
+{"name": "crystal curiel"},
+{"name": "carol walter"},
+{"name": "sandra alvarez"},
+{"name": "jason rogne"},
+{"name": "dave wenberg"},
+{"name": "erick kauhini"},
+{"name": "sara schmoldt"},
+{"name": "sara doyle"},
+{"name": "melissa h"},
+{"name": "trevor bach"},
+{"name": "brenda giddings"},
+{"name": "diana emery"},
+{"name": "joe eagan"},
+{"name": "sophia payind"},
+{"name": "george lynch"},
+{"name": "ned matthews"},
+{"name": "andy armshlong"},
+{"name": "david good"},
+{"name": "sheila novak"},
+{"name": "brett denney"},
+{"name": "alice bozzi"},
+{"name": "megan carrigan"},
+{"name": "jen munoz"},
+{"name": "al cell"},
+{"name": "kim scardino"},
+{"name": "raymond knoll"},
+{"name": "theron mcmillon"},
+{"name": "elena sobolic"},
+{"name": "kelly doll"},
+{"name": "ken lin"},
+{"name": "karen huaulme"},
+{"name": "jim brock"},
+{"name": "skye new"},
+{"name": "robby miller"},
+{"name": "steve phelps"},
+{"name": "david umbenhaur"},
+{"name": "lynn verchere"},
+{"name": "mike crawford"},
+{"name": "jody madson"},
+{"name": "leslie shaw"},
+{"name": "jon keene"},
+{"name": "terry angstadt"},
+{"name": "george aguilar"},
+{"name": "sherron boardley"},
+{"name": "jeffrey hoosear"},
+{"name": "robin downing"},
+{"name": "tillie terrell"},
+{"name": "donald armour"},
+{"name": "jason loftus"},
+{"name": "debra pelegrin"},
+{"name": "cathy shields"},
+{"name": "randi elite"},
+{"name": "carli olmstead"},
+{"name": "adam tallent"},
+{"name": "hank thode"},
+{"name": "sergio trujillo"},
+{"name": "bob mcgowan"},
+{"name": "kris rowe"},
+{"name": "gerry hart"},
+{"name": "garrett ichimura"},
+{"name": "michele king"},
+{"name": "jeff sapp"},
+{"name": "rosanna jett"},
+{"name": "rich webber"},
+{"name": "jerry pearman"},
+{"name": "holly miner"},
+{"name": "lynn poole"},
+{"name": "mike v"},
+{"name": "george maamari"},
+{"name": "nicola saliendra"},
+{"name": "larry menedez"},
+{"name": "louis trepanier"},
+{"name": "stefanie lau"},
+{"name": "marc fuller"},
+{"name": "jennifer legree"},
+{"name": "doug boles"},
+{"name": "dan erwin"},
+{"name": "jimmy missuri"},
+{"name": "joseph nuccio"},
+{"name": "hillary model"},
+{"name": "brandon vassalotti"},
+{"name": "melanie lampa"},
+{"name": "garrett rosier"},
+{"name": "bob king"},
+{"name": "marilyn cheatham"},
+{"name": "gerald young"},
+{"name": "carolyn kellogg"},
+{"name": "noel hyde"},
+{"name": "frank hulskoetter"},
+{"name": "missy way"},
+{"name": "richard rose"},
+{"name": "melissa depot"},
+{"name": "kari r"},
+{"name": "tony piazza"},
+{"name": "tarah n"},
+{"name": "ben wurschmidt"},
+{"name": "denis dionne"},
+{"name": "morgan huttle"},
+{"name": "angela fallenbeck"},
+{"name": "tina locke"},
+{"name": "william steakhouse"},
+{"name": "megan riley"},
+{"name": "mariah bloom"},
+{"name": "michael warnecke"},
+{"name": "ramon nevarez"},
+{"name": "mike ress"},
+{"name": "bree v"},
+{"name": "bob conti"},
+{"name": "frank sisca"},
+{"name": "rob karl"},
+{"name": "bonnie jasso"},
+{"name": "eric criswell"},
+{"name": "samantha gregg"},
+{"name": "mike phelps"},
+{"name": "jane mitchell"},
+{"name": "nick arvizu"},
+{"name": "dana martin"},
+{"name": "michelle o'neil"},
+{"name": "john sly"},
+{"name": "martha alvarado"},
+{"name": "jay holiday"},
+{"name": "jaime eberhart"},
+{"name": "dennis geiser"},
+{"name": "kelsie cox"},
+{"name": "hector garceau"},
+{"name": "justin olson"},
+{"name": "marilyn pujols"},
+{"name": "shanna eichelberger"},
+{"name": "tony ellis"},
+{"name": "jason farrer"},
+{"name": "kent hammond"},
+{"name": "walker miller"},
+{"name": "alex moreno"},
+{"name": "john jacobi"},
+{"name": "melisa cin"},
+{"name": "patti christie"},
+{"name": "david causey"},
+{"name": "morris virginia"},
+{"name": "curt grandia"},
+{"name": "nancy dixon"},
+{"name": "tyler york"},
+{"name": "kristy akin"},
+{"name": "mel hosler"},
+{"name": "robert moore"},
+{"name": "albert gallo"},
+{"name": "jake c"},
+{"name": "justin acc"},
+{"name": "tony andres"},
+{"name": "karen boardman"},
+{"name": "jason lotton"},
+{"name": "lee ilse"},
+{"name": "nathan kreye"},
+{"name": "tony jurgens"},
+{"name": "jim cokato"},
+{"name": "jennifer overton"},
+{"name": "megan dittl"},
+{"name": "paul shawah"},
+{"name": "mike noble"},
+{"name": "julie zielinski"},
+{"name": "ryan k"},
+{"name": "jillian ravenscroft"},
+{"name": "dale gurley"},
+{"name": "heather norvell"},
+{"name": "elizabeth corvino"},
+{"name": "nick aspeslagh"},
+{"name": "derek gutter"},
+{"name": "ana hernandez"},
+{"name": "deborah deux"},
+{"name": "beau graffin"},
+{"name": "genevieve fausett"},
+{"name": "ruben cardenas"},
+{"name": "rob renfro"},
+{"name": "christopher liss"},
+{"name": "arturo arias"},
+{"name": "bruce langston"},
+{"name": "bill pc"},
+{"name": "eric feldman"},
+{"name": "zenaida flores"},
+{"name": "daryl delosreyes"},
+{"name": "august brown"},
+{"name": "michael mcguinness"},
+{"name": "anthony hoang"},
+{"name": "justin dounce"},
+{"name": "stephanie vacuna"},
+{"name": "bob jones"},
+{"name": "daniel oludemi"},
+{"name": "andrea daa"},
+{"name": "mark drescher"},
+{"name": "larry marvin"},
+{"name": "amanda bueno"},
+{"name": "elena shore"},
+{"name": "christine strube"},
+{"name": "glen buchner"},
+{"name": "greg wynne"},
+{"name": "anna sacripanti"},
+{"name": "megan misf"},
+{"name": "brandon woodland"},
+{"name": "ray hair"},
+{"name": "robert mintz"},
+{"name": "casey harvey"},
+{"name": "alex mangen"},
+{"name": "tim zoma"},
+{"name": "amy chung"},
+{"name": "david banner"},
+{"name": "brian chitwood"},
+{"name": "carlos pest"},
+{"name": "barry kryst"},
+{"name": "kevin broas"},
+{"name": "tami bruner"},
+{"name": "jason champps"},
+{"name": "tracie duggard"},
+{"name": "jose virgo"},
+{"name": "perry bro"},
+{"name": "tony saeteurn"},
+{"name": "jim pipolo"},
+{"name": "tim tran"},
+{"name": "tom o'brien"},
+{"name": "casey mac"},
+{"name": "anh nguyen"},
+{"name": "matt salinger"},
+{"name": "tommy poker"},
+{"name": "spencer waldman"},
+{"name": "mei king"},
+{"name": "tim wiltman"},
+{"name": "bill proctor"},
+{"name": "kevin snu"},
+{"name": "chanelle regoli"},
+{"name": "duane geiger"},
+{"name": "marcia nance"},
+{"name": "aaron lauterret"},
+{"name": "jon sum"},
+{"name": "charles tyler"},
+{"name": "kim campbell"},
+{"name": "john tallarico"},
+{"name": "arthur dietze"},
+{"name": "su sim"},
+{"name": "pat surgeon"},
+{"name": "charles mathis"},
+{"name": "laura kruse"},
+{"name": "justin moore"},
+{"name": "garry bettencourt"},
+{"name": "donna winters"},
+{"name": "bob stange"},
+{"name": "bruce deese"},
+{"name": "scott fitzpatrick"},
+{"name": "sam huston"},
+{"name": "george lafrance"},
+{"name": "thomas balcezak"},
+{"name": "robin canetella"},
+{"name": "porter mason"},
+{"name": "jennifer graff"},
+{"name": "chris smith"},
+{"name": "nick malcom"},
+{"name": "fred figeroa"},
+{"name": "andrew dueckman"},
+{"name": "john sharff"},
+{"name": "nichelle brown"},
+{"name": "todd simpson"},
+{"name": "boyd gilkey"},
+{"name": "bob palmer"},
+{"name": "laurence winter"},
+{"name": "judy tran"},
+{"name": "rick clifford"},
+{"name": "justin horvath"},
+{"name": "juan laserna"},
+{"name": "sheri shipman"},
+{"name": "amanda i"},
+{"name": "peggy darnell"},
+{"name": "david blackwell"},
+{"name": "kelly clark"},
+{"name": "tim forzley"},
+{"name": "tommy miller"},
+{"name": "david wu"},
+{"name": "jake estes"},
+{"name": "betsy starr"},
+{"name": "camille ebert"},
+{"name": "kacey fullington"},
+{"name": "eddie re"},
+{"name": "mike promoter"},
+{"name": "bob borgstrom"},
+{"name": "jesse riker"},
+{"name": "bill binford"},
+{"name": "brandy carr"},
+{"name": "ed kanabay"},
+{"name": "rusty legg"},
+{"name": "christian grimm"},
+{"name": "william heestand"},
+{"name": "sheron franklin"},
+{"name": "danny rubinshtein"},
+{"name": "jana keele"},
+{"name": "rich oldach"},
+{"name": "jonathan kile"},
+{"name": "charolette butler"},
+{"name": "teddy tossiant"},
+{"name": "mark mactaggart"},
+{"name": "james williams"},
+{"name": "elaine schoendorf"},
+{"name": "faye bramhall"},
+{"name": "chuck dickson"},
+{"name": "michael matthew"},
+{"name": "elliot cunningham"},
+{"name": "george stewart"},
+{"name": "rick lereaux"},
+{"name": "evan brownstein"},
+{"name": "elizabeth mall"},
+{"name": "john toppari"},
+{"name": "craig jaffrey"},
+{"name": "steven lieberman"},
+{"name": "john shedd"},
+{"name": "paul paluzzi"},
+{"name": "tina adkison"},
+{"name": "gisele wegleitner"},
+{"name": "gary oram"},
+{"name": "art murray"},
+{"name": "andrew stout"},
+{"name": "robert pudell"},
+{"name": "trang tran"},
+{"name": "beatriz giraldo"},
+{"name": "dave machika"},
+{"name": "josh rowe"},
+{"name": "joe grover"},
+{"name": "tom o'conner"},
+{"name": "paul o'rourke"},
+{"name": "janet engler"},
+{"name": "isabella argueso"},
+{"name": "don garner"},
+{"name": "ed port"},
+{"name": "james royal"},
+{"name": "george maguire"},
+{"name": "dan bowman"},
+{"name": "amber bantz"},
+{"name": "peter noble"},
+{"name": "layne hoote"},
+{"name": "misty martin"},
+{"name": "matthew stewart"},
+{"name": "marilyn schimdt"},
+{"name": "jean fehl"},
+{"name": "keri dugan"},
+{"name": "don schwartz"},
+{"name": "chad duncan"},
+{"name": "roseanne brandon"},
+{"name": "paul valentine"},
+{"name": "helen reingold"},
+{"name": "christine finnigan"},
+{"name": "dan bergmann"},
+{"name": "linda coleman"},
+{"name": "joel ehler"},
+{"name": "jacob linares"},
+{"name": "christy ragland"},
+{"name": "sarah mcging"},
+{"name": "frank mao"},
+{"name": "tammy rock"},
+{"name": "carlos malone"},
+{"name": "katie c"},
+{"name": "george gramaglia"},
+{"name": "ellen clean"},
+{"name": "jason hertlein"},
+{"name": "dean odegaard"},
+{"name": "robert kleck"},
+{"name": "lynn keller"},
+{"name": "chris bradley"},
+{"name": "megan vasu"},
+{"name": "michelle robertson"},
+{"name": "james mora"},
+{"name": "corey tucker"},
+{"name": "ann chou"},
+{"name": "kate anderson"},
+{"name": "jennifer guerera"},
+{"name": "bill ladouceur"},
+{"name": "nancy martinez"},
+{"name": "kirk nervis"},
+{"name": "dale heintze"},
+{"name": "marc moens"},
+{"name": "grant jarvis"},
+{"name": "brian linver"},
+{"name": "michael smedley"},
+{"name": "ashley dill"},
+{"name": "timmy rich"},
+{"name": "pat frazer"},
+{"name": "joey hardrock"},
+{"name": "sandra blackhawk"},
+{"name": "danielle pulido"},
+{"name": "gary lang"},
+{"name": "ed galvin"},
+{"name": "shawn dumas"},
+{"name": "jim wilber"},
+{"name": "bo cell"},
+{"name": "nicolette brown"},
+{"name": "lou shipley"},
+{"name": "patrick bartlett"},
+{"name": "julianna rivas"},
+{"name": "demetrius hollingsworth"},
+{"name": "justin grim"},
+{"name": "marc schwartz"},
+{"name": "tim rep"},
+{"name": "james dorfman"},
+{"name": "vickie woznick"},
+{"name": "mark deeulio"},
+{"name": "robert nagel"},
+{"name": "rafael egurrola"},
+{"name": "oliver morris"},
+{"name": "krishna rangarajan"},
+{"name": "stuart smith"},
+{"name": "jazmine washington"},
+{"name": "tom laborde"},
+{"name": "dennis bever"},
+{"name": "alba llanes"},
+{"name": "hollis booker"},
+{"name": "lynn werle"},
+{"name": "tony muniz"},
+{"name": "stanley louis"},
+{"name": "don ferguson"},
+{"name": "alicia dove"},
+{"name": "david hunt"},
+{"name": "kevin francis"},
+{"name": "natalya sobolova"},
+{"name": "marvin reid"},
+{"name": "robert hathorn"},
+{"name": "keith smith"},
+{"name": "patrica yanez"},
+{"name": "shannon glass"},
+{"name": "ginger brazil"},
+{"name": "jay davis"},
+{"name": "michael henschell"},
+{"name": "pearl rose"},
+{"name": "dana berardi"},
+{"name": "ronnie jaquez"},
+{"name": "margaret kwan"},
+{"name": "bibi work"},
+{"name": "sandi shadbolt"},
+{"name": "debi raphael"},
+{"name": "tamar quintana"},
+{"name": "grady er"},
+{"name": "leon ricks"},
+{"name": "marvin mcmillan"},
+{"name": "joseph albergo"},
+{"name": "milford exterminating"},
+{"name": "francisco angara"},
+{"name": "daniel parks"},
+{"name": "cliff sara"},
+{"name": "eric spelley"},
+{"name": "amy socha"},
+{"name": "angie defilippi"},
+{"name": "adam l"},
+{"name": "scott murphy"},
+{"name": "jill mccoy"},
+{"name": "matt michig"},
+{"name": "april murray"},
+{"name": "greg santowski"},
+{"name": "phil composer"},
+{"name": "johnny greek"},
+{"name": "carrie poe"},
+{"name": "shauna carlson"},
+{"name": "ron carli"},
+{"name": "todd davisson"},
+{"name": "janet cross"},
+{"name": "george hessenthaler"},
+{"name": "veronika galvez"},
+{"name": "sarah huyck"},
+{"name": "craig tyler"},
+{"name": "carol bryja"},
+{"name": "michael zerbel"},
+{"name": "sean quintana"},
+{"name": "mario faria"},
+{"name": "cheryl denoi"},
+{"name": "kurt reiper"},
+{"name": "david bloom"},
+{"name": "herman terry"},
+{"name": "renae sommers"},
+{"name": "wally lynn"},
+{"name": "chad waltman"},
+{"name": "heidi rios"},
+{"name": "don caldera"},
+{"name": "jackie reese"},
+{"name": "justin lin"},
+{"name": "ronald johnson"},
+{"name": "lindsey mockenhaupt"},
+{"name": "david korse"},
+{"name": "walter miller"},
+{"name": "danny bullock"},
+{"name": "brian shuman"},
+{"name": "darla cook"},
+{"name": "ashley green"},
+{"name": "rob press"},
+{"name": "art klok"},
+{"name": "derek roe"},
+{"name": "eric mmv"},
+{"name": "carline lubin"},
+{"name": "sarah downstairs"},
+{"name": "katrina j"},
+{"name": "mara higgins"},
+{"name": "chad tomaszewski"},
+{"name": "frank castanea"},
+{"name": "sara knoester"},
+{"name": "todd parids"},
+{"name": "jeff sieber"},
+{"name": "jim bennitt"},
+{"name": "david croom"},
+{"name": "bobby chianese"},
+{"name": "freddy king"},
+{"name": "kimberly allen"},
+{"name": "paul backstrom"},
+{"name": "larry matthews"},
+{"name": "ellen scurlock"},
+{"name": "john mccready"},
+{"name": "andy hoopengardner"},
+{"name": "shin shibata"},
+{"name": "nancy cuz"},
+{"name": "pat neff"},
+{"name": "greg tallman"},
+{"name": "omar buford"},
+{"name": "carlos reteria"},
+{"name": "ron hillbrand"},
+{"name": "charles breyer"},
+{"name": "bryan rodriguez"},
+{"name": "jenny wagner"},
+{"name": "lee mattson"},
+{"name": "scot rosendahl"},
+{"name": "scott herrick"},
+{"name": "janet wilson"},
+{"name": "nancy mcintire"},
+{"name": "alicia getchius"},
+{"name": "jeffery boborwitz"},
+{"name": "nancy gakere"},
+{"name": "doug sturges"},
+{"name": "clinton weckesser"},
+{"name": "charlotte cain"},
+{"name": "tyler harmon"},
+{"name": "marshall eric"},
+{"name": "latonya coats"},
+{"name": "phyllis shank"},
+{"name": "natalie lawson"},
+{"name": "tamara cell"},
+{"name": "gary lucas"},
+{"name": "dominic digiacomo"},
+{"name": "sheila cell"},
+{"name": "rachel dyer"},
+{"name": "irene alvarado"},
+{"name": "erika castaneda"},
+{"name": "casey brady"},
+{"name": "bruce robinson"},
+{"name": "jo rogers"},
+{"name": "brenda salyers"},
+{"name": "kevin lunsgarten"},
+{"name": "john mullens"},
+{"name": "steve beermann"},
+{"name": "john sawyer"},
+{"name": "shawn hines"},
+{"name": "jan bootcheck"},
+{"name": "andy cook"},
+{"name": "eddie r"},
+{"name": "chad gates"},
+{"name": "donna thompson"},
+{"name": "dena danz"},
+{"name": "jeff larose"},
+{"name": "diane phillips"},
+{"name": "tracy ryan"},
+{"name": "gil pritt"},
+{"name": "marc porterfield"},
+{"name": "angie phillippi"},
+{"name": "rhiannon fiocchi"},
+{"name": "judy chaffe"},
+{"name": "dave bolanzia"},
+{"name": "craig olive"},
+{"name": "kimberly mckinzey"},
+{"name": "lakeshia davis"},
+{"name": "mike wysocki"},
+{"name": "heidi rozein"},
+{"name": "james monmouth"},
+{"name": "kelly spaulding"},
+{"name": "jamie banks"},
+{"name": "angela cleveland"},
+{"name": "cassandra hoye"},
+{"name": "kristi tyree"},
+{"name": "louis g"},
+{"name": "pat meek"},
+{"name": "kylie muir"},
+{"name": "forrest bao"},
+{"name": "nicole stogner"},
+{"name": "jackie marshall"},
+{"name": "rico barnes"},
+{"name": "joe mills"},
+{"name": "michael stansbury"},
+{"name": "walter statler"},
+{"name": "jeni fortunato"},
+{"name": "vicki wong"},
+{"name": "ed hope"},
+{"name": "keith stansfeild"},
+{"name": "karyn hunsaker"},
+{"name": "jack peterson"},
+{"name": "josh stowe"},
+{"name": "george pager"},
+{"name": "star crawford"},
+{"name": "joan grayman"},
+{"name": "matt miller"},
+{"name": "ken keith"},
+{"name": "ruth printer"},
+{"name": "pamella elaine"},
+{"name": "william zhe"},
+{"name": "cynthia wiseman"},
+{"name": "curt maki"},
+{"name": "nikki knafulc"},
+{"name": "chris gaffney"},
+{"name": "pete almazan"},
+{"name": "karen hays"},
+{"name": "john mohamad"},
+{"name": "jim schrader"},
+{"name": "miguel ayala"},
+{"name": "marie hayakawa"},
+{"name": "jim greco"},
+{"name": "stan bostwick"},
+{"name": "ryan grav"},
+{"name": "jessika jennings"},
+{"name": "carly engelbart"},
+{"name": "charlie matteson"},
+{"name": "john jackson"},
+{"name": "john lipscomb"},
+{"name": "ronald laing"},
+{"name": "kimberly segovia"},
+{"name": "margaret jacobs"},
+{"name": "chad hart"},
+{"name": "hannah tran"},
+{"name": "bryan kruskol"},
+{"name": "bruce gundersen"},
+{"name": "tony phillip"},
+{"name": "brian ford"},
+{"name": "lynn monaghan"},
+{"name": "kevin byrne"},
+{"name": "amanda w"},
+{"name": "greg astle"},
+{"name": "ted stumpf"},
+{"name": "michael luther"},
+{"name": "jacque derksen"},
+{"name": "jo salvestrini"},
+{"name": "gordon inman"},
+{"name": "jim dair"},
+{"name": "peggy horton"},
+{"name": "marshall hancock"},
+{"name": "grant hay"},
+{"name": "marlene edwards"},
+{"name": "josh white"},
+{"name": "ara bang"},
+{"name": "duncan card"},
+{"name": "adam galeon"},
+{"name": "aaron hinkle"},
+{"name": "james client"},
+{"name": "mark vandersall"},
+{"name": "lance cowart"},
+{"name": "scott papineau"},
+{"name": "michelle harwood"},
+{"name": "chris wright"},
+{"name": "shane downey"},
+{"name": "beatriz vasconez"},
+{"name": "angela schmidt"},
+{"name": "tyrell hickman"},
+{"name": "gary bisel"},
+{"name": "ryan kelly"},
+{"name": "daniel belanger"},
+{"name": "ed cumming"},
+{"name": "karina alves"},
+{"name": "sam simmons"},
+{"name": "german castillo"},
+{"name": "james wharburton"},
+{"name": "alvin cheng"},
+{"name": "patrick lynich"},
+{"name": "betty peralta"},
+{"name": "jeff lockyer"},
+{"name": "colby campbell"},
+{"name": "jenna holt"},
+{"name": "alyssa h"},
+{"name": "joey payne"},
+{"name": "jessica trudell"},
+{"name": "paul thompson"},
+{"name": "shane tenhet"},
+{"name": "shane sommers"},
+{"name": "marshall ford"},
+{"name": "eddie u"},
+{"name": "alfred habash"},
+{"name": "gwen brooks"},
+{"name": "anne putnam"},
+{"name": "lori nelson"},
+{"name": "debbie cohen"},
+{"name": "lisa vickers"},
+{"name": "taylor miller"},
+{"name": "judy zellen"},
+{"name": "parthenia terrace"},
+{"name": "meghan m"},
+{"name": "carey alcott"},
+{"name": "phyllis lichtenstein"},
+{"name": "shelly bar"},
+{"name": "teresa grice"},
+{"name": "john carline"},
+{"name": "michael galloway"},
+{"name": "bill blount"},
+{"name": "nancy macek"},
+{"name": "wendy mcintyre"},
+{"name": "kristi davis"},
+{"name": "joe arndt"},
+{"name": "kim giles"},
+{"name": "jim andritsch"},
+{"name": "bell mobility"},
+{"name": "pat dougherty"},
+{"name": "bill mccoy"},
+{"name": "patrick kelly"},
+{"name": "debbie roeske"},
+{"name": "greg lang"},
+{"name": "marc lipkin"},
+{"name": "emily saunders"},
+{"name": "stacey lundquist"},
+{"name": "jonathan stuffer"},
+{"name": "tammy brackett"},
+{"name": "chantelle aders"},
+{"name": "susan hadley"},
+{"name": "brett mosher"},
+{"name": "joel kellumns"},
+{"name": "neil cox"},
+{"name": "thresa eason"},
+{"name": "carmen montez"},
+{"name": "virginia forney"},
+{"name": "stephanie hansen"},
+{"name": "kenneth weiss"},
+{"name": "neal oliver"},
+{"name": "jane burson"},
+{"name": "philip cole"},
+{"name": "niki mercer"},
+{"name": "ralph lindenblatt"},
+{"name": "ron gelet"},
+{"name": "terry pyper"},
+{"name": "lee kell"},
+{"name": "erma tyson"},
+{"name": "susan infantino"},
+{"name": "karen lloyd"},
+{"name": "micheal prill"},
+{"name": "grady florida"},
+{"name": "pete filion"},
+{"name": "marie jones"},
+{"name": "robert garza"},
+{"name": "chong yen"},
+{"name": "don clapper"},
+{"name": "charles jobe"},
+{"name": "tom feeley"},
+{"name": "mark las"},
+{"name": "bill sonnhalter"},
+{"name": "jimmy bugarin"},
+{"name": "paul marshal"},
+{"name": "shannon valcich"},
+{"name": "anita t"},
+{"name": "brenda lake"},
+{"name": "irma hernandez"},
+{"name": "angela inman"},
+{"name": "ann schwartz"},
+{"name": "danielle pittman"},
+{"name": "michael kong"},
+{"name": "jeff skeldon"},
+{"name": "rick audette"},
+{"name": "melina alvarado"},
+{"name": "tom erickson"},
+{"name": "bobby chavez"},
+{"name": "pete ww"},
+{"name": "ramona mitchell"},
+{"name": "randy gascoigne"},
+{"name": "devorah tradburks"},
+{"name": "daniel magnusson"},
+{"name": "wes hodgson"},
+{"name": "richard c"},
+{"name": "roy stearns"},
+{"name": "kelly wauchope"},
+{"name": "min chester"},
+{"name": "ernest white"},
+{"name": "cody bonds"},
+{"name": "zoe cabral"},
+{"name": "mike flames"},
+{"name": "richard grey"},
+{"name": "joe bolley"},
+{"name": "jennifer peacock"},
+{"name": "kate guppy"},
+{"name": "stephan swanson"},
+{"name": "sam schlesinger"},
+{"name": "ken eheart"},
+{"name": "kristine joson"},
+{"name": "andy sykes"},
+{"name": "kirk hobart"},
+{"name": "hanh hanoi"},
+{"name": "albert einstein"},
+{"name": "evangeline alcantara"},
+{"name": "chris laffey"},
+{"name": "hugh bello"},
+{"name": "erin c"},
+{"name": "jess smith"},
+{"name": "danielle dowling"},
+{"name": "charles hunter"},
+{"name": "mark schonbrod"},
+{"name": "mike hammerslug"},
+{"name": "kimberly kirchner"},
+{"name": "andy coblentz"},
+{"name": "jeanette flowers"},
+{"name": "dick mendres"},
+{"name": "tim mahan"},
+{"name": "vickie home"},
+{"name": "eric maybaum"},
+{"name": "peter saliba"},
+{"name": "beth earls"},
+{"name": "diane hawkins"},
+{"name": "joey mekhayel"},
+{"name": "john chicarella"},
+{"name": "sarah stitz"},
+{"name": "debi barber"},
+{"name": "rachael hopper"},
+{"name": "mike flick"},
+{"name": "freddy zarka"},
+{"name": "marylynn lavigna"},
+{"name": "lynette sharaz"},
+{"name": "tyler holly"},
+{"name": "mariah j"},
+{"name": "suzanne clay"},
+{"name": "lanny billings"},
+{"name": "brian dengler"},
+{"name": "katie schaub"},
+{"name": "greg cook"},
+{"name": "jenny manbeck"},
+{"name": "jeremy fna"},
+{"name": "jeremy shephard"},
+{"name": "david mckay"},
+{"name": "charles gottlieb"},
+{"name": "ann schleicher"},
+{"name": "john maloney"},
+{"name": "spencer kuttler"},
+{"name": "simone sibert"},
+{"name": "ellen bodkins"},
+{"name": "shauna bcbg"},
+{"name": "michael winer"},
+{"name": "larry camp"},
+{"name": "ross levi"},
+{"name": "david greene"},
+{"name": "dan olschwang"},
+{"name": "miss amazin"},
+{"name": "chris robers"},
+{"name": "norma treague"},
+{"name": "craig newton"},
+{"name": "cherry yates"},
+{"name": "hugh bryan"},
+{"name": "lawrence fabian"},
+{"name": "tiffany mitchell"},
+{"name": "alan mcelroy"},
+{"name": "bob hensley"},
+{"name": "karen vehlow"},
+{"name": "george shindo"},
+{"name": "darrell hersey"},
+{"name": "ciara roseville"},
+{"name": "brian yeh"},
+{"name": "sherri coffman"},
+{"name": "paul hahn"},
+{"name": "bob cullen"},
+{"name": "trudy mcculloch"},
+{"name": "jan smith"},
+{"name": "annette olivia"},
+{"name": "steve iwcc"},
+{"name": "isaiah harris"},
+{"name": "linda bender"},
+{"name": "john h"},
+{"name": "todd webber"},
+{"name": "adam fivenson"},
+{"name": "joe cole"},
+{"name": "mark cell"},
+{"name": "nelson chui"},
+{"name": "zack bar"},
+{"name": "jeffrey dallas"},
+{"name": "derick takamine"},
+{"name": "daniel n"},
+{"name": "whitney strain"},
+{"name": "jane cusack"},
+{"name": "donna gray"},
+{"name": "randy moallankamp"},
+{"name": "mary riso"},
+{"name": "mark pedroncelli"},
+{"name": "tom nolan"},
+{"name": "chris patulis"},
+{"name": "bonnie choi"},
+{"name": "brian mcelfresh"},
+{"name": "eric olsen"},
+{"name": "neil merchantson"},
+{"name": "brooke clark"},
+{"name": "rebecca hodgers"},
+{"name": "wes hayden"},
+{"name": "alise churchill"},
+{"name": "tiffany parsons"},
+{"name": "craig peters"},
+{"name": "kieth kling"},
+{"name": "joel evans"},
+{"name": "larry lacey"},
+{"name": "bruce coll"},
+{"name": "lauren ashley"},
+{"name": "erick mccallister"},
+{"name": "brigid macdonald"},
+{"name": "al jon"},
+{"name": "jeff tropple"},
+{"name": "billy matranga"},
+{"name": "tim kay"},
+{"name": "ryan mcdonalds"},
+{"name": "kieth kruger"},
+{"name": "berna regalado"},
+{"name": "chris singer"},
+{"name": "donna argall"},
+{"name": "mark decker"},
+{"name": "chris karajanis"},
+{"name": "jon folsom"},
+{"name": "joshua son"},
+{"name": "michael lambert"},
+{"name": "richard behmke"},
+{"name": "todd tintorri"},
+{"name": "abel rodriguez"},
+{"name": "jeff lowe"},
+{"name": "alex abogado"},
+{"name": "mary hughes"},
+{"name": "tom romeo"},
+{"name": "dennis brown"},
+{"name": "rhonda hedtke"},
+{"name": "pat mcmackin"},
+{"name": "will broker"},
+{"name": "andreas labrakis"},
+{"name": "barbara mcmanus"},
+{"name": "don warnet"},
+{"name": "crystal kerr"},
+{"name": "mike downey"},
+{"name": "noel nitinthorn"},
+{"name": "chris abbott"},
+{"name": "tara kenyon"},
+{"name": "julia brannan"},
+{"name": "jason philips"},
+{"name": "wes harris"},
+{"name": "john tucker"},
+{"name": "brandon alltel"},
+{"name": "noelle richards"},
+{"name": "jim adelsick"},
+{"name": "andy ludcus"},
+{"name": "sherry xxxxx"},
+{"name": "sean woodard"},
+{"name": "jim parrett"},
+{"name": "jillian christison"},
+{"name": "terry mostrom"},
+{"name": "eddy rumps"},
+{"name": "mike shiner"},
+{"name": "susan odem"},
+{"name": "taylor howell"},
+{"name": "ryan wildman"},
+{"name": "brook olson"},
+{"name": "derek best"},
+{"name": "alyssa kaufman"},
+{"name": "keith white"},
+{"name": "dave allway"},
+{"name": "tony level"},
+{"name": "katie home"},
+{"name": "trudy sidener"},
+{"name": "logan shidawara"},
+{"name": "don home"},
+{"name": "tom jordan"},
+{"name": "tyler aiken"},
+{"name": "john chatowski"},
+{"name": "jackie model"},
+{"name": "donnie bledsoe"},
+{"name": "ray ny"},
+{"name": "robert jameson"},
+{"name": "jessica g'gf"},
+{"name": "daniel dooley"},
+{"name": "susan goldberg"},
+{"name": "alec lanari"},
+{"name": "dee martin"},
+{"name": "david bartley"},
+{"name": "jim mcdaniel"},
+{"name": "john munsey"},
+{"name": "laura eck"},
+{"name": "blake mcneill"},
+{"name": "kate donaldson"},
+{"name": "cheri peterson"},
+{"name": "mark short"},
+{"name": "dave loomba"},
+{"name": "anthony t"},
+{"name": "arturo rosales"},
+{"name": "jonathan grahm"},
+{"name": "shelley nix"},
+{"name": "richie cohen"},
+{"name": "ian prosser"},
+{"name": "dan loyer"},
+{"name": "ann goggins"},
+{"name": "tom ta"},
+{"name": "leslie hill"},
+{"name": "alejandro reyes"},
+{"name": "dan decker"},
+{"name": "brittany puffer"},
+{"name": "josephine irlbacher"},
+{"name": "bill moore"},
+{"name": "pedro zamora"},
+{"name": "timmy remi"},
+{"name": "andrew haddad"},
+{"name": "charles matthews"},
+{"name": "kathryn theissen"},
+{"name": "michele thomas"},
+{"name": "andy burton"},
+{"name": "alisha williams"},
+{"name": "omar duran"},
+{"name": "thelma jenkins"},
+{"name": "sheila schaffer"},
+{"name": "lenard tyndell"},
+{"name": "eddie ryono"},
+{"name": "vanessa kato"},
+{"name": "jeanie hernandez"},
+{"name": "jeff pryor"},
+{"name": "michael parsons"},
+{"name": "holly ordway"},
+{"name": "charlie kisner"},
+{"name": "phil cuomo"},
+{"name": "alma meli"},
+{"name": "jason hilkey"},
+{"name": "john baumert"},
+{"name": "jodi gabl"},
+{"name": "brooks salon"},
+{"name": "georgina hill"},
+{"name": "dan acheson"},
+{"name": "ginny adams"},
+{"name": "erica cooper"},
+{"name": "andrew norton"},
+{"name": "tammy meeks"},
+{"name": "kenneth rose"},
+{"name": "brandon fields"},
+{"name": "amy cell"},
+{"name": "chris cooper"},
+{"name": "rebecca trujillo"},
+{"name": "charlie garcia"},
+{"name": "pete schulz"},
+{"name": "vince mira"},
+{"name": "beth ufc"},
+{"name": "laura segarra"},
+{"name": "steven penn"},
+{"name": "alex cabrerra"},
+{"name": "richard gelinas"},
+{"name": "cheryl trout"},
+{"name": "terry calvin"},
+{"name": "randy shoemaker"},
+{"name": "josh gould"},
+{"name": "dan howell"},
+{"name": "desiree macias"},
+{"name": "mike herbold"},
+{"name": "mai n"},
+{"name": "becky jenks"},
+{"name": "ashton kovacs"},
+{"name": "dick nowacki"},
+{"name": "aaron band"},
+{"name": "vince zalapi"},
+{"name": "doug lenhoff"},
+{"name": "patty encinas"},
+{"name": "carlo madia"},
+{"name": "joy scott"},
+{"name": "vickey nguyen"},
+{"name": "lynn hillard"},
+{"name": "jonathan robinson"},
+{"name": "jenny brantlee"},
+{"name": "nick teusch"},
+{"name": "mike danyi"},
+{"name": "brent v"},
+{"name": "laura cherry"},
+{"name": "rodney zooyork"},
+{"name": "liz kress"},
+{"name": "ann olson"},
+{"name": "james flannery"},
+{"name": "donna lamarre"},
+{"name": "nadia chaudry"},
+{"name": "mindy parsons"},
+{"name": "charles cornwell"},
+{"name": "jay howell"},
+{"name": "chris chivers"},
+{"name": "bob chianese"},
+{"name": "sha ba"},
+{"name": "danny bubbli"},
+{"name": "frank frydrych"},
+{"name": "tony guard"},
+{"name": "bob ibuilder"},
+{"name": "michael mclntyre"},
+{"name": "jayna marques"},
+{"name": "ed altemeier"},
+{"name": "anette goldman"},
+{"name": "julio lucero"},
+{"name": "mark pingry"},
+{"name": "warren ragsdale"},
+{"name": "brain work"},
+{"name": "john stogis"},
+{"name": "aaron nameless"},
+{"name": "jacob chernov"},
+{"name": "glen rupe"},
+{"name": "alex stikhilyas"},
+{"name": "ahmad hazouri"},
+{"name": "max sports"},
+{"name": "len sisk"},
+{"name": "eric marriott"},
+{"name": "alice clark"},
+{"name": "deborah hall"},
+{"name": "drew webber"},
+{"name": "jennifer waters"},
+{"name": "mary eidson"},
+{"name": "gary perl"},
+{"name": "michelle gaona"},
+{"name": "ross finke"},
+{"name": "matt xxxxx"},
+{"name": "jonathan whitcomb"},
+{"name": "cheryl aubuchon"},
+{"name": "matt sharuga"},
+{"name": "tammy venkler"},
+{"name": "melanie longworth"},
+{"name": "scott michael"},
+{"name": "steve peck"},
+{"name": "bob falzone"},
+{"name": "joe roberts"},
+{"name": "craig roberts"},
+{"name": "brian fow"},
+{"name": "marcela rojas"},
+{"name": "angela carney"},
+{"name": "valerie grinman"},
+{"name": "alicia greene"},
+{"name": "wendy spradlin"},
+{"name": "jessica ball"},
+{"name": "frank lomax"},
+{"name": "mike consoli"},
+{"name": "adam ziccardi"},
+{"name": "ashley heb"},
+{"name": "greg hardester"},
+{"name": "sergio asef"},
+{"name": "aaron adams"},
+{"name": "andrew sh"},
+{"name": "mike lanigan"},
+{"name": "sam meraw"},
+{"name": "sherry walker"},
+{"name": "neville brathwaite"},
+{"name": "brad carson"},
+{"name": "bryan price"},
+{"name": "percy weathington"},
+{"name": "carlo power"},
+{"name": "roy lippman"},
+{"name": "matt luongo"},
+{"name": "kris olstead"},
+{"name": "walter snook"},
+{"name": "terry pollick"},
+{"name": "keith bricklemyer"},
+{"name": "billy canipe"},
+{"name": "jeff cuteboy"},
+{"name": "joyce lee"},
+{"name": "timmy cell"},
+{"name": "carmen sanders"},
+{"name": "james hunt"},
+{"name": "david frederick"},
+{"name": "jennifer lau"},
+{"name": "matt dempsey"},
+{"name": "sheila mccorvey"},
+{"name": "isabel buzby"},
+{"name": "robert castro"},
+{"name": "janet barnes"},
+{"name": "robert lucisano"},
+{"name": "william barbier"},
+{"name": "brian marks"},
+{"name": "ann herzog"},
+{"name": "cliff showell"},
+{"name": "keli johnston"},
+{"name": "nick parilla"},
+{"name": "kelly deviney"},
+{"name": "steve phoenix"},
+{"name": "kim q"},
+{"name": "flo tech"},
+{"name": "debra ledsinger"},
+{"name": "megan malone"},
+{"name": "ray repairs"},
+{"name": "noah jacobson"},
+{"name": "pam cab"},
+{"name": "jeff schick"},
+{"name": "erin berenson"},
+{"name": "ed ward"},
+{"name": "miranda bydone"},
+{"name": "michael bonanno"},
+{"name": "karen williams"},
+{"name": "anne o'brien"},
+{"name": "scott brodrick"},
+{"name": "king cell"},
+{"name": "jessica samson"},
+{"name": "charles allgood"},
+{"name": "greg rankin"},
+{"name": "terry mcdermott"},
+{"name": "april vasquez"},
+{"name": "andy coventry"},
+{"name": "garry canmore"},
+{"name": "alisha info"},
+{"name": "susie kladko"},
+{"name": "nelson jurica"},
+{"name": "merle nishimura"},
+{"name": "patrick carroll"},
+{"name": "sharon ringier"},
+{"name": "adam stever"},
+{"name": "jessica powelcup"},
+{"name": "jon ho"},
+{"name": "jennifer arellano"},
+{"name": "janine kurnoff"},
+{"name": "natalie mack"},
+{"name": "jarrod larocco"},
+{"name": "marty diebold"},
+{"name": "carol barroso"},
+{"name": "bill berry"},
+{"name": "michael morant"},
+{"name": "ted ozuna"},
+{"name": "robert weenig"},
+{"name": "allen chen"},
+{"name": "ty christensen"},
+{"name": "bennett wright"},
+{"name": "becky hoffer"},
+{"name": "byron dentler"},
+{"name": "jim rinke"},
+{"name": "jake birkholtz"},
+{"name": "duane oxenham"},
+{"name": "cathy mcgau"},
+{"name": "caroline parent"},
+{"name": "alma rivera"},
+{"name": "gay brian"},
+{"name": "nancy vandergrift"},
+{"name": "bill parkerson"},
+{"name": "mark bonacci"},
+{"name": "ron cole"},
+{"name": "dina raniga"},
+{"name": "florence russell"},
+{"name": "david sommer"},
+{"name": "brandon ny"},
+{"name": "paul larsen"},
+{"name": "diego g"},
+{"name": "danielle korba"},
+{"name": "andy roberts"},
+{"name": "andrew vogt"},
+{"name": "sharron huffman"},
+{"name": "sam kiefer"},
+{"name": "mike toxic"},
+{"name": "nick weinart"},
+{"name": "laurie flynn"},
+{"name": "mary vallesteros"},
+{"name": "angelica garcia"},
+{"name": "donovan morrison"},
+{"name": "amy catlet"},
+{"name": "ralph peterson"},
+{"name": "lia hicks"},
+{"name": "angel gonzalez"},
+{"name": "tim dunleavy"},
+{"name": "tim heinze"},
+{"name": "john redstone"},
+{"name": "katie dorn"},
+{"name": "lorraine o'leary"},
+{"name": "steve vollhardt"},
+{"name": "dan brabec"},
+{"name": "sandra chaffin"},
+{"name": "cory skillern"},
+{"name": "dwayne blackamore"},
+{"name": "kathryn pendergast"},
+{"name": "glen thorne"},
+{"name": "brent jones"},
+{"name": "karen buck"},
+{"name": "richard gomberg"},
+{"name": "john copenhaver"},
+{"name": "zenobia ealey"},
+{"name": "george harrison"},
+{"name": "emilie paige"},
+{"name": "austin haye"},
+{"name": "peter mitrik"},
+{"name": "sue schwegler"},
+{"name": "jake hall"},
+{"name": "tom learman"},
+{"name": "julie bridge"},
+{"name": "don brodnansky"},
+{"name": "richard graber"},
+{"name": "mary treadway"},
+{"name": "ross ludwig"},
+{"name": "mark bornstein"},
+{"name": "cheryl bielema"},
+{"name": "dave spence"},
+{"name": "mary anna"},
+{"name": "darryl stamper"},
+{"name": "matt grove"},
+{"name": "kitty hailey"},
+{"name": "jo harris"},
+{"name": "joel johnson"},
+{"name": "katina ahrenholtz"},
+{"name": "julia robertson"},
+{"name": "anna ward"},
+{"name": "chris herndon"},
+{"name": "christine cummings"},
+{"name": "tommy iorizzo"},
+{"name": "dave ruelas"},
+{"name": "jayme rea"},
+{"name": "sue kinch"},
+{"name": "joe ocasio"},
+{"name": "jenni steel"},
+{"name": "grace simmons"},
+{"name": "charles estell"},
+{"name": "tammy almond"},
+{"name": "erika kirkland"},
+{"name": "scott hedrick"},
+{"name": "will att"},
+{"name": "christopher suknundun"},
+{"name": "elizabeth rybicki"},
+{"name": "karl shannon"},
+{"name": "dan karp"},
+{"name": "john kirk"},
+{"name": "mike bianco"},
+{"name": "ana sandoval"},
+{"name": "josh valk"},
+{"name": "martin glick"},
+{"name": "kaylee l"},
+{"name": "marvin estes"},
+{"name": "dudley beene"},
+{"name": "jennifer bianchini"},
+{"name": "ronnie burrough"},
+{"name": "joe lipman"},
+{"name": "leslie kight"},
+{"name": "bobby loco"},
+{"name": "wesley woods"},
+{"name": "eddie dulles"},
+{"name": "mary hunter"},
+{"name": "mark remey"},
+{"name": "henry ortega"},
+{"name": "robby overvliet"},
+{"name": "gary keller"},
+{"name": "peter schwartz"},
+{"name": "tony bouffard"},
+{"name": "paul doroshuk"},
+{"name": "moshe stutman"},
+{"name": "jessica stout"},
+{"name": "scott mcgill"},
+{"name": "kristi bitoff"},
+{"name": "todd peters"},
+{"name": "robert marples"},
+{"name": "matthew cannon"},
+{"name": "dianne kron"},
+{"name": "adam goldstien"},
+{"name": "todd wilkenson"},
+{"name": "grace balaoro"},
+{"name": "tyrone dipset"},
+{"name": "danny pentin"},
+{"name": "oliver lei"},
+{"name": "jerry schmeiling"},
+{"name": "charles clawson"},
+{"name": "matt pof"},
+{"name": "david wilkes"},
+{"name": "rob woolley"},
+{"name": "georgia strong"},
+{"name": "jennifer pearson"},
+{"name": "stan brown"},
+{"name": "kristen pensivy"},
+{"name": "john marovic"},
+{"name": "david stanton"},
+{"name": "steven copen"},
+{"name": "wade johnson"},
+{"name": "david drews"},
+{"name": "brent priday"},
+{"name": "carolyn zucker"},
+{"name": "tony saiz"},
+{"name": "andres rodriguez"},
+{"name": "bryan lederhouse"},
+{"name": "kit bruce"},
+{"name": "dannielle sidekick"},
+{"name": "bob klee"},
+{"name": "terry stepps"},
+{"name": "lana mareca"},
+{"name": "art landis"},
+{"name": "michael willet"},
+{"name": "jose felix"},
+{"name": "paul survival"},
+{"name": "bruce barnet"},
+{"name": "karla wynia"},
+{"name": "eddie vargas"},
+{"name": "anja eggenberger"},
+{"name": "tyler gma"},
+{"name": "kristen wilkes"},
+{"name": "jenna kootstra"},
+{"name": "glenda luft"},
+{"name": "cathy pierce"},
+{"name": "nicole stewart"},
+{"name": "carrie lynn"},
+{"name": "brian roe"},
+{"name": "kyle scott"},
+{"name": "michelle minchew"},
+{"name": "marvin brooks"},
+{"name": "richard sones"},
+{"name": "joseph dimaio"},
+{"name": "andrea wooten"},
+{"name": "ashley q"},
+{"name": "paul cuttingham"},
+{"name": "shelley smith"},
+{"name": "andre lane"},
+{"name": "marcia barkoff"},
+{"name": "carrie steele"},
+{"name": "paul callis"},
+{"name": "chin rodney"},
+{"name": "pauline david"},
+{"name": "devin marquez{v}"},
+{"name": "monique rush"},
+{"name": "kareem hudson"},
+{"name": "dean flowers"},
+{"name": "frank jones"},
+{"name": "jack henderson"},
+{"name": "mary leon"},
+{"name": "danny butler"},
+{"name": "jose mendosa"},
+{"name": "carolyn adler"},
+{"name": "robert reaney"},
+{"name": "steve barrys"},
+{"name": "debra marr"},
+{"name": "fred godinez"},
+{"name": "tim price"},
+{"name": "frank mirra"},
+{"name": "sarah matt"},
+{"name": "john cumpstone"},
+{"name": "linda msg"},
+{"name": "gene wheeler"},
+{"name": "john rudder"},
+{"name": "betty gordon"},
+{"name": "paul dottori"},
+{"name": "granville rocksolid"},
+{"name": "kevin lutz"},
+{"name": "jay keebler"},
+{"name": "larry laduke"},
+{"name": "john bilson"},
+{"name": "danny mercado"},
+{"name": "william tansey"},
+{"name": "rob cross"},
+{"name": "johnnie pike"},
+{"name": "joe cassin"},
+{"name": "phyllis pardue"},
+{"name": "mike potapov"},
+{"name": "sue marino"},
+{"name": "andrew steeves"},
+{"name": "graham best"},
+{"name": "john pentecost"},
+{"name": "patty facio"},
+{"name": "ada dentistry"},
+{"name": "dennis nowakowski"},
+{"name": "andrew potthoff"},
+{"name": "michael hernandez"},
+{"name": "eric lara"},
+{"name": "stephen welsh"},
+{"name": "sheila coleman"},
+{"name": "robin templeton"},
+{"name": "alvin paulino"},
+{"name": "dan cotherman"},
+{"name": "eric lorenz"},
+{"name": "pierre tremblay"},
+{"name": "amanda fox"},
+{"name": "ruth weldon"},
+{"name": "shawn boire"},
+{"name": "thomas dunphy"},
+{"name": "hannah jenkins"},
+{"name": "lucas driscoll"},
+{"name": "elizabeth bakanic"},
+{"name": "jason mateo"},
+{"name": "clayton stauss"},
+{"name": "steve zimmerman"},
+{"name": "winnie chung"},
+{"name": "jessica witt"},
+{"name": "anne boychuck"},
+{"name": "mike howard"},
+{"name": "julie yamauichi"},
+{"name": "alan whitley"},
+{"name": "viki gallentine"},
+{"name": "corrinne korzen"},
+{"name": "jesse mccormick"},
+{"name": "tracy stanford"},
+{"name": "joseph work"},
+{"name": "stephanie cuz"},
+{"name": "jake hodges"},
+{"name": "scotty mac"},
+{"name": "george kliavkoff"},
+{"name": "eugenia munoz"},
+{"name": "brady thomas"},
+{"name": "richard morehouse"},
+{"name": "terry klingerman"},
+{"name": "forrest brooks"},
+{"name": "andrew feinberg"},
+{"name": "rebecca muniz"},
+{"name": "john davenport"},
+{"name": "scott ulmer"},
+{"name": "stacy kroq"},
+{"name": "ashley holt"},
+{"name": "mark western"},
+{"name": "vicky ledoux"},
+{"name": "gordon blomgren"},
+{"name": "jan portage"},
+{"name": "blair r"},
+{"name": "james scanlan"},
+{"name": "kathy pang"},
+{"name": "judy lanyon"},
+{"name": "jill carson"},
+{"name": "jodi freeo"},
+{"name": "gail s"},
+{"name": "eric glick"},
+{"name": "dave garloff"},
+{"name": "noreen parrish"},
+{"name": "tom supr"},
+{"name": "david stalling"},
+{"name": "stan wardwell"},
+{"name": "eric schweighoffer"},
+{"name": "matt labow"},
+{"name": "esther lee"},
+{"name": "rick saskatchewan"},
+{"name": "william velez"},
+{"name": "charles cooper"},
+{"name": "paula purifoy"},
+{"name": "kacey picine"},
+{"name": "dave o'donnel"},
+{"name": "marti stanton"},
+{"name": "martina jecker"},
+{"name": "kori bernardino"},
+{"name": "betty flowers"},
+{"name": "anna newton"},
+{"name": "bonnie drake"},
+{"name": "caitlin dulles"},
+{"name": "jim padilla"},
+{"name": "jose campero"},
+{"name": "mike evans"},
+{"name": "steven lurie"},
+{"name": "alphonso sastre"},
+{"name": "lisa proveaux"},
+{"name": "jimmy mays"},
+{"name": "benny yisrael"},
+{"name": "autumn barrett"},
+{"name": "alicia bruce"},
+{"name": "mark effron"},
+{"name": "tim chutz"},
+{"name": "carlene simon"},
+{"name": "dan proctor"},
+{"name": "andy chicago"},
+{"name": "robin switzenbaum"},
+{"name": "crystal dickerson"},
+{"name": "delta flt"},
+{"name": "aldo difelice"},
+{"name": "gina torres"},
+{"name": "jenna yarborough"},
+{"name": "david friedman"},
+{"name": "peter wendell"},
+{"name": "david carr"},
+{"name": "bernie weston"},
+{"name": "drew echelson"},
+{"name": "melissa alves"},
+{"name": "crystal mtn"},
+{"name": "liz paternotte"},
+{"name": "tracey maier"},
+{"name": "rubin jeff"},
+{"name": "ben shalom"},
+{"name": "deborah horn"},
+{"name": "brian elko"},
+{"name": "kathleen schneider"},
+{"name": "hannah randoja"},
+{"name": "joel pollack"},
+{"name": "marcus barnes"},
+{"name": "corey carlson"},
+{"name": "matt perron"},
+{"name": "josh schema"},
+{"name": "jason deny"},
+{"name": "bob vanna"},
+{"name": "scott morse"},
+{"name": "jae lim"},
+{"name": "mary lindsey"},
+{"name": "brian rien"},
+{"name": "chris swanson"},
+{"name": "michelle windward"},
+{"name": "ed stalder"},
+{"name": "joe pearson"},
+{"name": "juanita small"},
+{"name": "alisha marie"},
+{"name": "allen martin"},
+{"name": "sean santore"},
+{"name": "amy johnson"},
+{"name": "henry scheiner"},
+{"name": "ellen alexander"},
+{"name": "chrissy wise"},
+{"name": "chris bjorklund"},
+{"name": "lisa garrison"},
+{"name": "mike hardrick"},
+{"name": "carlos segura"},
+{"name": "ann amaru"},
+{"name": "brad arnold"},
+{"name": "matt kronish"},
+{"name": "brian boll"},
+{"name": "paul buschur"},
+{"name": "jessica brett's"},
+{"name": "stephen medley"},
+{"name": "ted fitzpatrick"},
+{"name": "kelly oosbree"},
+{"name": "bailey hulin"},
+{"name": "steven lancaster"},
+{"name": "beth foose"},
+{"name": "john allgair"},
+{"name": "connie dunn"},
+{"name": "lori goracke"},
+{"name": "ashley kotch"},
+{"name": "mike liebel"},
+{"name": "robin davis"},
+{"name": "molly solbach"},
+{"name": "george group"},
+{"name": "ronald lindsay"},
+{"name": "nick bmw"},
+{"name": "chelsea hooters"},
+{"name": "michael besson"},
+{"name": "gordon lederman"},
+{"name": "kelly paine"},
+{"name": "chris sopithakul"},
+{"name": "patrick broxterman"},
+{"name": "kym gloff"},
+{"name": "kyle lucis"},
+{"name": "larry mchugh"},
+{"name": "dayna schuessler"},
+{"name": "neal hersh"},
+{"name": "kate bluralz"},
+{"name": "lori sorrells"},
+{"name": "john chavez"},
+{"name": "michelle birthwright"},
+{"name": "josh liang"},
+{"name": "helen sievers"},
+{"name": "will s"},
+{"name": "greg engbretson"},
+{"name": "dannie jenkins"},
+{"name": "ashley gonzalez"},
+{"name": "carmen uop"},
+{"name": "ben forer"},
+{"name": "linda chesney"},
+{"name": "vanessa work"},
+{"name": "daniel godbout"},
+{"name": "erin shewchuck"},
+{"name": "jeremy schmidt"},
+{"name": "don eastman"},
+{"name": "karen macintosh"},
+{"name": "richie mac"},
+{"name": "willy robinson"},
+{"name": "cathy harbottle"},
+{"name": "jamie tramp"},
+{"name": "dean swett"},
+{"name": "ryan caraballo"},
+{"name": "aaron ward"},
+{"name": "greg h"},
+{"name": "murray knecht"},
+{"name": "ariel richer"},
+{"name": "melissa chew"},
+{"name": "tony mazy"},
+{"name": "joe grimes"},
+{"name": "andre alston"},
+{"name": "maggie home"},
+{"name": "michael keith"},
+{"name": "greg film"},
+{"name": "nancy richardson"},
+{"name": "thomas jennings"},
+{"name": "brittany flug"},
+{"name": "sonya muzyca"},
+{"name": "tony huge"},
+{"name": "jeff letterman"},
+{"name": "rose roberts"},
+{"name": "laura miami"},
+{"name": "ruth carew"},
+{"name": "jann olsten"},
+{"name": "ken kawakami"},
+{"name": "matt aeschlimann"},
+{"name": "steve cooke"},
+{"name": "janice nice"},
+{"name": "cory roehl"},
+{"name": "gayle cost"},
+{"name": "chris mcfarland"},
+{"name": "wade armentrout"},
+{"name": "joy hastings"},
+{"name": "alyssa hollman"},
+{"name": "brad brooks"},
+{"name": "steve winick"},
+{"name": "don zucco"},
+{"name": "john ireland"},
+{"name": "scott meehan"},
+{"name": "gene mcelhaney"},
+{"name": "daniel solomon"},
+{"name": "vincent o'donnell"},
+{"name": "lilli hadselk"},
+{"name": "armand hhc"},
+{"name": "chuck cleary"},
+{"name": "angie kail"},
+{"name": "reggie susanto"},
+{"name": "jackson hardage"},
+{"name": "brent markham"},
+{"name": "larry arendt"},
+{"name": "ian adams"},
+{"name": "brian cournoyer"},
+{"name": "karen indiana"},
+{"name": "thomas bersani"},
+{"name": "logan wilcox"},
+{"name": "luis staples"},
+{"name": "john vzw"},
+{"name": "ron engleman"},
+{"name": "jennifer brauer"},
+{"name": "andy grill"},
+{"name": "carol franket"},
+{"name": "willie baily"},
+{"name": "roberto molina"},
+{"name": "richard whittaker"},
+{"name": "toni walker"},
+{"name": "crystal jones"},
+{"name": "rich gilmore"},
+{"name": "john ferris"},
+{"name": "howard kiem"},
+{"name": "britney monroe"},
+{"name": "corey smith"},
+{"name": "andrew meister"},
+{"name": "patrick anstaett"},
+{"name": "jennifer moreno"},
+{"name": "beth rush"},
+{"name": "ed mclarty"},
+{"name": "mark barry"},
+{"name": "kerri kuster"},
+{"name": "dave matre"},
+{"name": "farrah shyer"},
+{"name": "brenda henshaw"},
+{"name": "chad lyke"},
+{"name": "camille spitzer"},
+{"name": "heather orr"},
+{"name": "claudia zapata"},
+{"name": "rolland thomason"},
+{"name": "dallas bbq"},
+{"name": "lisa kranabetter"},
+{"name": "emily taylor"},
+{"name": "fred neville"},
+{"name": "patricia mohar"},
+{"name": "jennifer martin"},
+{"name": "ted dintersmith"},
+{"name": "sonny connell"},
+{"name": "eric tran"},
+{"name": "betty dowling"},
+{"name": "sara ambriz"},
+{"name": "kyle obrein"},
+{"name": "scott kershaw"},
+{"name": "linda fisher"},
+{"name": "michelle navarro"},
+{"name": "terry mendenhall"},
+{"name": "francine madera"},
+{"name": "chris giffen"},
+{"name": "joann lagman"},
+{"name": "heather meadows"},
+{"name": "elizabeth menius"},
+{"name": "tim hutchins"},
+{"name": "alex impala"},
+{"name": "scott tenhulzen"},
+{"name": "rosalba rios"},
+{"name": "ashley perkins"},
+{"name": "derrick hansford"},
+{"name": "jeffrey strahan"},
+{"name": "lindsey paschal"},
+{"name": "pete voss"},
+{"name": "milton agurs"},
+{"name": "julianna sanchez"},
+{"name": "chelsea k"},
+{"name": "catherine lifeso"},
+{"name": "joe gerez"},
+{"name": "tara price"},
+{"name": "steve liberty"},
+{"name": "gregg wolin"},
+{"name": "susan delgado"},
+{"name": "charles sims"},
+{"name": "rachael billingsly"},
+{"name": "matt yuhas"},
+{"name": "judson murray"},
+{"name": "sarah hersack"},
+{"name": "brett satterlee"},
+{"name": "daniel desimone"},
+{"name": "josh eisenstat"},
+{"name": "kim henderson"},
+{"name": "margie charles"},
+{"name": "lily liu"},
+{"name": "jeff herda"},
+{"name": "jeff christenson"},
+{"name": "lee lou"},
+{"name": "tina dahlquist"},
+{"name": "juan estrada"},
+{"name": "rachel porn"},
+{"name": "pat mcgowan"},
+{"name": "christina briana"},
+{"name": "billie sanchez"},
+{"name": "jessica stowell"},
+{"name": "kathy prince"},
+{"name": "jim courier"},
+{"name": "michael k"},
+{"name": "nick s"},
+{"name": "eleanor pemper"},
+{"name": "ben constance"},
+{"name": "jake dogeye"},
+{"name": "andrea ronderos"},
+{"name": "pedro valdez"},
+{"name": "karri mange"},
+{"name": "gene botto"},
+{"name": "peter kutrubes"},
+{"name": "yen do"},
+{"name": "jon muller"},
+{"name": "joan collins"},
+{"name": "michele solis"},
+{"name": "joseph naegle"},
+{"name": "peggy froloc"},
+{"name": "lorena d'gala"},
+{"name": "dave beers"},
+{"name": "andrew floyd"},
+{"name": "jaclyn oribello"},
+{"name": "dale stubblefield"},
+{"name": "nick vanderwal"},
+{"name": "shawn nicoll"},
+{"name": "clay cell"},
+{"name": "jill barella"},
+{"name": "tyrone humphrey"},
+{"name": "harry randoph"},
+{"name": "vivian sapirman"},
+{"name": "sarah mabey"},
+{"name": "shannon fink"},
+{"name": "kay maples"},
+{"name": "kenneth clyat"},
+{"name": "darrin joncas"},
+{"name": "jess baker"},
+{"name": "becky bishop"},
+{"name": "michael hildebrandt"},
+{"name": "summer m"},
+{"name": "rodney bruce"},
+{"name": "lino solis"},
+{"name": "joseph herzog"},
+{"name": "mike mannix"},
+{"name": "sara lee"},
+{"name": "lori groves"},
+{"name": "mickey trigilio"},
+{"name": "gail dorfman"},
+{"name": "matt noon"},
+{"name": "scott henry"},
+{"name": "wanda oakey"},
+{"name": "todd lutz"},
+{"name": "liz pomish"},
+{"name": "karen stallone"},
+{"name": "richard l"},
+{"name": "jacqueline winkler"},
+{"name": "rochel shields"},
+{"name": "wes brown"},
+{"name": "jerry fishing"},
+{"name": "dawn spale"},
+{"name": "paul talcott"},
+{"name": "aron rosen"},
+{"name": "john gilbaugh"},
+{"name": "james fastrak"},
+{"name": "lynn boiter"},
+{"name": "vincent rioux"},
+{"name": "claudia majestic"},
+{"name": "tammy hadley"},
+{"name": "richard pearce"},
+{"name": "mike guarino"},
+{"name": "carlos valdeblanquez"},
+{"name": "bobby coyle"},
+{"name": "kathy mabry"},
+{"name": "rachel grafstein"},
+{"name": "steven moody"},
+{"name": "david enid"},
+{"name": "lynn ledonois"},
+{"name": "tracy ferrier"},
+{"name": "pamela friedman"},
+{"name": "al rotker"},
+{"name": "joe joe"},
+{"name": "beth thompson"},
+{"name": "otha motha"},
+{"name": "gregory perrone"},
+{"name": "lori brooks"},
+{"name": "mike saenz"},
+{"name": "celeste mclaughlin"},
+{"name": "duane fulps"},
+{"name": "evelyn sharp"},
+{"name": "noel vega"},
+{"name": "julie lewis"},
+{"name": "mark olson"},
+{"name": "tom odell"},
+{"name": "andrea andrea"},
+{"name": "suzann brantner"},
+{"name": "steve maker"},
+{"name": "beth jardina"},
+{"name": "elise pratt"},
+{"name": "brad terk"},
+{"name": "shaina wiess"},
+{"name": "alice ribs"},
+{"name": "denny reed"},
+{"name": "steve oliver"},
+{"name": "molly johnson"},
+{"name": "lee parish"},
+{"name": "chang tnt"},
+{"name": "sierra med"},
+{"name": "sara caldeira"},
+{"name": "michael rueb"},
+{"name": "keri honda"},
+{"name": "genie gavenchack"},
+{"name": "sharon mclean"},
+{"name": "stacy macbeth"},
+{"name": "beth conley"},
+{"name": "ryan thune"},
+{"name": "mike raffell"},
+{"name": "karen jost"},
+{"name": "ron sauer"},
+{"name": "sarah patterson"},
+{"name": "harold harris"},
+{"name": "willie p"},
+{"name": "ruth lane"},
+{"name": "ron jennings"},
+{"name": "dawn schmitt"},
+{"name": "bradley fisher"},
+{"name": "phillip taylor"},
+{"name": "nikki l"},
+{"name": "mike gillespie"},
+{"name": "robert cotner"},
+{"name": "thomas dibiase"},
+{"name": "charles sr"},
+{"name": "melissa meyers"},
+{"name": "anna white"},
+{"name": "vanesa ayala"},
+{"name": "gene chandler"},
+{"name": "carlos montem"},
+{"name": "anita wieduwilt"},
+{"name": "nathan heald"},
+{"name": "antony uncle"},
+{"name": "steve falcon"},
+{"name": "lawrence d"},
+{"name": "jeremy ng"},
+{"name": "donna jaggers"},
+{"name": "harley rubin"},
+{"name": "daniel fernandez"},
+{"name": "ed pinegar"},
+{"name": "katy zanville"},
+{"name": "jon dimalante"},
+{"name": "jessica morales"},
+{"name": "lionel gracia"},
+{"name": "frank atwood"},
+{"name": "toney t"},
+{"name": "damon gammage"},
+{"name": "randy jones"},
+{"name": "matt rutherford"},
+{"name": "john dalfior"},
+{"name": "michele miyashiro"},
+{"name": "brenda k"},
+{"name": "greg bagley"},
+{"name": "doug boyles"},
+{"name": "alice wachol"},
+{"name": "kelly slow"},
+{"name": "frank hayes"},
+{"name": "joseph shamirizadi"},
+{"name": "rich martinez"},
+{"name": "john sinnott"},
+{"name": "sue witt"},
+{"name": "jin kim"},
+{"name": "bill so"},
+{"name": "karen wilcox"},
+{"name": "diane farrell"},
+{"name": "mark sawyer"},
+{"name": "mark beccue"},
+{"name": "amanda roe"},
+{"name": "andy hech"},
+{"name": "ian clement"},
+{"name": "sam ni"},
+{"name": "bob mcgough"},
+{"name": "brian mccomas"},
+{"name": "mary knobler"},
+{"name": "patrick angel"},
+{"name": "matt kury"},
+{"name": "niki brunswick"},
+{"name": "robert xxxxx"},
+{"name": "bernard lord"},
+{"name": "debra fuess"},
+{"name": "mike mccormick"},
+{"name": "david lezak"},
+{"name": "sarah hobbs"},
+{"name": "tim hudson"},
+{"name": "brad dittmer"},
+{"name": "peter worley"},
+{"name": "bo silvia"},
+{"name": "joe chin"},
+{"name": "richard ann"},
+{"name": "kenny ellis"},
+{"name": "mathew krause"},
+{"name": "keith stogdell"},
+{"name": "barb kayter"},
+{"name": "tom boyce"},
+{"name": "dwayne richardson"},
+{"name": "steve roper"},
+{"name": "heidi brooker"},
+{"name": "becky powell"},
+{"name": "erica andreski"},
+{"name": "melissa wallenbeck"},
+{"name": "mac report"},
+{"name": "paul hershiser"},
+{"name": "scott norris"},
+{"name": "christine utica"},
+{"name": "sean katz"},
+{"name": "john schumacher"},
+{"name": "nick carlson"},
+{"name": "gail bassett"},
+{"name": "john dolmage"},
+{"name": "joan francis"},
+{"name": "domenic maggio"},
+{"name": "pamela duncan"},
+{"name": "paul bessent"},
+{"name": "karl gotlieb"},
+{"name": "vincent mcclendon"},
+{"name": "richard zachar"},
+{"name": "glen weddell"},
+{"name": "rick shrotri"},
+{"name": "mike jingozian"},
+{"name": "ryan herbert"},
+{"name": "william batzkall"},
+{"name": "nancy mileikis"},
+{"name": "robin nicole"},
+{"name": "tim burkhead"},
+{"name": "martha johnson"},
+{"name": "phil machek"},
+{"name": "ami schwab"},
+{"name": "courtney leak"},
+{"name": "rachel goodman"},
+{"name": "robby cox"},
+{"name": "stephen laroco"},
+{"name": "sarah rocano"},
+{"name": "chris gioffre"},
+{"name": "katie webber"},
+{"name": "jamie kavalieros"},
+{"name": "scott packam"},
+{"name": "page jr"},
+{"name": "danny victoriano"},
+{"name": "kyle kinzy"},
+{"name": "neal takai"},
+{"name": "christian mendoza"},
+{"name": "kenneth heulitt"},
+{"name": "pat determan"},
+{"name": "tom malone"},
+{"name": "lou mussman"},
+{"name": "isaac gowon"},
+{"name": "peter browm"},
+{"name": "james marchesani"},
+{"name": "don troyer"},
+{"name": "theresa irwin"},
+{"name": "janice moore"},
+{"name": "rudy villalobos"},
+{"name": "karen modesitt"},
+{"name": "juan home"},
+{"name": "chris cramer"},
+{"name": "sam arcilla"},
+{"name": "sean gindo"},
+{"name": "marsha roniece"},
+{"name": "pat hines"},
+{"name": "joe bellio"},
+{"name": "carl casper"},
+{"name": "brandon bogue"},
+{"name": "nicola gandossi"},
+{"name": "michael durden"},
+{"name": "warren davis"},
+{"name": "john elias"},
+{"name": "mike pro"},
+{"name": "don griego"},
+{"name": "greg brenda"},
+{"name": "corey j"},
+{"name": "josh stephenson"},
+{"name": "dino chiesa"},
+{"name": "eric farber"},
+{"name": "alex nudell"},
+{"name": "anna mchargue"},
+{"name": "ron allchin"},
+{"name": "patrick symmester"},
+{"name": "tom karson"},
+{"name": "lee hirsch"},
+{"name": "charles shean"},
+{"name": "lana leslie"},
+{"name": "debi parker"},
+{"name": "bart cavanaugh"},
+{"name": "anna roberts"},
+{"name": "santo dodaro"},
+{"name": "bill herlihy"},
+{"name": "joella ellis"},
+{"name": "kenny tapahanoc"},
+{"name": "dwight mexico"},
+{"name": "adam younger"},
+{"name": "martin loewengart"},
+{"name": "cindy mackay"},
+{"name": "becky cottrell"},
+{"name": "don santoski"},
+{"name": "jim folkman"},
+{"name": "george bing"},
+{"name": "gwen larson"},
+{"name": "mariah burnett"},
+{"name": "nita cook"},
+{"name": "andre lalande"},
+{"name": "kim dyches"},
+{"name": "rosemary sanci"},
+{"name": "amy willis"},
+{"name": "paul minsky"},
+{"name": "robin sutherland"},
+{"name": "david kimbell"},
+{"name": "brooks marvin"},
+{"name": "chuck langley"},
+{"name": "ron cooper"},
+{"name": "richard stahl"},
+{"name": "nelson lee"},
+{"name": "krista cleary"},
+{"name": "tina garfolo"},
+{"name": "steve bechthold"},
+{"name": "cathy raffeto"},
+{"name": "willie iannucci"},
+{"name": "tanya gallegos"},
+{"name": "janie donaldson"},
+{"name": "cecil leffel"},
+{"name": "tim fugate"},
+{"name": "tony isaacs"},
+{"name": "chelsea moran"},
+{"name": "lee fortney"},
+{"name": "jackie hardy"},
+{"name": "jeff marks"},
+{"name": "christine hernandez"},
+{"name": "john kibble"},
+{"name": "sandra carson"},
+{"name": "lee caron"},
+{"name": "jimmy butch"},
+{"name": "pat wickenhauser"},
+{"name": "nathan traughber"},
+{"name": "floyd krengel"},
+{"name": "steve levenson"},
+{"name": "bernie parsons"},
+{"name": "cindy filipinas"},
+{"name": "john prickett"},
+{"name": "raphael phillips"},
+{"name": "john palmquist"},
+{"name": "margaret o'donnell"},
+{"name": "libby knudson"},
+{"name": "marc primo"},
+{"name": "rob howard"},
+{"name": "austin cook"},
+{"name": "shelley broader"},
+{"name": "ian goldston"},
+{"name": "jessica mckinley"},
+{"name": "teresa brian"},
+{"name": "catherine snow"},
+{"name": "leo heinert"},
+{"name": "jamie lindberg"},
+{"name": "larry shipley"},
+{"name": "lisa kissinger"},
+{"name": "santana dennis"},
+{"name": "jenny maccan"},
+{"name": "mike leplant"},
+{"name": "teri patrson"},
+{"name": "philip hampton"},
+{"name": "monique sanchez"},
+{"name": "bob downing"},
+{"name": "annette singletary"},
+{"name": "bill zhu"},
+{"name": "cheryl pollack"},
+{"name": "dan mcgowan"},
+{"name": "matt baker"},
+{"name": "darlene wilson"},
+{"name": "larissa blakley"},
+{"name": "jean weyandt"},
+{"name": "chelsea berryman"},
+{"name": "dave carpenter"},
+{"name": "zack hamideh"},
+{"name": "natalie havlina"},
+{"name": "kevin medina"},
+{"name": "carlo vitulano"},
+{"name": "ken converse"},
+{"name": "dustin lofdah"},
+{"name": "mike polvere"},
+{"name": "stefan gran"},
+{"name": "matt schaap"},
+{"name": "joe acoin"},
+{"name": "jarrod mcfarland"},
+{"name": "darlene mappin"},
+{"name": "oscar aceves"},
+{"name": "phyllis honey"},
+{"name": "mary hall"},
+{"name": "dave bonham"},
+{"name": "lenore weil"},
+{"name": "alexander donovan"},
+{"name": "christopher dux"},
+{"name": "devin kessler"},
+{"name": "mary jakubowski"},
+{"name": "carrie huerta"},
+{"name": "denise negro"},
+{"name": "tom schiemer"},
+{"name": "tony j"},
+{"name": "louis pabon"},
+{"name": "carla rondel"},
+{"name": "jenna stanley"},
+{"name": "ashley monicas"},
+{"name": "jimmy watts"},
+{"name": "josh jensen"},
+{"name": "tony delansky"},
+{"name": "karla tofte"},
+{"name": "arnold kalan"},
+{"name": "elena mclean"},
+{"name": "dawn hankin"},
+{"name": "donna kirk"},
+{"name": "matt wagaman"},
+{"name": "diane taylor"},
+{"name": "wendy hames"},
+{"name": "dave lint"},
+{"name": "david frazier"},
+{"name": "lynne abeshouse"},
+{"name": "bob stinson"},
+{"name": "leslie perez"},
+{"name": "nikki aponte"},
+{"name": "gary hubbard"},
+{"name": "vanessa sanborn"},
+{"name": "john deangelis"},
+{"name": "missy frye"},
+{"name": "kyle utz"},
+{"name": "trey richardson"},
+{"name": "robert schumacher"},
+{"name": "jeff stanley"},
+{"name": "doris belk"},
+{"name": "mark caruso"},
+{"name": "mike keith"},
+{"name": "brad schneider"},
+{"name": "robert bonney"},
+{"name": "laura usur"},
+{"name": "amy cutter"},
+{"name": "bryan teel"},
+{"name": "raquel andres"},
+{"name": "elaine morlock"},
+{"name": "john fenico"},
+{"name": "mark j"},
+{"name": "wendy spakes"},
+{"name": "crystal short"},
+{"name": "blake moore"},
+{"name": "joe lucchese"},
+{"name": "karen koonan"},
+{"name": "sue sitton"},
+{"name": "bob ford"},
+{"name": "kathy farmer"},
+{"name": "robert abernathy"},
+{"name": "jeff brandon"},
+{"name": "danny newman"},
+{"name": "rachel lawson"},
+{"name": "mike greenewald"},
+{"name": "dennis hui"},
+{"name": "dan holden"},
+{"name": "jessica ellegood"},
+{"name": "dean hayse"},
+{"name": "angela wagenaar"},
+{"name": "ursula clark"},
+{"name": "jonathan askin"},
+{"name": "john begley"},
+{"name": "jeff hechendorf"},
+{"name": "karen pettit"},
+{"name": "jimmy kalamaras"},
+{"name": "jim carriger"},
+{"name": "rodney washington"},
+{"name": "jason fedore"},
+{"name": "sam hood"},
+{"name": "sean francis"},
+{"name": "charles spence"},
+{"name": "william robinson"},
+{"name": "lee melnychuk"},
+{"name": "tyler petty"},
+{"name": "gustavo guerrero"},
+{"name": "bob norwood"},
+{"name": "jerry sacks"},
+{"name": "john freeman"},
+{"name": "chuck dipiazza"},
+{"name": "anthony vereyken"},
+{"name": "mary burch"},
+{"name": "linda greaver"},
+{"name": "sam white"},
+{"name": "jim streeter"},
+{"name": "christine lee"},
+{"name": "matt crow"},
+{"name": "cindy tinge"},
+{"name": "patricia alibutod"},
+{"name": "sandy oneal"},
+{"name": "allen goins"},
+{"name": "holly eyebrows"},
+{"name": "nancy b"},
+{"name": "spencer byrnes"},
+{"name": "alexis newman"},
+{"name": "don bollinger"},
+{"name": "stacia milne"},
+{"name": "dennis harrah"},
+{"name": "jacob higgins"},
+{"name": "lorie ann"},
+{"name": "pat lenzer"},
+{"name": "kendra hills"},
+{"name": "charlotte cambell"},
+{"name": "jim wefest"},
+{"name": "rita butherus"},
+{"name": "rob z"},
+{"name": "matt bailey"},
+{"name": "iris avellano"},
+{"name": "tom pasto"},
+{"name": "mark lockschmidt"},
+{"name": "john barnitz"},
+{"name": "ginger oliver"},
+{"name": "jerrod mackimoto"},
+{"name": "jarrod n"},
+{"name": "dave k"},
+{"name": "jennifer ferrante"},
+{"name": "dave harper"},
+{"name": "tammy trujillo"},
+{"name": "meredith work"},
+{"name": "kevin ht"},
+{"name": "brandon flack"},
+{"name": "spencer head"},
+{"name": "ariel elite"},
+{"name": "lisa allman"},
+{"name": "greg byrne"},
+{"name": "matt heeringa"},
+{"name": "cathy neben"},
+{"name": "janice heid"},
+{"name": "sarah borofsky"},
+{"name": "hazel vincoy"},
+{"name": "tony merkel"},
+{"name": "dario pintor"},
+{"name": "brett harris"},
+{"name": "richard bales"},
+{"name": "lorrie summers"},
+{"name": "beryl miller"},
+{"name": "dwight stewart"},
+{"name": "margaret drysdale"},
+{"name": "amy collins"},
+{"name": "jeremiah lasslett"},
+{"name": "heidi werner"},
+{"name": "todd h"},
+{"name": "june angel"},
+{"name": "chad fleck"},
+{"name": "ed gottheil"},
+{"name": "scott gardner"},
+{"name": "tom teixeira"},
+{"name": "betty clendenon"},
+{"name": "tad fbo"},
+{"name": "heather maccallum"},
+{"name": "jared knight"},
+{"name": "bob pablish"},
+{"name": "kayla willis"},
+{"name": "douglas salyers"},
+{"name": "bernie bregman"},
+{"name": "joe siau"},
+{"name": "paula gemora"},
+{"name": "angelo mendez"},
+{"name": "luke p"},
+{"name": "kenny kurtzman"},
+{"name": "aurora merida"},
+{"name": "glenna kassel"},
+{"name": "tina parker"},
+{"name": "jess johnson"},
+{"name": "kaitlyn kramer"},
+{"name": "allen ellison"},
+{"name": "barbara holgate"},
+{"name": "paula sellers"},
+{"name": "spencer i"},
+{"name": "jeff cummings"},
+{"name": "nikki harding"},
+{"name": "jose terrones"},
+{"name": "rose caruso"},
+{"name": "michelle challenger"},
+{"name": "brian lythgoe"},
+{"name": "sean griffin"},
+{"name": "anne maguire"},
+{"name": "clint long"},
+{"name": "seymour joffe"},
+{"name": "tricia kelly"},
+{"name": "emily nelson"},
+{"name": "karla neuweg"},
+{"name": "bud younts"},
+{"name": "mike slayden"},
+{"name": "karen powell"},
+{"name": "kathy gonzalez"},
+{"name": "charlie kelly"},
+{"name": "agnes stacia"},
+{"name": "sam holland"},
+{"name": "ena couriers"},
+{"name": "kathy abney"},
+{"name": "don lowe"},
+{"name": "stephanie kugel"},
+{"name": "matt headrick"},
+{"name": "lisa gaunt"},
+{"name": "james pridgen"},
+{"name": "steve g"},
+{"name": "daniel crowe"},
+{"name": "jake centeno"},
+{"name": "julia rose"},
+{"name": "heather johnstone"},
+{"name": "nick santoro"},
+{"name": "gary wicker"},
+{"name": "thelma patterson"},
+{"name": "patsy sanchez"},
+{"name": "kati cruger"},
+{"name": "michelle cole"},
+{"name": "tony uno"},
+{"name": "kay iozzo"},
+{"name": "chris alexander"},
+{"name": "john rorabaugh"},
+{"name": "shane salmari"},
+{"name": "brandon tentation"},
+{"name": "chris cali"},
+{"name": "rita liebelt"},
+{"name": "jennifer lamoureux"},
+{"name": "denny blew"},
+{"name": "jennifer logan"},
+{"name": "sheryl gillespie"},
+{"name": "jeff mumma"},
+{"name": "robert brunner"},
+{"name": "kimberly richburg"},
+{"name": "brandon hams"},
+{"name": "linda agnos"},
+{"name": "leda arguello"},
+{"name": "paul blanner"},
+{"name": "eric haggin"},
+{"name": "carmel m"},
+{"name": "christine choi"},
+{"name": "barbara nix"},
+{"name": "matt krywy"},
+{"name": "tony lumber"},
+{"name": "curt wada"},
+{"name": "eric huffman"},
+{"name": "kyle cell"},
+{"name": "terry riorden"},
+{"name": "evon whitley"},
+{"name": "cheyenne cyr"},
+{"name": "david lewis"},
+{"name": "david holdcroft"},
+{"name": "chris bassham"},
+{"name": "allen henderson"},
+{"name": "jason glass"},
+{"name": "bryan rr"},
+{"name": "norbert pools"},
+{"name": "jeremy martin"},
+{"name": "eric fisher"},
+{"name": "isaac redmay"},
+{"name": "heidi groth"},
+{"name": "daniella kassar"},
+{"name": "robyn coley"},
+{"name": "laura mcgees"},
+{"name": "gloria connors"},
+{"name": "sergio murillo"},
+{"name": "mark wiehl"},
+{"name": "augustine soundranayakam"},
+{"name": "lou alzate"},
+{"name": "don auld"},
+{"name": "carter morse"},
+{"name": "merrill lynch"},
+{"name": "thomas trumphour"},
+{"name": "brianna bostwick"},
+{"name": "greg lake"},
+{"name": "william song"},
+{"name": "joshua lin"},
+{"name": "robert fin"},
+{"name": "chris luu"},
+{"name": "michelle mckinney"},
+{"name": "claudia montrone"},
+{"name": "mike diamanths"},
+{"name": "dan lindell"},
+{"name": "neil smith"},
+{"name": "luis love"},
+{"name": "brandi jonse"},
+{"name": "kate wisnewski"},
+{"name": "ray dizon"},
+{"name": "jeanie blaylock"},
+{"name": "grady hanshaw"},
+{"name": "kristin murray"},
+{"name": "louis friedman"},
+{"name": "kathy rogers"},
+{"name": "chris majors"},
+{"name": "dave foster"},
+{"name": "ken zambelli"},
+{"name": "don barlow"},
+{"name": "jon home"},
+{"name": "barry draeger"},
+{"name": "john weaver"},
+{"name": "michelle lugo"},
+{"name": "kelsey reis"},
+{"name": "neil witherow"},
+{"name": "young cho"},
+{"name": "dan smeak"},
+{"name": "ken davidson"},
+{"name": "amy younger"},
+{"name": "penny olson"},
+{"name": "jennifer pastores"},
+{"name": "joel stocks"},
+{"name": "kent mcdowell"},
+{"name": "dennis d"},
+{"name": "tanya deavers"},
+{"name": "heather atler"},
+{"name": "sheila alvarez"},
+{"name": "chris sevil"},
+{"name": "mike pederson"},
+{"name": "bobbi fowler"},
+{"name": "jimmie reign"},
+{"name": "lloyd droller"},
+{"name": "rich pearson"},
+{"name": "matt gonzales"},
+{"name": "marvin house"},
+{"name": "kevin falk"},
+{"name": "yolanda williams"},
+{"name": "patricia suh"},
+{"name": "shirley gebert"},
+{"name": "pat c"},
+{"name": "daren manaco"},
+{"name": "kristen toponce"},
+{"name": "bailey whitehead"},
+{"name": "stacie ayala"},
+{"name": "drew tibbits"},
+{"name": "taylor moyer"},
+{"name": "ian holten"},
+{"name": "roger shanafelt"},
+{"name": "jeremy burt"},
+{"name": "raul martinez"},
+{"name": "sherry lasley"},
+{"name": "rick rummel"},
+{"name": "roger berke"},
+{"name": "erica work"},
+{"name": "jeff cressman"},
+{"name": "laura radford"},
+{"name": "nikki safady"},
+{"name": "ann menchetti"},
+{"name": "dedra trail"},
+{"name": "susie t"},
+{"name": "dennis goldstein"},
+{"name": "mark plecnik"},
+{"name": "van vaketis"},
+{"name": "ben richard"},
+{"name": "pat egan"},
+{"name": "andy grumbles"},
+{"name": "linda rogers"},
+{"name": "andrew selormey"},
+{"name": "tommy gun"},
+{"name": "jim peirce"},
+{"name": "linda deal"},
+{"name": "travis dunn"},
+{"name": "jon glusband"},
+{"name": "chris saurez"},
+{"name": "kathleen mais"},
+{"name": "lori rowland"},
+{"name": "andres villegas"},
+{"name": "josh adongay"},
+{"name": "ginny goss"},
+{"name": "ron bochenek"},
+{"name": "scott orr"},
+{"name": "stacey bomeli"},
+{"name": "valerie berry"},
+{"name": "coralee mitchell"},
+{"name": "devon prioleau"},
+{"name": "max j"},
+{"name": "dave harrah"},
+{"name": "royce foster"},
+{"name": "sharon sponslor"},
+{"name": "jim kc"},
+{"name": "blake hollister"},
+{"name": "danny lilly"},
+{"name": "scot griffith"},
+{"name": "jess g"},
+{"name": "ralph losey"},
+{"name": "louise haverman"},
+{"name": "andrea boyd"},
+{"name": "ann carlson"},
+{"name": "tyler miehm"},
+{"name": "jim dutra"},
+{"name": "chris banfield"},
+{"name": "denise reed"},
+{"name": "noel murphy"},
+{"name": "mindy zheng"},
+{"name": "brian viglione"},
+{"name": "don bennett"},
+{"name": "robin kreines"},
+{"name": "katie morrisey"},
+{"name": "emma jurado"},
+{"name": "shanna sabet"},
+{"name": "floyd dakil"},
+{"name": "chris shin"},
+{"name": "ryan ash"},
+{"name": "josh needelman"},
+{"name": "brett matthews"},
+{"name": "earl nicholson"},
+{"name": "roxanne ashe"},
+{"name": "adam storm"},
+{"name": "martha pozdyn"},
+{"name": "monique grech"},
+{"name": "robin bryan"},
+{"name": "edie rhea"},
+{"name": "hank boughner"},
+{"name": "kris markus"},
+{"name": "erika gutherz"},
+{"name": "joy engelberg"},
+{"name": "dennis sawyer"},
+{"name": "bill maestretti"},
+{"name": "cindy moses"},
+{"name": "rick henson"},
+{"name": "steve samaniego"},
+{"name": "ryan bordas"},
+{"name": "mary tobin"},
+{"name": "jonathan leitersdorf"},
+{"name": "luis ortiz"},
+{"name": "george washington"},
+{"name": "cynthia class"},
+{"name": "mark nolte"},
+{"name": "randy cell"},
+{"name": "susan mcvety"},
+{"name": "frank ackley"},
+{"name": "andrew perez"},
+{"name": "jaimee schmidt"},
+{"name": "dara gomshei"},
+{"name": "paul storch"},
+{"name": "matthew rohr"},
+{"name": "robert yankanin"},
+{"name": "chantal lepine"},
+{"name": "philip fraser"},
+{"name": "tom crowly"},
+{"name": "ann agnew"},
+{"name": "sharon steward"},
+{"name": "seth brigman"},
+{"name": "ashleigh brooks"},
+{"name": "ken stem"},
+{"name": "johnie howle"},
+{"name": "john bair"},
+{"name": "cindy vetter"},
+{"name": "ralph lux"},
+{"name": "michael somsavath"},
+{"name": "dave bade"},
+{"name": "ma pa"},
+{"name": "chandra crear"},
+{"name": "rob petry"},
+{"name": "robert gardner"},
+{"name": "dan hoak"},
+{"name": "tim lovelady"},
+{"name": "nicole urada"},
+{"name": "jackie bortters"},
+{"name": "craig dossman"},
+{"name": "matt lafortune"},
+{"name": "douglas honda"},
+{"name": "chelsey spencer"},
+{"name": "michael figeroa"},
+{"name": "jeff young"},
+{"name": "yadira pena"},
+{"name": "elizabeth gil"},
+{"name": "kyle gonzalez"},
+{"name": "gary vosberg"},
+{"name": "mary liz"},
+{"name": "lindsey henderson"},
+{"name": "reed machinski"},
+{"name": "diane spence"},
+{"name": "ryann inman"},
+{"name": "ray durran"},
+{"name": "anne cleaner"},
+{"name": "garrett jackson"},
+{"name": "jim lake"},
+{"name": "jessica davis"},
+{"name": "eli olson"},
+{"name": "david burrows"},
+{"name": "john gibbins"},
+{"name": "gena bell"},
+{"name": "gary rehoboth"},
+{"name": "patricia manos"},
+{"name": "sierra jason"},
+{"name": "sasha rastegari"},
+{"name": "niki toth"},
+{"name": "barb carl"},
+{"name": "sarah eastman"},
+{"name": "cindy lepak"},
+{"name": "greg saul"},
+{"name": "rob handsom"},
+{"name": "amy gregory"},
+{"name": "vickie mcpeters"},
+{"name": "dan steenbergen"},
+{"name": "tom cades"},
+{"name": "ryan maxwell"},
+{"name": "kristina sandras"},
+{"name": "nicole k"},
+{"name": "debbie munoz"},
+{"name": "george page"},
+{"name": "lauren davidson"},
+{"name": "megan holland"},
+{"name": "alison schwartzkopf"},
+{"name": "jim kelly"},
+{"name": "barb schwaubauer"},
+{"name": "dixie pump"},
+{"name": "jake hm"},
+{"name": "elizabeth botes"},
+{"name": "robert greenspoon"},
+{"name": "kip kim"},
+{"name": "robert haskell"},
+{"name": "ronnie bartels"},
+{"name": "klara attorney"},
+{"name": "dan barrett"},
+{"name": "delores mawhinney"},
+{"name": "jessica stanky"},
+{"name": "bart mc"},
+{"name": "alfonso larin"},
+{"name": "nelson selcer"},
+{"name": "steve leo"},
+{"name": "ron pipe"},
+{"name": "william nicodemus"},
+{"name": "bobby wong"},
+{"name": "jacqueline ayer"},
+{"name": "laurie kaplan"},
+{"name": "meredith quinn"},
+{"name": "kimberly glenn"},
+{"name": "brian light"},
+{"name": "elsa heredia"},
+{"name": "esther michaels"},
+{"name": "tommy avant"},
+{"name": "samantha myspace"},
+{"name": "nicole case"},
+{"name": "carol krumm"},
+{"name": "jody martin"},
+{"name": "rudy ariaga"},
+{"name": "jimmy ponds"},
+{"name": "lora shipman"},
+{"name": "kristi spontius"},
+{"name": "allen rentalhome"},
+{"name": "phyllis knaak"},
+{"name": "matt chapman"},
+{"name": "susan bess"},
+{"name": "jillian brice"},
+{"name": "ron lingle"},
+{"name": "jacob diaz"},
+{"name": "dan first"},
+{"name": "janae h"},
+{"name": "john mclauren"},
+{"name": "velma tipton"},
+{"name": "kay freeland"},
+{"name": "eric adams"},
+{"name": "maria gray"},
+{"name": "ed price"},
+{"name": "deborah pires"},
+{"name": "chuck atkins"},
+{"name": "kia grandparents"},
+{"name": "jeremy spurgin"},
+{"name": "mike pulli"},
+{"name": "phil devargas"},
+{"name": "george t"},
+{"name": "jacquie aguirre"},
+{"name": "gregory irish"},
+{"name": "steven reichard"},
+{"name": "dean molanen"},
+{"name": "jason fall"},
+{"name": "preston haag"},
+{"name": "dan maez"},
+{"name": "marc sencer"},
+{"name": "stephen ohsovgl"},
+{"name": "may cheng"},
+{"name": "frank decaires"},
+{"name": "lisa benjamin"},
+{"name": "lou phan"},
+{"name": "barry rooney"},
+{"name": "mike madsen"},
+{"name": "jonathan griffin"},
+{"name": "josh yoder"},
+{"name": "robert kropp"},
+{"name": "ray frants"},
+{"name": "vicki ridgway"},
+{"name": "scott blois"},
+{"name": "michael krupa"},
+{"name": "terry cadenas"},
+{"name": "ashley champs"},
+{"name": "candi kalm"},
+{"name": "wendy mcdowell"},
+{"name": "bianca favia"},
+{"name": "dwight fontenot"},
+{"name": "nancy o'donnell"},
+{"name": "susan higley"},
+{"name": "jake kettler"},
+{"name": "ricky sanger"},
+{"name": "sarah irby"},
+{"name": "michael peterson"},
+{"name": "tiffany hungerford"},
+{"name": "lorena garcia"},
+{"name": "rob markey"},
+{"name": "michael fahid"},
+{"name": "bryant garcia"},
+{"name": "jared glover"},
+{"name": "brenda beck"},
+{"name": "gay johnson"},
+{"name": "jimmy gray"},
+{"name": "robert rines"},
+{"name": "mark speciner"},
+{"name": "sade sis"},
+{"name": "amanda schmidt"},
+{"name": "nicole dss"},
+{"name": "mitch tutor"},
+{"name": "sean koppels"},
+{"name": "lupe esther"},
+{"name": "frank mts"},
+{"name": "alex cheng"},
+{"name": "tom abbott"},
+{"name": "thomas jarmai"},
+{"name": "eric axelander"},
+{"name": "john lopes"},
+{"name": "tisha white"},
+{"name": "marisa joseph"},
+{"name": "lori coticchia"},
+{"name": "lindsy f"},
+{"name": "betsy croney"},
+{"name": "david loaiza"},
+{"name": "angie egbert"},
+{"name": "will nexsen"},
+{"name": "veronica mullins"},
+{"name": "jim g"},
+{"name": "jared han"},
+{"name": "coleen billings"},
+{"name": "eric radford"},
+{"name": "anna walenga"},
+{"name": "shana solomon"},
+{"name": "tom loitz"},
+{"name": "alex ruby"},
+{"name": "therese harper"},
+{"name": "anne paul"},
+{"name": "amber price"},
+{"name": "rob patterson"},
+{"name": "rick alspach"},
+{"name": "john lynn"},
+{"name": "max meyers"},
+{"name": "matt khan"},
+{"name": "marcia williams"},
+{"name": "bill faucette"},
+{"name": "mike breen"},
+{"name": "mindy michalak"},
+{"name": "darren williams"},
+{"name": "nick siersema"},
+{"name": "crystal herron"},
+{"name": "mark armbrister"},
+{"name": "sara pereda"},
+{"name": "anna florida"},
+{"name": "daniel mattieson"},
+{"name": "sam beene"},
+{"name": "ben stoller"},
+{"name": "lisa cirnwalace"},
+{"name": "joe barnet"},
+{"name": "aileen brown"},
+{"name": "bill kouwenhoven"},
+{"name": "doreen dimiceli"},
+{"name": "porter chartney"},
+{"name": "tracy guice"},
+{"name": "joe josephson"},
+{"name": "shannon ghers"},
+{"name": "paul it"},
+{"name": "jerry cline"},
+{"name": "al moser"},
+{"name": "wendy payne"},
+{"name": "mike duboise"},
+{"name": "dale hill"},
+{"name": "rob medina"},
+{"name": "angela benfield"},
+{"name": "jackie feder"},
+{"name": "richard sharp"},
+{"name": "velvet dow"},
+{"name": "rob scott"},
+{"name": "shelly currier"},
+{"name": "ed killenberger"},
+{"name": "chris couch"},
+{"name": "maria rosko"},
+{"name": "emily reppun"},
+{"name": "terry larson"},
+{"name": "allyson lorenzo"},
+{"name": "cody limo"},
+{"name": "patty office"},
+{"name": "karen beasley"},
+{"name": "justin b"},
+{"name": "peter seebold"},
+{"name": "douglas campbell"},
+{"name": "tom fry"},
+{"name": "joanne lota"},
+{"name": "clay richardson"},
+{"name": "fred noreen"},
+{"name": "ben block"},
+{"name": "richard nathan"},
+{"name": "jin xu"},
+{"name": "lorraine kajikawa"},
+{"name": "clint mckall"},
+{"name": "kandi kane"},
+{"name": "brian webb"},
+{"name": "mel santiago"},
+{"name": "shawn iowa"},
+{"name": "alicia thompson"},
+{"name": "david rossoff"},
+{"name": "brad stewart"},
+{"name": "roman shklanka"},
+{"name": "evan kleinhenz"},
+{"name": "david camenson"},
+{"name": "stephen cunningham"},
+{"name": "amanda baker"},
+{"name": "claudia taylor"},
+{"name": "sheri peters"},
+{"name": "suzie lewcvyk"},
+{"name": "steve sam"},
+{"name": "kurt zeagler"},
+{"name": "edith soto"},
+{"name": "dan boverman"},
+{"name": "patrick wheeler"},
+{"name": "michael bogdanoff"},
+{"name": "clint mckenzie"},
+{"name": "donny bass"},
+{"name": "john faced"},
+{"name": "joe rivera"},
+{"name": "leslie donahue"},
+{"name": "fran lacina"},
+{"name": "frank wirick"},
+{"name": "ian golding"},
+{"name": "paul gonnella"},
+{"name": "jake hattan"},
+{"name": "andrew baker"},
+{"name": "chris stone"},
+{"name": "chris post"},
+{"name": "robin kahan"},
+{"name": "jess williamson"},
+{"name": "ryan mahoney"},
+{"name": "debbie mosseri"},
+{"name": "ross turner"},
+{"name": "richard godwin"},
+{"name": "lindsay lavelle"},
+{"name": "lindsay dyer"},
+{"name": "morgan high"},
+{"name": "chaz himself"},
+{"name": "steve beatty"},
+{"name": "ty kane"},
+{"name": "kathy rosman"},
+{"name": "kirstin mcmillan"},
+{"name": "chris dean"},
+{"name": "kelly tripp"},
+{"name": "debbie manes"},
+{"name": "jim keeney"},
+{"name": "brooke j"},
+{"name": "stephanie herring"},
+{"name": "nathan pedigo"},
+{"name": "jimmy sanders"},
+{"name": "brian kolligian"},
+{"name": "daniel kubin"},
+{"name": "duane farmer"},
+{"name": "hector chavez"},
+{"name": "meg ochoa"},
+{"name": "kevin hooper"},
+{"name": "jim fonseca"},
+{"name": "bob grusk"},
+{"name": "gerald ferrari"},
+{"name": "tom schwartz"},
+{"name": "shane branham"},
+{"name": "richard sosa"},
+{"name": "mike ashburn"},
+{"name": "hector quiles"},
+{"name": "star cinema"},
+{"name": "ivan roberts"},
+{"name": "amanda spencer"},
+{"name": "ashley anderson"},
+{"name": "christina chartney"},
+{"name": "stephane moraille"},
+{"name": "dave genson"},
+{"name": "loretta koerner"},
+{"name": "wendy warring"},
+{"name": "eddie stallings"},
+{"name": "john portaro"},
+{"name": "will kohler"},
+{"name": "kia watkins"},
+{"name": "michael boyd"},
+{"name": "randy mccoy"},
+{"name": "cathy chalk"},
+{"name": "john conyers"},
+{"name": "jeanette klanow"},
+{"name": "sam miles"},
+{"name": "janet burns"},
+{"name": "bill snedden"},
+{"name": "fred marcus"},
+{"name": "linda crook"},
+{"name": "thu oesterreich"},
+{"name": "rick rebel"},
+{"name": "john mellor"},
+{"name": "kent nishioka"},
+{"name": "marlene aguirre"},
+{"name": "eric miles"},
+{"name": "naomi regalado"},
+{"name": "jim gonzalez"},
+{"name": "raul mireles"},
+{"name": "julianne winterfield"},
+{"name": "jenni bennett"},
+{"name": "daniel labaredas"},
+{"name": "pete eakland"},
+{"name": "shira becker"},
+{"name": "will stevens"},
+{"name": "golden light"},
+{"name": "tom gaye"},
+{"name": "celina campbell"},
+{"name": "joshua lee"},
+{"name": "tiffany davis"},
+{"name": "bonnie june"},
+{"name": "paul cavassa"},
+{"name": "justin stutter"},
+{"name": "jason toole"},
+{"name": "nick marx"},
+{"name": "mike ritter"},
+{"name": "ben tarr"},
+{"name": "crystal sima"},
+{"name": "johnny horton"},
+{"name": "chris oberkfell"},
+{"name": "alice bartelt"},
+{"name": "joyce collins"},
+{"name": "beth cemetery"},
+{"name": "anthony everett"},
+{"name": "douglas richter"},
+{"name": "becky pete"},
+{"name": "williams travis"},
+{"name": "allison carrel"},
+{"name": "mike nula"},
+{"name": "craig martel"},
+{"name": "bryan rucker"},
+{"name": "doug manager"},
+{"name": "arline faustin"},
+{"name": "mary barros"},
+{"name": "candy cce"},
+{"name": "sean fehl"},
+{"name": "mike barth"},
+{"name": "lee whedbee"},
+{"name": "casey cordon"},
+{"name": "steve poker"},
+{"name": "dave sakas"},
+{"name": "lauren arduino"},
+{"name": "roberto caceres"},
+{"name": "bobbie callese"},
+{"name": "hillary randoja"},
+{"name": "janice shaffer"},
+{"name": "john huntington"},
+{"name": "chris mclaughlin"},
+{"name": "sarah nadin"},
+{"name": "samantha morton"},
+{"name": "lou knack"},
+{"name": "mike grannis"},
+{"name": "gary armstrong"},
+{"name": "kimberly tipton"},
+{"name": "suzanne montgomery"},
+{"name": "marina edwards"},
+{"name": "holly lynn"},
+{"name": "phil friedland"},
+{"name": "martha ortiz"},
+{"name": "matt weinart"},
+{"name": "ron santos"},
+{"name": "sara w"},
+{"name": "johnnie s"},
+{"name": "bill caldwell"},
+{"name": "tom craigo"},
+{"name": "gary singh"},
+{"name": "donnell detweiler"},
+{"name": "shawn klitch"},
+{"name": "chris c"},
+{"name": "raul kuchinad"},
+{"name": "alfred zencak"},
+{"name": "david hadley"},
+{"name": "helen hm"},
+{"name": "esperanza rothwell"},
+{"name": "mark l"},
+{"name": "linda linton"},
+{"name": "tracy crider"},
+{"name": "ronald mcdonald"},
+{"name": "adam soun"},
+{"name": "liz sydow"},
+{"name": "jessica rich"},
+{"name": "nancy harmel"},
+{"name": "michael delone"},
+{"name": "marci glenney"},
+{"name": "chris zamzow"},
+{"name": "sally clawson"},
+{"name": "ken phillips"},
+{"name": "kurt renner"},
+{"name": "vicki nuetzel"},
+{"name": "thomas towning"},
+{"name": "jody gibney"},
+{"name": "stacey allen"},
+{"name": "heidi lewandowski"},
+{"name": "heidi leiman"},
+{"name": "cindy vanschoyck"},
+{"name": "julie customer"},
+{"name": "marc peeler"},
+{"name": "eva jones"},
+{"name": "dennis perkins"},
+{"name": "nancy mosher"},
+{"name": "andrew steele"},
+{"name": "patrick donnellan"},
+{"name": "dwight bailey"},
+{"name": "loretta hughbanks"},
+{"name": "sally stewert"},
+{"name": "leslie pope"},
+{"name": "jay janicki"},
+{"name": "johnny two"},
+{"name": "patrick veg"},
+{"name": "shea homes"},
+{"name": "stephen suttles"},
+{"name": "gregg frank"},
+{"name": "tyler babcock"},
+{"name": "raymond osborne"},
+{"name": "scott goodsell"},
+{"name": "steve smith"},
+{"name": "chris hintz"},
+{"name": "michael pohl"},
+{"name": "tracey hogan"},
+{"name": "jamie singer"},
+{"name": "marna hauk"},
+{"name": "barb stauffer"},
+{"name": "jeff shimek"},
+{"name": "erin elk"},
+{"name": "emily underwood"},
+{"name": "rachel deboer"},
+{"name": "cindy sestile"},
+{"name": "jacquie king"},
+{"name": "raymond newsom"},
+{"name": "rhonda feragen"},
+{"name": "steven link"},
+{"name": "reiko hineno"},
+{"name": "bunny lamonte"},
+{"name": "john nyguen"},
+{"name": "tim turpin"},
+{"name": "jaime bby"},
+{"name": "linda girls"},
+{"name": "brian palmer"},
+{"name": "brenda waddoups"},
+{"name": "peter lucey"},
+{"name": "brian harter"},
+{"name": "marla link"},
+{"name": "darren trukn"},
+{"name": "amanda mohabeer"},
+{"name": "john bates"},
+{"name": "nick maloni"},
+{"name": "wendy morrison"},
+{"name": "erin macom"},
+{"name": "jesse karate"},
+{"name": "pam szokol"},
+{"name": "tim kuhn"},
+{"name": "mel soloman"},
+{"name": "jacquelyn mcmahon"},
+{"name": "sam nyc"},
+{"name": "adam daniels"},
+{"name": "erna hodgkin"},
+{"name": "ezra brown"},
+{"name": "geoffrey peiffer"},
+{"name": "alfred mcneil"},
+{"name": "michele vega"},
+{"name": "travis bix"},
+{"name": "andrew island"},
+{"name": "grady watson"},
+{"name": "corey bad"},
+{"name": "gary minevich"},
+{"name": "troy amundson"},
+{"name": "jenny brown"},
+{"name": "jordan john"},
+{"name": "daniel wei"},
+{"name": "shauna o"},
+{"name": "david feild"},
+{"name": "scott s"},
+{"name": "wes fisher"},
+{"name": "kelley presley"},
+{"name": "michelle sinotte"},
+{"name": "kevin grisham"},
+{"name": "laurie kaufman"},
+{"name": "joy greco"},
+{"name": "patrick hansri"},
+{"name": "mark mallory"},
+{"name": "bill weimer"},
+{"name": "kenneth maclaurin"},
+{"name": "rick harrison"},
+{"name": "mavis fitzgerald"},
+{"name": "cynthia chu"},
+{"name": "brett miller"},
+{"name": "lisa gypsy"},
+{"name": "matt lambeth"},
+{"name": "david schwarz"},
+{"name": "lori lamb"},
+{"name": "greg rairdon"},
+{"name": "dwayne saunders"},
+{"name": "paul blaine"},
+{"name": "troy bmore"},
+{"name": "gail ward"},
+{"name": "leo spagnola"},
+{"name": "esther hanuka"},
+{"name": "jeremy allaire"},
+{"name": "mary snee"},
+{"name": "rich cormier"},
+{"name": "valerie putnam"},
+{"name": "cynthia g"},
+{"name": "peter xxxxx"},
+{"name": "bobby mitchell"},
+{"name": "mike henchmen"},
+{"name": "bill butz"},
+{"name": "jim aschoff"},
+{"name": "sandra cassese"},
+{"name": "cynthia nails"},
+{"name": "megan barkve"},
+{"name": "leslie downey"},
+{"name": "fiona clover"},
+{"name": "dave dat"},
+{"name": "ron risebrough"},
+{"name": "charles jones"},
+{"name": "paul gunn"},
+{"name": "vince palazzolo"},
+{"name": "charlie smith"},
+{"name": "angie rosales"},
+{"name": "jim ollrogge"},
+{"name": "brett caswell"},
+{"name": "kaylee vance"},
+{"name": "matt little"},
+{"name": "brad parrott"},
+{"name": "amy curran"},
+{"name": "bo harvig"},
+{"name": "tom poberezny"},
+{"name": "tom bishop"},
+{"name": "ed argenziano"},
+{"name": "lisa rutherford"},
+{"name": "marianne ryan"},
+{"name": "chris pete"},
+{"name": "ardell davis"},
+{"name": "warren degraff"},
+{"name": "timmy smith"},
+{"name": "rudy abbott"},
+{"name": "jennifer beery"},
+{"name": "chaz billington"},
+{"name": "sue weeden"},
+{"name": "paul lettow"},
+{"name": "sadie w"},
+{"name": "dominque meridy"},
+{"name": "scott penske"},
+{"name": "andre julien"},
+{"name": "marlon esguerra"},
+{"name": "mark warner"},
+{"name": "johnny d"},
+{"name": "lenny fairfield"},
+{"name": "james maxwell"},
+{"name": "bruce cross"},
+{"name": "kenny p"},
+{"name": "damien gallardo"},
+{"name": "sandra lilly"},
+{"name": "julie hirata"},
+{"name": "gene prizer"},
+{"name": "lauren morris"},
+{"name": "edgar cheech"},
+{"name": "val burnell"},
+{"name": "cheri varner"},
+{"name": "will poker"},
+{"name": "pam williams"},
+{"name": "chase turner"},
+{"name": "don lawrenz"},
+{"name": "annie vance"},
+{"name": "susan tremble"},
+{"name": "brianna pennywell"},
+{"name": "kimberly parnell"},
+{"name": "kyle ballard"},
+{"name": "billy baumberger"},
+{"name": "lucia zayas"},
+{"name": "frank frerraro"},
+{"name": "chris deparo"},
+{"name": "steven salny"},
+{"name": "paul martin"},
+{"name": "sarah magee"},
+{"name": "rozanne wetmore"},
+{"name": "ellis fla"},
+{"name": "kevin thomson"},
+{"name": "holly stang"},
+{"name": "amanda black"},
+{"name": "rich mulvihill"},
+{"name": "brandon karr"},
+{"name": "tom hume"},
+{"name": "darryl behnke"},
+{"name": "jeffrey cuccia"},
+{"name": "martha galvan"},
+{"name": "shawn strong"},
+{"name": "rich goon"},
+{"name": "jay mckenzie"},
+{"name": "jessica melton"},
+{"name": "john hale"},
+{"name": "emily quigly"},
+{"name": "monica katena"},
+{"name": "adrian castillo"},
+{"name": "taylor apo"},
+{"name": "diane christopher"},
+{"name": "brittany cecilia"},
+{"name": "jack crosby"},
+{"name": "paul benning"},
+{"name": "gloria vaughn"},
+{"name": "eva lopez"},
+{"name": "juan lopez"},
+{"name": "justin lisk"},
+{"name": "jose creeper"},
+{"name": "kathy aulger"},
+{"name": "amanda nesbit"},
+{"name": "marco ramirez"},
+{"name": "mark salient"},
+{"name": "derek s"},
+{"name": "jack bloundin"},
+{"name": "gary wilhelm"},
+{"name": "jimmy belcastro"},
+{"name": "vince bailey"},
+{"name": "paulina lipets"},
+{"name": "ellie sadeghi"},
+{"name": "natalie capello"},
+{"name": "david azevedo"},
+{"name": "bobby hastings"},
+{"name": "carol cottingham"},
+{"name": "nydia garcia"},
+{"name": "scott stabler"},
+{"name": "scott fields"},
+{"name": "tom rutherford"},
+{"name": "camille mcwhirter"},
+{"name": "steve hubbard"},
+{"name": "angie babcock"},
+{"name": "diana coleman"},
+{"name": "elizabet garzon"},
+{"name": "angela english"},
+{"name": "chris cornely"},
+{"name": "byron farthing"},
+{"name": "pete maldonado"},
+{"name": "russ parrish"},
+{"name": "dave moodie"},
+{"name": "alberto piedra"},
+{"name": "linda swiatek"},
+{"name": "mark filson"},
+{"name": "jessica cahill"},
+{"name": "tommy wright"},
+{"name": "eddie lloyd"},
+{"name": "henry tran"},
+{"name": "steve butcher"},
+{"name": "candace derosier"},
+{"name": "andrew wyka"},
+{"name": "marcos perez"},
+{"name": "steve dail"},
+{"name": "angela hinnant"},
+{"name": "dave ferrell"},
+{"name": "leigh madden"},
+{"name": "sam leblond"},
+{"name": "clay feaster"},
+{"name": "jeff beery"},
+{"name": "pedro l"},
+{"name": "phyllis conley"},
+{"name": "justin thompson"},
+{"name": "georgia ober"},
+{"name": "louis mcgraw"},
+{"name": "beth kish"},
+{"name": "melissa ashbaugh"},
+{"name": "genie f"},
+{"name": "sean hurley"},
+{"name": "tamara watkins"},
+{"name": "allison walker"},
+{"name": "bill stovin"},
+{"name": "john vida"},
+{"name": "bernie thyen"},
+{"name": "joseph hollins"},
+{"name": "jessica calderon"},
+{"name": "dwight engle"},
+{"name": "troy mullryan"},
+{"name": "karen yeg"},
+{"name": "jeff gentges"},
+{"name": "maria nevarez"},
+{"name": "christine kelly"},
+{"name": "brad bebee"},
+{"name": "brian pj's"},
+{"name": "gloria martin"},
+{"name": "denis z"},
+{"name": "brent mendoza"},
+{"name": "john liacone"},
+{"name": "susan vaketis"},
+{"name": "sherri krause"},
+{"name": "robyn hallet"},
+{"name": "paul steed"},
+{"name": "ellen bollinger"},
+{"name": "larry neilson"},
+{"name": "dave brunelle"},
+{"name": "todd bankofier"},
+{"name": "john giles"},
+{"name": "marc cram"},
+{"name": "doyle royer"},
+{"name": "meredith meyer"},
+{"name": "dave parkinson"},
+{"name": "doug hampton"},
+{"name": "chad larsen"},
+{"name": "antonio leach"},
+{"name": "noel leon"},
+{"name": "david wills"},
+{"name": "barbie cell"},
+{"name": "denver hardware"},
+{"name": "eleanor roberts"},
+{"name": "john rankin"},
+{"name": "denise l"},
+{"name": "tim mock"},
+{"name": "debra steele"},
+{"name": "susan goodwill"},
+{"name": "dale pendry"},
+{"name": "mark pegler"},
+{"name": "jim lynch"},
+{"name": "bret barnes"},
+{"name": "gene biker"},
+{"name": "irene siwik"},
+{"name": "nicolle room"},
+{"name": "jenifer garland"},
+{"name": "jess leo"},
+{"name": "josh myrick"},
+{"name": "carl gillispie"},
+{"name": "laura lyle"},
+{"name": "megan a"},
+{"name": "jayne bahoura"},
+{"name": "katy kennedy"},
+{"name": "sarah silva"},
+{"name": "christopher ballas"},
+{"name": "bill ortolano"},
+{"name": "jenny iovino"},
+{"name": "stephen shepard"},
+{"name": "liza davis"},
+{"name": "alisa hm"},
+{"name": "steven morris"},
+{"name": "mark cresswell"},
+{"name": "karen fischer"},
+{"name": "steve mcmclung"},
+{"name": "chris elkins"},
+{"name": "marge bumen"},
+{"name": "bruce wallace"},
+{"name": "simon caine"},
+{"name": "les baxter"},
+{"name": "blake vandergeest"},
+{"name": "glen woods"},
+{"name": "jami brown"},
+{"name": "jeff visosky"},
+{"name": "steven goldman"},
+{"name": "cheryl mccoy"},
+{"name": "janis shoemaker"},
+{"name": "jill cancilla"},
+{"name": "logan anderson"},
+{"name": "james brooks"},
+{"name": "mel spooner"},
+{"name": "jeremy bolton"},
+{"name": "juliet gayle"},
+{"name": "ida trevino"},
+{"name": "mark mangiagli"},
+{"name": "sharon frey"},
+{"name": "brendan donnelly"},
+{"name": "blake harrop"},
+{"name": "joy cousin"},
+{"name": "jim tucker"},
+{"name": "stacey giannacini"},
+{"name": "steven marr"},
+{"name": "ryan cell"},
+{"name": "michael paris"},
+{"name": "ian boyd"},
+{"name": "lyn allan"},
+{"name": "june king"},
+{"name": "paul reveres"},
+{"name": "tim gilbert"},
+{"name": "brian mueler"},
+{"name": "stephen goldberg"},
+{"name": "dan tai"},
+{"name": "garret schade"},
+{"name": "curtis sorochan"},
+{"name": "meg callaghan"},
+{"name": "sherry piel"},
+{"name": "adam brager"},
+{"name": "arnold stanio"},
+{"name": "betty att"},
+{"name": "colin gromley"},
+{"name": "april medly"},
+{"name": "tom gimenez"},
+{"name": "bob bean"},
+{"name": "les williams"},
+{"name": "cody k"},
+{"name": "tom agg"},
+{"name": "tyler bates"},
+{"name": "shelley savanni"},
+{"name": "judy gephardt"},
+{"name": "allyson whitfield"},
+{"name": "tony jerome"},
+{"name": "georgia parrott"},
+{"name": "phuong tenis"},
+{"name": "steven r"},
+{"name": "don corter"},
+{"name": "eric green"},
+{"name": "linh expo"},
+{"name": "michael collins"},
+{"name": "samantha g"},
+{"name": "joe ferland"},
+{"name": "jennifer toledo"},
+{"name": "larry hatch"},
+{"name": "tim grisham"},
+{"name": "bruce coles"},
+{"name": "jamie guidera"},
+{"name": "ryan bru"},
+{"name": "vickie brobst"},
+{"name": "jeff dunnavant"},
+{"name": "alexia grey"},
+{"name": "chris slinker"},
+{"name": "dave gilbert"},
+{"name": "travis lacno"},
+{"name": "joe iorio"},
+{"name": "angel heredia"},
+{"name": "tom delfosse"},
+{"name": "dexter john"},
+{"name": "jordon cell"},
+{"name": "norma straugh"},
+{"name": "trina dasgupta"},
+{"name": "jon kennedy"},
+{"name": "andrew shrewsbury"},
+{"name": "dave riccardo"},
+{"name": "thanh trang"},
+{"name": "geri titus"},
+{"name": "don farthing"},
+{"name": "nancy denbroeder"},
+{"name": "linda martinez"},
+{"name": "whitney bailey"},
+{"name": "cathy tamkin"},
+{"name": "wade kirkpatrick"},
+{"name": "jacquie brown"},
+{"name": "frank wood"},
+{"name": "krista sk"},
+{"name": "ivy wong"},
+{"name": "john dong"},
+{"name": "andy seng"},
+{"name": "scott pike"},
+{"name": "kayleen kick"},
+{"name": "chris welch"},
+{"name": "sandy mayer"},
+{"name": "roger oliver"},
+{"name": "maggie sentor"},
+{"name": "brian whitmer"},
+{"name": "joanne swindler"},
+{"name": "mark ybarra"},
+{"name": "jennifer hardy"},
+{"name": "mike kimball"},
+{"name": "bill shirley"},
+{"name": "colby straughter"},
+{"name": "todd cooper"},
+{"name": "mariana zamora"},
+{"name": "ryan salzman"},
+{"name": "lai kibildis"},
+{"name": "fred christian"},
+{"name": "joey justmeman"},
+{"name": "victor albert"},
+{"name": "rebecca keg"},
+{"name": "david ttu"},
+{"name": "mike oc"},
+{"name": "suzy hayes"},
+{"name": "karin anderson"},
+{"name": "mike tuck"},
+{"name": "sammy navarro"},
+{"name": "scott werkmeister"},
+{"name": "dave kirkland"},
+{"name": "phil pauling"},
+{"name": "jessica wood"},
+{"name": "dana fermanian"},
+{"name": "graig hebchen"},
+{"name": "aaron reed"},
+{"name": "greg thirkhill"},
+{"name": "ryan kolosso"},
+{"name": "faith curtis"},
+{"name": "kirsten runschke"},
+{"name": "brian spangler"},
+{"name": "mark curtis"},
+{"name": "pete smith"},
+{"name": "nathan fechter"},
+{"name": "eric rashid"},
+{"name": "rob libetti"},
+{"name": "dave devore"},
+{"name": "laurie handelman"},
+{"name": "ron e"},
+{"name": "josh murray"},
+{"name": "chandra sekar"},
+{"name": "chelsea jerome"},
+{"name": "sonia christopher"},
+{"name": "elena lau"},
+{"name": "curt luitgens"},
+{"name": "dawn diley"},
+{"name": "carli meyer"},
+{"name": "andy vinh"},
+{"name": "kay taylor"},
+{"name": "sarah giddens"},
+{"name": "frank coletti"},
+{"name": "kelly bols"},
+{"name": "don sullivan"},
+{"name": "sherry kasper"},
+{"name": "carolyn o'connell"},
+{"name": "mike bregman"},
+{"name": "joe daniels"},
+{"name": "kathy schmidt"},
+{"name": "beth springer"},
+{"name": "debra karper"},
+{"name": "dara zigrang"},
+{"name": "mike grouleau"},
+{"name": "pat conlan"},
+{"name": "zack barker"},
+{"name": "ryan stockton"},
+{"name": "jordan maxey"},
+{"name": "harry bedrossian"},
+{"name": "christina castellanos"},
+{"name": "katie obier"},
+{"name": "ronald bibeault"},
+{"name": "dave campbell"},
+{"name": "shannon gallaher"},
+{"name": "cynthia mcadoo"},
+{"name": "blake n"},
+{"name": "sonia williams"},
+{"name": "lee mackellar"},
+{"name": "catherine gardos"},
+{"name": "ron burnett"},
+{"name": "nicolas petrie"},
+{"name": "maryjane kapleyn"},
+{"name": "kristen potsck"},
+{"name": "sharon beech"},
+{"name": "michelle douglas"},
+{"name": "james cell"},
+{"name": "luis rosales"},
+{"name": "walker pat"},
+{"name": "michael elias"},
+{"name": "cory a"},
+{"name": "teresa castillo"},
+{"name": "jason hopkins"},
+{"name": "diane f"},
+{"name": "alfred hicks"},
+{"name": "mindy loftus"},
+{"name": "jay rosenfeld"},
+{"name": "isaac ortiz"},
+{"name": "tim tyler"},
+{"name": "abby w"},
+{"name": "mary boussy"},
+{"name": "dawn lyon"},
+{"name": "randi greenstein"},
+{"name": "thomas ncaa"},
+{"name": "ed kasaba"},
+{"name": "paul semet"},
+{"name": "john thanopoulos"},
+{"name": "jay trien"},
+{"name": "preston villavicencio"},
+{"name": "hans cheuk"},
+{"name": "ann hennes"},
+{"name": "tom huber"},
+{"name": "gail lundquist"},
+{"name": "summer tinnie"},
+{"name": "shawn quinn"},
+{"name": "guy sier"},
+{"name": "bob balian"},
+{"name": "graham burdis"},
+{"name": "stephen rohde"},
+{"name": "gina tavone"},
+{"name": "leo goldman"},
+{"name": "russell wilson"},
+{"name": "linda elam"},
+{"name": "jim luck"},
+{"name": "kenton cell"},
+{"name": "brent cordil"},
+{"name": "tesha evans"},
+{"name": "brent elasser"},
+{"name": "christopher whyte"},
+{"name": "ronald laxer"},
+{"name": "tanya grimm"},
+{"name": "sabrina brooks"},
+{"name": "douglas cell"},
+{"name": "ryan fakhoorian"},
+{"name": "mike fincher"},
+{"name": "john mcgauvran"},
+{"name": "tony amahda"},
+{"name": "dave spahr"},
+{"name": "korey rush"},
+{"name": "wade kinnison"},
+{"name": "randy weatherton"},
+{"name": "brenda fuentes"},
+{"name": "shirley harris"},
+{"name": "sandra mcleod"},
+{"name": "karl buhr"},
+{"name": "jesse valdovinos"},
+{"name": "george stoneman"},
+{"name": "amanda bastian"},
+{"name": "lacey mcormick"},
+{"name": "dennis girl"},
+{"name": "diana hall"},
+{"name": "bruce mafia"},
+{"name": "yvonne mila"},
+{"name": "richard shannon"},
+{"name": "marilyn bryant"},
+{"name": "charles leduc"},
+{"name": "tyler squared"},
+{"name": "jason fanguy"},
+{"name": "shelby manzitto"},
+{"name": "lora bryner"},
+{"name": "christina guerrero"},
+{"name": "david rosa"},
+{"name": "mike haynie"},
+{"name": "jasmine luna"},
+{"name": "tara feldstein"},
+{"name": "susan gilreath"},
+{"name": "lila fladwood"},
+{"name": "buck darts"},
+{"name": "nicole cattouse"},
+{"name": "marc berm"},
+{"name": "dave beckman"},
+{"name": "hector ramos"},
+{"name": "josh crews"},
+{"name": "howard walmsley"},
+{"name": "hector arce"},
+{"name": "ashley land"},
+{"name": "jimmy stevens"},
+{"name": "john dorris"},
+{"name": "daniel lancaster"},
+{"name": "erin timmerman"},
+{"name": "heather cook"},
+{"name": "dean auld"},
+{"name": "stan miller"},
+{"name": "todd pennington"},
+{"name": "jay steele"},
+{"name": "ron refrigerator"},
+{"name": "kathy gilbert"},
+{"name": "venus delicatessen"},
+{"name": "amanda davis"},
+{"name": "steve sovacki"},
+{"name": "santa maria"},
+{"name": "william goodman"},
+{"name": "melissa wings"},
+{"name": "jeff wittenbrg"},
+{"name": "blake rod"},
+{"name": "cindi copland"},
+{"name": "jason treglia"},
+{"name": "corey blumberg"},
+{"name": "monica valencia"},
+{"name": "don fladwood"},
+{"name": "darwin albrecht"},
+{"name": "dayna sanders"},
+{"name": "terence chippa"},
+{"name": "mike augustyiak"},
+{"name": "allison siler"},
+{"name": "cory freeze"},
+{"name": "britt new"},
+{"name": "sara brown"},
+{"name": "darrel glover"},
+{"name": "daisy lopez"},
+{"name": "scott forkner"},
+{"name": "john sparby"},
+{"name": "antony schweitzer"},
+{"name": "kate mcdermott"},
+{"name": "graham anderson"},
+{"name": "darcy kirkman"},
+{"name": "valarie arenas"},
+{"name": "carolyn cell"},
+{"name": "derek mcloughlin"},
+{"name": "joel a"},
+{"name": "mike plummer"},
+{"name": "brian feldkamp"},
+{"name": "jason bruner"},
+{"name": "dustin fickle"},
+{"name": "steve miller"},
+{"name": "sharon duke"},
+{"name": "gary allender"},
+{"name": "emanuel burgess"},
+{"name": "ryan segovia"},
+{"name": "debbie waters"},
+{"name": "taylor wright"},
+{"name": "susan elkins"},
+{"name": "anthony bonnici"},
+{"name": "kyle mosley"},
+{"name": "stacy harrison"},
+{"name": "mike rivers"},
+{"name": "mike eisenman"},
+{"name": "fernando napoles"},
+{"name": "alex mudge"},
+{"name": "jonathan silverblatt"},
+{"name": "bob morgan"},
+{"name": "bill card"},
+{"name": "anthony pia"},
+{"name": "kathryn reece"},
+{"name": "matthew washington"},
+{"name": "barbara vanderhoof"},
+{"name": "ed durand"},
+{"name": "victor young"},
+{"name": "brandi roberson"},
+{"name": "donna irby"},
+{"name": "randy borden"},
+{"name": "charles busch"},
+{"name": "farah kotadia"},
+{"name": "jack s"},
+{"name": "daniel medvec"},
+{"name": "susan ramsey"},
+{"name": "mike ziehnert"},
+{"name": "shelly o'neill"},
+{"name": "jackie howell"},
+{"name": "bill scholz"},
+{"name": "phuong diethelm"},
+{"name": "gail courtney"},
+{"name": "robert doherty"},
+{"name": "vince finnell"},
+{"name": "lisa c"},
+{"name": "sherry proehl"},
+{"name": "paul cook"},
+{"name": "john smolinski"},
+{"name": "rene hm"},
+{"name": "jimmy smith"},
+{"name": "eddie danley"},
+{"name": "alicia dl"},
+{"name": "gaylord security"},
+{"name": "jack genest"},
+{"name": "mike goldie"},
+{"name": "andy karve"},
+{"name": "allie p"},
+{"name": "michelle elliott"},
+{"name": "boris gluck"},
+{"name": "karen worstell"},
+{"name": "siobhan guiney"},
+{"name": "william bineham"},
+{"name": "tom benze"},
+{"name": "lance chadwell"},
+{"name": "barney laverty"},
+{"name": "burt hekmatnia"},
+{"name": "jenny wettergreen"},
+{"name": "lacy logue"},
+{"name": "karina alverez"},
+{"name": "kurt dahlstrand"},
+{"name": "jeremy haynes"},
+{"name": "mike graef"},
+{"name": "simon jones"},
+{"name": "jessica sahuaqui"},
+{"name": "kendall ufer"},
+{"name": "josh dutcher"},
+{"name": "carolyn watts"},
+{"name": "kathy neal"},
+{"name": "buddy dickerson"},
+{"name": "carly rosa"},
+{"name": "stacie cudmore"},
+{"name": "gerald dunbar"},
+{"name": "kevin woodget"},
+{"name": "anna golf"},
+{"name": "michelle abramoff"},
+{"name": "artie dunn"},
+{"name": "andre house"},
+{"name": "manuel tomasir"},
+{"name": "patrick mcmanamon"},
+{"name": "larry severson"},
+{"name": "tim reader"},
+{"name": "david misumi"},
+{"name": "robert leone"},
+{"name": "david leffers"},
+{"name": "tommy dethridge"},
+{"name": "jonathan estes"},
+{"name": "tony gossett"},
+{"name": "sandra joseph"},
+{"name": "andrew ying"},
+{"name": "grant jacobs"},
+{"name": "wade boggs"},
+{"name": "neil unl"},
+{"name": "zachary stowasser"},
+{"name": "diane kenney"},
+{"name": "margarita seaman"},
+{"name": "joel weiskpf"},
+{"name": "racheal schutte"},
+{"name": "dave berry"},
+{"name": "joe maloof"},
+{"name": "deborah wolfe"},
+{"name": "lee couture"},
+{"name": "wayne koftinoff"},
+{"name": "bob kennedy"},
+{"name": "kathy reese"},
+{"name": "david whang"},
+{"name": "shane byrd"},
+{"name": "ken derkach"},
+{"name": "derrick cowart"},
+{"name": "matt oberlander"},
+{"name": "sylvester dozal"},
+{"name": "tom burtney"},
+{"name": "keith cousin"},
+{"name": "jim keron"},
+{"name": "trent wotherspoon"},
+{"name": "quinn gooch"},
+{"name": "jim sellars"},
+{"name": "eric apple"},
+{"name": "don schumucker"},
+{"name": "johnny misa"},
+{"name": "steve raney"},
+{"name": "brett olson"},
+{"name": "zack karnes"},
+{"name": "matt hasher"},
+{"name": "pete lawless"},
+{"name": "patty bennett"},
+{"name": "mike foisy"},
+{"name": "claire widmark"},
+{"name": "tony lopez"},
+{"name": "mitch medlin"},
+{"name": "chris beck"},
+{"name": "barbara rominski"},
+{"name": "sarah ireland"},
+{"name": "chan mcclinton"},
+{"name": "wyatt bp"},
+{"name": "penny miller"},
+{"name": "dean moble"},
+{"name": "michael rodriguez"},
+{"name": "lawrence benbassett"},
+{"name": "erik casa"},
+{"name": "letty sanchez"},
+{"name": "jeff jeff"},
+{"name": "john rennie"},
+{"name": "david mcmullen"},
+{"name": "jon brogden"},
+{"name": "ross kump"},
+{"name": "marian fink"},
+{"name": "brad kemp"},
+{"name": "mark mcmurray"},
+{"name": "tyler dull"},
+{"name": "ronald coleman"},
+{"name": "kendrick kirkland"},
+{"name": "jodi elite"},
+{"name": "marie bulut"},
+{"name": "michelle king"},
+{"name": "amanda lynch"},
+{"name": "nina demarkey"},
+{"name": "jon luc"},
+{"name": "melinda freitas"},
+{"name": "david falke"},
+{"name": "mary byrne"},
+{"name": "richard thibault"},
+{"name": "monica ferguson"},
+{"name": "leo basuchi"},
+{"name": "ken miles"},
+{"name": "julia pratt"},
+{"name": "janie reynolds"},
+{"name": "michele sanders"},
+{"name": "tim schneider"},
+{"name": "scott jurica"},
+{"name": "clarence gibson"},
+{"name": "jason thornbrugh"},
+{"name": "robert kumin"},
+{"name": "wendy urbina"},
+{"name": "lydia droge"},
+{"name": "joel wilhelm"},
+{"name": "alyssa jones"},
+{"name": "christina young"},
+{"name": "bob chalfin"},
+{"name": "rob diplotti"},
+{"name": "steve holmes"},
+{"name": "miles dupree"},
+{"name": "melanie fernandes"},
+{"name": "kevin buckley"},
+{"name": "keith may"},
+{"name": "tom webb"},
+{"name": "sherman mosley"},
+{"name": "breanna jones"},
+{"name": "david gaver"},
+{"name": "carol branch"},
+{"name": "carlos gonsalez"},
+{"name": "ben katz"},
+{"name": "bill faison"},
+{"name": "tim kibler"},
+{"name": "rob a"},
+{"name": "mercedes younger"},
+{"name": "wendy ayala"},
+{"name": "scott haw"},
+{"name": "samantha rood"},
+{"name": "rob serafin"},
+{"name": "tyler hollingsworth"},
+{"name": "alex miranda+"},
+{"name": "trevor whenham"},
+{"name": "jessica neciuk"},
+{"name": "christopher saridakis"},
+{"name": "bill agrios"},
+{"name": "dave kerdell"},
+{"name": "lacey wirkus"},
+{"name": "eric serrano"},
+{"name": "blair smith"},
+{"name": "amber parlet"},
+{"name": "john palmieri"},
+{"name": "ron tuske"},
+{"name": "angie scates"},
+{"name": "toni swartout"},
+{"name": "wilma davidson"},
+{"name": "shelby christy"},
+{"name": "chris fiorentino"},
+{"name": "mauricio galdamez"},
+{"name": "jim ruonavaara"},
+{"name": "charles moore"},
+{"name": "bruce tobin"},
+{"name": "jaime albornoz"},
+{"name": "mario maintenance"},
+{"name": "trevor nw"},
+{"name": "william kopcke"},
+{"name": "michael frame"},
+{"name": "monica bmw"},
+{"name": "kathy peleggi"},
+{"name": "kayla pittman"},
+{"name": "bruce cleveland"},
+{"name": "darin hamilton"},
+{"name": "beau bowersox"},
+{"name": "toni leal"},
+{"name": "sarah coe"},
+{"name": "michael penfield"},
+{"name": "justin gest"},
+{"name": "lin blair"},
+{"name": "theresa b"},
+{"name": "paul haan"},
+{"name": "mark mityo"},
+{"name": "jimmie wooten"},
+{"name": "christine dell"},
+{"name": "john mulyk"},
+{"name": "daniel jeffrey"},
+{"name": "joe barger"},
+{"name": "see rachel"},
+{"name": "ernie cop"},
+{"name": "julie catalusci"},
+{"name": "shannon savage"},
+{"name": "bryce woerner"},
+{"name": "jaime room"},
+{"name": "tim croddy"},
+{"name": "esther baez"},
+{"name": "jennifer borres"},
+{"name": "jimmy k"},
+{"name": "erin margolis"},
+{"name": "brenda bissett"},
+{"name": "carol levin"},
+{"name": "sara peacock"},
+{"name": "sylvia mcgregor"},
+{"name": "katie werner"},
+{"name": "david desjardins"},
+{"name": "luke finn"},
+{"name": "mark hollman"},
+{"name": "marisa solorzano"},
+{"name": "laura nederbragt"},
+{"name": "dina moeller"},
+{"name": "ken marino"},
+{"name": "paul surender"},
+{"name": "kris hartwell"},
+{"name": "melissa heffrenan"},
+{"name": "robert bucci"},
+{"name": "ryan skaggs"},
+{"name": "dustin covey"},
+{"name": "jeff wald"},
+{"name": "carlo trafficante"},
+{"name": "mike griffith"},
+{"name": "jim petrone"},
+{"name": "kris ross"},
+{"name": "tim anclade"},
+{"name": "regine phillips"},
+{"name": "eric nicks"},
+{"name": "steve foumia"},
+{"name": "john acardo"},
+{"name": "john hudecek"},
+{"name": "rochelle berman"},
+{"name": "teri martin"},
+{"name": "mary amos"},
+{"name": "danielle cuz"},
+{"name": "ann hobaugh"},
+{"name": "steven linn"},
+{"name": "jordan christopher"},
+{"name": "patrick buono"},
+{"name": "joann benson"},
+{"name": "zella tohill"},
+{"name": "jackson racing"},
+{"name": "josh mayans"},
+{"name": "peggy gautschi"},
+{"name": "ian anderson"},
+{"name": "katherine johnson"},
+{"name": "howard bender"},
+{"name": "cindy effron"},
+{"name": "jeff duhaime"},
+{"name": "caroline rothstein"},
+{"name": "jimmy bunch"},
+{"name": "bobby yablunsky"},
+{"name": "amy freeze"},
+{"name": "kathy westernoff"},
+{"name": "jenny sampilo"},
+{"name": "mike beatty"},
+{"name": "vince floriani"},
+{"name": "justin shih"},
+{"name": "joe perez"},
+{"name": "randy fox"},
+{"name": "reggie harris"},
+{"name": "kyle evans"},
+{"name": "eddie lane"},
+{"name": "paul rochlin"},
+{"name": "kevin lyman"},
+{"name": "adam kees"},
+{"name": "eric zapalac"},
+{"name": "melissa quiles"},
+{"name": "nadine bennett"},
+{"name": "jordan tower"},
+{"name": "brenda pena"},
+{"name": "golden spur"},
+{"name": "teresa agustin"},
+{"name": "rodney brooks"},
+{"name": "joe preamo"},
+{"name": "douglas brown"},
+{"name": "gayle alltel"},
+{"name": "leslie kalicharan"},
+{"name": "kevin chen"},
+{"name": "will cook"},
+{"name": "kyle ngc"},
+{"name": "travis select"},
+{"name": "jamie lubin"},
+{"name": "philip giancinti"},
+{"name": "megan mcwayne"},
+{"name": "mark aubin"},
+{"name": "allison truell"},
+{"name": "keith rolle"},
+{"name": "dana team"},
+{"name": "mike weitz"},
+{"name": "kevin bickner"},
+{"name": "dennis meehan"},
+{"name": "debbie smith"},
+{"name": "roy ibm"},
+{"name": "ellen b"},
+{"name": "jack saber"},
+{"name": "tim ambrust"},
+{"name": "rodger lyle"},
+{"name": "aaron compton"},
+{"name": "timmy vaught"},
+{"name": "brenda peterson"},
+{"name": "kelly goold"},
+{"name": "tim hansen"},
+{"name": "tom clowdus"},
+{"name": "charles mattson"},
+{"name": "jim killoran"},
+{"name": "michael bui"},
+{"name": "jackie hales"},
+{"name": "john wraga"},
+{"name": "vicky davies"},
+{"name": "colin mcinnis"},
+{"name": "marsha garst"},
+{"name": "james leibsohn"},
+{"name": "rebecca bstone"},
+{"name": "thomas luszawski"},
+{"name": "latoya meredith"},
+{"name": "rafael castro"},
+{"name": "bill fetzer"},
+{"name": "will zendner"},
+{"name": "steve flabel"},
+{"name": "paul hedrick"},
+{"name": "maria jacques"},
+{"name": "amber mcloud"},
+{"name": "priscilla king"},
+{"name": "mark elect"},
+{"name": "rick ortiz"},
+{"name": "brian gill"},
+{"name": "richard blumenthal"},
+{"name": "katie randall"},
+{"name": "adrienne stintson"},
+{"name": "diane west"},
+{"name": "jed weaver"},
+{"name": "shelley basham"},
+{"name": "andy wallace"},
+{"name": "sharon steffens"},
+{"name": "juan lara"},
+{"name": "troy hendricks"},
+{"name": "chris vogodo"},
+{"name": "chris lynn"},
+{"name": "josh shine"},
+{"name": "brad rosy"},
+{"name": "susan winchell"},
+{"name": "denise henderson"},
+{"name": "joel ramos"},
+{"name": "alexis shuntrece"},
+{"name": "joe aulino"},
+{"name": "thad evans"},
+{"name": "daniel m"},
+{"name": "hugh allen"},
+{"name": "charles rubin"},
+{"name": "ed doherty"},
+{"name": "kris peters"},
+{"name": "tracy cheng"},
+{"name": "kyle t"},
+{"name": "jason moore"},
+{"name": "kelly lim"},
+{"name": "mike molezzi"},
+{"name": "pete dudek"},
+{"name": "andres gustavo"},
+{"name": "ernest simson"},
+{"name": "gary kulhanek"},
+{"name": "leon tuo"},
+{"name": "rudy garcia"},
+{"name": "al jackson"},
+{"name": "candace reeves"},
+{"name": "leo hirner"},
+{"name": "marvin bembry"},
+{"name": "brian romig"},
+{"name": "david bressler"},
+{"name": "will clark"},
+{"name": "tom carroll"},
+{"name": "charmaine davis"},
+{"name": "wendy jamison"},
+{"name": "chris kuklinski"},
+{"name": "don fsdm"},
+{"name": "joe dallo"},
+{"name": "jessica guenther"},
+{"name": "man wome"},
+{"name": "ahmed cab"},
+{"name": "jon harper"},
+{"name": "ryan larsen"},
+{"name": "scot lassle"},
+{"name": "lisa raufman"},
+{"name": "chuck livingston"},
+{"name": "john southard"},
+{"name": "chris landry"},
+{"name": "chris sales"},
+{"name": "keith cell"},
+{"name": "steve duffner"},
+{"name": "mike katona"},
+{"name": "nancy colby"},
+{"name": "nancy wong"},
+{"name": "krystal payne"},
+{"name": "jean estes"},
+{"name": "theresa peavler"},
+{"name": "tracie butler"},
+{"name": "connie chang"},
+{"name": "michael pang"},
+{"name": "don dons"},
+{"name": "brian grossi"},
+{"name": "jason rutkowski"},
+{"name": "linda cebu"},
+{"name": "dan cleary"},
+{"name": "robert bailey"},
+{"name": "matt snell"},
+{"name": "lindsay mccormick"},
+{"name": "joe tam"},
+{"name": "caroline holicky"},
+{"name": "echo housing"},
+{"name": "heidi bartlett"},
+{"name": "rick rentz"},
+{"name": "larry cantu"},
+{"name": "john marn"},
+{"name": "brian sanders"},
+{"name": "dawn mazzie"},
+{"name": "beth keiller"},
+{"name": "alma gutierrez"},
+{"name": "teri white"},
+{"name": "jeff weiss"},
+{"name": "heather jeffcoat"},
+{"name": "jackson keller"},
+{"name": "nora landry"},
+{"name": "mike wheaton"},
+{"name": "dee haber"},
+{"name": "brian shear"},
+{"name": "tama mobley"},
+{"name": "mark ba"},
+{"name": "cyrus nowroozani"},
+{"name": "tracy cole"},
+{"name": "jeanna schultz"},
+{"name": "jack giambrone"},
+{"name": "bryan carroll"},
+{"name": "richard radbil"},
+{"name": "malcolm johnson"},
+{"name": "laura irving"},
+{"name": "annie dai"},
+{"name": "ron quinoes"},
+{"name": "chris ropp"},
+{"name": "tony pur"},
+{"name": "aubrey newson"},
+{"name": "tia johanna"},
+{"name": "josh laurel"},
+{"name": "jimmy coach"},
+{"name": "min byrd"},
+{"name": "paul dydo"},
+{"name": "don monkovic"},
+{"name": "jean nadeau"},
+{"name": "cameron takasaki"},
+{"name": "deanna haas"},
+{"name": "dan stehly"},
+{"name": "jack mcnamara"},
+{"name": "gretchen anderson"},
+{"name": "mark whittle"},
+{"name": "patricia woodard"},
+{"name": "tina cecil"},
+{"name": "bret harsham"},
+{"name": "chad southwell"},
+{"name": "mike butter"},
+{"name": "amy vanderlip"},
+{"name": "richard judd"},
+{"name": "cliff roper"},
+{"name": "lauren rubin"},
+{"name": "missy luczak"},
+{"name": "kathy beale"},
+{"name": "jeff barnes"},
+{"name": "lauren bowling"},
+{"name": "ivan navarro"},
+{"name": "matt maggie"},
+{"name": "rod buford"},
+{"name": "kyle sound"},
+{"name": "mike sassi"},
+{"name": "kent marlor"},
+{"name": "chris gardner"},
+{"name": "nathan rinsema"},
+{"name": "michael decrescio"},
+{"name": "matt weeks"},
+{"name": "emily noble"},
+{"name": "robert frankel"},
+{"name": "richard eiswirth"},
+{"name": "jason dees"},
+{"name": "mike nasi"},
+{"name": "sharon knorr"},
+{"name": "tim renner"},
+{"name": "cathy garrison"},
+{"name": "sabrina wiedemeier"},
+{"name": "heidy cano"},
+{"name": "tami jones"},
+{"name": "johnson cooper"},
+{"name": "neal mccullohs"},
+{"name": "adam michigan"},
+{"name": "susan bell"},
+{"name": "ralph meyer"},
+{"name": "christina tang"},
+{"name": "ann gray"},
+{"name": "mark ant"},
+{"name": "chris tigri"},
+{"name": "tammy madnette"},
+{"name": "van straaten"},
+{"name": "joe gull"},
+{"name": "jose super"},
+{"name": "craig burns"},
+{"name": "gary barber"},
+{"name": "bernadette vargas"},
+{"name": "ryan alvey"},
+{"name": "nicole feaster"},
+{"name": "mario soto"},
+{"name": "cris pruit"},
+{"name": "lizzie richardson"},
+{"name": "terry happ"},
+{"name": "joyce griffin"},
+{"name": "camille enriquez"},
+{"name": "randy johns"},
+{"name": "sarah heskarie"},
+{"name": "fred archibald"},
+{"name": "carl reissig"},
+{"name": "marti mcguire"},
+{"name": "john evangelista"},
+{"name": "michael cesario"},
+{"name": "ryan maisano"},
+{"name": "margarite sitter"},
+{"name": "anthony montoya"},
+{"name": "michelle cue"},
+{"name": "wes reuning"},
+{"name": "john gadberry"},
+{"name": "mike pepoon"},
+{"name": "sandra bell"},
+{"name": "alex haven"},
+{"name": "marta chavira"},
+{"name": "sam duncan"},
+{"name": "dave kiser"},
+{"name": "frank kelley"},
+{"name": "bob barth"},
+{"name": "kristin vocalist"},
+{"name": "daniel rothschild"},
+{"name": "chanda smith"},
+{"name": "verna asman"},
+{"name": "dan kaufmann"},
+{"name": "bob work"},
+{"name": "richard barnes"},
+{"name": "george carson"},
+{"name": "lauren guzak"},
+{"name": "bert mobile"},
+{"name": "sandy wiegers"},
+{"name": "jessica kottmeier"},
+{"name": "mellisa newill"},
+{"name": "rachel ho"},
+{"name": "andres podra"},
+{"name": "basil lewis"},
+{"name": "jay huzzle"},
+{"name": "josh morris"},
+{"name": "anthony cordova"},
+{"name": "johnathan devlin"},
+{"name": "clark robinson"},
+{"name": "ashley west"},
+{"name": "ian armstrong"},
+{"name": "matt wilson"},
+{"name": "paul santor"},
+{"name": "brian damario"},
+{"name": "peter lischerelli"},
+{"name": "nancy almasi"},
+{"name": "amanda pearson"},
+{"name": "gay boy"},
+{"name": "joann sopchak"},
+{"name": "mark lumos"},
+{"name": "karla marck"},
+{"name": "katheryn aldridge"},
+{"name": "chuck coughran"},
+{"name": "patti urban"},
+{"name": "sarah huff"},
+{"name": "marty brown"},
+{"name": "janet scott"},
+{"name": "nathan franzen"},
+{"name": "penny picket"},
+{"name": "krystal boobs"},
+{"name": "nicole murphy"},
+{"name": "ashley aura"},
+{"name": "alexander samwer"},
+{"name": "jesus barraza"},
+{"name": "eric dallor"},
+{"name": "donald hofmann"},
+{"name": "mark heydorff"},
+{"name": "frances loveland"},
+{"name": "jim willard"},
+{"name": "gene hopper"},
+{"name": "phil carroll"},
+{"name": "greg garrett"},
+{"name": "donald dustin"},
+{"name": "marcel wingerden"},
+{"name": "ricky ross"},
+{"name": "jessica aitain"},
+{"name": "allan pixton"},
+{"name": "thurman sammie"},
+{"name": "brenda disney"},
+{"name": "kim adrian"},
+{"name": "summer grove"},
+{"name": "keith keener"},
+{"name": "misty allen"},
+{"name": "bobby karr"},
+{"name": "bob gillespie"},
+{"name": "michael zeisser"},
+{"name": "roger baird"},
+{"name": "kathy loven"},
+{"name": "mike profeta"},
+{"name": "grant call"},
+{"name": "christian couturier"},
+{"name": "susan mald"},
+{"name": "kevin hodges"},
+{"name": "cesar ramirez"},
+{"name": "molly dunphy"},
+{"name": "van natta"},
+{"name": "mike colosimo"},
+{"name": "jill williams"},
+{"name": "keith butler"},
+{"name": "brandon mayernick"},
+{"name": "scott carlisle"},
+{"name": "andre fino"},
+{"name": "rod givens"},
+{"name": "jonathan conforti"},
+{"name": "chris detert"},
+{"name": "john touchet"},
+{"name": "kurt ludlow"},
+{"name": "delbert aden"},
+{"name": "jimmie parker"},
+{"name": "lynda anderson"},
+{"name": "brian stearns"},
+{"name": "andre caradine"},
+{"name": "mike cordero"},
+{"name": "florida employee"},
+{"name": "meagan melgaard"},
+{"name": "marie scott"},
+{"name": "dick oxford"},
+{"name": "jennifer mauri"},
+{"name": "andrew bentley"},
+{"name": "rachel holt"},
+{"name": "chris riley"},
+{"name": "james morand"},
+{"name": "tom nofi"},
+{"name": "annette harris"},
+{"name": "dan habeeb"},
+{"name": "mark hamilton"},
+{"name": "mario olivieri"},
+{"name": "kristin melrose"},
+{"name": "dan crawford"},
+{"name": "carey davis"},
+{"name": "meryl fox"},
+{"name": "mitchell kroll"},
+{"name": "valerie price"},
+{"name": "sharon forrest"},
+{"name": "barry alberstein"},
+{"name": "brittany fiorini"},
+{"name": "boris koechlin"},
+{"name": "demetrius johnson"},
+{"name": "zita brooks"},
+{"name": "jimmy voce"},
+{"name": "chad dalton"},
+{"name": "diana palma"},
+{"name": "carin buckman"},
+{"name": "rob snow"},
+{"name": "steve papian"},
+{"name": "aja sansbury"},
+{"name": "jessica pengcell"},
+{"name": "frank mandarino"},
+{"name": "julio v"},
+{"name": "craig stevens"},
+{"name": "pete tipton"},
+{"name": "eddie mam"},
+{"name": "jeffrey michaelson"},
+{"name": "frank canada"},
+{"name": "una dean"},
+{"name": "bill parks"},
+{"name": "moshe klodny"},
+{"name": "alex fast"},
+{"name": "danielle rios"},
+{"name": "carl flatman"},
+{"name": "mark addicks"},
+{"name": "natalie toalson"},
+{"name": "maurice abernathy"},
+{"name": "raymond aviles"},
+{"name": "jeff bolles"},
+{"name": "mac specialist"},
+{"name": "amy artiga"},
+{"name": "dustin creden"},
+{"name": "paul swierczek"},
+{"name": "bill winward"},
+{"name": "mitch bell"},
+{"name": "jim hostler"},
+{"name": "dennis abell"},
+{"name": "michel grenier"},
+{"name": "jaime wirth"},
+{"name": "leah cell"},
+{"name": "stephanie moval"},
+{"name": "carolyn boothe"},
+{"name": "erika owens"},
+{"name": "annette gulley"},
+{"name": "rudy castanon"},
+{"name": "dorothy franks"},
+{"name": "betty xxxxx"},
+{"name": "claudia b"},
+{"name": "victor sultana"},
+{"name": "mark berret"},
+{"name": "ben schopick"},
+{"name": "lannie garrett"},
+{"name": "tommy mann"},
+{"name": "erma erma"},
+{"name": "heather lonsdale"},
+{"name": "john ruppert"},
+{"name": "aaron farrell"},
+{"name": "denise baxter"},
+{"name": "jason staudt"},
+{"name": "shaun varsos"},
+{"name": "justin ragsdale"},
+{"name": "mildred ruiz"},
+{"name": "mike denman"},
+{"name": "parker county"},
+{"name": "steve leavitt"},
+{"name": "judy hutchinson"},
+{"name": "stefanie shawn"},
+{"name": "melissa paterno"},
+{"name": "anne hutchins"},
+{"name": "maria crawford"},
+{"name": "john niemi"},
+{"name": "brandi meyer"},
+{"name": "steve keisling"},
+{"name": "jeff thomas"},
+{"name": "kerry tullis"},
+{"name": "wendy client"},
+{"name": "jennifer felt"},
+{"name": "joey iannucci"},
+{"name": "joshua baiel"},
+{"name": "lynn marquez"},
+{"name": "wes lathen"},
+{"name": "eric glader"},
+{"name": "shane mathai"},
+{"name": "bill buster"},
+{"name": "jeremy johnson"},
+{"name": "max franco"},
+{"name": "sally sackett"},
+{"name": "james wan"},
+{"name": "cynthia booker"},
+{"name": "tonya mercer"},
+{"name": "anita sahi"},
+{"name": "frank bucys"},
+{"name": "emily wolf"},
+{"name": "vickie boyles"},
+{"name": "george powers"},
+{"name": "kevin yajko"},
+{"name": "bobby o"},
+{"name": "buster grayson"},
+{"name": "chuck patton"},
+{"name": "kevin lewis"},
+{"name": "anthony abbondandolo"},
+{"name": "sean evans"},
+{"name": "thomas hoeff"},
+{"name": "mike hadjinian"},
+{"name": "april boyd"},
+{"name": "alejandra nunez"},
+{"name": "barbara bucciarelli"},
+{"name": "errol vassell"},
+{"name": "david augustine"},
+{"name": "chris dion"},
+{"name": "mike wooten"},
+{"name": "frank puchia"},
+{"name": "brandon peabodys"},
+{"name": "anika hunter"},
+{"name": "brock hansen"},
+{"name": "rick barrs"},
+{"name": "genevieve berardino"},
+{"name": "thomas sherer"},
+{"name": "lynn burge"},
+{"name": "markus king"},
+{"name": "david gilday"},
+{"name": "john yapundich"},
+{"name": "jayson rodriguez"},
+{"name": "kris stone"},
+{"name": "morgan cell"},
+{"name": "carlos henriques"},
+{"name": "jon decolos"},
+{"name": "arthur dehn"},
+{"name": "anna mcgrath"},
+{"name": "stuart mckown"},
+{"name": "tammy houston"},
+{"name": "matthew roos"},
+{"name": "brett k"},
+{"name": "keith zendler"},
+{"name": "ricky wedner"},
+{"name": "danielle herl"},
+{"name": "ryan walz"},
+{"name": "brett maclean"},
+{"name": "rachel derby"},
+{"name": "adam myers"},
+{"name": "howard long"},
+{"name": "dawn atkin"},
+{"name": "kiley peek"},
+{"name": "rachel jensen"},
+{"name": "kai foster"},
+{"name": "mark eichten"},
+{"name": "zoe brown"},
+{"name": "john poss"},
+{"name": "michael licata"},
+{"name": "moses harb"},
+{"name": "anthony crescimano"},
+{"name": "ashley j"},
+{"name": "tommy gunn"},
+{"name": "sharon gall"},
+{"name": "damon phillips"},
+{"name": "francis kasama"},
+{"name": "amy truesdell"},
+{"name": "ray lincoln"},
+{"name": "michelle herdmann"},
+{"name": "billy dakroub"},
+{"name": "gerald saldo"},
+{"name": "chris cantor"},
+{"name": "cyrus santiago"},
+{"name": "agustin cruz"},
+{"name": "victor sanchez"},
+{"name": "arturo moreno"},
+{"name": "marty cell"},
+{"name": "micah guster"},
+{"name": "violet borgic"},
+{"name": "brandon vick"},
+{"name": "sherry parkside"},
+{"name": "debbie coffman"},
+{"name": "chris loftin"},
+{"name": "jackie powell"},
+{"name": "warren dubrow"},
+{"name": "leona cotruvo"},
+{"name": "candice m"},
+{"name": "jill merkey"},
+{"name": "cortez ilwu"},
+{"name": "mike hardin"},
+{"name": "jessica w"},
+{"name": "steve mills"},
+{"name": "ashlee williams"},
+{"name": "eli gross"},
+{"name": "vernon ausby"},
+{"name": "tony cindy"},
+{"name": "sean gautier"},
+{"name": "marc forman"},
+{"name": "jada c"},
+{"name": "hope leber"},
+{"name": "richard scannell"},
+{"name": "bill keller"},
+{"name": "glen ellyn"},
+{"name": "josephine gee"},
+{"name": "chad simmons"},
+{"name": "julie ingram"},
+{"name": "brooke brunell"},
+{"name": "allan delaine"},
+{"name": "hugo delgado"},
+{"name": "tom ahrendt"},
+{"name": "herb rikelman"},
+{"name": "octavia ealey"},
+{"name": "edwina mccain"},
+{"name": "erica lewis"},
+{"name": "greg soly"},
+{"name": "thomas lang"},
+{"name": "lucille roberts"},
+{"name": "laura jeffcoat"},
+{"name": "philip fisher"},
+{"name": "sonia rao"},
+{"name": "richie ramirez"},
+{"name": "alan israel"},
+{"name": "karen miller"},
+{"name": "lidia kupiec"},
+{"name": "jim kilroy"},
+{"name": "tim blind"},
+{"name": "alex barwinski"},
+{"name": "shea inglis"},
+{"name": "andy rav"},
+{"name": "george hart"},
+{"name": "patsy chu"},
+{"name": "rob corsino"},
+{"name": "eli gluckowsky"},
+{"name": "paul casper"},
+{"name": "paul pei"},
+{"name": "renee labran"},
+{"name": "doug amos"},
+{"name": "john hunt"},
+{"name": "johnny powell"},
+{"name": "don delf"},
+{"name": "brandon mize"},
+{"name": "tracy mcallister"},
+{"name": "randy roberts"},
+{"name": "terry hollstein"},
+{"name": "robert covarrubias"},
+{"name": "nicole curry"},
+{"name": "roland wilson"},
+{"name": "brian murphy"},
+{"name": "steve brotman"},
+{"name": "jenny lopez"},
+{"name": "kaylee cell"},
+{"name": "gerald wendt"},
+{"name": "melisa ilia"},
+{"name": "bonnie liston"},
+{"name": "ernie durrah"},
+{"name": "rafael goeting"},
+{"name": "sam haggerty"},
+{"name": "derrick bildner"},
+{"name": "linda benea"},
+{"name": "sheryll norris"},
+{"name": "joe deguida"},
+{"name": "shayna lynn"},
+{"name": "joe mccabe"},
+{"name": "mark casado"},
+{"name": "tom peters"},
+{"name": "troy owens"},
+{"name": "tim ginter"},
+{"name": "jerry scarola"},
+{"name": "jesse malonie"},
+{"name": "monica garcia"},
+{"name": "rene fortin"},
+{"name": "rob ciampa"},
+{"name": "jeromy rogan"},
+{"name": "alex baum"},
+{"name": "nicole trottie"},
+{"name": "tony fedx"},
+{"name": "rebecca jane"},
+{"name": "sheila b"},
+{"name": "jennifer weigele"},
+{"name": "kyung sung"},
+{"name": "shanna p"},
+{"name": "joanne berry"},
+{"name": "barbara brasher"},
+{"name": "raul moncarz"},
+{"name": "nancy hyland"},
+{"name": "carol chang"},
+{"name": "dale hall"},
+{"name": "joyce jones"},
+{"name": "lupe dance"},
+{"name": "carmen contreras"},
+{"name": "fred covery"},
+{"name": "mabel polanco"},
+{"name": "susan castagna"},
+{"name": "kimberley dias"},
+{"name": "virginia crack"},
+{"name": "buck goldstein"},
+{"name": "connie spotwood"},
+{"name": "bernie uhlich"},
+{"name": "doyle liesenfelt"},
+{"name": "bea ryan"},
+{"name": "victor dado"},
+{"name": "daniel w"},
+{"name": "kelly irvin"},
+{"name": "ardella cell"},
+{"name": "kathleen hinkley"},
+{"name": "sue fuse"},
+{"name": "steve davey"},
+{"name": "irene meza"},
+{"name": "dan trujillo"},
+{"name": "leona thomas"},
+{"name": "marie stein"},
+{"name": "ryan doll"},
+{"name": "lilian mosre"},
+{"name": "amy cole"},
+{"name": "bart pugh"},
+{"name": "anthony strand"},
+{"name": "marlo hannah"},
+{"name": "stephanie ferrell"},
+{"name": "yolanda maintenance"},
+{"name": "luke burroughs"},
+{"name": "ian winter"},
+{"name": "steve gonzales"},
+{"name": "marnie francis"},
+{"name": "scott goodreau"},
+{"name": "monique gorman"},
+{"name": "kevin trudeau"},
+{"name": "danny worksforheadofit"},
+{"name": "nick grohl"},
+{"name": "paul rivich"},
+{"name": "wendy nesta"},
+{"name": "lynn martin"},
+{"name": "dale yonkin"},
+{"name": "danielle eisner"},
+{"name": "omar khan"},
+{"name": "marcus baldwin"},
+{"name": "marie russell"},
+{"name": "steve gamboa"},
+{"name": "andre calis"},
+{"name": "ron powell"},
+{"name": "steve elbert"},
+{"name": "cecil callis"},
+{"name": "travis sheive"},
+{"name": "sara wells"},
+{"name": "gwen prather"},
+{"name": "martin ruth"},
+{"name": "john church"},
+{"name": "cheryl kay"},
+{"name": "emily moeller"},
+{"name": "bill patten"},
+{"name": "lauren work"},
+{"name": "brian mcgrain"},
+{"name": "gary nelson"},
+{"name": "malena francis"},
+{"name": "penny bayer"},
+{"name": "diana shishalovsky"},
+{"name": "elana hathaway"},
+{"name": "jamie larson"},
+{"name": "jack heim"},
+{"name": "tina tp"},
+{"name": "linda silvers"},
+{"name": "joe bernstein"},
+{"name": "lindsey carswell"},
+{"name": "felicia cooper"},
+{"name": "jessica altman"},
+{"name": "michelle hallowell"},
+{"name": "nathan barry"},
+{"name": "linda cole"},
+{"name": "elise russell"},
+{"name": "katie fortenberry"},
+{"name": "gail rauch"},
+{"name": "mike maychack"},
+{"name": "mark jolesch"},
+{"name": "glen tofani"},
+{"name": "jonathan wellum"},
+{"name": "shelly palmer"},
+{"name": "tiffany fortna"},
+{"name": "mike kennewick"},
+{"name": "gina maiden"},
+{"name": "tommy jimenez"},
+{"name": "richard harris"},
+{"name": "anna saysith"},
+{"name": "justin medina"},
+{"name": "rod kauffman"},
+{"name": "tim herb"},
+{"name": "john artenies"},
+{"name": "robert horn"},
+{"name": "rachel v"},
+{"name": "heather brassel"},
+{"name": "joe d"},
+{"name": "mike blair"},
+{"name": "dong cell"},
+{"name": "allison roehrs"},
+{"name": "phil white"},
+{"name": "frankie sol"},
+{"name": "ken abes"},
+{"name": "bryan bray"},
+{"name": "jerry ko"},
+{"name": "rona mercado"},
+{"name": "kelli littleton"},
+{"name": "thomas chambers"},
+{"name": "austin hodges"},
+{"name": "mark rita"},
+{"name": "tyler bridges"},
+{"name": "ricky rick"},
+{"name": "jim gattuso"},
+{"name": "thomas steinert"},
+{"name": "jamie milburn"},
+{"name": "james cazort"},
+{"name": "alisa neely"},
+{"name": "joanna arnold"},
+{"name": "cesar silva"},
+{"name": "brandi hardin"},
+{"name": "dave shackton"},
+{"name": "wayne haye"},
+{"name": "chris owens"},
+{"name": "anthony villalobos"},
+{"name": "dan riordan"},
+{"name": "jason electrician"},
+{"name": "matt budd"},
+{"name": "rick zeiler"},
+{"name": "wyatt bryan"},
+{"name": "jean pallardy"},
+{"name": "sarah gotham"},
+{"name": "charles english"},
+{"name": "sara stacey"},
+{"name": "harriet ellis"},
+{"name": "rafael duarte"},
+{"name": "roxy reynolds"},
+{"name": "dave leduc"},
+{"name": "richard stewart"},
+{"name": "gary white"},
+{"name": "ken drake"},
+{"name": "tom decker"},
+{"name": "jillian lewis"},
+{"name": "jonathan shapiro"},
+{"name": "matt redfield"},
+{"name": "lynda britt"},
+{"name": "thao le"},
+{"name": "brian shaw"},
+{"name": "kaye schmuck"},
+{"name": "paul magee"},
+{"name": "shelby tuttle"},
+{"name": "chris tat"},
+{"name": "renee eichert"},
+{"name": "jason geraci"},
+{"name": "tony chi"},
+{"name": "charisse mclorren"},
+{"name": "charlie burgess"},
+{"name": "randy pannell"},
+{"name": "tony ware"},
+{"name": "kelsey martin"},
+{"name": "jeff overmeyer"},
+{"name": "james velvin"},
+{"name": "fred house"},
+{"name": "ali nordstrom"},
+{"name": "warren edis"},
+{"name": "robert lolohea"},
+{"name": "dan oberes"},
+{"name": "marcel mack"},
+{"name": "candace maddin"},
+{"name": "sam giles"},
+{"name": "nicole waterfront"},
+{"name": "amber drabick"},
+{"name": "christina carpenter"},
+{"name": "nathan romanchuk"},
+{"name": "ed ronan"},
+{"name": "paul surles"},
+{"name": "terry ward"},
+{"name": "sara crawford"},
+{"name": "rusty haak"},
+{"name": "nicole smith"},
+{"name": "pablo gomez"},
+{"name": "wayne baker"},
+{"name": "john corritore"},
+{"name": "mike azzarelli"},
+{"name": "tim baldwin"},
+{"name": "alan home"},
+{"name": "marty cousin"},
+{"name": "dennis payonk"},
+{"name": "theresa truss"},
+{"name": "karrie nordberg"},
+{"name": "kevin czarnecki"},
+{"name": "aaron allen"},
+{"name": "rich gillette"},
+{"name": "jon garvey"},
+{"name": "quinn apt"},
+{"name": "carmen mueller"},
+{"name": "april jones"},
+{"name": "kendra collins"},
+{"name": "paula downey"},
+{"name": "sheree thurmand"},
+{"name": "dave broucek"},
+{"name": "jared thomas"},
+{"name": "jessica liu"},
+{"name": "stephanie smith"},
+{"name": "jeff bartley"},
+{"name": "mary laumar"},
+{"name": "doreen dumond"},
+{"name": "echo falls"},
+{"name": "star tattoo"},
+{"name": "tiffany baker"},
+{"name": "lloyd hendershot"},
+{"name": "kelli brandt"},
+{"name": "abe driedger"},
+{"name": "philip heller"},
+{"name": "kurt abbott"},
+{"name": "bill reissfelder"},
+{"name": "greg bellos"},
+{"name": "jeremy tke"},
+{"name": "tabitha culler"},
+{"name": "anne hooper"},
+{"name": "mike stoessel"},
+{"name": "tim woods"},
+{"name": "michael lockridge"},
+{"name": "john gaittens"},
+{"name": "kevin rollings"},
+{"name": "johnathan c"},
+{"name": "christine webster"},
+{"name": "john staton"},
+{"name": "denise reiling"},
+{"name": "devin rasta"},
+{"name": "david kalloor"},
+{"name": "adina kalet"},
+{"name": "lee fenimore"},
+{"name": "rob forman"},
+{"name": "lea kreimes"},
+{"name": "dixie broussard"},
+{"name": "marie issels"},
+{"name": "cindy frank"},
+{"name": "brenda mcleish"},
+{"name": "betty dosher"},
+{"name": "sandra ikilljew"},
+{"name": "cari smith"},
+{"name": "caroline home"},
+{"name": "jordan grotzinger"},
+{"name": "kenneth pickering"},
+{"name": "blake weaver"},
+{"name": "robert ash"},
+{"name": "jen siddle"},
+{"name": "andre nedranets"},
+{"name": "fredric sugarman"},
+{"name": "george spears"},
+{"name": "brent hatcher"},
+{"name": "amanda samantha"},
+{"name": "elizabeth bennington"},
+{"name": "jeremiah lynn"},
+{"name": "monte sahba"},
+{"name": "james thomsen"},
+{"name": "paul hernandez"},
+{"name": "alexander vinnychuk"},
+{"name": "bill buxton"},
+{"name": "beverley dorsey"},
+{"name": "kevin cogswell"},
+{"name": "pedro delgado"},
+{"name": "bob harlow"},
+{"name": "katie frisbe"},
+{"name": "mark mittelman"},
+{"name": "mary kovacevic"},
+{"name": "carol dj"},
+{"name": "herbert alexander"},
+{"name": "zachary dobbins"},
+{"name": "patti staack"},
+{"name": "lauren cape"},
+{"name": "natalie singleton"},
+{"name": "mark debosier"},
+{"name": "carlton cull"},
+{"name": "charles baur"},
+{"name": "carter gibbs"},
+{"name": "michelle callahan"},
+{"name": "susan shue"},
+{"name": "anne sieracki"},
+{"name": "angelique louden"},
+{"name": "rob prigge"},
+{"name": "jim rico"},
+{"name": "tara saladyga"},
+{"name": "meg meaney"},
+{"name": "leon jr"},
+{"name": "amina bingle"},
+{"name": "derek yau"},
+{"name": "xavier williams"},
+{"name": "jason cook"},
+{"name": "graham kozco"},
+{"name": "juli sande"},
+{"name": "kelly roughley"},
+{"name": "jeff barrington"},
+{"name": "bobby sanchez"},
+{"name": "jamie henderson"},
+{"name": "paul pearson"},
+{"name": "sarah derricot"},
+{"name": "paul pugh"},
+{"name": "jessica barakat"},
+{"name": "debi adams"},
+{"name": "wallace elect"},
+{"name": "robert hudson"},
+{"name": "ken spaeth"},
+{"name": "kelly powell"},
+{"name": "jeff mendlin"},
+{"name": "jennie flocken"},
+{"name": "andrea becker"},
+{"name": "chris gosling"},
+{"name": "josh boots"},
+{"name": "armando meras"},
+{"name": "kevin mckee"},
+{"name": "jeff memlar"},
+{"name": "tom mcnally"},
+{"name": "judy jacksina"},
+{"name": "katherine nguyen"},
+{"name": "barton tanenbaum"},
+{"name": "joan eric"},
+{"name": "vicky jone"},
+{"name": "leon chapman"},
+{"name": "jimmy ocean"},
+{"name": "david hospital"},
+{"name": "ricardo cerdan"},
+{"name": "joel williams"},
+{"name": "jim marchildon"},
+{"name": "pedro mendez"},
+{"name": "cindy campbell"},
+{"name": "ali o'connor"},
+{"name": "rob waldman"},
+{"name": "sam hooters"},
+{"name": "scott weiner"},
+{"name": "sandra bertelle"},
+{"name": "joseph sireci"},
+{"name": "jazmin jackson"},
+{"name": "peter angelo"},
+{"name": "karen dispatch"},
+{"name": "brandon team"},
+{"name": "daniel biello"},
+{"name": "maggie heinz"},
+{"name": "mathew hughes"},
+{"name": "brett sperry"},
+{"name": "matt rock"},
+{"name": "cameron c"},
+{"name": "christa lawarence"},
+{"name": "lorraine sneed"},
+{"name": "steven diaz"},
+{"name": "glen thompson"},
+{"name": "katie knipp"},
+{"name": "renata king"},
+{"name": "kurt shipcott"},
+{"name": "alex rylov"},
+{"name": "randy strand"},
+{"name": "sal nolasco"},
+{"name": "melony stagg"},
+{"name": "natalie sutton"},
+{"name": "david burke"},
+{"name": "ken rasmusen"},
+{"name": "roger parker"},
+{"name": "mandy deland"},
+{"name": "ralph veller"},
+{"name": "omar adt"},
+{"name": "brian hadcock"},
+{"name": "deon badu"},
+{"name": "roger spore"},
+{"name": "richard fishman"},
+{"name": "brian zuck"},
+{"name": "kevin connelly"},
+{"name": "jesse marinez"},
+{"name": "dylan strong"},
+{"name": "angie giovenco"},
+{"name": "eddie lopez"},
+{"name": "brian matthews"},
+{"name": "kathie gruen"},
+{"name": "matt ducoffe"},
+{"name": "angela ebl"},
+{"name": "edison specialty"},
+{"name": "john nitinthorn"},
+{"name": "may lei"},
+{"name": "roy greenberg"},
+{"name": "ricky hooker"},
+{"name": "andrea phar"},
+{"name": "dave beaulieu"},
+{"name": "caitlyn curtis"},
+{"name": "tony tonyr"},
+{"name": "patrice cadieux"},
+{"name": "jason welker"},
+{"name": "anna security"},
+{"name": "bryan piard"},
+{"name": "freddie tennis"},
+{"name": "gary isaac"},
+{"name": "kathy tran"},
+{"name": "patrica bilotto"},
+{"name": "carla daley"},
+{"name": "ann nylen"},
+{"name": "vicki lawson"},
+{"name": "mike fogle"},
+{"name": "kim b"},
+{"name": "issac q"},
+{"name": "luke pryde"},
+{"name": "david rounds"},
+{"name": "sara undies"},
+{"name": "linda thurman"},
+{"name": "wayne dodd"},
+{"name": "tiffani greene"},
+{"name": "paul thacker"},
+{"name": "jeff orange"},
+{"name": "lili phangia"},
+{"name": "cliff white"},
+{"name": "van buskirk"},
+{"name": "long distance"},
+{"name": "porter airlines"},
+{"name": "kelli lubbers"},
+{"name": "carolyn burgin"},
+{"name": "jason standiford"},
+{"name": "tracy warzynski"},
+{"name": "allan weaver"},
+{"name": "david poare"},
+{"name": "dee spuriel"},
+{"name": "sherman munch"},
+{"name": "bryan greenawalt"},
+{"name": "van huis"},
+{"name": "bill tadlock"},
+{"name": "jan hoffmaster"},
+{"name": "steve shapiro"},
+{"name": "william pangestu"},
+{"name": "christopher johns"},
+{"name": "sam mahakrittiyadhorn"},
+{"name": "steve slyke"},
+{"name": "mary perez"},
+{"name": "maria soto"},
+{"name": "keri luecht"},
+{"name": "bethany harlan"},
+{"name": "sid gathers"},
+{"name": "keith wong"},
+{"name": "bob cooper"},
+{"name": "caleb landis"},
+{"name": "bryan padilla"},
+{"name": "kelly kinnaman"},
+{"name": "ryan mackiewich"},
+{"name": "mary marshall"},
+{"name": "melissa plowden"},
+{"name": "ann manafi"},
+{"name": "mark linscomb"},
+{"name": "jim kreitz"},
+{"name": "jim nietfield"},
+{"name": "darlene hernandez"},
+{"name": "bruce gagle"},
+{"name": "carey kusik"},
+{"name": "dean pavletich"},
+{"name": "shirl sochacki"},
+{"name": "jeff elling"},
+{"name": "jeanne brammer"},
+{"name": "jay o"},
+{"name": "tom handy"},
+{"name": "jan carreon"},
+{"name": "wayne innes"},
+{"name": "virginia eby"},
+{"name": "isabel silva"},
+{"name": "pat fracavilla"},
+{"name": "sean mckillion"},
+{"name": "justin y"},
+{"name": "chris sedensky"},
+{"name": "tasha hageman"},
+{"name": "ronnie ellenbrook"},
+{"name": "alice lee"},
+{"name": "chris parps"},
+{"name": "cari burnette"},
+{"name": "jesse williams"},
+{"name": "nick mercurio"},
+{"name": "john thibault"},
+{"name": "bruce fischer"},
+{"name": "rob debar"},
+{"name": "alan stowell"},
+{"name": "patricia keith"},
+{"name": "christina hooters"},
+{"name": "ricardo flores"},
+{"name": "jan ting"},
+{"name": "chad miller"},
+{"name": "gerald cole"},
+{"name": "andrew hogg"},
+{"name": "phil foss"},
+{"name": "paul s"},
+{"name": "christy hancock"},
+{"name": "ellen mcmahon"},
+{"name": "cathy mendlin"},
+{"name": "billy laskota"},
+{"name": "charlie wild"},
+{"name": "anthony wil"},
+{"name": "bobbi binder"},
+{"name": "darryl isaacs"},
+{"name": "christopher stutzman"},
+{"name": "sarah mann"},
+{"name": "troy spilde"},
+{"name": "james defendis"},
+{"name": "tania weidick"},
+{"name": "chris lg"},
+{"name": "kevin niessen"},
+{"name": "kristi agena"},
+{"name": "brandi bacon"},
+{"name": "dixie crossroads"},
+{"name": "neal katz"},
+{"name": "david digdo"},
+{"name": "mollie gonzalez"},
+{"name": "sherri leader"},
+{"name": "elizabeth donohue"},
+{"name": "john egan"},
+{"name": "liz graffeden"},
+{"name": "warren prescott"},
+{"name": "nick chu"},
+{"name": "john haines"},
+{"name": "julie ma"},
+{"name": "kim gibson"},
+{"name": "linda knese"},
+{"name": "jerry rembert"},
+{"name": "ray daniels"},
+{"name": "david higgins"},
+{"name": "ivan white"},
+{"name": "bob rautnberg"},
+{"name": "rick tuepker"},
+{"name": "jin nishi"},
+{"name": "kim scheidel"},
+{"name": "gina voun"},
+{"name": "michael mcclendon"},
+{"name": "caleb yeung"},
+{"name": "ryan higgins"},
+{"name": "scott zanon"},
+{"name": "rachel auger"},
+{"name": "darlene d'anna"},
+{"name": "tommy tran"},
+{"name": "annie hall"},
+{"name": "lyn home"},
+{"name": "nancy heverly"},
+{"name": "joe guiliano"},
+{"name": "matthew snook"},
+{"name": "matt xxxx"},
+{"name": "kari lions"},
+{"name": "dan torres"},
+{"name": "judy clayton"},
+{"name": "josh laymen"},
+{"name": "jill perez"},
+{"name": "anne o'connor"},
+{"name": "carol wade"},
+{"name": "maria calabro"},
+{"name": "jamee pia"},
+{"name": "connie caulk"},
+{"name": "sophia zon"},
+{"name": "matthew gordon"},
+{"name": "matt ken"},
+{"name": "tammy hicks"},
+{"name": "lindsay proud"},
+{"name": "bill weise"},
+{"name": "sharon jackson"},
+{"name": "manuel h"},
+{"name": "jessie hibner"},
+{"name": "preston ives"},
+{"name": "desiree allen"},
+{"name": "matt leboeuf"},
+{"name": "lara jones"},
+{"name": "rochelle model"},
+{"name": "cori younghans"},
+{"name": "leo arias"},
+{"name": "wayne mcdermott"},
+{"name": "andy weisser"},
+{"name": "pablo escalera"},
+{"name": "shirley nathan"},
+{"name": "mike nizich"},
+{"name": "min evelyn"},
+{"name": "dave fogle"},
+{"name": "sherry edwards"},
+{"name": "justin schienle"},
+{"name": "harvey highiet"},
+{"name": "cindi patsios"},
+{"name": "joe shedron"},
+{"name": "jane finch"},
+{"name": "ty snear"},
+{"name": "kara wamu"},
+{"name": "natalie morgan"},
+{"name": "paul summerville"},
+{"name": "sarah bliss"},
+{"name": "lupe miranda"},
+{"name": "katie park"},
+{"name": "donald orion"},
+{"name": "peter letko"},
+{"name": "krystal ward"},
+{"name": "reggie anderson"},
+{"name": "pam broadfield"},
+{"name": "janette johnson"},
+{"name": "tim scanlan"},
+{"name": "brett mcqueen"},
+{"name": "robert ferrell"},
+{"name": "howard martin"},
+{"name": "becky hubbard"},
+{"name": "joel whiting"},
+{"name": "lindsay hardy"},
+{"name": "raquel beckys"},
+{"name": "chrissy toledo"},
+{"name": "mark barrett"},
+{"name": "priscilla molina"},
+{"name": "lindsey cell"},
+{"name": "matt hammernik"},
+{"name": "hershel magid"},
+{"name": "frank k"},
+{"name": "chris purser"},
+{"name": "sherri carroll"},
+{"name": "caleb whitson"},
+{"name": "george neil"},
+{"name": "cathy hanscom"},
+{"name": "david mitby"},
+{"name": "jan dik"},
+{"name": "kim platko"},
+{"name": "sara leatherman"},
+{"name": "robert kelleher"},
+{"name": "david jacobson"},
+{"name": "tommy airsoft"},
+{"name": "carol heath"},
+{"name": "elaine winger"},
+{"name": "tom adams"},
+{"name": "jay schwartzman"},
+{"name": "rob washington"},
+{"name": "amanda zehner"},
+{"name": "beth larson"},
+{"name": "eric dalton"},
+{"name": "juan anaya"},
+{"name": "george patton"},
+{"name": "julie chee"},
+{"name": "janet maxwell"},
+{"name": "mike brabants"},
+{"name": "russel cortez"},
+{"name": "sammy abbetan"},
+{"name": "dan mcanally"},
+{"name": "micah cosmo"},
+{"name": "hui deng"},
+{"name": "andy katz"},
+{"name": "mike ramrahka"},
+{"name": "alexis auliano"},
+{"name": "gina fuqua"},
+{"name": "dave dami"},
+{"name": "dan gullickson"},
+{"name": "shari roberts"},
+{"name": "eli sitty"},
+{"name": "justin tway"},
+{"name": "teri muenter"},
+{"name": "ana hilda"},
+{"name": "jess h"},
+{"name": "terry o'brien"},
+{"name": "bud east"},
+{"name": "roseanna muhammad"},
+{"name": "brian pickett"},
+{"name": "joan adams"},
+{"name": "brian moen"},
+{"name": "james ferguson"},
+{"name": "robert gabel"},
+{"name": "debrah dunivant"},
+{"name": "jim birdwell"},
+{"name": "ken klein"},
+{"name": "bob mancuso"},
+{"name": "ken crawley"},
+{"name": "michael back"},
+{"name": "ken lipp"},
+{"name": "ed mckrink"},
+{"name": "gina capitano"},
+{"name": "stacey devries"},
+{"name": "susan kostopoulos"},
+{"name": "amanda pope"},
+{"name": "joshua kaufman"},
+{"name": "leah robin"},
+{"name": "catalina behavioral"},
+{"name": "paul riazantev"},
+{"name": "edgar larios"},
+{"name": "alisha barbour"},
+{"name": "jim alesci"},
+{"name": "sara gabbert"},
+{"name": "jim hargis"},
+{"name": "sierra telephone"},
+{"name": "megan barnes"},
+{"name": "mike steward"},
+{"name": "don vandenberg"},
+{"name": "alec johnston"},
+{"name": "roger valdez"},
+{"name": "brian danney"},
+{"name": "nina strickland"},
+{"name": "vanessa wrk"},
+{"name": "floyd bosko"},
+{"name": "helen underwood"},
+{"name": "nadia montoya"},
+{"name": "robin sullivan"},
+{"name": "ed silberman"},
+{"name": "dana stanley"},
+{"name": "winston wrk"},
+{"name": "roger pries"},
+{"name": "randy williams"},
+{"name": "jan cox"},
+{"name": "tyler herbert"},
+{"name": "luke davis"},
+{"name": "amy holmes"},
+{"name": "dan lord"},
+{"name": "wayne pierce"},
+{"name": "john pisacone"},
+{"name": "johnny cert"},
+{"name": "larissa montesano"},
+{"name": "joseph meo"},
+{"name": "stella jang"},
+{"name": "cassie jacobs"},
+{"name": "tom mackey"},
+{"name": "anthony parvey"},
+{"name": "jeff rutledge"},
+{"name": "colby langenberg"},
+{"name": "nichole jesse"},
+{"name": "stacy hodges"},
+{"name": "leon wardle"},
+{"name": "shirley miller"},
+{"name": "danielle humphries"},
+{"name": "evette hollins"},
+{"name": "tom ramsey"},
+{"name": "jason jason"},
+{"name": "pauline tillinghast"},
+{"name": "christine creter"},
+{"name": "julie carrillo"},
+{"name": "michele klein"},
+{"name": "roger jennings"},
+{"name": "joaquin fernandez"},
+{"name": "natalia vanegas"},
+{"name": "victor meraz"},
+{"name": "ray madden"},
+{"name": "amy preister"},
+{"name": "joe bates"},
+{"name": "brandy espinosa"},
+{"name": "dan steffel"},
+{"name": "corinne reinford"},
+{"name": "nicole gubi"},
+{"name": "addie kirnon"},
+{"name": "anne sinclaire"},
+{"name": "carly franklin"},
+{"name": "steven stewart"},
+{"name": "matt matt"},
+{"name": "michael caravetta"},
+{"name": "anderson assoc"},
+{"name": "phuong mai"},
+{"name": "chuck reid"},
+{"name": "wilson ochoa"},
+{"name": "ryan starr"},
+{"name": "jordan willis"},
+{"name": "david betts"},
+{"name": "vincent rowe"},
+{"name": "stephen bartos"},
+{"name": "brittaney englemon"},
+{"name": "stewart cell"},
+{"name": "dave carver"},
+{"name": "melissa job"},
+{"name": "mavis yaste"},
+{"name": "scott beine"},
+{"name": "willie ruffin"},
+{"name": "michael bowens"},
+{"name": "liz work"},
+{"name": "susan shulthis"},
+{"name": "debbie sylvester"},
+{"name": "gloria keels"},
+{"name": "michelle teniente"},
+{"name": "nikki bernstein"},
+{"name": "michael kane"},
+{"name": "robert thompson"},
+{"name": "laura meyer"},
+{"name": "mica flaw"},
+{"name": "john signorelli"},
+{"name": "david fischette"},
+{"name": "liz childres"},
+{"name": "wilma theater"},
+{"name": "garrett glover"},
+{"name": "cindy yang"},
+{"name": "wayne hagerman"},
+{"name": "linda welch"},
+{"name": "jeremy chance"},
+{"name": "dennis miller"},
+{"name": "alan deckel"},
+{"name": "maria p"},
+{"name": "dave grow"},
+{"name": "mark gabos"},
+{"name": "paula fischer"},
+{"name": "lisa carter"},
+{"name": "larry knauf"},
+{"name": "francis robertson"},
+{"name": "leann boggs"},
+{"name": "james strackman"},
+{"name": "jim savino"},
+{"name": "art camargo"},
+{"name": "lauren clivens"},
+{"name": "kyle kofed"},
+{"name": "shannon smith"},
+{"name": "stephanie monsurno"},
+{"name": "matt barbosa"},
+{"name": "steve taylor"},
+{"name": "simone sanchez"},
+{"name": "debbie mcguire"},
+{"name": "mary rogers"},
+{"name": "norma aceves"},
+{"name": "anthony borques"},
+{"name": "jorge delgado"},
+{"name": "glenda belcher"},
+{"name": "lance connor"},
+{"name": "chris umlauf"},
+{"name": "glenn holland"},
+{"name": "john fok"},
+{"name": "peter thomson"},
+{"name": "johnny banh"},
+{"name": "john kane"},
+{"name": "cara bags"},
+{"name": "martha montalvo"},
+{"name": "carol howes"},
+{"name": "scott chappell"},
+{"name": "beth adams"},
+{"name": "anthony demby"},
+{"name": "traci mwi"},
+{"name": "melanie miller"},
+{"name": "jennifer henry"},
+{"name": "vicki randolph"},
+{"name": "mike krach"},
+{"name": "lori griggs"},
+{"name": "drew gufstason"},
+{"name": "jason bounds"},
+{"name": "matt lindsay"},
+{"name": "billy cell"},
+{"name": "gerry meyer"},
+{"name": "mike wintermantel"},
+{"name": "tom merman"},
+{"name": "amanda dickison"},
+{"name": "mike landrum"},
+{"name": "virginia qin"},
+{"name": "robert chambers"},
+{"name": "phillip hill"},
+{"name": "stacy miller"},
+{"name": "mandy hazelden"},
+{"name": "roman thompson"},
+{"name": "courtney venable"},
+{"name": "charles kvochick"},
+{"name": "ben musson"},
+{"name": "marc angello"},
+{"name": "casey cox"},
+{"name": "michael billiel"},
+{"name": "china gate"},
+{"name": "marcia hall"},
+{"name": "brian marshall"},
+{"name": "christopher kalid"},
+{"name": "leslie simmons"},
+{"name": "liliana reyes"},
+{"name": "christina west"},
+{"name": "mike holekrik"},
+{"name": "michael bach"},
+{"name": "jim noecker"},
+{"name": "dewey flynn"},
+{"name": "jim garrard"},
+{"name": "nina bar"},
+{"name": "randy southerland"},
+{"name": "ernie yingling"},
+{"name": "wayne pfau"},
+{"name": "shane mokler"},
+{"name": "ewa saviano"},
+{"name": "michele gendreau"},
+{"name": "kenny phillips"},
+{"name": "jo fruchtman"},
+{"name": "brent suerdieck"},
+{"name": "doug bivona"},
+{"name": "thao confec"},
+{"name": "mikel rozier"},
+{"name": "lindsey kellog"},
+{"name": "melanie aiken"},
+{"name": "john chapman"},
+{"name": "bud turner"},
+{"name": "michael salerno"},
+{"name": "boris rimsky"},
+{"name": "johnny cohen"},
+{"name": "tom hoffman"},
+{"name": "mark sliva"},
+{"name": "nam loi"},
+{"name": "joe mcroberts"},
+{"name": "stacie perry"},
+{"name": "carol clark"},
+{"name": "bruce blasnik"},
+{"name": "ignacio sosa"},
+{"name": "dan hennelly"},
+{"name": "kate hunter"},
+{"name": "jay garcia"},
+{"name": "adam lawrence"},
+{"name": "amy clifton"},
+{"name": "kelly leeman"},
+{"name": "robert d"},
+{"name": "amber g"},
+{"name": "jerry cotellessa"},
+{"name": "buddy birchfield"},
+{"name": "alton williams"},
+{"name": "jay vosberg"},
+{"name": "willy dayan"},
+{"name": "marnie litz"},
+{"name": "chris church"},
+{"name": "mario johnson"},
+{"name": "scott vieth"},
+{"name": "deborah jensen"},
+{"name": "frank antonio"},
+{"name": "jeff frank"},
+{"name": "ed pitula"},
+{"name": "mark alarmax"},
+{"name": "debi loeb"},
+{"name": "emily womack"},
+{"name": "kelly dees"},
+{"name": "susanne vuksic"},
+{"name": "jon coleman"},
+{"name": "rachel att"},
+{"name": "lon warner"},
+{"name": "steve schultz"},
+{"name": "cruz sub"},
+{"name": "jillian cioccari"},
+{"name": "hope salinas"},
+{"name": "faith acosta"},
+{"name": "bruce richard"},
+{"name": "casey cell"},
+{"name": "tina middleton"},
+{"name": "janet bolling"},
+{"name": "allan horrocks"},
+{"name": "kelly castellanos"},
+{"name": "richard serimento"},
+{"name": "steve palmer"},
+{"name": "lenny manno"},
+{"name": "chris football"},
+{"name": "elizabeth earhart"},
+{"name": "jeff jakob"},
+{"name": "kate whalen"},
+{"name": "daniel craighead"},
+{"name": "john estrada"},
+{"name": "rachael green"},
+{"name": "susan irwin"},
+{"name": "rachel porras"},
+{"name": "anna gillen"},
+{"name": "david goodrowe"},
+{"name": "josh mosko"},
+{"name": "jon troxell"},
+{"name": "rosa sauza"},
+{"name": "steve mccoy"},
+{"name": "danny trong"},
+{"name": "charles shepard"},
+{"name": "oretha boyd"},
+{"name": "courtney woodson"},
+{"name": "mark tabaeu"},
+{"name": "tom garrett"},
+{"name": "katie wolverton"},
+{"name": "anna fuentes"},
+{"name": "joseph moore"},
+{"name": "helen manalis"},
+{"name": "linda stokes"},
+{"name": "terry steacy"},
+{"name": "karl b"},
+{"name": "tony isola"},
+{"name": "chris summers"},
+{"name": "bob green"},
+{"name": "leo tortoriello"},
+{"name": "nick sarlo"},
+{"name": "george handtmann"},
+{"name": "ron budweiser"},
+{"name": "alan glick"},
+{"name": "mark elledge"},
+{"name": "laine hendricks"},
+{"name": "casandra heitman"},
+{"name": "nathan goodwin"},
+{"name": "lynn plote"},
+{"name": "steve culver"},
+{"name": "carole evans"},
+{"name": "jeanette weiss"},
+{"name": "robert vanbekkum"},
+{"name": "bob thurston"},
+{"name": "patrick holly"},
+{"name": "malcolm hammond"},
+{"name": "benny ng"},
+{"name": "carma wood"},
+{"name": "john marmora"},
+{"name": "vanessa bandera"},
+{"name": "margaret evans"},
+{"name": "al parsons"},
+{"name": "josh obrien"},
+{"name": "james orswell"},
+{"name": "seth jasper"},
+{"name": "pat stern"},
+{"name": "sharon tuscaloosa"},
+{"name": "justin rosencrantz"},
+{"name": "ronnie floor"},
+{"name": "melanie kunkle"},
+{"name": "ernie pozos"},
+{"name": "susan raven"},
+{"name": "donna garrett"},
+{"name": "rikki worthen"},
+{"name": "lee dawkins"},
+{"name": "harvey goodman"},
+{"name": "john cawood"},
+{"name": "sandra kim"},
+{"name": "jerry nano"},
+{"name": "margaret barge"},
+{"name": "jeff bachman"},
+{"name": "dan goetz"},
+{"name": "rey nicolas"},
+{"name": "alison gause"},
+{"name": "tony elkins"},
+{"name": "edmund klamann"},
+{"name": "cara a"},
+{"name": "alan singer"},
+{"name": "jason robertson"},
+{"name": "easter tesfamichael"},
+{"name": "mike lowery"},
+{"name": "nick martin"},
+{"name": "maria bongco"},
+{"name": "gene fein"},
+{"name": "karen ogletree"},
+{"name": "jay roc"},
+{"name": "ken so"},
+{"name": "paige home"},
+{"name": "kevin lafollette"},
+{"name": "chase lumber"},
+{"name": "doug dagin"},
+{"name": "blake hylen"},
+{"name": "pat simpson"},
+{"name": "will yee"},
+{"name": "michael black"},
+{"name": "roberto nunez"},
+{"name": "trish ames"},
+{"name": "john georgia"},
+{"name": "stephanie badua"},
+{"name": "jean steve"},
+{"name": "justin mcneill"},
+{"name": "joe holibaugh"},
+{"name": "clare madden"},
+{"name": "herbert puffer"},
+{"name": "grace wigal"},
+{"name": "luke fournier"},
+{"name": "albert cheung"},
+{"name": "zachery katzen"},
+{"name": "elaine eppler"},
+{"name": "chris nyren"},
+{"name": "john cerrone"},
+{"name": "chuck jackson"},
+{"name": "sandee utterback"},
+{"name": "sam sahyouni"},
+{"name": "chris tennessee"},
+{"name": "letitia stalling"},
+{"name": "mike pembrooke"},
+{"name": "dion johnson"},
+{"name": "mark otto"},
+{"name": "barbara logan"},
+{"name": "roy dixon"},
+{"name": "greg linda"},
+{"name": "tim schafer's"},
+{"name": "sarah shirilla"},
+{"name": "terry baker"},
+{"name": "kris comeaux"},
+{"name": "jim morrison"},
+{"name": "carolyn greer"},
+{"name": "ashton ames"},
+{"name": "jeff peele"},
+{"name": "holly cooke"},
+{"name": "madeleine smith"},
+{"name": "jeremy whiting"},
+{"name": "anthony alva"},
+{"name": "duncan ballantyne"},
+{"name": "jessica fr"},
+{"name": "kelvin simmons"},
+{"name": "thomas bithell"},
+{"name": "darin dickson"},
+{"name": "carl knoblock"},
+{"name": "peter booth"},
+{"name": "julie rosenfeld"},
+{"name": "nick laurila"},
+{"name": "karla williams"},
+{"name": "angela miller"},
+{"name": "adam kerkes"},
+{"name": "tory juntenen"},
+{"name": "stephanie brummels"},
+{"name": "grace neal"},
+{"name": "luke taylor"},
+{"name": "dan peterson"},
+{"name": "vince foster"},
+{"name": "valerie butler"},
+{"name": "brenda parents"},
+{"name": "gordon granger"},
+{"name": "pat rondon"},
+{"name": "karen ong"},
+{"name": "rob arellano"},
+{"name": "randy fischer"},
+{"name": "laura guess"},
+{"name": "ryan kling"},
+{"name": "derek rutledge"},
+{"name": "vern walter"},
+{"name": "jamie maldonado"},
+{"name": "ariel denise"},
+{"name": "scott harmon"},
+{"name": "allan davis"},
+{"name": "kristine brixius"},
+{"name": "john kuffner"},
+{"name": "nicole xxxx"},
+{"name": "wayne koerner"},
+{"name": "whitney paget"},
+{"name": "steven moore"},
+{"name": "john waldow"},
+{"name": "mike middleton"},
+{"name": "joel chadwick"},
+{"name": "jim whiton"},
+{"name": "dave robin"},
+{"name": "josh richmond"},
+{"name": "megan mom"},
+{"name": "frank delzio"},
+{"name": "adria henderson"},
+{"name": "travis lape"},
+{"name": "lillian ennesser"},
+{"name": "linda yuen"},
+{"name": "heather henry"},
+{"name": "mike morey"},
+{"name": "deborah edmonds"},
+{"name": "justin hasen"},
+{"name": "david weissmann"},
+{"name": "eric melson"},
+{"name": "brian schmidt"},
+{"name": "mary farrer"},
+{"name": "joel gelman"},
+{"name": "michael hefren"},
+{"name": "david lennon"},
+{"name": "trisha tetreault"},
+{"name": "jill brooks"},
+{"name": "doug bratton"},
+{"name": "karla becerra"},
+{"name": "neil blindauer"},
+{"name": "donna newman"},
+{"name": "janice pierson"},
+{"name": "mark bushey"},
+{"name": "dana green"},
+{"name": "desiree tirado"},
+{"name": "mike christy"},
+{"name": "ryan oxyer"},
+{"name": "anthony denha"},
+{"name": "vickie lightsey"},
+{"name": "colleen tajari"},
+{"name": "becky rheinhardt"},
+{"name": "amanda windle"},
+{"name": "martin deale"},
+{"name": "kyle gregory"},
+{"name": "marie chambers"},
+{"name": "eric belmar"},
+{"name": "ellen rubell"},
+{"name": "karen thorup"},
+{"name": "robby new"},
+{"name": "joy chua"},
+{"name": "matt bishop"},
+{"name": "bob klamser"},
+{"name": "jack moffett"},
+{"name": "joel ostrander"},
+{"name": "jim lenz"},
+{"name": "dalton asshole"},
+{"name": "lilia alvarez"},
+{"name": "tiffany sneer"},
+{"name": "geoffrey rubinshtein"},
+{"name": "don bowen"},
+{"name": "jessica fullman"},
+{"name": "dana hart"},
+{"name": "gail lovejoy"},
+{"name": "shakira farden"},
+{"name": "ian mattinson"},
+{"name": "steve brady"},
+{"name": "philip kling"},
+{"name": "brynn lewis"},
+{"name": "kelly fulps"},
+{"name": "kelly mckerahan"},
+{"name": "carole orlando"},
+{"name": "jackie prill"},
+{"name": "larry nix"},
+{"name": "tim cooper"},
+{"name": "heather party"},
+{"name": "john van"},
+{"name": "timmy iinuma"},
+{"name": "roberto cabrera"},
+{"name": "kevin weir"},
+{"name": "jan dawson"},
+{"name": "sheri feinberg"},
+{"name": "myriam bartz"},
+{"name": "william henry"},
+{"name": "charlotte garrison"},
+{"name": "larisa schirba"},
+{"name": "john batter"},
+{"name": "lou beeson"},
+{"name": "randy pp"},
+{"name": "arlene lawson"},
+{"name": "paul goldman"},
+{"name": "gary mccully"},
+{"name": "nicole martinex"},
+{"name": "melissa gamauche"},
+{"name": "malka rabi"},
+{"name": "nathan goshgarian"},
+{"name": "ryan vinyard"},
+{"name": "greg turner"},
+{"name": "cindy birkland"},
+{"name": "mel manglicmot"},
+{"name": "carol douglas"},
+{"name": "jeff kenosha"},
+{"name": "reid ags"},
+{"name": "mike ridolfi"},
+{"name": "isaac bright"},
+{"name": "sandra leier"},
+{"name": "art stevens"},
+{"name": "dylan cowan"},
+{"name": "janice ortez"},
+{"name": "jon alfieri"},
+{"name": "bruna aloe"},
+{"name": "robert haynie"},
+{"name": "matt wookie"},
+{"name": "sandra whitfield"},
+{"name": "david hayslip"},
+{"name": "johnny hasen"},
+{"name": "jeff davidson"},
+{"name": "roxane peckelherring"},
+{"name": "jerry strugala"},
+{"name": "tim herbts"},
+{"name": "deborah strong"},
+{"name": "john methot"},
+{"name": "shawn council"},
+{"name": "michael gedeon"},
+{"name": "ron anderson"},
+{"name": "kirsten casper"},
+{"name": "sean q"},
+{"name": "sam mosher"},
+{"name": "john means"},
+{"name": "carolyn holbert"},
+{"name": "cindy harris"},
+{"name": "terri carter"},
+{"name": "clark cindy"},
+{"name": "ron onesti"},
+{"name": "ray evans"},
+{"name": "mike goering"},
+{"name": "lee glenn"},
+{"name": "pete hetyey"},
+{"name": "victor styrsky"},
+{"name": "grant lewis"},
+{"name": "gretchen stroud"},
+{"name": "rich fiorella"},
+{"name": "kelly morio"},
+{"name": "rubin jr"},
+{"name": "nick mccarroll"},
+{"name": "jim lovell"},
+{"name": "jerrica crib"},
+{"name": "sam moser"},
+{"name": "bruce naylor"},
+{"name": "connie lin"},
+{"name": "pete armstrong"},
+{"name": "rich jereb"},
+{"name": "kaitlyn j"},
+{"name": "sean lewis"},
+{"name": "joe willy"},
+{"name": "elisha stanley"},
+{"name": "dave wisniewski"},
+{"name": "nancy graber"},
+{"name": "richard salas"},
+{"name": "jeff shuman"},
+{"name": "jake reynolds"},
+{"name": "jesus torres"},
+{"name": "sean curtis"},
+{"name": "jackie closer"},
+{"name": "lacie h"},
+{"name": "sidney girl"},
+{"name": "todd amlee"},
+{"name": "wilma jeffery"},
+{"name": "linda d"},
+{"name": "ann hendrickson"},
+{"name": "pam mahony"},
+{"name": "shirley king"},
+{"name": "beth henasee"},
+{"name": "rob dassow"},
+{"name": "sterling blake"},
+{"name": "paul farnsworth"},
+{"name": "dennis rivera"},
+{"name": "stephen storey"},
+{"name": "max lowenbaum"},
+{"name": "brandi martini"},
+{"name": "mike borelli"},
+{"name": "edith home"},
+{"name": "anne savel"},
+{"name": "dan nalian"},
+{"name": "rose miranda"},
+{"name": "sue hudson"},
+{"name": "becky grainger"},
+{"name": "steven nelson"},
+{"name": "ryan nolan"},
+{"name": "matt tracey"},
+{"name": "alice schafer"},
+{"name": "jon branch"},
+{"name": "mark edelstein"},
+{"name": "paul kraus"},
+{"name": "reyes tc"},
+{"name": "jamie basset"},
+{"name": "marla white"},
+{"name": "stephanie pingle"},
+{"name": "pete strom"},
+{"name": "fred black"},
+{"name": "randy hobson"},
+{"name": "anne lewis"},
+{"name": "bill finagin"},
+{"name": "lisette marquez"},
+{"name": "jerry askin"},
+{"name": "david tolley"},
+{"name": "russ strathdee"},
+{"name": "yvette melendez"},
+{"name": "hunter door"},
+{"name": "jerry joanne"},
+{"name": "gwendolyn ortiz"},
+{"name": "shelley home"},
+{"name": "dianne monks"},
+{"name": "george stelluto"},
+{"name": "kelly burner"},
+{"name": "dawn dawood"},
+{"name": "jeff lemaster"},
+{"name": "megan mcelroy"},
+{"name": "karen rockwell"},
+{"name": "lindsay perry"},
+{"name": "chad bullock"},
+{"name": "terra muhlbeirer"},
+{"name": "eric loewe"},
+{"name": "brian cell"},
+{"name": "steven d"},
+{"name": "florence meyer"},
+{"name": "kyle jensen"},
+{"name": "liz nowak"},
+{"name": "kristina berian"},
+{"name": "andrew dixon"},
+{"name": "sarah r"},
+{"name": "kris salon"},
+{"name": "jonathan hudis"},
+{"name": "charlie leekley"},
+{"name": "natalie canull"},
+{"name": "michael olloguec"},
+{"name": "jeremy barr"},
+{"name": "joey p"},
+{"name": "kristi takaki"},
+{"name": "fran duggan"},
+{"name": "eric holmlund"},
+{"name": "michael zhuang"},
+{"name": "tim jubach"},
+{"name": "rose kearns"},
+{"name": "david baker"},
+{"name": "danny honea"},
+{"name": "danielle washington"},
+{"name": "issac church"},
+{"name": "pat chavez"},
+{"name": "derrick pecson"},
+{"name": "kerri phillips"},
+{"name": "chris imbills"},
+{"name": "mike roomate"},
+{"name": "julia shoner"},
+{"name": "kellie mojica"},
+{"name": "jimmy thai"},
+{"name": "kathleen smith"},
+{"name": "jen cabon"},
+{"name": "jim gaffney"},
+{"name": "andrea thornton"},
+{"name": "tammy griffith"},
+{"name": "richard construction"},
+{"name": "daphne gamez"},
+{"name": "tom construction"},
+{"name": "alex nickman"},
+{"name": "ann hernandez"},
+{"name": "dwight dunn"},
+{"name": "michael britt"},
+{"name": "mike stumpf"},
+{"name": "jim couture"},
+{"name": "glen wilson"},
+{"name": "annabel salinas"},
+{"name": "ronnie buerger"},
+{"name": "peter collins"},
+{"name": "russel dott"},
+{"name": "bill hayes"},
+{"name": "kyle gong"},
+{"name": "fabian morales"},
+{"name": "janice ruiter"},
+{"name": "jimmy batista"},
+{"name": "greg carver"},
+{"name": "wally whinna"},
+{"name": "pete casini"},
+{"name": "kim eldridge"},
+{"name": "heidi work"},
+{"name": "darren valez"},
+{"name": "crystal schofield"},
+{"name": "david porter"},
+{"name": "nikki kagey"},
+{"name": "morgan mcbee"},
+{"name": "lupe aguilar"},
+{"name": "hannah clifford"},
+{"name": "roger kinser"},
+{"name": "dee carpenter"},
+{"name": "david maniscalco"},
+{"name": "pam aiello"},
+{"name": "thomas gioia"},
+{"name": "peter kerr"},
+{"name": "andy kilian"},
+{"name": "tom staats"},
+{"name": "kerry mowry"},
+{"name": "shawn kratochvil"},
+{"name": "jeremy joyce"},
+{"name": "karl kriskeitz"},
+{"name": "marcus graham"},
+{"name": "carolyn hunsaker"},
+{"name": "virginia moore"},
+{"name": "kisha young"},
+{"name": "vanessa salinas"},
+{"name": "john schloetter"},
+{"name": "jared ags"},
+{"name": "martin poeshel"},
+{"name": "rebecca home"},
+{"name": "bill rodgers"},
+{"name": "paul shamieh"},
+{"name": "rex bybee"},
+{"name": "eugene escayg"},
+{"name": "tony lema"},
+{"name": "laura firman"},
+{"name": "cathy hein"},
+{"name": "larry phillips"},
+{"name": "larry haupt"},
+{"name": "michael hice"},
+{"name": "ed rainey"},
+{"name": "jeff a"},
+{"name": "dane molina"},
+{"name": "austin audi"},
+{"name": "amanda southward"},
+{"name": "daniel glend"},
+{"name": "blaine elementary"},
+{"name": "rene bandong"},
+{"name": "tim gonerka"},
+{"name": "pat jurgensmeyer"},
+{"name": "gregory pavlov"},
+{"name": "janet cam"},
+{"name": "johnny handsome"},
+{"name": "britt ford"},
+{"name": "albert fernando"},
+{"name": "vincent pitruzzella"},
+{"name": "courtney douglas"},
+{"name": "george pinechie"},
+{"name": "deena schaumburg"},
+{"name": "guy ronen"},
+{"name": "kirk murdock"},
+{"name": "brittany rodriguez"},
+{"name": "ross zimmer"},
+{"name": "simon leonov"},
+{"name": "tori ryan"},
+{"name": "seth kaufman"},
+{"name": "frank abel"},
+{"name": "paul rogers"},
+{"name": "ted way"},
+{"name": "judy perdue"},
+{"name": "fiona childe"},
+{"name": "chris crawford"},
+{"name": "jim lourie"},
+{"name": "chuck sobiech"},
+{"name": "marilyn spiegel"},
+{"name": "chris ngc"},
+{"name": "michael brand"},
+{"name": "margaret stephenson"},
+{"name": "amy james"},
+{"name": "robert webber"},
+{"name": "brian crall"},
+{"name": "meryl price"},
+{"name": "ryan patrick"},
+{"name": "tim tilson"},
+{"name": "duane peterson"},
+{"name": "stephanie snelson"},
+{"name": "cheryl reed"},
+{"name": "sam cooper"},
+{"name": "sam kniesteadt"},
+{"name": "dale sagan"},
+{"name": "nicola hayes"},
+{"name": "kim mccoy"},
+{"name": "jim lange"},
+{"name": "kelly mccoll"},
+{"name": "angie bergie"},
+{"name": "bree nauman"},
+{"name": "ted bernard"},
+{"name": "jason mccord"},
+{"name": "laurie dempsey"},
+{"name": "sam chapman"},
+{"name": "jake smart"},
+{"name": "john mariane"},
+{"name": "alissa antle"},
+{"name": "david pulliam"},
+{"name": "david milligan"},
+{"name": "cynthia thomas"},
+{"name": "lenora evans"},
+{"name": "rachel loebs"},
+{"name": "ricky lee"},
+{"name": "katie sandy"},
+{"name": "john barry"},
+{"name": "robert simmons"},
+{"name": "diana gopp"},
+{"name": "omar sawyer"},
+{"name": "trina martel"},
+{"name": "stacy forshee"},
+{"name": "art niemela"},
+{"name": "janelle hanson"},
+{"name": "li chong"},
+{"name": "dave ernstrom"},
+{"name": "tony coffey"},
+{"name": "derrick mebane"},
+{"name": "rina shanaman"},
+{"name": "ken buck"},
+{"name": "michael lazar"},
+{"name": "ricky rios"},
+{"name": "lourdes corona"},
+{"name": "wyatt cell"},
+{"name": "marla peterson"},
+{"name": "alicia littleton"},
+{"name": "eric jaramillo"},
+{"name": "erik fjeseth"},
+{"name": "chris harwood"},
+{"name": "david richards"},
+{"name": "al brookbanks"},
+{"name": "eileen anderson"},
+{"name": "nancy hindman"},
+{"name": "sean brown"},
+{"name": "jenny parks"},
+{"name": "krista michell"},
+{"name": "ka porter"},
+{"name": "lyn baldwin"},
+{"name": "max lowdermilk"},
+{"name": "christine ali"},
+{"name": "joe dumont"},
+{"name": "chris huck"},
+{"name": "terry firstpresby"},
+{"name": "dave pohster"},
+{"name": "sharon carz"},
+{"name": "don singh"},
+{"name": "tyrone fisher"},
+{"name": "bryan massey"},
+{"name": "howard truman"},
+{"name": "dan snider"},
+{"name": "kerry maus"},
+{"name": "chris cabana"},
+{"name": "elaine melbardis"},
+{"name": "mona puri"},
+{"name": "britney hd"},
+{"name": "rich delossantos"},
+{"name": "maya choi"},
+{"name": "summer elgin"},
+{"name": "bill wik"},
+{"name": "raquel perez"},
+{"name": "jennifer lehnert"},
+{"name": "dino ripa"},
+{"name": "amelia goeppinger"},
+{"name": "tommy haegele"},
+{"name": "steve fuller"},
+{"name": "mike hansberger"},
+{"name": "monique demps"},
+{"name": "martin son"},
+{"name": "matt pilla"},
+{"name": "kristen bagwell"},
+{"name": "mike marboe"},
+{"name": "teddy beech"},
+{"name": "wanda ortiz"},
+{"name": "sydney adams"},
+{"name": "roy glassey"},
+{"name": "sabrina dudhnath"},
+{"name": "kate rasmussen"},
+{"name": "rob row"},
+{"name": "gary diciano"},
+{"name": "john jardine"},
+{"name": "john coffey"},
+{"name": "myles murray"},
+{"name": "mike alerich"},
+{"name": "min uecker"},
+{"name": "debra robershotte"},
+{"name": "jim schacht"},
+{"name": "matt cell"},
+{"name": "victoria gentry"},
+{"name": "bob casteel"},
+{"name": "bob kerlin"},
+{"name": "jonathan katzman"},
+{"name": "charles wirt"},
+{"name": "robin wiley"},
+{"name": "taylor work"},
+{"name": "sarah popish"},
+{"name": "michael keller"},
+{"name": "erin ihnat"},
+{"name": "cheryl home"},
+{"name": "ned clyde"},
+{"name": "eric albritton"},
+{"name": "timmy oldstrum"},
+{"name": "ryan workman"},
+{"name": "rory bird"},
+{"name": "jason stevens"},
+{"name": "tim robbins"},
+{"name": "rick sweet"},
+{"name": "kerry zock"},
+{"name": "debbie kemp"},
+{"name": "lauren bernhard"},
+{"name": "rick olin"},
+{"name": "valrie jensen"},
+{"name": "donny stanley"},
+{"name": "terry griffin"},
+{"name": "laurie baldwin"},
+{"name": "larry fish"},
+{"name": "jim s"},
+{"name": "brandon brunson"},
+{"name": "charley tool"},
+{"name": "jarrod wilkening"},
+{"name": "elizabeth hwong"},
+{"name": "martin acuna"},
+{"name": "ken jackson"},
+{"name": "bailey blanck"},
+{"name": "paul elias"},
+{"name": "michael hessler"},
+{"name": "rachelle daniels"},
+{"name": "sunny s"},
+{"name": "nick ellis"},
+{"name": "santa college"},
+{"name": "kimberly olson"},
+{"name": "joe allaria"},
+{"name": "cynthia cell"},
+{"name": "andrew eastman"},
+{"name": "doug cozen"},
+{"name": "alex retodo"},
+{"name": "debra robinson"},
+{"name": "pam deperio"},
+{"name": "eric cortez"},
+{"name": "aaron cochran"},
+{"name": "trevor carter"},
+{"name": "tanya house"},
+{"name": "jon a"},
+{"name": "robbie dodd"},
+{"name": "myrna phillips"},
+{"name": "jared mccullough"},
+{"name": "lauren sousa"},
+{"name": "jordan hassel"},
+{"name": "brian ofarrell"},
+{"name": "sara runningcrane"},
+{"name": "william decker"},
+{"name": "rob ruth"},
+{"name": "chi vu"},
+{"name": "julia anderson"},
+{"name": "rick mathews"},
+{"name": "brian brown"},
+{"name": "victor perez"},
+{"name": "chu khiet"},
+{"name": "matt luey"},
+{"name": "linda clark"},
+{"name": "donna perry"},
+{"name": "leon dudes"},
+{"name": "catherine zucchero"},
+{"name": "jim campanis"},
+{"name": "mark bush"},
+{"name": "tom cheribino"},
+{"name": "gisela moran"},
+{"name": "scott bethmann"},
+{"name": "lindsey hosner"},
+{"name": "charles tennis"},
+{"name": "scotty budow"},
+{"name": "omar jones"},
+{"name": "josh culver"},
+{"name": "george mcphee"},
+{"name": "louise giesbrecht"},
+{"name": "kevin mullen"},
+{"name": "lyman marshall"},
+{"name": "maureen raher"},
+{"name": "mimi ii"},
+{"name": "brigitte beaudry"},
+{"name": "sophie polan"},
+{"name": "scott corner"},
+{"name": "rodney deroche"},
+{"name": "julie j"},
+{"name": "neal mitchell"},
+{"name": "michelle bridges"},
+{"name": "sarah a"},
+{"name": "rosa chan"},
+{"name": "jason sullivan"},
+{"name": "stephanie flint"},
+{"name": "penny wight"},
+{"name": "dexter west"},
+{"name": "ronald parsons"},
+{"name": "deedee george"},
+{"name": "stephen bland"},
+{"name": "mike uncle"},
+{"name": "kevin shelton"},
+{"name": "ray chmielewski"},
+{"name": "charlie ott"},
+{"name": "laraine corneilson"},
+{"name": "meagan wesd"},
+{"name": "ross reinhart"},
+{"name": "tracy fink"},
+{"name": "kitty whitaker"},
+{"name": "julie cane"},
+{"name": "leslie waldman"},
+{"name": "steve coffey"},
+{"name": "jimmy fredricks"},
+{"name": "william klindt"},
+{"name": "peter jacobsen"},
+{"name": "jerry clark"},
+{"name": "angela vavrica"},
+{"name": "jack piao"},
+{"name": "don carver"},
+{"name": "jennifer langdon"},
+{"name": "andy neumann"},
+{"name": "colleen calling"},
+{"name": "angie hill"},
+{"name": "john farrell"},
+{"name": "june pierce"},
+{"name": "james money"},
+{"name": "bruce kinghorn"},
+{"name": "rachel crihfield"},
+{"name": "jerry segona"},
+{"name": "matthew gebarowski"},
+{"name": "david weyls"},
+{"name": "johnny batista"},
+{"name": "kenneth rind"},
+{"name": "alison dominic"},
+{"name": "eric cymanski"},
+{"name": "wayne daniels"},
+{"name": "sandy james"},
+{"name": "shirley may"},
+{"name": "erika marquez"},
+{"name": "michael headrick"},
+{"name": "gena jones"},
+{"name": "jessica collins"},
+{"name": "greg alcantar"},
+{"name": "jamie yoder"},
+{"name": "lisa gibilisco"},
+{"name": "vince carrol"},
+{"name": "paul voorn"},
+{"name": "joe lorenzo"},
+{"name": "matt sotelo"},
+{"name": "len carey"},
+{"name": "jennifer macnichol"},
+{"name": "ronald rott"},
+{"name": "bob fusaro"},
+{"name": "melissa condi"},
+{"name": "cherie mclean"},
+{"name": "gene karpinski"},
+{"name": "dustin abrahams"},
+{"name": "jen eisenbarth"},
+{"name": "kyle blankenship"},
+{"name": "nicole sopp"},
+{"name": "jess moore"},
+{"name": "ann boreland"},
+{"name": "lesley morris"},
+{"name": "archie harris"},
+{"name": "mike groesser"},
+{"name": "debbie deering"},
+{"name": "patti engle"},
+{"name": "linda garnette"},
+{"name": "kelly pope"},
+{"name": "fran irvine"},
+{"name": "cameron bar"},
+{"name": "vanessa ha"},
+{"name": "tracy ilwu"},
+{"name": "ta rothman"},
+{"name": "ben lehner"},
+{"name": "clara valley"},
+{"name": "kevin mason"},
+{"name": "shannon brinsfield"},
+{"name": "ron glenn"},
+{"name": "alan shomers"},
+{"name": "kerry maloney"},
+{"name": "allyson norris"},
+{"name": "martha varner"},
+{"name": "mike maggio"},
+{"name": "brandon bruey"},
+{"name": "john turner"},
+{"name": "kelvin robinson"},
+{"name": "keith downbeat"},
+{"name": "jon ng"},
+{"name": "chris osden"},
+{"name": "alex feldman"},
+{"name": "tyrone hannah"},
+{"name": "art vincent"},
+{"name": "terry paul"},
+{"name": "nick alfarah"},
+{"name": "mark cruz"},
+{"name": "bryan dixson"},
+{"name": "derrick curtis"},
+{"name": "rick kiser"},
+{"name": "tom murdock"},
+{"name": "kelly fish"},
+{"name": "cara macdonald"},
+{"name": "anna jorge"},
+{"name": "andre woodley"},
+{"name": "sal line"},
+{"name": "jeff flaro"},
+{"name": "lori price"},
+{"name": "joe il"},
+{"name": "aaron taylor"},
+{"name": "trina hunn"},
+{"name": "nick martinez"},
+{"name": "devorah danziger"},
+{"name": "brian young"},
+{"name": "matt franks"},
+{"name": "patrick brockenborough"},
+{"name": "jay southwood"},
+{"name": "rick nichols"},
+{"name": "sharen bowman"},
+{"name": "ron ashley"},
+{"name": "lisa kid"},
+{"name": "sandy fontes"},
+{"name": "amy lusk"},
+{"name": "amy jendrucko"},
+{"name": "robert e"},
+{"name": "siobhan flanagan"},
+{"name": "mike cooley"},
+{"name": "jordan s"},
+{"name": "joe gerber"},
+{"name": "milton museum"},
+{"name": "matt lachapel"},
+{"name": "michelle breckenridg"},
+{"name": "nathan jacobus"},
+{"name": "marva bond"},
+{"name": "perry karen"},
+{"name": "rosemarie baruelo"},
+{"name": "elaine keller"},
+{"name": "paul loefstedt"},
+{"name": "ben mendosa"},
+{"name": "dave garland"},
+{"name": "heather tsang"},
+{"name": "wendy alley"},
+{"name": "armando aguirre"},
+{"name": "pansy tor"},
+{"name": "sarah willis"},
+{"name": "richard chard"},
+{"name": "greg joffe"},
+{"name": "earline lewis"},
+{"name": "janice hodges"},
+{"name": "judith chiodo"},
+{"name": "mark mcintosh"},
+{"name": "duane ittner"},
+{"name": "erin gardiner"},
+{"name": "jared osaki"},
+{"name": "eric pannone"},
+{"name": "kari briscoe"},
+{"name": "forrest smith"},
+{"name": "scott mitzner"},
+{"name": "mike greci"},
+{"name": "david khuu"},
+{"name": "kenneth huey"},
+{"name": "mary raftery"},
+{"name": "mary pat"},
+{"name": "lance smith"},
+{"name": "nina wang"},
+{"name": "tim bolden"},
+{"name": "andy chung"},
+{"name": "alex santamaria"},
+{"name": "golden krust"},
+{"name": "dan yamini"},
+{"name": "lindsey martin"},
+{"name": "fernando carvajal"},
+{"name": "cory schriener"},
+{"name": "dave hooton"},
+{"name": "jon love"},
+{"name": "karmen wiliams"},
+{"name": "chad perkins"},
+{"name": "josh goderis"},
+{"name": "laurie lessans"},
+{"name": "alex torres"},
+{"name": "jo zayer"},
+{"name": "pat rolow"},
+{"name": "ervin dennis"},
+{"name": "dani olsen"},
+{"name": "van heest"},
+{"name": "bobby glynn"},
+{"name": "edward mulrooney"},
+{"name": "paige walters"},
+{"name": "loan elwanger"},
+{"name": "queen morris"},
+{"name": "melanie jones"},
+{"name": "bob lebryk"},
+{"name": "alex lewis"},
+{"name": "chris campana"},
+{"name": "kirk lake"},
+{"name": "tim wilson"},
+{"name": "tiffany fliszar"},
+{"name": "nicole lippman"},
+{"name": "kyle sample"},
+{"name": "kit bramblee"},
+{"name": "lindsey finley"},
+{"name": "lydia arabo"},
+{"name": "nichol home"},
+{"name": "judy clampit"},
+{"name": "scott ingold"},
+{"name": "kim koenigs"},
+{"name": "justin simpson"},
+{"name": "tommy mertz"},
+{"name": "kevin cain"},
+{"name": "joseph clavero"},
+{"name": "tami boley"},
+{"name": "lindsey kappa"},
+{"name": "mike flinn"},
+{"name": "richard lee"},
+{"name": "jeff tat"},
+{"name": "james seifert"},
+{"name": "martha hill"},
+{"name": "gail robinson"},
+{"name": "rob cochman"},
+{"name": "ernie munick"},
+{"name": "jake bar"},
+{"name": "cynthia weymouth"},
+{"name": "jonathan west"},
+{"name": "jenny leroy"},
+{"name": "david bruener"},
+{"name": "mike compton"},
+{"name": "alexis cell"},
+{"name": "mark brennan"},
+{"name": "kristina hoffman"},
+{"name": "dan milojevich"},
+{"name": "ian atkinson"},
+{"name": "jessie patton"},
+{"name": "keith rogers"},
+{"name": "meghan mcrae"},
+{"name": "john crochet"},
+{"name": "jeff landers"},
+{"name": "scott brenowitz"},
+{"name": "steve witkus"},
+{"name": "michael palomino"},
+{"name": "lincoln christian"},
+{"name": "dustin mcgee"},
+{"name": "ryan barker"},
+{"name": "marjorie porter"},
+{"name": "karen gassler"},
+{"name": "john beman"},
+{"name": "eddy gaetane"},
+{"name": "parker lamando"},
+{"name": "nathan sutcliffe"},
+{"name": "steve school"},
+{"name": "kristin farren"},
+{"name": "adrienne tam"},
+{"name": "brock sparks"},
+{"name": "scott hefter"},
+{"name": "ed mcbeth"},
+{"name": "april shirly"},
+{"name": "randall strother"},
+{"name": "matt hammer"},
+{"name": "tyler p"},
+{"name": "anthony parisi"},
+{"name": "victor romero"},
+{"name": "oliver haige"},
+{"name": "shayna prince"},
+{"name": "kevin cuellar"},
+{"name": "bob grygotis"},
+{"name": "david orozco"},
+{"name": "jake furey"},
+{"name": "denise simons"},
+{"name": "angel anderson"},
+{"name": "adam lane"},
+{"name": "james murphy"},
+{"name": "tom arlington"},
+{"name": "laura sanderman"},
+{"name": "guillermo castaneda"},
+{"name": "patrick callery"},
+{"name": "ann cecchettini"},
+{"name": "julie hykes"},
+{"name": "lisa belmonte"},
+{"name": "reggie miller"},
+{"name": "tom ott"},
+{"name": "mike cates"},
+{"name": "warren roll"},
+{"name": "ricky server"},
+{"name": "patricia gutierrez"},
+{"name": "dave roark"},
+{"name": "tabitha douglas"},
+{"name": "adam urban"},
+{"name": "mel auto"},
+{"name": "john starotska"},
+{"name": "johna whittington"},
+{"name": "maryann preli"},
+{"name": "audra cell"},
+{"name": "shelby moyer"},
+{"name": "sarah easley"},
+{"name": "samantha elenbas"},
+{"name": "james turner"},
+{"name": "eddie hall"},
+{"name": "eddie wallach"},
+{"name": "david ihedigbo"},
+{"name": "dennis weems"},
+{"name": "lauran scherr"},
+{"name": "brett walters"},
+{"name": "kelly guzman"},
+{"name": "jason m"},
+{"name": "cory angal"},
+{"name": "greg polito"},
+{"name": "danny ford"},
+{"name": "katie doody"},
+{"name": "rich faul"},
+{"name": "kathy jacobson"},
+{"name": "guillermo soto"},
+{"name": "beverley guyer"},
+{"name": "christine nicker"},
+{"name": "gary bylund"},
+{"name": "erin work"},
+{"name": "robin macara"},
+{"name": "diane baum"},
+{"name": "chris goldshlogger"},
+{"name": "jackie ceballos"},
+{"name": "randy cl"},
+{"name": "celia conover"},
+{"name": "jennifer greer"},
+{"name": "mac partlow"},
+{"name": "aaron polak"},
+{"name": "lloyd mason"},
+{"name": "tiffany parkers"},
+{"name": "lauren brenon"},
+{"name": "dale sackrider"},
+{"name": "jenny jabareen"},
+{"name": "craig aaron"},
+{"name": "jack turner"},
+{"name": "eleanor putman"},
+{"name": "justin matcli"},
+{"name": "mandi fathauer"},
+{"name": "wesley texas"},
+{"name": "grace hughes"},
+{"name": "john fontanelle"},
+{"name": "nick long"},
+{"name": "scott kleiman"},
+{"name": "ginger mgk"},
+{"name": "jamie lau"},
+{"name": "fernando paz"},
+{"name": "steve jenkins"},
+{"name": "rachel duvall"},
+{"name": "wesley williams"},
+{"name": "tim bell"},
+{"name": "charlotte lauret"},
+{"name": "john lai"},
+{"name": "bob briggs"},
+{"name": "cody blue"},
+{"name": "jim martin"},
+{"name": "heidi winston"},
+{"name": "lee dryer"},
+{"name": "frank lopes"},
+{"name": "kurtis miller"},
+{"name": "cindy nguyen"},
+{"name": "alejandra bermudez"},
+{"name": "aaron elliott"},
+{"name": "kathy fisher"},
+{"name": "tanya alexander"},
+{"name": "dustin carlton"},
+{"name": "phillip koehnke"},
+{"name": "pat rusk"},
+{"name": "chloe hillard"},
+{"name": "al stornelli"},
+{"name": "vito panza"},
+{"name": "mark taurone"},
+{"name": "robbie littleton"},
+{"name": "jen cliff's"},
+{"name": "terry summers"},
+{"name": "michael kessel"},
+{"name": "monica muniz"},
+{"name": "shawn mckinnon"},
+{"name": "kristin ortiz"},
+{"name": "mark stone"},
+{"name": "bill simo"},
+{"name": "gary galvin"},
+{"name": "debra hoss"},
+{"name": "tessa metz"},
+{"name": "jason kellerman"},
+{"name": "lynn gurney"},
+{"name": "michael smydra"},
+{"name": "kim espinoza"},
+{"name": "brain alvarez"},
+{"name": "shawn glick"},
+{"name": "mark starkey"},
+{"name": "alex muller"},
+{"name": "ashley sweat"},
+{"name": "britt gallard"},
+{"name": "ken hidgon"},
+{"name": "janette haley"},
+{"name": "karen palori"},
+{"name": "dave ulrich"},
+{"name": "matt abajian"},
+{"name": "rick bee"},
+{"name": "linda lutz"},
+{"name": "jody mookhoek"},
+{"name": "jerry prybycin"},
+{"name": "michal merten"},
+{"name": "ray shingler"},
+{"name": "david o'leary"},
+{"name": "todd hennum"},
+{"name": "marissa lipkin"},
+{"name": "leslie wolf"},
+{"name": "kelly bradley"},
+{"name": "michael lloyd"},
+{"name": "richard jacobs"},
+{"name": "alesha clarke"},
+{"name": "joanna ruiz"},
+{"name": "kayla stevens"},
+{"name": "bill gooley"},
+{"name": "ron blumenthal"},
+{"name": "michael rizzuto"},
+{"name": "steve cowen"},
+{"name": "curt raftshol"},
+{"name": "candy ketelsleger"},
+{"name": "carol pichelman"},
+{"name": "katie iup"},
+{"name": "ariel g"},
+{"name": "carol slater"},
+{"name": "karla held"},
+{"name": "julia kremen"},
+{"name": "tony strickland"},
+{"name": "wayne western"},
+{"name": "peter frankudakis"},
+{"name": "todd r"},
+{"name": "heather myspace"},
+{"name": "tameka wilson"},
+{"name": "joey miller"},
+{"name": "julie steinman"},
+{"name": "mark southard"},
+{"name": "christine burrell"},
+{"name": "anna maid"},
+{"name": "aaron moores"},
+{"name": "emmy emmy"},
+{"name": "tony paz"},
+{"name": "amber black"},
+{"name": "joanna anderson"},
+{"name": "larisa topov"},
+{"name": "john siciliano"},
+{"name": "jody cell"},
+{"name": "rick hasselbarth"},
+{"name": "jason cali"},
+{"name": "melissa ramos"},
+{"name": "thelma jefferson"},
+{"name": "beth bamberger"},
+{"name": "sandy scheer"},
+{"name": "carolyn biesecker"},
+{"name": "gene whitaker"},
+{"name": "kate bradley"},
+{"name": "ann p"},
+{"name": "chris houle"},
+{"name": "ira bibicoff"},
+{"name": "skye drycleaning"},
+{"name": "aurora inspections"},
+{"name": "susan gregory"},
+{"name": "james parrelli"},
+{"name": "keith shishido"},
+{"name": "jessica hamilton"},
+{"name": "michael mukhtar"},
+{"name": "kevin ballmer"},
+{"name": "maria faul"},
+{"name": "david temesi"},
+{"name": "brandon stellges"},
+{"name": "david brandt"},
+{"name": "blair h"},
+{"name": "will frannie"},
+{"name": "alexa math"},
+{"name": "bob durazo"},
+{"name": "jimmy f"},
+{"name": "glen kaas"},
+{"name": "billy duffy"},
+{"name": "anna spade"},
+{"name": "robert schoenthaler"},
+{"name": "brian connor"},
+{"name": "mike somer"},
+{"name": "elsie fling"},
+{"name": "gary dunn"},
+{"name": "michael graef"},
+{"name": "don jacklich"},
+{"name": "ali garfias"},
+{"name": "scottie anderson"},
+{"name": "melissa hartley"},
+{"name": "greg k"},
+{"name": "royal blunts"},
+{"name": "steve wheelwright"},
+{"name": "belva poland"},
+{"name": "cole storley"},
+{"name": "julian gonzalez"},
+{"name": "rick alimena"},
+{"name": "jeff loeb"},
+{"name": "sandra kowallis"},
+{"name": "dani neufeld"},
+{"name": "chelsea anderson"},
+{"name": "julie white"},
+{"name": "yi lu"},
+{"name": "debra king"},
+{"name": "randolph bazi"},
+{"name": "terrance williams"},
+{"name": "jamie collard"},
+{"name": "mack fullmer"},
+{"name": "dave bryant"},
+{"name": "todd sullivan"},
+{"name": "chris saad"},
+{"name": "scott ramsey"},
+{"name": "valerie aney"},
+{"name": "becky stinson"},
+{"name": "maria prieto"},
+{"name": "deborah lherison"},
+{"name": "ann flatau"},
+{"name": "carol arbogast"},
+{"name": "brant avondet"},
+{"name": "wilson church"},
+{"name": "henry ng"},
+{"name": "jermaine travis"},
+{"name": "sara sebahtu"},
+{"name": "andrew drake"},
+{"name": "jose cordoza"},
+{"name": "damion fuller"},
+{"name": "larry bashore"},
+{"name": "scott schaffer"},
+{"name": "dennis kline"},
+{"name": "dan hassler"},
+{"name": "carlos ravago"},
+{"name": "joe larimer"},
+{"name": "lee grizzard"},
+{"name": "eric allgaier"},
+{"name": "terri boss"},
+{"name": "paula hill"},
+{"name": "megan laque"},
+{"name": "natalie allard"},
+{"name": "brad bowser"},
+{"name": "lorraine gray"},
+{"name": "cheryl catania"},
+{"name": "becky fowler"},
+{"name": "ed waffle"},
+{"name": "trevor jukes"},
+{"name": "brandon shaffer"},
+{"name": "phil frasier"},
+{"name": "doug bike"},
+{"name": "lauren waite"},
+{"name": "dave tonni"},
+{"name": "silvia leveque"},
+{"name": "aaron helm"},
+{"name": "james yule"},
+{"name": "vickie sowka"},
+{"name": "keisha littles"},
+{"name": "nancy sainz"},
+{"name": "gloria padron"},
+{"name": "brady smith"},
+{"name": "carl schwartz"},
+{"name": "charlene sade"},
+{"name": "andrea flack"},
+{"name": "justin white"},
+{"name": "ken lovegreen"},
+{"name": "robert glenning"},
+{"name": "jimmy hamilton"},
+{"name": "jacob wolfe"},
+{"name": "dawn miller"},
+{"name": "bernard zimmerman"},
+{"name": "tim mom"},
+{"name": "chris risling"},
+{"name": "aaron valenti"},
+{"name": "andy macdonald"},
+{"name": "ian gallagher"},
+{"name": "katrina gibbs"},
+{"name": "adriene copen"},
+{"name": "tony sanders"},
+{"name": "bob mulvanity"},
+{"name": "jason sheldon"},
+{"name": "tyler armstrong"},
+{"name": "james lam"},
+{"name": "denise melendez"},
+{"name": "michael spensley"},
+{"name": "don kissner"},
+{"name": "sharon lehman"},
+{"name": "kim mcguire"},
+{"name": "janelle waldron"},
+{"name": "pat malloy"},
+{"name": "scott hoover"},
+{"name": "ariel llanos"},
+{"name": "leisha bolton"},
+{"name": "terry amen"},
+{"name": "jessica carson"},
+{"name": "jillian cell"},
+{"name": "ryan kerekes"},
+{"name": "salvador romero"},
+{"name": "gisele lopez"},
+{"name": "lola minnifield"},
+{"name": "john konc"},
+{"name": "pam blackburn"},
+{"name": "bruce carbone"},
+{"name": "alex villacana"},
+{"name": "ben cluff"},
+{"name": "marie amesse"},
+{"name": "anthony piva"},
+{"name": "tyler boyle"},
+{"name": "jaimie t"},
+{"name": "dave sullivan"},
+{"name": "tiffani ballinger"},
+{"name": "greg rublev"},
+{"name": "kyla dollar"},
+{"name": "ted nolan"},
+{"name": "vanessa gardiner"},
+{"name": "tony lajoie"},
+{"name": "lindsey e"},
+{"name": "vicente felix"},
+{"name": "autumn bar"},
+{"name": "ethan corman"},
+{"name": "anne shaw"},
+{"name": "jake seaton"},
+{"name": "joe sawasaki"},
+{"name": "diane shiffer"},
+{"name": "chris cole"},
+{"name": "joann allen"},
+{"name": "michael rutten"},
+{"name": "hannah cusumano"},
+{"name": "amy tatum"},
+{"name": "jillian parent"},
+{"name": "adam roberts"},
+{"name": "eneida pleasant"},
+{"name": "crystal wiegand"},
+{"name": "valarie copen"},
+{"name": "wm benefits"},
+{"name": "dawn roitblat"},
+{"name": "sally hill"},
+{"name": "genevieve elefante"},
+{"name": "reid hoffman"},
+{"name": "karen sieren"},
+{"name": "vicky ventura"},
+{"name": "beverly masterson"},
+{"name": "thomas kranz"},
+{"name": "keith beidel"},
+{"name": "jessica sykes"},
+{"name": "eric lampe"},
+{"name": "mike joseph"},
+{"name": "lynn myers"},
+{"name": "devon wald"},
+{"name": "denise donovan"},
+{"name": "joseph montesa"},
+{"name": "jason saltdogs"},
+{"name": "danny hoyt"},
+{"name": "cathy ayala"},
+{"name": "mike white"},
+{"name": "janet diggs"},
+{"name": "janice cavalieri"},
+{"name": "jessica shelley"},
+{"name": "barbara benson"},
+{"name": "martha ruelas"},
+{"name": "linda kirk"},
+{"name": "jason fritz"},
+{"name": "gale ginzburg"},
+{"name": "tony franco"},
+{"name": "christina cecchettini"},
+{"name": "vicky cine"},
+{"name": "alfredo rodriguez"},
+{"name": "mark sorum"},
+{"name": "aisha duran"},
+{"name": "sandy burton"},
+{"name": "john windeguth"},
+{"name": "carol mobile"},
+{"name": "mike sisterhen"},
+{"name": "joslyn fulford"},
+{"name": "michael gilmore"},
+{"name": "sam xxxxx"},
+{"name": "charles bock"},
+{"name": "dan effa"},
+{"name": "david guerrero"},
+{"name": "donald conway"},
+{"name": "shayla green"},
+{"name": "sharon pringle"},
+{"name": "emily fox"},
+{"name": "ray dotterw"},
+{"name": "dale carter"},
+{"name": "mark jarreau"},
+{"name": "zack morris"},
+{"name": "bruce nicholson"},
+{"name": "nicole anita"},
+{"name": "louise ospina"},
+{"name": "brandon evans"},
+{"name": "dan doolen"},
+{"name": "deborah riley"},
+{"name": "chris hawkins"},
+{"name": "beverly rossio"},
+{"name": "walter hinkle"},
+{"name": "suzanne boschetti"},
+{"name": "david zambrana"},
+{"name": "scott chaplan"},
+{"name": "lourdes garcia"},
+{"name": "katie niles"},
+{"name": "mack webner"},
+{"name": "latrice brown"},
+{"name": "ron ridderbusch"},
+{"name": "steven silvestri"},
+{"name": "peggy kirkham"},
+{"name": "richard black"},
+{"name": "carlos austin"},
+{"name": "diane harvey"},
+{"name": "al danielski"},
+{"name": "bruce williamson"},
+{"name": "linda duran"},
+{"name": "jessie jacinto"},
+{"name": "monique wilhite"},
+{"name": "john saurwein"},
+{"name": "linda rebrovich"},
+{"name": "eric plestor"},
+{"name": "ernest campbell"},
+{"name": "dan esch"},
+{"name": "jerome dougherty"},
+{"name": "mike foxworthy"},
+{"name": "steve wadley"},
+{"name": "maren christensen"},
+{"name": "nick manzion"},
+{"name": "jeff gamber"},
+{"name": "stewart webster"},
+{"name": "tom blinn"},
+{"name": "laura friend"},
+{"name": "michelle witington"},
+{"name": "jeremy whitman"},
+{"name": "chantel house"},
+{"name": "joe nafso"},
+{"name": "shelley kurz"},
+{"name": "dave delguercio"},
+{"name": "cathy guillermo"},
+{"name": "liana rohr"},
+{"name": "jackson bb"},
+{"name": "chris elliot"},
+{"name": "heather e"},
+{"name": "mariam popal"},
+{"name": "travis coach"},
+{"name": "nicky harris"},
+{"name": "albert gonzalez"},
+{"name": "brian haner"},
+{"name": "sherry connors"},
+{"name": "roberto juarez"},
+{"name": "david burch"},
+{"name": "jane bloomfield"},
+{"name": "jim thournir"},
+{"name": "kimberly randolph"},
+{"name": "bruce thalacker"},
+{"name": "kelly paige"},
+{"name": "derek draper"},
+{"name": "donna english"},
+{"name": "jamie cooper"},
+{"name": "michael mccormick"},
+{"name": "don bushing"},
+{"name": "brian kim"},
+{"name": "jeff fuller"},
+{"name": "matt manderll"},
+{"name": "dick knierem"},
+{"name": "john harold"},
+{"name": "dave vannorden"},
+{"name": "tyson freaky"},
+{"name": "george d'ascento"},
+{"name": "peter ju"},
+{"name": "tim perkinson"},
+{"name": "julia brinkman"},
+{"name": "von eckartsberg"},
+{"name": "dan kanngiesser"},
+{"name": "melvin sigma"},
+{"name": "bob coache"},
+{"name": "leslie clark"},
+{"name": "mario robinson"},
+{"name": "brittany barton"},
+{"name": "trisha o'hare"},
+{"name": "cherie wienszak"},
+{"name": "erin talbot"},
+{"name": "johnny williams"},
+{"name": "theresa bateman"},
+{"name": "jade palace"},
+{"name": "roger coughenauer"},
+{"name": "teresa ornelas"},
+{"name": "rob birdsell"},
+{"name": "luke daily"},
+{"name": "melanie tong"},
+{"name": "michael stephens"},
+{"name": "lucas trujillo"},
+{"name": "al mance"},
+{"name": "rueben robinson"},
+{"name": "chris rawley"},
+{"name": "shawn white"},
+{"name": "arthur cambeiro"},
+{"name": "alpha vet"},
+{"name": "courtney larson"},
+{"name": "miguel gallegos"},
+{"name": "pat may"},
+{"name": "phil verdegan"},
+{"name": "phillip vernon"},
+{"name": "imelda rodriguez"},
+{"name": "dustin gabriel"},
+{"name": "gary edwards"},
+{"name": "art d"},
+{"name": "jacob mitchell"},
+{"name": "taylor trost"},
+{"name": "andy snyder"},
+{"name": "josh josh"},
+{"name": "alan kaplin"},
+{"name": "brenda rascher"},
+{"name": "justin estrada"},
+{"name": "paul hinman"},
+{"name": "heather hill"},
+{"name": "stewart lyman"},
+{"name": "sharon twin"},
+{"name": "matt bashaar"},
+{"name": "richard mcmichael"},
+{"name": "marco a"},
+{"name": "angelo garro"},
+{"name": "steve skates"},
+{"name": "rick harvey"},
+{"name": "sandra miranda"},
+{"name": "barry young"},
+{"name": "joseph provo"},
+{"name": "isabel thompson"},
+{"name": "curt oishi"},
+{"name": "alicia gilbranson"},
+{"name": "nanci aunt"},
+{"name": "nichole shields"},
+{"name": "john preston"},
+{"name": "justin grandy"},
+{"name": "david recruitor"},
+{"name": "annette stevenson"},
+{"name": "henry fbi"},
+{"name": "laura cantwell"},
+{"name": "jeff wrightsell"},
+{"name": "liz burdick"},
+{"name": "angie vizaniaris"},
+{"name": "hunter izee"},
+{"name": "jason seifert"},
+{"name": "basil depinto"},
+{"name": "matthew desimone"},
+{"name": "colleen blain"},
+{"name": "hugo sign"},
+{"name": "tamara warren"},
+{"name": "george matress"},
+{"name": "nancy laurdson"},
+{"name": "jose perez"},
+{"name": "eileen twiggs"},
+{"name": "angie davis"},
+{"name": "robert hemphill"},
+{"name": "sydney cantrel"},
+{"name": "evan dwinnell"},
+{"name": "tim harrity"},
+{"name": "anthony harrison"},
+{"name": "jen mcmahan"},
+{"name": "louis smith"},
+{"name": "jacob anderson"},
+{"name": "bernard grossman"},
+{"name": "misty jaramillo"},
+{"name": "kevin patja"},
+{"name": "elizabeth bautista"},
+{"name": "shelby houttiker"},
+{"name": "mickey olson"},
+{"name": "earl robertson"},
+{"name": "howard tsung"},
+{"name": "kathleen dorian"},
+{"name": "jessie berggren"},
+{"name": "maria moran"},
+{"name": "paul jouhal"},
+{"name": "brooke mortenson"},
+{"name": "james shaheen"},
+{"name": "lawrence engebretson"},
+{"name": "christian bell"},
+{"name": "megan knall"},
+{"name": "gary siegner"},
+{"name": "joyce baker"},
+{"name": "james stewart"},
+{"name": "sandy hewitt"},
+{"name": "kevin fleming"},
+{"name": "milton pedroza"},
+{"name": "jacob reinbolt"},
+{"name": "janice kim"},
+{"name": "larry hildabran"},
+{"name": "velda sorrentino"},
+{"name": "carrie cheek"},
+{"name": "steve bowne"},
+{"name": "alison buck"},
+{"name": "duncan macdonald"},
+{"name": "nicole rauch"},
+{"name": "jesse sara"},
+{"name": "kelly pa"},
+{"name": "dave alexander"},
+{"name": "john hunter"},
+{"name": "lindsay hangos"},
+{"name": "adam towns"},
+{"name": "ken chase"},
+{"name": "lesley smith"},
+{"name": "ed orozco"},
+{"name": "will fromup"},
+{"name": "neil vzw"},
+{"name": "bill landlord"},
+{"name": "jessie cramer"},
+{"name": "earl anderson"},
+{"name": "kevin starai"},
+{"name": "erica rhinehart"},
+{"name": "carlos mejia"},
+{"name": "tracy guiley"},
+{"name": "marissa levy"},
+{"name": "debra huston"},
+{"name": "julie murnane"},
+{"name": "marcus handy"},
+{"name": "donna fahy"},
+{"name": "bruce tompson"},
+{"name": "eric medina"},
+{"name": "mary gleason"},
+{"name": "kate bray"},
+{"name": "victor v"},
+{"name": "tony n"},
+{"name": "paul lopez"},
+{"name": "tamika brown"},
+{"name": "monica bustillos"},
+{"name": "jill gennett"},
+{"name": "pat kemball"},
+{"name": "dan redman"},
+{"name": "dave balter"},
+{"name": "robin bauer"},
+{"name": "curtis rekter"},
+{"name": "craig hammer"},
+{"name": "matt manh"},
+{"name": "stephanie zia"},
+{"name": "mark brunsma"},
+{"name": "william ferguson"},
+{"name": "lindsey butte"},
+{"name": "brian dastrup"},
+{"name": "jeff graves"},
+{"name": "jerry trobaugh"},
+{"name": "sam banda"},
+{"name": "daniel krieg"},
+{"name": "mike daley"},
+{"name": "gina palermo"},
+{"name": "eric idasas"},
+{"name": "paul farrell"},
+{"name": "kay gallin"},
+{"name": "mike beutien"},
+{"name": "marcus shepard"},
+{"name": "carrie marquez"},
+{"name": "greg bayless"},
+{"name": "dustin crites"},
+{"name": "dana home"},
+{"name": "peggy herzig"},
+{"name": "pedro adao"},
+{"name": "david feinstein"},
+{"name": "eric perkins"},
+{"name": "kathy mayfield"},
+{"name": "al r"},
+{"name": "anderson dave"},
+{"name": "dan weaver"},
+{"name": "gary hodnett"},
+{"name": "michael gotzler"},
+{"name": "maria uribe"},
+{"name": "robert adams"},
+{"name": "jaimie spayduh"},
+{"name": "joan cannon"},
+{"name": "joslyn corporation"},
+{"name": "christian martin"},
+{"name": "brett gudim"},
+{"name": "amber graddick"},
+{"name": "dan ferrell"},
+{"name": "steven weihrouch"},
+{"name": "steve jurichich"},
+{"name": "alberto vazquez"},
+{"name": "heather smith"},
+{"name": "kitty cheema"},
+{"name": "chris elson"},
+{"name": "anthony spina"},
+{"name": "judy missey"},
+{"name": "bob labrier"},
+{"name": "lara wahlbeck"},
+{"name": "liz naiman"},
+{"name": "cristy farmer"},
+{"name": "john menge"},
+{"name": "maggie doughty"},
+{"name": "amy craib"},
+{"name": "chris dussiaume"},
+{"name": "sheila potter"},
+{"name": "bonnie lopez"},
+{"name": "chuck obrian"},
+{"name": "kristi rushing"},
+{"name": "blake fronk"},
+{"name": "erin fu"},
+{"name": "huey kocher"},
+{"name": "george supervisor"},
+{"name": "amy childress"},
+{"name": "tom barthel"},
+{"name": "connie goodly"},
+{"name": "jasmine snoddy"},
+{"name": "mike z"},
+{"name": "harry lord"},
+{"name": "sam ligon"},
+{"name": "kerry tyler"},
+{"name": "rachell miller"},
+{"name": "morgan matthews"},
+{"name": "donn peters"},
+{"name": "colin yohe"},
+{"name": "bryan harding"},
+{"name": "walker dodson"},
+{"name": "william sommerschield"},
+{"name": "brad gordon"},
+{"name": "suzanne mccormick"},
+{"name": "daniel fontenot"},
+{"name": "lori wakerton"},
+{"name": "lee dungey"},
+{"name": "denise gullickson"},
+{"name": "mike cutri"},
+{"name": "omar campos"},
+{"name": "pat crabtree"},
+{"name": "todd provencher"},
+{"name": "tom hanchar"},
+{"name": "bryan bernal"},
+{"name": "matthew shanahan"},
+{"name": "jeremy s"},
+{"name": "walter recinos"},
+{"name": "phyllis mielke"},
+{"name": "ted staloch"},
+{"name": "chris cm"},
+{"name": "adrian rosas"},
+{"name": "ed covell"},
+{"name": "barry hurewitz"},
+{"name": "enoch perry"},
+{"name": "blair austin"},
+{"name": "glenn hackemer"},
+{"name": "gary dufek"},
+{"name": "evan kaichi"},
+{"name": "berta shilman"},
+{"name": "carol lubin"},
+{"name": "kenny chan"},
+{"name": "latoya johnson"},
+{"name": "sarah stohler"},
+{"name": "lydia castro"},
+{"name": "catherine dyakiewicz"},
+{"name": "jim gettys"},
+{"name": "theresa cusimano"},
+{"name": "sierra vista"},
+{"name": "mike morrissey"},
+{"name": "rob stefanic"},
+{"name": "larry allan"},
+{"name": "jeremy o"},
+{"name": "pam rodrigues"},
+{"name": "kyla cell"},
+{"name": "elda home"},
+{"name": "rob gerstein"},
+{"name": "zack moss"},
+{"name": "jamie hartrich"},
+{"name": "roberto torres"},
+{"name": "chandra line"},
+{"name": "richard tomacheck"},
+{"name": "pat hester"},
+{"name": "julian burton"},
+{"name": "jackie interiano"},
+{"name": "christine yang"},
+{"name": "ed herzog"},
+{"name": "matt millington"},
+{"name": "steve n"},
+{"name": "gabriel acosta"},
+{"name": "merle norman"},
+{"name": "donald ritchie"},
+{"name": "justin vernon"},
+{"name": "ellie cano"},
+{"name": "kirk simmons"},
+{"name": "megan cadow"},
+{"name": "dean hoooog"},
+{"name": "ashley faustin"},
+{"name": "richard bumbalough"},
+{"name": "susan crutchfield"},
+{"name": "chris skibba"},
+{"name": "mark gray"},
+{"name": "holly walters"},
+{"name": "brandon ferguson"},
+{"name": "john white"},
+{"name": "jennifer goerzen"},
+{"name": "steve dirks"},
+{"name": "mark balaban"},
+{"name": "joann mazzara"},
+{"name": "vicky burch"},
+{"name": "tim gayda"},
+{"name": "phil vaninwigen"},
+{"name": "christopher barker"},
+{"name": "larry hansen"},
+{"name": "paul tibbenham"},
+{"name": "alex hartz"},
+{"name": "tom hulse"},
+{"name": "chad howle"},
+{"name": "ron jenkins"},
+{"name": "dennis wilenchik"},
+{"name": "maria roscino"},
+{"name": "gordon gates"},
+{"name": "kelly allegar"},
+{"name": "pam ybarrolaza"},
+{"name": "tom wix"},
+{"name": "kim teranova"},
+{"name": "charlotte miller"},
+{"name": "carlos cymerman"},
+{"name": "darrel hannah"},
+{"name": "lindsey geier"},
+{"name": "steve gahnz"},
+{"name": "nicholas ho"},
+{"name": "melissa dassori"},
+{"name": "tom schaumberg"},
+{"name": "glen park"},
+{"name": "anthony roxy"},
+{"name": "chris coulson"},
+{"name": "kay kay"},
+{"name": "scott isaacs"},
+{"name": "beatrice moritz"},
+{"name": "casey boost"},
+{"name": "greg gredvig"},
+{"name": "susan woo"},
+{"name": "christy barks"},
+{"name": "brian jordan"},
+{"name": "emery lecrone"},
+{"name": "craig gap"},
+{"name": "richard menzies"},
+{"name": "simon illinois"},
+{"name": "gordon daines"},
+{"name": "dawn hinkle"},
+{"name": "zoe gonza"},
+{"name": "gretchen cell"},
+{"name": "caroline kirchner"},
+{"name": "alex montoya"},
+{"name": "david krumanaker"},
+{"name": "juan dejesus"},
+{"name": "emma alabis"},
+{"name": "cindy lugtu"},
+{"name": "susan burton"},
+{"name": "ben lion"},
+{"name": "isabelle buzby"},
+{"name": "joshua hetherington"},
+{"name": "christian zann"},
+{"name": "brandi self"},
+{"name": "dawn cucurullo"},
+{"name": "brandon pickett"},
+{"name": "jon delange"},
+{"name": "andy honeycutt"},
+{"name": "cody fisher"},
+{"name": "robert tasker"},
+{"name": "mike facer"},
+{"name": "brian mcinerney"},
+{"name": "derek riley"},
+{"name": "bryan king"},
+{"name": "michelle <gym>"},
+{"name": "andre curry"},
+{"name": "kristin bindon"},
+{"name": "lucy photobucket"},
+{"name": "steve rossow"},
+{"name": "scott stanford"},
+{"name": "dave video"},
+{"name": "kim thompson"},
+{"name": "bruce g"},
+{"name": "rick chilcott"},
+{"name": "connie steinke"},
+{"name": "todd greene"},
+{"name": "warren lee"},
+{"name": "james windsor"},
+{"name": "dianna leen"},
+{"name": "patrick arguello"},
+{"name": "joel sanford"},
+{"name": "debbie phillips"},
+{"name": "terry briggs"},
+{"name": "heather loyd"},
+{"name": "ana jail"},
+{"name": "austin abell"},
+{"name": "john o'brien"},
+{"name": "matt falk"},
+{"name": "tuyet le"},
+{"name": "david talley"},
+{"name": "wendy whalen"},
+{"name": "chuck hill"},
+{"name": "victor reyes"},
+{"name": "brian rowley"},
+{"name": "gregory voit"},
+{"name": "cherrie pedigo"},
+{"name": "trevor nicholson"},
+{"name": "debbie mick"},
+{"name": "dave buck"},
+{"name": "joseph ghoul"},
+{"name": "denise kovalevich"},
+{"name": "carlos ausejo"},
+{"name": "eddie dragon"},
+{"name": "charles mounday"},
+{"name": "werner theiss"},
+{"name": "leigh ihop"},
+{"name": "mike clifton"},
+{"name": "shira hammerman"},
+{"name": "rick wanek"},
+{"name": "scott fahey"},
+{"name": "steve benidict"},
+{"name": "hector rodrigues"},
+{"name": "lee robertson"},
+{"name": "phoebe connell"},
+{"name": "john hetrick"},
+{"name": "diane chladny"},
+{"name": "linda martin"},
+{"name": "kristin sztengel"},
+{"name": "jason garner"},
+{"name": "gloria ayala"},
+{"name": "adina flores"},
+{"name": "sabrina verizon"},
+{"name": "jennifer holmes"},
+{"name": "whitney crazy"},
+{"name": "al cloud"},
+{"name": "lawrence weinberg"},
+{"name": "drew kawagucho"},
+{"name": "tim dorek"},
+{"name": "al dentino"},
+{"name": "peg burns"},
+{"name": "maribeth leineke"},
+{"name": "vanessa madrid"},
+{"name": "robin feinman"},
+{"name": "britney thompson"},
+{"name": "mike humphrey"},
+{"name": "elena tornez"},
+{"name": "diane citrone"},
+{"name": "kacie clemens"},
+{"name": "alisha nagarkar"},
+{"name": "mike skullcandy"},
+{"name": "sara livermore"},
+{"name": "kevin worley"},
+{"name": "jose korneluk"},
+{"name": "ron fulton"},
+{"name": "jason weiss"},
+{"name": "kenny kerzner"},
+{"name": "megan deas"},
+{"name": "bill fenizio"},
+{"name": "tom sammons"},
+{"name": "brett outchcunis"},
+{"name": "sharon barron"},
+{"name": "chris yoon"},
+{"name": "george garcia"},
+{"name": "jerry polis"},
+{"name": "andrea endup"},
+{"name": "jim pacula"},
+{"name": "lori cable"},
+{"name": "daniel malaty"},
+{"name": "mike stopak"},
+{"name": "martha trotman"},
+{"name": "dustin judd"},
+{"name": "randy bergh"},
+{"name": "shawn kuhns"},
+{"name": "mae donaldson"},
+{"name": "loretta bailey"},
+{"name": "alberto urueta"},
+{"name": "pat dohogne"},
+{"name": "jonathan boozeman"},
+{"name": "linda huber"},
+{"name": "susan thomson"},
+{"name": "ann svetlic"},
+{"name": "jay hirsch"},
+{"name": "cliff benson"},
+{"name": "david haws"},
+{"name": "andrew deak"},
+{"name": "phil clayt"},
+{"name": "fred curtis"},
+{"name": "andy contero"},
+{"name": "william broadnax"},
+{"name": "wendy sage"},
+{"name": "joanna frame"},
+{"name": "adam gold"},
+{"name": "ann rella"},
+{"name": "thao tran"},
+{"name": "jeffrey bauer"},
+{"name": "marie boutin"},
+{"name": "mark billig"},
+{"name": "tyson tuttle"},
+{"name": "paul duchaney"},
+{"name": "craig custer"},
+{"name": "cheryl ziegler"},
+{"name": "paul paulakus"},
+{"name": "steve fryer"},
+{"name": "jeanette shaheen"},
+{"name": "bobby baker"},
+{"name": "christopher lambert"},
+{"name": "cassy house"},
+{"name": "celena g"},
+{"name": "barbara farnsworth"},
+{"name": "brooke benthin"},
+{"name": "jorge hernandez"},
+{"name": "collin cole"},
+{"name": "sharon frank"},
+{"name": "jenny mulder"},
+{"name": "albert palomino"},
+{"name": "todd worz"},
+{"name": "diane elmer"},
+{"name": "florence papouschek"},
+{"name": "chris colins"},
+{"name": "mae robinson"},
+{"name": "tim harkins"},
+{"name": "lance chody"},
+{"name": "cathy lewis"},
+{"name": "rusty reed"},
+{"name": "chi head"},
+{"name": "jade rogers"},
+{"name": "roy early"},
+{"name": "jeremy church"},
+{"name": "maryann perero"},
+{"name": "kara glynn"},
+{"name": "mildred hughes"},
+{"name": "jason cutone"},
+{"name": "lenny ojeda"},
+{"name": "bob ogawa"},
+{"name": "levi idaho"},
+{"name": "vanessa yslas"},
+{"name": "andrea steinbeck"},
+{"name": "matt lowe"},
+{"name": "duane hecht"},
+{"name": "gloria eutsler"},
+{"name": "ralph tedman"},
+{"name": "janice burris"},
+{"name": "michael mann"},
+{"name": "bill cluff"},
+{"name": "shirley thalacker"},
+{"name": "daryl cummings"},
+{"name": "paul adineran"},
+{"name": "shirley e"},
+{"name": "david taulbee"},
+{"name": "pennie pride"},
+{"name": "vincent verderame"},
+{"name": "doug stiteler"},
+{"name": "george budd"},
+{"name": "ernie lv"},
+{"name": "peter sanchez"},
+{"name": "stacey dillingers"},
+{"name": "fran hasslacher"},
+{"name": "mike behm"},
+{"name": "selina rogers"},
+{"name": "karey hart"},
+{"name": "mark keifer"},
+{"name": "chris mathews"},
+{"name": "will mckenna"},
+{"name": "sue vaneerden"},
+{"name": "karen pearson"},
+{"name": "courtney north"},
+{"name": "jeff kaliner"},
+{"name": "rachel chang"},
+{"name": "robert higgins"},
+{"name": "james broome"},
+{"name": "andrew david"},
+{"name": "donald smith"},
+{"name": "peter siragusa"},
+{"name": "anthony turso"},
+{"name": "lana st"},
+{"name": "jessica kiper"},
+{"name": "phil v"},
+{"name": "ben lohman"},
+{"name": "joe reeves"},
+{"name": "amie s"},
+{"name": "randy spahn"},
+{"name": "liz pacazzi"},
+{"name": "amy hett"},
+{"name": "frank drywall"},
+{"name": "jen oc"},
+{"name": "robert mackey"},
+{"name": "rashida forbes"},
+{"name": "rebecca mitchell"},
+{"name": "connie huedepohl"},
+{"name": "terry modesitt"},
+{"name": "debby henning"},
+{"name": "keith randale"},
+{"name": "joshua scherer"},
+{"name": "michael little"},
+{"name": "carlos gonzales"},
+{"name": "mike soulema"},
+{"name": "dayna miami"},
+{"name": "michael youn"},
+{"name": "anna bannana"},
+{"name": "curtis high"},
+{"name": "bill arehart"},
+{"name": "susan wandmacher"},
+{"name": "josh hisle"},
+{"name": "chrystal buford"},
+{"name": "kevin nicolay"},
+{"name": "david simmons"},
+{"name": "tam tam"},
+{"name": "danny mclane"},
+{"name": "paul sousa"},
+{"name": "will faust"},
+{"name": "clay granger"},
+{"name": "ivy brouhard"},
+{"name": "dan leonard"},
+{"name": "philip fraher"},
+{"name": "matt white"},
+{"name": "kenneth colbert"},
+{"name": "dina tito"},
+{"name": "jack drury"},
+{"name": "casey schwendeman"},
+{"name": "tom client"},
+{"name": "heather leah"},
+{"name": "joel beaty"},
+{"name": "maurice jcfs"},
+{"name": "art acosta"},
+{"name": "marcia stellpflug"},
+{"name": "pam wright"},
+{"name": "linda adcock"},
+{"name": "barry kemp"},
+{"name": "lawrence pruett"},
+{"name": "garret hilseth"},
+{"name": "duane hunn"},
+{"name": "mark larsen"},
+{"name": "daniel evertt"},
+{"name": "richard yaffa"},
+{"name": "bob karen"},
+{"name": "eliana gutiernez"},
+{"name": "tommy work"},
+{"name": "jolene brown"},
+{"name": "danny kenyon"},
+{"name": "mickey agent"},
+{"name": "sandra navarro"},
+{"name": "john klossing"},
+{"name": "bruce steines"},
+{"name": "megan oh"},
+{"name": "larissa lam"},
+{"name": "randy medina"},
+{"name": "mckenzie moore"},
+{"name": "dell computer"},
+{"name": "amy f"},
+{"name": "jen qubain"},
+{"name": "pat donohue"},
+{"name": "jim marggraff"},
+{"name": "courtney parsons"},
+{"name": "luis mota"},
+{"name": "william coe"},
+{"name": "kayla dad"},
+{"name": "joy nichols"},
+{"name": "dan strothers"},
+{"name": "jennifer bain"},
+{"name": "letty trevino"},
+{"name": "dave jackson"},
+{"name": "austin holloway"},
+{"name": "rene inman"},
+{"name": "russell abraham"},
+{"name": "glenda harrison"},
+{"name": "matthew wiech"},
+{"name": "travis bryant"},
+{"name": "angie batchelor"},
+{"name": "ryan dwyer"},
+{"name": "henry campa"},
+{"name": "steve duran"},
+{"name": "john picozzi"},
+{"name": "glenn wendel"},
+{"name": "tom prettyman"},
+{"name": "peter hwang"},
+{"name": "grace manzano"},
+{"name": "sean spiralsun"},
+{"name": "haley coldwell"},
+{"name": "bella vargas"},
+{"name": "dan garcia"},
+{"name": "chloe shackelton"},
+{"name": "jessica k"},
+{"name": "catherine herb"},
+{"name": "louise landrum"},
+{"name": "floyd krey"},
+{"name": "william agado"},
+{"name": "horace huntley"},
+{"name": "joey pereira"},
+{"name": "ted cramer"},
+{"name": "bill shop"},
+{"name": "jessie security"},
+{"name": "casey hardy"},
+{"name": "mark zepeda'b"},
+{"name": "phil crews"},
+{"name": "brian connolly"},
+{"name": "jimmy dixon"},
+{"name": "alden homrich"},
+{"name": "sarah vernon"},
+{"name": "eric abele"},
+{"name": "joshua coater"},
+{"name": "patrick mcelmurry"},
+{"name": "sandy miller"},
+{"name": "irene lehman"},
+{"name": "tanya armenta"},
+{"name": "deanna cooke"},
+{"name": "lisa legg"},
+{"name": "kathy hughes"},
+{"name": "elidia suchomel"},
+{"name": "sean grogan"},
+{"name": "pierre zgheib"},
+{"name": "heather welborn"},
+{"name": "harris twersky"},
+{"name": "ron aviv"},
+{"name": "karine nehme"},
+{"name": "charlie black"},
+{"name": "sharron sharif"},
+{"name": "perry hirsch"},
+{"name": "matt sherer"},
+{"name": "jacinda welch"},
+{"name": "betty wadell"},
+{"name": "david dunhinn"},
+{"name": "madison porzio"},
+{"name": "oliver maletz"},
+{"name": "tiffany hankins"},
+{"name": "gerald klein"},
+{"name": "sheldon harris"},
+{"name": "greg lartilleux"},
+{"name": "chris gass"},
+{"name": "sydney locke"},
+{"name": "kevin gilson"},
+{"name": "ashley david"},
+{"name": "kristen fields"},
+{"name": "katie bohatch"},
+{"name": "kylie sedlacek"},
+{"name": "eduardo samame"},
+{"name": "jeff zimina"},
+{"name": "joe acchione"},
+{"name": "david butler"},
+{"name": "raul sanchez"},
+{"name": "james talley"},
+{"name": "pat kim"},
+{"name": "daniel fox"},
+{"name": "eric morris"},
+{"name": "scott rosenberger"},
+{"name": "manuel gonzales"},
+{"name": "raymond dingle"},
+{"name": "john star"},
+{"name": "paul pushert"},
+{"name": "marilyn poole"},
+{"name": "ron hawkins"},
+{"name": "michael chow"},
+{"name": "roger michel"},
+{"name": "sara remax"},
+{"name": "joe dempsey"},
+{"name": "shannon mullis"},
+{"name": "dara dnb"},
+{"name": "jeff f"},
+{"name": "wai thai"},
+{"name": "blaine chiroprac"},
+{"name": "christian vida"},
+{"name": "leroy perry"},
+{"name": "julie theriault"},
+{"name": "eric thayer"},
+{"name": "diane harris"},
+{"name": "alice z"},
+{"name": "joe kitchen"},
+{"name": "heather clem"},
+{"name": "yu david"},
+{"name": "art welch"},
+{"name": "sam liggett"},
+{"name": "kelly kimura"},
+{"name": "tina phan"},
+{"name": "michelle jonson"},
+{"name": "donna hammick"},
+{"name": "manuel sr"},
+{"name": "ryan odeal"},
+{"name": "joe grasso"},
+{"name": "steven sewell"},
+{"name": "steve campbell"},
+{"name": "desmond mack"},
+{"name": "robert bennett"},
+{"name": "warren wilson"},
+{"name": "cliff stoller"},
+{"name": "teresa darts"},
+{"name": "laura hamilton"},
+{"name": "dan chen"},
+{"name": "donna gamboni"},
+{"name": "bruce cain"},
+{"name": "chris blondek"},
+{"name": "clarissa rillera"},
+{"name": "stephanie oquendo"},
+{"name": "jennifer craddock"},
+{"name": "ryan yagura"},
+{"name": "ryan wells"},
+{"name": "rachel gonzales"},
+{"name": "christopher gassett"},
+{"name": "josh dye"},
+{"name": "luke hillman"},
+{"name": "michael zender"},
+{"name": "tam kiengiang"},
+{"name": "frank birkas"},
+{"name": "tony theodore"},
+{"name": "charles lott"},
+{"name": "ron demoulin"},
+{"name": "robin nagel"},
+{"name": "chuck cushman"},
+{"name": "erin graham"},
+{"name": "howard davison"},
+{"name": "erica b"},
+{"name": "bradley ruff"},
+{"name": "greg buhene"},
+{"name": "erica nesselroad"},
+{"name": "kathi martin"},
+{"name": "jeff hotvet"},
+{"name": "ryan lindsey"},
+{"name": "tom lynch"},
+{"name": "colleen alday"},
+{"name": "kevin drake"},
+{"name": "matthew beatty"},
+{"name": "jorge ii"},
+{"name": "steven liu"},
+{"name": "rob holland"},
+{"name": "mike difranza"},
+{"name": "jeanette nagle"},
+{"name": "joe mcphereson"},
+{"name": "joann coughlin"},
+{"name": "mike maher"},
+{"name": "rick chamberland"},
+{"name": "anna brown"},
+{"name": "david brotman"},
+{"name": "christine zammar"},
+{"name": "francis roxanne"},
+{"name": "phil hollaway"},
+{"name": "jack carswell"},
+{"name": "sara paul"},
+{"name": "deangelo nicholoson"},
+{"name": "librada vivian"},
+{"name": "renee yee"},
+{"name": "tony furano"},
+{"name": "emma rothrock"},
+{"name": "john hopkins"},
+{"name": "don starnes"},
+{"name": "angel ortiz"},
+{"name": "nelson ripoll"},
+{"name": "annalisa stone"},
+{"name": "amanda rothschiller"},
+{"name": "lisa atagi"},
+{"name": "phil johnson"},
+{"name": "jean t"},
+{"name": "mike slayman"},
+{"name": "maddie daniels"},
+{"name": "lynn howes"},
+{"name": "bill gerrard"},
+{"name": "jesse martin"},
+{"name": "kim odom"},
+{"name": "steven milton"},
+{"name": "ryan feinburg"},
+{"name": "jeff diers"},
+{"name": "josiah citrin"},
+{"name": "davis stephon"},
+{"name": "jim nash"},
+{"name": "julie stutesman"},
+{"name": "steven romero"},
+{"name": "louis lamana"},
+{"name": "brett maziman"},
+{"name": "jonathan elite"},
+{"name": "kristi maha"},
+{"name": "marshall glesby"},
+{"name": "dick runge"},
+{"name": "robert halliday"},
+{"name": "danny t"},
+{"name": "mike okada"},
+{"name": "kristi gargiulo"},
+{"name": "brook buddell"},
+{"name": "justin cimino"},
+{"name": "roy hughes"},
+{"name": "bill barten"},
+{"name": "holly reay"},
+{"name": "chase dastrup"},
+{"name": "richard horvat"},
+{"name": "percy davis"},
+{"name": "jan bell"},
+{"name": "noriko webb"},
+{"name": "max hager"},
+{"name": "kayla nichols"},
+{"name": "gail plevinsky"},
+{"name": "gary sanders"},
+{"name": "kathy butt"},
+{"name": "sarah lum"},
+{"name": "rodger boleman"},
+{"name": "stanley westberg"},
+{"name": "fred vizi"},
+{"name": "becky wall"},
+{"name": "jasmine bowers"},
+{"name": "annie kratochvil"},
+{"name": "timothy schigel"},
+{"name": "saundra saari"},
+{"name": "mary joy"},
+{"name": "shannon sharp"},
+{"name": "kevin fullmer"},
+{"name": "keith hudson"},
+{"name": "laura resler"},
+{"name": "eric fossil"},
+{"name": "rick neumann"},
+{"name": "steve savoy"},
+{"name": "john reinisch"},
+{"name": "eric wolgemuth"},
+{"name": "may stoppe"},
+{"name": "armando martinez"},
+{"name": "doug marlow"},
+{"name": "michiko singh"},
+{"name": "bob poetting"},
+{"name": "ann voges"},
+{"name": "don fuller"},
+{"name": "janice green"},
+{"name": "keith caletri"},
+{"name": "eugene matt"},
+{"name": "nick marcucci"},
+{"name": "kevin lieu"},
+{"name": "glen agrekko"},
+{"name": "lynnette zanetti"},
+{"name": "miles roberson"},
+{"name": "katrina avery"},
+{"name": "eric rehnquist"},
+{"name": "bill spittle"},
+{"name": "michael troiani"},
+{"name": "travis mcpherson"},
+{"name": "phillip whiting"},
+{"name": "britney hoskins"},
+{"name": "robin cirrintano"},
+{"name": "angie gill"},
+{"name": "brian humphrey"},
+{"name": "douglas smith"},
+{"name": "kevin robbins"},
+{"name": "donnie moore"},
+{"name": "stacy wharton"},
+{"name": "kelsey walker"},
+{"name": "tia cookie"},
+{"name": "brian canada"},
+{"name": "mia johnson"},
+{"name": "dan weeks"},
+{"name": "patricia wilson"},
+{"name": "katrina crawford"},
+{"name": "brenda piche"},
+{"name": "micheal hamilton"},
+{"name": "laura schaffer"},
+{"name": "mark pahr"},
+{"name": "kari fesler"},
+{"name": "denise gosling"},
+{"name": "allie harrison"},
+{"name": "chelsea flynn"},
+{"name": "jamie mikelson"},
+{"name": "angelica cob"},
+{"name": "michael baker"},
+{"name": "bruce neyers"},
+{"name": "michelle fuxan"},
+{"name": "david pearson"},
+{"name": "steven work"},
+{"name": "anthony milton"},
+{"name": "antony rosales"},
+{"name": "shelley iii"},
+{"name": "jeff krivis"},
+{"name": "chad english"},
+{"name": "jon myslivy"},
+{"name": "calvin daks"},
+{"name": "margaret verderame"},
+{"name": "angela woodfruff"},
+{"name": "pete chevrolet"},
+{"name": "beth sereni"},
+{"name": "jeffrey lyons"},
+{"name": "dustin rinehart"},
+{"name": "tony cirrintano"},
+{"name": "eric tat"},
+{"name": "alex silicz"},
+{"name": "brandy dunn"},
+{"name": "david berley"},
+{"name": "quyen pham"},
+{"name": "wayne burks"},
+{"name": "jay fisk"},
+{"name": "levi palmbach"},
+{"name": "mike e"},
+{"name": "nelson lara"},
+{"name": "ed farr"},
+{"name": "eric gonzalez"},
+{"name": "randy uglem"},
+{"name": "keith gercak"},
+{"name": "ian chen"},
+{"name": "jeremy lees"},
+{"name": "ron waterlyn"},
+{"name": "clint powell"},
+{"name": "enrique dibildogs"},
+{"name": "alexa chitwood"},
+{"name": "rebecca willett"},
+{"name": "amanda morris"},
+{"name": "stephanie wadas"},
+{"name": "phil gray"},
+{"name": "lissa marciano"},
+{"name": "leon turner"},
+{"name": "mike darnbrough"},
+{"name": "gilbert cwwx"},
+{"name": "walter isaloo"},
+{"name": "brett nortwick"},
+{"name": "john shawnkyes"},
+{"name": "shawn tweedell"},
+{"name": "ed sikaffy"},
+{"name": "nadia vinichenko"},
+{"name": "kevin cindy"},
+{"name": "karl micotti"},
+{"name": "matt mcnair"},
+{"name": "chris simp"},
+{"name": "renee graves"},
+{"name": "megan gwynne"},
+{"name": "van kerkhoven"},
+{"name": "adam southward"},
+{"name": "selma tibbs"},
+{"name": "george goldfarb"},
+{"name": "greg schmidt"},
+{"name": "brandon murphy"},
+{"name": "kevin johns"},
+{"name": "john leiter"},
+{"name": "taylor mom"},
+{"name": "guy pinto"},
+{"name": "abbey gipson"},
+{"name": "jodi lien"},
+{"name": "crystal darden"},
+{"name": "jill droge"},
+{"name": "matt ford"},
+{"name": "eric gamble"},
+{"name": "steve swartz"},
+{"name": "john rahn"},
+{"name": "melisa mcneil"},
+{"name": "melanie wilcoxson"},
+{"name": "renae aguilar"},
+{"name": "scott siney"},
+{"name": "amber lundquist"},
+{"name": "glenn nerona"},
+{"name": "sandra silva"},
+{"name": "tim mclain"},
+{"name": "gary dover"},
+{"name": "derek wilkinson"},
+{"name": "terry bromley"},
+{"name": "shane overfield"},
+{"name": "steve polce"},
+{"name": "nick kavouklis"},
+{"name": "an bartlett"},
+{"name": "jean cottrell"},
+{"name": "kevin patnick"},
+{"name": "randy stone"},
+{"name": "charles richards"},
+{"name": "mark schaefer"},
+{"name": "james lupino"},
+{"name": "ryan gallaspie"},
+{"name": "wayne spiekerman"},
+{"name": "sheri perricone"},
+{"name": "gloria galeno"},
+{"name": "michelle horowitz"},
+{"name": "keith baker"},
+{"name": "michelle lefebvre"},
+{"name": "nick bearden"},
+{"name": "russ hanson"},
+{"name": "andre legris"},
+{"name": "sue mercedes"},
+{"name": "whitley grandberry"},
+{"name": "simon flavin"},
+{"name": "margaret watson"},
+{"name": "carol hendrixson"},
+{"name": "ryan main"},
+{"name": "mike migliore"},
+{"name": "roger nedel"},
+{"name": "joanne fortney"},
+{"name": "steven pof"},
+{"name": "may iii"},
+{"name": "lynn henry"},
+{"name": "shannon james"},
+{"name": "mike kelland"},
+{"name": "dorothy marty"},
+{"name": "dominic gnanapragasam"},
+{"name": "kirk mcandrew"},
+{"name": "william ferron"},
+{"name": "ashley taft"},
+{"name": "caron richardson"},
+{"name": "chad martin"},
+{"name": "hoa checkout"},
+{"name": "jeff jackel"},
+{"name": "bob okano"},
+{"name": "cole alleman"},
+{"name": "milton elliott"},
+{"name": "audrey rubacava"},
+{"name": "rob moore"},
+{"name": "abe sung"},
+{"name": "cassey mcclintock"},
+{"name": "vikki lujano"},
+{"name": "peter steinhouse"},
+{"name": "tyler moore"},
+{"name": "jonathon isaac"},
+{"name": "bruce b"},
+{"name": "ron jensen"},
+{"name": "elizabeth mason"},
+{"name": "jimmie j"},
+{"name": "richie rich"},
+{"name": "lisa gonzales"},
+{"name": "abe flores"},
+{"name": "sam ricke"},
+{"name": "jack paolin"},
+{"name": "mark shibuya"},
+{"name": "michael villers"},
+{"name": "lois steward"},
+{"name": "mark clein"},
+{"name": "diane stanley"},
+{"name": "joni bussell"},
+{"name": "chanel wood"},
+{"name": "dave pumneo"},
+{"name": "synthia elmore"},
+{"name": "adrian walters"},
+{"name": "jessie koch"},
+{"name": "brett fodero"},
+{"name": "cheryl serio"},
+{"name": "dan vannes"},
+{"name": "gary gray"},
+{"name": "pete petersen"},
+{"name": "mike aminov"},
+{"name": "jere smokes"},
+{"name": "chris westlund"},
+{"name": "matthew young"},
+{"name": "anthony celestino"},
+{"name": "greg m"},
+{"name": "david barrett"},
+{"name": "marvin riggins"},
+{"name": "jesse nichols"},
+{"name": "thomas anable"},
+{"name": "ben marsh"},
+{"name": "amy jedlica"},
+{"name": "paula leggett"},
+{"name": "ben jones"},
+{"name": "kenny mcinnis"},
+{"name": "ryan h"},
+{"name": "reid nansen"},
+{"name": "claire stockton"},
+{"name": "chris ray"},
+{"name": "eric venice"},
+{"name": "vicki herbalife"},
+{"name": "sue mes"},
+{"name": "danny lennon"},
+{"name": "rachael rigaurd"},
+{"name": "issac odom"},
+{"name": "amber stavenger"},
+{"name": "jackie lane"},
+{"name": "jeff schussler"},
+{"name": "jeffrey jay"},
+{"name": "mike perron"},
+{"name": "jody mepham"},
+{"name": "michelle ward"},
+{"name": "brittany chi"},
+{"name": "lucy greenwell"},
+{"name": "alex klabin"},
+{"name": "johnny tickets"},
+{"name": "dean becker"},
+{"name": "bob shafer"},
+{"name": "anne tufts"},
+{"name": "chelsea jones"},
+{"name": "kevin dunn"},
+{"name": "domingo gonzalez"},
+{"name": "matt rauch"},
+{"name": "anita ianniciello"},
+{"name": "louise berggren"},
+{"name": "steve babcock"},
+{"name": "holly marquardt"},
+{"name": "kevin ozam"},
+{"name": "murray megan"},
+{"name": "ronnie barnet"},
+{"name": "daniel goroff"},
+{"name": "michael homer"},
+{"name": "rick lehman"},
+{"name": "tom isett"},
+{"name": "leland hall"},
+{"name": "bonita jaskie"},
+{"name": "renee anderson"},
+{"name": "steve seeger"},
+{"name": "jonathan manjarrez"},
+{"name": "josh iverson"},
+{"name": "michael reul"},
+{"name": "angela marshall"},
+{"name": "kendall john"},
+{"name": "drew bauer"},
+{"name": "greg brott"},
+{"name": "thomas jackson"},
+{"name": "ashley pulido"},
+{"name": "lisa renteria"},
+{"name": "jon hall"},
+{"name": "jessie langley"},
+{"name": "katherine shields"},
+{"name": "linda trotter"},
+{"name": "lucio echeverria"},
+{"name": "dawn williscroft"},
+{"name": "justine maldonado"},
+{"name": "vicki haneckow"},
+{"name": "cory thomas"},
+{"name": "linda janiak"},
+{"name": "claire bryan"},
+{"name": "elizabeth dowd"},
+{"name": "bruce brown"},
+{"name": "aaron felsheim"},
+{"name": "dana margolis"},
+{"name": "len stokes"},
+{"name": "wes white"},
+{"name": "fred myers"},
+{"name": "rich kurta"},
+{"name": "dave forest"},
+{"name": "tony steward"},
+{"name": "shana odinga"},
+{"name": "dennis burright"},
+{"name": "chu cang"},
+{"name": "don pistotnik"},
+{"name": "jon margolis"},
+{"name": "danny smalls"},
+{"name": "russell mullin"},
+{"name": "kirsten deirup"},
+{"name": "damien zamora"},
+{"name": "lisa bown"},
+{"name": "eilene brown"},
+{"name": "teri munger"},
+{"name": "mike blakely"},
+{"name": "oren cohen"},
+{"name": "justin dahmen"},
+{"name": "judith jarrett"},
+{"name": "jaimie busby"},
+{"name": "whitney gardner"},
+{"name": "danny weidenhoft"},
+{"name": "kristi keefe"},
+{"name": "dick kantor"},
+{"name": "ashley wi"},
+{"name": "susie sanders"},
+{"name": "henry cook"},
+{"name": "stacy carruth"},
+{"name": "tyler jardine"},
+{"name": "john roe"},
+{"name": "devin devore"},
+{"name": "larry klein"},
+{"name": "tony estabo"},
+{"name": "brandy wells"},
+{"name": "toni foreman"},
+{"name": "preston miller"},
+{"name": "johnny reese"},
+{"name": "mike pagano"},
+{"name": "mindy crum"},
+{"name": "tim fitzgerald"},
+{"name": "mira lee"},
+{"name": "richard miller"},
+{"name": "judson gregory"},
+{"name": "erica jensen"},
+{"name": "liz popenhouse"},
+{"name": "lisa lui"},
+{"name": "leslie ballard"},
+{"name": "john kowalski"},
+{"name": "alvin smith"},
+{"name": "john emrick"},
+{"name": "connie nguyen"},
+{"name": "faye thorek"},
+{"name": "tia rogers"},
+{"name": "steve helms"},
+{"name": "hector graniel"},
+{"name": "danielle ledoux"},
+{"name": "jody riggs"},
+{"name": "susan vidal"},
+{"name": "chris plaia"},
+{"name": "trey barclay"},
+{"name": "harris millman"},
+{"name": "mark vaught"},
+{"name": "frank corso"},
+{"name": "kim honora"},
+{"name": "roy helo"},
+{"name": "john garza"},
+{"name": "al martinez"},
+{"name": "heidi mayo"},
+{"name": "kristin bauer"},
+{"name": "deborah morell"},
+{"name": "jennifer rozumowicz"},
+{"name": "dina lasky"},
+{"name": "brian bobo"},
+{"name": "jon larson"},
+{"name": "ben sappington"},
+{"name": "ann comber"},
+{"name": "sam ruscica"},
+{"name": "may tran"},
+{"name": "tanja saarinen"},
+{"name": "brandon gage"},
+{"name": "chasity haden"},
+{"name": "mitch arnold"},
+{"name": "roy smit"},
+{"name": "derek steves"},
+{"name": "christy ratheal"},
+{"name": "ed holmes"},
+{"name": "amy schiepher"},
+{"name": "jan rosenfeld"},
+{"name": "shane walker"},
+{"name": "ariel dorn"},
+{"name": "jesse penny"},
+{"name": "janis newell"},
+{"name": "tony turrentine"},
+{"name": "david olivares"},
+{"name": "stacey lima"},
+{"name": "dallas henderson"},
+{"name": "adam williams"},
+{"name": "justin yerkes"},
+{"name": "sid golf"},
+{"name": "roger perez"},
+{"name": "herman schwantz"},
+{"name": "laurence jackson"},
+{"name": "hayley clarke"},
+{"name": "dean huntley"},
+{"name": "marilyn palmer"},
+{"name": "robert hempel"},
+{"name": "rick mossman"},
+{"name": "vince pusteri"},
+{"name": "faith martinez"},
+{"name": "chris depico"},
+{"name": "chris hester"},
+{"name": "phil braden"},
+{"name": "eric ryan"},
+{"name": "melanie kees"},
+{"name": "aaron newell"},
+{"name": "beth carrick"},
+{"name": "joshua sims"},
+{"name": "arielle sobel"},
+{"name": "jeff manchan"},
+{"name": "sue kuchinski"},
+{"name": "steve kearns"},
+{"name": "james stanger"},
+{"name": "julie moreau"},
+{"name": "louise berleth"},
+{"name": "kevin lam"},
+{"name": "jeffrey mark"},
+{"name": "josh clifton"},
+{"name": "randy facey"},
+{"name": "brant jones"},
+{"name": "deidra lyod"},
+{"name": "christeen barbalic"},
+{"name": "jerry carinci"},
+{"name": "mike gregorio"},
+{"name": "terry sisco"},
+{"name": "elizabeth gilmore"},
+{"name": "laura vega"},
+{"name": "steve geno"},
+{"name": "mariah connolly"},
+{"name": "gerald ito"},
+{"name": "jamie saylor"},
+{"name": "dave dobkin"},
+{"name": "todd bennett"},
+{"name": "mary e"},
+{"name": "marcie wood"},
+{"name": "tony lucero"},
+{"name": "cris bahar"},
+{"name": "louie martinez"},
+{"name": "cecilia bueso"},
+{"name": "carlee bator"},
+{"name": "cheryl rental"},
+{"name": "alvin dayday"},
+{"name": "randy eichorn"},
+{"name": "georgia meyer"},
+{"name": "candy tessmann"},
+{"name": "brian carrol"},
+{"name": "nancy werner"},
+{"name": "mike cable"},
+{"name": "rich haight"},
+{"name": "michael tv"},
+{"name": "gerry bauman"},
+{"name": "dave sorenson"},
+{"name": "rich ferera"},
+{"name": "lee fish"},
+{"name": "mary argimon"},
+{"name": "elizabeth deyoung"},
+{"name": "jake s"},
+{"name": "mitzi moore"},
+{"name": "bruce patterson"},
+{"name": "paul silvestri"},
+{"name": "brad langley"},
+{"name": "andy scott"},
+{"name": "lisa hoffman"},
+{"name": "angela garner"},
+{"name": "berry muninger"},
+{"name": "richard evans"},
+{"name": "linda beach"},
+{"name": "boris shimanovsky"},
+{"name": "quyen du"},
+{"name": "william kozachuk"},
+{"name": "kevin bates"},
+{"name": "lloyd bean"},
+{"name": "lita giraldi"},
+{"name": "charity bishop"},
+{"name": "wendi fast"},
+{"name": "alisha norfus"},
+{"name": "stephanie robbins"},
+{"name": "harry kendal"},
+{"name": "gregory roby"},
+{"name": "chris colpaert"},
+{"name": "rob frederick"},
+{"name": "john naitoh"},
+{"name": "brett link"},
+{"name": "sandra sahouria"},
+{"name": "kenneth kelman"},
+{"name": "galen palmer"},
+{"name": "ralph antitomoso"},
+{"name": "dan hefner"},
+{"name": "april cheney"},
+{"name": "greg cooper"},
+{"name": "sean martin"},
+{"name": "jeff goodwin"},
+{"name": "ross safko"},
+{"name": "dan brennan"},
+{"name": "gina nave"},
+{"name": "michael giles"},
+{"name": "josh randell"},
+{"name": "kris johnson"},
+{"name": "brad slaybaugh"},
+{"name": "andrea dr"},
+{"name": "paul witko"},
+{"name": "herman kwan"},
+{"name": "charlie rook"},
+{"name": "john dorcas"},
+{"name": "dorothy rowson"},
+{"name": "roger nelson"},
+{"name": "kevin steele"},
+{"name": "shane courtney"},
+{"name": "sheila spence"},
+{"name": "dara tapout"},
+{"name": "janice burke"},
+{"name": "avery weiner"},
+{"name": "matt urban"},
+{"name": "burt wallace"},
+{"name": "chris villenueva"},
+{"name": "tony ketcham"},
+{"name": "trevor darnell"},
+{"name": "ray malphrus"},
+{"name": "debby w"},
+{"name": "yolanda mata"},
+{"name": "will jason"},
+{"name": "will nicol"},
+{"name": "joe pence"},
+{"name": "mark seavy"},
+{"name": "willie taylor"},
+{"name": "mike yates"},
+{"name": "rebecca flemming"},
+{"name": "kenny stanley"},
+{"name": "marco andrettii"},
+{"name": "king david"},
+{"name": "katie monsees"},
+{"name": "ava swendseid"},
+{"name": "carol boyd"},
+{"name": "michael cherry"},
+{"name": "jessica bp"},
+{"name": "justin dx"},
+{"name": "jim lopez"},
+{"name": "cassie viallpando"},
+{"name": "christa lofquist"},
+{"name": "victor oritz"},
+{"name": "harry baer"},
+{"name": "tamara crowley"},
+{"name": "darwin hathorn"},
+{"name": "bruno guez"},
+{"name": "rob esmonde"},
+{"name": "toni caldas"},
+{"name": "tia cata"},
+{"name": "mary bridges"},
+{"name": "quentin duan"},
+{"name": "joel srodes"},
+{"name": "tina nabseth"},
+{"name": "darrin mell"},
+{"name": "tyler radtke"},
+{"name": "doug buell"},
+{"name": "cathleen lawler"},
+{"name": "michael george"},
+{"name": "jim meaney"},
+{"name": "jared jones"},
+{"name": "pat barry"},
+{"name": "brian koontz"},
+{"name": "ryan ec"},
+{"name": "dave barranti"},
+{"name": "lou karakas"},
+{"name": "marcus polk"},
+{"name": "robin holbrook"},
+{"name": "jimmy zan"},
+{"name": "linda potter"},
+{"name": "danny boutros"},
+{"name": "wes hazlett"},
+{"name": "beverly burrell"},
+{"name": "jc penney"},
+{"name": "alexandra halalau"},
+{"name": "aaron unger"},
+{"name": "herb kunz"},
+{"name": "jim moff"},
+{"name": "nathan griff"},
+{"name": "andrea budisak"},
+{"name": "jaime bayntun"},
+{"name": "stuart stribling"},
+{"name": "jim reily"},
+{"name": "christian seaman"},
+{"name": "mohammed besharah"},
+{"name": "jason garti"},
+{"name": "fernando barrajas"},
+{"name": "brian caldeira"},
+{"name": "tara nultemeier"},
+{"name": "tony davidson"},
+{"name": "heather walls"},
+{"name": "robert keller"},
+{"name": "mike prine"},
+{"name": "sondra hoosier"},
+{"name": "selma cemetery"},
+{"name": "nathan hooper"},
+{"name": "don chargin"},
+{"name": "robin peterson"},
+{"name": "phil carter"},
+{"name": "kristi harvey"},
+{"name": "douglas auto"},
+{"name": "bill blixt"},
+{"name": "trina sanchez"},
+{"name": "jason clayson"},
+{"name": "wayne porter"},
+{"name": "awilda caban"},
+{"name": "mike cooney"},
+{"name": "wayne justice"},
+{"name": "antonio tmobile"},
+{"name": "drew davis"},
+{"name": "mike grisham"},
+{"name": "scott darling"},
+{"name": "terrence crampton"},
+{"name": "shannon kerrigan"},
+{"name": "george warner"},
+{"name": "christopher vilchez"},
+{"name": "brian boyd"},
+{"name": "jeff rubin"},
+{"name": "herb rochlin"},
+{"name": "anthony campout"},
+{"name": "ben olsen"},
+{"name": "asia hauter"},
+{"name": "susan wellenkamp"},
+{"name": "becky ulmer"},
+{"name": "freddy guard"},
+{"name": "doug cunningham"},
+{"name": "kris persson"},
+{"name": "joe miles"},
+{"name": "tim schaaff"},
+{"name": "jessie mendez"},
+{"name": "greg gilmore"},
+{"name": "ariana chaung"},
+{"name": "pete disilvio"},
+{"name": "tom harris"},
+{"name": "sean iverson"},
+{"name": "mary sibley"},
+{"name": "linda cote"},
+{"name": "luke bryan"},
+{"name": "danielle onstot"},
+{"name": "brian kirschner"},
+{"name": "nathaniel washington"},
+{"name": "mary aguilar"},
+{"name": "jack box"},
+{"name": "jimmy kittleson"},
+{"name": "taylor anderson"},
+{"name": "jeffrey ostrander"},
+{"name": "gary joffe"},
+{"name": "norma aguilar"},
+{"name": "eugene boyfriend"},
+{"name": "adam msg"},
+{"name": "drew grunwald"},
+{"name": "tony woodworth"},
+{"name": "ryan maddock"},
+{"name": "norman davidson"},
+{"name": "jeff dehn"},
+{"name": "barry funkhouser"},
+{"name": "charlie edwards"},
+{"name": "greg cal"},
+{"name": "anthony matis"},
+{"name": "charlie cubillo"},
+{"name": "tom stornelli"},
+{"name": "ed dragon"},
+{"name": "rick parker"},
+{"name": "robert romanek"},
+{"name": "louis theriault"},
+{"name": "ed manansala"},
+{"name": "karen home"},
+{"name": "liz sloan"},
+{"name": "robert pilgrim"},
+{"name": "mark rishniw"},
+{"name": "claude vachet"},
+{"name": "diane shafer"},
+{"name": "julia tenser"},
+{"name": "dan keats"},
+{"name": "alan hinson"},
+{"name": "joe onstott"},
+{"name": "omar fl"},
+{"name": "marian liu"},
+{"name": "john lombardi"},
+{"name": "chris zappavigna"},
+{"name": "joye fuston"},
+{"name": "will sheive"},
+{"name": "michel bornacelli"},
+{"name": "elizabeth kocur"},
+{"name": "octavio herrera"},
+{"name": "josh kokomo"},
+{"name": "ashley a"},
+{"name": "rob schroder"},
+{"name": "jon biggins"},
+{"name": "jay schelt"},
+{"name": "misty anguiano"},
+{"name": "van moore"},
+{"name": "dwight merriman"},
+{"name": "stan sherry"},
+{"name": "kyle sephton"},
+{"name": "wes chambliss"},
+{"name": "joe lipera"},
+{"name": "jason garland"},
+{"name": "stephen seidel"},
+{"name": "freddy gillespie"},
+{"name": "jeff sumpter"},
+{"name": "chris moreno"},
+{"name": "joey menousek"},
+{"name": "kellie mudgett"},
+{"name": "paul watco"},
+{"name": "jaimie finley"},
+{"name": "shelly meetup"},
+{"name": "rick beaulieu"},
+{"name": "pete lacko"},
+{"name": "jeff mosley"},
+{"name": "doug french"},
+{"name": "melody adams"},
+{"name": "chris espino"},
+{"name": "don warren"},
+{"name": "ashley lee"},
+{"name": "laura bowen"},
+{"name": "ashley willing"},
+{"name": "paul kerwin"},
+{"name": "martha katz"},
+{"name": "brenda gonzalez"},
+{"name": "liz carson"},
+{"name": "danny andres"},
+{"name": "jess jay"},
+{"name": "nicole macedonia"},
+{"name": "ron deramus"},
+{"name": "jill hintz"},
+{"name": "stuart bull"},
+{"name": "tom henke"},
+{"name": "lou dixon"},
+{"name": "larry flax"},
+{"name": "cindy pan"},
+{"name": "cynthia dutra"},
+{"name": "christine matheney"},
+{"name": "eric hawkins"},
+{"name": "laurel brinkman"},
+{"name": "jerry melisaratos"},
+{"name": "nick tracy"},
+{"name": "jim krejci"},
+{"name": "kieth lee"},
+{"name": "bonnie mcgraw"},
+{"name": "john schiebelhoffer"},
+{"name": "caleb gideon"},
+{"name": "doug lingner"},
+{"name": "carolyn mann"},
+{"name": "george woodall"},
+{"name": "christopher visick"},
+{"name": "joe wetzel"},
+{"name": "jade daniels"},
+{"name": "allison briggs"},
+{"name": "anne merzel"},
+{"name": "richard marken"},
+{"name": "blaine p"},
+{"name": "chuck buggs"},
+{"name": "joel linzner"},
+{"name": "donna monte"},
+{"name": "doug doggett"},
+{"name": "kim carey"},
+{"name": "wiley richard"},
+{"name": "todd cates"},
+{"name": "chris newell"},
+{"name": "kim vanmolle"},
+{"name": "robert kellner"},
+{"name": "andy nimo"},
+{"name": "howard render"},
+{"name": "rachel cl"},
+{"name": "jenny laundry"},
+{"name": "curtis linnel"},
+{"name": "heide forsythe"},
+{"name": "bernie brown"},
+{"name": "dave roper"},
+{"name": "randy pesklewis"},
+{"name": "angela spears"},
+{"name": "andrea lanier"},
+{"name": "wilson lighting"},
+{"name": "karen schuman"},
+{"name": "mike leedle"},
+{"name": "sharon drew"},
+{"name": "fred lidskog"},
+{"name": "michael quinton"},
+{"name": "marlene rouleau"},
+{"name": "jim manker"},
+{"name": "lisa feiga"},
+{"name": "scott vick"},
+{"name": "eric newman"},
+{"name": "ali florian"},
+{"name": "suzi verizon"},
+{"name": "emily m"},
+{"name": "glenn robbins"},
+{"name": "ann baer"},
+{"name": "steve concept"},
+{"name": "jennifer borg"},
+{"name": "tai nahm"},
+{"name": "william costabile"},
+{"name": "rob hache"},
+{"name": "russell anderson"},
+{"name": "ta staff"},
+{"name": "jerry nielsen"},
+{"name": "rich anderson"},
+{"name": "curt fry"},
+{"name": "ray helen"},
+{"name": "cortney white"},
+{"name": "matt odgers"},
+{"name": "bobby lillo"},
+{"name": "fred tempes"},
+{"name": "kasandra gabrie"},
+{"name": "evan ithaca"},
+{"name": "ben lang"},
+{"name": "emilio diaz"},
+{"name": "robert zapata"},
+{"name": "mario carbajal"},
+{"name": "joanna tennis"},
+{"name": "eddy alexander"},
+{"name": "cathleen sward"},
+{"name": "matthew johnston"},
+{"name": "carolyn acri"},
+{"name": "daria hall"},
+{"name": "beth carboni"},
+{"name": "phil berger"},
+{"name": "dave weber"},
+{"name": "diane phlume"},
+{"name": "kim krieg"},
+{"name": "rose merrit"},
+{"name": "alberto painter"},
+{"name": "april wyatt"},
+{"name": "lizzette strickland"},
+{"name": "nick berry"},
+{"name": "mary hogan"},
+{"name": "tom rainwater"},
+{"name": "sherrie mcallister"},
+{"name": "matt laws"},
+{"name": "sandy banks"},
+{"name": "nick christodoulou"},
+{"name": "vincent lotano"},
+{"name": "evelyn jones"},
+{"name": "cheryl frymire"},
+{"name": "nick milovich"},
+{"name": "beth vansant"},
+{"name": "wayne campbell"},
+{"name": "brad davis"},
+{"name": "david sperry"},
+{"name": "brett scott"},
+{"name": "debbie mathews"},
+{"name": "alex spence"},
+{"name": "michael laboone"},
+{"name": "bill sabo"},
+{"name": "amanda kalil"},
+{"name": "michael halloren"},
+{"name": "ann speight"},
+{"name": "katie kindley"},
+{"name": "lorenzo north"},
+{"name": "heidi blair"},
+{"name": "stephanie selby"},
+{"name": "jenny retundie"},
+{"name": "jackson corneleous"},
+{"name": "lloyd boone"},
+{"name": "beverly mayo"},
+{"name": "dave feygin"},
+{"name": "tony whitfield"},
+{"name": "kerry nicholson"},
+{"name": "lindsay koren"},
+{"name": "chuck tinder"},
+{"name": "rachel hammel"},
+{"name": "ingrid woods"},
+{"name": "michele kimbrough"},
+{"name": "ryan movie"},
+{"name": "hilary jacoway"},
+{"name": "ben burke"},
+{"name": "lisa benson"},
+{"name": "michelle urias"},
+{"name": "darren hawkins"},
+{"name": "jamie koll"},
+{"name": "richard hamermesh"},
+{"name": "nicole l"},
+{"name": "blair ford"},
+{"name": "garth voplanansky"},
+{"name": "bridget potter"},
+{"name": "elaine hund"},
+{"name": "justin lindsey"},
+{"name": "bruce whittig"},
+{"name": "eva penner"},
+{"name": "judy mcguire"},
+{"name": "josh felton"},
+{"name": "edward houston"},
+{"name": "dan lawson"},
+{"name": "greg g"},
+{"name": "jen lo"},
+{"name": "bo murray"},
+{"name": "rebecca butner"},
+{"name": "ed evans"},
+{"name": "jared bennington"},
+{"name": "darren merli"},
+{"name": "jessica deutsch"},
+{"name": "paul keys"},
+{"name": "jean edwards"},
+{"name": "david lim"},
+{"name": "rita k"},
+{"name": "rafael rosado"},
+{"name": "ryan floor"},
+{"name": "tom murray"},
+{"name": "neil schubert"},
+{"name": "robert layne"},
+{"name": "sheryl phung"},
+{"name": "tara strickwerda"},
+{"name": "scott silverstein"},
+{"name": "amanda carpenter"},
+{"name": "mattie blake"},
+{"name": "amber mahoney"},
+{"name": "sheldon greenspan"},
+{"name": "joel brovont"},
+{"name": "kami nogo"},
+{"name": "jerald shetty"},
+{"name": "kathy knaf"},
+{"name": "teresa snyder"},
+{"name": "phil babbit"},
+{"name": "linda stevens"},
+{"name": "vanessa becerra"},
+{"name": "ricky hawkins"},
+{"name": "sandra macdonald"},
+{"name": "adriane thomas"},
+{"name": "gary mason"},
+{"name": "cody mg"},
+{"name": "gary so"},
+{"name": "les lambert"},
+{"name": "nolan rollins"},
+{"name": "tia martha"},
+{"name": "lisa mellick"},
+{"name": "barry witz"},
+{"name": "erin sullivan"},
+{"name": "jeff gale"},
+{"name": "alex mesas"},
+{"name": "britany pope"},
+{"name": "susan mysp"},
+{"name": "stacey siegel"},
+{"name": "dave kautz"},
+{"name": "emma wallace"},
+{"name": "sheena khemaney"},
+{"name": "tim kite"},
+{"name": "jonathan goss"},
+{"name": "christian melendez"},
+{"name": "cindy ford"},
+{"name": "debbie barnes"},
+{"name": "james hibert"},
+{"name": "lacey darnell"},
+{"name": "courtney boucher"},
+{"name": "kala adame"},
+{"name": "brian konona"},
+{"name": "mason slaine"},
+{"name": "joe b"},
+{"name": "barbara major"},
+{"name": "david chapman"},
+{"name": "aaron westover"},
+{"name": "amy bernheisel"},
+{"name": "larissa moorenweiser"},
+{"name": "dorothy robinson"},
+{"name": "eric weinstein"},
+{"name": "rick bain"},
+{"name": "lacey lyman"},
+{"name": "jorge padron"},
+{"name": "gary lewis"},
+{"name": "nick caterino"},
+{"name": "nick sovereign"},
+{"name": "joey cell"},
+{"name": "marcus outlaw"},
+{"name": "junior achievement"},
+{"name": "ray potts"},
+{"name": "jim house"},
+{"name": "doug kalbaugh"},
+{"name": "lore rodriquez"},
+{"name": "jill healy"},
+{"name": "gina rodriguez"},
+{"name": "lauren dz"},
+{"name": "jefferson pierre"},
+{"name": "rich jarv"},
+{"name": "tod town"},
+{"name": "billy stone"},
+{"name": "david delgado"},
+{"name": "michael litwin"},
+{"name": "scott corrales"},
+{"name": "ray hancock"},
+{"name": "brian angel"},
+{"name": "frank follemer"},
+{"name": "lauren turton"},
+{"name": "jay groves"},
+{"name": "amber jacobson"},
+{"name": "brooke hogan"},
+{"name": "jordan blake"},
+{"name": "rebecca quinn"},
+{"name": "jean cole"},
+{"name": "don cahalan"},
+{"name": "kim rooney"},
+{"name": "ginger smith"},
+{"name": "maureen mcgrath"},
+{"name": "ken robertson"},
+{"name": "michelle reyes"},
+{"name": "benjamin conway"},
+{"name": "dave hunter"},
+{"name": "lila leopoldo"},
+{"name": "alex fullerton"},
+{"name": "lawrence bonin"},
+{"name": "ethyl home"},
+{"name": "arnold labatete"},
+{"name": "megan provost"},
+{"name": "darrell jacobson"},
+{"name": "anthony alcala"},
+{"name": "greg sanford"},
+{"name": "brendan snodgrass"},
+{"name": "jared katz"},
+{"name": "bob mason"},
+{"name": "carl pierce"},
+{"name": "dave hamlin"},
+{"name": "crystal anderson"},
+{"name": "van every"},
+{"name": "wendy sykes"},
+{"name": "tommy elec"},
+{"name": "nancy satur"},
+{"name": "keena snare"},
+{"name": "jaime diaz"},
+{"name": "jerry ng"},
+{"name": "matt o'brien"},
+{"name": "gale chadwick"},
+{"name": "ted porcetta"},
+{"name": "andy brown"},
+{"name": "tom tierney"},
+{"name": "matt swann"},
+{"name": "vicki penrose"},
+{"name": "ross chapel"},
+{"name": "alyssa schaffer"},
+{"name": "derek jackman"},
+{"name": "andy krites"},
+{"name": "nick boucher"},
+{"name": "jenni hale"},
+{"name": "randy specht"},
+{"name": "lawrence sr"},
+{"name": "katie hennis"},
+{"name": "jackson hewitt"},
+{"name": "ben desmond"},
+{"name": "andre orejel"},
+{"name": "pat dicapo"},
+{"name": "gwen simpson"},
+{"name": "justin rottger"},
+{"name": "howard delfranco"},
+{"name": "joel dylhoff"},
+{"name": "gary marr"},
+{"name": "andrea clements"},
+{"name": "melissa b"},
+{"name": "patrick dunagan"},
+{"name": "lindsey murphy"},
+{"name": "linda cannon"},
+{"name": "jared carlton"},
+{"name": "debbie macomber"},
+{"name": "steve messina"},
+{"name": "valerie pinto"},
+{"name": "enrique escalante"},
+{"name": "renee kinler"},
+{"name": "mike trexler"},
+{"name": "alma corla"},
+{"name": "terry hill"},
+{"name": "diego garcia"},
+{"name": "sterling white"},
+{"name": "sandi home"},
+{"name": "renae bass"},
+{"name": "robert fabbricatore"},
+{"name": "greg skalaski"},
+{"name": "abram ngyuen"},
+{"name": "andrew aun"},
+{"name": "lillian house"},
+{"name": "dee toal"},
+{"name": "kenneth lucas"},
+{"name": "vera cell"},
+{"name": "steve levin"},
+{"name": "brian trapeno"},
+{"name": "jim vitucci"},
+{"name": "elise samuels"},
+{"name": "frank hicks"},
+{"name": "winston wright"},
+{"name": "dick edwards"},
+{"name": "fred pictures"},
+{"name": "sarah mcmanus"},
+{"name": "kevin fechtmeyer"},
+{"name": "tyler hoffman"},
+{"name": "troy caupain"},
+{"name": "natalie mackey"},
+{"name": "blake edwards"},
+{"name": "ty eldridge"},
+{"name": "johnny rae"},
+{"name": "ron ritter"},
+{"name": "felipe ruiz"},
+{"name": "jeremy appel"},
+{"name": "phillip renouf"},
+{"name": "chad krill"},
+{"name": "kris boustedt"},
+{"name": "chris pictus"},
+{"name": "stacey hill"},
+{"name": "amber klino"},
+{"name": "jordan freshwater"},
+{"name": "jill staci"},
+{"name": "martin wallace"},
+{"name": "john mein"},
+{"name": "tom dent"},
+{"name": "charlene fletcher"},
+{"name": "jim altschwager"},
+{"name": "orlando zapata"},
+{"name": "deb brattelli"},
+{"name": "whitney flake"},
+{"name": "scott vegas"},
+{"name": "anthony moreno"},
+{"name": "china malay"},
+{"name": "ken rubin"},
+{"name": "alex cefalu"},
+{"name": "kelsey shearer"},
+{"name": "tony costa"},
+{"name": "ruben newell"},
+{"name": "eric stansby"},
+{"name": "tommy vaughan"},
+{"name": "pete o'grady"},
+{"name": "doug newbury"},
+{"name": "mary weathers"},
+{"name": "joel griese"},
+{"name": "ronald mcclean"},
+{"name": "scott mcnair"},
+{"name": "matt tedrow"},
+{"name": "warren booker"},
+{"name": "frank bender"},
+{"name": "rob gibbons"},
+{"name": "karen ferguson"},
+{"name": "anthony dibona"},
+{"name": "jim watters"},
+{"name": "kelsey cell"},
+{"name": "kris cantrell"},
+{"name": "abraham ordover"},
+{"name": "jack wignall"},
+{"name": "fe guda"},
+{"name": "mark zimerfeld"},
+{"name": "terrance smalls"},
+{"name": "roland brimley"},
+{"name": "raymond tsai"},
+{"name": "jessie jamison"},
+{"name": "john verciglio"},
+{"name": "steve calhoun"},
+{"name": "james leslie"},
+{"name": "david godfrey"},
+{"name": "justin girard"},
+{"name": "paula hattley"},
+{"name": "miss adams"},
+{"name": "jeannie steller"},
+{"name": "paul salem"},
+{"name": "gertrud douglas"},
+{"name": "tom chavez"},
+{"name": "erika jeske"},
+{"name": "clyde o'dell"},
+{"name": "roy wilson"},
+{"name": "joe stannard"},
+{"name": "terry drummer"},
+{"name": "tim irwin"},
+{"name": "dustin frost"},
+{"name": "becky petross"},
+{"name": "rochelle gales"},
+{"name": "christina sanchez"},
+{"name": "scott piner"},
+{"name": "bob moczydlowsky"},
+{"name": "whitney david"},
+{"name": "lola longoria"},
+{"name": "danny miller"},
+{"name": "kevin olcott"},
+{"name": "anthony durkacz"},
+{"name": "katie nye"},
+{"name": "matt ganier"},
+{"name": "preston magnus"},
+{"name": "gina troung"},
+{"name": "james maculuso"},
+{"name": "judy eddington"},
+{"name": "marc padilla"},
+{"name": "susan mcmasters"},
+{"name": "william sweeney"},
+{"name": "tammy yuen"},
+{"name": "joe maleski"},
+{"name": "mary huang"},
+{"name": "chris flanagan"},
+{"name": "johnny mo"},
+{"name": "gladys murphy"},
+{"name": "dave desisto"},
+{"name": "patrick mckemy"},
+{"name": "erica alexander"},
+{"name": "terry paster"},
+{"name": "david werp"},
+{"name": "john humpres"},
+{"name": "robin caldera"},
+{"name": "kristi nash"},
+{"name": "rick pitrowski"},
+{"name": "yan tsirklin"},
+{"name": "sean cohen"},
+{"name": "debra yang"},
+{"name": "jordan filip"},
+{"name": "rick salinas"},
+{"name": "joey mills"},
+{"name": "ann walker"},
+{"name": "susie parrent"},
+{"name": "jason reeve"},
+{"name": "adrian velasco"},
+{"name": "brian doubt"},
+{"name": "sheila morris"},
+{"name": "stacy brown"},
+{"name": "rob hoffman"},
+{"name": "jack shields"},
+{"name": "edith drazek"},
+{"name": "samuel kabue"},
+{"name": "don purdy"},
+{"name": "sierra bartz"},
+{"name": "debbie wiley"},
+{"name": "bob bostain"},
+{"name": "bryce richardson"},
+{"name": "mark slivovsky"},
+{"name": "bobbie harris"},
+{"name": "verona hendricks"},
+{"name": "alice whitley"},
+{"name": "susan bartlett"},
+{"name": "philip tang"},
+{"name": "troy kilbourne"},
+{"name": "zack brown"},
+{"name": "luz cars"},
+{"name": "chris haan"},
+{"name": "bee bauerly"},
+{"name": "sandra bryan"},
+{"name": "amber mandel"},
+{"name": "hector botello"},
+{"name": "debbie manguerten"},
+{"name": "nicole miller"},
+{"name": "belinda g"},
+{"name": "steve chestnut"},
+{"name": "michael dicosola"},
+{"name": "cody shoultz"},
+{"name": "dominique minor"},
+{"name": "scott kimmy"},
+{"name": "erica parker"},
+{"name": "jim derkatch"},
+{"name": "jim trussell"},
+{"name": "mike winter"},
+{"name": "julius damato"},
+{"name": "katie villars"},
+{"name": "debbie rodin"},
+{"name": "marylou vachon"},
+{"name": "steve karlovsky"},
+{"name": "niki tailgaters"},
+{"name": "julia thomson"},
+{"name": "rebecca nielsen"},
+{"name": "anthony asenjo"},
+{"name": "renee munson"},
+{"name": "marcos dlh"},
+{"name": "chris kern"},
+{"name": "walker freddy"},
+{"name": "sandra aviles"},
+{"name": "lori bing"},
+{"name": "errol lawrence"},
+{"name": "sebastian palazzo"},
+{"name": "lindsay mals"},
+{"name": "brandon woodfield"},
+{"name": "kevin fitzpatrick"},
+{"name": "juan bro"},
+{"name": "sarah carper"},
+{"name": "pa graham"},
+{"name": "brad engle"},
+{"name": "laura goetz"},
+{"name": "jennifer melreit"},
+{"name": "john mushman"},
+{"name": "gustavo flores"},
+{"name": "jeff carver"},
+{"name": "marty woznicki"},
+{"name": "kim collum"},
+{"name": "elizabeth taylor"},
+{"name": "dan mottaz"},
+{"name": "andrew nova"},
+{"name": "chris washington"},
+{"name": "allen wong"},
+{"name": "lupe ward"},
+{"name": "shari thornton"},
+{"name": "marcus hacker"},
+{"name": "bryce isackson"},
+{"name": "david gage"},
+{"name": "john lemeux"},
+{"name": "jorge h"},
+{"name": "terrell bell"},
+{"name": "john geresi"},
+{"name": "carter mechanical"},
+{"name": "bryan ross"},
+{"name": "veronica dinkins"},
+{"name": "christine mcconnell"},
+{"name": "steve wag"},
+{"name": "diamond furniture"},
+{"name": "virginia jones"},
+{"name": "ashlie welte"},
+{"name": "carlos soto"},
+{"name": "jamie mack"},
+{"name": "sarah grosz"},
+{"name": "lauren licata"},
+{"name": "vaughn z"},
+{"name": "chuck sprint"},
+{"name": "jordan wong"},
+{"name": "ben redflecks"},
+{"name": "sharon ucsb"},
+{"name": "melissa sam"},
+{"name": "alma posada"},
+{"name": "kim crawford"},
+{"name": "sean webb"},
+{"name": "jeff bakst"},
+{"name": "xiao lie"},
+{"name": "anthony martwick"},
+{"name": "craig fitzpatrick"},
+{"name": "david zahn"},
+{"name": "adrian hoaghia"},
+{"name": "ed brycon"},
+{"name": "dale dungan"},
+{"name": "erica margolius"},
+{"name": "shad kari"},
+{"name": "john rosenthal"},
+{"name": "brian deacon"},
+{"name": "rodney bennett"},
+{"name": "jenny lynn"},
+{"name": "damian mcelgunn"},
+{"name": "desire thomas"},
+{"name": "sean duval"},
+{"name": "jason jurusz"},
+{"name": "sharon zearfoss"},
+{"name": "keith ogle"},
+{"name": "keith savoy"},
+{"name": "mary lowery"},
+{"name": "christopher pagel"},
+{"name": "pat soloman"},
+{"name": "kara g"},
+{"name": "john chinen"},
+{"name": "paul yowhan"},
+{"name": "anne michaels"},
+{"name": "jill lick"},
+{"name": "gerry kennedy"},
+{"name": "nicole oliver"},
+{"name": "ken beatty"},
+{"name": "doug herron"},
+{"name": "alexander nacho"},
+{"name": "susannah kettenring"},
+{"name": "travis bbm"},
+{"name": "veronica murray"},
+{"name": "bob white"},
+{"name": "joanna guetter"},
+{"name": "michelle gold"},
+{"name": "bradford barnes"},
+{"name": "carlton steele"},
+{"name": "valerie cronin"},
+{"name": "rick stafford"},
+{"name": "sheila holeman"},
+{"name": "deb pashley"},
+{"name": "bill mcgowen"},
+{"name": "eric danzeisen"},
+{"name": "shaun sequeira"},
+{"name": "elyse degen"},
+{"name": "paul philpot"},
+{"name": "susan beale"},
+{"name": "christie benner"},
+{"name": "donna belgram"},
+{"name": "benjamin scott"},
+{"name": "shannon nicholson"},
+{"name": "anne papowski"},
+{"name": "randy chu"},
+{"name": "fe fe"},
+{"name": "joelle reed"},
+{"name": "dan maloney"},
+{"name": "bryan gautie"},
+{"name": "darrell whitman"},
+{"name": "anna p"},
+{"name": "kevin frat"},
+{"name": "ira tyszler"},
+{"name": "tad fies"},
+{"name": "lindsay irwin"},
+{"name": "bryan dana"},
+{"name": "william marsh"},
+{"name": "alan wright"},
+{"name": "paul laporte"},
+{"name": "steve blum"},
+{"name": "christina dude"},
+{"name": "nikki braxmeier"},
+{"name": "rex speelman"},
+{"name": "shelby amos"},
+{"name": "helen willink"},
+{"name": "richard nalick"},
+{"name": "corie stewart"},
+{"name": "greg gibby"},
+{"name": "marci reichart"},
+{"name": "matt gates"},
+{"name": "pat jungels"},
+{"name": "chelsie sousa"},
+{"name": "jack yuan"},
+{"name": "ernie colacion"},
+{"name": "dave kornfield"},
+{"name": "tom peacock"},
+{"name": "kristin williams"},
+{"name": "diane vallejo"},
+{"name": "skye cannel{v}"},
+{"name": "jean walters"},
+{"name": "mike irwin"},
+{"name": "sara jarvis"},
+{"name": "trish rawlake"},
+{"name": "jeff hudgins"},
+{"name": "paul birch"},
+{"name": "candice ivey"},
+{"name": "aaron nunez"},
+{"name": "robert viney"},
+{"name": "josh sampson"},
+{"name": "jaclyn bedinelli"},
+{"name": "mark zorensky"},
+{"name": "brittany verkler"},
+{"name": "alex jarvis"},
+{"name": "jim bonds"},
+{"name": "justin johns"},
+{"name": "clint hicks"},
+{"name": "jerry hindes"},
+{"name": "joey samson"},
+{"name": "jeremy barber"},
+{"name": "patrick cullara"},
+{"name": "darin morris"},
+{"name": "cari borja"},
+{"name": "chris keen"},
+{"name": "deb dulsky"},
+{"name": "joshua webb"},
+{"name": "toni lowery"},
+{"name": "mavis brown"},
+{"name": "greg johns"},
+{"name": "matthew goodwin"},
+{"name": "ann house"},
+{"name": "mike halbig"},
+{"name": "terry a"},
+{"name": "les syren"},
+{"name": "tiffany cappel"},
+{"name": "andrew carrigan"},
+{"name": "steve gowen"},
+{"name": "greg mcmahon"},
+{"name": "mike rhodes"},
+{"name": "nick muffintop"},
+{"name": "jennifer george"},
+{"name": "corey chico"},
+{"name": "charles vanmiddlesworth"},
+{"name": "mark samuels"},
+{"name": "jennifer lesmeister"},
+{"name": "marilyn lieberman"},
+{"name": "lane cook"},
+{"name": "chris ami"},
+{"name": "michael russano"},
+{"name": "brenda rodriguez"},
+{"name": "mike gray"},
+{"name": "clay halverson"},
+{"name": "hector jimenez"},
+{"name": "diego brenes"},
+{"name": "lacey green"},
+{"name": "stephen soper"},
+{"name": "fran brus"},
+{"name": "archie hayley"},
+{"name": "tyler houston"},
+{"name": "norman chui"},
+{"name": "anita mukerji"},
+{"name": "bill lang"},
+{"name": "chris holmes"},
+{"name": "briana hart"},
+{"name": "stuart kaswell"},
+{"name": "sha kim"},
+{"name": "justin thigpen"},
+{"name": "shawn loussia"},
+{"name": "debbie glenn"},
+{"name": "andrea email"},
+{"name": "edison coach"},
+{"name": "al ivey"},
+{"name": "judy romero"},
+{"name": "sally thanhouser"},
+{"name": "nola jones"},
+{"name": "will bateson"},
+{"name": "emanuel prioleau"},
+{"name": "jaime pino"},
+{"name": "paul suburban"},
+{"name": "jaimie pb"},
+{"name": "james barsamian"},
+{"name": "angela iowa"},
+{"name": "melissa rozsa"},
+{"name": "albert moussa"},
+{"name": "joanna smith"},
+{"name": "chelsey degman"},
+{"name": "mark dewey"},
+{"name": "eric mandale"},
+{"name": "scott barnett"},
+{"name": "lisa reinsmith"},
+{"name": "lacey ruzicka"},
+{"name": "mark morley"},
+{"name": "thomas marshall"},
+{"name": "john pelham"},
+{"name": "teresa statue"},
+{"name": "bo jackson"},
+{"name": "michael guest"},
+{"name": "jim arn"},
+{"name": "melissa rich"},
+{"name": "lou andrew"},
+{"name": "stacey taylor"},
+{"name": "don auge"},
+{"name": "kevin kilgore"},
+{"name": "luis castillejos"},
+{"name": "tim kidd"},
+{"name": "richard horwood"},
+{"name": "brad ham"},
+{"name": "jacob pizana"},
+{"name": "lucinda luna"},
+{"name": "cheryl capp"},
+{"name": "lisa d"},
+{"name": "matt george"},
+{"name": "jen salazar"},
+{"name": "rich gerstel"},
+{"name": "todd fox"},
+{"name": "angel r"},
+{"name": "wes goodwin"},
+{"name": "chris applebottom"},
+{"name": "melanie murphy"},
+{"name": "josh schwartz"},
+{"name": "jeff crepeau"},
+{"name": "jay defuria"},
+{"name": "brian starling"},
+{"name": "armando estevan"},
+{"name": "darci tattoo"},
+{"name": "matt piersma"},
+{"name": "sandra kinchen"},
+{"name": "rita cooper"},
+{"name": "heather hall"},
+{"name": "joanne constantin"},
+{"name": "sue shaheen"},
+{"name": "neil patel"},
+{"name": "paul b"},
+{"name": "tammi b"},
+{"name": "art house"},
+{"name": "evelyn ivey"},
+{"name": "tina preciado"},
+{"name": "william dougherty"},
+{"name": "brady hogan"},
+{"name": "ron christensen"},
+{"name": "andrew henderson"},
+{"name": "le martin"},
+{"name": "jeff hall"},
+{"name": "marva doremus"},
+{"name": "shannon oglesby"},
+{"name": "joe wilson"},
+{"name": "bianca yi"},
+{"name": "patrick pline"},
+{"name": "bruce ashe"},
+{"name": "greg gumwood"},
+{"name": "ryan mac"},
+{"name": "ria lacher"},
+{"name": "alicia tangerinegurl"},
+{"name": "mike pyle"},
+{"name": "shannon hardin"},
+{"name": "millie stewart"},
+{"name": "robert lanter"},
+{"name": "greg gates"},
+{"name": "tim furst"},
+{"name": "sam hinton"},
+{"name": "cheryl klass"},
+{"name": "fran price"},
+{"name": "han park"},
+{"name": "kathy elmore"},
+{"name": "joey bakes"},
+{"name": "leo holtort"},
+{"name": "dan henderson"},
+{"name": "alex rinker"},
+{"name": "dani murie"},
+{"name": "kent christman"},
+{"name": "ronald berglund"},
+{"name": "alice david"},
+{"name": "donald robertson"},
+{"name": "matt bridwell"},
+{"name": "michael moore"},
+{"name": "tom kelton"},
+{"name": "monte hammon"},
+{"name": "keith martin"},
+{"name": "james balardi"},
+{"name": "mike best"},
+{"name": "eden lake"},
+{"name": "reagan hyundai"},
+{"name": "dan siroin"},
+{"name": "kayla t"},
+{"name": "kellie willames"},
+{"name": "nancy wangas"},
+{"name": "chris bajdek"},
+{"name": "grant lackey"},
+{"name": "jamie rosmarin"},
+{"name": "doug coons"},
+{"name": "julie gadreau"},
+{"name": "patty reese"},
+{"name": "sean landis"},
+{"name": "jesse corrington"},
+{"name": "gary roth"},
+{"name": "kevin vaughn"},
+{"name": "peter warrick"},
+{"name": "barb atchison"},
+{"name": "brett cappelluti"},
+{"name": "ann harding"},
+{"name": "annette warren"},
+{"name": "bobby cooper"},
+{"name": "han bui"},
+{"name": "mike flannigan"},
+{"name": "yen nguyen"},
+{"name": "nadia afif"},
+{"name": "kayla brown"},
+{"name": "mike jording"},
+{"name": "mathew yohannan"},
+{"name": "mike fish"},
+{"name": "john vu"},
+{"name": "chi ku"},
+{"name": "dan osborne"},
+{"name": "brittney leclerc"},
+{"name": "ivan hood"},
+{"name": "lawrence mann"},
+{"name": "eric forsberg"},
+{"name": "clark woods"},
+{"name": "kyra loveall"},
+{"name": "liz c"},
+{"name": "ami ficken"},
+{"name": "adam moss"},
+{"name": "alex griswl"},
+{"name": "fred soto"},
+{"name": "danica ceballosc"},
+{"name": "wendy cann"},
+{"name": "molly schissler"},
+{"name": "kathy durch"},
+{"name": "steve gebhart"},
+{"name": "richard merlino"},
+{"name": "jeremy walterscheid"},
+{"name": "anthony rogers"},
+{"name": "trish aaron"},
+{"name": "brendon hoellien"},
+{"name": "matt muller"},
+{"name": "candy cannon"},
+{"name": "claudia vero"},
+{"name": "hee chung"},
+{"name": "scott wong"},
+{"name": "mario vegas"},
+{"name": "bonnie stewart"},
+{"name": "lauren parks"},
+{"name": "laurie rood"},
+{"name": "bonnie doherty"},
+{"name": "adam owens"},
+{"name": "tina j"},
+{"name": "katelyn regin"},
+{"name": "vicki newby"},
+{"name": "patrick holland"},
+{"name": "stephanie tvcc"},
+{"name": "brian drosdzal"},
+{"name": "ricky chiu"},
+{"name": "shannon staines"},
+{"name": "meredith burnett"},
+{"name": "jamie weinberg"},
+{"name": "tony sopko"},
+{"name": "jon bassett"},
+{"name": "margaret huling"},
+{"name": "lorraine paur"},
+{"name": "angie orta"},
+{"name": "rick lambeth"},
+{"name": "nancy dufault"},
+{"name": "shawn gilbert"},
+{"name": "kevin leak"},
+{"name": "juan diz"},
+{"name": "chase black"},
+{"name": "samantha balogh"},
+{"name": "janie mcdermott"},
+{"name": "ryan mcds"},
+{"name": "neal mintz"},
+{"name": "steve cully"},
+{"name": "alex reamer"},
+{"name": "sam tcg"},
+{"name": "jay pomales"},
+{"name": "susana moreno"},
+{"name": "james sorbo"},
+{"name": "josh senior"},
+{"name": "john canton"},
+{"name": "george grippo"},
+{"name": "keith hinshaw"},
+{"name": "dan zimmerman"},
+{"name": "morgan irvine"},
+{"name": "cody nunley"},
+{"name": "amy lupo"},
+{"name": "katie partenteau"},
+{"name": "jayson ahlan"},
+{"name": "charles fisher"},
+{"name": "stuart vzv"},
+{"name": "chuck cook"},
+{"name": "yolanda gonzales"},
+{"name": "matt kamont"},
+{"name": "matthew mitchell"},
+{"name": "kelly atkins"},
+{"name": "shawanda mcmillan"},
+{"name": "mary rodriguez"},
+{"name": "william bohannon"},
+{"name": "penny streff"},
+{"name": "cindy harville"},
+{"name": "wilma ginn"},
+{"name": "regina gallon"},
+{"name": "kami johnson"},
+{"name": "alex kumar"},
+{"name": "douglas donald"},
+{"name": "brian ruff"},
+{"name": "todd pate"},
+{"name": "todd burr"},
+{"name": "fred guidi"},
+{"name": "steve biggs"},
+{"name": "latoya p"},
+{"name": "ron mccreless"},
+{"name": "david huerta"},
+{"name": "lindsey jacobs"},
+{"name": "don hershey"},
+{"name": "kara altice"},
+{"name": "jamie w"},
+{"name": "john sweet"},
+{"name": "james sarnecky"},
+{"name": "jim wed"},
+{"name": "kimberly pierre"},
+{"name": "lance tuomey"},
+{"name": "sheryl knight"},
+{"name": "johnny villa"},
+{"name": "paul olson"},
+{"name": "daniel l"},
+{"name": "jesse garza"},
+{"name": "phuong dao"},
+{"name": "jordan massey"},
+{"name": "judy arkin"},
+{"name": "joelle gold"},
+{"name": "lori neugebauer"},
+{"name": "julia baxter"},
+{"name": "dan mehan"},
+{"name": "kyle winter"},
+{"name": "cindy schmid"},
+{"name": "stephanie thomason"},
+{"name": "eric ashline"},
+{"name": "maria ory"},
+{"name": "justin prioleau"},
+{"name": "pat crothers"},
+{"name": "kim hedon"},
+{"name": "damien thomas"},
+{"name": "suzie weldon"},
+{"name": "tim barley"},
+{"name": "ed brooks"},
+{"name": "stephen nestlerode"},
+{"name": "seth greenstein"},
+{"name": "mary bell"},
+{"name": "jessica sams"},
+{"name": "jim oday"},
+{"name": "christine young"},
+{"name": "keri eller"},
+{"name": "marie javier"},
+{"name": "helen adams"},
+{"name": "jack dowlearn"},
+{"name": "david hooper"},
+{"name": "heath massengle"},
+{"name": "katherine freeman"},
+{"name": "donnie pounds"},
+{"name": "kyle lawrence"},
+{"name": "marla watts"},
+{"name": "allie haley"},
+{"name": "diane ford"},
+{"name": "adam hughes"},
+{"name": "laura h"},
+{"name": "amber pellum"},
+{"name": "kurt kinsey"},
+{"name": "brandon hoop"},
+{"name": "tara pavelic"},
+{"name": "stanley landlord"},
+{"name": "eric jimenez"},
+{"name": "tim johnston"},
+{"name": "lorraine o'brein"},
+{"name": "april gebert"},
+{"name": "austin tex"},
+{"name": "paul wisniewski"},
+{"name": "modesto fontanez"},
+{"name": "meghan city"},
+{"name": "don halverson"},
+{"name": "laura rosales"},
+{"name": "leon montgomery"},
+{"name": "mark knoble"},
+{"name": "caitlin dn"},
+{"name": "randall bishir"},
+{"name": "jim rosen"},
+{"name": "carl carter"},
+{"name": "ralph center"},
+{"name": "jackie brownback"},
+{"name": "max gordon"},
+{"name": "randy churnutt"},
+{"name": "joseph chloupek"},
+{"name": "anthony shaw"},
+{"name": "michael kaindl"},
+{"name": "tom gorham"},
+{"name": "tony ballagas"},
+{"name": "art melville"},
+{"name": "janet blackwell"},
+{"name": "heidi licos"},
+{"name": "richard goldhor"},
+{"name": "erin mccarthy"},
+{"name": "jose garma"},
+{"name": "kari kientz"},
+{"name": "steve santangelo"},
+{"name": "dan charboneau"},
+{"name": "herman moore"},
+{"name": "maria ciaravino"},
+{"name": "john gruenberg"},
+{"name": "becky clinard"},
+{"name": "alan boggie"},
+{"name": "cleveland clinic"},
+{"name": "michael wilkinson"},
+{"name": "jim lovegrove"},
+{"name": "michelle pomale"},
+{"name": "joann vallejo"},
+{"name": "jimmy schott"},
+{"name": "todd briere"},
+{"name": "ross jones"},
+{"name": "roland wrinkle"},
+{"name": "rhonda washington"},
+{"name": "gary b"},
+{"name": "ismael lopez"},
+{"name": "mary riggin"},
+{"name": "joseph marigliano"},
+{"name": "jim shelton"},
+{"name": "pam akers"},
+{"name": "nikki ngo"},
+{"name": "scott garrett"},
+{"name": "paul jacobsen"},
+{"name": "orval eshelman"},
+{"name": "shana kirchner"},
+{"name": "stephen {v}"},
+{"name": "steven merkle"},
+{"name": "elyse myers"},
+{"name": "martin botts"},
+{"name": "michael pfau"},
+{"name": "gil penchina"},
+{"name": "ray williams"},
+{"name": "hoa nguyen"},
+{"name": "brian ambrosini"},
+{"name": "bryan breckenridge"},
+{"name": "brian martin"},
+{"name": "john maynard"},
+{"name": "tai do"},
+{"name": "luke grimm"},
+{"name": "mike varrasso"},
+{"name": "alex broz"},
+{"name": "bonnie baker"},
+{"name": "breanna livie"},
+{"name": "jerry snapp"},
+{"name": "larry stevens"},
+{"name": "mark lehrhoff"},
+{"name": "adam stielow"},
+{"name": "kevin kiltz"},
+{"name": "marie sasser"},
+{"name": "brian auckland"},
+{"name": "bobby thomas"},
+{"name": "toya d"},
+{"name": "jean paul"},
+{"name": "damon elsden"},
+{"name": "carrie downstair"},
+{"name": "vera demonte"},
+{"name": "chad kasell"},
+{"name": "gordon beith"},
+{"name": "tyler thomas"},
+{"name": "jeremiah seijo"},
+{"name": "tony z"},
+{"name": "ken connor"},
+{"name": "sarah shay"},
+{"name": "greg grinnell"},
+{"name": "candy busa"},
+{"name": "taylor mcgrew"},
+{"name": "clark domae"},
+{"name": "mike foddrell"},
+{"name": "penny save"},
+{"name": "nena tario"},
+{"name": "melissa linkus"},
+{"name": "carrie peel"},
+{"name": "dee anderson"},
+{"name": "matilde cell"},
+{"name": "rick cinclair"},
+{"name": "diane heyman"},
+{"name": "jim holly"},
+{"name": "keven tolbert"},
+{"name": "ken c"},
+{"name": "michel rashidi"},
+{"name": "victor hertz"},
+{"name": "bill sigler"},
+{"name": "robert gilbert"},
+{"name": "chester holyfield"},
+{"name": "andrea gonzalez"},
+{"name": "jennifer trudel"},
+{"name": "kayla home"},
+{"name": "andy karp"},
+{"name": "elly coleman"},
+{"name": "kurt price"},
+{"name": "bennie nieves"},
+{"name": "david harless"},
+{"name": "jim roush"},
+{"name": "dennis hodgkins"},
+{"name": "sue wadsworth"},
+{"name": "ed ferreira"},
+{"name": "carl reeds"},
+{"name": "tony hitch"},
+{"name": "tim badal"},
+{"name": "brant uncg"},
+{"name": "katie blaker"},
+{"name": "jessica roark"},
+{"name": "mary pang"},
+{"name": "ryan insurance"},
+{"name": "clark drake"},
+{"name": "ken biz"},
+{"name": "tony nelson"},
+{"name": "darryl parham"},
+{"name": "ron feinbaum"},
+{"name": "rhonda f"},
+{"name": "joe balati"},
+{"name": "christopher errington"},
+{"name": "steve diamond"},
+{"name": "jermaine jackson"},
+{"name": "sally chaves"},
+{"name": "derek scholz"},
+{"name": "dale pope"},
+{"name": "artie pascoao"},
+{"name": "andy donnelly"},
+{"name": "sara ross"},
+{"name": "maddie mcsorley"},
+{"name": "jeremy hiebert"},
+{"name": "holly peters"},
+{"name": "frank garcia"},
+{"name": "eric lucas"},
+{"name": "tom conti"},
+{"name": "jason king"},
+{"name": "jason leclair"},
+{"name": "sarah huffman"},
+{"name": "robert woodgate"},
+{"name": "mike feltner"},
+{"name": "elizabeth burns"},
+{"name": "john hewitt"},
+{"name": "bruce burttram"},
+{"name": "cheryl acosta"},
+{"name": "kirstin kananen"},
+{"name": "ricky passions"},
+{"name": "roger huang"},
+{"name": "tom charity"},
+{"name": "john doucett"},
+{"name": "kenny farrell"},
+{"name": "mike eggertsen"},
+{"name": "john crenshaw"},
+{"name": "daisy floral"},
+{"name": "sherry mullen"},
+{"name": "chad evolution"},
+{"name": "rachel beissel"},
+{"name": "matt mcdono"},
+{"name": "sean fxe"},
+{"name": "brian graham"},
+{"name": "steve roth"},
+{"name": "bryce cell"},
+{"name": "emily hibberd"},
+{"name": "jeff nesbitt"},
+{"name": "amanda syers"},
+{"name": "bonnie dean"},
+{"name": "nelda popkey"},
+{"name": "marianela blandon"},
+{"name": "eric marks"},
+{"name": "mike arshambo"},
+{"name": "isiah barse"},
+{"name": "bryan pierce"},
+{"name": "sara boadle"},
+{"name": "jamie patton"},
+{"name": "amy thompson"},
+{"name": "christy caniglia"},
+{"name": "christine kilgore"},
+{"name": "susan summers"},
+{"name": "kimberly ann"},
+{"name": "maria carruyo"},
+{"name": "gary whhite"},
+{"name": "irma bolanos"},
+{"name": "phil collins"},
+{"name": "wally commisso"},
+{"name": "rick mccabe"},
+{"name": "lindy goodling"},
+{"name": "jon ward"},
+{"name": "vincent c"},
+{"name": "fernando lasso"},
+{"name": "les merritt"},
+{"name": "todd devries"},
+{"name": "steven mesita"},
+{"name": "eileen hartwings"},
+{"name": "cory leighton"},
+{"name": "isabella merrill"},
+{"name": "julio cruz"},
+{"name": "bill farmer"},
+{"name": "patrick o'donnell"},
+{"name": "christy gibney"},
+{"name": "betty saff"},
+{"name": "jeanette maracas"},
+{"name": "melanie gleason"},
+{"name": "sherry less"},
+{"name": "mark basso"},
+{"name": "irish thompson"},
+{"name": "christine tarchala"},
+{"name": "greg williams"},
+{"name": "tom lemanowicz"},
+{"name": "kim dicks"},
+{"name": "wally ingram"},
+{"name": "john kennelly"},
+{"name": "melissa baffert"},
+{"name": "david scarborough"},
+{"name": "jim laughlin"},
+{"name": "nina adams"},
+{"name": "tony trainer"},
+{"name": "kevin knotts"},
+{"name": "scott chew"},
+{"name": "lois blake"},
+{"name": "wanda rhine"},
+{"name": "gustavo jr"},
+{"name": "jacob fattal"},
+{"name": "dave brand"},
+{"name": "tori house"},
+{"name": "greg erker"},
+{"name": "dana manager"},
+{"name": "frank berg"},
+{"name": "michael crowell"},
+{"name": "amanda daily"},
+{"name": "heather turner"},
+{"name": "phil tripoli"},
+{"name": "tasha foster"},
+{"name": "thomas keehn"},
+{"name": "luke o'lay"},
+{"name": "mac gauthier"},
+{"name": "kevin carey"},
+{"name": "kent lisenby"},
+{"name": "jonathan koplin"},
+{"name": "dawn smith"},
+{"name": "ken jones"},
+{"name": "jay howden"},
+{"name": "van roy"},
+{"name": "dave o'connell"},
+{"name": "kathleen hasslinger"},
+{"name": "shannon gobbato"},
+{"name": "jen a"},
+{"name": "chris benz"},
+{"name": "jose acosta"},
+{"name": "latrice graham"},
+{"name": "george chang"},
+{"name": "lindsey ford"},
+{"name": "warren manhagas"},
+{"name": "angel alberto"},
+{"name": "laura ausick"},
+{"name": "jamel arcenox"},
+{"name": "caitlin daly"},
+{"name": "greg henery"},
+{"name": "todd martel"},
+{"name": "gloria sanford"},
+{"name": "eric markham"},
+{"name": "shin kawai"},
+{"name": "kyle cohen"},
+{"name": "nicole stotts"},
+{"name": "mary ej"},
+{"name": "steven cumins"},
+{"name": "pat simons"},
+{"name": "ellen sist"},
+{"name": "kent hospital"},
+{"name": "michelle mullins"},
+{"name": "earl sun"},
+{"name": "william willkinson"},
+{"name": "joellen archerd"},
+{"name": "dylan stiegemeyer"},
+{"name": "sheila cochran"},
+{"name": "john negus"},
+{"name": "jillian taylor"},
+{"name": "jon hamilton"},
+{"name": "oliver jarrell"},
+{"name": "jocelyn lemieux"},
+{"name": "randy black"},
+{"name": "ali g"},
+{"name": "john gollnick"},
+{"name": "lisa kuklinski"},
+{"name": "christine harnack"},
+{"name": "andy zoller"},
+{"name": "michael payne"},
+{"name": "miss martha"},
+{"name": "mary ward"},
+{"name": "ray fleming"},
+{"name": "holly johnson"},
+{"name": "ben mcclinton"},
+{"name": "rudy tabooty"},
+{"name": "matt jenkins"},
+{"name": "tyler stafford"},
+{"name": "kevin smeltzer"},
+{"name": "nick arliss"},
+{"name": "michelle gregory"},
+{"name": "karen tolleson"},
+{"name": "diana lindstrom"},
+{"name": "maurice hall"},
+{"name": "gayle zupko"},
+{"name": "paul hoover"},
+{"name": "ron carter"},
+{"name": "wilson transport"},
+{"name": "frank kai"},
+{"name": "kevin toussaint"},
+{"name": "marcus trahan"},
+{"name": "william buster"},
+{"name": "seth yishay"},
+{"name": "keisha shop"},
+{"name": "tony montana"},
+{"name": "gale ceo"},
+{"name": "pauline killoran"},
+{"name": "shelby douglas"},
+{"name": "sandy derus"},
+{"name": "benjamin harrison"},
+{"name": "jacque mullen"},
+{"name": "joseph vaught"},
+{"name": "peter yim"},
+{"name": "eric hobson"},
+{"name": "whitney cameron"},
+{"name": "jack hakop"},
+{"name": "tom cleary"},
+{"name": "shawn patterson"},
+{"name": "doug boes"},
+{"name": "harriet klein"},
+{"name": "samuel seto"},
+{"name": "gary murphy"},
+{"name": "randy swets"},
+{"name": "tom sampley"},
+{"name": "jeff brown"},
+{"name": "joe reyes"},
+{"name": "ryan morhman"},
+{"name": "nicki gatlin"},
+{"name": "dale schaub"},
+{"name": "andrea woods"},
+{"name": "david mickelson"},
+{"name": "doug stockton"},
+{"name": "natalie forte"},
+{"name": "jody baker"},
+{"name": "danielle smart"},
+{"name": "jessica wilson"},
+{"name": "chantel zarka"},
+{"name": "page carter"},
+{"name": "dominic d"},
+{"name": "megan perry"},
+{"name": "christy masuse"},
+{"name": "allan taylor"},
+{"name": "tara stenbakken"},
+{"name": "steven jagusch"},
+{"name": "ryan santos"},
+{"name": "felicia sanders"},
+{"name": "chris bement"},
+{"name": "henry morganstein"},
+{"name": "sonia gomez"},
+{"name": "thomas blackmer"},
+{"name": "patty calhoun"},
+{"name": "rob fiallo"},
+{"name": "kim germany"},
+{"name": "wesley greenfield"},
+{"name": "megan rooney"},
+{"name": "debra yip"},
+{"name": "lawrence wong"},
+{"name": "steve edgar"},
+{"name": "harry lindner"},
+{"name": "michelle dojo"},
+{"name": "eric dankee"},
+{"name": "rachel crane"},
+{"name": "kara boehnert"},
+{"name": "gene atley"},
+{"name": "dee simpson"},
+{"name": "nick garvy"},
+{"name": "aleisha wagenmann"},
+{"name": "eden weston"},
+{"name": "paula maldonado"},
+{"name": "emma staller"},
+{"name": "kevin gatewood"},
+{"name": "shelli kurth"},
+{"name": "jack newkirk"},
+{"name": "brady yount"},
+{"name": "chris croghan"},
+{"name": "jerry leong"},
+{"name": "dale neighbor"},
+{"name": "steve k"},
+{"name": "steve sobonya"},
+{"name": "sandra guyman"},
+{"name": "michelle geisler"},
+{"name": "will cone"},
+{"name": "stephany lau"},
+{"name": "aileen pacis"},
+{"name": "jeffrey camp"},
+{"name": "ronald brotzman"},
+{"name": "marshall kwait"},
+{"name": "katie lenik"},
+{"name": "scott novotny"},
+{"name": "sallie office"},
+{"name": "billy byrne"},
+{"name": "paul coony"},
+{"name": "jim kock"},
+{"name": "jason goolesby"},
+{"name": "amie vu"},
+{"name": "andy s"},
+{"name": "scott gleason"},
+{"name": "stuart kauffman"},
+{"name": "rob frizzell"},
+{"name": "dave plotter"},
+{"name": "avery colbertson"},
+{"name": "brett dale"},
+{"name": "casey stone"},
+{"name": "alexander denson"},
+{"name": "sharon duong"},
+{"name": "ronnie smith"},
+{"name": "scott swearingen"},
+{"name": "denise ochoa"},
+{"name": "lee fleming"},
+{"name": "sarah dempsy"},
+{"name": "doug manning"},
+{"name": "steve baird"},
+{"name": "pam matthews"},
+{"name": "john sutton"},
+{"name": "janell fracassi"},
+{"name": "john bellino"},
+{"name": "ivan frishberg"},
+{"name": "hannah golay"},
+{"name": "jose sanchez"},
+{"name": "amanda saltzman"},
+{"name": "thomas zimmermann"},
+{"name": "martha lomely"},
+{"name": "matthew mccaslin"},
+{"name": "linda holcomb"},
+{"name": "sherril agency"},
+{"name": "carl williams"},
+{"name": "dave marett"},
+{"name": "joe difrancesco"},
+{"name": "dana andrews"},
+{"name": "robert rausch"},
+{"name": "norma jean"},
+{"name": "mark meloon"},
+{"name": "ryan jamboretz"},
+{"name": "david man"},
+{"name": "kristina f"},
+{"name": "cindy bell"},
+{"name": "meg gerfen"},
+{"name": "ken weyant"},
+{"name": "michael troy"},
+{"name": "art bode"},
+{"name": "dave pickett"},
+{"name": "john reynolds"},
+{"name": "everett boyd"},
+{"name": "james good"},
+{"name": "taylor peterson"},
+{"name": "paul turino"},
+{"name": "chris vert"},
+{"name": "craig harline"},
+{"name": "richard hernandez"},
+{"name": "john mathews"},
+{"name": "kyle smith"},
+{"name": "gary george"},
+{"name": "robert mckay"},
+{"name": "ron norinski"},
+{"name": "sam zone"},
+{"name": "mike bazzoni"},
+{"name": "richard ma"},
+{"name": "jan mink"},
+{"name": "angela yee"},
+{"name": "mathew walsh"},
+{"name": "gary keisker"},
+{"name": "samuel steed"},
+{"name": "enrique hernandez"},
+{"name": "rina rolen"},
+{"name": "liz little"},
+{"name": "pete klimis"},
+{"name": "jeff lehr"},
+{"name": "arthur soben"},
+{"name": "darryl deason"},
+{"name": "ryan claudio"},
+{"name": "ashley wood"},
+{"name": "tim paridon"},
+{"name": "becky mccormick"},
+{"name": "andrew ollis"},
+{"name": "chris sorensen"},
+{"name": "george thompson"},
+{"name": "jordan bar"},
+{"name": "larry club"},
+{"name": "lillian klein"},
+{"name": "christian d'amore"},
+{"name": "carmen burasco"},
+{"name": "kim demasie"},
+{"name": "rob gandy"},
+{"name": "jayson maglaqui"},
+{"name": "andrew hancock"},
+{"name": "randy reinhardt"},
+{"name": "van sciver"},
+{"name": "linda hunter"},
+{"name": "brandon gallagher"},
+{"name": "kurtis houston"},
+{"name": "ty huard"},
+{"name": "taren jones"},
+{"name": "bernie newman"},
+{"name": "dan miller"},
+{"name": "stan tsu"},
+{"name": "mike shine"},
+{"name": "charles deals"},
+{"name": "paul singer"},
+{"name": "tom riley"},
+{"name": "dan diefendorf"},
+{"name": "jesse merlin"},
+{"name": "ernest jones"},
+{"name": "chad kenny"},
+{"name": "jake king"},
+{"name": "george lambert"},
+{"name": "temeka douglas"},
+{"name": "joel schafer"},
+{"name": "greg southey"},
+{"name": "sheila cross"},
+{"name": "paul church"},
+{"name": "tom pof"},
+{"name": "julie simmons"},
+{"name": "coral fernndo"},
+{"name": "stephen foster"},
+{"name": "andrea rich"},
+{"name": "nick hitchcock"},
+{"name": "eric leese"},
+{"name": "dolores vassallo"},
+{"name": "brandon moncrief"},
+{"name": "amanda urich"},
+{"name": "rick donavan"},
+{"name": "abbie gregg"},
+{"name": "diana ewing"},
+{"name": "clay bramhall"},
+{"name": "donnie dean"},
+{"name": "becky leung"},
+{"name": "joe k"},
+{"name": "scott alberino"},
+{"name": "andy ducus"},
+{"name": "javier roman"},
+{"name": "steve scheffler"},
+{"name": "pat doley"},
+{"name": "charles l"},
+{"name": "michael carvatta"},
+{"name": "todd cummins"},
+{"name": "james edwards"},
+{"name": "cheryl darts"},
+{"name": "brittany k"},
+{"name": "janine dellacroce"},
+{"name": "krista grayson"},
+{"name": "dennis williams"},
+{"name": "rick ware"},
+{"name": "adam pietz"},
+{"name": "julian sinai"},
+{"name": "jamie s"},
+{"name": "oliva niel"},
+{"name": "jackie stewart"},
+{"name": "bill thompson"},
+{"name": "chad desserich"},
+{"name": "ricky jones"},
+{"name": "sharon chen"},
+{"name": "cleveland williams"},
+{"name": "kevin benjamin"},
+{"name": "murray killer"},
+{"name": "lawrence wall"},
+{"name": "anita ravipati"},
+{"name": "gina myers"},
+{"name": "colleen khoun"},
+{"name": "mark weisman"},
+{"name": "kelly fabian"},
+{"name": "ben port"},
+{"name": "rose landis"},
+{"name": "claire g"},
+{"name": "chris grippo"},
+{"name": "marcel cell"},
+{"name": "jason healy"},
+{"name": "mario fascino"},
+{"name": "rosa casa"},
+{"name": "julie jaster"},
+{"name": "donya prioleau"},
+{"name": "larissa stone"},
+{"name": "bob marks"},
+{"name": "isabel tavares"},
+{"name": "barry wares"},
+{"name": "nicole solecki"},
+{"name": "jim seins"},
+{"name": "aaron alms"},
+{"name": "maria irving"},
+{"name": "dennis haptyanov"},
+{"name": "bill ewen"},
+{"name": "drew girl"},
+{"name": "jonathan cd"},
+{"name": "danielle durnill"},
+{"name": "robert tayl"},
+{"name": "bob armel"},
+{"name": "jayson watson"},
+{"name": "irma principal"},
+{"name": "shawn firehock"},
+{"name": "phillis schmitt"},
+{"name": "ryan graffeo"},
+{"name": "janel plowman"},
+{"name": "mark glaser"},
+{"name": "michael marino"},
+{"name": "danny santiago"},
+{"name": "joshua owens"},
+{"name": "nina faust"},
+{"name": "ann gallup"},
+{"name": "lacy hawkins"},
+{"name": "bonnie jeanette"},
+{"name": "michelle lloyd"},
+{"name": "ben lee"},
+{"name": "renee hayes"},
+{"name": "katie tallant"},
+{"name": "paul bromfield"},
+{"name": "jonathan keselenko"},
+{"name": "kevin evans"},
+{"name": "mark curran"},
+{"name": "steve nussbaum"},
+{"name": "alex m"},
+{"name": "rob mercer"},
+{"name": "allen webster"},
+{"name": "denise barbartia"},
+{"name": "mac morgan"},
+{"name": "kayla cell"},
+{"name": "maria alvir"},
+{"name": "denita sibert"},
+{"name": "katie davidson"},
+{"name": "kathleen cahill"},
+{"name": "steve tidwell"},
+{"name": "charles mason"},
+{"name": "rachel canada"},
+{"name": "mark gaydos"},
+{"name": "nick milka"},
+{"name": "john crute"},
+{"name": "deon chuck"},
+{"name": "tyrone jordan"},
+{"name": "david saitta"},
+{"name": "scott freisen"},
+{"name": "steve welch"},
+{"name": "fred laporte"},
+{"name": "veronique lussier"},
+{"name": "martha mako"},
+{"name": "katie meyer"},
+{"name": "natalie goodwin"},
+{"name": "kris langei"},
+{"name": "roberto jimenez"},
+{"name": "ruth cummins"},
+{"name": "kristen stevens"},
+{"name": "jessica areopostal"},
+{"name": "karen eddings"},
+{"name": "gordon davidson"},
+{"name": "chris zagar"},
+{"name": "tabitha brown"},
+{"name": "jodie littrup"},
+{"name": "andrew deslaurier"},
+{"name": "jonathan gales"},
+{"name": "bob edgell"},
+{"name": "ashley demello"},
+{"name": "danny wascou"},
+{"name": "sam joll"},
+{"name": "daniel rogers"},
+{"name": "julio chavez"},
+{"name": "tamara slade"},
+{"name": "patti howitt"},
+{"name": "ben haines"},
+{"name": "josh kolo"},
+{"name": "anthony scalfaro"},
+{"name": "alex imming"},
+{"name": "rob krackenfels"},
+{"name": "shayla howard"},
+{"name": "barbara damon"},
+{"name": "mai ketcherside"},
+{"name": "jc cordero"},
+{"name": "art pfeffer"},
+{"name": "tammy doerksen"},
+{"name": "angela oppedisano"},
+{"name": "john cell"},
+{"name": "robert rosenfelt"},
+{"name": "katherine fleming"},
+{"name": "nina moye"},
+{"name": "ray b"},
+{"name": "robert bortfeld"},
+{"name": "chris sheldon"},
+{"name": "jacque wall"},
+{"name": "sammy home"},
+{"name": "wayne ivary"},
+{"name": "kimberly farrugio"},
+{"name": "eric lockwood"},
+{"name": "gilberto camacho"},
+{"name": "rebecca lape"},
+{"name": "todd berghaus"},
+{"name": "brook hect"},
+{"name": "mike duncan"},
+{"name": "troy v"},
+{"name": "jeff marquez"},
+{"name": "marcel chaparteguy"},
+{"name": "hubert cell"},
+{"name": "becky ellis"},
+{"name": "gil hong"},
+{"name": "karen perkowski"},
+{"name": "jason huber"},
+{"name": "toby bright"},
+{"name": "jennifer stetz"},
+{"name": "alex marshall"},
+{"name": "stacey shallenbarger"},
+{"name": "sam salsbury"},
+{"name": "barb multari"},
+{"name": "adam malner"},
+{"name": "nick rickman"},
+{"name": "allie sister"},
+{"name": "summer housley"},
+{"name": "joe manugid"},
+{"name": "jeff arch"},
+{"name": "stephen echavia"},
+{"name": "ray blanc"},
+{"name": "jose freyre"},
+{"name": "betty douglas"},
+{"name": "dave waliszewski"},
+{"name": "ashley rose"},
+{"name": "mark watthuber"},
+{"name": "roy simmons"},
+{"name": "lauren crownshaw"},
+{"name": "pam devereux"},
+{"name": "sean lilly"},
+{"name": "kyle roberts"},
+{"name": "russ walter"},
+{"name": "nicole kennedy"},
+{"name": "mario zamora"},
+{"name": "tim dunn"},
+{"name": "kyle bergeron"},
+{"name": "amy kinser"},
+{"name": "megan buford"},
+{"name": "leah santos"},
+{"name": "jeremy andrews"},
+{"name": "jordan gilbert"},
+{"name": "jonathon millman"},
+{"name": "clint robertson"},
+{"name": "alexa welch"},
+{"name": "lucy uk"},
+{"name": "mary eck"},
+{"name": "danna freeman"},
+{"name": "tracy brandon"},
+{"name": "liz edwards"},
+{"name": "jason veno"},
+{"name": "ana marie"},
+{"name": "lisa durston"},
+{"name": "matt kruschack"},
+{"name": "johnny thompson"},
+{"name": "jimmy richards"},
+{"name": "tom miale"},
+{"name": "eric hammond"},
+{"name": "brad bonnell"},
+{"name": "barbara tate"},
+{"name": "ronda baker"},
+{"name": "amy spalding"},
+{"name": "kristen palmer"},
+{"name": "michael birnbaum"},
+{"name": "david coleman"},
+{"name": "ken waggoner"},
+{"name": "alan blaustein"},
+{"name": "scott kidman"},
+{"name": "louis bedocs"},
+{"name": "chris visentin"},
+{"name": "michael mcnerney"},
+{"name": "jeff borsuk"},
+{"name": "larry domres"},
+{"name": "david johnston"},
+{"name": "john epeneter"},
+{"name": "arthur weiner"},
+{"name": "erica vanderlinden"},
+{"name": "jim cintron"},
+{"name": "robert gibson"},
+{"name": "william harness"},
+{"name": "tim sinclair"},
+{"name": "kayla kirkwood"},
+{"name": "ron sloman"},
+{"name": "david crapo"},
+{"name": "tami holzhuerter"},
+{"name": "candace croxton"},
+{"name": "shay hirota"},
+{"name": "christine work"},
+{"name": "sung elder"},
+{"name": "bruce hall"},
+{"name": "gordon moench"},
+{"name": "mark yeager"},
+{"name": "charlene graham"},
+{"name": "carroll fry"},
+{"name": "neal dempsey"},
+{"name": "samuel vail"},
+{"name": "dave thonn"},
+{"name": "jen king"},
+{"name": "jenette bryant"},
+{"name": "maria navejar"},
+{"name": "adam taylor"},
+{"name": "kenisha sumner"},
+{"name": "michelle c"},
+{"name": "dan nerwinski"},
+{"name": "mary j"},
+{"name": "nikki hiers"},
+{"name": "harry o'neal"},
+{"name": "toby hyde"},
+{"name": "steve keeling"},
+{"name": "becky dauzat"},
+{"name": "bill sponsee"},
+{"name": "sue kaplowe"},
+{"name": "kristen brockmen"},
+{"name": "armand bassi"},
+{"name": "dennis jacobsen"},
+{"name": "cristal johengen"},
+{"name": "tim hedberg"},
+{"name": "perry martin"},
+{"name": "sarah weadick"},
+{"name": "michael kuhl"},
+{"name": "danny barnes"},
+{"name": "matthew finerman"},
+{"name": "patrick heneghan"},
+{"name": "mike bischoff"},
+{"name": "joan rodberg"},
+{"name": "amber regkamp"},
+{"name": "catalina lopez"},
+{"name": "sean v"},
+{"name": "mike reyes"},
+{"name": "jeff moure"},
+{"name": "oscar tovar"},
+{"name": "jack edwards"},
+{"name": "kimberly jennings"},
+{"name": "richard cockrell"},
+{"name": "nora oats"},
+{"name": "shane phillips"},
+{"name": "heather pearson"},
+{"name": "alissa yahoo"},
+{"name": "maria riley"},
+{"name": "jamison gabriel"},
+{"name": "matt thomson"},
+{"name": "darren bonghiter"},
+{"name": "alex cw"},
+{"name": "leo shahidi"},
+{"name": "kate nichols"},
+{"name": "susan rasmussen"},
+{"name": "steve light"},
+{"name": "huong buyer"},
+{"name": "will bob"},
+{"name": "jen st"},
+{"name": "freida hernandez"},
+{"name": "kirsten sims"},
+{"name": "robert benmergui"},
+{"name": "britt paris"},
+{"name": "ashley palmer"},
+{"name": "alan palmer"},
+{"name": "karl nero"},
+{"name": "allison henderson"},
+{"name": "josh bailey"},
+{"name": "glenn butler"},
+{"name": "lisa hite"},
+{"name": "amber brunner"},
+{"name": "warren finlay"},
+{"name": "alvin young"},
+{"name": "richard walkers"},
+{"name": "curt kirkpatrick"},
+{"name": "matthew burczyk"},
+{"name": "emily belleau"},
+{"name": "dave stelling"},
+{"name": "celina michelle"},
+{"name": "stephanie gallardo"},
+{"name": "bill jensen"},
+{"name": "joey o"},
+{"name": "son low"},
+{"name": "rich couden"},
+{"name": "david vasquez"},
+{"name": "brian fixter"},
+{"name": "bruce eisenberg"},
+{"name": "amy sivilay"},
+{"name": "mike prutz"},
+{"name": "ahmad khwanda"},
+{"name": "gary theodore"},
+{"name": "maegan miller"},
+{"name": "emily trask"},
+{"name": "dino scott"},
+{"name": "thomas lange"},
+{"name": "vincent fontaine"},
+{"name": "craig nelson"},
+{"name": "laura greenstein"},
+{"name": "lydia toda"},
+{"name": "hannah schnack"},
+{"name": "bill ward"},
+{"name": "paul parents"},
+{"name": "casey martinez"},
+{"name": "charles boyd"},
+{"name": "frank poulin"},
+{"name": "monica ahn"},
+{"name": "michael saragossi"},
+{"name": "dean chiapetto"},
+{"name": "gary swart"},
+{"name": "michelle naguiat"},
+{"name": "eddie alvarado"},
+{"name": "kit kat"},
+{"name": "sarah gray"},
+{"name": "doyle moss"},
+{"name": "max mald"},
+{"name": "jack strike"},
+{"name": "robert maro"},
+{"name": "van kampen"},
+{"name": "bruce brunda"},
+{"name": "damon wright"},
+{"name": "lauren enriquez"},
+{"name": "robert neilson"},
+{"name": "mark sanderson"},
+{"name": "hank wells"},
+{"name": "john dole"},
+{"name": "celeste villarreal"},
+{"name": "meredith kaner"},
+{"name": "brad mehr"},
+{"name": "bruno pirecki"},
+{"name": "joe pinter"},
+{"name": "ken ellis"},
+{"name": "sandy casting"},
+{"name": "larry blaker"},
+{"name": "ralph amelio"},
+{"name": "aaron rezak"},
+{"name": "michael polson"},
+{"name": "becky grant"},
+{"name": "mira waukee"},
+{"name": "corey trujillo"},
+{"name": "sharon shealey"},
+{"name": "joel wk"},
+{"name": "adam dae"},
+{"name": "karen ettre"},
+{"name": "katie limoncelli"},
+{"name": "joe gibbs"},
+{"name": "todd d"},
+{"name": "jaime barbosa"},
+{"name": "doug taxadremy"},
+{"name": "dwayne brown"},
+{"name": "ryan cadinha"},
+{"name": "reggie connell"},
+{"name": "mary hayden"},
+{"name": "shayla bergman"},
+{"name": "scott denton"},
+{"name": "jenny phillips"},
+{"name": "al ledebur"},
+{"name": "damon whatley"},
+{"name": "kieth point"},
+{"name": "john alteio@amazon"},
+{"name": "marta fredericks"},
+{"name": "michael coulis"},
+{"name": "jim sharko"},
+{"name": "rachel albani"},
+{"name": "chris suggs"},
+{"name": "barrie taxi"},
+{"name": "angel marini"},
+{"name": "robin clayton"},
+{"name": "cherie price"},
+{"name": "latoya semple"},
+{"name": "ruth shaw"},
+{"name": "russ darrow"},
+{"name": "eric patterson"},
+{"name": "carolyn harmon"},
+{"name": "mathew gallagher"},
+{"name": "adam symington"},
+{"name": "gary deblase"},
+{"name": "michael brander"},
+{"name": "francine vecchiolla"},
+{"name": "richard otool"},
+{"name": "jenna bruce"},
+{"name": "guy hoffrage"},
+{"name": "cassie hatfield"},
+{"name": "cory cropper"},
+{"name": "dan lisa"},
+{"name": "barbra c"},
+{"name": "eric noten"},
+{"name": "nancy meyer"},
+{"name": "pete montague"},
+{"name": "fred mazari"},
+{"name": "jeff amp"},
+{"name": "joanne marsicek"},
+{"name": "kendall williams"},
+{"name": "brent doolittle"},
+{"name": "andrew alvarado"},
+{"name": "pat yohe"},
+{"name": "rob bohannan"},
+{"name": "sheri dickson"},
+{"name": "nathan giroux"},
+{"name": "crystal wandler"},
+{"name": "barb schriever"},
+{"name": "ben tseng"},
+{"name": "audra cooper"},
+{"name": "john kilcullen"},
+{"name": "karen wang"},
+{"name": "russ carter"},
+{"name": "joe tumor"},
+{"name": "chris fletcher"},
+{"name": "carter williams"},
+{"name": "matt bratlien"},
+{"name": "jennifer messick"},
+{"name": "joe jizza"},
+{"name": "kris dumadag"},
+{"name": "byron macaulay"},
+{"name": "jin yu"},
+{"name": "james sanderson"},
+{"name": "gail wong"},
+{"name": "rick bishop"},
+{"name": "van winkle"},
+{"name": "vicki ackerman"},
+{"name": "mark mcd"},
+{"name": "joanna forbes"},
+{"name": "brandon prescott"},
+{"name": "samantha caldwell"},
+{"name": "sandee downey"},
+{"name": "lee norman"},
+{"name": "pat kiernan"},
+{"name": "melody propheter"},
+{"name": "tim dunphy"},
+{"name": "jessie thai"},
+{"name": "sam wonchek"},
+{"name": "bruce raisner"},
+{"name": "macie douglas"},
+{"name": "doris payne"},
+{"name": "tommy chiro"},
+{"name": "hannah sheffield"},
+{"name": "charles mueller"},
+{"name": "jose flores"},
+{"name": "nathan tosh"},
+{"name": "ann greenhaw"},
+{"name": "alan halan"},
+{"name": "gerald linden"},
+{"name": "sandra pinney"},
+{"name": "kasey chandler"},
+{"name": "sara selbert"},
+{"name": "ben stafford"},
+{"name": "jay sugarman"},
+{"name": "richard borell"},
+{"name": "curtis dennis"},
+{"name": "david paul"},
+{"name": "eric walters"},
+{"name": "victor syng"},
+{"name": "gary fellner"},
+{"name": "paul swearengin"},
+{"name": "gwen vicki"},
+{"name": "jeff raggs"},
+{"name": "ricardo castillo"},
+{"name": "raymond berlinger"},
+{"name": "jack summers"},
+{"name": "bruce naegelen"},
+{"name": "jimmy france"},
+{"name": "richard schoen"},
+{"name": "todd han"},
+{"name": "julie deverik"},
+{"name": "craig gutow"},
+{"name": "brice s"},
+{"name": "helen hirshberg"},
+{"name": "susan ronnback"},
+{"name": "dusty black"},
+{"name": "laura hartman"},
+{"name": "patti delisi"},
+{"name": "don stapp"},
+{"name": "les darnall"},
+{"name": "jeremy norred"},
+{"name": "patrick cp"},
+{"name": "gary lionberger"},
+{"name": "jason talman"},
+{"name": "alfredo diaz"},
+{"name": "anna zee"},
+{"name": "jennifer guevara"},
+{"name": "lindsey herrera"},
+{"name": "john menezes"},
+{"name": "cherrone griffith"},
+{"name": "dennis chapman"},
+{"name": "heather salerno"},
+{"name": "steven baron"},
+{"name": "mike medvec"},
+{"name": "daniel sauce"},
+{"name": "mike walters"},
+{"name": "paula day"},
+{"name": "dorothy simmons"},
+{"name": "eric cada"},
+{"name": "amiee pyatt"},
+{"name": "adrian losifescu"},
+{"name": "tyler shelby"},
+{"name": "ali sadiq"},
+{"name": "rebecca gale"},
+{"name": "sara s"},
+{"name": "colleen scruggs"},
+{"name": "bruce marc"},
+{"name": "randy harmdierks"},
+{"name": "roxie house"},
+{"name": "linda parton"},
+{"name": "cassandra aguilera"},
+{"name": "rich erie"},
+{"name": "dona richardson"},
+{"name": "lois ballard"},
+{"name": "robert tipman"},
+{"name": "paul piesa"},
+{"name": "doug hogue"},
+{"name": "stacy godwin"},
+{"name": "erica white"},
+{"name": "kristina oliver"},
+{"name": "ronald johnston"},
+{"name": "terry krantz"},
+{"name": "bill burtton"},
+{"name": "dawn arceneaux"},
+{"name": "lauren madson"},
+{"name": "codi b"},
+{"name": "norman peters"},
+{"name": "peter kuhn"},
+{"name": "wallace taylor"},
+{"name": "larry jennings"},
+{"name": "mimi mazzara"},
+{"name": "chris witt"},
+{"name": "scott lloyd"},
+{"name": "bob lemay"},
+{"name": "tony barrett"},
+{"name": "dana rubinstein"},
+{"name": "jaclyn schwab"},
+{"name": "kathryn james"},
+{"name": "michelle mays"},
+{"name": "amy reichman"},
+{"name": "kent olmstead"},
+{"name": "susan bransfield"},
+{"name": "jen munz"},
+{"name": "jeremy paul"},
+{"name": "pennie herbert"},
+{"name": "ashley jensen"},
+{"name": "jeff waeckerle"},
+{"name": "tisha arthurs"},
+{"name": "glen lyons"},
+{"name": "carolyn thomas"},
+{"name": "rob clavier"},
+{"name": "ryan chippeaux"},
+{"name": "ron licari"},
+{"name": "cathi nanninga"},
+{"name": "donald savoie"},
+{"name": "barbara laura"},
+{"name": "trey stearns"},
+{"name": "jack gale"},
+{"name": "geraldine coleman"},
+{"name": "corey taylor"},
+{"name": "dan dickerson"},
+{"name": "lance hamilton"},
+{"name": "cole swedenburg"},
+{"name": "kris knox"},
+{"name": "david eckert"},
+{"name": "christopher derouin"},
+{"name": "joseph nana"},
+{"name": "brett ruynan"},
+{"name": "andy faber"},
+{"name": "alex maas"},
+{"name": "peter angerhofer"},
+{"name": "alex rogers"},
+{"name": "terry boyer"},
+{"name": "jesse seay"},
+{"name": "mark burchem"},
+{"name": "jared sawyer"},
+{"name": "brian booty"},
+{"name": "allison ghaman"},
+{"name": "alan forte"},
+{"name": "katie shefield"},
+{"name": "pat richardson"},
+{"name": "jamie stribling"},
+{"name": "mitch renko"},
+{"name": "sheryl crum"},
+{"name": "daniel jeffcott"},
+{"name": "max klimer"},
+{"name": "tom willard"},
+{"name": "lisa sexton"},
+{"name": "marilee lieber"},
+{"name": "jay conkin"},
+{"name": "john midby"},
+{"name": "newton lingenfelter"},
+{"name": "robert ozankan"},
+{"name": "krista d"},
+{"name": "dani canadia"},
+{"name": "carl elmore"},
+{"name": "peter kieffer"},
+{"name": "chris prenovost"},
+{"name": "michele burns"},
+{"name": "matt westberg"},
+{"name": "somer forest"},
+{"name": "annette bills"},
+{"name": "tiffaney mccutcheon"},
+{"name": "veronica dasilva"},
+{"name": "eric hawes"},
+{"name": "alison fey"},
+{"name": "jon fine"},
+{"name": "vincent johnson"},
+{"name": "ellen germann"},
+{"name": "mike trahan"},
+{"name": "anthony lowe"},
+{"name": "val clark"},
+{"name": "ryan munn"},
+{"name": "kurt holmstead"},
+{"name": "irwin alter"},
+{"name": "patricia tsai"},
+{"name": "susan orosz"},
+{"name": "larry roers"},
+{"name": "rina carmel"},
+{"name": "robert lavita"},
+{"name": "robert m"},
+{"name": "erica tessmann"},
+{"name": "mark hornor"},
+{"name": "michael hoffacker"},
+{"name": "robert dharmasaputra"},
+{"name": "connie garrison"},
+{"name": "billy n"},
+{"name": "katelin keacher"},
+{"name": "erin e"},
+{"name": "roni kent"},
+{"name": "tony telan"},
+{"name": "travis patterson"},
+{"name": "jennifer devin"},
+{"name": "kelly e"},
+{"name": "chuck crow"},
+{"name": "vince romero"},
+{"name": "david platt"},
+{"name": "jeanette lopez"},
+{"name": "sam pierce"},
+{"name": "josh bambino"},
+{"name": "shelia boudreaux"},
+{"name": "jim ferman"},
+{"name": "michael varma"},
+{"name": "perry dau"},
+{"name": "mike mitter"},
+{"name": "adriana sevilla"},
+{"name": "gloria wait"},
+{"name": "cornell prater"},
+{"name": "amber koch"},
+{"name": "gary olympia"},
+{"name": "alma paine"},
+{"name": "john hannum"},
+{"name": "marie murray"},
+{"name": "jen bridges"},
+{"name": "dewayne va"},
+{"name": "darlene gilliland"},
+{"name": "sandy mwi"},
+{"name": "marina aunt"},
+{"name": "andy kirsch"},
+{"name": "carol johnson"},
+{"name": "fred gorrell"},
+{"name": "beverly piazza"},
+{"name": "john bucket"},
+{"name": "julie walsh"},
+{"name": "megan rogers"},
+{"name": "janet cruz"},
+{"name": "pat doyle"},
+{"name": "doug combie"},
+{"name": "craig provost"},
+{"name": "stanley fine"},
+{"name": "dave renner"},
+{"name": "len stoler"},
+{"name": "jack big"},
+{"name": "cindy desplinter"},
+{"name": "ed beadnell"},
+{"name": "brandon donahoe"},
+{"name": "martha cousin"},
+{"name": "eduardo garcia"},
+{"name": "ann subin"},
+{"name": "debbie p"},
+{"name": "angela mallory"},
+{"name": "sharon levi"},
+{"name": "julia w"},
+{"name": "andrew clarke"},
+{"name": "cliff childs"},
+{"name": "patricia silao"},
+{"name": "richard christensen"},
+{"name": "anthony choquette"},
+{"name": "wayne clarke"},
+{"name": "rob glover"},
+{"name": "guy rotte"},
+{"name": "john lee"},
+{"name": "kristie lenz"},
+{"name": "crystal berentz"},
+{"name": "mickey miela"},
+{"name": "tanya lanice"},
+{"name": "ali gilroy"},
+{"name": "debbie kaup"},
+{"name": "steve ritter"},
+{"name": "james leggieri"},
+{"name": "bobbie dulaney"},
+{"name": "steve jespersen"},
+{"name": "ben wong"},
+{"name": "charles dilucente"},
+{"name": "jennifer dollarhide"},
+{"name": "james powell"},
+{"name": "jeffery kahn"},
+{"name": "julie janke"},
+{"name": "phil gustafson"},
+{"name": "lisa smith"},
+{"name": "sheldon jordan"},
+{"name": "matt tawni"},
+{"name": "erika yorio"},
+{"name": "catherine sangiolo"},
+{"name": "janet giorgio"},
+{"name": "scott mcbee"},
+{"name": "nicole z"},
+{"name": "dave johnston"},
+{"name": "darlene whitfield"},
+{"name": "vicki silva"},
+{"name": "jeremiah cell"},
+{"name": "roberto g"},
+{"name": "tom clatters"},
+{"name": "chase keener"},
+{"name": "rosemary dominquez"},
+{"name": "stephen adams"},
+{"name": "larry egbert"},
+{"name": "chris benes"},
+{"name": "jen yohn"},
+{"name": "linda singer"},
+{"name": "angelica hesse"},
+{"name": "hans alse"},
+{"name": "veronica cc"},
+{"name": "reinaldo hill"},
+{"name": "lori amicangelo"},
+{"name": "thomas slack"},
+{"name": "rob sapirstein"},
+{"name": "nathan solting"},
+{"name": "jeff hinrichs"},
+{"name": "dan genter"},
+{"name": "joyce davison"},
+{"name": "tony fonseca"},
+{"name": "david villager"},
+{"name": "jeremy jernigan"},
+{"name": "jerry patava"},
+{"name": "david reed"},
+{"name": "jon foster"},
+{"name": "jackie cookies"},
+{"name": "kyle butz"},
+{"name": "kevin robinson"},
+{"name": "alex gamble"},
+{"name": "mike sanft"},
+{"name": "josh freeguard"},
+{"name": "sara mackellar"},
+{"name": "bill portado"},
+{"name": "lindsey jenson"},
+{"name": "dann agosini"},
+{"name": "chris t"},
+{"name": "derek mar"},
+{"name": "kai lam"},
+{"name": "jim szeremeta"},
+{"name": "austin roach"},
+{"name": "george difederico"},
+{"name": "nolan classen"},
+{"name": "tara bolyard"},
+{"name": "melinda potcher"},
+{"name": "roger blumenthal"},
+{"name": "duane grimsman"},
+{"name": "john badalich"},
+{"name": "jessica sanders"},
+{"name": "pat forges"},
+{"name": "dewayne smith"},
+{"name": "judi bixby"},
+{"name": "roman kischenko"},
+{"name": "matt pilgrim"},
+{"name": "katherine webb"},
+{"name": "david eatchel"},
+{"name": "pearl snelling"},
+{"name": "robert colbourn"},
+{"name": "daniel rzonca"},
+{"name": "debby peterson"},
+{"name": "matt wolf"},
+{"name": "charlie rutledge"},
+{"name": "david o'connor"},
+{"name": "trevor talton"},
+{"name": "bob bumpus"},
+{"name": "paula moses"},
+{"name": "colby cr"},
+{"name": "nancy fitzgerald"},
+{"name": "fred goldsberry"},
+{"name": "jim link"},
+{"name": "rosario shriver"},
+{"name": "patty armstrong"},
+{"name": "pete lauzon"},
+{"name": "berry laura"},
+{"name": "susan s"},
+{"name": "barbara anne's"},
+{"name": "brad goldberg"},
+{"name": "celia pena"},
+{"name": "chris hardwick"},
+{"name": "dave hodgs"},
+{"name": "angela rita"},
+{"name": "patrick greene"},
+{"name": "sylvia brown"},
+{"name": "jesus tapia"},
+{"name": "eileen silva"},
+{"name": "andres arango"},
+{"name": "tom fly"},
+{"name": "david aldridge"},
+{"name": "nick putman"},
+{"name": "marshall moore"},
+{"name": "jennifer escola"},
+{"name": "adam allred"},
+{"name": "ngoc admin"},
+{"name": "seth christian"},
+{"name": "ryan wight"},
+{"name": "john ressler"},
+{"name": "linda charles"},
+{"name": "john bushman"},
+{"name": "joe markey"},
+{"name": "ivan valentine"},
+{"name": "austin utter"},
+{"name": "fred hibbler"},
+{"name": "debra hines"},
+{"name": "justin chambers"},
+{"name": "mandy patten"},
+{"name": "gina spinello"},
+{"name": "craig wax"},
+{"name": "david xxxxx"},
+{"name": "paul weber"},
+{"name": "jason mexico"},
+{"name": "junior handball"},
+{"name": "charlie lovalle"},
+{"name": "ray manning"},
+{"name": "tony lowe"},
+{"name": "john spinelli"},
+{"name": "omar kinnebrew"},
+{"name": "gwen howard"},
+{"name": "kristen stewart"},
+{"name": "homer rieffanaugh"},
+{"name": "jan hittle"},
+{"name": "carrie jensen"},
+{"name": "star nissan"},
+{"name": "mark manning"},
+{"name": "luke french"},
+{"name": "fred daniels"},
+{"name": "colleen ungos"},
+{"name": "missy laptop"},
+{"name": "veronica v"},
+{"name": "barry blackburn"},
+{"name": "cary tangerine"},
+{"name": "paul heckel"},
+{"name": "mary mancini"},
+{"name": "cathy gebhardt"},
+{"name": "tori reyna"},
+{"name": "bill bushong"},
+{"name": "rhett bowman"},
+{"name": "al pasquel"},
+{"name": "carol nelson"},
+{"name": "katie herringa"},
+{"name": "jen trautmann"},
+{"name": "danny a"},
+{"name": "cami tedoldi"},
+{"name": "dina rocha"},
+{"name": "lin robets"},
+{"name": "dede grace"},
+{"name": "heather wilde"},
+{"name": "christina vorobets"},
+{"name": "martin orient"},
+{"name": "keith perry"},
+{"name": "nancy padilla"},
+{"name": "boyd jr"},
+{"name": "mike june"},
+{"name": "tyler ford"},
+{"name": "al tees"},
+{"name": "amanda kindred"},
+{"name": "justin noah"},
+{"name": "michael simon"},
+{"name": "jen stein"},
+{"name": "candy lady"},
+{"name": "frankie davis"},
+{"name": "brent curtis"},
+{"name": "stephanie osbourn"},
+{"name": "paul mcdonnell"},
+{"name": "harold burtnett"},
+{"name": "elina simanas"},
+{"name": "irene opuka"},
+{"name": "dale equitz"},
+{"name": "kassie lutchko"},
+{"name": "john kirst"},
+{"name": "patricia kimball"},
+{"name": "jake burns"},
+{"name": "tyler bball"},
+{"name": "normand rinfret"},
+{"name": "eric ekstam"},
+{"name": "alex elm"},
+{"name": "jessi lockington"},
+{"name": "jane phips"},
+{"name": "wayne sandberry"},
+{"name": "mary manross"},
+{"name": "matt wright"},
+{"name": "juan vanegas"},
+{"name": "tom kielty"},
+{"name": "gerald meza"},
+{"name": "jason rund"},
+{"name": "florencia camera"},
+{"name": "andy paul"},
+{"name": "debbie accountant"},
+{"name": "scott clyne"},
+{"name": "alex llorente"},
+{"name": "tom graff"},
+{"name": "lonnie ritzer"},
+{"name": "vanessa winkler"},
+{"name": "randy cao"},
+{"name": "jackson yiu"},
+{"name": "erik mack"},
+{"name": "tangela foxx"},
+{"name": "jared eggett"},
+{"name": "rick basa"},
+{"name": "candis scott"},
+{"name": "robin ore"},
+{"name": "blair ullman"},
+{"name": "chris amundsen"},
+{"name": "chris moore"},
+{"name": "luke tarter"},
+{"name": "sarah south"},
+{"name": "amanda lazo"},
+{"name": "cynthia donato"},
+{"name": "dale haas"},
+{"name": "krystal blair"},
+{"name": "john g'sell"},
+{"name": "angela yost"},
+{"name": "gilberto alvarez"},
+{"name": "bill dunn"},
+{"name": "michael newman"},
+{"name": "larry n"},
+{"name": "milan fronk"},
+{"name": "randall talich"},
+{"name": "wendy wendlandt"},
+{"name": "cherie debernardi"},
+{"name": "teena arrington"},
+{"name": "pam jamison"},
+{"name": "dan donahoe"},
+{"name": "jayne pelger"},
+{"name": "kip h"},
+{"name": "jeff wertz"},
+{"name": "sam cross"},
+{"name": "randy posner"},
+{"name": "anne goetsch"},
+{"name": "thomas hunter"},
+{"name": "whitney blanton"},
+{"name": "charlie margoisian"},
+{"name": "joseph hinrichs"},
+{"name": "andy gilkison"},
+{"name": "katelyn lynch"},
+{"name": "jimmy odonnell"},
+{"name": "cruz new"},
+{"name": "janie hale"},
+{"name": "david flores"},
+{"name": "martin corona"},
+{"name": "norma seymour"},
+{"name": "mitchell jones"},
+{"name": "frank duncan"},
+{"name": "david sperber"},
+{"name": "sean audio"},
+{"name": "chris product"},
+{"name": "derek tires"},
+{"name": "alan cohee"},
+{"name": "donna fascenda"},
+{"name": "kelley davis"},
+{"name": "john semel"},
+{"name": "paul biasevich"},
+{"name": "martin ruef"},
+{"name": "derick spencer"},
+{"name": "george adams"},
+{"name": "tyler s"},
+{"name": "michelle caplinger"},
+{"name": "jack gregory"},
+{"name": "steve rigdon"},
+{"name": "keith mcdaniel"},
+{"name": "joy southwell"},
+{"name": "sarah reynolds"},
+{"name": "ann o'bien"},
+{"name": "tom glatt"},
+{"name": "lonnie barnes"},
+{"name": "melanie watkins"},
+{"name": "caren otiato"},
+{"name": "karen torres"},
+{"name": "erica mcmillan"},
+{"name": "gladys gilley"},
+{"name": "sarah sophia"},
+{"name": "theresa bratton"},
+{"name": "ed gable"},
+{"name": "lauren boumaroun"},
+{"name": "alonzo brinkley"},
+{"name": "bob lovett"},
+{"name": "megan bewsey"},
+{"name": "phil davis"},
+{"name": "jamie alaska"},
+{"name": "anne desimone"},
+{"name": "tisa adamson"},
+{"name": "megan dykas"},
+{"name": "jimmy sparks"},
+{"name": "michael pittman"},
+{"name": "kyle bluff"},
+{"name": "brian priest"},
+{"name": "ashley zandiotis"},
+{"name": "rex mixon"},
+{"name": "kim vargas"},
+{"name": "cindie desmond"},
+{"name": "john matos"},
+{"name": "chi phi"},
+{"name": "rene mendieta"},
+{"name": "santiago corrada"},
+{"name": "pam cheng"},
+{"name": "tom roommate"},
+{"name": "stephanie gonzales"},
+{"name": "theresa hayden"},
+{"name": "rachel pizano"},
+{"name": "melodee hillcrest"},
+{"name": "erin powel"},
+{"name": "bruce conrey"},
+{"name": "nancy chrisman"},
+{"name": "david branfman"},
+{"name": "paul alati"},
+{"name": "kelly ireland"},
+{"name": "nichole nardoni"},
+{"name": "allison worl"},
+{"name": "michael diaz"},
+{"name": "greg lewis"},
+{"name": "janice stalter"},
+{"name": "heather ferroni"},
+{"name": "rachel bradley"},
+{"name": "ellen toe"},
+{"name": "brenda blair"},
+{"name": "jess irs"},
+{"name": "matt markel"},
+{"name": "christy fritts"},
+{"name": "carter quolonge"},
+{"name": "tim johns"},
+{"name": "michael p"},
+{"name": "don wagner"},
+{"name": "kristina davis"},
+{"name": "nicole w"},
+{"name": "adam bertin"},
+{"name": "estela martell"},
+{"name": "joe marino"},
+{"name": "yelena mikich"},
+{"name": "chad arlington"},
+{"name": "john rambo"},
+{"name": "maura dooley"},
+{"name": "jenny work"},
+{"name": "derek scott"},
+{"name": "eric outbak"},
+{"name": "charlie jobbins"},
+{"name": "mark tannery"},
+{"name": "peter goedegebuure"},
+{"name": "wesley jones"},
+{"name": "dan chiu"},
+{"name": "andy pants"},
+{"name": "sandy rasmusen"},
+{"name": "brittany mckinney"},
+{"name": "james wei"},
+{"name": "raquel stewart"},
+{"name": "kathleen maunder"},
+{"name": "al ditta"},
+{"name": "damian cristiani"},
+{"name": "sammy dudesnude"},
+{"name": "hillary elliott"},
+{"name": "bruce kelsey"},
+{"name": "jake illian"},
+{"name": "joanna yoakum"},
+{"name": "brian kieser"},
+{"name": "john garver"},
+{"name": "chrystal foy"},
+{"name": "sara wolf"},
+{"name": "margaret hager"},
+{"name": "james nauman"},
+{"name": "ken childers"},
+{"name": "shana m"},
+{"name": "mike suzuki"},
+{"name": "bill foley"},
+{"name": "pat renfrow"},
+{"name": "joe evans"},
+{"name": "terry regnault"},
+{"name": "archie paje"},
+{"name": "amber kelly"},
+{"name": "karen tupu"},
+{"name": "fred kelly"},
+{"name": "johnnie moore"},
+{"name": "pauline nahabedian"},
+{"name": "rita starr"},
+{"name": "joe francher"},
+{"name": "hillary davis"},
+{"name": "stan free"},
+{"name": "jeff heller"},
+{"name": "john rampino"},
+{"name": "joe dolgas"},
+{"name": "debbie robinson"},
+{"name": "michelle norris"},
+{"name": "raul hernandez"},
+{"name": "warren zeserman"},
+{"name": "mark laflamme"},
+{"name": "rob whitmore"},
+{"name": "jake cell"},
+{"name": "mike preacher"},
+{"name": "steven ward"},
+{"name": "wyatt crane"},
+{"name": "marcia garcia"},
+{"name": "ron newkirk"},
+{"name": "amy raasch"},
+{"name": "andria finau"},
+{"name": "jana ross"},
+{"name": "ernie arias"},
+{"name": "christina toll"},
+{"name": "sophia estrella"},
+{"name": "maria v"},
+{"name": "danielle f"},
+{"name": "john keck"},
+{"name": "jean charity"},
+{"name": "charmaine powell"},
+{"name": "jamie opatrny"},
+{"name": "ryan richey"},
+{"name": "abby garcia"},
+{"name": "lou spengel"},
+{"name": "phil greer"},
+{"name": "mark greenburg"},
+{"name": "althea jasper"},
+{"name": "carrie barrett"},
+{"name": "john moffly"},
+{"name": "mike cinnabon"},
+{"name": "andrew hawker"},
+{"name": "jason diesley"},
+{"name": "jackie p"},
+{"name": "brian bowman"},
+{"name": "kyle fiore"},
+{"name": "lance shabazz"},
+{"name": "paul coastal"},
+{"name": "maryland perel"},
+{"name": "frank vitale"},
+{"name": "jason harp"},
+{"name": "jason bernal"},
+{"name": "ken wilson"},
+{"name": "lynn daugherty"},
+{"name": "mike schiller"},
+{"name": "jason poore"},
+{"name": "stephen sprint"},
+{"name": "beverly naidoo"},
+{"name": "jesse anderson"},
+{"name": "amy amsterdam"},
+{"name": "tammy shaikh"},
+{"name": "mark waldron"},
+{"name": "tony rodriguez"},
+{"name": "kathryn mcateer"},
+{"name": "michelle keen"},
+{"name": "ryan protection"},
+{"name": "judy glover"},
+{"name": "steve politziner"},
+{"name": "erika sanjuan"},
+{"name": "james deleon"},
+{"name": "rosemarie beltz"},
+{"name": "mike water"},
+{"name": "eddie hebert"},
+{"name": "greg anderson"},
+{"name": "al williamson"},
+{"name": "brandon karmann"},
+{"name": "jennifer fisher"},
+{"name": "rob hayward"},
+{"name": "frank mann"},
+{"name": "eddy guzzo"},
+{"name": "lauren cat"},
+{"name": "marc richardson"},
+{"name": "dan park"},
+{"name": "jason oroszy"},
+{"name": "allen tran"},
+{"name": "marty deginaro"},
+{"name": "jerry buchanan"},
+{"name": "vincent pullara"},
+{"name": "ralph hemenway"},
+{"name": "neal crouse"},
+{"name": "jeff lawrence"},
+{"name": "corine julien"},
+{"name": "peter konstantakis"},
+{"name": "james pillatzki"},
+{"name": "louis morales"},
+{"name": "tracy rankin"},
+{"name": "chelsea moss"},
+{"name": "amy williams"},
+{"name": "lisa rafferty"},
+{"name": "allison d'attelo"},
+{"name": "reed pilot"},
+{"name": "ken reddick"},
+{"name": "greg denker"},
+{"name": "brian birnbaum"},
+{"name": "lavina herring"},
+{"name": "lucy rodriguez"},
+{"name": "brett riley"},
+{"name": "susan henderson"},
+{"name": "adriana hernandez"},
+{"name": "frank caricatto"},
+{"name": "david lumber"},
+{"name": "mario magro"},
+{"name": "cathy ulery"},
+{"name": "claudia lentini"},
+{"name": "cyril suszckiewicz"},
+{"name": "arlie condo"},
+{"name": "kristy gatz"},
+{"name": "randy korba"},
+{"name": "rachel hill"},
+{"name": "janice rezak"},
+{"name": "niki house"},
+{"name": "vincent tsai"},
+{"name": "asha bellis"},
+{"name": "alisha phillips"},
+{"name": "pat mcdermot"},
+{"name": "jody doucet"},
+{"name": "joel humburg"},
+{"name": "anne klosterman"},
+{"name": "heath johnson"},
+{"name": "george bookataub"},
+{"name": "eddie robles"},
+{"name": "mark joslin"},
+{"name": "kristi aldrine"},
+{"name": "marc d"},
+{"name": "evan griffith"},
+{"name": "chris stout"},
+{"name": "josh ross"},
+{"name": "ryan s"},
+{"name": "dick krites"},
+{"name": "trisha zeigler"},
+{"name": "john senese"},
+{"name": "lisa bush"},
+{"name": "linda pera"},
+{"name": "brian dunn"},
+{"name": "aaron goldhammer"},
+{"name": "brian lapansie"},
+{"name": "toby presley"},
+{"name": "penny rappa"},
+{"name": "stephen williams"},
+{"name": "steve colic"},
+{"name": "paul maffey"},
+{"name": "mitch burr"},
+{"name": "aaron ginn"},
+{"name": "rachel roark"},
+{"name": "bud peterson"},
+{"name": "roderick ervin"},
+{"name": "ian cell"},
+{"name": "anthony sokolowski"},
+{"name": "marcia martin"},
+{"name": "patrick hodgins"},
+{"name": "hai buyer"},
+{"name": "rachel wadell"},
+{"name": "janette harmon"},
+{"name": "randal hark"},
+{"name": "mary cusack"},
+{"name": "thad fuller"},
+{"name": "jessica d"},
+{"name": "amanda guess"},
+{"name": "dominic shortridge"},
+{"name": "daniel schwartz"},
+{"name": "matt watkins"},
+{"name": "jarrett petero"},
+{"name": "debra poris"},
+{"name": "kurt demmel"},
+{"name": "paul mora"},
+{"name": "robert shippy"},
+{"name": "chris cuschieri"},
+{"name": "erika robertson"},
+{"name": "pablo donato"},
+{"name": "chris flaw"},
+{"name": "kendra knuppel"},
+{"name": "greg lay"},
+{"name": "ben cooper"},
+{"name": "drew diehm"},
+{"name": "phil burkholder"},
+{"name": "golden griffith"},
+{"name": "maureen z"},
+{"name": "james markin"},
+{"name": "terri hayman"},
+{"name": "michael sparks"},
+{"name": "erica bravo"},
+{"name": "kevin pua"},
+{"name": "terra blackwell"},
+{"name": "matt howland"},
+{"name": "jeannie layne"},
+{"name": "brady herman"},
+{"name": "brett cypress"},
+{"name": "terry anderson"},
+{"name": "derek dophied"},
+{"name": "janice bonamo"},
+{"name": "edmond primeau"},
+{"name": "paul drzaic"},
+{"name": "jennifer medley"},
+{"name": "john bruholski"},
+{"name": "max kotelevets"},
+{"name": "perry johnson"},
+{"name": "alex band"},
+{"name": "carl greenhalgh"},
+{"name": "ashton barden"},
+{"name": "michael luyten"},
+{"name": "carl irwin"},
+{"name": "jim lewis"},
+{"name": "major stinson"},
+{"name": "john eydenberg"},
+{"name": "jason nako"},
+{"name": "tiffany fomin"},
+{"name": "willis auto"},
+{"name": "crystal txs"},
+{"name": "lindsay deats"},
+{"name": "lynne french"},
+{"name": "roger portnoy"},
+{"name": "tabitha crookes"},
+{"name": "walter davis"},
+{"name": "tom bender"},
+{"name": "cary gota"},
+{"name": "raul lastra"},
+{"name": "sam ray"},
+{"name": "nikki sigale"},
+{"name": "brian bolves"},
+{"name": "julio santana"},
+{"name": "adan rivera"},
+{"name": "wendy o'neill"},
+{"name": "gary shelden"},
+{"name": "anthony colbert"},
+{"name": "ernie kohagura"},
+{"name": "judi guerra"},
+{"name": "robert suber"},
+{"name": "carl mechanic"},
+{"name": "timothy durst"},
+{"name": "jesse hildebrand"},
+{"name": "joe todd"},
+{"name": "fran turner"},
+{"name": "erin lynch"},
+{"name": "barb meadows"},
+{"name": "kym barger"},
+{"name": "angel eastman"},
+{"name": "jennifer frazier"},
+{"name": "janet whitlock"},
+{"name": "linda piccolo"},
+{"name": "martha funke"},
+{"name": "charlie blevins"},
+{"name": "chris poorman"},
+{"name": "jess efird"},
+{"name": "jennifer parker"},
+{"name": "carl goin"},
+{"name": "teri considine"},
+{"name": "steve brown"},
+{"name": "danny hurley"},
+{"name": "monica haun"},
+{"name": "donnell taylor"},
+{"name": "mari gonzalez"},
+{"name": "brian haynes"},
+{"name": "dave d"},
+{"name": "amy garrington"},
+{"name": "alan elias"},
+{"name": "gayle galloway"},
+{"name": "jason forsyte"},
+{"name": "ivan huang"},
+{"name": "marcus nicholls"},
+{"name": "joyce duffy"},
+{"name": "barry demo"},
+{"name": "andrew wilner"},
+{"name": "calvin leung"},
+{"name": "sarah xxxxx"},
+{"name": "max wazack"},
+{"name": "ryan c"},
+{"name": "david kopasz"},
+{"name": "martha contreras"},
+{"name": "rafael barba"},
+{"name": "josh newman"},
+{"name": "jeremy kruk"},
+{"name": "katherine lucchese"},
+{"name": "jean fletcher"},
+{"name": "todd edwards"},
+{"name": "roger wilcox"},
+{"name": "scott raley"},
+{"name": "annie klassen"},
+{"name": "dianna browning"},
+{"name": "brandon wunder"},
+{"name": "john zarafa"},
+{"name": "dustin cutrer"},
+{"name": "eric chaika"},
+{"name": "helen beck"},
+{"name": "kris a"},
+{"name": "becky hettman"},
+{"name": "joel wilder"},
+{"name": "mary baine"},
+{"name": "kevin corcoran"},
+{"name": "bob horsley"},
+{"name": "niki home"},
+{"name": "amina ekpaji"},
+{"name": "tom berthold"},
+{"name": "greg freeman"},
+{"name": "cliff allen"},
+{"name": "dave binenstock"},
+{"name": "jeff b"},
+{"name": "ray rauch"},
+{"name": "jennifer hardee"},
+{"name": "dallas jones"},
+{"name": "jeff reiher"},
+{"name": "royal china"},
+{"name": "josiah gillespie"},
+{"name": "justin valley"},
+{"name": "austin ross"},
+{"name": "scott minot"},
+{"name": "elliott inandoutdock"},
+{"name": "jen todd"},
+{"name": "lance varden"},
+{"name": "peggy caldwell"},
+{"name": "lorraine prochownik"},
+{"name": "travis landrum"},
+{"name": "callie conrad"},
+{"name": "chris covell"},
+{"name": "james henning"},
+{"name": "james donaldson"},
+{"name": "garrett moretz"},
+{"name": "bob stimson"},
+{"name": "ryan j"},
+{"name": "ralph bultman"},
+{"name": "bev more"},
+{"name": "elaine ford"},
+{"name": "linda higbee"},
+{"name": "scott customer"},
+{"name": "clayton holcolmb"},
+{"name": "virginia apellaniz"},
+{"name": "justin kew"},
+{"name": "mike cadwell"},
+{"name": "tim hatch"},
+{"name": "kim ripper"},
+{"name": "becky hall"},
+{"name": "pat coplen"},
+{"name": "ryan harris"},
+{"name": "david lawton"},
+{"name": "allen williams"},
+{"name": "derick cornell"},
+{"name": "marguerite rangel"},
+{"name": "stacy spring"},
+{"name": "jenna mcfarland"},
+{"name": "ryan uoa"},
+{"name": "pam ng"},
+{"name": "denis akzam"},
+{"name": "dennis fong"},
+{"name": "joey spencer"},
+{"name": "erica rogers"},
+{"name": "greg lutzka"},
+{"name": "min v"},
+{"name": "kurt kepheart"},
+{"name": "hunter brown"},
+{"name": "erin hulbert"},
+{"name": "larry kronk"},
+{"name": "melissa chivington"},
+{"name": "craig mccarthy"},
+{"name": "arianna t"},
+{"name": "greg wilson"},
+{"name": "steve radonjic"},
+{"name": "tina nguyen"},
+{"name": "kate dickie"},
+{"name": "eric d"},
+{"name": "ashley barbie"},
+{"name": "ann free"},
+{"name": "justin juencke"},
+{"name": "daniel promo"},
+{"name": "perry huff"},
+{"name": "kelly rich"},
+{"name": "heidi wilkens"},
+{"name": "catherine lockhart"},
+{"name": "ned callister"},
+{"name": "alexander day"},
+{"name": "glenn beck"},
+{"name": "bruce deutsch"},
+{"name": "steve magliozzi"},
+{"name": "rich adducci"},
+{"name": "anthony howard"},
+{"name": "carlos ruiz"},
+{"name": "joe myspace"},
+{"name": "benjamin northcutt"},
+{"name": "eli erdan"},
+{"name": "rhonda adair"},
+{"name": "ed lamoureaux"},
+{"name": "cheryl webb"},
+{"name": "jeanne lundgren"},
+{"name": "lora clark"},
+{"name": "tori doyle"},
+{"name": "david simon"},
+{"name": "tashina spoon"},
+{"name": "mary andretti"},
+{"name": "brandon tompson"},
+{"name": "alaina yan"},
+{"name": "doug lasit"},
+{"name": "sheila summers"},
+{"name": "lavera rios"},
+{"name": "jim miller"},
+{"name": "kristopher winkler"},
+{"name": "john mckee"},
+{"name": "ryan bales"},
+{"name": "michael maynard"},
+{"name": "bill chappell"},
+{"name": "so fly"},
+{"name": "julia johnson"},
+{"name": "taylor bass"},
+{"name": "brad fanshaw"},
+{"name": "jose velasquez"},
+{"name": "wilma gunn"},
+{"name": "chris carlson"},
+{"name": "suzanne colucci"},
+{"name": "max d"},
+{"name": "ernie morones"},
+{"name": "gary freeman"},
+{"name": "jordan hunter"},
+{"name": "brandon whitfield"},
+{"name": "scott hixson"},
+{"name": "george kitch"},
+{"name": "erin jade"},
+{"name": "ruben dl"},
+{"name": "phyllis pettengill"},
+{"name": "sam farmer"},
+{"name": "david shively"},
+{"name": "john hiers"},
+{"name": "jay robinson"},
+{"name": "chuck koehn"},
+{"name": "bao ran"},
+{"name": "richard hurst"},
+{"name": "robin chestnut"},
+{"name": "peter liang"},
+{"name": "alan ruppe"},
+{"name": "yung sir"},
+{"name": "rikki mata"},
+{"name": "annette pena"},
+{"name": "rachael coleman"},
+{"name": "nikki williams"},
+{"name": "brittany fox"},
+{"name": "kyle garwood"},
+{"name": "kelly aaa"},
+{"name": "bob killworth"},
+{"name": "mark hancock"},
+{"name": "laurel bender"},
+{"name": "heather danner"},
+{"name": "jeff infusino"},
+{"name": "joe beutel"},
+{"name": "al forline"},
+{"name": "ben rabner"},
+{"name": "robert driscoll"},
+{"name": "jim melvin"},
+{"name": "rob redden"},
+{"name": "cynthia write"},
+{"name": "paul baccus"},
+{"name": "brian odom"},
+{"name": "hannah warren"},
+{"name": "steve valentine"},
+{"name": "rick kapple"},
+{"name": "andrew deleon"},
+{"name": "mike f"},
+{"name": "ronald gardner"},
+{"name": "jacqueline parker"},
+{"name": "louis karen"},
+{"name": "barbara olsthoorn"},
+{"name": "jack lecomp"},
+{"name": "ericka porter"},
+{"name": "tom gale"},
+{"name": "karen beveridge"},
+{"name": "wendy prior"},
+{"name": "stewart hough"},
+{"name": "nancy kuhn"},
+{"name": "guy vega"},
+{"name": "aaron p"},
+{"name": "travis millman"},
+{"name": "alissa vinizki"},
+{"name": "elaine lu"},
+{"name": "joe murdico"},
+{"name": "shari urban"},
+{"name": "jamie sims"},
+{"name": "david caldwell"},
+{"name": "rich schaus"},
+{"name": "david roque"},
+{"name": "steve perry"},
+{"name": "brandon horning"},
+{"name": "stacey ingenito"},
+{"name": "anne melvin"},
+{"name": "tyler enderly"},
+{"name": "angie franco"},
+{"name": "benedict morelli"},
+{"name": "connie gallion"},
+{"name": "bella b's"},
+{"name": "joseph nieves"},
+{"name": "kylee f"},
+{"name": "dennis petroff"},
+{"name": "joey yatooma"},
+{"name": "heather giddens"},
+{"name": "bruce johanson"},
+{"name": "suzanne kilner"},
+{"name": "nicole pearson"},
+{"name": "betsy freeman"},
+{"name": "bree robbins"},
+{"name": "diana plummer"},
+{"name": "judith mullaney"},
+{"name": "dan town"},
+{"name": "greg dodge"},
+{"name": "john farmosa"},
+{"name": "trisha gregory"},
+{"name": "corey zeigler"},
+{"name": "matt nerney"},
+{"name": "glenn brush"},
+{"name": "todd hill"},
+{"name": "cindy stidham"},
+{"name": "samuel agui"},
+{"name": "will gamio"},
+{"name": "tony montenegro"},
+{"name": "rick borden"},
+{"name": "john malozzi"},
+{"name": "joe elder"},
+{"name": "kevin swanson"},
+{"name": "robert ades"},
+{"name": "bill little"},
+{"name": "kim hawley"},
+{"name": "cheryl moss"},
+{"name": "jessica purfume"},
+{"name": "shane bellis"},
+{"name": "scott wolf"},
+{"name": "janet davis"},
+{"name": "gary verdone"},
+{"name": "joe carrillo"},
+{"name": "bradley goodman"},
+{"name": "jarred bbq"},
+{"name": "dick lambert"},
+{"name": "steve leahy"},
+{"name": "tom nabors"},
+{"name": "dennis hicks"},
+{"name": "taylor marvin"},
+{"name": "justin burnette"},
+{"name": "rose cerda"},
+{"name": "mike hides"},
+{"name": "merlin mufflers"},
+{"name": "kim reed"},
+{"name": "darryl phillips"},
+{"name": "leonard jackson"},
+{"name": "nell dallon"},
+{"name": "nicky cuz"},
+{"name": "catherine follett"},
+{"name": "randy s"},
+{"name": "emily vegas"},
+{"name": "mike vitolo"},
+{"name": "nancy bayless"},
+{"name": "evan dreyfuss"},
+{"name": "thuy tran"},
+{"name": "maurice marable"},
+{"name": "jack cheng"},
+{"name": "dara pannebaker"},
+{"name": "ken gellman"},
+{"name": "mike appel"},
+{"name": "luke rowan"},
+{"name": "john phipps"},
+{"name": "hanna gelder"},
+{"name": "josh wade"},
+{"name": "hilton sf"},
+{"name": "jim perifoy"},
+{"name": "andrew woodward"},
+{"name": "steve mustain"},
+{"name": "gina hoosier"},
+{"name": "alexandra rua"},
+{"name": "valerie smith"},
+{"name": "andrew everetts"},
+{"name": "jolene baca"},
+{"name": "adam knobeloch"},
+{"name": "john genovese"},
+{"name": "carie barnard"},
+{"name": "tony serfin"},
+{"name": "gilbert tripp"},
+{"name": "cindi straup"},
+{"name": "ann stacy"},
+{"name": "joey michael"},
+{"name": "matt beats"},
+{"name": "belinda orem"},
+{"name": "dave moore"},
+{"name": "tammie manning"},
+{"name": "van alstine"},
+{"name": "sandra woitkowiak"},
+{"name": "jenna white"},
+{"name": "alison travis"},
+{"name": "vicki haddix"},
+{"name": "eva redette"},
+{"name": "ruben bernal"},
+{"name": "deborah mcmindes"},
+{"name": "roger faircloth"},
+{"name": "justin gibbs"},
+{"name": "mike melton"},
+{"name": "kyle andrus"},
+{"name": "adan chung"},
+{"name": "bobby bell"},
+{"name": "mark moretti"},
+{"name": "virginia nienstedt"},
+{"name": "jon black"},
+{"name": "mandy hicks"},
+{"name": "dave brody"},
+{"name": "duane hazelbaker"},
+{"name": "jimmy shipley"},
+{"name": "james lucas"},
+{"name": "doug rager"},
+{"name": "kerry davidson"},
+{"name": "robert knighten"},
+{"name": "wendy gilbert"},
+{"name": "dwayne smith"},
+{"name": "richard hessel"},
+{"name": "brian folland"},
+{"name": "christa neeman"},
+{"name": "lee mullins"},
+{"name": "ryan weaver"},
+{"name": "art newson"},
+{"name": "tracy monroe"},
+{"name": "lynn schleif"},
+{"name": "brian chappell"},
+{"name": "matthew stephenson"},
+{"name": "maureen fischer"},
+{"name": "jon litlfld"},
+{"name": "alex telford"},
+{"name": "ellen little"},
+{"name": "kyle bacon"},
+{"name": "mark gardin"},
+{"name": "ron miz"},
+{"name": "vanessa aranda"},
+{"name": "chuck newby"},
+{"name": "luis prez"},
+{"name": "bill langin"},
+{"name": "dave albart"},
+{"name": "wanda davies"},
+{"name": "bill jackson"},
+{"name": "melissa mac"},
+{"name": "juliet andre"},
+{"name": "susan lidner"},
+{"name": "jude kersaint"},
+{"name": "doug davies"},
+{"name": "lee greg"},
+{"name": "romeo osorio"},
+{"name": "jeffrey spitz"},
+{"name": "david grimes"},
+{"name": "tomas havrda"},
+{"name": "jeremy white"},
+{"name": "marlene verhoeven"},
+{"name": "carl warners"},
+{"name": "jim lutsch"},
+{"name": "cynthia edmonds"},
+{"name": "gary hall"},
+{"name": "sheila ginzel"},
+{"name": "jim cole"},
+{"name": "todd mauk"},
+{"name": "jorge fletes"},
+{"name": "sherri tejeda"},
+{"name": "victoria nurse"},
+{"name": "eric kurzik"},
+{"name": "christina evans"},
+{"name": "rob miller"},
+{"name": "anne innis"},
+{"name": "michelle paisley"},
+{"name": "mike jimenez"},
+{"name": "chris linnel"},
+{"name": "kitty wilson"},
+{"name": "marty townsend"},
+{"name": "nikki robbins"},
+{"name": "bryan cavender"},
+{"name": "sierra ademco"},
+{"name": "dave barber"},
+{"name": "brett templin"},
+{"name": "matt summers"},
+{"name": "meghann kane"},
+{"name": "ruben g"},
+{"name": "charlotte botsford"},
+{"name": "joe pittera"},
+{"name": "brian llewellyn"},
+{"name": "derek nakachi"},
+{"name": "ted bray"},
+{"name": "austin farnlof"},
+{"name": "willy mosquera"},
+{"name": "rose leon"},
+{"name": "josh vanduyn"},
+{"name": "oscar moore"},
+{"name": "lori list"},
+{"name": "faith williams"},
+{"name": "cheryl sykes"},
+{"name": "ken robinson"},
+{"name": "ashley barton"},
+{"name": "diane hargis"},
+{"name": "marlena sandor"},
+{"name": "ken ward"},
+{"name": "albert aldrich"},
+{"name": "chris rasch"},
+{"name": "dell computers"},
+{"name": "solomon milhoan"},
+{"name": "rhoda makled"},
+{"name": "lou mazzucchelli"},
+{"name": "paul vongontard"},
+{"name": "brittny e"},
+{"name": "dana myers"},
+{"name": "dan williams"},
+{"name": "ira sakolsky"},
+{"name": "chad gardunial"},
+{"name": "lonnie deal"},
+{"name": "kim frost"},
+{"name": "glen kippas"},
+{"name": "alan sanders"},
+{"name": "leroy brown"},
+{"name": "robert ro"},
+{"name": "brian oneil"},
+{"name": "jason ho"},
+{"name": "ray sedgwick"},
+{"name": "vernon hawthorne"},
+{"name": "suzanne head"},
+{"name": "mark zebrowski"},
+{"name": "jamie sewell"},
+{"name": "mike tally"},
+{"name": "john devore"},
+{"name": "jay rodriquez"},
+{"name": "harry shearer"},
+{"name": "carla askew"},
+{"name": "larry douglas"},
+{"name": "millie greathouse"},
+{"name": "steve yi"},
+{"name": "lori pa"},
+{"name": "jerry beauchane"},
+{"name": "tommy mac"},
+{"name": "jan reb"},
+{"name": "jaime villalovos"},
+{"name": "toya client"},
+{"name": "dionne calhoun"},
+{"name": "anna hicks"},
+{"name": "david nadler"},
+{"name": "robert beardsley"},
+{"name": "matt zucker"},
+{"name": "chris harvey"},
+{"name": "laura fautsko"},
+{"name": "bob entringer"},
+{"name": "jocelyn doan"},
+{"name": "john lawrence"},
+{"name": "mike knell"},
+{"name": "shea bossard"},
+{"name": "jose d"},
+{"name": "dallas scott"},
+{"name": "katie hensley"},
+{"name": "chad krischke"},
+{"name": "grant skabelund"},
+{"name": "tristan bayless"},
+{"name": "terrance underwood"},
+{"name": "sha mcgee"},
+{"name": "michael krutsch"},
+{"name": "mark appraiser"},
+{"name": "glory shea"},
+{"name": "kevin heavikev"},
+{"name": "carla mcmahon"},
+{"name": "sasha thomson"},
+{"name": "pat casey"},
+{"name": "bernie castrow"},
+{"name": "maggie pascaly"},
+{"name": "john joseph"},
+{"name": "frank rolapp"},
+{"name": "joe ahmada"},
+{"name": "brad hastings"},
+{"name": "tanya avila"},
+{"name": "chris havron"},
+{"name": "katrina kuley"},
+{"name": "jason gbar"},
+{"name": "greg bowers"},
+{"name": "felix brown"},
+{"name": "robbin ryan"},
+{"name": "ryan beffy"},
+{"name": "jane mallen"},
+{"name": "curt clayton"},
+{"name": "rebecca braslau"},
+{"name": "bob carzoli"},
+{"name": "karissa owyang"},
+{"name": "jason stilson"},
+{"name": "eduardo visbal"},
+{"name": "dave fazzio"},
+{"name": "sharon demers"},
+{"name": "gail smith"},
+{"name": "lindsay miller"},
+{"name": "amanda view"},
+{"name": "blake moses"},
+{"name": "pat bunch"},
+{"name": "clay tippet"},
+{"name": "jessica rodriguez"},
+{"name": "becky bryant"},
+{"name": "lance nadel"},
+{"name": "donna hugh"},
+{"name": "emily wait"},
+{"name": "johnathan whitacre"},
+{"name": "mike pantlitz"},
+{"name": "steve addleman"},
+{"name": "kelsie gentry"},
+{"name": "clay stratton"},
+{"name": "tim darnell"},
+{"name": "sean stribling"},
+{"name": "mary bessent"},
+{"name": "forest reeder"},
+{"name": "myles harris"},
+{"name": "camille tedesco"},
+{"name": "jeff eckley"},
+{"name": "peter henry"},
+{"name": "lisa recchia"},
+{"name": "tommy rhodes"},
+{"name": "van robinson"},
+{"name": "mary o'connor"},
+{"name": "cindy roth"},
+{"name": "john neppl"},
+{"name": "charlie benedict"},
+{"name": "jamie adams"},
+{"name": "jim weeden"},
+{"name": "pauline duke"},
+{"name": "scott sia"},
+{"name": "matt shoemaker"},
+{"name": "neil blankenship"},
+{"name": "nolan shari"},
+{"name": "ruth solach"},
+{"name": "earl beecham"},
+{"name": "tim mensend"},
+{"name": "dane hatch"},
+{"name": "paul kusunoki"},
+{"name": "jonathan thomas"},
+{"name": "peter cho"},
+{"name": "trista wolfe"},
+{"name": "kendra gordon"},
+{"name": "pablo claussen"},
+{"name": "brittany edwards"},
+{"name": "jon vaughan"},
+{"name": "donald scanlon"},
+{"name": "tammy grant"},
+{"name": "ted chua"},
+{"name": "tracy cryder"},
+{"name": "barb hart"},
+{"name": "jamison jones"},
+{"name": "christine calareso"},
+{"name": "adam wilke"},
+{"name": "garret henderson"},
+{"name": "lou partridge"},
+{"name": "sanford gips"},
+{"name": "jim graves"},
+{"name": "chris x"},
+{"name": "richard daines"},
+{"name": "harrison l"},
+{"name": "marisol lau"},
+{"name": "whitney atlas"},
+{"name": "kyra stoddart"},
+{"name": "jessica munyon"},
+{"name": "marcy pineau"},
+{"name": "marion petry"},
+{"name": "ira stern"},
+{"name": "jim julie"},
+{"name": "leo cordingley"},
+{"name": "james stiarwalt"},
+{"name": "wayne purcell"},
+{"name": "mallory m"},
+{"name": "steve mcclain"},
+{"name": "alex stedman"},
+{"name": "jonathon nunez"},
+{"name": "tristan boy"},
+{"name": "gary pollard"},
+{"name": "darlene wolf"},
+{"name": "paul zebrowski"},
+{"name": "ray simon"},
+{"name": "robin nielsen"},
+{"name": "edith guttierrez"},
+{"name": "kevin patrick"},
+{"name": "eric nichols"},
+{"name": "jessica madera"},
+{"name": "mike lanza"},
+{"name": "bob huges"},
+{"name": "kasey jones"},
+{"name": "lynn work"},
+{"name": "betty cox"},
+{"name": "tom peterson"},
+{"name": "tony green"},
+{"name": "charles galea"},
+{"name": "lena butterfield"},
+{"name": "allison boldger"},
+{"name": "milton promo"},
+{"name": "kim tipton"},
+{"name": "randy powell"},
+{"name": "wes mason"},
+{"name": "eric joely"},
+{"name": "nathan sego"},
+{"name": "hank bordowitz"},
+{"name": "adam hollingsworth"},
+{"name": "adrienne ingham"},
+{"name": "andrew usmiani"},
+{"name": "stephen ruehmann"},
+{"name": "jake sandin"},
+{"name": "stacy crevello"},
+{"name": "allen bragdon"},
+{"name": "kate diranna"},
+{"name": "diana lopez"},
+{"name": "jane howze"},
+{"name": "glenn song"},
+{"name": "jesse esparza"},
+{"name": "barb williams"},
+{"name": "lewis seiden"},
+{"name": "jeff bollen"},
+{"name": "deborah hooper"},
+{"name": "amy stader"},
+{"name": "mike serna"},
+{"name": "greg tataw"},
+{"name": "allison edwards"},
+{"name": "steve cutlip"},
+{"name": "linda mcmurtry"},
+{"name": "robert simon"},
+{"name": "stan marcuss"},
+{"name": "charley eisler"},
+{"name": "stephen sein"},
+{"name": "kathryn salyer"},
+{"name": "bob lapointe"},
+{"name": "ivan luciano"},
+{"name": "josh grant"},
+{"name": "ashley holcomb"},
+{"name": "michael wirsing"},
+{"name": "jeff pence"},
+{"name": "dan croner"},
+{"name": "andrew cron"},
+{"name": "robert himes"},
+{"name": "rusty deaton"},
+{"name": "william stanback"},
+{"name": "randy beaver"},
+{"name": "holly whittig"},
+{"name": "harvey gladys"},
+{"name": "marcia walker"},
+{"name": "chelsea steiner"},
+{"name": "dee devi"},
+{"name": "don jewelers"},
+{"name": "shirley wood"},
+{"name": "rudy renfer"},
+{"name": "tara beasley"},
+{"name": "esther job"},
+{"name": "harry tziotzios"},
+{"name": "erick elliot"},
+{"name": "jason spector"},
+{"name": "rodrigo lopez"},
+{"name": "giuseppe rossi"},
+{"name": "crystal ma"},
+{"name": "salvador mungia"},
+{"name": "eric rob"},
+{"name": "ana rio"},
+{"name": "tom boxman"},
+{"name": "jamie byrd"},
+{"name": "paul tien"},
+{"name": "todd foster"},
+{"name": "charles rankin"},
+{"name": "claudia gueli"},
+{"name": "tony rossell"},
+{"name": "kaylee quenzer"},
+{"name": "morgan h"},
+{"name": "phil moeller"},
+{"name": "ashley home"},
+{"name": "marie mcdonald"},
+{"name": "george barone"},
+{"name": "matthew berry"},
+{"name": "bill whalen"},
+{"name": "skye thomas"},
+{"name": "andy allen"},
+{"name": "eric frederickson"},
+{"name": "bernita washington"},
+{"name": "evan fader"},
+{"name": "ryan gannon"},
+{"name": "gene verdegan"},
+{"name": "josh holden"},
+{"name": "kimberly gotthardt"},
+{"name": "angie nieland"},
+{"name": "amanda padilla"},
+{"name": "sid rizvy"},
+{"name": "sean cuz"},
+{"name": "tiffani horton"},
+{"name": "john skelly"},
+{"name": "john robison"},
+{"name": "olivia h"},
+{"name": "stacey hudson"},
+{"name": "elias hankash"},
+{"name": "frank nelson"},
+{"name": "jenny martin"},
+{"name": "elizabeth luce"},
+{"name": "myron glaser"},
+{"name": "colleen sommers"},
+{"name": "taylor beumel"},
+{"name": "sarah mcclaran"},
+{"name": "stuart hwang"},
+{"name": "peter rostas"},
+{"name": "javier bastante"},
+{"name": "ernest moringlane"},
+{"name": "dale montford"},
+{"name": "dave fairchild"},
+{"name": "virginia huang"},
+{"name": "dayna matthew"},
+{"name": "tiffany briana"},
+{"name": "debbie laswell"},
+{"name": "monica atchoo"},
+{"name": "james romhanyi"},
+{"name": "chris crdbl"},
+{"name": "karen krueger"},
+{"name": "ronnie peterson"},
+{"name": "joe grody"},
+{"name": "beth torrence"},
+{"name": "ben hard"},
+{"name": "shari chapman"},
+{"name": "lorena frausto"},
+{"name": "john williamson"},
+{"name": "paul nicholas"},
+{"name": "wayne niou"},
+{"name": "doug johns"},
+{"name": "robert greene"},
+{"name": "nichole dupree"},
+{"name": "marina buckner"},
+{"name": "charlie gabay"},
+{"name": "rick mottle"},
+{"name": "janice a"},
+{"name": "ryan actor"},
+{"name": "kristin barrick"},
+{"name": "rubin sanchez"},
+{"name": "david candlefuse"},
+{"name": "fay strait"},
+{"name": "glenn gittus"},
+{"name": "mauricio espinoza"},
+{"name": "linwood parker"},
+{"name": "scott pulley"},
+{"name": "joe mckinney"},
+{"name": "ryan patient"},
+{"name": "randall ushijima"},
+{"name": "steve rainb"},
+{"name": "jason calhoun"},
+{"name": "tina curtis"},
+{"name": "mike valdez"},
+{"name": "todd knowles"},
+{"name": "alan scherer"},
+{"name": "michael legg"},
+{"name": "robert sykosky"},
+{"name": "shane hogan"},
+{"name": "angie burdette"},
+{"name": "anne fink"},
+{"name": "rafael martinez"},
+{"name": "jim nutt"},
+{"name": "paul cordell"},
+{"name": "jayme beach"},
+{"name": "justin mibradt"},
+{"name": "demetrius cobb"},
+{"name": "dan mayo"},
+{"name": "erica stockfish"},
+{"name": "nancy painter"},
+{"name": "jason whittle"},
+{"name": "april wilson"},
+{"name": "ina risman"},
+{"name": "joanie williams"},
+{"name": "matt lacroix"},
+{"name": "lorna wright"},
+{"name": "malinda steele"},
+{"name": "michelle newman"},
+{"name": "ethan gee"},
+{"name": "mary wallace"},
+{"name": "gene brown"},
+{"name": "lauren simmonsen"},
+{"name": "kristin woods"},
+{"name": "nick agostino"},
+{"name": "ann seamons"},
+{"name": "lauren aycock"},
+{"name": "debra frame"},
+{"name": "erin hunsinger"},
+{"name": "greg harris"},
+{"name": "brad rain"},
+{"name": "steven lee"},
+{"name": "debra kolosh"},
+{"name": "nancy annunziata"},
+{"name": "tracy cayolle"},
+{"name": "matthew koth"},
+{"name": "katina adams"},
+{"name": "douglas mccormick"},
+{"name": "sara hunter"},
+{"name": "terri dugan"},
+{"name": "kaitlyn trobaugh"},
+{"name": "pam fulmer"},
+{"name": "andrew suzsuki"},
+{"name": "mike filippone"},
+{"name": "crystal cooper"},
+{"name": "richard olson"},
+{"name": "ora fisher"},
+{"name": "susan carlson"},
+{"name": "paul heiselmann"},
+{"name": "kyle crook"},
+{"name": "joy motisi"},
+{"name": "evonne t"},
+{"name": "chris hardy"},
+{"name": "adrian v"},
+{"name": "david andersen"},
+{"name": "john bondy"},
+{"name": "melissa waller"},
+{"name": "ron oliver"},
+{"name": "bob beleson"},
+{"name": "al peterson"},
+{"name": "anthony papaleo"},
+{"name": "mike stankiewicz"},
+{"name": "jerry rondonelli"},
+{"name": "cole hambalton"},
+{"name": "denise lasher"},
+{"name": "jan cruz"},
+{"name": "tony cook"},
+{"name": "jon schleichkorn"},
+{"name": "ruben paredes"},
+{"name": "joe lynch"},
+{"name": "becky vezakis"},
+{"name": "ann salvestrini"},
+{"name": "elena valle"},
+{"name": "ebony cash"},
+{"name": "darryl deagle"},
+{"name": "jason broadwater"},
+{"name": "todd waylan"},
+{"name": "ray decker"},
+{"name": "jessica hawes"},
+{"name": "devin flames"},
+{"name": "christina angeles"},
+{"name": "christopher linderman"},
+{"name": "beverly cell"},
+{"name": "melissa stratton"},
+{"name": "leona breece"},
+{"name": "roberta hamer"},
+{"name": "jon raus"},
+{"name": "jill wittekind"},
+{"name": "kayla blanton"},
+{"name": "lori masi"},
+{"name": "maureen bausch"},
+{"name": "brandon haenel"},
+{"name": "jessica wilkinson"},
+{"name": "ryan gales"},
+{"name": "bruce dugdale"},
+{"name": "charlie laburi"},
+{"name": "mark brown"},
+{"name": "tom forms"},
+{"name": "pat wills"},
+{"name": "holly glass"},
+{"name": "gina durfee"},
+{"name": "karen ryan"},
+{"name": "patti wood"},
+{"name": "eunice groves"},
+{"name": "beverly endsley"},
+{"name": "aaron payne"},
+{"name": "candy falk"},
+{"name": "april combs"},
+{"name": "cheryl lansing"},
+{"name": "daryl carson"},
+{"name": "michael schoenholz"},
+{"name": "patrick ward"},
+{"name": "lori rhodes"},
+{"name": "chris young"},
+{"name": "stephen nyquist"},
+{"name": "mike berber"},
+{"name": "cory williams"},
+{"name": "otha gilyard"},
+{"name": "craig wincey"},
+{"name": "bob fries"},
+{"name": "monica lily"},
+{"name": "jon lin"},
+{"name": "chris braley"},
+{"name": "jose perea"},
+{"name": "angie pugens"},
+{"name": "craig dembeck"},
+{"name": "steve freeman"},
+{"name": "jennifer gerstenberg"},
+{"name": "timothy pittman"},
+{"name": "stacey pretz"},
+{"name": "linda pioneer"},
+{"name": "mckenzie prudential"},
+{"name": "alex woodford"},
+{"name": "leanne adams"},
+{"name": "omar arzate"},
+{"name": "wendy lussier"},
+{"name": "jamie keatts"},
+{"name": "tom atherton"},
+{"name": "stacy mcdowell"},
+{"name": "irma moody"},
+{"name": "jen parker"},
+{"name": "dina gonzales"},
+{"name": "patti knoll"},
+{"name": "sabrina nguyen"},
+{"name": "juan felix"},
+{"name": "josh lawson"},
+{"name": "david lampe"},
+{"name": "jennifer hawes"},
+{"name": "joe cornejo"},
+{"name": "kelly s"},
+{"name": "larry pinkston"},
+{"name": "kylie o'day"},
+{"name": "grace tsau"},
+{"name": "bob flannigan"},
+{"name": "don bianco"},
+{"name": "giovanni degidio"},
+{"name": "jerry hiller"},
+{"name": "lynette cummins"},
+{"name": "fred jenkins"},
+{"name": "michael lwin"},
+{"name": "kaitlyn sill"},
+{"name": "leland daniels"},
+{"name": "jon lundblad"},
+{"name": "mary pattillo"},
+{"name": "casey venediktova"},
+{"name": "melissa tackett"},
+{"name": "paula jones"},
+{"name": "britany allen"},
+{"name": "christine villareal"},
+{"name": "van valkenburg"},
+{"name": "morris chan"},
+{"name": "mike tmo"},
+{"name": "daniel gaertner"},
+{"name": "gregory bayless"},
+{"name": "darin b"},
+{"name": "bella leatherman"},
+{"name": "michelle arsenault"},
+{"name": "carole clause"},
+{"name": "bryce banning"},
+{"name": "dan klausmeyer"},
+{"name": "chad lyman"},
+{"name": "robert uy"},
+{"name": "ivey sidoti"},
+{"name": "lee vilardo"},
+{"name": "jerry klein"},
+{"name": "bob muskego"},
+{"name": "katie keenan"},
+{"name": "andy acker"},
+{"name": "ryan eaton"},
+{"name": "kim ware"},
+{"name": "perry khosroupry"},
+{"name": "patty fisher"},
+{"name": "ruth rich"},
+{"name": "michael christenson"},
+{"name": "marisa strauss"},
+{"name": "howard pool"},
+{"name": "joan provencher"},
+{"name": "mark chamama"},
+{"name": "kenneth wirt"},
+{"name": "jim mapstead"},
+{"name": "angel odgen"},
+{"name": "pamela farrell"},
+{"name": "keith basketball"},
+{"name": "brandon doran"},
+{"name": "andy zehnder"},
+{"name": "matt coach"},
+{"name": "jeff kline"},
+{"name": "sean grimmett"},
+{"name": "katy m"},
+{"name": "john crosby"},
+{"name": "terry sanchez"},
+{"name": "orlando uranga"},
+{"name": "dana pinnick"},
+{"name": "ashley james"},
+{"name": "jessica raphael"},
+{"name": "rebecca lee"},
+{"name": "ruben dominguez"},
+{"name": "tangela crawford"},
+{"name": "dave doc"},
+{"name": "justin peterson"},
+{"name": "john argall"},
+{"name": "judy cabrera"},
+{"name": "duane hartlep"},
+{"name": "philip stack"},
+{"name": "daniel martinez"},
+{"name": "paul benson"},
+{"name": "loretta harris"},
+{"name": "alex bornokov"},
+{"name": "sandie crook"},
+{"name": "denna michail"},
+{"name": "richard pike"},
+{"name": "dave krawczyk"},
+{"name": "joe minerd"},
+{"name": "steve huckaby"},
+{"name": "ken lil"},
+{"name": "betty crow"},
+{"name": "greg facktor"},
+{"name": "grady willun"},
+{"name": "tam cordial"},
+{"name": "roger delzer"},
+{"name": "sandra poole"},
+{"name": "bruce hancock"},
+{"name": "daniel miller"},
+{"name": "jill riola"},
+{"name": "layne peterson"},
+{"name": "andrew chevrolet"},
+{"name": "joe napientek"},
+{"name": "dave laurentino"},
+{"name": "brittney mayfield"},
+{"name": "susan black"},
+{"name": "ervin wilkerson"},
+{"name": "stephanie rush"},
+{"name": "gordon hunt"},
+{"name": "eric jenna"},
+{"name": "pia triquell"},
+{"name": "tyson yirak"},
+{"name": "hector corrales"},
+{"name": "norma leon"},
+{"name": "yu joseph"},
+{"name": "lindsey oppedisano"},
+{"name": "brad metzger"},
+{"name": "marcia deans"},
+{"name": "kathy totsch"},
+{"name": "lisa lak"},
+{"name": "tony robinson"},
+{"name": "ed devlin"},
+{"name": "edward manche"},
+{"name": "rick kreczmer"},
+{"name": "jim lauret"},
+{"name": "neal house"},
+{"name": "andy boyer"},
+{"name": "dennis turner"},
+{"name": "janet platt"},
+{"name": "shelley simpson"},
+{"name": "tom banks"},
+{"name": "shelly kramer"},
+{"name": "rich roomie"},
+{"name": "anh hunter"},
+{"name": "cindy gallagher"},
+{"name": "gail tolliver"},
+{"name": "paul smith"},
+{"name": "cole corwin"},
+{"name": "karri thompson"},
+{"name": "caleb forrest"},
+{"name": "mike heber"},
+{"name": "deandre washington"},
+{"name": "matt honson"},
+{"name": "anthony ayala"},
+{"name": "grant stucker"},
+{"name": "kim jungck"},
+{"name": "martin martinez"},
+{"name": "karen johannaber"},
+{"name": "brad amos"},
+{"name": "gabriel alvarado"},
+{"name": "kirk barton"},
+{"name": "frank trujillo"},
+{"name": "wendy eckert"},
+{"name": "magdalena mendoza"},
+{"name": "alan soudakoff"},
+{"name": "marjorie cell"},
+{"name": "matt colarusso"},
+{"name": "tom valdez"},
+{"name": "todd moody"},
+{"name": "robert mellor"},
+{"name": "sandy horner"},
+{"name": "justin kerner"},
+{"name": "allen whitaker"},
+{"name": "eric rogers"},
+{"name": "scott tibbitts"},
+{"name": "brianna s"},
+{"name": "carolyn bryan"},
+{"name": "joyce honda"},
+{"name": "susan steinert"},
+{"name": "mable porter"},
+{"name": "brittany leonard"},
+{"name": "daryl newell"},
+{"name": "jim rathgeber"},
+{"name": "craig husa"},
+{"name": "rob horn"},
+{"name": "mary giles"},
+{"name": "stephanie pope"},
+{"name": "sun club"},
+{"name": "isabel off"},
+{"name": "marcia hudson"},
+{"name": "chandra dominguez"},
+{"name": "wayne boswell"},
+{"name": "kendall herzer"},
+{"name": "cynthia redding"},
+{"name": "edwin barnes"},
+{"name": "keith mills"},
+{"name": "mark falco"},
+{"name": "james draaaper"},
+{"name": "howard emery"},
+{"name": "brian gray"},
+{"name": "stewart varich"},
+{"name": "barbara m"},
+{"name": "michelle ferrise"},
+{"name": "ramon zabriskie"},
+{"name": "betsy everett"},
+{"name": "gary lairson"},
+{"name": "jade epps"},
+{"name": "linda dalpe"},
+{"name": "zachary voegler"},
+{"name": "sam t"},
+{"name": "claudia sconion"},
+{"name": "page whitman"},
+{"name": "jim fanning"},
+{"name": "jennifer minuchi"},
+{"name": "monika friend"},
+{"name": "lorna pack"},
+{"name": "george szenczy"},
+{"name": "george gay"},
+{"name": "rick topper"},
+{"name": "carolina quintana"},
+{"name": "joel taylor"},
+{"name": "latrice totsch"},
+{"name": "john kouri"},
+{"name": "kristen mayfield"},
+{"name": "john cox"},
+{"name": "lisa ellrod"},
+{"name": "stephanie bywater"},
+{"name": "timothy randall"},
+{"name": "rick cenex"},
+{"name": "jarrett lewis"},
+{"name": "walter marshall"},
+{"name": "mike nuzzolese"},
+{"name": "scott alcorn"},
+{"name": "tony c"},
+{"name": "chris robin"},
+{"name": "william owens"},
+{"name": "tiffany henry"},
+{"name": "don ensign"},
+{"name": "albert son"},
+{"name": "jackie bos"},
+{"name": "andrew asch"},
+{"name": "fran epstein"},
+{"name": "lauren whitney"},
+{"name": "keith foote"},
+{"name": "christina barber"},
+{"name": "earl campbell"},
+{"name": "todd becker"},
+{"name": "douglas hawn"},
+{"name": "ted hosmer"},
+{"name": "george koumaras"},
+{"name": "patty hickey"},
+{"name": "adrian balderas"},
+{"name": "todd hensel"},
+{"name": "christine watanabe"},
+{"name": "heidi christensen"},
+{"name": "terri sacks"},
+{"name": "chase sudlah"},
+{"name": "paul luce"},
+{"name": "lisa mcnamee"},
+{"name": "danny nessett"},
+{"name": "craig jones"},
+{"name": "dave rooster"},
+{"name": "bill difranco"},
+{"name": "sharon polonia"},
+{"name": "john dunne"},
+{"name": "joe lr"},
+{"name": "mike bauer"},
+{"name": "michelle reines"},
+{"name": "joey fedor"},
+{"name": "frank asberry"},
+{"name": "anita bruckner"},
+{"name": "carrie koltz"},
+{"name": "billy roberts"},
+{"name": "mark stavrakis"},
+{"name": "barry blair"},
+{"name": "pam holliman"},
+{"name": "lisa bar"},
+{"name": "tom maduell"},
+{"name": "ronald schlosser"},
+{"name": "jesse m"},
+{"name": "danny rimer"},
+{"name": "peter fear"},
+{"name": "allan goodman"},
+{"name": "karen schumann"},
+{"name": "brande denton"},
+{"name": "jeri coulson"},
+{"name": "chris chlarson"},
+{"name": "erin rusch"},
+{"name": "chris cube"},
+{"name": "kristin campbell"},
+{"name": "jaime price"},
+{"name": "chris womack"},
+{"name": "adam morgan"},
+{"name": "dennis fredrickson"},
+{"name": "freddy rodriguez"},
+{"name": "brian winkler"},
+{"name": "tom bienkowski"},
+{"name": "jonathan ruane"},
+{"name": "jennifer clements"},
+{"name": "wes king"},
+{"name": "andy wong"},
+{"name": "jose zavala"},
+{"name": "frank buda"},
+{"name": "lee g"},
+{"name": "andres blummer"},
+{"name": "vikki thomson"},
+{"name": "barbara saalman"},
+{"name": "bill ngo"},
+{"name": "bobby burgess"},
+{"name": "marissa kerby"},
+{"name": "percy escalante"},
+{"name": "antione finley"},
+{"name": "andy johnson"},
+{"name": "russ lowd"},
+{"name": "danny goldstein"},
+{"name": "jocelyn strauber"},
+{"name": "denise tws"},
+{"name": "judy snyder"},
+{"name": "joey cain"},
+{"name": "saul podemski"},
+{"name": "jade mills"},
+{"name": "chery dean"},
+{"name": "margaret dixon"},
+{"name": "james gomez"},
+{"name": "duane dean"},
+{"name": "jim patterson"},
+{"name": "nicole harmelink"},
+{"name": "warren wong"},
+{"name": "jason h"},
+{"name": "robert carreon"},
+{"name": "jill tsugawa"},
+{"name": "catherine stringer"},
+{"name": "dennis fabro"},
+{"name": "florida home"},
+{"name": "mary shearer"},
+{"name": "pattie salazar"},
+{"name": "tony do"},
+{"name": "laura may"},
+{"name": "ed nassan"},
+{"name": "mike cripe"},
+{"name": "robert moye"},
+{"name": "dan johnston"},
+{"name": "michael hollingsworth"},
+{"name": "nick jonesy"},
+{"name": "linda tax"},
+{"name": "lenny smith"},
+{"name": "shoshana goldfeld"},
+{"name": "krista nagley"},
+{"name": "adam grayer"},
+{"name": "joyce wheeler"},
+{"name": "jason tan"},
+{"name": "eugene smith"},
+{"name": "neil droppers"},
+{"name": "emily vanbebber"},
+{"name": "walker mortuary"},
+{"name": "carol gines"},
+{"name": "johnny cano"},
+{"name": "steve morgan"},
+{"name": "mark gardner"},
+{"name": "mara holley"},
+{"name": "victor rucans"},
+{"name": "mario scarface"},
+{"name": "anthony ruberto"},
+{"name": "lucy lapraim"},
+{"name": "morris insurance"},
+{"name": "erica fox"},
+{"name": "collin read"},
+{"name": "tara yochum"},
+{"name": "mary d"},
+{"name": "john perlman"},
+{"name": "craig valkenburg"},
+{"name": "jonathan hilton"},
+{"name": "ann keisha"},
+{"name": "shannon clark"},
+{"name": "mary ching"},
+{"name": "mike yovon"},
+{"name": "joel gunstream"},
+{"name": "tony whitham"},
+{"name": "sharon morlock"},
+{"name": "mike kissane"},
+{"name": "liberty mutual"},
+{"name": "jim jenkins"},
+{"name": "linda scott"},
+{"name": "lenny c"},
+{"name": "nick base"},
+{"name": "randy weinstein"},
+{"name": "brandon roque"},
+{"name": "diane wieland"},
+{"name": "richard grow"},
+{"name": "erik baumgarten"},
+{"name": "darren schnell"},
+{"name": "josh myers"},
+{"name": "mike breit"},
+{"name": "jim hands"},
+{"name": "isidro castorena"},
+{"name": "alan stephens"},
+{"name": "jose posado"},
+{"name": "nathalie imbault"},
+{"name": "thad trub"},
+{"name": "bobbi primo"},
+{"name": "timmy griffen"},
+{"name": "john gurasich"},
+{"name": "chris salo"},
+{"name": "chris kappos"},
+{"name": "john ariaga"},
+{"name": "kim schulte"},
+{"name": "samantha holler"},
+{"name": "holly mcgrath"},
+{"name": "paul noonan"},
+{"name": "scott wallman"},
+{"name": "lisa culver"},
+{"name": "gregory white"},
+{"name": "lydia cai"},
+{"name": "rick kam"},
+{"name": "david jirku"},
+{"name": "mike kotc"},
+{"name": "katie kurtz"},
+{"name": "alicia work"},
+{"name": "joyce caldwell"},
+{"name": "brice horning"},
+{"name": "craig telford"},
+{"name": "dave holmes"},
+{"name": "cynthia hanke"},
+{"name": "alicia koon"},
+{"name": "steven king"},
+{"name": "jane windsor"},
+{"name": "ed tarbox"},
+{"name": "margaret copeland"},
+{"name": "frank alverio"},
+{"name": "austin jenkins"},
+{"name": "michael cipollone"},
+{"name": "ann carmichael"},
+{"name": "dale vick"},
+{"name": "john possey"},
+{"name": "timothy melton"},
+{"name": "david rubin"},
+{"name": "jay cell"},
+{"name": "alan richins"},
+{"name": "jesse pedroza"},
+{"name": "jenna dobkin"},
+{"name": "ed perkins"},
+{"name": "nikki hall"},
+{"name": "mike wannemacher"},
+{"name": "barry preusch"},
+{"name": "rhonda martin"},
+{"name": "russell caddy"},
+{"name": "milan eaton"},
+{"name": "paul flaherty"},
+{"name": "erika soto"},
+{"name": "matt simon"},
+{"name": "sue czubala"},
+{"name": "robin anderson"},
+{"name": "beau roy"},
+{"name": "greg king"},
+{"name": "neal saarella"},
+{"name": "peter kim"},
+{"name": "mike pate"},
+{"name": "dani hines"},
+{"name": "dave steger"},
+{"name": "cortney mills"},
+{"name": "heather thorstenson"},
+{"name": "gina house"},
+{"name": "shannon mazza"},
+{"name": "rick warren"},
+{"name": "clara boudreaux"},
+{"name": "florence nurse"},
+{"name": "laura grandados"},
+{"name": "doug zimmerman"},
+{"name": "adrian gladenier"},
+{"name": "benjamin reigle"},
+{"name": "nicole french"},
+{"name": "russ henrichsen"},
+{"name": "frank mayer"},
+{"name": "russ helwig"},
+{"name": "david chandler"},
+{"name": "janet hardin"},
+{"name": "jaunita saldivar"},
+{"name": "alphonso callis"},
+{"name": "sandy lodge"},
+{"name": "jason becky"},
+{"name": "ronald graham"},
+{"name": "emily robison"},
+{"name": "steven leiberman"},
+{"name": "scott hinsperger"},
+{"name": "clayton lau"},
+{"name": "rich white"},
+{"name": "enrique morales"},
+{"name": "tom fetters"},
+{"name": "richard keefer"},
+{"name": "jose seijas"},
+{"name": "bob merriwether"},
+{"name": "kasey work"},
+{"name": "dick shinee"},
+{"name": "gene wright"},
+{"name": "casey baucum"},
+{"name": "holly mion"},
+{"name": "alexis homee"},
+{"name": "casey trupin"},
+{"name": "lauren sum"},
+{"name": "kenneth erickson"},
+{"name": "lucas armena"},
+{"name": "carla smith"},
+{"name": "bill swindells"},
+{"name": "winston hughs"},
+{"name": "tammy mailhot"},
+{"name": "carla murphy"},
+{"name": "bryon elkins"},
+{"name": "jennifer evans"},
+{"name": "scott mayer"},
+{"name": "andrew crossett"},
+{"name": "toney lindsey"},
+{"name": "phillip stead"},
+{"name": "dana fish"},
+{"name": "valerie post"},
+{"name": "brandon vzw"},
+{"name": "jen escobar"},
+{"name": "jessi may"},
+{"name": "andrew gonzalez"},
+{"name": "greg derin"},
+{"name": "amanda comer"},
+{"name": "debra garcia"},
+{"name": "brian canfield"},
+{"name": "ken chang"},
+{"name": "pat burkby"},
+{"name": "donnie bilnoski"},
+{"name": "monica dennison"},
+{"name": "heather barrie"},
+{"name": "ivonne funes"},
+{"name": "debbie conrad"},
+{"name": "bob isaacs"},
+{"name": "elena gifton"},
+{"name": "todd washwholesale"},
+{"name": "justin t"},
+{"name": "richard smith"},
+{"name": "antonia coleman"},
+{"name": "dan oliver"},
+{"name": "carol thompson"},
+{"name": "tyler losman"},
+{"name": "sandy lash"},
+{"name": "eileen mal"},
+{"name": "kurt rao"},
+{"name": "rosanna muniz"},
+{"name": "chuck w"},
+{"name": "frances stichel"},
+{"name": "tracey wrk"},
+{"name": "chris rhue"},
+{"name": "jay hendrix"},
+{"name": "andy hardwick"},
+{"name": "jana allen"},
+{"name": "andrew orman"},
+{"name": "jack goldsberry"},
+{"name": "miguel benavides"},
+{"name": "tanya peralto"},
+{"name": "john gonzales"},
+{"name": "eric bushe"},
+{"name": "robin bartlett"},
+{"name": "meghan tyre"},
+{"name": "brian reeves"},
+{"name": "jeremy french"},
+{"name": "jacqueline ackerman"},
+{"name": "sonya jeanotte"},
+{"name": "mike ciaccia"},
+{"name": "steve coonce"},
+{"name": "melinda gatheright"},
+{"name": "eric aerni"},
+{"name": "andrew brooks"},
+{"name": "bo crear"},
+{"name": "stacy aab"},
+{"name": "greg brunswick"},
+{"name": "nancy kochis"},
+{"name": "becky mccutcheon"},
+{"name": "stephen yaffey"},
+{"name": "mike sexton"},
+{"name": "jennifer mccue"},
+{"name": "sarah zhu"},
+{"name": "ken eady"},
+{"name": "burt ferrini"},
+{"name": "nikki olson"},
+{"name": "perla pesqueira"},
+{"name": "eric hunker"},
+{"name": "chris jamison"},
+{"name": "ali wrk"},
+{"name": "albert berger"},
+{"name": "jess terrel"},
+{"name": "raven taylor"},
+{"name": "gil bernardino"},
+{"name": "rose d"},
+{"name": "everett hs"},
+{"name": "josh s"},
+{"name": "veronica lawton"},
+{"name": "art posch"},
+{"name": "shawn kenon"},
+{"name": "anthony valentini"},
+{"name": "beth jacober"},
+{"name": "lawrence gan"},
+{"name": "allison levinson"},
+{"name": "michael vallejo"},
+{"name": "alan anthony"},
+{"name": "alan goodsitt"},
+{"name": "samantha ward"},
+{"name": "shannon mckenna"},
+{"name": "emily tillery"},
+{"name": "giovanni taylor"},
+{"name": "christi carter"},
+{"name": "jack lawton"},
+{"name": "jaime meraz"},
+{"name": "brenda staley"},
+{"name": "anissa galifant"},
+{"name": "robert ceballos"},
+{"name": "jonathan sopha"},
+{"name": "joe menta"},
+{"name": "shane bombay"},
+{"name": "john tomaski"},
+{"name": "bryce tychsen"},
+{"name": "jennifer lauriello"},
+{"name": "ron retterer"},
+{"name": "roman zubrytsky"},
+{"name": "stephen work"},
+{"name": "joshua johnston"},
+{"name": "mary maclean"},
+{"name": "kelly p"},
+{"name": "daniel zahler"},
+{"name": "cody pope"},
+{"name": "david muller"},
+{"name": "danny shaw"},
+{"name": "jennifer ridgeway"},
+{"name": "cindy heim"},
+{"name": "phillip peacock"},
+{"name": "troy kimpton"},
+{"name": "deb brandt"},
+{"name": "marty wikstrom"},
+{"name": "jeff evans"},
+{"name": "john large"},
+{"name": "grace seman"},
+{"name": "vicki veatch"},
+{"name": "amy beaupre"},
+{"name": "kathleen models"},
+{"name": "brian hicks"},
+{"name": "paul sami"},
+{"name": "heather wachter"},
+{"name": "rolf schild"},
+{"name": "marcus linda"},
+{"name": "jim birmingham"},
+{"name": "nick lenert"},
+{"name": "brenda beane"},
+{"name": "bill lopez"},
+{"name": "bryon courter"},
+{"name": "erin fuentecilla"},
+{"name": "phil mcdonald"},
+{"name": "michelle harrocks"},
+{"name": "clayton beck"},
+{"name": "laurie ruby"},
+{"name": "cristal mohrman"},
+{"name": "charles bits"},
+{"name": "jenna ozland"},
+{"name": "karen casa"},
+{"name": "dennis clark"},
+{"name": "tobias oceguera"},
+{"name": "jeffrey tinney"},
+{"name": "jeff case"},
+{"name": "sean bryant"},
+{"name": "ken kiser"},
+{"name": "janet hintz"},
+{"name": "roland oliver"},
+{"name": "ruben arenas"},
+{"name": "david peggy"},
+{"name": "jimmy gallagher"},
+{"name": "penny harrington"},
+{"name": "peter derba"},
+{"name": "pam davis"},
+{"name": "brian riebow"},
+{"name": "brandon stewart"},
+{"name": "dewayne martin"},
+{"name": "ray tarpley"},
+{"name": "james burkhart"},
+{"name": "joseph ocasio"},
+{"name": "timothy benjamin"},
+{"name": "paul morgan"},
+{"name": "nicki estrada"},
+{"name": "paul bouchard"},
+{"name": "travis edwards"},
+{"name": "michael luhrs"},
+{"name": "courtney traphagan"},
+{"name": "byron colton"},
+{"name": "kurt harris"},
+{"name": "michael carlson"},
+{"name": "joe ryan"},
+{"name": "julie sams"},
+{"name": "mike ranone"},
+{"name": "phil lloyd"},
+{"name": "angie massey"},
+{"name": "tom carpino"},
+{"name": "jeni mclaughlin"},
+{"name": "kelly dibiagio"},
+{"name": "rory baumstein"},
+{"name": "john kolonich"},
+{"name": "jamie forbes"},
+{"name": "ian gleadle"},
+{"name": "tom zn"},
+{"name": "marc andres"},
+{"name": "susan mazrui"},
+{"name": "jen thomas"},
+{"name": "sarah lasko"},
+{"name": "andy johnston"},
+{"name": "diane reineke"},
+{"name": "steve scheppler"},
+{"name": "britt inn"},
+{"name": "kristin poppe"},
+{"name": "april lomibao"},
+{"name": "jeremy michalosky"},
+{"name": "doug romer"},
+{"name": "luis beserra"},
+{"name": "jessica deforest"},
+{"name": "jack hilton"},
+{"name": "gregory kesmetis"},
+{"name": "tim renyer"},
+{"name": "james jarmusch"},
+{"name": "jack byas"},
+{"name": "nadine graham"},
+{"name": "tommy toledo"},
+{"name": "mark hoefer"},
+{"name": "kerry slaughter"},
+{"name": "victor herrera"},
+{"name": "al alam"},
+{"name": "rene worthey"},
+{"name": "lawrence guo"},
+{"name": "crystal sexxy"},
+{"name": "sonia butler"},
+{"name": "tyler journeys"},
+{"name": "chelsea plumb"},
+{"name": "carl smith"},
+{"name": "peter wilson"},
+{"name": "ryan meyers"},
+{"name": "mike bjork"},
+{"name": "alexander nguyen"},
+{"name": "billy daniel"},
+{"name": "john ta"},
+{"name": "ralph knight"},
+{"name": "warren epps"},
+{"name": "john tsourounis"},
+{"name": "brian wine"},
+{"name": "andrew polioungas"},
+{"name": "michelle cina"},
+{"name": "mike bodkin"},
+{"name": "jane hsiung"},
+{"name": "jean smith"},
+{"name": "jeramy thomas"},
+{"name": "sarah ipc"},
+{"name": "dan carlson"},
+{"name": "becky jordan"},
+{"name": "rodney peart"},
+{"name": "ryan gust"},
+{"name": "rick marinelli"},
+{"name": "tom mangum"},
+{"name": "michelle adkisson"},
+{"name": "rachel o'shields"},
+{"name": "natalie delong"},
+{"name": "shaun t"},
+{"name": "jennifer chang"},
+{"name": "juliana donovan"},
+{"name": "rachael thayer"},
+{"name": "danny abramson"},
+{"name": "charlotte allen"},
+{"name": "mike bowe"},
+{"name": "courtney sears"},
+{"name": "crystal lia"},
+{"name": "connie phillips"},
+{"name": "tracey bond"},
+{"name": "rob tantric"},
+{"name": "gail brower"},
+{"name": "marla aunt"},
+{"name": "elizabeth harris"},
+{"name": "alex ruelas"},
+{"name": "tracy weslosky"},
+{"name": "anthony pennachio"},
+{"name": "steve weyland"},
+{"name": "joe schuck"},
+{"name": "chris etling"},
+{"name": "cheri jennings"},
+{"name": "randall moore"},
+{"name": "carl compagner"},
+{"name": "peggy meidinger"},
+{"name": "tyron mcdonald"},
+{"name": "george salon"},
+{"name": "kim hyde"},
+{"name": "alan stamp"},
+{"name": "josh faul"},
+{"name": "jesse orbe"},
+{"name": "frank balough"},
+{"name": "marco n"},
+{"name": "andrew schueler"},
+{"name": "roberta stitt"},
+{"name": "rodney muhammad"},
+{"name": "dennis carlo"},
+{"name": "ben devries"},
+{"name": "linda smalley"},
+{"name": "brian yau"},
+{"name": "joe devarian"},
+{"name": "james dickerson"},
+{"name": "bob ennis"},
+{"name": "scott gulley"},
+{"name": "samuel lekieffre"},
+{"name": "natalie mounier"},
+{"name": "philip scholz"},
+{"name": "jim huse"},
+{"name": "john minascalco"},
+{"name": "mark younger"},
+{"name": "nicholas jr"},
+{"name": "jim nuttal"},
+{"name": "jeffrey miller"},
+{"name": "terry s"},
+{"name": "clint sullivan"},
+{"name": "billy kamienski"},
+{"name": "thomas taylor"},
+{"name": "dan eichstead"},
+{"name": "sheila melo"},
+{"name": "tiffany h"},
+{"name": "carol taylor"},
+{"name": "jesse hepperly"},
+{"name": "michelle chatman"},
+{"name": "kenny lester"},
+{"name": "lonnie battle"},
+{"name": "jason christides"},
+{"name": "ronnie ocello"},
+{"name": "jack noblin"},
+{"name": "john harris"},
+{"name": "dee fox"},
+{"name": "michael christian"},
+{"name": "peggy b"},
+{"name": "amanda ellsworth"},
+{"name": "kristen sharp"},
+{"name": "greg bailly"},
+{"name": "freddie p"},
+{"name": "frederic dumais"},
+{"name": "andrew currie"},
+{"name": "greg frey"},
+{"name": "ted rusch"},
+{"name": "nicole pratt"},
+{"name": "joel justus"},
+{"name": "jorge work"},
+{"name": "summer smith"},
+{"name": "tom mcneill"},
+{"name": "aaron simo"},
+{"name": "christina liu"},
+{"name": "sandy brubaker"},
+{"name": "tina powell"},
+{"name": "issac ramos"},
+{"name": "greg keksi"},
+{"name": "don howe"},
+{"name": "karl blomback"},
+{"name": "laura russell"},
+{"name": "robert bella"},
+{"name": "cary pd"},
+{"name": "eric fearn"},
+{"name": "dan blt"},
+{"name": "marcus leblanc"},
+{"name": "al diguido"},
+{"name": "mark rufino"},
+{"name": "chris dildude"},
+{"name": "mike t"},
+{"name": "jimmy gonzales"},
+{"name": "william gonzalez"},
+{"name": "juan salazar"},
+{"name": "natalie turpan"},
+{"name": "jay jewel"},
+{"name": "nathalie roldan"},
+{"name": "miguel ramirez"},
+{"name": "rudy chech"},
+{"name": "mike ferrari"},
+{"name": "mike subin"},
+{"name": "john risdon"},
+{"name": "brian perez"},
+{"name": "anthony helbing"},
+{"name": "samantha sprint"},
+{"name": "lupe anaya"},
+{"name": "mark quintero"},
+{"name": "gabriel castillo"},
+{"name": "courtney howlett"},
+{"name": "brad bashford"},
+{"name": "amy tennessee"},
+{"name": "brittany piercy"},
+{"name": "cindi shump"},
+{"name": "emanuel green"},
+{"name": "ellen markman"},
+{"name": "maria guadarrama"},
+{"name": "kimberly o'hara"},
+{"name": "barbara lloyd"},
+{"name": "owen crean"},
+{"name": "anthony chiarel"},
+{"name": "craig urch"},
+{"name": "george sorenson"},
+{"name": "dean meyers"},
+{"name": "louie garnica"},
+{"name": "kurt niebel"},
+{"name": "chris girardi"},
+{"name": "ian mottershead"},
+{"name": "kim edge"},
+{"name": "william barton"},
+{"name": "maureen zebian"},
+{"name": "ron dixon"},
+{"name": "jeannine johnson"},
+{"name": "gene morphis"},
+{"name": "travis aunt"},
+{"name": "duncan thomasen"},
+{"name": "matt vancleave"},
+{"name": "justin hamby"},
+{"name": "alan tang"},
+{"name": "kathy tynen"},
+{"name": "susana gonzalez"},
+{"name": "ted stephan"},
+{"name": "marty ruvalcava"},
+{"name": "royce markey"},
+{"name": "fernando calvillo"},
+{"name": "calvin genna"},
+{"name": "melvin cheeks"},
+{"name": "danny le"},
+{"name": "luther snow"},
+{"name": "angie kay"},
+{"name": "kurt schurer"},
+{"name": "matt i"},
+{"name": "hans bok"},
+{"name": "shari lane"},
+{"name": "jodi payne"},
+{"name": "troy w"},
+{"name": "tiffany broadway"},
+{"name": "kate murray"},
+{"name": "shelby howard"},
+{"name": "stacey gould"},
+{"name": "mike flores"},
+{"name": "david spears"},
+{"name": "alex home"},
+{"name": "aaron ford"},
+{"name": "marcia primus"},
+{"name": "austin buxton"},
+{"name": "lynn wielder"},
+{"name": "mai cantho"},
+{"name": "fern brandt"},
+{"name": "darren olsen"},
+{"name": "cheryl stanton"},
+{"name": "rachel stone"},
+{"name": "andrew macneily"},
+{"name": "kaitlyn le"},
+{"name": "kaylene hayden"},
+{"name": "levi mochkin"},
+{"name": "sheila hair"},
+{"name": "sarah jankowski"},
+{"name": "jarrett new"},
+{"name": "christy taylor"},
+{"name": "carol berger"},
+{"name": "angie parents"},
+{"name": "amy won"},
+{"name": "alan pollock"},
+{"name": "steve punch"},
+{"name": "darryl stephens"},
+{"name": "paul jaksich"},
+{"name": "jack tomann"},
+{"name": "eric lisa"},
+{"name": "adam stettner"},
+{"name": "paul marquis"},
+{"name": "nicolas kammes"},
+{"name": "daniel aguilar"},
+{"name": "chris morakis"},
+{"name": "warren miller"},
+{"name": "pasquale cancelliere"},
+{"name": "fred jefferson"},
+{"name": "jeremy radcliffe"},
+{"name": "jim calcinari"},
+{"name": "adam silvan"},
+{"name": "ashley rascon"},
+{"name": "brad cabrera"},
+{"name": "peter cooperrider"},
+{"name": "sharon h"},
+{"name": "carrie thomson"},
+{"name": "mike mckaigg"},
+{"name": "melissa wan"},
+{"name": "ted upland"},
+{"name": "joseph biden"},
+{"name": "cathy stylist"},
+{"name": "jerry nelson"},
+{"name": "kim martell"},
+{"name": "madison computers"},
+{"name": "lauren garner"},
+{"name": "brian faust"},
+{"name": "jeffrey endervelt"},
+{"name": "peter dixon"},
+{"name": "jim bain"},
+{"name": "dan leech"},
+{"name": "joni bell"},
+{"name": "josh sims"},
+{"name": "tami doerr"},
+{"name": "ross ericksen"},
+{"name": "dale fischer"},
+{"name": "marcus hudson"},
+{"name": "jim spres"},
+{"name": "allison potter"},
+{"name": "shannon daniels"},
+{"name": "alex perversive"},
+{"name": "heather orosco"},
+{"name": "louis lockley"},
+{"name": "jefferson terrace"},
+{"name": "judith unwin"},
+{"name": "john bockman"},
+{"name": "larissa goldstein"},
+{"name": "amy meng"},
+{"name": "ana cowan"},
+{"name": "jeff filippi"},
+{"name": "geraldine limbo"},
+{"name": "natalie stephenson"},
+{"name": "ken jenkins"},
+{"name": "jeff ward"},
+{"name": "felipe sandoval"},
+{"name": "von foxy"},
+{"name": "jacob wilder"},
+{"name": "mike ayers"},
+{"name": "andrea ferguson"},
+{"name": "shane akeroyd"},
+{"name": "kim mgr"},
+{"name": "chris gurney"},
+{"name": "leon kurtz"},
+{"name": "robert jarmillo"},
+{"name": "megan walker"},
+{"name": "erica lesa"},
+{"name": "frances sandoval"},
+{"name": "david kermavner"},
+{"name": "jennifer montenegro"},
+{"name": "james sligar"},
+{"name": "juan soto"},
+{"name": "jayme wagner"},
+{"name": "amee godani"},
+{"name": "hugh hutchinson"},
+{"name": "wyatt wolf"},
+{"name": "lisa wall"},
+{"name": "diane bevis"},
+{"name": "bryan prach"},
+{"name": "nicole bernard"},
+{"name": "craig richardson"},
+{"name": "stuart baker"},
+{"name": "dan moore"},
+{"name": "gary figueroa"},
+{"name": "david rubinoff"},
+{"name": "rachel garcia"},
+{"name": "herb cell"},
+{"name": "steve long"},
+{"name": "jenny t"},
+{"name": "mark dulsky"},
+{"name": "kristina gardina"},
+{"name": "jack ducoffe"},
+{"name": "brad g"},
+{"name": "tammy ornelas"},
+{"name": "kimberly riley"},
+{"name": "erin ireland"},
+{"name": "rodney sampson"},
+{"name": "daniel rodiguez"},
+{"name": "sean wk"},
+{"name": "simon chan"},
+{"name": "robert moraga"},
+{"name": "gloria jones"},
+{"name": "kenneth green"},
+{"name": "kathy king"},
+{"name": "brady wrestling"},
+{"name": "cathy emmerth"},
+{"name": "carly salem"},
+{"name": "gary garza"},
+{"name": "vanessa colon"},
+{"name": "matt mcgraw"},
+{"name": "warren lenard"},
+{"name": "ed daniel"},
+{"name": "ryan logan"},
+{"name": "troy cushman"},
+{"name": "christy watts"},
+{"name": "chris mcadams"},
+{"name": "linda ghanim"},
+{"name": "michael mcevoy"},
+{"name": "beverly salbin"},
+{"name": "gretchen queen"},
+{"name": "keith essick"},
+{"name": "martin mckenna"},
+{"name": "alan perlstein"},
+{"name": "charlotte combs"},
+{"name": "erlinda ku"},
+{"name": "john harlan"},
+{"name": "vinnie leab"},
+{"name": "francis kesler"},
+{"name": "debbie lynch"},
+{"name": "jamie boldger"},
+{"name": "john quist"},
+{"name": "roberto diaz"},
+{"name": "sandra sanchez"},
+{"name": "carie rollman"},
+{"name": "raul aguirre"},
+{"name": "harry eksteen"},
+{"name": "lisa putt"},
+{"name": "kena nails"},
+{"name": "susan h"},
+{"name": "abby weiss"},
+{"name": "bert romero"},
+{"name": "steve bynam"},
+{"name": "jimmy dvd"},
+{"name": "hans larsen"},
+{"name": "kim hayes"},
+{"name": "dana odegaard"},
+{"name": "wayne shirley"},
+{"name": "brent klovstad"},
+{"name": "carla inkrote"},
+{"name": "jack eisenberger"},
+{"name": "mike odor"},
+{"name": "porsche derricks"},
+{"name": "michael lema"},
+{"name": "allan meyer"},
+{"name": "kim wells"},
+{"name": "florence sizemore"},
+{"name": "alicia herrera"},
+{"name": "derek munn"},
+{"name": "jim mahoney"},
+{"name": "john organic"},
+{"name": "mike luciano"},
+{"name": "james mcquivey"},
+{"name": "debbie turintine"},
+{"name": "curt uyemura"},
+{"name": "karen schwartz"},
+{"name": "steve barry's"},
+{"name": "claudia morales"},
+{"name": "clay sheperd"},
+{"name": "kenneth panitch"},
+{"name": "thomas clougherty"},
+{"name": "kareem bishop"},
+{"name": "jim abbey"},
+{"name": "rich stern"},
+{"name": "nicole tipton"},
+{"name": "luis r"},
+{"name": "nancy hildebrand"},
+{"name": "paul phillips"},
+{"name": "lauren kate"},
+{"name": "brittany h"},
+{"name": "kelly koski"},
+{"name": "nathan chavarria"},
+{"name": "jacob lebell"},
+{"name": "marie petros"},
+{"name": "jon ollmann"},
+{"name": "matt nurse"},
+{"name": "theresa wilcox"},
+{"name": "miguel munoz"},
+{"name": "peter blank"},
+{"name": "david moss"},
+{"name": "leonardo puig"},
+{"name": "josh estate"},
+{"name": "shari cell"},
+{"name": "susan donohoe"},
+{"name": "jason dailey"},
+{"name": "debbie leeson"},
+{"name": "phil friesen"},
+{"name": "matt kudrick"},
+{"name": "leon mazyn"},
+{"name": "dennis hood"},
+{"name": "julie lang"},
+{"name": "larry schmidt"},
+{"name": "sherry trotman"},
+{"name": "michelle robinson"},
+{"name": "lincoln may"},
+{"name": "cheryl makela"},
+{"name": "james klein"},
+{"name": "harriet mirow"},
+{"name": "tracey mccullough"},
+{"name": "amy harvischak"},
+{"name": "david cardoza"},
+{"name": "randy lavene"},
+{"name": "barb berg"},
+{"name": "steve mosley"},
+{"name": "mike hitchdick"},
+{"name": "sophie porzio"},
+{"name": "kristin ripple"},
+{"name": "liz sauter"},
+{"name": "ashlyn doctor"},
+{"name": "paul simon"},
+{"name": "lisa miller"},
+{"name": "christina hourani"},
+{"name": "sunny abouaravong"},
+{"name": "teresa hastings"},
+{"name": "jackson wong"},
+{"name": "jessie getz"},
+{"name": "andy parsons"},
+{"name": "angie b"},
+{"name": "rick zepp"},
+{"name": "daniel marquardt"},
+{"name": "eddie breit"},
+{"name": "blake drury"},
+{"name": "kris doubletree"},
+{"name": "daren trousdell"},
+{"name": "luis gil"},
+{"name": "matt aloisio"},
+{"name": "mario nigro"},
+{"name": "andres cmn"},
+{"name": "casey grimsley"},
+{"name": "chase ful"},
+{"name": "liz magura"},
+{"name": "tony thottukadavil"},
+{"name": "gloria montelongo"},
+{"name": "frances miller"},
+{"name": "daniel hopkins"},
+{"name": "missy cell"},
+{"name": "victor huerta"},
+{"name": "carolyn texter"},
+{"name": "lorena pineda"},
+{"name": "young life"},
+{"name": "anne vandercreek"},
+{"name": "kyle twin"},
+{"name": "larry marion"},
+{"name": "ashley steranka"},
+{"name": "anthony simmons"},
+{"name": "audrey hoyt"},
+{"name": "curt morton"},
+{"name": "shawn king"},
+{"name": "calvin walker"},
+{"name": "kendra hubick"},
+{"name": "glenn gerlach"},
+{"name": "kevin steck"},
+{"name": "jason rushing"},
+{"name": "carla christian"},
+{"name": "ricarda santiago"},
+{"name": "drew theodore"},
+{"name": "carlos alfonso"},
+{"name": "aaron brown"},
+{"name": "angel gomez"},
+{"name": "jodi wenger"},
+{"name": "rick heeley"},
+{"name": "stephan valkenburgh"},
+{"name": "todd ritter"},
+{"name": "tasha kahn"},
+{"name": "stacey wing"},
+{"name": "marc paquette"},
+{"name": "sara pfefer"},
+{"name": "wendy hoffman"},
+{"name": "loan phalm"},
+{"name": "cheryl gluckman"},
+{"name": "erik gallimore"},
+{"name": "steve goldware"},
+{"name": "cynthia kelly"},
+{"name": "darren hillman"},
+{"name": "tom crawford"},
+{"name": "tony santoro"},
+{"name": "debra welsh"},
+{"name": "richie belli"},
+{"name": "john pc"},
+{"name": "tara soward"},
+{"name": "michael ruscetta"},
+{"name": "amanda swanson"},
+{"name": "lynda gould"},
+{"name": "kirk roadshop"},
+{"name": "angela hunt"},
+{"name": "kelley clark"},
+{"name": "mira kheny"},
+{"name": "ken rodhe"},
+{"name": "bee thao"},
+{"name": "heather sternberg"},
+{"name": "robin s"},
+{"name": "diane smith"},
+{"name": "jeff giesler"},
+{"name": "emily buckeye"},
+{"name": "brad oviatt"},
+{"name": "joanne sapadin"},
+{"name": "paul xxxxx"},
+{"name": "max iunlock"},
+{"name": "ann hanswirth"},
+{"name": "marlon harvey"},
+{"name": "darlene carreau"},
+{"name": "rebecca wall"},
+{"name": "charles barker"},
+{"name": "chris lascola"},
+{"name": "leisa farmers"},
+{"name": "bart springer"},
+{"name": "chris lacroix"},
+{"name": "john sabelka"},
+{"name": "geraldine owens"},
+{"name": "ernest pastor"},
+{"name": "rebecca butler"},
+{"name": "alfred krammer"},
+{"name": "leslie tracy"},
+{"name": "kareem boyce"},
+{"name": "pete conduragis"},
+{"name": "jacob myatt"},
+{"name": "tina farina"},
+{"name": "john ambule"},
+{"name": "keith savage"},
+{"name": "steve sutherland"},
+{"name": "tammy cardenas"},
+{"name": "dustin weible"},
+{"name": "todd hanyo"},
+{"name": "tammy b"},
+{"name": "keith waller"},
+{"name": "jose celo"},
+{"name": "tam wells"},
+{"name": "pia esthetics"},
+{"name": "jerry o'neal"},
+{"name": "michelle lynch"},
+{"name": "leroy scharfenberg"},
+{"name": "annette wegner"},
+{"name": "duane bascum"},
+{"name": "ron hunt"},
+{"name": "justin tony"},
+{"name": "mai mcvey"},
+{"name": "lee jones"},
+{"name": "erik lowery"},
+{"name": "rey reyes"},
+{"name": "stephen greigo"},
+{"name": "krista snider"},
+{"name": "kim garnett"},
+{"name": "gail tofil"},
+{"name": "steven decker"},
+{"name": "douglas anderson"},
+{"name": "emil khodorkovsky"},
+{"name": "enoch driscoll"},
+{"name": "charles poole"},
+{"name": "heather howard"},
+{"name": "megan cell"},
+{"name": "dave rigotti"},
+{"name": "michelle mayes"},
+{"name": "jay colbert"},
+{"name": "michelle payne"},
+{"name": "kim carson"},
+{"name": "al garnier"},
+{"name": "doug meads"},
+{"name": "greg crowly"},
+{"name": "wade jacobson"},
+{"name": "justin c"},
+{"name": "jeff ekback"},
+{"name": "aaron daru"},
+{"name": "ellis money"},
+{"name": "nicole wells"},
+{"name": "whitney verizon"},
+{"name": "joel may"},
+{"name": "ashley gr"},
+{"name": "linda linebaugh"},
+{"name": "brandon prudent"},
+{"name": "juan bautista"},
+{"name": "darren lister"},
+{"name": "nick dobron"},
+{"name": "jeremy davis"},
+{"name": "brittany belger"},
+{"name": "tanya carter"},
+{"name": "laura anzaldi"},
+{"name": "jeff plant"},
+{"name": "joe woo"},
+{"name": "maria devine"},
+{"name": "robert coler"},
+{"name": "mary sanchez"},
+{"name": "alan wheeler"},
+{"name": "lori rush"},
+{"name": "rob gill"},
+{"name": "suzanne anderson"},
+{"name": "karen rhees"},
+{"name": "kathy danneman"},
+{"name": "mike lorton"},
+{"name": "angelica puentes"},
+{"name": "mark atkins"},
+{"name": "rick fowler"},
+{"name": "chris newland"},
+{"name": "mitch schubert"},
+{"name": "lynn carnahan"},
+{"name": "john bourne"},
+{"name": "christopher downey"},
+{"name": "julie sieben"},
+{"name": "tony demartino"},
+{"name": "jeannette uwase"},
+{"name": "patrick baptise"},
+{"name": "alan taylor"},
+{"name": "nancy balbutin"},
+{"name": "gary case"},
+{"name": "luke chick"},
+{"name": "jeremy zachary"},
+{"name": "scott mccoy"},
+{"name": "richard saccocio"},
+{"name": "marie arroyo"},
+{"name": "amy rinaldi"},
+{"name": "jesse bowery"},
+{"name": "darci azd"},
+{"name": "jacqueline asselin"},
+{"name": "ariel piper"},
+{"name": "justin heikes"},
+{"name": "hanna cell"},
+{"name": "tim bocca"},
+{"name": "bob finly"},
+{"name": "ward griffith"},
+{"name": "alison swank"},
+{"name": "young execc"},
+{"name": "karie orendorff"},
+{"name": "reid thompson"},
+{"name": "dave tait"},
+{"name": "cody shelton"},
+{"name": "ted tackaberry"},
+{"name": "travis n"},
+{"name": "tom aloisi"},
+{"name": "steve boek"},
+{"name": "jon deb"},
+{"name": "phil wilson"},
+{"name": "adrienne pegs"},
+{"name": "derek gelinas"},
+{"name": "daniel guimond"},
+{"name": "pat m"},
+{"name": "doug fullerton"},
+{"name": "katie walsh"},
+{"name": "cindy thompson"},
+{"name": "john schuh"},
+{"name": "donna stroka"},
+{"name": "mario rhinehart"},
+{"name": "diane gaal"},
+{"name": "amanda demars"},
+{"name": "lisa sherman"},
+{"name": "jeremy burris"},
+{"name": "barbara mcdaniel"},
+{"name": "derek mason"},
+{"name": "ryan lynn"},
+{"name": "patrick bala"},
+{"name": "richard purdy"},
+{"name": "amy hale"},
+{"name": "lucy scarsellone"},
+{"name": "carlos mendicia"},
+{"name": "philip huff"},
+{"name": "austin chappel"},
+{"name": "andrea hallman"},
+{"name": "brandon mair"},
+{"name": "monica grandmas"},
+{"name": "jim souderton"},
+{"name": "dana davis"},
+{"name": "jim doss"},
+{"name": "dale odom"},
+{"name": "frank dr"},
+{"name": "ezra goldberg"},
+{"name": "dustin motorcycle"},
+{"name": "delia cyra"},
+{"name": "chris hodge"},
+{"name": "dan kleiner"},
+{"name": "bill mooney"},
+{"name": "brandon tanario"},
+{"name": "chuck olson"},
+{"name": "john bourgeois"},
+{"name": "tony a"},
+{"name": "dina sokoloff"},
+{"name": "robyn williams"},
+{"name": "eric sedlacek"},
+{"name": "jim bonfanti"},
+{"name": "dina ravenscraft"},
+{"name": "lachelle cunningham"},
+{"name": "benny schvarcz"},
+{"name": "kelly kierluk"},
+{"name": "shaun lambert"},
+{"name": "don petty"},
+{"name": "susan persechino"},
+{"name": "ben johnson"},
+{"name": "alvin ferrer"},
+{"name": "grace leimer"},
+{"name": "allison logie"},
+{"name": "natalie chin"},
+{"name": "jerry iervolino"},
+{"name": "chris ford"},
+{"name": "gary molohan"},
+{"name": "pam lineburg"},
+{"name": "cynthia weber"},
+{"name": "ken duran"},
+{"name": "tony burrus"},
+{"name": "lisa cl"},
+{"name": "melinda rogers"},
+{"name": "saul niz"},
+{"name": "christopher schulz"},
+{"name": "bill johnson"},
+{"name": "steven kunde"},
+{"name": "steve palakunnel"},
+{"name": "sharon morgan"},
+{"name": "darrick adams"},
+{"name": "paul mazzara"},
+{"name": "kyle fm"},
+{"name": "rhonda dowling"},
+{"name": "donna masterson"},
+{"name": "brian debben"},
+{"name": "rick pitts"},
+{"name": "troy knuppel"},
+{"name": "erica jones"},
+{"name": "michael iacovelli"},
+{"name": "star futch"},
+{"name": "emily tinsley"},
+{"name": "dave gates"},
+{"name": "pete petroski"},
+{"name": "marcus sumner"},
+{"name": "landon evans"},
+{"name": "doug white"},
+{"name": "jerry meier"},
+{"name": "bill mehr"},
+{"name": "emily prellberg"},
+{"name": "luther fisher"},
+{"name": "helene schick"},
+{"name": "toby royer"},
+{"name": "manuel moran"},
+{"name": "dave sutton"},
+{"name": "brian taptich"},
+{"name": "bob welt"},
+{"name": "cris lira"},
+{"name": "lloyd snellson"},
+{"name": "karen sisk"},
+{"name": "victoria serna"},
+{"name": "jessie salce"},
+{"name": "michael woods"},
+{"name": "rebecca kral"},
+{"name": "dean schill"},
+{"name": "dustin king"},
+{"name": "bruna bordim"},
+{"name": "edward braginsky"},
+{"name": "john elton"},
+{"name": "stephen dolphin"},
+{"name": "olin brown"},
+{"name": "dave stanek"},
+{"name": "amber kerley"},
+{"name": "justin moss"},
+{"name": "ivan spencer"},
+{"name": "ellen bonner"},
+{"name": "duane atkins"},
+{"name": "lindsay souder"},
+{"name": "kevin noetzli"},
+{"name": "cory smith"},
+{"name": "pat mccusker"},
+{"name": "marcie corbett"},
+{"name": "kayla skinner"},
+{"name": "denny wyoming"},
+{"name": "cesar moreno"},
+{"name": "denis deryder"},
+{"name": "kris curry"},
+{"name": "nick cheever"},
+{"name": "andrew fishmann"},
+{"name": "justin kettel"},
+{"name": "garrett nay"},
+{"name": "albert lara"},
+{"name": "brian wang"},
+{"name": "armando morales"},
+{"name": "cathy naranjo"},
+{"name": "nelson allen"},
+{"name": "adam zieberg"},
+{"name": "milton times"},
+{"name": "joe mccray"},
+{"name": "natalie place"},
+{"name": "bob wise"},
+{"name": "donnie gist"},
+{"name": "candace lee"},
+{"name": "amanda mcgaugh"},
+{"name": "paul thatcher"},
+{"name": "rodney ledbetter"},
+{"name": "rachel fowler"},
+{"name": "isaiah winston"},
+{"name": "jeffrey jacobowitz"},
+{"name": "don carkner"},
+{"name": "mark henderson"},
+{"name": "jack dittoe"},
+{"name": "pam ryder"},
+{"name": "alex belfield"},
+{"name": "mitch metgovich"},
+{"name": "allyson olivere"},
+{"name": "christy escobar"},
+{"name": "candy miller"},
+{"name": "michelle dodd"},
+{"name": "mason vann"},
+{"name": "paula drury"},
+{"name": "jack bitzer"},
+{"name": "greg lindsey"},
+{"name": "laurel pearson"},
+{"name": "lon slechta"},
+{"name": "john strachan"},
+{"name": "jennifer rhoades"},
+{"name": "jeff krueger"},
+{"name": "cathy volpe"},
+{"name": "casey suchan"},
+{"name": "jeremy lang"},
+{"name": "peter lund"},
+{"name": "dan buntley"},
+{"name": "russell fields"},
+{"name": "nicole luberski"},
+{"name": "sal love"},
+{"name": "darrell squires"},
+{"name": "daniel zimmer"},
+{"name": "nick luckett"},
+{"name": "dung phat"},
+{"name": "josh munford"},
+{"name": "steve hoover"},
+{"name": "kim lax"},
+{"name": "raymond cel#"},
+{"name": "kevin nelson"},
+{"name": "terry cornish"},
+{"name": "jamie campbell"},
+{"name": "john spielman"},
+{"name": "lauren quintanilla"},
+{"name": "mark namy"},
+{"name": "tracy fisher"},
+{"name": "marcos d"},
+{"name": "natasha burton"},
+{"name": "heather mcginnis"},
+{"name": "sean pierre"},
+{"name": "maxine jennings"},
+{"name": "tyler sparkman"},
+{"name": "crystal home"},
+{"name": "peggy still"},
+{"name": "kay boz"},
+{"name": "erik gonzalez"},
+{"name": "mai hoa"},
+{"name": "larry espinola"},
+{"name": "helene schuck"},
+{"name": "michael chu"},
+{"name": "ken att"},
+{"name": "jon hoo'lei"},
+{"name": "nicole nathan"},
+{"name": "zachary markis"},
+{"name": "herbert mwakaliku"},
+{"name": "chris harmeling"},
+{"name": "brett dunhoft"},
+{"name": "lance austin"},
+{"name": "bennett ackerman"},
+{"name": "justin mcdonnell"},
+{"name": "ann francis"},
+{"name": "richard webel"},
+{"name": "mike finch"},
+{"name": "wally kada"},
+{"name": "brittany muir"},
+{"name": "natacha rincon"},
+{"name": "sheryl teague"},
+{"name": "micheal donoghue"},
+{"name": "bryan dye"},
+{"name": "gordon boost"},
+{"name": "dave elbery"},
+{"name": "lori clark"},
+{"name": "lydia mendoza"},
+{"name": "jackson sport"},
+{"name": "chris urias"},
+{"name": "stephanie diettz"},
+{"name": "alyssa j"},
+{"name": "albert vasallo"},
+{"name": "paula ryan"},
+{"name": "xavier stancil"},
+{"name": "fernando munoz"},
+{"name": "jack boyt"},
+{"name": "ali saeed"},
+{"name": "edgar hotttt"},
+{"name": "matt algate"},
+{"name": "aaron davenport"},
+{"name": "gina wilson"},
+{"name": "kelly walton"},
+{"name": "cheryl espinosa"},
+{"name": "greg hall"},
+{"name": "rob baker"},
+{"name": "paul hanis"},
+{"name": "taylor pedron"},
+{"name": "justin barry"},
+{"name": "carlos babcock"},
+{"name": "jon knickerbocker"},
+{"name": "jeff regan"},
+{"name": "joanna vzw"},
+{"name": "elena salgado"},
+{"name": "marilyn rowles"},
+{"name": "janell binder"},
+{"name": "benito guzman"},
+{"name": "christi allen"},
+{"name": "allan litwack"},
+{"name": "sparkle carter"},
+{"name": "bob dad"},
+{"name": "mike vargulish"},
+{"name": "barbara mccaskill"},
+{"name": "ken southcott"},
+{"name": "david beals"},
+{"name": "gary fales"},
+{"name": "jorge lopez"},
+{"name": "adrienne scott"},
+{"name": "jimmy maintenance"},
+{"name": "tony verdoia"},
+{"name": "john dumars"},
+{"name": "ken dantzler"},
+{"name": "steven eaves"},
+{"name": "debra mckinney"},
+{"name": "sean blickf"},
+{"name": "caren kettenburg"},
+{"name": "dan slone"},
+{"name": "brett alvarez"},
+{"name": "michael ontiveros"},
+{"name": "david anyadike"},
+{"name": "kristyn smith"},
+{"name": "shelly allen"},
+{"name": "amanda gazi"},
+{"name": "art tapy"},
+{"name": "beth venditti"},
+{"name": "tracy durant"},
+{"name": "jay raposa"},
+{"name": "dorothy lakso"},
+{"name": "anna viera"},
+{"name": "clifford tyree"},
+{"name": "bryan peck"},
+{"name": "sam kerr"},
+{"name": "darlene holladay"},
+{"name": "tia yolanda"},
+{"name": "dennis jordan"},
+{"name": "john thompson"},
+{"name": "marcus troyer"},
+{"name": "jessica stern"},
+{"name": "andrew williams"},
+{"name": "kevin hingson"},
+{"name": "jean vandette"},
+{"name": "ron foster"},
+{"name": "jeannie almond"},
+{"name": "dan prenger"},
+{"name": "frank pineda"},
+{"name": "nick pantalakis"},
+{"name": "bryan wolfe"},
+{"name": "ron buelna"},
+{"name": "frank iakovidis"},
+{"name": "james alpha"},
+{"name": "alan producer"},
+{"name": "jill polek"},
+{"name": "lisa stange"},
+{"name": "robert wychoff"},
+{"name": "ian mccloud"},
+{"name": "evan fletcher"},
+{"name": "todd cesati"},
+{"name": "bob cesari"},
+{"name": "lee w"},
+{"name": "charles zillmann"},
+{"name": "eric pinto"},
+{"name": "brian pratt"},
+{"name": "lori danner"},
+{"name": "lindsay mengis"},
+{"name": "larry weglarz"},
+{"name": "paul harper"},
+{"name": "jackie stanton"},
+{"name": "mark santos"},
+{"name": "anthony mata"},
+{"name": "brett simmons"},
+{"name": "katy robinson"},
+{"name": "lindsay lincoln"},
+{"name": "kim hulin"},
+{"name": "bobby perez"},
+{"name": "mike whaley"},
+{"name": "edward campbell"},
+{"name": "greg patton"},
+{"name": "errol roper"},
+{"name": "tom cooley"},
+{"name": "wade parsons"},
+{"name": "carlos mayes"},
+{"name": "wayne feinberg"},
+{"name": "roberta young"},
+{"name": "donnie vigil"},
+{"name": "jenny miel"},
+{"name": "kate fetter"},
+{"name": "jon ezell"},
+{"name": "tom mcclaskey"},
+{"name": "isaac borzikofsky"},
+{"name": "austin courtland"},
+{"name": "nick watts"},
+{"name": "jaime nino"},
+{"name": "lenny vandermade"},
+{"name": "tom hoch"},
+{"name": "patrice pettaway"},
+{"name": "jan wilson"},
+{"name": "carol emanuel"},
+{"name": "trish martin"},
+{"name": "dennis compton"},
+{"name": "sandra boyer"},
+{"name": "tony pallos"},
+{"name": "howard mantelmacher"},
+{"name": "jay ross"},
+{"name": "pierre lacroix"},
+{"name": "glen laws"},
+{"name": "rachel home"},
+{"name": "laura luck"},
+{"name": "dan schwartz"},
+{"name": "ron buckman"},
+{"name": "scott stewart"},
+{"name": "gilbert cerat"},
+{"name": "jan home"},
+{"name": "wendy cheung"},
+{"name": "gabriel kloet"},
+{"name": "vincent marquez"},
+{"name": "mark swezy"},
+{"name": "ashley warren"},
+{"name": "david reichler"},
+{"name": "taylor shelberg"},
+{"name": "ted tsana"},
+{"name": "chase bk"},
+{"name": "williams dan"},
+{"name": "john suess"},
+{"name": "debra garrison"},
+{"name": "travis giles"},
+{"name": "tiffany yeh"},
+{"name": "ashleigh edmonds"},
+{"name": "miranda cohen"},
+{"name": "lauren stacey"},
+{"name": "paula basch"},
+{"name": "emily griffith"},
+{"name": "heath kamp"},
+{"name": "paul bb"},
+{"name": "lori andrews"},
+{"name": "franklyn pamoja"},
+{"name": "jean perbet"},
+{"name": "ruby jones"},
+{"name": "terri o'brian"},
+{"name": "jason pund"},
+{"name": "ed peaser"},
+{"name": "ashley kennedy"},
+{"name": "chris rooks"},
+{"name": "eric prust"},
+{"name": "janet wholer"},
+{"name": "megan davis"},
+{"name": "neil greenstein"},
+{"name": "adrienne hair"},
+{"name": "james hart"},
+{"name": "michael snedegar"},
+{"name": "alison mclean"},
+{"name": "dean culligan"},
+{"name": "lincoln martin"},
+{"name": "melissa meli"},
+{"name": "greg mizell"},
+{"name": "adela hyde"},
+{"name": "mallory o'grady"},
+{"name": "sophia banks"},
+{"name": "ben mcleish"},
+{"name": "jack klein"},
+{"name": "eric ruiz"},
+{"name": "john nf"},
+{"name": "cody bergner"},
+{"name": "destiny bff"},
+{"name": "ben ni"},
+{"name": "lamonica hummel"},
+{"name": "jeff dornenburg"},
+{"name": "mabel lewis"},
+{"name": "kathy villa"},
+{"name": "kelly battleson"},
+{"name": "warren c"},
+{"name": "scotty fitzpatrick"},
+{"name": "bill pelt"},
+{"name": "joan metz"},
+{"name": "william talbott"},
+{"name": "eric zavala"},
+{"name": "ann dmi"},
+{"name": "tyson devron"},
+{"name": "ilene stover"},
+{"name": "mike hugos"},
+{"name": "brandon bishops"},
+{"name": "brett finkley"},
+{"name": "derek armstrong"},
+{"name": "rita jankouzian"},
+{"name": "edward lin"},
+{"name": "mike curtis"},
+{"name": "chris asta"},
+{"name": "craig bloom"},
+{"name": "blaine shank"},
+{"name": "susan finkam"},
+{"name": "mike florio"},
+{"name": "kam hutchins"},
+{"name": "ted trigs"},
+{"name": "greg baird"},
+{"name": "jessica debiaso"},
+{"name": "bob watt"},
+{"name": "carlos trevino"},
+{"name": "chase card"},
+{"name": "joyce giseke"},
+{"name": "kenny payne"},
+{"name": "sean virsack"},
+{"name": "aaron haskins"},
+{"name": "stephanie payne"},
+{"name": "chaz macalinga"},
+{"name": "jamie augustyn"},
+{"name": "maria gamble"},
+{"name": "hung truong"},
+{"name": "jackie harris"},
+{"name": "jeffrey jefferson"},
+{"name": "greg kramer"},
+{"name": "alan lane"},
+{"name": "aaron whitely"},
+{"name": "michael dziak"},
+{"name": "nathan varni"},
+{"name": "steven kennedy"},
+{"name": "alfredo lambour"},
+{"name": "chad rice"},
+{"name": "shasta merrell"},
+{"name": "lonnie barker"},
+{"name": "bob ducasse"},
+{"name": "lori hfa"},
+{"name": "renae hines"},
+{"name": "tony saldate"},
+{"name": "kevin aleson"},
+{"name": "steve baum"},
+{"name": "brian olson"},
+{"name": "john shain"},
+{"name": "fabiola ordonez"},
+{"name": "toby peak"},
+{"name": "morgan sherfield"},
+{"name": "marie fortin"},
+{"name": "alex adekoya"},
+{"name": "billy h"},
+{"name": "pam sharp"},
+{"name": "ryan kimbrough"},
+{"name": "frank jackson"},
+{"name": "david neighbor"},
+{"name": "charles coney"},
+{"name": "hank hough"},
+{"name": "eileen little"},
+{"name": "alicia curley"},
+{"name": "brian hopper"},
+{"name": "ray cel"},
+{"name": "miranda williams"},
+{"name": "del estrada"},
+{"name": "kris jackson"},
+{"name": "jeff wills"},
+{"name": "leslie peterson"},
+{"name": "jason pittman"},
+{"name": "sam feneque"},
+{"name": "julie fikes"},
+{"name": "pat lacass"},
+{"name": "melissa mckinney"},
+{"name": "jessica morgan"},
+{"name": "luann leiding"},
+{"name": "georgette xxxxx"},
+{"name": "marlene tamayo"},
+{"name": "tess mckenzie"},
+{"name": "john carter"},
+{"name": "ted teruya"},
+{"name": "rick sweat"},
+{"name": "liz hernandez"},
+{"name": "steve mc"},
+{"name": "matt boomsma"},
+{"name": "peter harrison"},
+{"name": "alex giannaras"},
+{"name": "kevin korthuis"},
+{"name": "dan donna"},
+{"name": "gregg salzman"},
+{"name": "al auto"},
+{"name": "kerry g"},
+{"name": "loretta garret"},
+{"name": "lorna moultry"},
+{"name": "robert hendley"},
+{"name": "kami stanley"},
+{"name": "ken fraser"},
+{"name": "gustavo guzman"},
+{"name": "brian work"},
+{"name": "frank bashaw"},
+{"name": "jenny peterson"},
+{"name": "jesse wong"},
+{"name": "john antolik"},
+{"name": "jorge ochoa"},
+{"name": "kerry anderson"},
+{"name": "sean dtlr"},
+{"name": "judy kilduff"},
+{"name": "tricia cell"},
+{"name": "gilbert vadez"},
+{"name": "ronald crompton"},
+{"name": "howard berglas"},
+{"name": "jackie kemp"},
+{"name": "billy p"},
+{"name": "rose patrick"},
+{"name": "curt kost"},
+{"name": "peter chadwick"},
+{"name": "joe tartaglia"},
+{"name": "aaron eddy"},
+{"name": "tom motsinger"},
+{"name": "diane gerovasil"},
+{"name": "blake henrie"},
+{"name": "david elmore"},
+{"name": "kelly car"},
+{"name": "dan galleano"},
+{"name": "scott withers"},
+{"name": "ken speer"},
+{"name": "kyle molina"},
+{"name": "brad tertell"},
+{"name": "benjamin mason"},
+{"name": "robert burk"},
+{"name": "john hyndman"},
+{"name": "erin derrider"},
+{"name": "brenda nemcek"},
+{"name": "amanda teague"},
+{"name": "marco murillo"},
+{"name": "brian collins"},
+{"name": "stephanie skaff"},
+{"name": "mark jeffers"},
+{"name": "jonathan hannan"},
+{"name": "karl meyer"},
+{"name": "gene bowers"},
+{"name": "kaylee peterson"},
+{"name": "rob mccalla"},
+{"name": "rod markin"},
+{"name": "petra klaus"},
+{"name": "malik thorne"},
+{"name": "perry wesely"},
+{"name": "john nord"},
+{"name": "les sendy"},
+{"name": "anna gregson"},
+{"name": "caprice wallace"},
+{"name": "dallas provenzano"},
+{"name": "sari breznau"},
+{"name": "tonia hack"},
+{"name": "john powell"},
+{"name": "renee fullerton"},
+{"name": "brian younkin"},
+{"name": "chris matheson"},
+{"name": "marie alexander"},
+{"name": "chris champion"},
+{"name": "aisha francis"},
+{"name": "brandy viera"},
+{"name": "amanda marquardt"},
+{"name": "nikki b"},
+{"name": "kelvin liu"},
+{"name": "sally knowles"},
+{"name": "anna straight"},
+{"name": "michael jaffarian"},
+{"name": "john galloway"},
+{"name": "billy hammons"},
+{"name": "tom malsack"},
+{"name": "john mcwhorter"},
+{"name": "george kanganis"},
+{"name": "stephanie gabriel"},
+{"name": "brian mazur"},
+{"name": "julianna prada"},
+{"name": "tim dearth"},
+{"name": "betty blanton"},
+{"name": "kay spriggs"},
+{"name": "ted lewis"},
+{"name": "jay shliefer"},
+{"name": "stanley wishner"},
+{"name": "mike zungali"},
+{"name": "matthew ragone"},
+{"name": "gary gubitz"},
+{"name": "jan hatfield"},
+{"name": "russell perkins"},
+{"name": "eva caballero"},
+{"name": "ryan hennesey"},
+{"name": "bernie cap"},
+{"name": "lisa amposta"},
+{"name": "bob myers"},
+{"name": "darlene tong"},
+{"name": "britt skarda"},
+{"name": "josephine cota"},
+{"name": "melissa isaiah"},
+{"name": "ken rethmeier"},
+{"name": "linda allen"},
+{"name": "rose garrett"},
+{"name": "tom likus"},
+{"name": "tony espy"},
+{"name": "dana kneer"},
+{"name": "adolfo dorothy"},
+{"name": "melissa mendez"},
+{"name": "stan gorman"},
+{"name": "marty thomasson"},
+{"name": "susan brisbin"},
+{"name": "stacy myre"},
+{"name": "malcom john"},
+{"name": "ken vanhorn"},
+{"name": "kenny hampton"},
+{"name": "roberta martinez"},
+{"name": "bethany comer"},
+{"name": "bruce tassan"},
+{"name": "bart lollino"},
+{"name": "marlene galicia"},
+{"name": "tracie hunter"},
+{"name": "tonya martinez"},
+{"name": "benjamin allen"},
+{"name": "micheal tschanan"},
+{"name": "maggie leverone"},
+{"name": "siobhan sullivan"},
+{"name": "robert infantino"},
+{"name": "george horhota"},
+{"name": "steve cell"},
+{"name": "dana heckman"},
+{"name": "nora rivera"},
+{"name": "tanja nuhsbaum"},
+{"name": "nicole cydc"},
+{"name": "charlotte watter"},
+{"name": "robin patterson"},
+{"name": "ashleigh day"},
+{"name": "ginny nixon"},
+{"name": "bailey cell"},
+{"name": "tony salah"},
+{"name": "jason link"},
+{"name": "cathy lucht"},
+{"name": "juan loera"},
+{"name": "jim brubaker"},
+{"name": "tom matthews"},
+{"name": "mel sacks"},
+{"name": "tiffaney kuhn"},
+{"name": "alicia leines"},
+{"name": "tom fennelly"},
+{"name": "marco rizzo"},
+{"name": "nancy fisher"},
+{"name": "jackson motor"},
+{"name": "josh stylman"},
+{"name": "erik vines"},
+{"name": "jay crain"},
+{"name": "john brew"},
+{"name": "keith carodine"},
+{"name": "sheri shefler"},
+{"name": "sabrina strange"},
+{"name": "amanda fallat"},
+{"name": "carol fedewa"},
+{"name": "george masone"},
+{"name": "ed pagilusio"},
+{"name": "eric billy"},
+{"name": "rick holtmeyer"},
+{"name": "tim pete"},
+{"name": "carol camren"},
+{"name": "nichol nelson"},
+{"name": "tracy lucis"},
+{"name": "tom genz"},
+{"name": "pamela lee"},
+{"name": "jamie schneidemeister"},
+{"name": "oliver bacon"},
+{"name": "jorge becerra"},
+{"name": "michael barron"},
+{"name": "julie shockey"},
+{"name": "dave hoey"},
+{"name": "israel cemetery"},
+{"name": "jimmy almansa"},
+{"name": "jacqueline banks"},
+{"name": "andrew butler"},
+{"name": "sherman austin"},
+{"name": "karl scholz"},
+{"name": "mai anne"},
+{"name": "jonathan rosenthal"},
+{"name": "mary giery"},
+{"name": "steve williams"},
+{"name": "kim durante"},
+{"name": "temple brown"},
+{"name": "ernest stalvey"},
+{"name": "bruce newell"},
+{"name": "jack deckleman"},
+{"name": "oscar kash"},
+{"name": "raymond gandolfo"},
+{"name": "matt schreiderer"},
+{"name": "sarah stiles"},
+{"name": "dan d"},
+{"name": "nick magera"},
+{"name": "greg pedigo"},
+{"name": "stuart landon"},
+{"name": "jason ricci"},
+{"name": "rodney holland"},
+{"name": "candice pel"},
+{"name": "greg roeper"},
+{"name": "frank nolimal"},
+{"name": "georgie vega"},
+{"name": "elaine sellig"},
+{"name": "heather rodrigez"},
+{"name": "ben tam"},
+{"name": "adam kelley"},
+{"name": "stuart singleton"},
+{"name": "ricky watson"},
+{"name": "parker dixon"},
+{"name": "pete meli"},
+{"name": "sara cramlet"},
+{"name": "taylor johnston"},
+{"name": "john rooney"},
+{"name": "steve berkowitz"},
+{"name": "danielle weed"},
+{"name": "eric collins"},
+{"name": "steve tubman"},
+{"name": "rodrigo gayta"},
+{"name": "clay h"},
+{"name": "hillary veals"},
+{"name": "erinn hughes"},
+{"name": "kyle hirning"},
+{"name": "brian mcintyre"},
+{"name": "irene ho"},
+{"name": "dena murray"},
+{"name": "amy taylor"},
+{"name": "eric blair"},
+{"name": "tommy collier"},
+{"name": "melanie k"},
+{"name": "vernon miller"},
+{"name": "deborah magid"},
+{"name": "allen h"},
+{"name": "mohamed hs"},
+{"name": "steve wood"},
+{"name": "steve konemany"},
+{"name": "deloris reinwald"},
+{"name": "larry walter"},
+{"name": "kim buttram"},
+{"name": "lori cortina"},
+{"name": "doug cruise"},
+{"name": "anita peek"},
+{"name": "darrell johnson"},
+{"name": "will connell"},
+{"name": "neal hugh"},
+{"name": "ryan dunlop"},
+{"name": "claudine bailey"},
+{"name": "wyatt larsen"},
+{"name": "todd baldanza"},
+{"name": "wally gallup"},
+{"name": "justin quintana"},
+{"name": "james barba"},
+{"name": "trent reis"},
+{"name": "laura williamson"},
+{"name": "lynnette crutcher"},
+{"name": "jill frakes"},
+{"name": "ann ruyle"},
+{"name": "carolina psychological"},
+{"name": "james highfill"},
+{"name": "philip vallejo"},
+{"name": "andrew scolza"},
+{"name": "colin m"},
+{"name": "scotty nova"},
+{"name": "paul equitb"},
+{"name": "larry harrison"},
+{"name": "val demetrious"},
+{"name": "cathy yip"},
+{"name": "steve orr"},
+{"name": "crystal w"},
+{"name": "jan banker"},
+{"name": "jay webb"},
+{"name": "marcy baim"},
+{"name": "nelson tires"},
+{"name": "joe canda"},
+{"name": "charlene dade"},
+{"name": "eli eisenberg"},
+{"name": "dan passen"},
+{"name": "brian austin"},
+{"name": "dell fox"},
+{"name": "martin majestic"},
+{"name": "elizabeth pottinge"},
+{"name": "lisa neal"},
+{"name": "carolyn turchin"},
+{"name": "brandi morrison"},
+{"name": "jay h"},
+{"name": "cory suazo"},
+{"name": "mimi rios"},
+{"name": "kristi anderson"},
+{"name": "marcel davelouise"},
+{"name": "luis cell"},
+{"name": "guy gauvin"},
+{"name": "ursula maul"},
+{"name": "shauna aumie"},
+{"name": "tommy school"},
+{"name": "jennifer molina"},
+{"name": "rob kingelin"},
+{"name": "veronica morales"},
+{"name": "kathy md"},
+{"name": "cassandra isom"},
+{"name": "william samuels"},
+{"name": "jessica clyde"},
+{"name": "julie mcintyre"},
+{"name": "alan castillo"},
+{"name": "roger devino"},
+{"name": "steven driskill"},
+{"name": "steve lindley"},
+{"name": "jared lusk"},
+{"name": "justin sanchez"},
+{"name": "jordan solting"},
+{"name": "chris murphy"},
+{"name": "matt bluesteelknight"},
+{"name": "melinda l"},
+{"name": "cody price"},
+{"name": "kathy kono"},
+{"name": "matthew lux"},
+{"name": "nancy carillo"},
+{"name": "debbie hubble"},
+{"name": "enid requena"},
+{"name": "cameron millsaps"},
+{"name": "steve lew"},
+{"name": "cherise candlish"},
+{"name": "harry carthan"},
+{"name": "davina gregoire"},
+{"name": "keely kraft"},
+{"name": "larry schumer"},
+{"name": "daniel griseto"},
+{"name": "shane furey"},
+{"name": "dawn hr"},
+{"name": "nick defilppis"},
+{"name": "scott dinger"},
+{"name": "steve nolte"},
+{"name": "dick waters"},
+{"name": "alan roark"},
+{"name": "natalie trimmer"},
+{"name": "justin dittburner"},
+{"name": "alex frias"},
+{"name": "alexandra suarez"},
+{"name": "karen bills"},
+{"name": "peter burns"},
+{"name": "renee walker"},
+{"name": "tommy richeson"},
+{"name": "byron mcken"},
+{"name": "spencer connelly"},
+{"name": "anita coke"},
+{"name": "rob mullins"},
+{"name": "jason babkes"},
+{"name": "chris emm"},
+{"name": "pete pariila"},
+{"name": "darren kemp"},
+{"name": "wendy brandt"},
+{"name": "john inak"},
+{"name": "ben levy"},
+{"name": "brandon clockwork"},
+{"name": "libby neil"},
+{"name": "christopher lavoy"},
+{"name": "orlando silver"},
+{"name": "gerry waltz"},
+{"name": "peter leone"},
+{"name": "travis dagman"},
+{"name": "stephanie triay"},
+{"name": "marsha newman"},
+{"name": "jimmy becsei"},
+{"name": "howard susan"},
+{"name": "eric gal"},
+{"name": "george guethlein"},
+{"name": "bill webb"},
+{"name": "melissa kanakry"},
+{"name": "erica namin"},
+{"name": "angela p"},
+{"name": "joel mills"},
+{"name": "maureen ruthman"},
+{"name": "andre ballard"},
+{"name": "shawn bashi"},
+{"name": "jordan alexander"},
+{"name": "debbie mayo"},
+{"name": "louis elguera"},
+{"name": "josh mom"},
+{"name": "jose interiano"},
+{"name": "jenna m"},
+{"name": "alexandra gonzalez"},
+{"name": "nancy tippten"},
+{"name": "katherine breig"},
+{"name": "bryan conley"},
+{"name": "nancy meeks"},
+{"name": "june axo"},
+{"name": "eddy terrace"},
+{"name": "destiny ingram"},
+{"name": "sam song"},
+{"name": "debra farber"},
+{"name": "ruben guzman"},
+{"name": "dan hudson"},
+{"name": "alix paultre"},
+{"name": "carla lindstrom"},
+{"name": "alexander superman"},
+{"name": "jim sloan"},
+{"name": "douglas bennett"},
+{"name": "nick depace"},
+{"name": "dan friesen"},
+{"name": "erik daoud"},
+{"name": "keisha wiedford"},
+{"name": "jesus toro"},
+{"name": "david beaupre"},
+{"name": "michael lovitt"},
+{"name": "ryan heslin"},
+{"name": "miss aimee"},
+{"name": "mike bendlin"},
+{"name": "amy horn"},
+{"name": "jen scremin"},
+{"name": "marissa luvender"},
+{"name": "susie shanahan"},
+{"name": "piper center"},
+{"name": "garth mitcham"},
+{"name": "dean shelley"},
+{"name": "fernanda martinez"},
+{"name": "brian galli"},
+{"name": "eric artis"},
+{"name": "nicole hughes"},
+{"name": "patrick webb"},
+{"name": "tom work"},
+{"name": "fred marsh"},
+{"name": "sandi g"},
+{"name": "derek andersen"},
+{"name": "jeff fox"},
+{"name": "carmen owen"},
+{"name": "barry arbuckle"},
+{"name": "cheryl rivers"},
+{"name": "deidre cantrell"},
+{"name": "james allen"},
+{"name": "james kittle"},
+{"name": "lane macdonald"},
+{"name": "james washington"},
+{"name": "eric mundis"},
+{"name": "christine benton"},
+{"name": "pete gronenthal"},
+{"name": "jen brat"},
+{"name": "jim gibbons"},
+{"name": "george reed"},
+{"name": "lisa lindquist"},
+{"name": "eric tysinger"},
+{"name": "taylor perkins"},
+{"name": "sandy mayra"},
+{"name": "chris tantau"},
+{"name": "marie chung"},
+{"name": "bruce dravas"},
+{"name": "julian gomez"},
+{"name": "jeff molofsky"},
+{"name": "elena ivanovski"},
+{"name": "bette tryon"},
+{"name": "joey stansbury"},
+{"name": "tony maglione"},
+{"name": "andrew wellner"},
+{"name": "donnie nabisco"},
+{"name": "mike migone"},
+{"name": "colby waltenburg"},
+{"name": "katia pache"},
+{"name": "ashley crib"},
+{"name": "chris hale"},
+{"name": "kathy black"},
+{"name": "kevin harris"},
+{"name": "rob j"},
+{"name": "sara burr"},
+{"name": "john reese"},
+{"name": "kelly bayliss"},
+{"name": "bill edwards"},
+{"name": "aaron ohama"},
+{"name": "krysta hall"},
+{"name": "gary krill"},
+{"name": "stacy lozano"},
+{"name": "greg mazzo"},
+{"name": "lawrence liu"},
+{"name": "mark nicholas"},
+{"name": "renee harrison"},
+{"name": "jolie martin"},
+{"name": "sean mendy"},
+{"name": "raymond herrera"},
+{"name": "rick freshko"},
+{"name": "troy f"},
+{"name": "gary tubiolo"},
+{"name": "tony radke"},
+{"name": "victor kirkland"},
+{"name": "tia santa"},
+{"name": "chantal courtney"},
+{"name": "tom oleszczuk"},
+{"name": "edward esc"},
+{"name": "tim kildine"},
+{"name": "gerald pigford"},
+{"name": "mike figueroa"},
+{"name": "sammy ortiz"},
+{"name": "katie w"},
+{"name": "kurt short"},
+{"name": "kate vaugn"},
+{"name": "jim hanson"},
+{"name": "ann fitzpatrick"},
+{"name": "andrew hosmer"},
+{"name": "kimberly hooie"},
+{"name": "anita ashland"},
+{"name": "michael markette"},
+{"name": "katie hicks"},
+{"name": "richard journett"},
+{"name": "jon b"},
+{"name": "ken wong"},
+{"name": "arthur coley"},
+{"name": "sharon day"},
+{"name": "sara kebil"},
+{"name": "jazmine lee"},
+{"name": "greg ness"},
+{"name": "anne wells"},
+{"name": "edward toussaint"},
+{"name": "kira hamer"},
+{"name": "stephine pough"},
+{"name": "drew webb"},
+{"name": "joe depauw"},
+{"name": "steve deal"},
+{"name": "natalie green"},
+{"name": "gayla mecham"},
+{"name": "micheal elliot"},
+{"name": "mark jarvis"},
+{"name": "claudia banegas"},
+{"name": "frankie reina"},
+{"name": "diane dunkley"},
+{"name": "corey brunet"},
+{"name": "genevieve rojas"},
+{"name": "buddy osteen"},
+{"name": "john swank"},
+{"name": "ken holl"},
+{"name": "saul corralles"},
+{"name": "jessie s"},
+{"name": "joe slaughter"},
+{"name": "michael farber"},
+{"name": "vanessa wallace"},
+{"name": "valerie ingco"},
+{"name": "alyssa levine"},
+{"name": "becky cortez"},
+{"name": "dave tennis"},
+{"name": "melissa davenport"},
+{"name": "alan archlbal"},
+{"name": "jeff swayze"},
+{"name": "kevin saunders"},
+{"name": "drew pascarella"},
+{"name": "keith henderson"},
+{"name": "chris greenway"},
+{"name": "blake kampen"},
+{"name": "sherry tewel"},
+{"name": "lyn schmidt"},
+{"name": "penny case"},
+{"name": "kristyn sheets"},
+{"name": "marilyn curry"},
+{"name": "bill dixon"},
+{"name": "sun thei"},
+{"name": "mac que's"},
+{"name": "tad wellborn"},
+{"name": "carol wrk"},
+{"name": "scott mulvaney"},
+{"name": "julia quintero"},
+{"name": "patrick vogel"},
+{"name": "danielle o'regan"},
+{"name": "victor ortiz"},
+{"name": "bob torino"},
+{"name": "john rohr"},
+{"name": "mary o'brien"},
+{"name": "ewa petroski"},
+{"name": "brian lynch"},
+{"name": "sandra barbour"},
+{"name": "lucia rodriguez"},
+{"name": "bill ezell"},
+{"name": "fred cooper"},
+{"name": "steve thornton"},
+{"name": "david bauman"},
+{"name": "lance lainge"},
+{"name": "ashley campbel"},
+{"name": "carol tamayo"},
+{"name": "david keschner"},
+{"name": "amy shields"},
+{"name": "troy hickerson"},
+{"name": "sam akers"},
+{"name": "darin rayburn"},
+{"name": "nina trout"},
+{"name": "scott independent"},
+{"name": "katie shelite"},
+{"name": "george archer"},
+{"name": "wes miller"},
+{"name": "stephanie tamargo"},
+{"name": "michele mccombs"},
+{"name": "rick eddie"},
+{"name": "steven law"},
+{"name": "ron gagne"},
+{"name": "clayton plumber"},
+{"name": "katherine luna"},
+{"name": "ward yurystowski"},
+{"name": "richard chen"},
+{"name": "wendy bim"},
+{"name": "jeri lyn"},
+{"name": "doug newall"},
+{"name": "joe herrera"},
+{"name": "gary gilchrist"},
+{"name": "joshua duhl"},
+{"name": "jeff dern"},
+{"name": "kate repucci"},
+{"name": "chris fortuna"},
+{"name": "murray grossner"},
+{"name": "toni chamoun"},
+{"name": "kathy neighbor"},
+{"name": "gus gus"},
+{"name": "richard howson"},
+{"name": "nick ezell"},
+{"name": "jessica ashby"},
+{"name": "laurie elgas"},
+{"name": "mary legato"},
+{"name": "olivia moreno"},
+{"name": "don foster"},
+{"name": "peter pizza"},
+{"name": "chris vera"},
+{"name": "dwight davis"},
+{"name": "derek mayeda"},
+{"name": "patrick gossage"},
+{"name": "chris kaiser"},
+{"name": "sandra stone"},
+{"name": "elizabeth keigher"},
+{"name": "bryce kubik"},
+{"name": "diane barragan"},
+{"name": "carol foley"},
+{"name": "shari bonesteel"},
+{"name": "derek blevins"},
+{"name": "megan pittenger"},
+{"name": "robert kimball"},
+{"name": "jessie bilstin"},
+{"name": "ann osborn"},
+{"name": "mike oneal"},
+{"name": "marc grozescu"},
+{"name": "kevin cox"},
+{"name": "bill brannan"},
+{"name": "ryan moore"},
+{"name": "keith campbell"},
+{"name": "david sklaver"},
+{"name": "david schwartz"},
+{"name": "heath finn"},
+{"name": "tammy roark"},
+{"name": "davis yoakum"},
+{"name": "misty douglass"},
+{"name": "walter greene"},
+{"name": "tim drevno"},
+{"name": "ana rojas"},
+{"name": "wayne buxton"},
+{"name": "elana gupton"},
+{"name": "paula radcliff"},
+{"name": "patrick perris"},
+{"name": "dawn narry"},
+{"name": "peter richardson"},
+{"name": "sandra mccune"},
+{"name": "scott stoval"},
+{"name": "carol dobbins"},
+{"name": "michelle lichtenwalter"},
+{"name": "marcus rhodes"},
+{"name": "karl stillner"},
+{"name": "marianne vitale"},
+{"name": "bill flannagan"},
+{"name": "beth pr"},
+{"name": "amber nuckles"},
+{"name": "mike valiente"},
+{"name": "eli gitler"},
+{"name": "andy ingriselli"},
+{"name": "steve lemme"},
+{"name": "brianna evert"},
+{"name": "dawn maples"},
+{"name": "shane young"},
+{"name": "miguel nava"},
+{"name": "rick mccahill"},
+{"name": "warren boen"},
+{"name": "sue padavano"},
+{"name": "john campin"},
+{"name": "jake knecht"},
+{"name": "william booth"},
+{"name": "lynnette khalfani"},
+{"name": "jake summerlin"},
+{"name": "terri favre"},
+{"name": "stan driver"},
+{"name": "tawanda banks"},
+{"name": "rick smilow"},
+{"name": "esther leong"},
+{"name": "bernie mccaskill"},
+{"name": "ramon nachos"},
+{"name": "laurel police"},
+{"name": "bob heyne"},
+{"name": "doris g"},
+{"name": "german jim"},
+{"name": "dwight iii"},
+{"name": "diane lowenstein"},
+{"name": "barb baker"},
+{"name": "brooke stinson"},
+{"name": "april ray"},
+{"name": "joe jensen"},
+{"name": "bob malowlanowski"},
+{"name": "stephen mongeau"},
+{"name": "carey conner"},
+{"name": "ted shill"},
+{"name": "raul gonzales"},
+{"name": "melissa nord"},
+{"name": "tiara riley"},
+{"name": "sherry cassano"},
+{"name": "sam mack"},
+{"name": "margaret work"},
+{"name": "carlo gherardi"},
+{"name": "margaret drabant"},
+{"name": "bob besse"},
+{"name": "russell witte"},
+{"name": "casey rodgers"},
+{"name": "hugo zamora"},
+{"name": "todd vnl"},
+{"name": "cindy mayhugh"},
+{"name": "rico estremera"},
+{"name": "noel villegas"},
+{"name": "kirk leslie"},
+{"name": "steve domingo"},
+{"name": "clint balaki"},
+{"name": "jim isu"},
+{"name": "michael girard"},
+{"name": "cecily merdes"},
+{"name": "jay beard"},
+{"name": "joel sandrol"},
+{"name": "mark fleischman"},
+{"name": "robert macintyre"},
+{"name": "timmy gage"},
+{"name": "ed robinson"},
+{"name": "tiffany lutz"},
+{"name": "burton walsh"},
+{"name": "chris kaminski"},
+{"name": "rebecca vidal"},
+{"name": "ashley howard"},
+{"name": "tim wright"},
+{"name": "jeff halbert"},
+{"name": "david langer"},
+{"name": "jackie brenneman"},
+{"name": "lauren ushijima"},
+{"name": "van oosterhout"},
+{"name": "mike jones"},
+{"name": "marie leip"},
+{"name": "scott mcnotin"},
+{"name": "martin walker"},
+{"name": "dennis mitchell"},
+{"name": "scott wheaton"},
+{"name": "ronnie baras"},
+{"name": "carlie desimone"},
+{"name": "dan harmon"},
+{"name": "jon ventin"},
+{"name": "susan jackson"},
+{"name": "terry everett"},
+{"name": "sandy sheppard"},
+{"name": "bob landes"},
+{"name": "donna spo"},
+{"name": "josh podell"},
+{"name": "elsa poon"},
+{"name": "lou healey"},
+{"name": "garth day"},
+{"name": "maria esquivera"},
+{"name": "mike giaccone"},
+{"name": "steve edwards"},
+{"name": "raven lopez"},
+{"name": "max perzucha"},
+{"name": "arturo ibanez"},
+{"name": "shauna austin"},
+{"name": "bob bauman"},
+{"name": "trevor christie"},
+{"name": "joaquin lopez"},
+{"name": "ann mete"},
+{"name": "melissa englebert"},
+{"name": "ashley horwath"},
+{"name": "kirk loevner"},
+{"name": "steve rattiner"},
+{"name": "greg eisenberg"},
+{"name": "joan ed"},
+{"name": "louise harrelson"},
+{"name": "mark carr"},
+{"name": "chris darkhorse"},
+{"name": "annette musson"},
+{"name": "bob mcvey"},
+{"name": "chad cox"},
+{"name": "kevin riggs"},
+{"name": "jeff prior"},
+{"name": "manuel rod"},
+{"name": "david starnes"},
+{"name": "mark husar"},
+{"name": "jessica brittingham"},
+{"name": "brian widmar"},
+{"name": "lyndsay belmont"},
+{"name": "alberto manuel"},
+{"name": "dave sucese"},
+{"name": "june scott"},
+{"name": "mark schutt"},
+{"name": "vicki sharp"},
+{"name": "jeff chem"},
+{"name": "ana police"},
+{"name": "marie cooper"},
+{"name": "rich poma"},
+{"name": "pete lacolla"},
+{"name": "dean weinkauf"},
+{"name": "blake d"},
+{"name": "cathy moore"},
+{"name": "ashleigh bing"},
+{"name": "jim mcclure"},
+{"name": "paul guillen"},
+{"name": "dave mann"},
+{"name": "haley s"},
+{"name": "charlie teskey"},
+{"name": "korey b"},
+{"name": "anita spofford"},
+{"name": "kristin hoke"},
+{"name": "craig mannix"},
+{"name": "johnathan escott"},
+{"name": "gene yan"},
+{"name": "dorian reed"},
+{"name": "marla grabner"},
+{"name": "jeremy landon"},
+{"name": "lee hoffstein"},
+{"name": "kara gipple"},
+{"name": "sam pre"},
+{"name": "justin steeby"},
+{"name": "heath cell"},
+{"name": "patricia cramer"},
+{"name": "joann reynolds"},
+{"name": "sun stephanie"},
+{"name": "brian stein"},
+{"name": "sandi love"},
+{"name": "natasha sysum"},
+{"name": "caroline warren"},
+{"name": "ricardo casanova"},
+{"name": "jessica polar"},
+{"name": "julianne decaro"},
+{"name": "jenny aragon"},
+{"name": "tracey comeaux"},
+{"name": "brandon mattox"},
+{"name": "al johnson"},
+{"name": "era west"},
+{"name": "joyce heringa"},
+{"name": "mike bogdonoff"},
+{"name": "michelle niswonger"},
+{"name": "myra valera"},
+{"name": "mike griffin"},
+{"name": "rana mandel"},
+{"name": "mike ramel"},
+{"name": "gina kirk"},
+{"name": "jodi dail"},
+{"name": "shera terry"},
+{"name": "heather schriver"},
+{"name": "austin harbour"},
+{"name": "tom resiloski"},
+{"name": "mike mccauley"},
+{"name": "phillip torres"},
+{"name": "matt d"},
+{"name": "katy beck"},
+{"name": "charles venzina"},
+{"name": "chris tan"},
+{"name": "pat aliano"},
+{"name": "bryan mccaffrey"},
+{"name": "george berdin"},
+{"name": "katie floyd"},
+{"name": "david ovard"},
+{"name": "nicole whiteman"},
+{"name": "doug warring"},
+{"name": "bonita volden"},
+{"name": "liz tabunar"},
+{"name": "tom subak"},
+{"name": "matthew cornall"},
+{"name": "debbie blanchard"},
+{"name": "velma lester"},
+{"name": "sarah stina"},
+{"name": "olivia cro"},
+{"name": "tina denwood"},
+{"name": "josh ward"},
+{"name": "chad vandornick"},
+{"name": "dave swartz"},
+{"name": "michael brogan"},
+{"name": "samantha garza"},
+{"name": "anthony acosta"},
+{"name": "myra falconer"},
+{"name": "leo metcalf"},
+{"name": "brian day"},
+{"name": "mark clausen"},
+{"name": "jefferson atty"},
+{"name": "matt robin"},
+{"name": "allen shelby"},
+{"name": "christina kos"},
+{"name": "larry young"},
+{"name": "aaron favero"},
+{"name": "jason finkelstein"},
+{"name": "kim randolph"},
+{"name": "cory haitsuka"},
+{"name": "matt thor"},
+{"name": "kim maddy"},
+{"name": "spencer puskas"},
+{"name": "john cruikshank"},
+{"name": "maria espinoza"},
+{"name": "andy yahoo"},
+{"name": "jessica gunn"},
+{"name": "jada jones"},
+{"name": "matt damore"},
+{"name": "rob wawrach"},
+{"name": "hana fire"},
+{"name": "amie peacock"},
+{"name": "joshua price"},
+{"name": "vivian williams"},
+{"name": "kyle sanders"},
+{"name": "marisa stewart"},
+{"name": "jim brant"},
+{"name": "roger reid"},
+{"name": "lance armstrong"},
+{"name": "john hemphill"},
+{"name": "sondra oldy"},
+{"name": "linda mazur"},
+{"name": "annie barry"},
+{"name": "cassie gross"},
+{"name": "belinda blair"},
+{"name": "pamela olszowowi"},
+{"name": "dave seibert"},
+{"name": "stephen buyze"},
+{"name": "larry weisbrod"},
+{"name": "tony bland"},
+{"name": "franklin first"},
+{"name": "marilou macandog"},
+{"name": "angela nielson"},
+{"name": "rob dantzer"},
+{"name": "shelia kelley"},
+{"name": "nathan darveau"},
+{"name": "john ludwig"},
+{"name": "bob saucedo"},
+{"name": "jordan doner"},
+{"name": "heather laskey"},
+{"name": "jessica green"},
+{"name": "rob tesauro"},
+{"name": "jake welch"},
+{"name": "donald fowler"},
+{"name": "ben skaggs"},
+{"name": "kurt birchler"},
+{"name": "kyle miley"},
+{"name": "mike boyles"},
+{"name": "nikki work"},
+{"name": "jasmine pagan"},
+{"name": "sheila carter"},
+{"name": "paul hsiung"},
+{"name": "julie sherry"},
+{"name": "josh palmere"},
+{"name": "mike speakman"},
+{"name": "amber hobgood"},
+{"name": "rex eaton"},
+{"name": "jim hill"},
+{"name": "jim mahfood"},
+{"name": "judy mandel"},
+{"name": "rene cisco"},
+{"name": "dan laidley"},
+{"name": "scott her"},
+{"name": "trent dilfer"},
+{"name": "ned rukavina"},
+{"name": "donna lee"},
+{"name": "jim q"},
+{"name": "mark cantey"},
+{"name": "danyel gable"},
+{"name": "moon gondolier"},
+{"name": "jay petruska"},
+{"name": "mel varrone"},
+{"name": "john gidwitz"},
+{"name": "kay bailey"},
+{"name": "lance hodges"},
+{"name": "tandra harris"},
+{"name": "rachel zusman"},
+{"name": "tony rome"},
+{"name": "gene dahmes"},
+{"name": "karl madcharo"},
+{"name": "janet saaka"},
+{"name": "emily neff"},
+{"name": "debra behnke"},
+{"name": "vince bruno"},
+{"name": "bob kelley"},
+{"name": "scott baldwin"},
+{"name": "freddy sidi"},
+{"name": "scott ingerson"},
+{"name": "jon clark"},
+{"name": "jim holley"},
+{"name": "todd compston"},
+{"name": "troy detroit"},
+{"name": "allison lewis"},
+{"name": "edward thomas"},
+{"name": "jordan gardner"},
+{"name": "jean augustin"},
+{"name": "zack paintball"},
+{"name": "sid cuevas"},
+{"name": "judy kushner"},
+{"name": "kenny zuckerman"},
+{"name": "sara cell"},
+{"name": "ed dempsey"},
+{"name": "ashley niler"},
+{"name": "paige powell"},
+{"name": "jason gillman"},
+{"name": "royal riverside"},
+{"name": "mark chambers"},
+{"name": "jerry roberts"},
+{"name": "chelsea thaxter"},
+{"name": "christian fox"},
+{"name": "joe alerio"},
+{"name": "cindi hunter"},
+{"name": "ralph mayer"},
+{"name": "annette blevins"},
+{"name": "carie sales"},
+{"name": "manuel martinez"},
+{"name": "daniel hurley"},
+{"name": "leo melenoski"},
+{"name": "megan desk"},
+{"name": "tony rogers"},
+{"name": "rafael ilwu"},
+{"name": "mica cabildo"},
+{"name": "lois kleisinger"},
+{"name": "laura narducci"},
+{"name": "erin davis"},
+{"name": "peter ballin"},
+{"name": "daniel wood"},
+{"name": "marianne poff"},
+{"name": "kelsey c"},
+{"name": "cody horning"},
+{"name": "mariana danilovic"},
+{"name": "josh wagner"},
+{"name": "maria luckevich"},
+{"name": "debbie fey"},
+{"name": "christopher longo"},
+{"name": "danny yagman"},
+{"name": "danny fetter"},
+{"name": "steve neal"},
+{"name": "katie alyssa"},
+{"name": "william wiese"},
+{"name": "karen talsma"},
+{"name": "bob vairo"},
+{"name": "don beck"},
+{"name": "johnny mobile"},
+{"name": "dan wyatt"},
+{"name": "dennis mcgee"},
+{"name": "tom ketchem"},
+{"name": "anthony ruiz"},
+{"name": "melissa tell"},
+{"name": "craig hudson"},
+{"name": "dee roscoe"},
+{"name": "eileen shatzman"},
+{"name": "bernard griffith"},
+{"name": "camila peterson"},
+{"name": "mark losby"},
+{"name": "rob bowe"},
+{"name": "ben matias"},
+{"name": "anthony pilny"},
+{"name": "julie rain"},
+{"name": "todd roberts"},
+{"name": "jerry rust"},
+{"name": "roberta fox"},
+{"name": "monique gaudet"},
+{"name": "stuart rosenfield"},
+{"name": "sheridan dallon"},
+{"name": "eric room"},
+{"name": "katherine kirkwood"},
+{"name": "mario costello"},
+{"name": "sarah carter"},
+{"name": "michael cobb"},
+{"name": "jeff tovez"},
+{"name": "scott stephens"},
+{"name": "debbie lee"},
+{"name": "mark krajnak"},
+{"name": "rose wilkinson"},
+{"name": "karen rooks"},
+{"name": "kyle mcdonald"},
+{"name": "dave yates"},
+{"name": "christian rasmussen"},
+{"name": "kenneth fiedler"},
+{"name": "shawn scott"},
+{"name": "erin bovendam"},
+{"name": "sarai allen"},
+{"name": "phil brown"},
+{"name": "jean schutt"},
+{"name": "van vu"},
+{"name": "kelly heath"},
+{"name": "bill bogg"},
+{"name": "mark helffrich"},
+{"name": "kristi com"},
+{"name": "joe miseli"},
+{"name": "tommye davis"},
+{"name": "crystal townsend"},
+{"name": "marc behrman"},
+{"name": "matt haney"},
+{"name": "chris guymon"},
+{"name": "james f"},
+{"name": "ken anderson"},
+{"name": "howard livingston"},
+{"name": "penny power"},
+{"name": "kurt koontz"},
+{"name": "justin cleary"},
+{"name": "mike assayag"},
+{"name": "lisa sambucci"},
+{"name": "cassidy model"},
+{"name": "peter monaco"},
+{"name": "phil bond"},
+{"name": "jess dichter"},
+{"name": "perry sihra"},
+{"name": "john syrcle"},
+{"name": "katharine drake"},
+{"name": "amber central"},
+{"name": "marcy crandall"},
+{"name": "patrick jennings"},
+{"name": "tony plaza"},
+{"name": "diana ramirez"},
+{"name": "hilary lane"},
+{"name": "jason petty"},
+{"name": "rachelle buhl"},
+{"name": "alicia cho"},
+{"name": "joe mcguckin"},
+{"name": "mike maria's"},
+{"name": "jon gabriel"},
+{"name": "earl stamatkin"},
+{"name": "sarah holroyd"},
+{"name": "lori endy"},
+{"name": "barb firchow"},
+{"name": "clifford ryan"},
+{"name": "james mifsud"},
+{"name": "adam emery"},
+{"name": "omar g"},
+{"name": "lisa paris"},
+{"name": "pia franco"},
+{"name": "nicola larry"},
+{"name": "lynda eubanks"},
+{"name": "kieth farmer"},
+{"name": "aaron kinard"},
+{"name": "henry pakbaz"},
+{"name": "janet holtman"},
+{"name": "pam morgan"},
+{"name": "garrett sanders"},
+{"name": "luis diablo"},
+{"name": "alisha garber"},
+{"name": "vicky sheehan"},
+{"name": "jennifer wright"},
+{"name": "jason green"},
+{"name": "letty quintanilla"},
+{"name": "chris stigall"},
+{"name": "dave milmine"},
+{"name": "kelly riley"},
+{"name": "mark finlinson"},
+{"name": "ken lorincz"},
+{"name": "ricardo jardim"},
+{"name": "graham urey"},
+{"name": "john ebia"},
+{"name": "jennifer gallego"},
+{"name": "lia model"},
+{"name": "jim favors"},
+{"name": "nathan ross"},
+{"name": "john belsher"},
+{"name": "brad nt"},
+{"name": "bill froelich"},
+{"name": "alanna sylvester"},
+{"name": "cheryl stevenson"},
+{"name": "sara canaday"},
+{"name": "nick kiland"},
+{"name": "jason gregory"},
+{"name": "carl kupfer"},
+{"name": "barry molteni"},
+{"name": "david eisenberg"},
+{"name": "roman schlaeger"},
+{"name": "allison baur"},
+{"name": "kelli cordova"},
+{"name": "john second"},
+{"name": "shelli dillon"},
+{"name": "jamie henry"},
+{"name": "mark frey"},
+{"name": "cassie tatum"},
+{"name": "johnny shimek"},
+{"name": "rick montalvo"},
+{"name": "holly v"},
+{"name": "michelle muhammad"},
+{"name": "maurice rawles"},
+{"name": "bryan tam"},
+{"name": "emily haarberg"},
+{"name": "brice hancock"},
+{"name": "ulrike moukabary"},
+{"name": "john menke"},
+{"name": "nathan walden"},
+{"name": "carmelita caimol"},
+{"name": "stephanie gehlenborg"},
+{"name": "dan koupal"},
+{"name": "dawn holcomb"},
+{"name": "rob bradley"},
+{"name": "bruce botkin"},
+{"name": "kris tetter"},
+{"name": "betty wooten"},
+{"name": "sheldon midnight"},
+{"name": "megan henderson"},
+{"name": "nicole dallo"},
+{"name": "jerry spirits"},
+{"name": "jimmy mclemore"},
+{"name": "jeanette mossman"},
+{"name": "johnny sangkam"},
+{"name": "lewis mowatt"},
+{"name": "sean big"},
+{"name": "marcia mazzocchi"},
+{"name": "margaret wilburn"},
+{"name": "manuel nava"},
+{"name": "tom bernal"},
+{"name": "charles clark"},
+{"name": "daren monnaco"},
+{"name": "andy sanchez"},
+{"name": "sofia hotel"},
+{"name": "preston medeiros"},
+{"name": "carl vilrich"},
+{"name": "dot kline"},
+{"name": "craig carlson"},
+{"name": "travis zack"},
+{"name": "vern marome"},
+{"name": "phil doukas"},
+{"name": "diane rakers"},
+{"name": "tom pom"},
+{"name": "mike dittman"},
+{"name": "ashley horn"},
+{"name": "bill follet"},
+{"name": "denny holmes"},
+{"name": "laura janis"},
+{"name": "ross fulmer"},
+{"name": "bob stanley"},
+{"name": "francis clayton"},
+{"name": "jeffrey batovsky"},
+{"name": "al roggow"},
+{"name": "moshe kurtz"},
+{"name": "robert strong"},
+{"name": "bill kavan"},
+{"name": "john davi"},
+{"name": "amy allison"},
+{"name": "mary miller"},
+{"name": "sean keven"},
+{"name": "mandy goat"},
+{"name": "david olivas"},
+{"name": "max erma's"},
+{"name": "joaquin ortiz"},
+{"name": "john vehlow"},
+{"name": "jordan foley"},
+{"name": "kathleen makris"},
+{"name": "otto molz"},
+{"name": "patrick kenealy"},
+{"name": "matt stepanovich"},
+{"name": "tara campbell"},
+{"name": "joe namath"},
+{"name": "allison ramsey"},
+{"name": "jason nutter"},
+{"name": "mark wallace"},
+{"name": "ryan jackson"},
+{"name": "alvaro vega"},
+{"name": "peggy mok"},
+{"name": "kris h"},
+{"name": "cathy strong"},
+{"name": "buddy lazier"},
+{"name": "michelle lore"},
+{"name": "carson parks"},
+{"name": "julie straus"},
+{"name": "jean suyenaga"},
+{"name": "fred myer"},
+{"name": "jon toomey"},
+{"name": "pilar hall"},
+{"name": "lauren gillespie"},
+{"name": "chase b"},
+{"name": "malcolm floyd"},
+{"name": "frank polachuck"},
+{"name": "sheila colman"},
+{"name": "janna beck"},
+{"name": "eddie johnson"},
+{"name": "brian lipman"},
+{"name": "lin shih"},
+{"name": "abe home"},
+{"name": "monique b"},
+{"name": "will mooney"},
+{"name": "sean lafrance"},
+{"name": "jeff sindicate"},
+{"name": "toby buchanan"},
+{"name": "felipe marin"},
+{"name": "peter dempster"},
+{"name": "chris hardlin"},
+{"name": "michelle zimmerer"},
+{"name": "phil campbell"},
+{"name": "chris j"},
+{"name": "lonnie moore"},
+{"name": "casey mincof"},
+{"name": "karma entertainment"},
+{"name": "alec kushnir"},
+{"name": "eric huguelet"},
+{"name": "mark yorgey"},
+{"name": "sharon payton"},
+{"name": "angie locke"},
+{"name": "van booven"},
+{"name": "gregoria vallejo"},
+{"name": "liz blaylock"},
+{"name": "larry ryan"},
+{"name": "linda gilmore"},
+{"name": "kellie cell"},
+{"name": "jennifer flores"},
+{"name": "kristen baker"},
+{"name": "amber vop"},
+{"name": "gus overstreet"},
+{"name": "jeremiah fritz"},
+{"name": "tom titus"},
+{"name": "barry armer"},
+{"name": "kim kennedy"},
+{"name": "christine sinclair"},
+{"name": "melissa scarafino"},
+{"name": "sarah graider"},
+{"name": "jay jaguar"},
+{"name": "danny neighbor"},
+{"name": "jeff runquist"},
+{"name": "jason kent"},
+{"name": "alex guerrero"},
+{"name": "anthony hairston"},
+{"name": "elizabeth blake"},
+{"name": "vivian popenhagen"},
+{"name": "elisabeth anderson"},
+{"name": "kimberley nicholas"},
+{"name": "jen bradford"},
+{"name": "karen regal"},
+{"name": "michael fuller"},
+{"name": "luke travins"},
+{"name": "bill droessler"},
+{"name": "mario pando"},
+{"name": "thelma nudo"},
+{"name": "jim winegardner"},
+{"name": "linda heath"},
+{"name": "bill ledingham"},
+{"name": "marvin gilliam"},
+{"name": "al phillips"},
+{"name": "saul salcedo"},
+{"name": "owen dolan"},
+{"name": "juan amaya"},
+{"name": "darlene cell"},
+{"name": "golden pizza"},
+{"name": "jimmy ngo"},
+{"name": "mike bryant"},
+{"name": "chang pf"},
+{"name": "matt davies"},
+{"name": "charisse davidian"},
+{"name": "jasmin garcia"},
+{"name": "david cantwell"},
+{"name": "chris weir"},
+{"name": "mike sepela"},
+{"name": "sue nelson"},
+{"name": "travis evans"},
+{"name": "carole mckinny"},
+{"name": "don buckingham"},
+{"name": "crystal gaza"},
+{"name": "bill larsen"},
+{"name": "sarah debolt"},
+{"name": "aleida osorio"},
+{"name": "justin erickson"},
+{"name": "brian youngin"},
+{"name": "william sirkis"},
+{"name": "chris premo"},
+{"name": "kelly o'bryan"},
+{"name": "ana esterov"},
+{"name": "corey cell"},
+{"name": "rod chaney"},
+{"name": "cynthia arredondo"},
+{"name": "frank monack"},
+{"name": "jack harper"},
+{"name": "tina geffken"},
+{"name": "kelly o'neill"},
+{"name": "mike petersen"},
+{"name": "denise bedford"},
+{"name": "patrick muldoon"},
+{"name": "candice garcia"},
+{"name": "leon srfan"},
+{"name": "bob lager"},
+{"name": "justine m"},
+{"name": "karla jurado"},
+{"name": "david lloyd"},
+{"name": "amanda atkison"},
+{"name": "stan zeyer"},
+{"name": "kelly allen"},
+{"name": "cora maclean"},
+{"name": "joe maffey"},
+{"name": "chad dunn"},
+{"name": "mike austin"},
+{"name": "matt mcelwee"},
+{"name": "susan costa"},
+{"name": "stan doll"},
+{"name": "pat davis"},
+{"name": "heidi olson"},
+{"name": "mary le"},
+{"name": "wen yang"},
+{"name": "jonathon jusino"},
+{"name": "jay buds"},
+{"name": "manuel pina"},
+{"name": "danielle rhymes"},
+{"name": "dena aloian"},
+{"name": "john dicuollo"},
+{"name": "catherine minster"},
+{"name": "justin nuckolls"},
+{"name": "donna scott"},
+{"name": "steve adler"},
+{"name": "dave maldonado"},
+{"name": "dave carter"},
+{"name": "brian dyer"},
+{"name": "steve o'sillivan"},
+{"name": "roger wolf"},
+{"name": "chris snow"},
+{"name": "lady hosley"},
+{"name": "robert ba"},
+{"name": "dave carlile"},
+{"name": "brent bornmann"},
+{"name": "conrad c"},
+{"name": "kevin wills"},
+{"name": "mariana butte"},
+{"name": "mary hanka"},
+{"name": "jennifer koplow"},
+{"name": "corey walker"},
+{"name": "sam zises"},
+{"name": "peter walling"},
+{"name": "leah durst"},
+{"name": "alan perkins"},
+{"name": "dawn wujcik"},
+{"name": "juan macias"},
+{"name": "erick micheles"},
+{"name": "jeff patterson"},
+{"name": "anthony moore"},
+{"name": "sheila valdez"},
+{"name": "alice estes"},
+{"name": "michael hudes"},
+{"name": "jane legore"},
+{"name": "billy sutton"},
+{"name": "william feaster"},
+{"name": "john topaloff"},
+{"name": "darrel thomas"},
+{"name": "linda modano"},
+{"name": "steve mcdonough"},
+{"name": "jed otown"},
+{"name": "paul guitar"},
+{"name": "david hanssens"},
+{"name": "deb cf"},
+{"name": "phyliss martin"},
+{"name": "lauren perkins"},
+{"name": "kristy wu"},
+{"name": "carol cox"},
+{"name": "nick pallo"},
+{"name": "george koelsch"},
+{"name": "jeremy baily"},
+{"name": "alexis g"},
+{"name": "valerie decristofaro"},
+{"name": "josh chambers"},
+{"name": "trish oneal"},
+{"name": "karen huey"},
+{"name": "ross coralville"},
+{"name": "howard pinkston"},
+{"name": "heather fellows"},
+{"name": "minnie mueller"},
+{"name": "jay howard"},
+{"name": "faye bland"},
+{"name": "mike moritz"},
+{"name": "cindy organ"},
+{"name": "kevin o"},
+{"name": "dave logan"},
+{"name": "jeff bernstein"},
+{"name": "bryce miller"},
+{"name": "mae ceralvo"},
+{"name": "sarah davis"},
+{"name": "jeff kuhl"},
+{"name": "david close"},
+{"name": "chante boyfriend"},
+{"name": "kimberly clark"},
+{"name": "robin cent"},
+{"name": "elena dewart"},
+{"name": "lori swetlin"},
+{"name": "betty green"},
+{"name": "kandace fierro"},
+{"name": "sue stanley"},
+{"name": "sydney hanson"},
+{"name": "cheryl thomas"},
+{"name": "roger dudley"},
+{"name": "michael conner"},
+{"name": "karina rojas"},
+{"name": "david yurden"},
+{"name": "terry bosik"},
+{"name": "mike wherley"},
+{"name": "jason o'hearn"},
+{"name": "mike savner"},
+{"name": "jim dearmond"},
+{"name": "danny city"},
+{"name": "charles enoch"},
+{"name": "tony kutolus"},
+{"name": "ryan nichols"},
+{"name": "john mencos"},
+{"name": "steven peters"},
+{"name": "shirley p"},
+{"name": "hunter cooksey"},
+{"name": "brad lnsfrd"},
+{"name": "jeff fike"},
+{"name": "britany hawkins"},
+{"name": "mike hoffman"},
+{"name": "carol mom"},
+{"name": "thomas papantonis"},
+{"name": "jesse gospodarek"},
+{"name": "rodger desai"},
+{"name": "john snethkamp"},
+{"name": "kelly carney"},
+{"name": "david bailey"},
+{"name": "george tabash"},
+{"name": "holly hamilton"},
+{"name": "nancy toojack"},
+{"name": "melissa cole"},
+{"name": "steve noell"},
+{"name": "pat mellitt"},
+{"name": "margarita suarez"},
+{"name": "irvin prioleau"},
+{"name": "micha reich"},
+{"name": "erica jennings"},
+{"name": "garret broussard"},
+{"name": "ty vanheusen"},
+{"name": "val roller"},
+{"name": "clay greer"},
+{"name": "patti o'reilly"},
+{"name": "ross willard"},
+{"name": "karen morgan"},
+{"name": "jay wittenborn"},
+{"name": "adrian gonzalez"},
+{"name": "alyssa s"},
+{"name": "nancy harrif"},
+{"name": "dustin mcnich"},
+{"name": "kara jones"},
+{"name": "jeremiah webb"},
+{"name": "paul ferrera"},
+{"name": "matt englebert"},
+{"name": "eric fl"},
+{"name": "jeremy smith"},
+{"name": "joe astin"},
+{"name": "christian loredo"},
+{"name": "gwendolyn miranda"},
+{"name": "jay preece"},
+{"name": "logan jonson"},
+{"name": "silva smith"},
+{"name": "gail agcaoili"},
+{"name": "darius mccall"},
+{"name": "edward walker"},
+{"name": "maria sis"},
+{"name": "james lithonia"},
+{"name": "matt windels"},
+{"name": "mike soltani"},
+{"name": "cherry mayberry"},
+{"name": "dusty snyder"},
+{"name": "anthony sean"},
+{"name": "richard strouse"},
+{"name": "bruce steinke"},
+{"name": "dale roofing"},
+{"name": "kristin macdonald"},
+{"name": "carin childress"},
+{"name": "susan cooper"},
+{"name": "tracy biller"},
+{"name": "justin radcliffe"},
+{"name": "anna miranda"},
+{"name": "mike burillo"},
+{"name": "andy su"},
+{"name": "jim behun"},
+{"name": "horace direct"},
+{"name": "brittany wells"},
+{"name": "troy maddox"},
+{"name": "peter spielman"},
+{"name": "pat turner"},
+{"name": "elizabeth hottie"},
+{"name": "melvin xbox"},
+{"name": "casey anderson"},
+{"name": "noble jones"},
+{"name": "lisa ward"},
+{"name": "george blazer"},
+{"name": "chris sparks"},
+{"name": "taylor klundt"},
+{"name": "john cortez"},
+{"name": "tom carmody"},
+{"name": "dan crues"},
+{"name": "sean meyerhoffer"},
+{"name": "mike marchi"},
+{"name": "beth rostan"},
+{"name": "george ronay"},
+{"name": "francis marian"},
+{"name": "teresa pulido"},
+{"name": "tom tubbs"},
+{"name": "shane wheeler"},
+{"name": "mandi modderman"},
+{"name": "tony hatz"},
+{"name": "charlene meyeraan"},
+{"name": "toni vernon"},
+{"name": "carol snow"},
+{"name": "britt chubs"},
+{"name": "josh jenson"},
+{"name": "vicki ostrander"},
+{"name": "cheryl ealey"},
+{"name": "mitchell glenn"},
+{"name": "alex gondola"},
+{"name": "ashley morgan"},
+{"name": "renee hanson"},
+{"name": "donna flowers"},
+{"name": "john simpson"},
+{"name": "kris s"},
+{"name": "jim beagle"},
+{"name": "lisa duerbeck"},
+{"name": "brian rucker"},
+{"name": "gilbert storage"},
+{"name": "ricky douglas"},
+{"name": "bruce francey"},
+{"name": "savanna rose"},
+{"name": "dean kennett"},
+{"name": "claude foster"},
+{"name": "frankie christian"},
+{"name": "kevin focht"},
+{"name": "irene taquian"},
+{"name": "deanna estrada"},
+{"name": "helen allen"},
+{"name": "tori black"},
+{"name": "lacey l"},
+{"name": "harold darge"},
+{"name": "bill kramer"},
+{"name": "jeff latham"},
+{"name": "angela petersen"},
+{"name": "cari autry"},
+{"name": "tim morgan"},
+{"name": "sam short"},
+{"name": "sam banano"},
+{"name": "joanna tarnawski"},
+{"name": "dana knave"},
+{"name": "rob netherton"},
+{"name": "julie zimmerman"},
+{"name": "roxanne roberts"},
+{"name": "michael ryan"},
+{"name": "mike beebe"},
+{"name": "elana calif"},
+{"name": "jennifer heimann"},
+{"name": "emily kyzer"},
+{"name": "judy clemon"},
+{"name": "rachel bass"},
+{"name": "steve hegwood"},
+{"name": "sarah master"},
+{"name": "ryan redeci"},
+{"name": "rob desilets"},
+{"name": "janette terry"},
+{"name": "cheryl sutherland"},
+{"name": "katie sactown"},
+{"name": "melissa murphy"},
+{"name": "debbie olshevski"},
+{"name": "brad erney"},
+{"name": "shaunte tweedie"},
+{"name": "bob traskowski"},
+{"name": "casey clair"},
+{"name": "terry clarke"},
+{"name": "andrea miller"},
+{"name": "fritz kaegi"},
+{"name": "bennett williams"},
+{"name": "nicole steakley"},
+{"name": "ben stiehl"},
+{"name": "prince home"},
+{"name": "mark herman"},
+{"name": "cynthia tietze"},
+{"name": "francie e"},
+{"name": "brandon br"},
+{"name": "george c"},
+{"name": "gary hebner"},
+{"name": "kristine luat"},
+{"name": "roy campbell"},
+{"name": "marcie ruddy"},
+{"name": "roy randel"},
+{"name": "andrew rodman"},
+{"name": "gena k"},
+{"name": "pam phee"},
+{"name": "marc manning"},
+{"name": "bryce sitter"},
+{"name": "fairy williams"},
+{"name": "jim france"},
+{"name": "denise vick"},
+{"name": "andreas grothe"},
+{"name": "anthony wozniak"},
+{"name": "barbie graser"},
+{"name": "heather braund"},
+{"name": "rob saliterman"},
+{"name": "alex lopez"},
+{"name": "joe spedale"},
+{"name": "robin leckinger"},
+{"name": "nancy hanson"},
+{"name": "andy rappela"},
+{"name": "cary palmer"},
+{"name": "sergio cell"},
+{"name": "garrett hachkowski"},
+{"name": "chris fradenburg"},
+{"name": "louis kafkes"},
+{"name": "steve jacobs"},
+{"name": "monica katzel"},
+{"name": "donnie locke"},
+{"name": "dave mellin"},
+{"name": "jeff hollenbeck"},
+{"name": "daniel mireles"},
+{"name": "sonya ilwu"},
+{"name": "tara blanton"},
+{"name": "christopher argentina"},
+{"name": "john stark"},
+{"name": "catherine gautot"},
+{"name": "darryl white"},
+{"name": "marsha lochard"},
+{"name": "laura rays"},
+{"name": "lori ladnier"},
+{"name": "jessica levon"},
+{"name": "bill egan"},
+{"name": "thomas mortenson"},
+{"name": "jim abrams"},
+{"name": "janna cryer"},
+{"name": "corey wight"},
+{"name": "lydia yung"},
+{"name": "joel home"},
+{"name": "van pools"},
+{"name": "roman mullokandov"},
+{"name": "mike post"},
+{"name": "christina seamus"},
+{"name": "jeff farnsworth"},
+{"name": "judy widener"},
+{"name": "rebecca shepard"},
+{"name": "dave davis"},
+{"name": "lester sprint"},
+{"name": "janet zamecnik"},
+{"name": "bradley roofing"},
+{"name": "cheryl stevens"},
+{"name": "steve sheldon"},
+{"name": "craig karmazin"},
+{"name": "rochelle price"},
+{"name": "pam turney"},
+{"name": "pamela hemphill"},
+{"name": "kathryn rizzi"},
+{"name": "penny cash"},
+{"name": "antoine sims"},
+{"name": "jeremiah peterson"},
+{"name": "howard thompson"},
+{"name": "kathleen mccomber"},
+{"name": "tiffany p"},
+{"name": "ed corwin"},
+{"name": "mark fanty"},
+{"name": "phyllis sicurezza"},
+{"name": "heather derryberry"},
+{"name": "grace obra"},
+{"name": "rick winder"},
+{"name": "jeremy wallace"},
+{"name": "dora gottesman"},
+{"name": "erin molly"},
+{"name": "justin new"},
+{"name": "anna chennault"},
+{"name": "carl norman"},
+{"name": "sasha model"},
+{"name": "beth cross"},
+{"name": "allen leach"},
+{"name": "lisa stokes"},
+{"name": "leah moore"},
+{"name": "anne talbert"},
+{"name": "george chey"},
+{"name": "alex shor"},
+{"name": "mark grajalva"},
+{"name": "sharon ncbh"},
+{"name": "william fulcher"},
+{"name": "anthony ali"},
+{"name": "nora guenther"},
+{"name": "dwight nance"},
+{"name": "amanda o'connor"},
+{"name": "tania sakalu"},
+{"name": "tim layhe"},
+{"name": "kevin coppin"},
+{"name": "austin park"},
+{"name": "mike urso"},
+{"name": "sharon spence"},
+{"name": "sam livingood"},
+{"name": "sammy ngetich"},
+{"name": "dennis rivas"},
+{"name": "anita mitchell"},
+{"name": "lisa natapow"},
+{"name": "nancy livingstun"},
+{"name": "josh wilcox"},
+{"name": "mercedez munoz"},
+{"name": "john blue"},
+{"name": "mario bocanegra"},
+{"name": "beth butler"},
+{"name": "matt beth"},
+{"name": "victor chocolate"},
+{"name": "graham matthews"},
+{"name": "richard johnson"},
+{"name": "brian luft"},
+{"name": "jesse rosenthal"},
+{"name": "darren huslig"},
+{"name": "kathy triplett"},
+{"name": "chana lehman"},
+{"name": "natalie christensen"},
+{"name": "mario demita"},
+{"name": "meghan rose"},
+{"name": "dan kempke"},
+{"name": "kris lloyd"},
+{"name": "lynette ferra"},
+{"name": "tim berry"},
+{"name": "joanna onato"},
+{"name": "robert roach"},
+{"name": "helen vu"},
+{"name": "hassan murphy"},
+{"name": "lance keg"},
+{"name": "sheri blaker"},
+{"name": "lisa rothbard"},
+{"name": "max liquid"},
+{"name": "scott cluck"},
+{"name": "gale peters"},
+{"name": "ron vartabedian"},
+{"name": "galen hardy@zappos"},
+{"name": "teri john"},
+{"name": "tien bui"},
+{"name": "art cook"},
+{"name": "nigel lewis"},
+{"name": "ana franca"},
+{"name": "elizabeth wells"},
+{"name": "jason custer"},
+{"name": "dan crowell"},
+{"name": "mary thornton"},
+{"name": "arthur herzfeld"},
+{"name": "anthony chan"},
+{"name": "mark webster"},
+{"name": "michael inge"},
+{"name": "robin mom"},
+{"name": "stephanie anderson"},
+{"name": "terry fail"},
+{"name": "jamey york"},
+{"name": "darren greenough"},
+{"name": "mike sipes"},
+{"name": "jen stubbs"},
+{"name": "claire walker"},
+{"name": "sally montgomery"},
+{"name": "julie lin"},
+{"name": "dee hamilton"},
+{"name": "david jean"},
+{"name": "katherine blackburn"},
+{"name": "glenn thomas"},
+{"name": "beau lamontage"},
+{"name": "crystal barn"},
+{"name": "mark spyrison"},
+{"name": "sandra sumrall"},
+{"name": "derrick frazer"},
+{"name": "matt mcgurk"},
+{"name": "gillian milne"},
+{"name": "brian medvedoff"},
+{"name": "hiedi robsinson"},
+{"name": "amanda schirber"},
+{"name": "taylor foundation"},
+{"name": "kayla mcgregor"},
+{"name": "kristina sanders"},
+{"name": "shannon shell"},
+{"name": "nancy margeson"},
+{"name": "barbara thompson"},
+{"name": "betty munyon"},
+{"name": "summer ruckh"},
+{"name": "ed lawyer"},
+{"name": "mike shaw"},
+{"name": "christine skutch"},
+{"name": "mark hester"},
+{"name": "scott hardin"},
+{"name": "tommy atkins"},
+{"name": "shayna jeffers"},
+{"name": "michel terzian"},
+{"name": "george badour"},
+{"name": "leo costales"},
+{"name": "james selna"},
+{"name": "tim fawn"},
+{"name": "matt pastorelli"},
+{"name": "dave voy"},
+{"name": "james foster"},
+{"name": "bill wu"},
+{"name": "jon cromartie"},
+{"name": "kevin shea"},
+{"name": "greg lewbart"},
+{"name": "todd doerner"},
+{"name": "dave cronin"},
+{"name": "debbie mcadams"},
+{"name": "boris ondercin"},
+{"name": "marianne fowler"},
+{"name": "amy bartnes"},
+{"name": "rosie jackson"},
+{"name": "dakota wolfe"},
+{"name": "john hardy"},
+{"name": "ted christa"},
+{"name": "kate diizy"},
+{"name": "mark aponte"},
+{"name": "ken sypolt"},
+{"name": "paola client"},
+{"name": "josh neiheisel"},
+{"name": "tracy nicholas"},
+{"name": "steve mueller"},
+{"name": "nancy rusas"},
+{"name": "susan schulte"},
+{"name": "trisha struble"},
+{"name": "joan shefferman"},
+{"name": "ethan lyell"},
+{"name": "brandon reed"},
+{"name": "lisa kleinman"},
+{"name": "craig gustafson"},
+{"name": "keith hanson"},
+{"name": "charles harris"},
+{"name": "andrew close"},
+{"name": "jenine garroutte"},
+{"name": "betsy burton"},
+{"name": "kelly bburg"},
+{"name": "samuel abraham"},
+{"name": "jennifer kyle"},
+{"name": "michael attenborough"},
+{"name": "richard groome"},
+{"name": "tina p"},
+{"name": "wendy chandler"},
+{"name": "wesley walmart"},
+{"name": "kimberly berry"},
+{"name": "john smythe"},
+{"name": "carrie stewart"},
+{"name": "jason dupont"},
+{"name": "jennifer david"},
+{"name": "robin m"},
+{"name": "ryan warren"},
+{"name": "cari dyer"},
+{"name": "alex smirnov"},
+{"name": "brad steele"},
+{"name": "james reckert"},
+{"name": "christina girl"},
+{"name": "kristin schwanke"},
+{"name": "melissa bg"},
+{"name": "colleen anderson"},
+{"name": "cristy bertoldi"},
+{"name": "brian felty"},
+{"name": "mike hawrysz"},
+{"name": "stephanie werther"},
+{"name": "rick graham"},
+{"name": "andrew rippy"},
+{"name": "francisco suits"},
+{"name": "lynn irwin"},
+{"name": "john greene"},
+{"name": "jamal pittman"},
+{"name": "tom thompson"},
+{"name": "tom farlow"},
+{"name": "amanda gusse"},
+{"name": "glen rinzler"},
+{"name": "ruben garcia"},
+{"name": "carolina sepulvida"},
+{"name": "jeffrey stoops"},
+{"name": "johnny august"},
+{"name": "trinity osborn"},
+{"name": "sydney stewart"},
+{"name": "joe comerford"},
+{"name": "lenny phelps"},
+{"name": "jeff whizzle"},
+{"name": "rich arapahoe"},
+{"name": "bobby sullavin"},
+{"name": "chris bmw"},
+{"name": "jim kronvoldt"},
+{"name": "lynne hummel"},
+{"name": "jada wilds"},
+{"name": "joe quernomoen"},
+{"name": "jorge macias"},
+{"name": "jim fitzpatrick"},
+{"name": "jose guzman"},
+{"name": "peter teaney"},
+{"name": "kathy castaneda"},
+{"name": "melanie ketter"},
+{"name": "katie fl"},
+{"name": "mindy murphy"},
+{"name": "juanita gomes"},
+{"name": "eric munoz"},
+{"name": "chuck wheaton"},
+{"name": "stacie thurston"},
+{"name": "david cole"},
+{"name": "corrine strempler"},
+{"name": "russell meketa"},
+{"name": "kevin weber"},
+{"name": "shari raphael"},
+{"name": "james rooney"},
+{"name": "karla gonzalez"},
+{"name": "danielle mordechai"},
+{"name": "tamra kochenash"},
+{"name": "hazel james"},
+{"name": "mark endo"},
+{"name": "susanna lowy"},
+{"name": "ella thompson"},
+{"name": "byron register"},
+{"name": "richard schultz"},
+{"name": "peter hill"},
+{"name": "macie bell"},
+{"name": "joe hacking"},
+{"name": "ed murphy"},
+{"name": "sandra rivas"},
+{"name": "thelma roby"},
+{"name": "zoe g"},
+{"name": "lynn dacus"},
+{"name": "scotty fox"},
+{"name": "dawn marchozzi"},
+{"name": "jason rood"},
+{"name": "felicia joseph"},
+{"name": "marie harris"},
+{"name": "cory webber"},
+{"name": "roy saxman"},
+{"name": "james buckner"},
+{"name": "alex okura"},
+{"name": "madison sanese"},
+{"name": "chuck johnson"},
+{"name": "jenny mom"},
+{"name": "rob mccarger"},
+{"name": "mackenzie lovings"},
+{"name": "marie forte"},
+{"name": "amy eskridge"},
+{"name": "china cafe"},
+{"name": "shaun tavazoie"},
+{"name": "cherise webb"},
+{"name": "lora liberty"},
+{"name": "dave lawrence"},
+{"name": "mike guidotti"},
+{"name": "louie roommate"},
+{"name": "philip bush"},
+{"name": "jayne pasatoro"},
+{"name": "cynthia corbett"},
+{"name": "melanie hall"},
+{"name": "myra pierce"},
+{"name": "jay graif"},
+{"name": "marcia goffin"},
+{"name": "william depalma"},
+{"name": "andy devlin"},
+{"name": "ashley utc"},
+{"name": "jenna george"},
+{"name": "susan darnell"},
+{"name": "lori strusis"},
+{"name": "shawn doman"},
+{"name": "emily lemanczyk"},
+{"name": "simone florida"},
+{"name": "monty sahni"},
+{"name": "alison weder"},
+{"name": "regina warren"},
+{"name": "toni bar"},
+{"name": "jamie berfield"},
+{"name": "pam beckwith"},
+{"name": "jerome bonnett"},
+{"name": "molly davidson"},
+{"name": "nora soohoo"},
+{"name": "dana french"},
+{"name": "jim burke"},
+{"name": "hilary foelker"},
+{"name": "tom lowderbaugh"},
+{"name": "kevin o'connor"},
+{"name": "karen broughton"},
+{"name": "david kiehl"},
+{"name": "shannon finn"},
+{"name": "meredith gray"},
+{"name": "david nixon"},
+{"name": "sharon derrick"},
+{"name": "greg thompson"},
+{"name": "lorie bartron"},
+{"name": "craig ruybalid"},
+{"name": "lisa fisher"},
+{"name": "chris sailus"},
+{"name": "jarod ewan"},
+{"name": "jerrod rumley"},
+{"name": "doug wagg"},
+{"name": "spencer gonzalez"},
+{"name": "francis almario"},
+{"name": "eddie stallworth"},
+{"name": "brett hpd"},
+{"name": "alan delmar"},
+{"name": "kelly met"},
+{"name": "maureen chang"},
+{"name": "rusty selix"},
+{"name": "adam drell"},
+{"name": "jonathan lewinson"},
+{"name": "talitha warby"},
+{"name": "del nodal"},
+{"name": "daniel ryan"},
+{"name": "jayson leibowitz"},
+{"name": "mark miller"},
+{"name": "leonard jed"},
+{"name": "jane asu"},
+{"name": "taylor mp"},
+{"name": "paul brownlee"},
+{"name": "paul ogrady"},
+{"name": "justin hughes"},
+{"name": "joe bernhardt"},
+{"name": "sergio irizarry"},
+{"name": "richard gonzalez"},
+{"name": "vicky griffiths"},
+{"name": "sherry garrelts"},
+{"name": "phillip lynch"},
+{"name": "drew piriak"},
+{"name": "gerry wawzonek"},
+{"name": "jimmy fontana"},
+{"name": "curtis bush"},
+{"name": "rick kemp"},
+{"name": "david graddy"},
+{"name": "todd benny"},
+{"name": "kathleen harris"},
+{"name": "amanda trader"},
+{"name": "john g"},
+{"name": "dan bucholt"},
+{"name": "claude deemer"},
+{"name": "danny banek"},
+{"name": "wayne haberkorn"},
+{"name": "steve kim"},
+{"name": "doug soltys"},
+{"name": "sean seidler"},
+{"name": "ryan sedlock"},
+{"name": "hana l"},
+{"name": "edward hudson"},
+{"name": "chelle heidenrich"},
+{"name": "shaun campbell"},
+{"name": "elizabeth dooling"},
+{"name": "sean dancer"},
+{"name": "eric gatlin"},
+{"name": "mindy buhrmeister"},
+{"name": "tom noonan"},
+{"name": "tonya johnson"},
+{"name": "charmaine derksen"},
+{"name": "john earnest"},
+{"name": "karen trevino"},
+{"name": "monty raley"},
+{"name": "christopher jackson"},
+{"name": "chad frampton"},
+{"name": "dave estes"},
+{"name": "russ white"},
+{"name": "katie zucker"},
+{"name": "rick flowers"},
+{"name": "phil sansom"},
+{"name": "jake blitz"},
+{"name": "jessica garone"},
+{"name": "mari castro"},
+{"name": "ray cyganiak"},
+{"name": "scotty b"},
+{"name": "john allen"},
+{"name": "derek sargent"},
+{"name": "josh crabtree"},
+{"name": "chris moers"},
+{"name": "mary therese"},
+{"name": "glenn durant"},
+{"name": "jennifer sullivan"},
+{"name": "lou maroun"},
+{"name": "polly arnold"},
+{"name": "jason scurry"},
+{"name": "nina marquez"},
+{"name": "sara bauer"},
+{"name": "glenda vigoreaux"},
+{"name": "cindy t"},
+{"name": "john clippenger"},
+{"name": "kenneth brand"},
+{"name": "eric webb"},
+{"name": "carla b"},
+{"name": "andrew carrizales"},
+{"name": "melinda romayor"},
+{"name": "carol formal"},
+{"name": "colleen adams"},
+{"name": "bret messling"},
+{"name": "steve zamzow"},
+{"name": "harvey russack"},
+{"name": "jeff pickles"},
+{"name": "matt lacati"},
+{"name": "anna novielli"},
+{"name": "andrew o'connor"},
+{"name": "joan roach"},
+{"name": "doug mcquilliams"},
+{"name": "meg powell"},
+{"name": "whitney crandall"},
+{"name": "eric horton"},
+{"name": "leo orr"},
+{"name": "diana emptage"},
+{"name": "jean morley"},
+{"name": "thomas fodaro"},
+{"name": "clayton scott"},
+{"name": "bob davies"},
+{"name": "thomas g"},
+{"name": "marc chestor"},
+{"name": "chris mcgee"},
+{"name": "joe hollom"},
+{"name": "mario heredia"},
+{"name": "rochelle woodland"},
+{"name": "clint ashby"},
+{"name": "bethel prep"},
+{"name": "lana adams"},
+{"name": "stephen lucey"},
+{"name": "victoria gilchrist"},
+{"name": "stella grinfeld"},
+{"name": "mandy yeung"},
+{"name": "andrew baeza"},
+{"name": "alisa barnes"},
+{"name": "sharon vastine"},
+{"name": "bob klein"},
+{"name": "kelly hollander"},
+{"name": "wayne mcnulty"},
+{"name": "mark cizek"},
+{"name": "clint phillips"},
+{"name": "debbie juris"},
+{"name": "aaron carlberg"},
+{"name": "kevin chambliss"},
+{"name": "misty velasco"},
+{"name": "katie phelan"},
+{"name": "tony huang"},
+{"name": "chris seifert"},
+{"name": "susanne stevens"},
+{"name": "keri lee"},
+{"name": "robert schwartz"},
+{"name": "erica viking"},
+{"name": "zack ziefker"},
+{"name": "randall wulff"},
+{"name": "albert tetrault"},
+{"name": "burt post"},
+{"name": "brian brom"},
+{"name": "andrea krochalis"},
+{"name": "ross holton"},
+{"name": "billy hoe"},
+{"name": "kayla darcell"},
+{"name": "brett insurance"},
+{"name": "patty hebert"},
+{"name": "chris harbour"},
+{"name": "joe paciulli"},
+{"name": "jay kronmiller"},
+{"name": "pablo garcia"},
+{"name": "julie perri"},
+{"name": "jerry soohoo"},
+{"name": "brian shively"},
+{"name": "kristian rukke"},
+{"name": "billy disciple"},
+{"name": "jenifer voyer"},
+{"name": "chris gimpel"},
+{"name": "chelsey brown"},
+{"name": "tom siemak"},
+{"name": "mike dalgaard"},
+{"name": "george blake"},
+{"name": "jesse keefe"},
+{"name": "justin spence"},
+{"name": "maria monard"},
+{"name": "renee gibbs"},
+{"name": "rob thompson"},
+{"name": "matt schema"},
+{"name": "art mcmullen"},
+{"name": "beth palumbo"},
+{"name": "tracey rosso"},
+{"name": "gerard rogers"},
+{"name": "stanley bell"},
+{"name": "kevin jacques"},
+{"name": "dalton cell"},
+{"name": "gary earl"},
+{"name": "diane colman"},
+{"name": "laurie hayes"},
+{"name": "harold paul"},
+{"name": "anh hang"},
+{"name": "alison heyman"},
+{"name": "dawn photo"},
+{"name": "kelsey hill"},
+{"name": "sean mason"},
+{"name": "donita clausen"},
+{"name": "bobby jr"},
+{"name": "barbara daniels"},
+{"name": "tiffany trask"},
+{"name": "jamie aten"},
+{"name": "jason lin"},
+{"name": "nancy sturrock"},
+{"name": "roger arthur"},
+{"name": "darren sanford"},
+{"name": "ted mannering"},
+{"name": "david nunez"},
+{"name": "terry hudson"},
+{"name": "mary beth"},
+{"name": "josh richards"},
+{"name": "justin vegas"},
+{"name": "eric andreasen"},
+{"name": "dave wick"},
+{"name": "homer gibson"},
+{"name": "karen rasmussen"},
+{"name": "sandra black"},
+{"name": "dan desouza"},
+{"name": "james finkelstein"},
+{"name": "jenny mcconnell"},
+{"name": "jason wpg"},
+{"name": "betty nevins"},
+{"name": "debby jay"},
+{"name": "jon ayres"},
+{"name": "tim coyle"},
+{"name": "chaya dimandstien"},
+{"name": "pat dempsey"},
+{"name": "alicia kinne"},
+{"name": "myra tobin"},
+{"name": "jessie kotarba"},
+{"name": "robby hemker"},
+{"name": "ryan dauchenbaugh"},
+{"name": "tom foscue"},
+{"name": "ashley goans"},
+{"name": "john hanlon"},
+{"name": "mandy johnson"},
+{"name": "jeff lenton"},
+{"name": "ben scholten"},
+{"name": "chris mutkoski"},
+{"name": "jake bochove"},
+{"name": "mark moss"},
+{"name": "andy lundburg"},
+{"name": "joe campodall'orto"},
+{"name": "stephanie gentry"},
+{"name": "jeffrey levin"},
+{"name": "jerry vazquez"},
+{"name": "priscilla garcia"},
+{"name": "matt muzza"},
+{"name": "chris syverson"},
+{"name": "roy mitros"},
+{"name": "marco orozco"},
+{"name": "jerry berg"},
+{"name": "maureen wojewodzki"},
+{"name": "beatrice parker"},
+{"name": "ervin brisko"},
+{"name": "anne larose"},
+{"name": "tyler duuring"},
+{"name": "ray giamporcaro"},
+{"name": "joseph logan"},
+{"name": "john praed"},
+{"name": "haley hager"},
+{"name": "john dorm"},
+{"name": "shelly wills"},
+{"name": "paul lucero"},
+{"name": "erik rawpigwc"},
+{"name": "steve akerman"},
+{"name": "david julian"},
+{"name": "ann trementozzi"},
+{"name": "todd mobly"},
+{"name": "steve chirokas"},
+{"name": "matt blanchard"},
+{"name": "andre studio"},
+{"name": "liz loveless"},
+{"name": "michele limbaugh"},
+{"name": "andrew moffat"},
+{"name": "david hess"},
+{"name": "john rycroft"},
+{"name": "christy thomas"},
+{"name": "danny case"},
+{"name": "leah meetup"},
+{"name": "grant samson"},
+{"name": "rick davis"},
+{"name": "molly donnelly"},
+{"name": "tommy degennaro"},
+{"name": "jeff ridgers"},
+{"name": "john chupa"},
+{"name": "alexis perumal"},
+{"name": "rob steele"},
+{"name": "megan moye"},
+{"name": "lillian taylor"},
+{"name": "tom serb"},
+{"name": "chris corneille"},
+{"name": "vince nelson"},
+{"name": "tyler williams"},
+{"name": "kurt lynam"},
+{"name": "peter suzuki"},
+{"name": "peter perram"},
+{"name": "arnold home"},
+{"name": "patty harden"},
+{"name": "keith reams"},
+{"name": "daniel hantigk"},
+{"name": "justin beastmode"},
+{"name": "thomas knauss"},
+{"name": "jay philly"},
+{"name": "stacie rouch"},
+{"name": "erin banister"},
+{"name": "jon shoff"},
+{"name": "diana magallanez"},
+{"name": "tom tier"},
+{"name": "wes stephenson"},
+{"name": "courtney g"},
+{"name": "david shipman"},
+{"name": "leif westermark"},
+{"name": "hans anderson"},
+{"name": "mari dl"},
+{"name": "jason webb"},
+{"name": "linda jackson"},
+{"name": "maggie dawkins"},
+{"name": "mattie stripling"},
+{"name": "alexandria allen"},
+{"name": "john convergys"},
+{"name": "brenda canada"},
+{"name": "matthew lott"},
+{"name": "dan kjelberg"},
+{"name": "vance cox"},
+{"name": "tanner hawey"},
+{"name": "jeannie bares"},
+{"name": "rudy covarrubio"},
+{"name": "frank harrington"},
+{"name": "andrea sinay"},
+{"name": "justin hardman"},
+{"name": "david fettig"},
+{"name": "douglas barth"},
+{"name": "penny raven"},
+{"name": "david studio"},
+{"name": "tony bondi"},
+{"name": "carrie romance"},
+{"name": "stacia wolff"},
+{"name": "rick alloway"},
+{"name": "kristen hersh"},
+{"name": "eric lo"},
+{"name": "bret robbe"},
+{"name": "tom avalos"},
+{"name": "jim schlabach"},
+{"name": "tracey weakley"},
+{"name": "vincent beals"},
+{"name": "tony florres"},
+{"name": "jackie bellanco"},
+{"name": "dennis hendrix"},
+{"name": "nicolas faure"},
+{"name": "dave bradley"},
+{"name": "bill tobey"},
+{"name": "erin lawson"},
+{"name": "brett kotelko"},
+{"name": "jeff hampton"},
+{"name": "john o'connor"},
+{"name": "brian wicke"},
+{"name": "julie lawson"},
+{"name": "daniella model"},
+{"name": "kelvin lockhart"},
+{"name": "janet lessner"},
+{"name": "jennifer rowland"},
+{"name": "rob e"},
+{"name": "gordon higgins"},
+{"name": "janie gustauson"},
+{"name": "rick trussell"},
+{"name": "jeff handwerg"},
+{"name": "coralie ottenbriet"},
+{"name": "xochitl ortega"},
+{"name": "preston shits"},
+{"name": "paul teeter"},
+{"name": "phil ducatelli"},
+{"name": "bruce levitz"},
+{"name": "melissa felske"},
+{"name": "angela chang"},
+{"name": "justin raines"},
+{"name": "joan mousley"},
+{"name": "jill bennett"},
+{"name": "jeffrey gomex"},
+{"name": "joanne mcfarlin"},
+{"name": "tony sprint"},
+{"name": "dustin barker"},
+{"name": "kevin wong"},
+{"name": "cheryl loring"},
+{"name": "krystal giron"},
+{"name": "chris kittle"},
+{"name": "moises costas"},
+{"name": "tom ladd"},
+{"name": "brandi mcpherson"},
+{"name": "daniel pritchett"},
+{"name": "allan schlar"},
+{"name": "lloyd durham"},
+{"name": "kyle lee"},
+{"name": "kim washington"},
+{"name": "ann bernal"},
+{"name": "sarah rancho"},
+{"name": "michelle cel"},
+{"name": "jason marcus"},
+{"name": "karl halterman"},
+{"name": "mike hall"},
+{"name": "christine adams"},
+{"name": "gerald pollard"},
+{"name": "anthony morgan"},
+{"name": "harold standley"},
+{"name": "israel flores"},
+{"name": "edwin cherp"},
+{"name": "gerard varlotta"},
+{"name": "ashley givens"},
+{"name": "clayton hensley"},
+{"name": "brittany moore"},
+{"name": "lisa hays"},
+{"name": "stacey mcnuer"},
+{"name": "joanna strohsal"},
+{"name": "crystal sea"},
+{"name": "chris corey"},
+{"name": "david frumm"},
+{"name": "jeff lisa"},
+{"name": "ryan vaneeps"},
+{"name": "matt reyenga"},
+{"name": "jeffrey james"},
+{"name": "keith black"},
+{"name": "armando boxer"},
+{"name": "robert amick"},
+{"name": "evon barney"},
+{"name": "brooke carlson"},
+{"name": "elaine lang"},
+{"name": "richard wiebe"},
+{"name": "gary jennings"},
+{"name": "collen joseph"},
+{"name": "ryan fleming"},
+{"name": "dana kim"},
+{"name": "kristina gor"},
+{"name": "aaron hunter"},
+{"name": "scott pettitt"},
+{"name": "tommy odom"},
+{"name": "will skype"},
+{"name": "thomas arons"},
+{"name": "ben kramer"},
+{"name": "january boten"},
+{"name": "david gardner"},
+{"name": "debbie juliani"},
+{"name": "todd mcclone"},
+{"name": "mark fiala"},
+{"name": "janay hines"},
+{"name": "alex hadaddy"},
+{"name": "robert jerom"},
+{"name": "adam scotch"},
+{"name": "jenna h"},
+{"name": "david cannom"},
+{"name": "charlie leary"},
+{"name": "joe baseball"},
+{"name": "alethea austin"},
+{"name": "michael vasquez"},
+{"name": "octavia pugh"},
+{"name": "paul salzetti"},
+{"name": "caroline venable"},
+{"name": "anthony crawford"},
+{"name": "kate windsor"},
+{"name": "gary vacon"},
+{"name": "billy owens"},
+{"name": "steve ulicny"},
+{"name": "jess brearton"},
+{"name": "jamey hebert"},
+{"name": "george lindsey"},
+{"name": "rich sloane"},
+{"name": "angie sarah"},
+{"name": "angel tisdale"},
+{"name": "rosalie muratschew"},
+{"name": "amy canter"},
+{"name": "kelly lopez"},
+{"name": "cory safady"},
+{"name": "lawrence lein"},
+{"name": "chris tahal"},
+{"name": "david bravo"},
+{"name": "britt r"},
+{"name": "vicky regan"},
+{"name": "le silve"},
+{"name": "jon herttua"},
+{"name": "ron vandervort"},
+{"name": "william quinn"},
+{"name": "roy s"},
+{"name": "jean bruce"},
+{"name": "deb sousa"},
+{"name": "scotty p's"},
+{"name": "cindy gee"},
+{"name": "timothy bolles"},
+{"name": "michael houston"},
+{"name": "holly mendenhall"},
+{"name": "arnold cajilig"},
+{"name": "don v"},
+{"name": "mark brady"},
+{"name": "arturo promoter"},
+{"name": "edith fernandez"},
+{"name": "jimmy brown"},
+{"name": "britney wilson"},
+{"name": "clayton cates"},
+{"name": "tom koczynski"},
+{"name": "cecil shirar"},
+{"name": "maria russo"},
+{"name": "chris schlosser"},
+{"name": "josh doerkson"},
+{"name": "mike varciage"},
+{"name": "kevin hancy"},
+{"name": "jerry mosketti"},
+{"name": "jeff benson"},
+{"name": "joleen gatton"},
+{"name": "terry pugh"},
+{"name": "tyler ratliff"},
+{"name": "martha valencia"},
+{"name": "randy barger"},
+{"name": "john richards"},
+{"name": "rochelle harris"},
+{"name": "martha gonzalez"},
+{"name": "andrew furman"},
+{"name": "jennifer kruger"},
+{"name": "tom leong"},
+{"name": "susan dl"},
+{"name": "marc charron"},
+{"name": "kayla johnson"},
+{"name": "michelle wise"},
+{"name": "oscar lopez"},
+{"name": "drew dolphus"},
+{"name": "michelle higgins"},
+{"name": "albert nissan"},
+{"name": "shakira alvarez"},
+{"name": "christopher smit"},
+{"name": "jim raschella"},
+{"name": "michael lipton"},
+{"name": "jorge perez"},
+{"name": "steve spawglass"},
+{"name": "sean garvey"},
+{"name": "ann lovell"},
+{"name": "andrea shop"},
+{"name": "alicia perkins"},
+{"name": "nathan gnc"},
+{"name": "cindy adams"},
+{"name": "anthony bstone"},
+{"name": "melissa beck"},
+{"name": "tracy att"},
+{"name": "nadine north"},
+{"name": "luke edington"},
+{"name": "tracy barone"},
+{"name": "blanca segura"},
+{"name": "angel garfio+"},
+{"name": "lynn williams"},
+{"name": "christopher smeall"},
+{"name": "christine herron"},
+{"name": "jo williams"},
+{"name": "eric escher"},
+{"name": "nita harold"},
+{"name": "amber goodwin"},
+{"name": "jeff kim"},
+{"name": "john d'amato"},
+{"name": "jen corbet"},
+{"name": "bruce wen"},
+{"name": "nia e"},
+{"name": "larry foshil"},
+{"name": "nick asturias"},
+{"name": "erin huthman"},
+{"name": "adella aragon"},
+{"name": "amy garbo"},
+{"name": "david garrison"},
+{"name": "leon tirrell"},
+{"name": "maria caballero"},
+{"name": "jack morgan"},
+{"name": "adam fisher"},
+{"name": "sharon bardrey"},
+{"name": "gene d"},
+{"name": "joshua thomason"},
+{"name": "angela calvillo"},
+{"name": "cora wimberly"},
+{"name": "burt harbert"},
+{"name": "todd earnhart"},
+{"name": "heather chase"},
+{"name": "derek grant"},
+{"name": "sue andryk"},
+{"name": "bill alwrth"},
+{"name": "barb fox"},
+{"name": "laura aten"},
+{"name": "chris hurst"},
+{"name": "randy salley"},
+{"name": "scott friend"},
+{"name": "brian wingfield"},
+{"name": "jessica malin"},
+{"name": "gino leblanc"},
+{"name": "mike santamarin"},
+{"name": "terry marks"},
+{"name": "pat nabor"},
+{"name": "anna marie"},
+{"name": "eddie e"},
+{"name": "jonathan franks"},
+{"name": "amber feld"},
+{"name": "robert prevost"},
+{"name": "scott rickelton"},
+{"name": "alan kwong"},
+{"name": "lisa fitzgerald"},
+{"name": "phil stover"},
+{"name": "charlie goldstone"},
+{"name": "mitch a"},
+{"name": "rob francis"},
+{"name": "abby cell"},
+{"name": "jason weber"},
+{"name": "luis matute"},
+{"name": "laurie gothelf"},
+{"name": "liz schimel"},
+{"name": "maria perez"},
+{"name": "colby rogers"},
+{"name": "john marcotte"},
+{"name": "jay lewis"},
+{"name": "kathy klein"},
+{"name": "sherri finch"},
+{"name": "megan m"},
+{"name": "scott weimar"},
+{"name": "gus schultz"},
+{"name": "rhea sullivan"},
+{"name": "mike dyson"},
+{"name": "dani rhynard"},
+{"name": "miss lee's"},
+{"name": "mark khan"},
+{"name": "brian battjer"},
+{"name": "aaron middleton"},
+{"name": "caitlin p"},
+{"name": "leo venzon"},
+{"name": "dominic chan"},
+{"name": "maggie osborn"},
+{"name": "todd schopp"},
+{"name": "joe ellis"},
+{"name": "melody covell"},
+{"name": "naomi levinson"},
+{"name": "michael glicksman"},
+{"name": "ed esguerra"},
+{"name": "brian perry"},
+{"name": "jay rims"},
+{"name": "guy messalem"},
+{"name": "bianca cell"},
+{"name": "nanette cunningham"},
+{"name": "jessica select"},
+{"name": "emilio nunez"},
+{"name": "pierre jammes"},
+{"name": "jacquelyn roth"},
+{"name": "christy nguyen"},
+{"name": "andy steinfeld"},
+{"name": "michelle bright"},
+{"name": "mike arrigo"},
+{"name": "willie baby"},
+{"name": "morgan carpenter"},
+{"name": "christopher gonzales"},
+{"name": "juan productions"},
+{"name": "norman saucedo"},
+{"name": "ivan mejia"},
+{"name": "david headstream"},
+{"name": "rich kirtley"},
+{"name": "gwen severson"},
+{"name": "bob griffin"},
+{"name": "andrew daire"},
+{"name": "juan iglesias"},
+{"name": "heather little"},
+{"name": "juanita himes"},
+{"name": "jeff randall"},
+{"name": "jamie ott"},
+{"name": "darrel fritzell"},
+{"name": "steve wilkes"},
+{"name": "justin griffith"},
+{"name": "albert genzen"},
+{"name": "kendall celly"},
+{"name": "michael byrd"},
+{"name": "henry korellis"},
+{"name": "dean prather"},
+{"name": "bob love"},
+{"name": "victor deblesi"},
+{"name": "dan mcdonald"},
+{"name": "mike fertner"},
+{"name": "cliff painter"},
+{"name": "rich ukiah"},
+{"name": "allie segura"},
+{"name": "katie neuman"},
+{"name": "jeff house"},
+{"name": "tiffany aldridge"},
+{"name": "steve westside"},
+{"name": "sunny merit"},
+{"name": "michelle doughty"},
+{"name": "tiffani mondragon"},
+{"name": "johnson drywall"},
+{"name": "leah blalock"},
+{"name": "chuck willig"},
+{"name": "hiedi thomas"},
+{"name": "joe legget"},
+{"name": "elizabeth brister"},
+{"name": "alex carberry"},
+{"name": "jen hurley"},
+{"name": "robert kalinauskas"},
+{"name": "lyn tidwell"},
+{"name": "tam le"},
+{"name": "marsha kee"},
+{"name": "rob howe"},
+{"name": "susan odom"},
+{"name": "josh mark"},
+{"name": "ryan broderick"},
+{"name": "therese martin"},
+{"name": "mike april"},
+{"name": "angela cohen"},
+{"name": "stephanie burchett"},
+{"name": "donnie lashier"},
+{"name": "jade skye"},
+{"name": "neil sequeira"},
+{"name": "david abbott"},
+{"name": "jenny ivanova"},
+{"name": "alexis bohan"},
+{"name": "joe bank"},
+{"name": "alex ling"},
+{"name": "julia young"},
+{"name": "john wirtz"},
+{"name": "rick tivers"},
+{"name": "sue scheer"},
+{"name": "justin creo"},
+{"name": "mia nakagawa"},
+{"name": "kyla kelley"},
+{"name": "joe staab"},
+{"name": "stacy booth"},
+{"name": "omar ortega"},
+{"name": "katie hamilton"},
+{"name": "stuart ellman"},
+{"name": "michael internaional"},
+{"name": "tiffany k"},
+{"name": "kelvin liwangitan"},
+{"name": "scott harryman"},
+{"name": "aundrea house"},
+{"name": "drew miller"},
+{"name": "lori schweigert"},
+{"name": "jeff schackman"},
+{"name": "victoria matlock"},
+{"name": "sandy rogers"},
+{"name": "brian lee"},
+{"name": "tom kissell"},
+{"name": "will stusek"},
+{"name": "clark ilwu"},
+{"name": "lauren merril"},
+{"name": "marisol minjarez"},
+{"name": "rick dryland"},
+{"name": "angie brother"},
+{"name": "fidel lucero"},
+{"name": "bryan denton"},
+{"name": "mike worth"},
+{"name": "mark collins"},
+{"name": "karen work"},
+{"name": "carrie phillips"},
+{"name": "dia simms"},
+{"name": "tim gatchet"},
+{"name": "denise bertsch"},
+{"name": "peggy larson"},
+{"name": "ron woods"},
+{"name": "joe mansour"},
+{"name": "sharon patterson"},
+{"name": "ricky ex"},
+{"name": "robert mcgovern"},
+{"name": "jeanette wessel"},
+{"name": "tomas schekter"},
+{"name": "heather darnell"},
+{"name": "david lariviere"},
+{"name": "rick banuelos"},
+{"name": "rob fitzwater"},
+{"name": "frank pecaitis"},
+{"name": "gary ambrose"},
+{"name": "janis burns"},
+{"name": "leon casa"},
+{"name": "jim weaver"},
+{"name": "alex seattle"},
+{"name": "sun east"},
+{"name": "christian bradford"},
+{"name": "cindy carpenter"},
+{"name": "shannon walla"},
+{"name": "charlie sharp"},
+{"name": "ray satterwhite"},
+{"name": "adam robinson"},
+{"name": "kim fehlberg"},
+{"name": "nick moulds"},
+{"name": "melanie trogolo"},
+{"name": "john landry"},
+{"name": "mike troyer"},
+{"name": "chris dino"},
+{"name": "lea schneider"},
+{"name": "pam tulley"},
+{"name": "carl hodges"},
+{"name": "miguel sprint"},
+{"name": "andrea paucar"},
+{"name": "anthony hernandez"},
+{"name": "nancy carnes"},
+{"name": "nancy hill"},
+{"name": "neal nicholas"},
+{"name": "brian nasiopolis"},
+{"name": "ellen parker"},
+{"name": "jeff reichmuth"},
+{"name": "john deem"},
+{"name": "buddy holley"},
+{"name": "sol shafer"},
+{"name": "mimi qunell"},
+{"name": "joe cihak"},
+{"name": "neil hamilton"},
+{"name": "jay effies"},
+{"name": "michael photographer"},
+{"name": "greg steph"},
+{"name": "cherie hayes"},
+{"name": "dana flaherty"},
+{"name": "monica magyar"},
+{"name": "kevin looney"},
+{"name": "mckenzie e"},
+{"name": "liliana solis"},
+{"name": "charles roberto"},
+{"name": "roberta edwell"},
+{"name": "brian mcmahon"},
+{"name": "carmen andrews"},
+{"name": "jose tech"},
+{"name": "charles headlam"},
+{"name": "cindy martindale"},
+{"name": "diane ikard"},
+{"name": "larry c"},
+{"name": "emilee k"},
+{"name": "keisha bolton"},
+{"name": "mary olson"},
+{"name": "mac keever"},
+{"name": "debbie hamberlain"},
+{"name": "paul gaynor"},
+{"name": "jamie levine"},
+{"name": "phil zita"},
+{"name": "mike wu"},
+{"name": "peter masurier"},
+{"name": "steve cox"},
+{"name": "joey pinkston"},
+{"name": "brandon milby"},
+{"name": "jayson iwanaga"},
+{"name": "colton k"},
+{"name": "teddy cantor"},
+{"name": "scott webster"},
+{"name": "monica schultz"},
+{"name": "davis insurance"},
+{"name": "cory stevens"},
+{"name": "misty ewald"},
+{"name": "alejandro radio"},
+{"name": "lindsay tanchuk"},
+{"name": "trish stahl"},
+{"name": "jeff limp"},
+{"name": "tiffany tubbs"},
+{"name": "holly meager"},
+{"name": "breanna folsom"},
+{"name": "julia brandt"},
+{"name": "sheila wallace"},
+{"name": "wade brooks"},
+{"name": "jason rios"},
+{"name": "tia elvira"},
+{"name": "rona finkelstein"},
+{"name": "vanessa caminos"},
+{"name": "carrie boldt"},
+{"name": "john maddox"},
+{"name": "kim ruiz"},
+{"name": "greg pal"},
+{"name": "erika wong"},
+{"name": "dan snyder"},
+{"name": "ana la"},
+{"name": "pam russell"},
+{"name": "renee mccauley"},
+{"name": "larry barnes"},
+{"name": "tom williscroft"},
+{"name": "pamela harbidge"},
+{"name": "gail erickson"},
+{"name": "keith thiel"},
+{"name": "erin kalihan"},
+{"name": "joe girgen"},
+{"name": "bernardo gallo"},
+{"name": "andrew beck"},
+{"name": "marc kalchman"},
+{"name": "david holt"},
+{"name": "lori loch"},
+{"name": "jack buckholtz"},
+{"name": "tom dickson"},
+{"name": "herbert serano"},
+{"name": "ariel hernandez"},
+{"name": "katie hale"},
+{"name": "jill radovitch"},
+{"name": "donna bridges"},
+{"name": "bryan taylor"},
+{"name": "mike lindley"},
+{"name": "esteban puga"},
+{"name": "michele miller"},
+{"name": "eric estes"},
+{"name": "sam gordon"},
+{"name": "cynthia hill"},
+{"name": "joey green"},
+{"name": "dianne singh"},
+{"name": "lindsay brow"},
+{"name": "bert universal"},
+{"name": "matt holley"},
+{"name": "david villarreal"},
+{"name": "kris andres"},
+{"name": "louis champagne"},
+{"name": "erin johnson"},
+{"name": "marianne dischmann"},
+{"name": "casey jones"},
+{"name": "michelle farmers"},
+{"name": "nancy patterson"},
+{"name": "katie bar"},
+{"name": "doug dorton"},
+{"name": "beverly norris"},
+{"name": "deborah jeffries"},
+{"name": "kathleen sweeney"},
+{"name": "tim harris"},
+{"name": "cami middleton"},
+{"name": "hong ky"},
+{"name": "stephanie luszyk"},
+{"name": "kyle toavs"},
+{"name": "stephen greeno"},
+{"name": "andrew miazga"},
+{"name": "alex mccalister"},
+{"name": "del wong"},
+{"name": "connie orcutt"},
+{"name": "claudia hererra"},
+{"name": "erin wells"},
+{"name": "eboni louis"},
+{"name": "casey hernandorf"},
+{"name": "edgar baker"},
+{"name": "molly evans"},
+{"name": "chuck jansen"},
+{"name": "michael clayton"},
+{"name": "kenny bacon"},
+{"name": "connie moser"},
+{"name": "dan lowetz"},
+{"name": "david lane"},
+{"name": "ben ci"},
+{"name": "michelle charland"},
+{"name": "mark beach"},
+{"name": "shane c"},
+{"name": "chris finlayson"},
+{"name": "steven babe"},
+{"name": "rich wood"},
+{"name": "karen nsc"},
+{"name": "teresa wilmoth"},
+{"name": "fred han"},
+{"name": "joanne clancy"},
+{"name": "brain tafoya"},
+{"name": "mindi rees"},
+{"name": "robert hudrick"},
+{"name": "fiona moseley"},
+{"name": "monique woodford"},
+{"name": "ma beebs"},
+{"name": "amanda earhart"},
+{"name": "ron shafner"},
+{"name": "jim sturgeon"},
+{"name": "trent kuharski"},
+{"name": "joe srncik"},
+{"name": "charles wilson"},
+{"name": "krista isaacson"},
+{"name": "joe graves"},
+{"name": "ethan luck"},
+{"name": "meghann kuhns"},
+{"name": "richard arsenault"},
+{"name": "tony luna"},
+{"name": "lauren demitchell"},
+{"name": "robert dubord"},
+{"name": "peggy bennett"},
+{"name": "tia amos"},
+{"name": "brandy jason"},
+{"name": "norbert frassa"},
+{"name": "lisa hendricks"},
+{"name": "fran bautista"},
+{"name": "bill garner"},
+{"name": "gina larsen"},
+{"name": "clark peyton"},
+{"name": "beth steinberg"},
+{"name": "jan scherer"},
+{"name": "john young"},
+{"name": "ronald marx"},
+{"name": "cassandra giedt"},
+{"name": "steven hines"},
+{"name": "tom lawton"},
+{"name": "jodi sperber"},
+{"name": "leslie gaskill"},
+{"name": "mark mccall"},
+{"name": "corey beals"},
+{"name": "misty hobart"},
+{"name": "matt fordon"},
+{"name": "miguel gomez"},
+{"name": "virginia woodhouse"},
+{"name": "brandon cagle"},
+{"name": "angie frisbe"},
+{"name": "robert turner"},
+{"name": "tasha lockeroom"},
+{"name": "larry striffler"},
+{"name": "chance rogers"},
+{"name": "pablo granadaz"},
+{"name": "michael matusz"},
+{"name": "kristi miller"},
+{"name": "ed boudrot"},
+{"name": "sue beatty"},
+{"name": "shaun vanderheide"},
+{"name": "lorraine roach"},
+{"name": "jim pouge"},
+{"name": "shelly armstrong"},
+{"name": "charles hawkins"},
+{"name": "china garden"},
+{"name": "gregory mckinley"},
+{"name": "jay carter"},
+{"name": "tim ault"},
+{"name": "kim parks"},
+{"name": "santo cell"},
+{"name": "megan cool"},
+{"name": "robert w"},
+{"name": "liane willey"},
+{"name": "ellsworth jane"},
+{"name": "takako yamamoto"},
+{"name": "chase dunaway"},
+{"name": "george yu"},
+{"name": "marlene johnston"},
+{"name": "douglas robertson"},
+{"name": "alex maturi"},
+{"name": "linda macias"},
+{"name": "tia cell"},
+{"name": "jonathan kaplan"},
+{"name": "tanya e"},
+{"name": "david t"},
+{"name": "john sabine"},
+{"name": "stanley stoll"},
+{"name": "gary wisser"},
+{"name": "james hume"},
+{"name": "beverly mclean"},
+{"name": "victor ou"},
+{"name": "rick nasser"},
+{"name": "michael gregory"},
+{"name": "david buckles"},
+{"name": "tracy her"},
+{"name": "selina garcia"},
+{"name": "matt robertson"},
+{"name": "lisa pirie"},
+{"name": "connie hardison"},
+{"name": "carol maye"},
+{"name": "michelle cachaper"},
+{"name": "drew clark"},
+{"name": "jay matos"},
+{"name": "lowell olcott"},
+{"name": "luis benitez"},
+{"name": "alex gluck"},
+{"name": "garrett bushong"},
+{"name": "lee garoutte"},
+{"name": "courtney cross"},
+{"name": "steve harman"},
+{"name": "marc cherveny"},
+{"name": "daniel d'auria"},
+{"name": "brandon copeland"},
+{"name": "jon neal"},
+{"name": "joey parker"},
+{"name": "kim adams"},
+{"name": "nina pumarejo"},
+{"name": "mike kubik"},
+{"name": "quinn cachiola"},
+{"name": "omar bryant"},
+{"name": "steve skiff"},
+{"name": "al laux"},
+{"name": "christian shipley"},
+{"name": "earl forman"},
+{"name": "judi irwin"},
+{"name": "michael ralke"},
+{"name": "nana williams"},
+{"name": "jeff rich"},
+{"name": "karina chavez"},
+{"name": "donnie baker"},
+{"name": "debbie rodgers"},
+{"name": "lynn goodrich"},
+{"name": "eleanor collins"},
+{"name": "brian unac"},
+{"name": "carol miller"},
+{"name": "brooke goldman"},
+{"name": "joel edwards"},
+{"name": "annette tomina"},
+{"name": "daniel goodwin"},
+{"name": "erin teare"},
+{"name": "carolyn adams"},
+{"name": "mark byland"},
+{"name": "amy restive"},
+{"name": "jerry boji"},
+{"name": "sandy blumberg"},
+{"name": "steve greenbaum"},
+{"name": "jess nyc"},
+{"name": "nancy arn"},
+{"name": "eric chen"},
+{"name": "tiffany gatto"},
+{"name": "jay stagnone"},
+{"name": "jessica nelson"},
+{"name": "nick lawn"},
+{"name": "dave heimbigner"},
+{"name": "diana baylor"},
+{"name": "veronica reyes"},
+{"name": "frank burgin"},
+{"name": "connie yang"},
+{"name": "toni farrelly"},
+{"name": "michelle gilgan"},
+{"name": "miguel rosario"},
+{"name": "sheena bales"},
+{"name": "carrie chavez"},
+{"name": "ethan mollick"},
+{"name": "yi shen"},
+{"name": "dennis hammond"},
+{"name": "paul penzer"},
+{"name": "ann lewis"},
+{"name": "rene arb"},
+{"name": "meghan melchi"},
+{"name": "linda cheney"},
+{"name": "parker jim"},
+{"name": "alex damino"},
+{"name": "benny boom"},
+{"name": "abel l"},
+{"name": "keith reid"},
+{"name": "mark lander"},
+{"name": "aaron weller"},
+{"name": "jacqueline schmidt"},
+{"name": "bernie dixon"},
+{"name": "joe martinson"},
+{"name": "debra robins"},
+{"name": "nolan wade"},
+{"name": "sarah strazzara"},
+{"name": "david chernick"},
+{"name": "ryan rapez"},
+{"name": "carrie jackson"},
+{"name": "stephen way"},
+{"name": "kari lacy"},
+{"name": "dan litz"},
+{"name": "al garcia"},
+{"name": "john mazza"},
+{"name": "audrey morgan"},
+{"name": "don bartlette"},
+{"name": "bruce mazza"},
+{"name": "dick schuh"},
+{"name": "diane carlino"},
+{"name": "charles little"},
+{"name": "dena nagel"},
+{"name": "molly w"},
+{"name": "brian matchett"},
+{"name": "dennis pezzato"},
+{"name": "david rose"},
+{"name": "jon schuhart"},
+{"name": "mark hickey"},
+{"name": "john steinberger"},
+{"name": "lupe altamirano"},
+{"name": "katie goodman"},
+{"name": "robert kellog"},
+{"name": "kevin coughlin"},
+{"name": "joe bannerman"},
+{"name": "david enzminger"},
+{"name": "ken ghram"},
+{"name": "zack zeigler"},
+{"name": "lucy ortiz"},
+{"name": "david senzig"},
+{"name": "dan naples"},
+{"name": "ashley jane"},
+{"name": "sally schneider"},
+{"name": "tasha la"},
+{"name": "nelson pr"},
+{"name": "kenneth hope"},
+{"name": "joel jr"},
+{"name": "kevin mahadio"},
+{"name": "lisa mohr"},
+{"name": "bill teaberry"},
+{"name": "garth fisher"},
+{"name": "stephenie w"},
+{"name": "bill schuch"},
+{"name": "karla kirkwood"},
+{"name": "jerry barros"},
+{"name": "byron schiel"},
+{"name": "sergio motalvo"},
+{"name": "anna chindris"},
+{"name": "randy north"},
+{"name": "tracy hershman"},
+{"name": "america air"},
+{"name": "irene rr"},
+{"name": "julia locke"},
+{"name": "samuel chabolla"},
+{"name": "rob tnt"},
+{"name": "irvin fev"},
+{"name": "jonathan keen"},
+{"name": "chas jeffries"},
+{"name": "brad meyers"},
+{"name": "garrett pritchett"},
+{"name": "steve rockman"},
+{"name": "seth taylor"},
+{"name": "ross goldstein"},
+{"name": "james barr"},
+{"name": "dwayne graves"},
+{"name": "monica zucco"},
+{"name": "lisa evans"},
+{"name": "jason cerutti"},
+{"name": "love line"},
+{"name": "john larson"},
+{"name": "john hoomani"},
+{"name": "doug kelly"},
+{"name": "etta gross"},
+{"name": "rochelle steele"},
+{"name": "royal roofing"},
+{"name": "johanna rodriguez"},
+{"name": "will keys"},
+{"name": "travis christianson"},
+{"name": "jen sinnott"},
+{"name": "jon kaltenbron"},
+{"name": "lee woolley"},
+{"name": "nick cherronie"},
+{"name": "john dionofrio"},
+{"name": "bill tyson"},
+{"name": "john hicky"},
+{"name": "justin roland"},
+{"name": "lori waddell"},
+{"name": "tom ketchum"},
+{"name": "shawn greenson"},
+{"name": "david stuart"},
+{"name": "richard allen"},
+{"name": "jim manzi"},
+{"name": "greg mosinski"},
+{"name": "lang rentals"},
+{"name": "michael blum"},
+{"name": "aaron seawood"},
+{"name": "randy smith"},
+{"name": "jeremy essex"},
+{"name": "ashley hotham"},
+{"name": "matt lamb"},
+{"name": "carrie taylor"},
+{"name": "becky hoover"},
+{"name": "toby williams"},
+{"name": "jeff zukerman"},
+{"name": "noah mills"},
+{"name": "steve bowsher"},
+{"name": "dave gringer"},
+{"name": "nicole smp"},
+{"name": "sherri wolf"},
+{"name": "dick grote"},
+{"name": "brittney boo"},
+{"name": "lane briggs"},
+{"name": "patrick danipour"},
+{"name": "bruce yu"},
+{"name": "vivian escoto"},
+{"name": "tom stegeman"},
+{"name": "mattie miller"},
+{"name": "marti iben"},
+{"name": "aaron st"},
+{"name": "barbara jones"},
+{"name": "kelly christopher"},
+{"name": "regina birrenkott"},
+{"name": "kiley randolph"},
+{"name": "dan meismer"},
+{"name": "jeff axelrod"},
+{"name": "pat mccullar"},
+{"name": "todd white"},
+{"name": "bill eastwood"},
+{"name": "jeff franken"},
+{"name": "chris henderson"},
+{"name": "rene abalos"},
+{"name": "kay sams"},
+{"name": "joan bailey"},
+{"name": "ellen zayer"},
+{"name": "mark harder"},
+{"name": "imelda cerda"},
+{"name": "linda h"},
+{"name": "clayton litt"},
+{"name": "john youngblood"},
+{"name": "tori knighten"},
+{"name": "pattie bar"},
+{"name": "travis roof"},
+{"name": "dylan tarbert"},
+{"name": "jess zavaleta"},
+{"name": "george muzaic"},
+{"name": "jeffrey mcgovern"},
+{"name": "ruth butler"},
+{"name": "deb lantz"},
+{"name": "casey wessels"},
+{"name": "dave rasmussen"},
+{"name": "sara seronko"},
+{"name": "christa medlock"},
+{"name": "linda hood"},
+{"name": "katherine spiegel"},
+{"name": "brendan tynan"},
+{"name": "marry napper"},
+{"name": "john flagler"},
+{"name": "ethan reith"},
+{"name": "sandie leviner"},
+{"name": "kelly robertson"},
+{"name": "patty hatter"},
+{"name": "michael akfali"},
+{"name": "gloria ortega"},
+{"name": "mike simpkins"},
+{"name": "greg murrell"},
+{"name": "rowena ripa"},
+{"name": "dave zitiello"},
+{"name": "cindy kane"},
+{"name": "ashley mccormack"},
+{"name": "peter steinlauf"},
+{"name": "courtney jordan"},
+{"name": "joe cruz"},
+{"name": "chris texas"},
+{"name": "sook im"},
+{"name": "peter bellini"},
+{"name": "moshe englander"},
+{"name": "leslie bailey"},
+{"name": "andy thomson"},
+{"name": "erik dogg"},
+{"name": "mindy wilson"},
+{"name": "david nitta"},
+{"name": "becky nash"},
+{"name": "kristen kelly"},
+{"name": "chris cumming"},
+{"name": "kris haven"},
+{"name": "cheryl pollick"},
+{"name": "faye park"},
+{"name": "george nahabedian"},
+{"name": "vincenzo scotto"},
+{"name": "minerva songco"},
+{"name": "oscar gallardo"},
+{"name": "jeff layton"},
+{"name": "jenny goring"},
+{"name": "casey h"},
+{"name": "larry duncan"},
+{"name": "mindi torrez"},
+{"name": "tim farr"},
+{"name": "jeff poole"},
+{"name": "ryan cox"},
+{"name": "lauren napier"},
+{"name": "ed mathias"},
+{"name": "julie specht"},
+{"name": "tim hager"},
+{"name": "joan kapson"},
+{"name": "morgan humpherys"},
+{"name": "brad householder"},
+{"name": "colleen oneil"},
+{"name": "karie lord"},
+{"name": "john scappatura"},
+{"name": "don salvato"},
+{"name": "al nelson"},
+{"name": "bruce womack"},
+{"name": "brenda spahn"},
+{"name": "connie cell"},
+{"name": "jim huckins"},
+{"name": "wayne eberts"},
+{"name": "cole truebenach"},
+{"name": "debbie gonzalez"},
+{"name": "lisa jouet"},
+{"name": "vanessa miranda"},
+{"name": "don mcmillen"},
+{"name": "cindy wilbanks"},
+{"name": "bradley davidowitz"},
+{"name": "nikki kaplan"},
+{"name": "allen spurgeon"},
+{"name": "eric windsor"},
+{"name": "neida vargas"},
+{"name": "matt r"},
+{"name": "bo zheng"},
+{"name": "gillian safdeye"},
+{"name": "donna tegan"},
+{"name": "william penn"},
+{"name": "kenny norstroms"},
+{"name": "tracy jenkins"},
+{"name": "chet wans"},
+{"name": "ray horspool"},
+{"name": "emily santana"},
+{"name": "jason strauss"},
+{"name": "alvin tat"},
+{"name": "colton kimbell"},
+{"name": "greg active"},
+{"name": "pat townsley"},
+{"name": "christy scissorhan"},
+{"name": "jose sun"},
+{"name": "heath evans"},
+{"name": "aisha anderson"},
+{"name": "alan hineki"},
+{"name": "rick vines"},
+{"name": "stephanie compere"},
+{"name": "kathy desaire"},
+{"name": "teresa toy"},
+{"name": "tommy george"},
+{"name": "keely wiegart"},
+{"name": "anthony felton"},
+{"name": "shawn g"},
+{"name": "jo francis"},
+{"name": "jeffrey leventhal"},
+{"name": "alex artiques"},
+{"name": "jean werum"},
+{"name": "nick yahoo"},
+{"name": "howard campbell"},
+{"name": "leona preston"},
+{"name": "daniel deyette"},
+{"name": "victor trucking"},
+{"name": "lillian jordan"},
+{"name": "joe upchurch"},
+{"name": "paul benveniste"},
+{"name": "erin essel"},
+{"name": "mario gutierrez"},
+{"name": "jessica scalissi"},
+{"name": "pete elek"},
+{"name": "nathan burns"},
+{"name": "meggan williams"},
+{"name": "britt mom"},
+{"name": "stephen horne"},
+{"name": "dorothy sandoval"},
+{"name": "melissa chu"},
+{"name": "john youngquist"},
+{"name": "bob berry"},
+{"name": "leslie klein"},
+{"name": "carole keller"},
+{"name": "john fasko"},
+{"name": "dave stall"},
+{"name": "damon fox"},
+{"name": "lynn faris"},
+{"name": "lisa jessie"},
+{"name": "joyce lam"},
+{"name": "gracie bellosi"},
+{"name": "tom regan"},
+{"name": "chris hed"},
+{"name": "miss chris"},
+{"name": "judy graber"},
+{"name": "john simko"},
+{"name": "marcia wallace"},
+{"name": "katie marie"},
+{"name": "van sprang"},
+{"name": "rich eagleinspectionservices"},
+{"name": "jim earnest"},
+{"name": "bob hughes"},
+{"name": "janie craig"},
+{"name": "rico toland"},
+{"name": "ed rusnak"},
+{"name": "brett honey"},
+{"name": "billi mcdonald"},
+{"name": "phil weathers"},
+{"name": "david joiner"},
+{"name": "trent merrill"},
+{"name": "donna shappert"},
+{"name": "anthony bierly"},
+{"name": "sandra clark"},
+{"name": "jackie michael"},
+{"name": "kayla stewart"},
+{"name": "tony altamirano"},
+{"name": "tina knauss"},
+{"name": "kris brady"},
+{"name": "jennifer dixon"},
+{"name": "lee spiegelman"},
+{"name": "eric alexander"},
+{"name": "richard henry"},
+{"name": "deanna martindale"},
+{"name": "aaron mcpeak"},
+{"name": "martin silver"},
+{"name": "joe torterelli"},
+{"name": "david eckberg"},
+{"name": "david prussky"},
+{"name": "david morales"},
+{"name": "alicia lark"},
+{"name": "matt karpacz"},
+{"name": "joe bielo"},
+{"name": "jack haan"},
+{"name": "dave augustine"},
+{"name": "mike royer"},
+{"name": "mike panayi"},
+{"name": "jenny tasto"},
+{"name": "robbi r"},
+{"name": "jesse b"},
+{"name": "michelle ippel"},
+{"name": "dale cook"},
+{"name": "danny young"},
+{"name": "tom sach"},
+{"name": "quiana birkbeck"},
+{"name": "peter bouchard"},
+{"name": "ken ungard"},
+{"name": "peggy davis"},
+{"name": "mira culf"},
+{"name": "jeremy cairns"},
+{"name": "dan harari"},
+{"name": "lakesha knighten"},
+{"name": "una help"},
+{"name": "matthew steinberg"},
+{"name": "clint beckstead"},
+{"name": "sue warren"},
+{"name": "joseph sds"},
+{"name": "elton ohio"},
+{"name": "gary chow"},
+{"name": "marie janis"},
+{"name": "shannon foust"},
+{"name": "jimmy murphy"},
+{"name": "kristen karabensh"},
+{"name": "michelle boyle"},
+{"name": "nicholas nguyen"},
+{"name": "jean booker"},
+{"name": "darrell peterson"},
+{"name": "laura talley"},
+{"name": "michelle custer"},
+{"name": "maritza ruiz"},
+{"name": "melissa mueller"},
+{"name": "john gartman"},
+{"name": "holly satterlee"},
+{"name": "rick tomich"},
+{"name": "bill peckford"},
+{"name": "johnny nashif"},
+{"name": "jordan miner"},
+{"name": "eric horejsi"},
+{"name": "michael easbey"},
+{"name": "josh baker"},
+{"name": "jeff fay"},
+{"name": "veronica munyon"},
+{"name": "daniel a"},
+{"name": "jackie cp"},
+{"name": "shawn jack"},
+{"name": "aimee painter"},
+{"name": "andy vallejo"},
+{"name": "mimi shemetra"},
+{"name": "marco ortiz"},
+{"name": "eric marty"},
+{"name": "vincent murphy"},
+{"name": "liz kempe"},
+{"name": "daniel altman"},
+{"name": "yvonne jacobs"},
+{"name": "lisa seitz"},
+{"name": "bob buczkowski"},
+{"name": "faith mom"},
+{"name": "leeann blakney"},
+{"name": "austin croshere"},
+{"name": "jimmy chou"},
+{"name": "bobby lopez"},
+{"name": "clark rick"},
+{"name": "king house"},
+{"name": "danielle driscoll"},
+{"name": "greg holshoe"},
+{"name": "linda ts"},
+{"name": "cameron cole"},
+{"name": "dan seaton"},
+{"name": "ann mazer"},
+{"name": "alex ybarrolaza"},
+{"name": "patrice lee"},
+{"name": "lori vilanueva"},
+{"name": "bob tucker"},
+{"name": "don gibel"},
+{"name": "carolyn doughty"},
+{"name": "carey trapp"},
+{"name": "lory viveiros"},
+{"name": "mark casey"},
+{"name": "donna lucchessi"},
+{"name": "casey huffman"},
+{"name": "jason watt"},
+{"name": "don taco"},
+{"name": "dan curtis"},
+{"name": "kaitlyn wittenburg"},
+{"name": "frances home"},
+{"name": "martha jenkins"},
+{"name": "chris prendergast"},
+{"name": "james flynn"},
+{"name": "katrina dodd"},
+{"name": "antoine rivera"},
+{"name": "kurt dieitrich"},
+{"name": "christy andrews"},
+{"name": "tom dale"},
+{"name": "martin volker"},
+{"name": "timothy isaac"},
+{"name": "richard engel"},
+{"name": "cindy laredo"},
+{"name": "julius brooks"},
+{"name": "bonnie schneider"},
+{"name": "elva licudine"},
+{"name": "chuck currie"},
+{"name": "andrea marx"},
+{"name": "jeff munn"},
+{"name": "david zonavetch"},
+{"name": "amy thoutte"},
+{"name": "frank andrel"},
+{"name": "peter fletcher"},
+{"name": "kelly holliman"},
+{"name": "kathy neith"},
+{"name": "harlan stafford"},
+{"name": "amber roasters"},
+{"name": "bridget bobel"},
+{"name": "bob birkeneder"},
+{"name": "kelvin nguyen"},
+{"name": "savannah laurey"},
+{"name": "mitchell lane"},
+{"name": "bryan tennis"},
+{"name": "tom greiwe"},
+{"name": "justin fernandes"},
+{"name": "lori vavarutsos"},
+{"name": "richard azrael"},
+{"name": "david arnold"},
+{"name": "dan stone"},
+{"name": "lee keller"},
+{"name": "damon brogdon"},
+{"name": "trina twyman"},
+{"name": "corinna mcqueen"},
+{"name": "rick webber"},
+{"name": "keith otherson"},
+{"name": "liz s"},
+{"name": "jean cleroux"},
+{"name": "meghan lewis"},
+{"name": "brian fox"},
+{"name": "alan cummings"},
+{"name": "susan kais"},
+{"name": "marty dempsey"},
+{"name": "ryan mcguinness"},
+{"name": "brenda meyer"},
+{"name": "nikki criss"},
+{"name": "albert cell"},
+{"name": "jim mingey"},
+{"name": "richard serra"},
+{"name": "jerry page"},
+{"name": "shane farley"},
+{"name": "jay carpenter"},
+{"name": "steve yu"},
+{"name": "brent nyznyk"},
+{"name": "tony dorphinghaus"},
+{"name": "jason mack"},
+{"name": "lorraine fill"},
+{"name": "steve ross"},
+{"name": "kenny lopez"},
+{"name": "norma mccall"},
+{"name": "patti zaknich"},
+{"name": "kyle miller"},
+{"name": "pam wade"},
+{"name": "marie mahoney"},
+{"name": "bob hofstetter"},
+{"name": "jimmy schada"},
+{"name": "brynn rassmussen"},
+{"name": "brad riesler"},
+{"name": "heidi mccarthy"},
+{"name": "roger cleveland"},
+{"name": "joe beattie"},
+{"name": "judy cole"},
+{"name": "dana telford"},
+{"name": "moses jangam"},
+{"name": "richard baca"},
+{"name": "dave rezendes"},
+{"name": "nathan voncolditz"},
+{"name": "jim bausano"},
+{"name": "jeffrey keller"},
+{"name": "danny yang"},
+{"name": "gary kniffen"},
+{"name": "kristie hart"},
+{"name": "audrey wright"},
+{"name": "humberto rosas"},
+{"name": "chantel emond"},
+{"name": "kathy littke"},
+{"name": "chuck cline"},
+{"name": "adrian elness"},
+{"name": "javier ortega"},
+{"name": "marie langhout"},
+{"name": "mason hoff"},
+{"name": "john mckeon"},
+{"name": "nathan carbo"},
+{"name": "markus work"},
+{"name": "justin berini"},
+{"name": "andy reid"},
+{"name": "beth mayhew"},
+{"name": "richard thorne"},
+{"name": "ed delmundo"},
+{"name": "doug mosely"},
+{"name": "abby store"},
+{"name": "delta air"},
+{"name": "rosa hoeski"},
+{"name": "mike weingrad"},
+{"name": "lydia tenah"},
+{"name": "jason pecarsky"},
+{"name": "kit wilke"},
+{"name": "nicole dix"},
+{"name": "lonnie poindexter"},
+{"name": "sarah osborn"},
+{"name": "ted wheeler"},
+{"name": "cindy casey"},
+{"name": "gary mattershead"},
+{"name": "kenny krauss"},
+{"name": "michael khalili"},
+{"name": "cammy white"},
+{"name": "bob lca"},
+{"name": "john menefee"},
+{"name": "laura wierzbowski"},
+{"name": "william age"},
+{"name": "john o'rear"},
+{"name": "steve anderson"},
+{"name": "danny kreichman"},
+{"name": "hayley robertson"},
+{"name": "jodee acres"},
+{"name": "garry nelson"},
+{"name": "lena eldridge"},
+{"name": "jonathan meltzer"},
+{"name": "terry spunaugle"},
+{"name": "chad dees"},
+{"name": "james wadsworth"},
+{"name": "david culler"},
+{"name": "brandon teal"},
+{"name": "daniel bulota"},
+{"name": "mac cosmetics"},
+{"name": "doug xxxxx"},
+{"name": "peg reznicek"},
+{"name": "nancy szeto"},
+{"name": "alex berson"},
+{"name": "alexandria rayson"},
+{"name": "brandee moody"},
+{"name": "john fyke"},
+{"name": "fran fleck"},
+{"name": "bart police"},
+{"name": "julia comadre"},
+{"name": "tina holm"},
+{"name": "jen stabach"},
+{"name": "pat wolffe"},
+{"name": "billy browne"},
+{"name": "branden riley"},
+{"name": "lena rabah"},
+{"name": "charles howard"},
+{"name": "lauren evans"},
+{"name": "ian adair"},
+{"name": "ann robertson"},
+{"name": "trenton stopher"},
+{"name": "ashley flemming"},
+{"name": "dave lorang"},
+{"name": "andrea griffin"},
+{"name": "marta partida"},
+{"name": "cindy denice"},
+{"name": "ted patterson"},
+{"name": "ben falk"},
+{"name": "amy gibson"},
+{"name": "becky larue"},
+{"name": "jesse lomonaco"},
+{"name": "teresa tarte"},
+{"name": "scott paisley"},
+{"name": "bruce kasmyere"},
+{"name": "mike trevino"},
+{"name": "amanda billyard"},
+{"name": "georgia bebe"},
+{"name": "jen coll"},
+{"name": "carl moore"},
+{"name": "bryce ingram"},
+{"name": "vernon shaut"},
+{"name": "danny wheeler"},
+{"name": "ronnie matthews"},
+{"name": "donna carter"},
+{"name": "michael peel"},
+{"name": "bob morrow"},
+{"name": "olivia bonom"},
+{"name": "jim dyson"},
+{"name": "buck rogers"},
+{"name": "kiesha dunlevy"},
+{"name": "bill sharpe"},
+{"name": "tom flint"},
+{"name": "hilary nelli"},
+{"name": "sam mar"},
+{"name": "sandra larrinaga"},
+{"name": "mark hirons"},
+{"name": "bill dickey"},
+{"name": "matt goodhue"},
+{"name": "nick kaschub"},
+{"name": "kim delfino"},
+{"name": "joseph swa"},
+{"name": "robert baker"},
+{"name": "richard bellezza"},
+{"name": "robbie richards"},
+{"name": "ben mitchell"},
+{"name": "mike stroppa"},
+{"name": "victor creese"},
+{"name": "leah wimberley"},
+{"name": "john fought"},
+{"name": "alina washington"},
+{"name": "teresa jen"},
+{"name": "manuel rodriguez"},
+{"name": "nelson fly"},
+{"name": "rosy loperena"},
+{"name": "jeremy comer"},
+{"name": "joe zucco"},
+{"name": "laura cooper"},
+{"name": "eric laclair"},
+{"name": "bobbie snow"},
+{"name": "ellen casey"},
+{"name": "an phong"},
+{"name": "luke raya"},
+{"name": "marc provost"},
+{"name": "chris vachter"},
+{"name": "jim stone"},
+{"name": "erin mackey"},
+{"name": "lottie tai"},
+{"name": "shirley davis"},
+{"name": "simone zakrzewski"},
+{"name": "maria matamoro"},
+{"name": "pete bouzianis"},
+{"name": "lance litton"},
+{"name": "celine fournier"},
+{"name": "veronica gallager"},
+{"name": "scott ward"},
+{"name": "thomas gorman"},
+{"name": "weston anson"},
+{"name": "anthony heard"},
+{"name": "gary brunk"},
+{"name": "mike colbert"},
+{"name": "mina hutchin"},
+{"name": "christy jannison"},
+{"name": "sandy he"},
+{"name": "marsha fuchs"},
+{"name": "bill martin"},
+{"name": "cesar fontalvo"},
+{"name": "michelle zatorski"},
+{"name": "jim harkass"},
+{"name": "lee adams"},
+{"name": "lee insurance"},
+{"name": "sam faivish"},
+{"name": "rachael rohrbach"},
+{"name": "chris sabandar"},
+{"name": "chris lafuria"},
+{"name": "johnathon aikey"},
+{"name": "monique watson"},
+{"name": "thomas shea"},
+{"name": "paul ricci"},
+{"name": "amber salem"},
+{"name": "brian bander"},
+{"name": "gary skulnik"},
+{"name": "jay nakamura"},
+{"name": "jamie gray"},
+{"name": "richard kotch"},
+{"name": "jeremiah bryant"},
+{"name": "karen tollison"},
+{"name": "john neugnbauer"},
+{"name": "mike kunce"},
+{"name": "katie green"},
+{"name": "frank stair"},
+{"name": "tonja dicenzo"},
+{"name": "leah driscoll"},
+{"name": "haley jones"},
+{"name": "kelly myers"},
+{"name": "corey howard"},
+{"name": "al besharah"},
+{"name": "erin ray"},
+{"name": "timothy gardner"},
+{"name": "brent salazar"},
+{"name": "patrick lee"},
+{"name": "randy olson"},
+{"name": "buddy flowers"},
+{"name": "juanita davis"},
+{"name": "erik kreutzer"},
+{"name": "ken bizovi"},
+{"name": "nicole r"},
+{"name": "glynis farr"},
+{"name": "ron berens"},
+{"name": "santos coy"},
+{"name": "tim purga"},
+{"name": "beth lieb"},
+{"name": "aaron silver"},
+{"name": "jan drennan"},
+{"name": "sally mooneyham"},
+{"name": "joe vzn"},
+{"name": "pat partlow"},
+{"name": "chris cota"},
+{"name": "jolene mumaugh"},
+{"name": "gordon owsley"},
+{"name": "amanda norris"},
+{"name": "kevin pavlish"},
+{"name": "tony beyer"},
+{"name": "leon fillya"},
+{"name": "sue l"},
+{"name": "mary costa"},
+{"name": "jeff grinalds"},
+{"name": "lauren belinda"},
+{"name": "josh danskin"},
+{"name": "megan dills"},
+{"name": "glen kluke"},
+{"name": "michael stein"},
+{"name": "crystal sanchez"},
+{"name": "erik mass"},
+{"name": "liz kundtz"},
+{"name": "doug andrews"},
+{"name": "tony baffa"},
+{"name": "bruce larson"},
+{"name": "jen hay"},
+{"name": "mark ginniny"},
+{"name": "greg campbell"},
+{"name": "bill richter"},
+{"name": "scott maiellaro"},
+{"name": "anh duong"},
+{"name": "brian charter"},
+{"name": "chad blenkin"},
+{"name": "erin brock"},
+{"name": "christa work"},
+{"name": "douglas lepisto"},
+{"name": "karen switzenbaum"},
+{"name": "billy jr"},
+{"name": "crystal porter"},
+{"name": "mary pride"},
+{"name": "alex ho"},
+{"name": "jarrett nunley"},
+{"name": "amy mc"},
+{"name": "karin gil"},
+{"name": "mike biggi"},
+{"name": "tyler campbell"},
+{"name": "danielle slavick"},
+{"name": "kenny brooks"},
+{"name": "erlinda velasco"},
+{"name": "heather hewitt"},
+{"name": "mike bear"},
+{"name": "billy powell"},
+{"name": "mark calcagno"},
+{"name": "fanny wong"},
+{"name": "jimmy v"},
+{"name": "david heckard"},
+{"name": "william barth"},
+{"name": "keith ely"},
+{"name": "gary huff"},
+{"name": "gary standel"},
+{"name": "annie harms"},
+{"name": "richard siquig"},
+{"name": "david q"},
+{"name": "kathy fitzpatric"},
+{"name": "suzie childers"},
+{"name": "edison takiyeh"},
+{"name": "dan ballou"},
+{"name": "rachelle sampson"},
+{"name": "peter cell"},
+{"name": "mia stewart"},
+{"name": "becky guzman"},
+{"name": "eddie helio"},
+{"name": "dave tools"},
+{"name": "howard perlow"},
+{"name": "jeremy ewing"},
+{"name": "otis c"},
+{"name": "marsha ferrell"},
+{"name": "mitchell cox"},
+{"name": "thad ashmore"},
+{"name": "linda thurber"},
+{"name": "jane coutts"},
+{"name": "kevin knight"},
+{"name": "sierra fischer"},
+{"name": "scot folks"},
+{"name": "lorena marino"},
+{"name": "andy beasley"},
+{"name": "rubin david"},
+{"name": "david drummer"},
+{"name": "earl dyer"},
+{"name": "patty b"},
+{"name": "shelly friedstein"},
+{"name": "lauren osterstock"},
+{"name": "brian polick"},
+{"name": "ron blount"},
+{"name": "williams caudillo"},
+{"name": "vivian ramzey"},
+{"name": "phyliss bend"},
+{"name": "cody may"},
+{"name": "rick valenzuela"},
+{"name": "carl barrio"},
+{"name": "tom kirkland"},
+{"name": "lori lind"},
+{"name": "carlos chile"},
+{"name": "michael wellington"},
+{"name": "erica cousin"},
+{"name": "alan mclemore"},
+{"name": "brandon miller"},
+{"name": "tommy church"},
+{"name": "deborah jones"},
+{"name": "andrew fortney"},
+{"name": "darrin boji"},
+{"name": "tony kazawitch"},
+{"name": "mary fish"},
+{"name": "heather r"},
+{"name": "elvira tung"},
+{"name": "bonny silver"},
+{"name": "brad kim"},
+{"name": "andrew moffs"},
+{"name": "hugo reyes"},
+{"name": "dino simotas"},
+{"name": "ryan dial"},
+{"name": "marci camp"},
+{"name": "chris beltrami"},
+{"name": "tammy garcia"},
+{"name": "deeann smith"},
+{"name": "scott mccullough"},
+{"name": "tiffany vincents"},
+{"name": "kelsey waterloo"},
+{"name": "josh jeffrey"},
+{"name": "china yan"},
+{"name": "john petiya"},
+{"name": "angie lopez"},
+{"name": "ann fam"},
+{"name": "tim daleen"},
+{"name": "sean king"},
+{"name": "xavier gallardo"},
+{"name": "kaila bloom"},
+{"name": "michelle peklo"},
+{"name": "diane hennelly"},
+{"name": "danny pannianikota"},
+{"name": "raymond shalhoub"},
+{"name": "dan colter"},
+{"name": "charlene hawkins"},
+{"name": "james bussell"},
+{"name": "john fassler"},
+{"name": "mike lau"},
+{"name": "emmitt hays"},
+{"name": "janice brune"},
+{"name": "melinda g"},
+{"name": "michael gustavel"},
+{"name": "colin schiller"},
+{"name": "nicole jones"},
+{"name": "carson tate"},
+{"name": "kristy star"},
+{"name": "patrice buford"},
+{"name": "brooke pilato"},
+{"name": "jack renfro"},
+{"name": "michelle ynajasa"},
+{"name": "alyssa maloof"},
+{"name": "jeff lancaster"},
+{"name": "mike perik"},
+{"name": "william lazarakis"},
+{"name": "jeff boarini"},
+{"name": "rob hernandez"},
+{"name": "hector joto"},
+{"name": "bob flippo"},
+{"name": "brian sprint"},
+{"name": "scott reed"},
+{"name": "mike cruz"},
+{"name": "chris spinner"},
+{"name": "steve circle"},
+{"name": "mario trs"},
+{"name": "brandon hosley"},
+{"name": "derek luke"},
+{"name": "ken verdegan"},
+{"name": "douglas weinstein"},
+{"name": "donald gould"},
+{"name": "justin zeiba"},
+{"name": "jane haney"},
+{"name": "chase mccullough"},
+{"name": "roberto chaneton"},
+{"name": "lisa quarrie"},
+{"name": "samuel lin"},
+{"name": "cecil cell"},
+{"name": "rashad terry"},
+{"name": "amanda grider"},
+{"name": "yvonne connett"},
+{"name": "howard levitt"},
+{"name": "mike marketos"},
+{"name": "andrew cooper"},
+{"name": "robert durst"},
+{"name": "lynn donofrio"},
+{"name": "rachel o'connor"},
+{"name": "mark brenner"},
+{"name": "karen ulrich"},
+{"name": "golden hooters"},
+{"name": "monica lincoln"},
+{"name": "joshua orzech"},
+{"name": "jessica kresge"},
+{"name": "dale reddell"},
+{"name": "chris lugo"},
+{"name": "wendy gottlieb"},
+{"name": "allen kaplan"},
+{"name": "robbie whitney"},
+{"name": "shawnda nelson"},
+{"name": "bert padell"},
+{"name": "dennis plumber"},
+{"name": "ashley kirkendall"},
+{"name": "steve irion"},
+{"name": "scott ogden"},
+{"name": "miguel mojica"},
+{"name": "kay taheri"},
+{"name": "jen myrdol"},
+{"name": "jerry robbins"},
+{"name": "joe macri"},
+{"name": "joe ho"},
+{"name": "alan martinez"},
+{"name": "tyler kerrigan"},
+{"name": "steve mcdonald"},
+{"name": "roy selmon"},
+{"name": "will wilson"},
+{"name": "emma bouch"},
+{"name": "charlotte matsumoto"},
+{"name": "timothy pederson"},
+{"name": "chuck hein"},
+{"name": "corey pebler"},
+{"name": "david halle"},
+{"name": "steve zarro"},
+{"name": "sheldon perry"},
+{"name": "erica mccormick"},
+{"name": "paul dupont"},
+{"name": "jim papp"},
+{"name": "nancy win"},
+{"name": "jana woodbury"},
+{"name": "andrew carmines"},
+{"name": "michael mcfalls"},
+{"name": "cecilia white"},
+{"name": "pamela roth"},
+{"name": "dan jackson"},
+{"name": "tony cell"},
+{"name": "warren wolfe"},
+{"name": "taylor western"},
+{"name": "buck biason"},
+{"name": "josh self"},
+{"name": "heather snyder"},
+{"name": "michael cammer"},
+{"name": "jon chandler"},
+{"name": "tom fanter"},
+{"name": "sharon rhamesey"},
+{"name": "tad denham"},
+{"name": "annette littlejohn"},
+{"name": "anna soriano"},
+{"name": "yvette platz"},
+{"name": "chuck prigmore"},
+{"name": "josh tiffany"},
+{"name": "nancy perez"},
+{"name": "anne monetti"},
+{"name": "michael nash"},
+{"name": "danielle allen"},
+{"name": "kelly murphy"},
+{"name": "ron mc"},
+{"name": "jimmie thomas"},
+{"name": "jaime perkins"},
+{"name": "richard drew"},
+{"name": "aaron chalfant"},
+{"name": "rhonda bartlett"},
+{"name": "howard rontal"},
+{"name": "tim meals"},
+{"name": "gavin robinson"},
+{"name": "nicole dumas"},
+{"name": "mike griggs"},
+{"name": "david @mack"},
+{"name": "adam youngbar"},
+{"name": "maye khazen"},
+{"name": "caroline morgan"},
+{"name": "nick asimakopoulos"},
+{"name": "reba peters"},
+{"name": "matt shmidtty"},
+{"name": "susan fox"},
+{"name": "mike younger"},
+{"name": "seth rye"},
+{"name": "angela manatt"},
+{"name": "stephen sipprell"},
+{"name": "brad heisler"},
+{"name": "camilla hsieh"},
+{"name": "raylene sinnott"},
+{"name": "dorothy blackmer"},
+{"name": "ed figel"},
+{"name": "jeffery petty"},
+{"name": "nikki tillman"},
+{"name": "joe illidge"},
+{"name": "greg bay"},
+{"name": "ryan fyfe"},
+{"name": "john fink"},
+{"name": "michelle kd"},
+{"name": "debbie goldreich"},
+{"name": "dale reeves"},
+{"name": "martha dean"},
+{"name": "jolyn mullin"},
+{"name": "cory snyder"},
+{"name": "bruce karen"},
+{"name": "norma sawdy"},
+{"name": "rob hudson"},
+{"name": "richard camajo"},
+{"name": "john obrien"},
+{"name": "juanita skeens"},
+{"name": "jeremy molby"},
+{"name": "norma glenn"},
+{"name": "kelly mcneil"},
+{"name": "danielle ahmed"},
+{"name": "daniel sanches"},
+{"name": "cori gadbury"},
+{"name": "doug quarles"},
+{"name": "jenifer corey"},
+{"name": "michael aloian"},
+{"name": "bob kane"},
+{"name": "joe ma"},
+{"name": "mindy greenberg"},
+{"name": "jordan lawson"},
+{"name": "brittney jones"},
+{"name": "mary berry"},
+{"name": "cristina parker"},
+{"name": "al novak"},
+{"name": "randy mulligan"},
+{"name": "jay vickers"},
+{"name": "sherie adams"},
+{"name": "darryl wong"},
+{"name": "bob chan"},
+{"name": "tom pl"},
+{"name": "lester henrickson"},
+{"name": "mike dunham"},
+{"name": "whitney hipp"},
+{"name": "tim whedon"},
+{"name": "paul wong"},
+{"name": "mark uffman"},
+{"name": "alex xie"},
+{"name": "sheldon seward"},
+{"name": "robert wickes"},
+{"name": "natalie tsigonis"},
+{"name": "lisa dejoseph"},
+{"name": "sara ball"},
+{"name": "laura karlins"},
+{"name": "darrell canfild"},
+{"name": "eric ho"},
+{"name": "mark ingold"},
+{"name": "al buro"},
+{"name": "james stella"},
+{"name": "holly ham"},
+{"name": "arlene p"},
+{"name": "joseph evasco"},
+{"name": "traci clark"},
+{"name": "lori clayton"},
+{"name": "erin rose"},
+{"name": "paula jonhson"},
+{"name": "mark fredkin"},
+{"name": "sue barnum"},
+{"name": "james fleming"},
+{"name": "bruce ellison"},
+{"name": "jason copola"},
+{"name": "rick campbell"},
+{"name": "mark sorensen"},
+{"name": "michelle vasquez"},
+{"name": "dustin wills"},
+{"name": "felicia gomez"},
+{"name": "karin gorseth"},
+{"name": "dave trim"},
+{"name": "elaine golladay"},
+{"name": "cherise thompson"},
+{"name": "mike fulton"},
+{"name": "denise palmer"},
+{"name": "jeff lacey"},
+{"name": "brittany lowrey"},
+{"name": "rebecca hughes"},
+{"name": "peter haeg"},
+{"name": "sylvia watson"},
+{"name": "keith staple"},
+{"name": "tia yoya"},
+{"name": "dan lerom"},
+{"name": "mike p"},
+{"name": "kyle roush"},
+{"name": "kate h"},
+{"name": "sam syed"},
+{"name": "clayton templeton"},
+{"name": "stephen bernard"},
+{"name": "bob rueer"},
+{"name": "linda kassin"},
+{"name": "gary gettes"},
+{"name": "mike ray"},
+{"name": "lisa faircloth"},
+{"name": "valerie hardt"},
+{"name": "olen wilford"},
+{"name": "aimee guarnieri"},
+{"name": "matthew yarbrough"},
+{"name": "kim marvin"},
+{"name": "jimmy lichter"},
+{"name": "debi holley"},
+{"name": "martin c"},
+{"name": "harold austin"},
+{"name": "max cell"},
+{"name": "duane bower"},
+{"name": "donna holt"},
+{"name": "david neptune"},
+{"name": "amanda stone"},
+{"name": "mellisa fire"},
+{"name": "phil getman"},
+{"name": "mark c"},
+{"name": "yasuko vukovitz"},
+{"name": "beth thomson"},
+{"name": "jocelyn smith"},
+{"name": "lynne o'reilly"},
+{"name": "jim smith"},
+{"name": "grant powers"},
+{"name": "angel johnson"},
+{"name": "tanya goudy"},
+{"name": "andrew hay"},
+{"name": "curtis r"},
+{"name": "marisol rivera"},
+{"name": "leah bloom"},
+{"name": "andy shop"},
+{"name": "bud @prsn"},
+{"name": "ron blackburn"},
+{"name": "andy hughes"},
+{"name": "ann muno"},
+{"name": "shawn krankey"},
+{"name": "ashley cornett"},
+{"name": "mark hobson"},
+{"name": "nicole dechristopher"},
+{"name": "tomika long"},
+{"name": "ivonne grado"},
+{"name": "nick goehring"},
+{"name": "sara bf"},
+{"name": "jon lee"},
+{"name": "helen nicol"},
+{"name": "sun engs"},
+{"name": "ron hargrove"},
+{"name": "phil wazonek"},
+{"name": "jason leagon"},
+{"name": "maria g"},
+{"name": "ashley clements"},
+{"name": "mike labate"},
+{"name": "jay nygaard"},
+{"name": "brandi bonesteel"},
+{"name": "joseph johnson"},
+{"name": "marty moss"},
+{"name": "mary taylor"},
+{"name": "mark brennard"},
+{"name": "anthony q"},
+{"name": "emma alford"},
+{"name": "heather dooley"},
+{"name": "brian nicholls"},
+{"name": "bryan carlson"},
+{"name": "brett jewel"},
+{"name": "david henry"},
+{"name": "brad schwartz"},
+{"name": "david carbohol"},
+{"name": "jess kline"},
+{"name": "nick clemment"},
+{"name": "edward iii"},
+{"name": "kristin brochman"},
+{"name": "jeri weight"},
+{"name": "billy shrock"},
+{"name": "ryan loyd"},
+{"name": "ted kepple"},
+{"name": "shane quinn"},
+{"name": "quiana evans"},
+{"name": "regina martin"},
+{"name": "rick k"},
+{"name": "edward whitfield"},
+{"name": "michelle johnson"},
+{"name": "christine zaki"},
+{"name": "bob axtell"},
+{"name": "julie lefebvre"},
+{"name": "jamie blair"},
+{"name": "shane cutting"},
+{"name": "kathy wimble"},
+{"name": "leanna waller"},
+{"name": "vince magsino"},
+{"name": "jen herter"},
+{"name": "judy riek"},
+{"name": "lindsay morabe"},
+{"name": "mike mob"},
+{"name": "carla windhorst"},
+{"name": "steve zaccardi"},
+{"name": "ryan berg"},
+{"name": "greg hamilton"},
+{"name": "rocky hodges"},
+{"name": "hector velazquez"},
+{"name": "rich waxman"},
+{"name": "valerie schmitz"},
+{"name": "kris miller"},
+{"name": "sheri parrish"},
+{"name": "todd buchas"},
+{"name": "phil prada"},
+{"name": "joey downstairs"},
+{"name": "dianne phillips"},
+{"name": "alex cheaib"},
+{"name": "gwen williams"},
+{"name": "trevor kunkle"},
+{"name": "dorothy vittner"},
+{"name": "richard stromquist"},
+{"name": "tom little"},
+{"name": "elena harper"},
+{"name": "chris barker"},
+{"name": "cynthia roberts"},
+{"name": "craig fletcher"},
+{"name": "christina cruz"},
+{"name": "sheridan k"},
+{"name": "kris hunter"},
+{"name": "john vautier"},
+{"name": "brittany godfrey"},
+{"name": "rick whitney"},
+{"name": "john barmby"},
+{"name": "nancy holekamp"},
+{"name": "matt clark"},
+{"name": "cleo raulerson"},
+{"name": "susan spielman"},
+{"name": "toney wilson"},
+{"name": "collette lamonday"},
+{"name": "dave pichelman"},
+{"name": "amber ten"},
+{"name": "richard salinas"},
+{"name": "richard portaro"},
+{"name": "joseph vargas"},
+{"name": "keith williamson"},
+{"name": "keith brooks"},
+{"name": "eric rossman"},
+{"name": "carrie parro"},
+{"name": "jerry doeling"},
+{"name": "louise wittern"},
+{"name": "justin chapman"},
+{"name": "paul loggersted"},
+{"name": "loyd james"},
+{"name": "ann hewitt"},
+{"name": "diane alex"},
+{"name": "john o'donnell"},
+{"name": "nathan fuqua"},
+{"name": "nikki farmer"},
+{"name": "robby bostain"},
+{"name": "jon genson"},
+{"name": "arnold mcbrien"},
+{"name": "chris gropp"},
+{"name": "janis palana"},
+{"name": "benny landa"},
+{"name": "dave stubbs"},
+{"name": "janette thomas"},
+{"name": "krystal bailey"},
+{"name": "peter park"},
+{"name": "ashley moore"},
+{"name": "sue chavas"},
+{"name": "karen hubbard"},
+{"name": "mike green"},
+{"name": "sam ironside"},
+{"name": "randy honydo"},
+{"name": "fred green"},
+{"name": "emery inafuku"},
+{"name": "mike lantos"},
+{"name": "gretchen ragadio"},
+{"name": "nancy miller"},
+{"name": "stacy scott"},
+{"name": "bridget cook"},
+{"name": "tina johnson"},
+{"name": "chad lamb"},
+{"name": "luke johnson"},
+{"name": "darius poiter"},
+{"name": "lakeshia chaptman"},
+{"name": "morris vhd"},
+{"name": "jess newton"},
+{"name": "niki nails"},
+{"name": "leonard chp"},
+{"name": "joe scalia"},
+{"name": "robert bobo"},
+{"name": "benjamin blank"},
+{"name": "david larbalestrier"},
+{"name": "john kiel"},
+{"name": "robert roman"},
+{"name": "don hansen"},
+{"name": "justin m"},
+{"name": "cameron beatty"},
+{"name": "james o'brien"},
+{"name": "brian goodwin"},
+{"name": "vickie barnhouse"},
+{"name": "marcie work"},
+{"name": "donald mactaggart"},
+{"name": "raphael montero"},
+{"name": "david gonzalez"},
+{"name": "barry ross"},
+{"name": "sandy wilbur"},
+{"name": "tamara smith"},
+{"name": "johnny hawks"},
+{"name": "tom saviano"},
+{"name": "tom azar"},
+{"name": "andrew maruoka"},
+{"name": "terri lopez"},
+{"name": "rodney benge"},
+{"name": "dave monico"},
+{"name": "carlton may"},
+{"name": "alex berta"},
+{"name": "sue boylan"},
+{"name": "mary aracena"},
+{"name": "margaretta symonian"},
+{"name": "mark mardock"},
+{"name": "margaret stewardson"},
+{"name": "jaime hepp"},
+{"name": "sharon vint"},
+{"name": "john fitzgerald"},
+{"name": "louis drumheller"},
+{"name": "doug walters"},
+{"name": "david hanners"},
+{"name": "chris thompson"},
+{"name": "tom marvin"},
+{"name": "karen educator"},
+{"name": "sharon lyons"},
+{"name": "tony kent"},
+{"name": "brian holmes"},
+{"name": "clay gemmel"},
+{"name": "kirby smith"},
+{"name": "patti sainato"},
+{"name": "michelle meeks"},
+{"name": "andrew sparrow"},
+{"name": "sarah peerze"},
+{"name": "stella ennis"},
+{"name": "sandra cell"},
+{"name": "todd folmer"},
+{"name": "arthur vlaez"},
+{"name": "travis phillips"},
+{"name": "brooke folsom"},
+{"name": "nancy creahan"},
+{"name": "jim riffe"},
+{"name": "barbara colter"},
+{"name": "adrian ross"},
+{"name": "reed rigging"},
+{"name": "kathleen keller"},
+{"name": "al hunter"},
+{"name": "cory swimfan"},
+{"name": "sherry trousdale"},
+{"name": "patrick conway"},
+{"name": "tom ruddick"},
+{"name": "geri ostrander"},
+{"name": "max nazarov"},
+{"name": "craig wascovich"},
+{"name": "ronnie jurado"},
+{"name": "joe levy"},
+{"name": "miriam custer"},
+{"name": "patti abernathy"},
+{"name": "shannon sweed"},
+{"name": "andrea cell"},
+{"name": "tommy warner"},
+{"name": "craig tds"},
+{"name": "eric tipton"},
+{"name": "mike riche"},
+{"name": "jonathan carey"},
+{"name": "elizabeth santos"},
+{"name": "doug hicthcock"},
+{"name": "lindsey r"},
+{"name": "marco descoteau"},
+{"name": "christina tjok"},
+{"name": "kellee scherff"},
+{"name": "susan macbeth"},
+{"name": "jackie house"},
+{"name": "katie osorio"},
+{"name": "matthew levine"},
+{"name": "justin england"},
+{"name": "elizabeth mcnicoll"},
+{"name": "howard kamienski"},
+{"name": "kevin hanna"},
+{"name": "berry jr"},
+{"name": "elana kripke"},
+{"name": "charlie g"},
+{"name": "william reid"},
+{"name": "charles devitis"},
+{"name": "rob chesnut"},
+{"name": "kellie mac"},
+{"name": "chris krouch"},
+{"name": "charles lawyer"},
+{"name": "mary farrior"},
+{"name": "scott fraser"},
+{"name": "josh baja"},
+{"name": "bob beal"},
+{"name": "terry kline"},
+{"name": "garry kinney"},
+{"name": "kelly monson"},
+{"name": "bryan mortensen"},
+{"name": "lisa meoli"},
+{"name": "norman russell"},
+{"name": "mary pund"},
+{"name": "monique gray"},
+{"name": "joel shoop"},
+{"name": "nicole ginas"},
+{"name": "bobby turse"},
+{"name": "matt williams"},
+{"name": "ian laughlin"},
+{"name": "jenny mckinley"},
+{"name": "tiffany rice"},
+{"name": "lynda jordan"},
+{"name": "steve barry"},
+{"name": "yasuko claar"},
+{"name": "dan pontefract"},
+{"name": "lori vaughn"},
+{"name": "jay anderson"},
+{"name": "steve butz"},
+{"name": "ronald droi"},
+{"name": "jazmine short"},
+{"name": "annette richardson"},
+{"name": "travis neidem"},
+{"name": "britany stearns"},
+{"name": "david rocha"},
+{"name": "cristina large"},
+{"name": "jason greenwood"},
+{"name": "freddie h"},
+{"name": "kerry fike"},
+{"name": "jasmine walker"},
+{"name": "sherry lightfoot"},
+{"name": "marlene penick"},
+{"name": "gary boyd"},
+{"name": "carol evans"},
+{"name": "jason bock"},
+{"name": "jennifer nabisco"},
+{"name": "holly fisher"},
+{"name": "kristin phillips"},
+{"name": "paul roque"},
+{"name": "consuelo hopp"},
+{"name": "tiffany douglas"},
+{"name": "kelly bennett"},
+{"name": "charles gentile"},
+{"name": "dan struble"},
+{"name": "erika hardy"},
+{"name": "tina acranis"},
+{"name": "nikki burnett"},
+{"name": "steve johnson"},
+{"name": "edward agustin"},
+{"name": "james reyes"},
+{"name": "stacey volz"},
+{"name": "bernie murphy"},
+{"name": "cindy nolan"},
+{"name": "mark sandvik"},
+{"name": "lauren wiley"},
+{"name": "steve judy"},
+{"name": "ryan element"},
+{"name": "tara denton"},
+{"name": "bob bowers"},
+{"name": "daniel cislo"},
+{"name": "sarah post"},
+{"name": "jen ryan"},
+{"name": "vince vallango"},
+{"name": "lee keese"},
+{"name": "paul media"},
+{"name": "richard nehus"},
+{"name": "lou tallon"},
+{"name": "michelle olsen"},
+{"name": "steve schick"},
+{"name": "alex williamson"},
+{"name": "keith maximillian"},
+{"name": "cassie reames"},
+{"name": "anthony lupo"},
+{"name": "ellen roberts"},
+{"name": "evan remenda"},
+{"name": "laurie curtis"},
+{"name": "brian hayden"},
+{"name": "allen ng"},
+{"name": "toi powell"},
+{"name": "bob brumfild"},
+{"name": "shawn frain"},
+{"name": "jewell reddick"},
+{"name": "tresa conner"},
+{"name": "kellie mitchell"},
+{"name": "nichole camery"},
+{"name": "shane hurst"},
+{"name": "paul skowronski"},
+{"name": "james anciso"},
+{"name": "douglas cox"},
+{"name": "scott ford"},
+{"name": "spencer gifts"},
+{"name": "ed koler"},
+{"name": "todd heaton"},
+{"name": "harry julkunen"},
+{"name": "michael stolz"},
+{"name": "mary bryant"},
+{"name": "nicolas miramontes"},
+{"name": "nga im"},
+{"name": "jeff schiff"},
+{"name": "sean thorsen"},
+{"name": "mike mcginn"},
+{"name": "ed tc"},
+{"name": "ray kmc"},
+{"name": "sid lauther"},
+{"name": "steve burns"},
+{"name": "reed mahlke"},
+{"name": "alissa cote"},
+{"name": "mario straccialini"},
+{"name": "beth beranek"},
+{"name": "cody cannon"},
+{"name": "lisa rowe"},
+{"name": "charles shephard"},
+{"name": "rita wesley"},
+{"name": "mark rathouse"},
+{"name": "brian cocktails"},
+{"name": "tiffany girl"},
+{"name": "andy williams"},
+{"name": "todd tamscin"},
+{"name": "david ralston"},
+{"name": "lucas todd"},
+{"name": "frank housekeeper"},
+{"name": "ken demske"},
+{"name": "andy huffman"},
+{"name": "james hair"},
+{"name": "bryan bilgore"},
+{"name": "tracey mancenido"},
+{"name": "kris jacob"},
+{"name": "sarah kensel"},
+{"name": "david deere"},
+{"name": "kevin adisek"},
+{"name": "carlos trucking"},
+{"name": "mimi trinh"},
+{"name": "glen ricard"},
+{"name": "scott poker"},
+{"name": "devin mecham"},
+{"name": "steven speece"},
+{"name": "willis properties"},
+{"name": "david rucker"},
+{"name": "tom cala"},
+{"name": "fred marx"},
+{"name": "james garofalo"},
+{"name": "robert ellis"},
+{"name": "henry frakl"},
+{"name": "owen conlan"},
+{"name": "cruz romero"},
+{"name": "martha monaco"},
+{"name": "amy gunther"},
+{"name": "eleanor nunez"},
+{"name": "brian bawden"},
+{"name": "shawn hickman"},
+{"name": "andrew kelly"},
+{"name": "cecilia perez"},
+{"name": "magda soucie"},
+{"name": "dan ivey"},
+{"name": "shaunda whalen"},
+{"name": "joey harline"},
+{"name": "ingrid franklin"},
+{"name": "phil ginn"},
+{"name": "edward eurich"},
+{"name": "liz fregoso"},
+{"name": "johnson breanna"},
+{"name": "jessica rae"},
+{"name": "missy stanley"},
+{"name": "ben holdaway"},
+{"name": "eric damondon"},
+{"name": "roseann baglino"},
+{"name": "mary mayberger"},
+{"name": "sonja wenzel"},
+{"name": "lee burn"},
+{"name": "heidi walt"},
+{"name": "laura barbara"},
+{"name": "james dunham"},
+{"name": "ruben zito"},
+{"name": "marco bravo"},
+{"name": "carole ann"},
+{"name": "ryan fleur"},
+{"name": "gino wente"},
+{"name": "jason reeves"},
+{"name": "jill pietrini"},
+{"name": "bill horobec"},
+{"name": "josh m"},
+{"name": "pat sheehan"},
+{"name": "ryan redhead"},
+{"name": "brian wiles"},
+{"name": "kristen ledke"},
+{"name": "shawn amsler"},
+{"name": "jane ran"},
+{"name": "tameka denmark"},
+{"name": "sam shop"},
+{"name": "rod moniz"},
+{"name": "terri byas"},
+{"name": "jarred beck"},
+{"name": "erik gustavson"},
+{"name": "lori feil"},
+{"name": "amy kirk"},
+{"name": "pa berthold"},
+{"name": "carol bezkostny"},
+{"name": "joyce schiebout"},
+{"name": "casey weigel"},
+{"name": "andrew simpson"},
+{"name": "lyle chastaine"},
+{"name": "florence smith"},
+{"name": "paul freeze"},
+{"name": "kit stetina"},
+{"name": "renee kurz"},
+{"name": "joy watkins"},
+{"name": "catherine chandler"},
+{"name": "sid croney"},
+{"name": "katherine diemer"},
+{"name": "annemarie barone"},
+{"name": "denise armstrong"},
+{"name": "vicky buentello"},
+{"name": "sean perry"},
+{"name": "ola koncewicz"},
+{"name": "michael ricketts"},
+{"name": "judy ball"},
+{"name": "jim o'brien"},
+{"name": "willie holland"},
+{"name": "bill bice"},
+{"name": "brandon mcquigg"},
+{"name": "matt suhayda"},
+{"name": "mollie williams"},
+{"name": "amy bauer"},
+{"name": "reagan denson"},
+{"name": "alexandra lenhard"},
+{"name": "megan ruane"},
+{"name": "cynthia funk"},
+{"name": "lisa nickels"},
+{"name": "carol ann"},
+{"name": "janet lopez"},
+{"name": "erin blair"},
+{"name": "adam hoastan"},
+{"name": "dustin wright"},
+{"name": "lee slayton"},
+{"name": "joey goped"},
+{"name": "travis centron"},
+{"name": "mark kidding"},
+{"name": "al bannon"},
+{"name": "don eddington"},
+{"name": "sharonda sexton"},
+{"name": "georgia markley"},
+{"name": "thomas chan"},
+{"name": "adam stark"},
+{"name": "jeff jurec"},
+{"name": "jon brewer"},
+{"name": "tom healey"},
+{"name": "russell lusignan"},
+{"name": "judy espejo"},
+{"name": "jennifer lloyd"},
+{"name": "rochelle duran"},
+{"name": "kenneth dumas"},
+{"name": "mario minakata"},
+{"name": "michael borkin"},
+{"name": "aliza grossman"},
+{"name": "pete mayallo"},
+{"name": "terri rogers"},
+{"name": "emily p"},
+{"name": "john mclaughlin"},
+{"name": "rob dabler"},
+{"name": "yuko matsumoto"},
+{"name": "wendy work"},
+{"name": "brian engle"},
+{"name": "jeff powell"},
+{"name": "michael grant"},
+{"name": "jasmin brooks"},
+{"name": "william maquindang"},
+{"name": "art valera"},
+{"name": "jessica powell"},
+{"name": "ashley laakso"},
+{"name": "corey winson"},
+{"name": "karen reid"},
+{"name": "douglas groh"},
+{"name": "ursula patterson"},
+{"name": "russell nauta"},
+{"name": "stan lee"},
+{"name": "diana white"},
+{"name": "jonie saures"},
+{"name": "jim harsha"},
+{"name": "belinda mcdonald"},
+{"name": "jan renner"},
+{"name": "peggy porter"},
+{"name": "ralph muniz"},
+{"name": "will green"},
+{"name": "william cantrell"},
+{"name": "kali simone"},
+{"name": "pat wiley"},
+{"name": "chris magras"},
+{"name": "tyler z"},
+{"name": "milton magnum"},
+{"name": "judy sokawski"},
+{"name": "marti perez"},
+{"name": "debbie vanlue"},
+{"name": "chris store"},
+{"name": "christopher kerbis"},
+{"name": "deanna jorgenson"},
+{"name": "jordan janusz"},
+{"name": "sabrina rouse"},
+{"name": "gail clark"},
+{"name": "van nguyen"},
+{"name": "nicole plantin"},
+{"name": "ivan drago"},
+{"name": "tim proetel"},
+{"name": "jude russell"},
+{"name": "kevin atchoo"},
+{"name": "nadia feddo"},
+{"name": "martha soria"},
+{"name": "sarina wigginton"},
+{"name": "ryan noerenberg"},
+{"name": "brian stoudt"},
+{"name": "jerry burrows"},
+{"name": "robert casterline"},
+{"name": "scotty jay"},
+{"name": "phil sweatman"},
+{"name": "patricia seybold"},
+{"name": "levi cell"},
+{"name": "ralph white"},
+{"name": "josh felber"},
+{"name": "garret gillespie"},
+{"name": "erin lee"},
+{"name": "danielle cowing"},
+{"name": "wally b"},
+{"name": "chad delong"},
+{"name": "kristina alvarez"},
+{"name": "kristy hamm"},
+{"name": "calvin townsend"},
+{"name": "travis pastrana"},
+{"name": "mike reekie"},
+{"name": "kim scataregia"},
+{"name": "don hammontree"},
+{"name": "david spire"},
+{"name": "paul pierce"},
+{"name": "wayne fowler"},
+{"name": "todd webb"},
+{"name": "diana shampansky"},
+{"name": "carol marx"},
+{"name": "frank insero"},
+{"name": "paige dobsch"},
+{"name": "bob vierkant"},
+{"name": "michael venice"},
+{"name": "liz perry"},
+{"name": "rod vitto"},
+{"name": "stacy alegroni"},
+{"name": "erin penne"},
+{"name": "tom trout"},
+{"name": "elizabeth heath"},
+{"name": "joey culito"},
+{"name": "mike higgins"},
+{"name": "walter munguia"},
+{"name": "piper taylor"},
+{"name": "jim farrough"},
+{"name": "nick ettelbrick"},
+{"name": "matt valdez"},
+{"name": "angie norton"},
+{"name": "stacey monroes"},
+{"name": "jennifer sutton"},
+{"name": "ryan stewart"},
+{"name": "jan kubatzki"},
+{"name": "ron g"},
+{"name": "tami weiss"},
+{"name": "regina petrauskas"},
+{"name": "robert plotowski"},
+{"name": "chris laderi"},
+{"name": "jimmy lang"},
+{"name": "buddy grimm"},
+{"name": "mary sokoloski"},
+{"name": "phil puljer"},
+{"name": "carly katz"},
+{"name": "luz garcia"},
+{"name": "brian vinsonhaler"},
+{"name": "natalie colunga"},
+{"name": "pam yugar"},
+{"name": "dan lamb"},
+{"name": "golden holt"},
+{"name": "laura kinzey"},
+{"name": "david breaux"},
+{"name": "shirley walker"},
+{"name": "lessie sanders"},
+{"name": "natalie a"},
+{"name": "cedric jones"},
+{"name": "jared miller"},
+{"name": "dave brady"},
+{"name": "timothy smith"},
+{"name": "cynthia moccio"},
+{"name": "greg frens"},
+{"name": "kevin jamsa"},
+{"name": "dan armstrong"},
+{"name": "greg bowman"},
+{"name": "david tanner"},
+{"name": "mark ibanez"},
+{"name": "lou adamis"},
+{"name": "lori humanities"},
+{"name": "lawrence little"},
+{"name": "debbie k"},
+{"name": "van lanen"},
+{"name": "zack zackowski"},
+{"name": "earl granger"},
+{"name": "nick kluthe"},
+{"name": "john mondelli"},
+{"name": "steve rokay"},
+{"name": "keith mignone"},
+{"name": "gordon tait"},
+{"name": "mark michuda"},
+{"name": "mimi miami"},
+{"name": "bruce kenney"},
+{"name": "oliver revel"},
+{"name": "marvin cooke"},
+{"name": "dan bar"},
+{"name": "ron lewis"},
+{"name": "mario flores"},
+{"name": "ann killian"},
+{"name": "monty donovan"},
+{"name": "ted yamamoto"},
+{"name": "debra brummer"},
+{"name": "tiffany dunning"},
+{"name": "stefan rubin"},
+{"name": "dean clark"},
+{"name": "lee aldridge"},
+{"name": "jane ellsworth"},
+{"name": "heather szerlag"},
+{"name": "meghan williams"},
+{"name": "ken soellner"},
+{"name": "mark ziman"},
+{"name": "maura mccartan"},
+{"name": "sue muncey"},
+{"name": "andria jackson"},
+{"name": "leanne fung"},
+{"name": "dustin mystic"},
+{"name": "erika nielson"},
+{"name": "colleen newton"},
+{"name": "john avery"},
+{"name": "peggy rob"},
+{"name": "susan bernal"},
+{"name": "randy gomez"},
+{"name": "vicki harrison"},
+{"name": "kyle kinch"},
+{"name": "allie conlay"},
+{"name": "lisa senters"},
+{"name": "terri andersen"},
+{"name": "marie camaya"},
+{"name": "steve wierzbowski"},
+{"name": "marta bartolacci"},
+{"name": "richard ellenbogen"},
+{"name": "tara bowden"},
+{"name": "george myers"},
+{"name": "phil mathis"},
+{"name": "dee manitt"},
+{"name": "rachel thompson"},
+{"name": "paul zaneli"},
+{"name": "todd hurst"},
+{"name": "james glavey"},
+{"name": "melissa ruffing"},
+{"name": "ed greaves"},
+{"name": "marie o"},
+{"name": "jason martnez"},
+{"name": "rob wayne"},
+{"name": "tim riforgiate"},
+{"name": "aaron gordon"},
+{"name": "chris lomenda"},
+{"name": "ricardo ramirez"},
+{"name": "rich powell"},
+{"name": "ryan tubongbanua"},
+{"name": "harold sarvetnick"},
+{"name": "chris waldrop"},
+{"name": "michael alicea"},
+{"name": "bert briones"},
+{"name": "kathy ishikawa"},
+{"name": "athena drum"},
+{"name": "debbie pazlar"},
+{"name": "john neighbors"},
+{"name": "peter furnari"},
+{"name": "annette dewoody"},
+{"name": "james vinson"},
+{"name": "larry smith"},
+{"name": "kevin s"},
+{"name": "laura cruz"},
+{"name": "jason wachtel"},
+{"name": "carol diaz"},
+{"name": "lee carnathan"},
+{"name": "daniel komelan"},
+{"name": "maggie farag"},
+{"name": "greg rushforth"},
+{"name": "jocelyn carroll"},
+{"name": "ali keyghobadi"},
+{"name": "peter hess"},
+{"name": "anne varrasso"},
+{"name": "sara hendricks"},
+{"name": "al power"},
+{"name": "eric wang"},
+{"name": "brian shield"},
+{"name": "milton keys"},
+{"name": "daniel welch"},
+{"name": "li wu"},
+{"name": "jeffrey sierawski"},
+{"name": "ed moller"},
+{"name": "eric yancy"},
+{"name": "son hm"},
+{"name": "kyla minyard"},
+{"name": "cory f"},
+{"name": "judith cedillos"},
+{"name": "beau woods"},
+{"name": "keith ruby"},
+{"name": "andrew kassman"},
+{"name": "kenneth plumley"},
+{"name": "polly carlson"},
+{"name": "adam burns"},
+{"name": "bernard white"},
+{"name": "tom baalmann"},
+{"name": "chaya shagalow"},
+{"name": "brad ku"},
+{"name": "dana mathis"},
+{"name": "mike drewery"},
+{"name": "krysta clark"},
+{"name": "mark ricigliano"},
+{"name": "sarah schriber"},
+{"name": "matt nuckols"},
+{"name": "colleen ito"},
+{"name": "jerry putnam"},
+{"name": "kenneth waurin"},
+{"name": "david conn"},
+{"name": "todd malone"},
+{"name": "sarah milligan"},
+{"name": "trent mullins"},
+{"name": "jon s"},
+{"name": "john walter"},
+{"name": "ron pentz"},
+{"name": "scott summers"},
+{"name": "ivette vzw"},
+{"name": "jim estes"},
+{"name": "abel morales"},
+{"name": "dan lackey"},
+{"name": "dana staples"},
+{"name": "maria berindoague"},
+{"name": "dee cell"},
+{"name": "kelly newton"},
+{"name": "francesca cater"},
+{"name": "carlton cell"},
+{"name": "julietta ranches"},
+{"name": "anthony lopez"},
+{"name": "marcus ezell"},
+{"name": "ken yee"},
+{"name": "sophie bundalo"},
+{"name": "jolie steppe"},
+{"name": "alicia kornegay"},
+{"name": "joe aguilar"},
+{"name": "alpha optical"},
+{"name": "sarah everright"},
+{"name": "kevin esser"},
+{"name": "james callejas"},
+{"name": "david ellis"},
+{"name": "cheryl adams"},
+{"name": "annie bowersox"},
+{"name": "matt truitt"},
+{"name": "bobby herbeck"},
+{"name": "robert shaw"},
+{"name": "stephanie norris"},
+{"name": "rod gregg"},
+{"name": "kenneth nixon"},
+{"name": "bill wootton"},
+{"name": "lachelle mound"},
+{"name": "steve hayes"},
+{"name": "china mobile"},
+{"name": "jessie cc"},
+{"name": "larry photos"},
+{"name": "marc kraft"},
+{"name": "lucia scheckner"},
+{"name": "ryan chan"},
+{"name": "casey loft"},
+{"name": "lauren tanner"},
+{"name": "michael crawford"},
+{"name": "matthew grayson"},
+{"name": "terrence osborne"},
+{"name": "fritz birkmaier"},
+{"name": "scott spicola"},
+{"name": "maria prevesk"},
+{"name": "angela hunter"},
+{"name": "edgar lopez"},
+{"name": "marc smith"},
+{"name": "samuel hemmings"},
+{"name": "carlos soldan"},
+{"name": "inge soenarko"},
+{"name": "vicki strom"},
+{"name": "dan crots"},
+{"name": "kent declerck"},
+{"name": "katie philpott"},
+{"name": "karen terlicher"},
+{"name": "richard dick"},
+{"name": "jeff sanders"},
+{"name": "mike mcginnis"},
+{"name": "timmy chang"},
+{"name": "vivian wood"},
+{"name": "vincent yu"},
+{"name": "shauna novy"},
+{"name": "james ll"},
+{"name": "leslie lash"},
+{"name": "heather threlkeld"},
+{"name": "chuck selner"},
+{"name": "louise steen"},
+{"name": "pat godfrey"},
+{"name": "cindy hattersley"},
+{"name": "anna agir"},
+{"name": "starr taylor"},
+{"name": "greg sebilian"},
+{"name": "tracie ro"},
+{"name": "jose cuervo"},
+{"name": "jon mahoney"},
+{"name": "donna santoroski"},
+{"name": "sheila reilly"},
+{"name": "kim hall"},
+{"name": "ed mcgreenhan"},
+{"name": "terri townsend"},
+{"name": "ryan wickers"},
+{"name": "sally pusey"},
+{"name": "david shedrick"},
+{"name": "emily starky"},
+{"name": "kyle sagan"},
+{"name": "dave tamroff"},
+{"name": "angie sturgeon"},
+{"name": "darren allwood"},
+{"name": "mike zelenak"},
+{"name": "david albertrson"},
+{"name": "amanda sigfrinius"},
+{"name": "douglas dugard"},
+{"name": "calvin choi"},
+{"name": "don ladd"},
+{"name": "chris hobbs"},
+{"name": "jason katzen"},
+{"name": "chris pro"},
+{"name": "larry glickman"},
+{"name": "judson phillips"},
+{"name": "jim travlos"},
+{"name": "bill newman"},
+{"name": "traci jensen"},
+{"name": "anne vivien"},
+{"name": "kelly farmer"},
+{"name": "sandra barrett"},
+{"name": "dylan gray"},
+{"name": "mark greg"},
+{"name": "jeff mock"},
+{"name": "mike weinar"},
+{"name": "josh carrier"},
+{"name": "michelle alvey"},
+{"name": "dale baird"},
+{"name": "ben sanders"},
+{"name": "fred brick"},
+{"name": "chris fries"},
+{"name": "jessie p"},
+{"name": "matt geren"},
+{"name": "chester pediatrics"},
+{"name": "ray noel"},
+{"name": "eric white"},
+{"name": "dale ______"},
+{"name": "matt routh"},
+{"name": "alison lemaster"},
+{"name": "anna dillon"},
+{"name": "taylor degooyer"},
+{"name": "darcel wright"},
+{"name": "philip denton"},
+{"name": "anna patron"},
+{"name": "daniel tran"},
+{"name": "eric elder"},
+{"name": "shirley israel"},
+{"name": "sue sanor"},
+{"name": "david boggins"},
+{"name": "francisco solis"},
+{"name": "grant dowty"},
+{"name": "stephani bocanegra"},
+{"name": "george olson"},
+{"name": "vida beth"},
+{"name": "tonie brown"},
+{"name": "valerie castillo"},
+{"name": "julie mayhew"},
+{"name": "andy guy"},
+{"name": "jacob bowen"},
+{"name": "mariah cakes"},
+{"name": "jamie paul"},
+{"name": "kathy mccrady"},
+{"name": "larry tate"},
+{"name": "bob rogers"},
+{"name": "marc jappaya"},
+{"name": "jodi poirier"},
+{"name": "wes walker"},
+{"name": "sarah rangel"},
+{"name": "patricia williams"},
+{"name": "ray rios"},
+{"name": "tina eskridge"},
+{"name": "marilyn busby"},
+{"name": "walter camp"},
+{"name": "anh tien"},
+{"name": "donnie oliver"},
+{"name": "dani synarski"},
+{"name": "steve bartley"},
+{"name": "kim massage"},
+{"name": "joey kessler"},
+{"name": "justin fatty"},
+{"name": "jim wolf"},
+{"name": "mary leaderman"},
+{"name": "kyla brand"},
+{"name": "mike dolak"},
+{"name": "anne holtsclaw"},
+{"name": "james rigney"},
+{"name": "marshall brumbelow"},
+{"name": "gloria balaban"},
+{"name": "adrian ho"},
+{"name": "june annis"},
+{"name": "kris jimenez"},
+{"name": "marc clement"},
+{"name": "deana williams"},
+{"name": "jack meyer"},
+{"name": "wayne sherman"},
+{"name": "george bonomo"},
+{"name": "jennifer sorensen"},
+{"name": "albert andrawos"},
+{"name": "joseph lopez"},
+{"name": "amy lawman"},
+{"name": "gregory king"},
+{"name": "matt croppo"},
+{"name": "heather grana"},
+{"name": "michaela soltan"},
+{"name": "mark thomco"},
+{"name": "john lindsey"},
+{"name": "aaron rambeau"},
+{"name": "ken wiley"},
+{"name": "edna kelly"},
+{"name": "kim ross"},
+{"name": "joey vic"},
+{"name": "maria marquez"},
+{"name": "rocco macri"},
+{"name": "lindsay saylor"},
+{"name": "nicole yankelovich"},
+{"name": "patrick kirtz"},
+{"name": "ali wing"},
+{"name": "tom kimbra"},
+{"name": "kim warda"},
+{"name": "jay hwang"},
+{"name": "marvin posey"},
+{"name": "pete cp"},
+{"name": "cheryl mooney"},
+{"name": "kurt swan"},
+{"name": "melissa young"},
+{"name": "jeff bishop"},
+{"name": "phyllis boykin"},
+{"name": "ed hollis"},
+{"name": "craig hayes"},
+{"name": "roxy rivas"},
+{"name": "randy sims"},
+{"name": "janice brinkley"},
+{"name": "brian burton"},
+{"name": "kassandra perry"},
+{"name": "dave jaq"},
+{"name": "karen hughes"},
+{"name": "brian wilder"},
+{"name": "peg sheehan"},
+{"name": "barb email"},
+{"name": "kirk bryde"},
+{"name": "ty thompson"},
+{"name": "dennis cherk"},
+{"name": "elton salinas"},
+{"name": "ruby model"},
+{"name": "michael spencer"},
+{"name": "bree green"},
+{"name": "marcus crump"},
+{"name": "brian farley"},
+{"name": "julie redken"},
+{"name": "thalia nalwy"},
+{"name": "ashley barriios"},
+{"name": "anna breland"},
+{"name": "justin text"},
+{"name": "linda beech"},
+{"name": "ha nguyen"},
+{"name": "nicole step"},
+{"name": "heidi pham"},
+{"name": "bobbie nicole"},
+{"name": "rachel lesiter"},
+{"name": "robert mcnamara"},
+{"name": "rob frakes"},
+{"name": "keely collet"},
+{"name": "david bank"},
+{"name": "scott siegal"},
+{"name": "jimmy long"},
+{"name": "eric gutierrez"},
+{"name": "jill mitchell"},
+{"name": "miranda taylor"},
+{"name": "jeannine nati"},
+{"name": "kyle robillard"},
+{"name": "mark bentley"},
+{"name": "tim wolfmeyer"},
+{"name": "bob townsand"},
+{"name": "frank gaona"},
+{"name": "ellen desaint"},
+{"name": "bill donnellan"},
+{"name": "kate zuckerman"},
+{"name": "kristen nobel"},
+{"name": "nikki twist"},
+{"name": "karrie brewster"},
+{"name": "julie la"},
+{"name": "ella shepherd"},
+{"name": "tabitha fe"},
+{"name": "lauren anderson"},
+{"name": "gregory kotovos"},
+{"name": "michelle posch"},
+{"name": "jesse mitchell"},
+{"name": "cynthia skoglund"},
+{"name": "todd melinn"},
+{"name": "mark walde"},
+{"name": "dana facemyer"},
+{"name": "paul maley"},
+{"name": "stephen hemmert"},
+{"name": "george orbin"},
+{"name": "zachary mattina"},
+{"name": "brandi akers"},
+{"name": "sam carruth"},
+{"name": "marisol travarez"},
+{"name": "deb helf"},
+{"name": "jose barreda"},
+{"name": "lee marshall"},
+{"name": "neil macnaughton"},
+{"name": "eric stacy"},
+{"name": "ed villar"},
+{"name": "doug saner"},
+{"name": "pat heaney"},
+{"name": "dawn wilson"},
+{"name": "joan charles"},
+{"name": "simon ross"},
+{"name": "tom curley"},
+{"name": "hung fm"},
+{"name": "melissa cell"},
+{"name": "moises cadena"},
+{"name": "joycelyn mashidas"},
+{"name": "sandra rios"},
+{"name": "nick kohut"},
+{"name": "peter caswell"},
+{"name": "lucy grandma"},
+{"name": "larry tannas"},
+{"name": "savannah jaime"},
+{"name": "ahmed merchant"},
+{"name": "andy noll"},
+{"name": "irish ivy"},
+{"name": "wes crockett"},
+{"name": "candice nosworthy"},
+{"name": "jerry gleason"},
+{"name": "brandy m"},
+{"name": "katrina roberts"},
+{"name": "tommy turner"},
+{"name": "sandra medina"},
+{"name": "kris arendt"},
+{"name": "joesph johnson"},
+{"name": "bobby d"},
+{"name": "kenneth thornton"},
+{"name": "janine harouni"},
+{"name": "janet arntzen"},
+{"name": "linda davis"},
+{"name": "craig meyers"},
+{"name": "chris att"},
+{"name": "maria salvador"},
+{"name": "jeremy useted"},
+{"name": "ronnie jappaya"},
+{"name": "randell heft"},
+{"name": "vinnie hagar"},
+{"name": "corey blade"},
+{"name": "oscar comcast"},
+{"name": "randy luct"},
+{"name": "bobby bet"},
+{"name": "kate gap"},
+{"name": "sheryl coleman"},
+{"name": "dana shayegan"},
+{"name": "ryan hendrick"},
+{"name": "ray z"},
+{"name": "george bowen"},
+{"name": "tim myers"},
+{"name": "andres abudei"},
+{"name": "gail taggart"},
+{"name": "gianna bean"},
+{"name": "maddie cooper"},
+{"name": "shawn fuller"},
+{"name": "rich bogen"},
+{"name": "alita kalgaard"},
+{"name": "wilfred muana"},
+{"name": "linda link"},
+{"name": "jamie meltzer"},
+{"name": "ryan leach"},
+{"name": "rosemary henderson"},
+{"name": "nancy thompson"},
+{"name": "roxanne lucero"},
+{"name": "nikki gadow"},
+{"name": "brad sims"},
+{"name": "wilfredo teran"},
+{"name": "nancy pettengill"},
+{"name": "justin long"},
+{"name": "carl delfs"},
+{"name": "stacie cooper"},
+{"name": "kenneth glacier"},
+{"name": "queen williams"},
+{"name": "valerie sinady"},
+{"name": "frank porche"},
+{"name": "brian robinson"},
+{"name": "mark dawson"},
+{"name": "nick cannon"},
+{"name": "megan duffy"},
+{"name": "gary vandenberg"},
+{"name": "randy reitz"},
+{"name": "amy bachelder"},
+{"name": "roger ehrenberg"},
+{"name": "roberto wandelai"},
+{"name": "ian mccubbin"},
+{"name": "ron sliney"},
+{"name": "blake fortune"},
+{"name": "nita payne"},
+{"name": "courtney glover"},
+{"name": "pete graziano"},
+{"name": "michael hamer"},
+{"name": "cassie collett"},
+{"name": "brittany philips"},
+{"name": "nick hood"},
+{"name": "eric andersen"},
+{"name": "star ind"},
+{"name": "darcy keller"},
+{"name": "tom taylor"},
+{"name": "grace robinson"},
+{"name": "margot girouard"},
+{"name": "pat seeber"},
+{"name": "jessica thomas"},
+{"name": "karen mimm"},
+{"name": "jan rothenhoefer"},
+{"name": "gerry cameron"},
+{"name": "amanda paffrath"},
+{"name": "gene loper"},
+{"name": "aline nobrega"},
+{"name": "kurt kinsley"},
+{"name": "carmelo caisip"},
+{"name": "katie t"},
+{"name": "louisa mcray"},
+{"name": "john macleod"},
+{"name": "patrick cooper"},
+{"name": "dave harrison"},
+{"name": "marissa gorlick"},
+{"name": "christy reeves"},
+{"name": "aaron johnston"},
+{"name": "rusty stapp"},
+{"name": "linda hadley"},
+{"name": "jennifer graham"},
+{"name": "sam whitesides"},
+{"name": "karen mccarty"},
+{"name": "amanda bernardi"},
+{"name": "daisy perry"},
+{"name": "don eland"},
+{"name": "charley west"},
+{"name": "cynthia christakis"},
+{"name": "carol buntyn"},
+{"name": "erin huffman"},
+{"name": "beth szymanski"},
+{"name": "melissa marion"},
+{"name": "vince johnston"},
+{"name": "dennis nish"},
+{"name": "tom piette"},
+{"name": "claire rivers"},
+{"name": "tommy moody"},
+{"name": "keisha atl"},
+{"name": "ted ulman"},
+{"name": "sheila venters"},
+{"name": "larry zimmer"},
+{"name": "don thornton"},
+{"name": "doug borer"},
+{"name": "vince delacruz"},
+{"name": "camilla whitman"},
+{"name": "james carrillo"},
+{"name": "carlos gil"},
+{"name": "steve gonzalez"},
+{"name": "wayne eugene"},
+{"name": "ben woodrum"},
+{"name": "jorge amezcua"},
+{"name": "lynn hitson"},
+{"name": "sandra hart"},
+{"name": "fred feeney"},
+{"name": "millicent seymour"},
+{"name": "beth brisbois"},
+{"name": "keren andrade"},
+{"name": "chrissy konczyk"},
+{"name": "mario cutiee"},
+{"name": "heather jensen"},
+{"name": "susan rotter"},
+{"name": "danny brewer"},
+{"name": "leanne wu"},
+{"name": "joe vega"},
+{"name": "kristina hlinka"},
+{"name": "jennifer garcia"},
+{"name": "marc wise"},
+{"name": "roger eichberger"},
+{"name": "kent rowe"},
+{"name": "jordan greenbaum"},
+{"name": "david scheumann"},
+{"name": "brent rose"},
+{"name": "twyla alvarez"},
+{"name": "jeff mohsenin"},
+{"name": "billie bailey"},
+{"name": "jon yaldoo"},
+{"name": "jordan isaac"},
+{"name": "julie salaz"},
+{"name": "david gutierrez"},
+{"name": "terry foss"},
+{"name": "jamie leary"},
+{"name": "melissa g"},
+{"name": "debbie walters"},
+{"name": "vanessa solis"},
+{"name": "mike hamilton"},
+{"name": "holly bell"},
+{"name": "colleen hart"},
+{"name": "ron towing"},
+{"name": "debbie lonzi"},
+{"name": "jacob francis"},
+{"name": "austin stout"},
+{"name": "tam tai"},
+{"name": "vince tpd"},
+{"name": "mel g"},
+{"name": "paul butler"},
+{"name": "brent pollock"},
+{"name": "tony wilwerding"},
+{"name": "jeffrey hodges"},
+{"name": "mike neff"},
+{"name": "crystal donohue"},
+{"name": "james francis"},
+{"name": "adriana jones"},
+{"name": "yolanda armstrong"},
+{"name": "gabriel medranda"},
+{"name": "ricky ponsaa"},
+{"name": "sarah caler"},
+{"name": "emily parsons"},
+{"name": "ed murray"},
+{"name": "matt hanna"},
+{"name": "sherri christensen"},
+{"name": "karen k"},
+{"name": "larry gardner"},
+{"name": "rick kline"},
+{"name": "elaine s"},
+{"name": "amy varao"},
+{"name": "scott birnbaum"},
+{"name": "bob colson"},
+{"name": "alisha thayer"},
+{"name": "jan horton"},
+{"name": "alisha c"},
+{"name": "lynn christopher"},
+{"name": "bill schaffner"},
+{"name": "steven lesha"},
+{"name": "robin workman"},
+{"name": "glen fajota"},
+{"name": "cassie cell"},
+{"name": "john evanoff"},
+{"name": "pam massi"},
+{"name": "caroline weber"},
+{"name": "catherine grant"},
+{"name": "ryan hodgkin"},
+{"name": "david rhodes"},
+{"name": "tim lampley"},
+{"name": "jennifer barona"},
+{"name": "stephanie rich"},
+{"name": "neal schmidt"},
+{"name": "amy miranda"},
+{"name": "jerry cross"},
+{"name": "rick electric"},
+{"name": "sean diaz"},
+{"name": "john sullivan"},
+{"name": "rick webb"},
+{"name": "joanne vieira"},
+{"name": "pearl betker"},
+{"name": "connie martens"},
+{"name": "alex abedejo"},
+{"name": "noah gold"},
+{"name": "bruce chittenden"},
+{"name": "kathleen farrell"},
+{"name": "crystal heuberge"},
+{"name": "brian hynes"},
+{"name": "kelsey durkin"},
+{"name": "jay neal"},
+{"name": "rosie leprohon"},
+{"name": "dave baionno"},
+{"name": "rod burns"},
+{"name": "joanne ray"},
+{"name": "nicholas poser"},
+{"name": "scott f"},
+{"name": "alex wallace"},
+{"name": "shannon jackson"},
+{"name": "george figeroa"},
+{"name": "marcella davies"},
+{"name": "gina moore"},
+{"name": "tom lloyd"},
+{"name": "maritza model"},
+{"name": "melvin cookout"},
+{"name": "sandra mann"},
+{"name": "jessie price"},
+{"name": "christie n"},
+{"name": "chris hogue"},
+{"name": "jack connors"},
+{"name": "lynda skaf"},
+{"name": "mark letchumanan"},
+{"name": "karma carey"},
+{"name": "linda damn"},
+{"name": "ken sherman"},
+{"name": "winnifred roth"},
+{"name": "ann duncan"},
+{"name": "henry ellard"},
+{"name": "jarvis moss"},
+{"name": "cyndi suarez"},
+{"name": "alison hake"},
+{"name": "david clark"},
+{"name": "linda whited"},
+{"name": "leanne g"},
+{"name": "fran seester"},
+{"name": "deb mercy"},
+{"name": "jackie fuller"},
+{"name": "jim adison"},
+{"name": "nancy davidson"},
+{"name": "dan rosenbaum"},
+{"name": "adam brown"},
+{"name": "david annen"},
+{"name": "carlo voelker"},
+{"name": "kelly wings"},
+{"name": "roberta bren"},
+{"name": "brian amr"},
+{"name": "sandra villareal"},
+{"name": "stephanie meyer"},
+{"name": "jacob pegel"},
+{"name": "jeremy hogue"},
+{"name": "kelly ann"},
+{"name": "melissa pietras"},
+{"name": "rosie cordero"},
+{"name": "alicia hart"},
+{"name": "doug henderson"},
+{"name": "sheena johnson"},
+{"name": "andrea glass"},
+{"name": "lou sandavol"},
+{"name": "judi f"},
+{"name": "darren dives"},
+{"name": "joe gobern"},
+{"name": "paul mcnamara"},
+{"name": "alex elkin"},
+{"name": "marie k"},
+{"name": "jerry beukelman"},
+{"name": "mike crowther"},
+{"name": "nicole stang"},
+{"name": "eric goes"},
+{"name": "al smash"},
+{"name": "angela cox"},
+{"name": "kimberly sandoval"},
+{"name": "phil buchanan"},
+{"name": "mark strother"},
+{"name": "margaret ferguson"},
+{"name": "rick h"},
+{"name": "michael fitzgerald"},
+{"name": "jon tinderbox"},
+{"name": "shawnda merriman"},
+{"name": "julie lederhos"},
+{"name": "mike deguzman"},
+{"name": "chris thayer"},
+{"name": "steve wieble"},
+{"name": "taryn austin"},
+{"name": "chris mcbennett"},
+{"name": "bridget miller"},
+{"name": "jenny edwards"},
+{"name": "gordon barr"},
+{"name": "rick bren"},
+{"name": "bea bobadilla"},
+{"name": "george brozos"},
+{"name": "josie cirrintano"},
+{"name": "santa taxi"},
+{"name": "jackie davis"},
+{"name": "jeff labriolb"},
+{"name": "jerry severson"},
+{"name": "lisa shell"},
+{"name": "tim flury"},
+{"name": "shirley acct"},
+{"name": "shane dunn"},
+{"name": "jennifer benson"},
+{"name": "mark shannon"},
+{"name": "al jenkins"},
+{"name": "jennifer burke"},
+{"name": "alfred kee"},
+{"name": "greg blount"},
+{"name": "greg marston"},
+{"name": "steve overbay"},
+{"name": "david tillman"},
+{"name": "jay burgus"},
+{"name": "tanya lee"},
+{"name": "karen steve"},
+{"name": "robert mattison"},
+{"name": "dustin schwaab"},
+{"name": "brian jesiolowski"},
+{"name": "doug dahlbeck"},
+{"name": "antonio flores"},
+{"name": "pat sandifer"},
+{"name": "george georghiades"},
+{"name": "michael shiakallis"},
+{"name": "bob schroeder"},
+{"name": "michelle hester"},
+{"name": "scott grove"},
+{"name": "jesse carlson"},
+{"name": "kendra drinnin"},
+{"name": "craig blair"},
+{"name": "heidi jinks"},
+{"name": "micheal goodman"},
+{"name": "rebecca armstrong"},
+{"name": "cheryl bready"},
+{"name": "dave smart"},
+{"name": "john benoit"},
+{"name": "toni t"},
+{"name": "ralph rabinowitz"},
+{"name": "robert moreyra"},
+{"name": "paul thornton"},
+{"name": "jason jaques"},
+{"name": "jaime dorman"},
+{"name": "bobby delacruz"},
+{"name": "jim windham"},
+{"name": "jim langham"},
+{"name": "johnathan perkins"},
+{"name": "jeff devita"},
+{"name": "brian luckman"},
+{"name": "bob jellison"},
+{"name": "curtis finch"},
+{"name": "julie lyles"},
+{"name": "val boston"},
+{"name": "kai ocean"},
+{"name": "roseanne floresca"},
+{"name": "kasey spencer"},
+{"name": "tyler kennedy"},
+{"name": "steven brisco"},
+{"name": "earnest shelby"},
+{"name": "john andrada"},
+{"name": "bill guy"},
+{"name": "paul guedes"},
+{"name": "peter escola"},
+{"name": "jim brandon"},
+{"name": "clint moeller"},
+{"name": "sean dooley"},
+{"name": "kerry newman"},
+{"name": "christian demeritt"},
+{"name": "adrian mcnair"},
+{"name": "rick silversto"},
+{"name": "julian cyr"},
+{"name": "cathy rudell"},
+{"name": "leslie cancilla"},
+{"name": "dave oliver"},
+{"name": "jim steinke"},
+{"name": "scott hallett"},
+{"name": "john karagas"},
+{"name": "whitney r"},
+{"name": "travis jordan"},
+{"name": "mitch schultz"},
+{"name": "charles sarowitz"},
+{"name": "chris nicholas"},
+{"name": "sarah travis"},
+{"name": "cheryl wong"},
+{"name": "von curry"},
+{"name": "courtney illinois"},
+{"name": "george bikandi"},
+{"name": "john jaffe"},
+{"name": "ross annonimous"},
+{"name": "danny rosario"},
+{"name": "lynsey phelps"},
+{"name": "richard whelan"},
+{"name": "craig zegers"},
+{"name": "randy yamamoto"},
+{"name": "gladys carnhan"},
+{"name": "jorge romero"},
+{"name": "kathy rr"},
+{"name": "ryan king"},
+{"name": "karen carter"},
+{"name": "james sandoval"},
+{"name": "lannie garret"},
+{"name": "jim hanley"},
+{"name": "norman troudt"},
+{"name": "regina twinkle"},
+{"name": "randy grouskay"},
+{"name": "ted williams"},
+{"name": "may vicki"},
+{"name": "dave goode"},
+{"name": "ryan gunderson"},
+{"name": "daniel fenyn"},
+{"name": "gregory cullum"},
+{"name": "jeff prostovich"},
+{"name": "bruno zumbuhl"},
+{"name": "michael seibert"},
+{"name": "timmy zaltsman"},
+{"name": "laura wilkinson"},
+{"name": "ray maras"},
+{"name": "carlos cole"},
+{"name": "victoria lucia"},
+{"name": "kelly bowling"},
+{"name": "jim scheren"},
+{"name": "chris roller"},
+{"name": "russel jones"},
+{"name": "pat appraisal"},
+{"name": "doug mauricio"},
+{"name": "britney coent"},
+{"name": "jayson jordan"},
+{"name": "jon mcphee"},
+{"name": "mauricio galarce"},
+{"name": "jacqui dominik"},
+{"name": "vicky summers"},
+{"name": "steve gamble"},
+{"name": "alvin betts"},
+{"name": "michael wd"},
+{"name": "eric marshall"},
+{"name": "tony olvet"},
+{"name": "sharan amirian"},
+{"name": "mary axelsen"},
+{"name": "sara thompson"},
+{"name": "emily renters"},
+{"name": "sam reese"},
+{"name": "penny adams"},
+{"name": "tiffany aco"},
+{"name": "ha house"},
+{"name": "amber pratley"},
+{"name": "lane wallace"},
+{"name": "daniel stewart"},
+{"name": "michael vogan"},
+{"name": "eddy calcines"},
+{"name": "donald spahn"},
+{"name": "dana block"},
+{"name": "danielle d"},
+{"name": "kevin sam"},
+{"name": "mark fredstrom"},
+{"name": "geri gol"},
+{"name": "john boy"},
+{"name": "rico montoya"},
+{"name": "emanuel vinea"},
+{"name": "jude koenig"},
+{"name": "liz webb"},
+{"name": "corey dalcerro"},
+{"name": "linda bennardo"},
+{"name": "jeremy maurer"},
+{"name": "raymond yau"},
+{"name": "amanda craig"},
+{"name": "christopher sanford"},
+{"name": "larry amiette"},
+{"name": "nicolas crapoulet"},
+{"name": "karen frank"},
+{"name": "milton hardwood"},
+{"name": "paul mcgarr"},
+{"name": "van hatdfield"},
+{"name": "roxy baker"},
+{"name": "johnson pontiac"},
+{"name": "elliot dille"},
+{"name": "andrew martinez"},
+{"name": "deb cole"},
+{"name": "bill penn"},
+{"name": "sandy perez"},
+{"name": "michael walls"},
+{"name": "andrew sherwood"},
+{"name": "melissa arkin"},
+{"name": "jason kinslow"},
+{"name": "eric dalby"},
+{"name": "travis gentile"},
+{"name": "derek prenner"},
+{"name": "andrew krueger"},
+{"name": "kina johnson"},
+{"name": "theresa dale"},
+{"name": "hayley burk"},
+{"name": "kirk backer"},
+{"name": "debbie pereira"},
+{"name": "peter carpender"},
+{"name": "jason floyd"},
+{"name": "jason newman"},
+{"name": "miguel jimenez"},
+{"name": "rhonda anderson"},
+{"name": "meredith findling"},
+{"name": "lori sullivan"},
+{"name": "mark daughtery"},
+{"name": "jeff pressman"},
+{"name": "joyce yang"},
+{"name": "rich brooks"},
+{"name": "bryant andrews"},
+{"name": "peter constant"},
+{"name": "monica berge"},
+{"name": "chanel davis"},
+{"name": "phillip serna"},
+{"name": "erik mpm"},
+{"name": "kim n"},
+{"name": "hugh farrior"},
+{"name": "brandon holloway"},
+{"name": "steven laflin"},
+{"name": "tom ostrom"},
+{"name": "ron armstrong"},
+{"name": "ashley godwin"},
+{"name": "steve sorensen"},
+{"name": "mike barnett"},
+{"name": "mike hoenig"},
+{"name": "dusti laird"},
+{"name": "john eakin"},
+{"name": "elijah whoshotyou"},
+{"name": "brandon swanson"},
+{"name": "mark dorcey"},
+{"name": "george stefankiewicz"},
+{"name": "catharine arnston"},
+{"name": "nina dudak"},
+{"name": "wayne b"},
+{"name": "valerie nelson"},
+{"name": "bryan blockman"},
+{"name": "victoria biancuzzo"},
+{"name": "terry burns"},
+{"name": "bobby werhane"},
+{"name": "damon munroe"},
+{"name": "bill church"},
+{"name": "mark coonce"},
+{"name": "whitney schreck"},
+{"name": "adam knepper"},
+{"name": "cortney wirick"},
+{"name": "gary mills"},
+{"name": "victoria henry"},
+{"name": "ana torre"},
+{"name": "ross williams"},
+{"name": "andrew parry"},
+{"name": "larry laahs"},
+{"name": "eric rubio"},
+{"name": "dan frazier"},
+{"name": "john pflug"},
+{"name": "ashley guerra"},
+{"name": "christina nardoni"},
+{"name": "charlene stewart"},
+{"name": "val nesbit"},
+{"name": "lindsay dolphins"},
+{"name": "thomas lebecque"},
+{"name": "charles berkman"},
+{"name": "pat home"},
+{"name": "terry campbell"},
+{"name": "tyler flores"},
+{"name": "beth gilley"},
+{"name": "ed vazquez"},
+{"name": "anthony durant"},
+{"name": "craig southey"},
+{"name": "steve elwanger"},
+{"name": "katie dl"},
+{"name": "laura brinkmann"},
+{"name": "jason mark"},
+{"name": "david seaton"},
+{"name": "daniel wenger"},
+{"name": "greg fields"},
+{"name": "milton barnes"},
+{"name": "michelle mcalear"},
+{"name": "christopher zeppa"},
+{"name": "robert schaap"},
+{"name": "bill mcintyre"},
+{"name": "polly xxxx"},
+{"name": "tiffany gresham"},
+{"name": "alexandria ramirez"},
+{"name": "michael bartolo"},
+{"name": "ka whore"},
+{"name": "greg hearndon"},
+{"name": "carrie sullenger"},
+{"name": "dave pierce"},
+{"name": "jennifer ryan"},
+{"name": "jesus castilla"},
+{"name": "allen ruletka"},
+{"name": "angela deppe"},
+{"name": "dixie cleaners"},
+{"name": "alex karaman"},
+{"name": "will ilwu"},
+{"name": "paul horst"},
+{"name": "tim dupree"},
+{"name": "matt bracht"},
+{"name": "laura catlin"},
+{"name": "chris palazzolo"},
+{"name": "norman mones"},
+{"name": "regina perez"},
+{"name": "gary belsky"},
+{"name": "david rico"},
+{"name": "chad hanna"},
+{"name": "jen garrett"},
+{"name": "chris toti"},
+{"name": "jim laduke"},
+{"name": "pat ashcraft"},
+{"name": "bruce isakow"},
+{"name": "liz theofilos"},
+{"name": "verna robles"},
+{"name": "marcy robles"},
+{"name": "jeannie cavanaugh"},
+{"name": "ryan sydenham"},
+{"name": "david boyce"},
+{"name": "lisa stevenson"},
+{"name": "donna xxxx"},
+{"name": "mark heydorf"},
+{"name": "linda hackstaff"},
+{"name": "arden anton"},
+{"name": "cheryl hyckie"},
+{"name": "ariel farr"},
+{"name": "page charki"},
+{"name": "joe casas"},
+{"name": "tom borg"},
+{"name": "jason talley"},
+{"name": "mike falcione"},
+{"name": "chris braschler"},
+{"name": "nick kosmo"},
+{"name": "erika laura"},
+{"name": "ethan kipilii"},
+{"name": "katherine lucey"},
+{"name": "robert whincup"},
+{"name": "craig belcher"},
+{"name": "mike foley"},
+{"name": "christopher cuby"},
+{"name": "nicole holzer"},
+{"name": "amanda galindo"},
+{"name": "heidi hill"},
+{"name": "benny bernado"},
+{"name": "howard sonderling"},
+{"name": "sean warnick"},
+{"name": "kari clingo"},
+{"name": "jeff herren"},
+{"name": "sean sanchez"},
+{"name": "rob wick"},
+{"name": "mimi tao"},
+{"name": "taylor strack"},
+{"name": "audrey tierney"},
+{"name": "chelsea turano"},
+{"name": "katie dundas"},
+{"name": "joe erwin"},
+{"name": "joseph bankoff"},
+{"name": "lou huffman"},
+{"name": "chris douglas"},
+{"name": "amy lin"},
+{"name": "tracy neudecker"},
+{"name": "thomas kinney"},
+{"name": "clay roberson"},
+{"name": "mark holzman"},
+{"name": "trina winter"},
+{"name": "maggie cell"},
+{"name": "bryan sims"},
+{"name": "melissa dussault"},
+{"name": "jeffrey rosenberq"},
+{"name": "leon burtnett"},
+{"name": "randy bury"},
+{"name": "john hemm"},
+{"name": "marlana meza"},
+{"name": "liz leblanc"},
+{"name": "erma mcallister"},
+{"name": "jonathan lowell"},
+{"name": "shawn chadwick"},
+{"name": "kaitlyn konecny"},
+{"name": "jessica ghramm"},
+{"name": "patty white"},
+{"name": "heather jones"},
+{"name": "jason boyd"},
+{"name": "brock close"},
+{"name": "sheryl wolf"},
+{"name": "emilie winn"},
+{"name": "katie burns"},
+{"name": "pete gross"},
+{"name": "andy senia"},
+{"name": "chris bloss"},
+{"name": "michael frey"},
+{"name": "ashley williams"},
+{"name": "don hornor"},
+{"name": "lauren pappas"},
+{"name": "billy moore"},
+{"name": "sun garden"},
+{"name": "mel marecic"},
+{"name": "perry ironhill"},
+{"name": "allen moser"},
+{"name": "christie webster"},
+{"name": "tim ruth"},
+{"name": "trevor calender"},
+{"name": "dorinda walker"},
+{"name": "justin hoffman"},
+{"name": "alex josowitz"},
+{"name": "ryan geotzman"},
+{"name": "eddie leon"},
+{"name": "kristine cook"},
+{"name": "autumn thomas"},
+{"name": "robert cavallo"},
+{"name": "justin n"},
+{"name": "ellen tirone"},
+{"name": "chris shaw"},
+{"name": "larry siegel"},
+{"name": "dennis klama"},
+{"name": "david keating"},
+{"name": "eric murray"},
+{"name": "rhonda wolfond"},
+{"name": "paul hayes"},
+{"name": "kristina smith"},
+{"name": "fredric haberman"},
+{"name": "brad belliston"},
+{"name": "robbie adams"},
+{"name": "alan edelman"},
+{"name": "ian goodman"},
+{"name": "leon ragunauth"},
+{"name": "linda franklin"},
+{"name": "rachel stribling"},
+{"name": "jeremy mccassy"},
+{"name": "jessica thunker"},
+{"name": "heather ross"},
+{"name": "diana kirk"},
+{"name": "liz yim"},
+{"name": "alicia vegas"},
+{"name": "ken wooley"},
+{"name": "laura zemsky"},
+{"name": "fred lewis"},
+{"name": "alison gamble"},
+{"name": "pat ritchey"},
+{"name": "kerry simmons"},
+{"name": "jason love"},
+{"name": "shelley munyon"},
+{"name": "darrell walker"},
+{"name": "bo boucher"},
+{"name": "howard gips"},
+{"name": "jennifer dominitz"},
+{"name": "blake peterson"},
+{"name": "dawne yusi"},
+{"name": "larissa reifschneider"},
+{"name": "tom conville"},
+{"name": "hoa driver"},
+{"name": "gary neighbor"},
+{"name": "robert masla"},
+{"name": "dennis ritton"},
+{"name": "steve c"},
+{"name": "lisa denike"},
+{"name": "adam boomer"},
+{"name": "michael gibson"},
+{"name": "hannah fahrney"},
+{"name": "erica f"},
+{"name": "dan reynolds"},
+{"name": "wendy robinson"},
+{"name": "chris maxi"},
+{"name": "deanna grossinger"},
+{"name": "craig b"},
+{"name": "jeff rhody"},
+{"name": "sue reed"},
+{"name": "marcus gasper"},
+{"name": "les godes"},
+{"name": "carlo perez"},
+{"name": "meg gernes"},
+{"name": "jessica ryan"},
+{"name": "seth scott"},
+{"name": "kevin campos"},
+{"name": "liz williams"},
+{"name": "carly berg"},
+{"name": "van horne"},
+{"name": "ron evancho"},
+{"name": "lillian marino"},
+{"name": "pat makokha"},
+{"name": "greg nelson"},
+{"name": "irma gutierrez"},
+{"name": "ray meza"},
+{"name": "kara locke"},
+{"name": "chris abaray"},
+{"name": "margarette chabot"},
+{"name": "chad thomasson"},
+{"name": "louise williams"},
+{"name": "karen burns"},
+{"name": "katie ware"},
+{"name": "karen scott"},
+{"name": "bell son"},
+{"name": "bill stewart"},
+{"name": "joe cowell"},
+{"name": "greg pyper"},
+{"name": "wendy stafford"},
+{"name": "jim clayton"},
+{"name": "ray wan"},
+{"name": "mike lindemann"},
+{"name": "janice feldman"},
+{"name": "alesha sands"},
+{"name": "russell day"},
+{"name": "carla saunders"},
+{"name": "patricia wiley"},
+{"name": "will perry"},
+{"name": "chloe cheung"},
+{"name": "kelly dagley"},
+{"name": "brent m"},
+{"name": "nanette love"},
+{"name": "jeff arenzana"},
+{"name": "elizabeth tamayo"},
+{"name": "jean chang"},
+{"name": "keith farnsworth"},
+{"name": "dwayne fujitani"},
+{"name": "justin pellerin"},
+{"name": "jason pabone"},
+{"name": "mike donovan"},
+{"name": "arden b"},
+{"name": "michele barowy"},
+{"name": "veronica caverly"},
+{"name": "anita altop"},
+{"name": "maria ba"},
+{"name": "rich jakubowski"},
+{"name": "john afon"},
+{"name": "angela lau"},
+{"name": "salvador mendoza"},
+{"name": "jimmie george"},
+{"name": "drew deanna"},
+{"name": "jasmine lawrence"},
+{"name": "gina lovick"},
+{"name": "michelle odiorne"},
+{"name": "janet mclaughlin"},
+{"name": "christopher stevens"},
+{"name": "nick alcorn"},
+{"name": "colette shepard"},
+{"name": "mike powell"},
+{"name": "jim casciotta"},
+{"name": "graciela wk"},
+{"name": "cory mccullick"},
+{"name": "jeff hodsdon"},
+{"name": "ali razi"},
+{"name": "danny provo"},
+{"name": "brad shocker"},
+{"name": "josh in"},
+{"name": "james levy"},
+{"name": "diana guteriez"},
+{"name": "paul stark"},
+{"name": "dan sandoval"},
+{"name": "stuart ellis"},
+{"name": "gary heck"},
+{"name": "christine radigan"},
+{"name": "meredith parrish"},
+{"name": "arthur juarez"},
+{"name": "molly harper"},
+{"name": "jeff hakimbachi"},
+{"name": "bob bergman"},
+{"name": "joe chu"},
+{"name": "brian urquhart"},
+{"name": "anna rairdon"},
+{"name": "sean gerolimatos"},
+{"name": "patrick crean"},
+{"name": "katie steenbik"},
+{"name": "rosemary lopez"},
+{"name": "jim trobaugh"},
+{"name": "andrew vanderline"},
+{"name": "gary deal"},
+{"name": "mike russel"},
+{"name": "chris gilchrist"},
+{"name": "brian cramer"},
+{"name": "mike richardson"},
+{"name": "chuck heidenrich"},
+{"name": "wendy sum"},
+{"name": "natalie burrola"},
+{"name": "rudy vzw"},
+{"name": "mollie bashura"},
+{"name": "laticia chavez"},
+{"name": "mark cullum"},
+{"name": "carrie murphy"},
+{"name": "larry rostoker"},
+{"name": "lauren bullett"},
+{"name": "eddie khalili"},
+{"name": "donna raley"},
+{"name": "debra roberts"},
+{"name": "fred snow"},
+{"name": "inga wood"},
+{"name": "rafael levites"},
+{"name": "winnie lin"},
+{"name": "kim agnew"},
+{"name": "karen bale"},
+{"name": "bill gribble"},
+{"name": "bob alosia"},
+{"name": "leslie jasper"},
+{"name": "joy hemme"},
+{"name": "george mcdaniel"},
+{"name": "royce meyers"},
+{"name": "patti ong"},
+{"name": "allen hatch"},
+{"name": "missy grinnell"},
+{"name": "ed friedricks"},
+{"name": "billy turnbow"},
+{"name": "alex perkins"},
+{"name": "adam grant"},
+{"name": "shelly stark"},
+{"name": "mike zarziki"},
+{"name": "bill brown"},
+{"name": "damien burnett"},
+{"name": "trevor moses"},
+{"name": "jason ford"},
+{"name": "matt werner"},
+{"name": "janie wang"},
+{"name": "al timm"},
+{"name": "stephanie willamson"},
+{"name": "carolyn peinhardt"},
+{"name": "edwina brown"},
+{"name": "kisha friend"},
+{"name": "john tickets"},
+{"name": "armando montelongo"},
+{"name": "pamela mcmanus"},
+{"name": "jayne batts"},
+{"name": "sonya george"},
+{"name": "patty gates"},
+{"name": "lisa albers"},
+{"name": "joan elder"},
+{"name": "darrell rosenthal"},
+{"name": "brynn hammer"},
+{"name": "kevin hogan"},
+{"name": "jewel white"},
+{"name": "marc villafuerte"},
+{"name": "connie lumpkins"},
+{"name": "matt key"},
+{"name": "matt mariani"},
+{"name": "emily home"},
+{"name": "donny bryant"},
+{"name": "lisa barrow"},
+{"name": "veronica vanderhyden"},
+{"name": "ben sorte"},
+{"name": "rich pike"},
+{"name": "eric padilla"},
+{"name": "robert drescher"},
+{"name": "traci ned"},
+{"name": "alison clark"},
+{"name": "dusty h"},
+{"name": "amanda ayres"},
+{"name": "jackie home"},
+{"name": "sandy duckwall"},
+{"name": "steve randle"},
+{"name": "rick babwin"},
+{"name": "greg jackson"},
+{"name": "patricia berlo"},
+{"name": "tessa strother"},
+{"name": "lorraine ross"},
+{"name": "alan mynatt"},
+{"name": "mercedes wilm"},
+{"name": "mark leinkram"},
+{"name": "jordan da"},
+{"name": "jill mason"},
+{"name": "andy bernstein"},
+{"name": "dolly diet"},
+{"name": "melissa doerr"},
+{"name": "jonas brothers"},
+{"name": "lisa pennacchia"},
+{"name": "dave stoll"},
+{"name": "matt volleyball"},
+{"name": "david schulman"},
+{"name": "luann gips"},
+{"name": "eric fish"},
+{"name": "chad joshpe"},
+{"name": "arthur tropp"},
+{"name": "marsha carlson"},
+{"name": "thomas willardson"},
+{"name": "mike madding"},
+{"name": "jay jung"},
+{"name": "steve lacy"},
+{"name": "jennifer client"},
+{"name": "eduardo mendoza"},
+{"name": "derrick bass"},
+{"name": "sean rudes"},
+{"name": "ken hagerty"},
+{"name": "chuck lipkin"},
+{"name": "matt figueroa"},
+{"name": "jeff o'neal"},
+{"name": "bradley keith"},
+{"name": "michael wilcox"},
+{"name": "verla penney"},
+{"name": "mike nishkian"},
+{"name": "terry ledbetter"},
+{"name": "missy giannosa"},
+{"name": "joe schwartz"},
+{"name": "raquel gamboni"},
+{"name": "ann kopeczy"},
+{"name": "tim blieden"},
+{"name": "jess holman"},
+{"name": "brad cort"},
+{"name": "melodi sawick"},
+{"name": "oliver morton"},
+{"name": "lori lee"},
+{"name": "josh dewberry"},
+{"name": "sue nogales"},
+{"name": "tim skibitsky"},
+{"name": "les selvon"},
+{"name": "mike burkett"},
+{"name": "don schmucker"},
+{"name": "salvador contreras"},
+{"name": "jamie albert"},
+{"name": "cindy moore"},
+{"name": "christine bolewski"},
+{"name": "jess hakken"},
+{"name": "todd rowley"},
+{"name": "eric snakes"},
+{"name": "grant williams"},
+{"name": "debra caito"},
+{"name": "alexis edwards"},
+{"name": "jess darold"},
+{"name": "jennifer brog"},
+{"name": "edwin yulius"},
+{"name": "britta swanson"},
+{"name": "ron english"},
+{"name": "ben irlbeck"},
+{"name": "james jolly"},
+{"name": "brian vescovi"},
+{"name": "mike knies"},
+{"name": "craig clayson"},
+{"name": "james wilhelm"},
+{"name": "heather myers"},
+{"name": "keith williams"},
+{"name": "kenny dl"},
+{"name": "jose castrillo"},
+{"name": "bob clegg"},
+{"name": "katie bigelow"},
+{"name": "pablo suarez"},
+{"name": "tracy cannon"},
+{"name": "jo tower"},
+{"name": "travis slaydon"},
+{"name": "julie jordan"},
+{"name": "misty strawn"},
+{"name": "lloyd f"},
+{"name": "taylor thames"},
+{"name": "kate kazynski"},
+{"name": "annie shaffer"},
+{"name": "steve blackburn"},
+{"name": "peggy alkema"},
+{"name": "sarah dery"},
+{"name": "joyce hairston"},
+{"name": "larry gordon"},
+{"name": "adam hansen"},
+{"name": "kelly kost"},
+{"name": "steve bulmer"},
+{"name": "eric levenson"},
+{"name": "robert tetenbaum"},
+{"name": "arlinda moroirty"},
+{"name": "luis chamie"},
+{"name": "jim grey"},
+{"name": "emily franklin"},
+{"name": "ruth willen"},
+{"name": "darlene bell"},
+{"name": "roy cruz"},
+{"name": "shad sanders"},
+{"name": "margurite sanders"},
+{"name": "kathy fasce"},
+{"name": "luis captain"},
+{"name": "chris landers"},
+{"name": "nick cannizzo"},
+{"name": "david witherell"},
+{"name": "jim fischer"},
+{"name": "sidney levy"},
+{"name": "craig rochin"},
+{"name": "jason dorn"},
+{"name": "brady flaherty"},
+{"name": "alex peitz"},
+{"name": "chris tjie"},
+{"name": "teresa vzw"},
+{"name": "william miller"},
+{"name": "dexter young"},
+{"name": "michael sabatine"},
+{"name": "jeremiah fullerton"},
+{"name": "chris krisna"},
+{"name": "jody beck"},
+{"name": "claire hughes"},
+{"name": "shane kokkines"},
+{"name": "keith stewart"},
+{"name": "angela gerace"},
+{"name": "michelle fannon"},
+{"name": "kristin heiny"},
+{"name": "sheldon apsell"},
+{"name": "kevin zushi"},
+{"name": "chris massey"},
+{"name": "clint harmer"},
+{"name": "walter mock"},
+{"name": "matt hendricks"},
+{"name": "sherman yeargan"},
+{"name": "bill loon"},
+{"name": "glenn desouza"},
+{"name": "amanda cuene"},
+{"name": "ken t"},
+{"name": "bruce umeck"},
+{"name": "debbie £"},
+{"name": "courtney nicoson"},
+{"name": "mario manriquez"},
+{"name": "kasha manns"},
+{"name": "toni wheeler"},
+{"name": "richard kupper"},
+{"name": "andrew d"},
+{"name": "david lerch"},
+{"name": "candice mathews"},
+{"name": "casey moore"},
+{"name": "major seaton"},
+{"name": "david shoprite"},
+{"name": "blanca tow"},
+{"name": "derek fernandez"},
+{"name": "david aschenbrener"},
+{"name": "mark eaton"},
+{"name": "henry mendez"},
+{"name": "lindsey crose"},
+{"name": "brandon storar"},
+{"name": "hilde allman"},
+{"name": "gary hockett"},
+{"name": "michele rendina"},
+{"name": "randy derfus"},
+{"name": "joey ickler"},
+{"name": "jim voight"},
+{"name": "norma metzger"},
+{"name": "johnette lovato"},
+{"name": "larry rooker"},
+{"name": "becky evans"},
+{"name": "rae seay"},
+{"name": "lonnie boyd"},
+{"name": "david macario"},
+{"name": "mary brunner"},
+{"name": "brant marcrum"},
+{"name": "melvin nelson"},
+{"name": "brian tenhulzen"},
+{"name": "adam edgerly"},
+{"name": "natalie frausto"},
+{"name": "scott munnelly"},
+{"name": "kara swisher"},
+{"name": "walter kelly"},
+{"name": "tom muff"},
+{"name": "france faucher"},
+{"name": "mike cross"},
+{"name": "lean cell"},
+{"name": "catherine reinhart"},
+{"name": "jeremiah wipf"},
+{"name": "terry bond"},
+{"name": "steve murad"},
+{"name": "dave butcher"},
+{"name": "alex lorton"},
+{"name": "laurel evans"},
+{"name": "mike jorgenson"},
+{"name": "keith gilmour"},
+{"name": "joyce grady"},
+{"name": "hope roche"},
+{"name": "tom maroney"},
+{"name": "alan tennis"},
+{"name": "derrick nelson"},
+{"name": "brett sanchez"},
+{"name": "victor coelho"},
+{"name": "luis arandia"},
+{"name": "pam gums"},
+{"name": "john quinn"},
+{"name": "renee smith"},
+{"name": "roberta sheilds"},
+{"name": "ira dolnick"},
+{"name": "connie long"},
+{"name": "mike herr"},
+{"name": "carolyn johnson"},
+{"name": "brittany t"},
+{"name": "karen rosenthal"},
+{"name": "nick leah"},
+{"name": "vince corter"},
+{"name": "josie miller"},
+{"name": "angie besonen"},
+{"name": "jose espindola"},
+{"name": "mike lesniak"},
+{"name": "bill turney"},
+{"name": "lonnie roberts"},
+{"name": "michael hills"},
+{"name": "cory halaby"},
+{"name": "holly maracle"},
+{"name": "walter fields"},
+{"name": "grady tabor"},
+{"name": "joya johnson"},
+{"name": "aura danby"},
+{"name": "peggy thompson"},
+{"name": "alexander peterson"},
+{"name": "jay suddreth"},
+{"name": "gary kanzora"},
+{"name": "michael don"},
+{"name": "mimi yee"},
+{"name": "gary doven"},
+{"name": "marie maguire"},
+{"name": "brooke lawson"},
+{"name": "michelle beasley"},
+{"name": "ann braswell"},
+{"name": "leota moya"},
+{"name": "tom yarmon"},
+{"name": "alex neary"},
+{"name": "kyle love"},
+{"name": "lisa nit"},
+{"name": "dave koven"},
+{"name": "steve stone"},
+{"name": "fernando manchan"},
+{"name": "jeremy medieros"},
+{"name": "scott standley"},
+{"name": "bradley bucholtz"},
+{"name": "john zick"},
+{"name": "lois johnson"},
+{"name": "richard jr"},
+{"name": "jason lance"},
+{"name": "chris kaminsky"},
+{"name": "jessica herbalife"},
+{"name": "derek goldman"},
+{"name": "scotty fredricks"},
+{"name": "dave paszko"},
+{"name": "george montoya"},
+{"name": "janice rillon"},
+{"name": "fabiola alvarez"},
+{"name": "jacqueline brooks"},
+{"name": "ruth caputo"},
+{"name": "simon aus"},
+{"name": "queenie fag"},
+{"name": "barbara manor"},
+{"name": "brian hamilton"},
+{"name": "wayne barsky"},
+{"name": "nikki sherbon"},
+{"name": "mellisa horine"},
+{"name": "gina salomone"},
+{"name": "lauren nelson"},
+{"name": "renee cook"},
+{"name": "mark odin"},
+{"name": "tim hermans"},
+{"name": "brandon howard"},
+{"name": "jeffrey horing"},
+{"name": "devin pekny"},
+{"name": "sandi d"},
+{"name": "tim minton"},
+{"name": "katie cohen"},
+{"name": "mike rollins"},
+{"name": "david llewellyn"},
+{"name": "steve sugarman"},
+{"name": "amy persons"},
+{"name": "ilene butka"},
+{"name": "shelley lavell"},
+{"name": "becky morin"},
+{"name": "china iiams"},
+{"name": "iris smith"},
+{"name": "frank boshoff"},
+{"name": "jose lara"},
+{"name": "simon turner"},
+{"name": "jenna kita"},
+{"name": "scott carter"},
+{"name": "dominic divito"},
+{"name": "fred manuel"},
+{"name": "amanda zebrowski"},
+{"name": "amy dunlop"},
+{"name": "ethan abell"},
+{"name": "jane wyatt"},
+{"name": "jenny zelt"},
+{"name": "debbie cressy"},
+{"name": "kevin smith"},
+{"name": "michael heldritch"},
+{"name": "pierre cumbo"},
+{"name": "jimmy retired"},
+{"name": "mitchell pilot"},
+{"name": "desmond wong"},
+{"name": "gene hughes"},
+{"name": "david merritt"},
+{"name": "cynthia little"},
+{"name": "mike jackson"},
+{"name": "lisa staples"},
+{"name": "chris pang"},
+{"name": "bryan bluth"},
+{"name": "rita herron"},
+{"name": "lori rinehart"},
+{"name": "bob lisovich"},
+{"name": "amber a"},
+{"name": "steve riccardi"},
+{"name": "armando brunetti"},
+{"name": "kristine dempsy"},
+{"name": "rich woodhouse"},
+{"name": "roger simmons"},
+{"name": "ben schapiro"},
+{"name": "stan ellis"},
+{"name": "bobby gaon"},
+{"name": "kelli newman"},
+{"name": "george wu"},
+{"name": "robert foreman"},
+{"name": "beth murley"},
+{"name": "erik sanchez"},
+{"name": "bill madden"},
+{"name": "ray cintron"},
+{"name": "robin derosiers"},
+{"name": "john amici"},
+{"name": "nicole kramer"},
+{"name": "ron odom"},
+{"name": "will reynolds"},
+{"name": "pat morley"},
+{"name": "cayla korte"},
+{"name": "doug pickens"},
+{"name": "buddy goldman"},
+{"name": "mike bigshow"},
+{"name": "cindy tremmel"},
+{"name": "gloria miramontez"},
+{"name": "monica c"},
+{"name": "john rossman"},
+{"name": "joannie lemaster"},
+{"name": "david pyles"},
+{"name": "eric garcia"},
+{"name": "jim morrow"},
+{"name": "archie gainus"},
+{"name": "jon nm"},
+{"name": "neil sigler"},
+{"name": "john leheay"},
+{"name": "robert saltillo"},
+{"name": "anthony w"},
+{"name": "laura adams"},
+{"name": "flor mora"},
+{"name": "nikki torrence"},
+{"name": "daniel rourke"},
+{"name": "jerome evans"},
+{"name": "shawn dupuis"},
+{"name": "josh dierking"},
+{"name": "linda katz"},
+{"name": "dan moylan"},
+{"name": "ann mitchell"},
+{"name": "clark company"},
+{"name": "craig palmer"},
+{"name": "mitchel fidorka"},
+{"name": "stewart elementry"},
+{"name": "michael mazis"},
+{"name": "james bolen"},
+{"name": "jerry greenspan"},
+{"name": "donna williamson"},
+{"name": "craig scott"},
+{"name": "gino leonardi"},
+{"name": "keith reese"},
+{"name": "garry letwin"},
+{"name": "jared loch"},
+{"name": "adam moller"},
+{"name": "sheri linker"},
+{"name": "matthew siegrist"},
+{"name": "kathy mom"},
+{"name": "jordan pransky"},
+{"name": "brigitte miller"},
+{"name": "ryan bensen"},
+{"name": "eldon jackson"},
+{"name": "don madisen"},
+{"name": "alex morales"},
+{"name": "sheena turner"},
+{"name": "travis bakko"},
+{"name": "rachel lovell"},
+{"name": "brian wanzer"},
+{"name": "ann neal"},
+{"name": "suzi tillman"},
+{"name": "jay geller"},
+{"name": "nick galli"},
+{"name": "hugh hendrix"},
+{"name": "harry vt"},
+{"name": "nigel andrews"},
+{"name": "nick maus"},
+{"name": "tom chang"},
+{"name": "julie sis"},
+{"name": "mike freeland"},
+{"name": "lisa media"},
+{"name": "ray atwood"},
+{"name": "bradley rose"},
+{"name": "miles potts"},
+{"name": "sharon yencharis"},
+{"name": "chase company"},
+{"name": "vickie mclaughlin"},
+{"name": "laura lenz"},
+{"name": "mike schuster"},
+{"name": "michael presnell"},
+{"name": "jim mcneely"},
+{"name": "paul brooker"},
+{"name": "jack snead"},
+{"name": "kaye alford"},
+{"name": "ray hunsaker"},
+{"name": "bob jordan"},
+{"name": "gary ehlert"},
+{"name": "henry wong"},
+{"name": "arlene carpenter"},
+{"name": "bernadette pabillare"},
+{"name": "tim hawk"},
+{"name": "darby kondratowicz"},
+{"name": "estela talavera"},
+{"name": "alex puskas"},
+{"name": "alex whitehurst"},
+{"name": "stacy lawrence"},
+{"name": "sylvia mcginty"},
+{"name": "edwin harris"},
+{"name": "ashli wsg"},
+{"name": "dan randolph"},
+{"name": "ian choi"},
+{"name": "roseann church"},
+{"name": "rick will"},
+{"name": "ralph cell"},
+{"name": "don seeker"},
+{"name": "gail audibert"},
+{"name": "dana raines"},
+{"name": "annie fleis"},
+{"name": "crystal wilson"},
+{"name": "aaron wagner"},
+{"name": "earl heidtke"},
+{"name": "kim huey"},
+{"name": "jeff altel"},
+{"name": "john sellig"},
+{"name": "justin verizon"},
+{"name": "jeff robyn"},
+{"name": "paul lanni"},
+{"name": "jim darling"},
+{"name": "leah marco"},
+{"name": "jean jespersen"},
+{"name": "melissa mostes"},
+{"name": "julia france"},
+{"name": "cathy deleon"},
+{"name": "christopher lawrence"},
+{"name": "craig wagstaf"},
+{"name": "isaiah dillard"},
+{"name": "jo desaint"},
+{"name": "louis park"},
+{"name": "kate scull"},
+{"name": "jennifer richard"},
+{"name": "candice clever"},
+{"name": "mark rabbe"},
+{"name": "louise kilby"},
+{"name": "lino ac"},
+{"name": "sean novo"},
+{"name": "steve brock"},
+{"name": "joy clare"},
+{"name": "joe gomez"},
+{"name": "jamie kight"},
+{"name": "kevin hunter"},
+{"name": "bud smith"},
+{"name": "bobby juliya"},
+{"name": "tu nguyen"},
+{"name": "merry nsba"},
+{"name": "kevin finucane"},
+{"name": "kathy clavin"},
+{"name": "tania germany"},
+{"name": "matthew caton"},
+{"name": "gene o'brien"},
+{"name": "dean wark"},
+{"name": "mike chaney"},
+{"name": "dana messineo"},
+{"name": "rachel axo"},
+{"name": "dean powers"},
+{"name": "lisa orenstein"},
+{"name": "polly slater"},
+{"name": "allen xxxxxx"},
+{"name": "debbie bishop"},
+{"name": "sarah loyd"},
+{"name": "karen skaggs"},
+{"name": "danielle marengere"},
+{"name": "bobby rodgers"},
+{"name": "mayra v"},
+{"name": "joe pinata"},
+{"name": "darlene echeverria"},
+{"name": "todd fields"},
+{"name": "cody gordon"},
+{"name": "damon wooley"},
+{"name": "jeremy m"},
+{"name": "grace gallagher"},
+{"name": "matt phillips"},
+{"name": "zack miller"},
+{"name": "allison richards"},
+{"name": "michael bourne"},
+{"name": "beth giaccone"},
+{"name": "paul manganelli"},
+{"name": "scott satterfield"},
+{"name": "craig holley"},
+{"name": "al hauck"},
+{"name": "john reinsberg"},
+{"name": "nathan barker"},
+{"name": "alex beachy"},
+{"name": "mitchell babcock"},
+{"name": "gary martinson"},
+{"name": "jill marslano"},
+{"name": "may lee"},
+{"name": "rick mano"},
+{"name": "lori arevalo"},
+{"name": "lisa briley"},
+{"name": "johnny rivas"},
+{"name": "ramona lewis"},
+{"name": "latia cox"},
+{"name": "karen simms"},
+{"name": "jerry fleet"},
+{"name": "deann estrada"},
+{"name": "jennifer chung"},
+{"name": "henry begziak"},
+{"name": "sarah healey"},
+{"name": "kevin tawes"},
+{"name": "marc estes"},
+{"name": "john ropte"},
+{"name": "justin petyon"},
+{"name": "paul wang"},
+{"name": "kent comfort"},
+{"name": "dan higgins"},
+{"name": "robert oberley"},
+{"name": "linda trenchatella"},
+{"name": "judi redlin"},
+{"name": "cesar perez"},
+{"name": "eric quade"},
+{"name": "harvey sol"},
+{"name": "john werner"},
+{"name": "robyn baer"},
+{"name": "maria space"},
+{"name": "dan mihailovic"},
+{"name": "wendy gregorich"},
+{"name": "frank balle"},
+{"name": "nolan dougherty"},
+{"name": "stephanie fierman"},
+{"name": "david dingess"},
+{"name": "paul sifter"},
+{"name": "mike mchugh"},
+{"name": "gregory kealey"},
+{"name": "blake dickson"},
+{"name": "zack lowe"},
+{"name": "michelle daly"},
+{"name": "tony lasaponara"},
+{"name": "regina wells"},
+{"name": "judy higbee"},
+{"name": "jeff wyszkowski"},
+{"name": "sasha kelly"},
+{"name": "jefferson er"},
+{"name": "jim braudt"},
+{"name": "rachel fregien"},
+{"name": "tina morris"},
+{"name": "john weingarten"},
+{"name": "rory chadwick"},
+{"name": "bill nasello"},
+{"name": "kim ice"},
+{"name": "chuck erine"},
+{"name": "katy fallucca"},
+{"name": "davis work"},
+{"name": "pat s"},
+{"name": "ian pazian"},
+{"name": "william finnegan"},
+{"name": "jean kipp"},
+{"name": "collette fordham"},
+{"name": "jacob mcdaniels"},
+{"name": "jason wardle"},
+{"name": "anthony sandoval"},
+{"name": "glen oc"},
+{"name": "michelle decurtis"},
+{"name": "rachel lickey"},
+{"name": "rex robertson"},
+{"name": "jason wolf"},
+{"name": "victor gebhardt"},
+{"name": "melissa fuller"},
+{"name": "wayne ronhaar"},
+{"name": "kelly renfro"},
+{"name": "eric jr"},
+{"name": "matt martelii"},
+{"name": "judith souva"},
+{"name": "richard kress"},
+{"name": "bobby battle"},
+{"name": "natalie costello"},
+{"name": "beth mina"},
+{"name": "jenny bromley"},
+{"name": "kaila pesach"},
+{"name": "mark mclemore"},
+{"name": "michelle s"},
+{"name": "lee gone"},
+{"name": "christopher kusy"},
+{"name": "lea herlong"},
+{"name": "arthur suran"},
+{"name": "sue prousa"},
+{"name": "mike lenkin"},
+{"name": "jenni kasselder"},
+{"name": "beatriz saavedra"},
+{"name": "greg bruseau"},
+{"name": "stephanie pearson"},
+{"name": "paul schween"},
+{"name": "grant groskoph"},
+{"name": "john caruso"},
+{"name": "erika spjute"},
+{"name": "courtney dusenbury"},
+{"name": "abe zack"},
+{"name": "ruby larsom"},
+{"name": "cynthia byrd"},
+{"name": "tina vause"},
+{"name": "jo lawer"},
+{"name": "charlie o'leary"},
+{"name": "antoine kauffeisen"},
+{"name": "laura roel"},
+{"name": "chris borghi"},
+{"name": "adam young"},
+{"name": "brian depierre"},
+{"name": "kristen ott"},
+{"name": "spencer woodrow"},
+{"name": "michael clbs"},
+{"name": "ryan allen"},
+{"name": "jay squllace"},
+{"name": "phil ping"},
+{"name": "annette fernandez"},
+{"name": "mike fernandez"},
+{"name": "dean derryberry"},
+{"name": "catherine vincent"},
+{"name": "tommy dees"},
+{"name": "mike runey"},
+{"name": "heidi lim"},
+{"name": "calvin thomas"},
+{"name": "crystal zimmerman"},
+{"name": "cammy house"},
+{"name": "lorena funes"},
+{"name": "vince pugliese"},
+{"name": "shay omar"},
+{"name": "carmen bayona"},
+{"name": "katie hope"},
+{"name": "brad reeves"},
+{"name": "jon montgomery"},
+{"name": "ivan rr"},
+{"name": "louise weaver"},
+{"name": "bonnie hathcock"},
+{"name": "alan urkowitz"},
+{"name": "ashley lund"},
+{"name": "kevin casolari"},
+{"name": "sabrina petito"},
+{"name": "dave avner"},
+{"name": "brad tyson"},
+{"name": "leeann walters"},
+{"name": "janet trevino"},
+{"name": "pamela coleman"},
+{"name": "janice sutphen"},
+{"name": "freddie hollaman"},
+{"name": "brook blaney"},
+{"name": "steve langen"},
+{"name": "virgie walker"},
+{"name": "travis ridgell"},
+{"name": "jessica oglesbee"},
+{"name": "sarah curtis"},
+{"name": "max security"},
+{"name": "jude sonju"},
+{"name": "kimberley robertson"},
+{"name": "josh sulliven"},
+{"name": "mark patton"},
+{"name": "randy bird"},
+{"name": "beckie korzyniewski"},
+{"name": "russell zimmerman"},
+{"name": "sean nissian"},
+{"name": "mac ginness"},
+{"name": "nick rupp"},
+{"name": "hugo tecpa"},
+{"name": "leslie townsend"},
+{"name": "jacinta lewis"},
+{"name": "deanne vernengo"},
+{"name": "chris power"},
+{"name": "linda harris"},
+{"name": "alejandro acero"},
+{"name": "lorna robertson"},
+{"name": "cathy lischerelli"},
+{"name": "julie pinkham"},
+{"name": "rhonda brusven"},
+{"name": "tony pearson"},
+{"name": "jesse luna"},
+{"name": "caitlin thill"},
+{"name": "blair richarson"},
+{"name": "luke cell"},
+{"name": "andrew yen"},
+{"name": "albert pineda"},
+{"name": "frank carnahan"},
+{"name": "dennis hartman"},
+{"name": "brian kent"},
+{"name": "craig wonsidler"},
+{"name": "sherry ecker"},
+{"name": "mike tompkins"},
+{"name": "norman alverez"},
+{"name": "oscar marquez"},
+{"name": "sean moghadam"},
+{"name": "paul curylo"},
+{"name": "duane johnsons"},
+{"name": "lisa peterson"},
+{"name": "terina fitzsimmons"},
+{"name": "robert reger"},
+{"name": "chloe cable"},
+{"name": "shelly blevins"},
+{"name": "ali hassan"},
+{"name": "brandy anderson"},
+{"name": "misty hooper"},
+{"name": "katie lee"},
+{"name": "taylor nestell"},
+{"name": "jesse leeds"},
+{"name": "kenny latour"},
+{"name": "vivian yueny"},
+{"name": "jim bockstall"},
+{"name": "lashanda cuz"},
+{"name": "peter gray"},
+{"name": "melinda estrella"},
+{"name": "jon edwards"},
+{"name": "patricia cloutier"},
+{"name": "julie landry"},
+{"name": "christa schroeder"},
+{"name": "cassie kersey"},
+{"name": "margie cel"},
+{"name": "marlene bullard"},
+{"name": "drew nieporent"},
+{"name": "al brodell"},
+{"name": "steve alberts"},
+{"name": "darren b"},
+{"name": "eric zanelli"},
+{"name": "sean tuchner"},
+{"name": "april bright"},
+{"name": "larry turk"},
+{"name": "kellie camp"},
+{"name": "chantell uhl"},
+{"name": "george lacas"},
+{"name": "bill pope"},
+{"name": "joe harper"},
+{"name": "paul graddy"},
+{"name": "jim riley"},
+{"name": "jasmine ny"},
+{"name": "katie yeffa"},
+{"name": "mitchell duncan"},
+{"name": "danielle dupree"},
+{"name": "mike harris"},
+{"name": "dawn heiss"},
+{"name": "wanda raney"},
+{"name": "dominic giannini"},
+{"name": "cindy irwin"},
+{"name": "roseanne mendoza"},
+{"name": "cynthia rosario"},
+{"name": "amber alerts"},
+{"name": "dave cargo"},
+{"name": "ted julian"},
+{"name": "justin curler"},
+{"name": "eli braun"},
+{"name": "edward laurin"},
+{"name": "elliot wadsworth"},
+{"name": "sean halls"},
+{"name": "erik massey"},
+{"name": "jimmy altman"},
+{"name": "meg nigro"},
+{"name": "gail markle"},
+{"name": "michael horvath"},
+{"name": "john dickman"},
+{"name": "kenny chuang"},
+{"name": "bill crawford"},
+{"name": "astrid lebanon"},
+{"name": "steven gomez"},
+{"name": "chris recinos"},
+{"name": "stan jackson"},
+{"name": "randall wiegand"},
+{"name": "andrea dula"},
+{"name": "matt kreage"},
+{"name": "jim becker"},
+{"name": "matt alford"},
+{"name": "emily gerhardstein"},
+{"name": "glenn mckee"},
+{"name": "mike grady"},
+{"name": "kaye randle"},
+{"name": "sue reeves"},
+{"name": "liz brief"},
+{"name": "van haley"},
+{"name": "jason west"},
+{"name": "rebecca harte"},
+{"name": "adam langston"},
+{"name": "china express"},
+{"name": "lloyd black"},
+{"name": "ben mullen"},
+{"name": "jason convento"},
+{"name": "julian rueda"},
+{"name": "patrick cozier"},
+{"name": "frank crane"},
+{"name": "brian stark"},
+{"name": "ruth mayne"},
+{"name": "hugo vaquez"},
+{"name": "marie king"},
+{"name": "nancy davison"},
+{"name": "roderick day"},
+{"name": "kim kervina"},
+{"name": "paul kelsey"},
+{"name": "stacey marotta"},
+{"name": "gary james"},
+{"name": "john baker"},
+{"name": "jeanine mclean"},
+{"name": "ethan allen"},
+{"name": "erin teater"},
+{"name": "kristin pramuk"},
+{"name": "taylor pom"},
+{"name": "charles shipley"},
+{"name": "sandra ramirez"},
+{"name": "donald gardner"},
+{"name": "john briley"},
+{"name": "laura vm"},
+{"name": "al collins"},
+{"name": "willie wynn"},
+{"name": "barbara rego"},
+{"name": "laurie devoto"},
+{"name": "michael etcheverry"},
+{"name": "teri stitt"},
+{"name": "dale mauck"},
+{"name": "andrew sauer"},
+{"name": "don roemer"},
+{"name": "esperanza unknown"},
+{"name": "ralph mackey"},
+{"name": "kimberly white"},
+{"name": "sandy wilson"},
+{"name": "marty dwyer"},
+{"name": "christy m"},
+{"name": "kara baker"},
+{"name": "paul lorenz"},
+{"name": "ken boegler"},
+{"name": "brian grassey"},
+{"name": "stephanie tran"},
+{"name": "janet zimmerman"},
+{"name": "nannette cruz"},
+{"name": "john bearden"},
+{"name": "martha crab"},
+{"name": "suzy rieber"},
+{"name": "amanda gross"},
+{"name": "traci linda"},
+{"name": "andrew ryan"},
+{"name": "alyssa corona"},
+{"name": "randy thurman"},
+{"name": "larry sparks"},
+{"name": "tommy graves"},
+{"name": "april ca"},
+{"name": "richard collins"},
+{"name": "eddie foster"},
+{"name": "frank krasin"},
+{"name": "violet nicole"},
+{"name": "kyle haller"},
+{"name": "steven kinney"},
+{"name": "sam collins"},
+{"name": "tina licences"},
+{"name": "nicole grillon"},
+{"name": "lisette simon"},
+{"name": "esther gayton"},
+{"name": "esther georgeon"},
+{"name": "rich olson"},
+{"name": "mary comfort"},
+{"name": "tim meuret"},
+{"name": "ben harrison"},
+{"name": "doug evans"},
+{"name": "allan potenciano"},
+{"name": "jess strazz"},
+{"name": "dan e"},
+{"name": "gloria cell"},
+{"name": "jaime duke"},
+{"name": "anita lascala"},
+{"name": "john fahnestiel"},
+{"name": "gary pullins"},
+{"name": "ben harn"},
+{"name": "ashley doty"},
+{"name": "dylan lewis"},
+{"name": "cliff kraushaar"},
+{"name": "brandon baller"},
+{"name": "mark griffey"},
+{"name": "ryan holt"},
+{"name": "kenny lenoir"},
+{"name": "nick colo"},
+{"name": "warren sckolnick"},
+{"name": "mark vandermuelen"},
+{"name": "darius troyer"},
+{"name": "kayla m"},
+{"name": "david goldman"},
+{"name": "michele kram"},
+{"name": "jill orobello"},
+{"name": "donald burton"},
+{"name": "charlie monahan"},
+{"name": "long it"},
+{"name": "diane emerson"},
+{"name": "pat barkley"},
+{"name": "randi cecchini"},
+{"name": "kay trio"},
+{"name": "denise kato"},
+{"name": "paul howarth"},
+{"name": "karen jeff"},
+{"name": "rene sayet"},
+{"name": "chad thompson"},
+{"name": "taylor g"},
+{"name": "keith bradach"},
+{"name": "joyce southard"},
+{"name": "henry stanley"},
+{"name": "gina pinto"},
+{"name": "jim nowicki"},
+{"name": "bart kelly"},
+{"name": "bob banner"},
+{"name": "andrea burmeister"},
+{"name": "jason anderson"},
+{"name": "eldon police"},
+{"name": "jimmy renfro"},
+{"name": "aaron gilchrist"},
+{"name": "mary hood"},
+{"name": "curtis jensen"},
+{"name": "tia chiqui"},
+{"name": "rob gaussion"},
+{"name": "cindy wild"},
+{"name": "john tunks"},
+{"name": "tasha swhier"},
+{"name": "ashley colley"},
+{"name": "krista hall"},
+{"name": "ryan abramson"},
+{"name": "blair walker"},
+{"name": "katie ford"},
+{"name": "kathy alyea"},
+{"name": "rachel mitchel"},
+{"name": "elaine cartwright"},
+{"name": "cameron tke"},
+{"name": "chris steakhouse"},
+{"name": "dan soucek"},
+{"name": "juan z"},
+{"name": "stephen kisber"},
+{"name": "neil burkett"},
+{"name": "lauren hunt"},
+{"name": "heather club"},
+{"name": "donna burke"},
+{"name": "jeff slagle"},
+{"name": "bill wamble"},
+{"name": "cornelius robinson"},
+{"name": "chris mahl"},
+{"name": "norman hirsh"},
+{"name": "ginger kim"},
+{"name": "joe rinaldi"},
+{"name": "john ohlson"},
+{"name": "danny desaire"},
+{"name": "joe minster"},
+{"name": "tristan berg"},
+{"name": "mike pryor"},
+{"name": "bianca bernal"},
+{"name": "rick hornung"},
+{"name": "tai pham"},
+{"name": "jillian garcia"},
+{"name": "carlos reyna"},
+{"name": "jeremy foster"},
+{"name": "mike black"},
+{"name": "melissa bartholomew"},
+{"name": "john mckerracher"},
+{"name": "christopher slatter"},
+{"name": "yvonne bartel"},
+{"name": "jeremy ec"},
+{"name": "carol gattinger"},
+{"name": "stephen bek"},
+{"name": "steve jepson"},
+{"name": "celia lee"},
+{"name": "john koeninger"},
+{"name": "kelly write"},
+{"name": "bill watkins"},
+{"name": "miss julie"},
+{"name": "linda michel"},
+{"name": "martin croteau"},
+{"name": "juana walz"},
+{"name": "veronica gonzalez"},
+{"name": "stuart platt"},
+{"name": "ron tubbs"},
+{"name": "theresa mcferrin"},
+{"name": "sybil erden"},
+{"name": "werner linder"},
+{"name": "susan leibowtz"},
+{"name": "sue murrary"},
+{"name": "marina kempton"},
+{"name": "taylor williams"},
+{"name": "kate cafaro"},
+{"name": "alisa bowen"},
+{"name": "joel montelongo"},
+{"name": "gloria burell"},
+{"name": "bryan wier"},
+{"name": "carol abrahamson"},
+{"name": "brooks rowlett"},
+{"name": "jenee george"},
+{"name": "stephanie wyatt"},
+{"name": "spencer grimes"},
+{"name": "stuart roach"},
+{"name": "mary healy"},
+{"name": "janna slagle"},
+{"name": "krista bartholomew"},
+{"name": "curt salvador"},
+{"name": "paula brockenborough"},
+{"name": "vickie packer"},
+{"name": "marvin hannah"},
+{"name": "jennifer tseng"},
+{"name": "brett hampton"},
+{"name": "luis phouse"},
+{"name": "theresa michelson"},
+{"name": "gary kiggins"},
+{"name": "paul crossman"},
+{"name": "dave softball"},
+{"name": "edward gilmore"},
+{"name": "danica stein"},
+{"name": "ashley belline"},
+{"name": "chris morrison"},
+{"name": "nick dasmalchi"},
+{"name": "cheryl toth"},
+{"name": "jeanne peters"},
+{"name": "chris stein"},
+{"name": "john martinsen"},
+{"name": "james kinshasa"},
+{"name": "jason kraizler"},
+{"name": "ricky hidalgo"},
+{"name": "darrel dendy"},
+{"name": "jay manni"},
+{"name": "paul camela"},
+{"name": "greg mccallister"},
+{"name": "rod crosby"},
+{"name": "linda ornelas"},
+{"name": "john gorsuch"},
+{"name": "jill haugh"},
+{"name": "marta crinejo"},
+{"name": "aisha ikramuddin"},
+{"name": "paul dowling"},
+{"name": "johnny r"},
+{"name": "kim long"},
+{"name": "jimmy shows"},
+{"name": "jess hubell"},
+{"name": "audrey kimbrell"},
+{"name": "david slobodetsky"},
+{"name": "bobby shin"},
+{"name": "nina ziefvert"},
+{"name": "joe bruns"},
+{"name": "joe smock"},
+{"name": "gary jarvis"},
+{"name": "joel bramlet"},
+{"name": "rhonda raglinhendrick"},
+{"name": "jody mullins"},
+{"name": "bethany cantrell"},
+{"name": "thomas kuhn"},
+{"name": "rita francis"},
+{"name": "mary quintero"},
+{"name": "chuck meetup"},
+{"name": "paula loeffler"},
+{"name": "doug fisher"},
+{"name": "jason c"},
+{"name": "ashley bff"},
+{"name": "andrea moolenbeek"},
+{"name": "betsy bradt"},
+{"name": "johnson megan"},
+{"name": "bob schuler"},
+{"name": "wendy everett"},
+{"name": "grant canary"},
+{"name": "bill kindle"},
+{"name": "candace herron"},
+{"name": "kendrick mj"},
+{"name": "dave taylor"},
+{"name": "dave moe"},
+{"name": "kathy danley"},
+{"name": "scott cuticchia"},
+{"name": "kelly hsu"},
+{"name": "ian rumley"},
+{"name": "traci arzillo"},
+{"name": "chi phuc"},
+{"name": "angie landes"},
+{"name": "steve aflac"},
+{"name": "marcus purnell"},
+{"name": "rene mejia"},
+{"name": "daniel alick"},
+{"name": "jenny koehl"},
+{"name": "royce maxwell"},
+{"name": "michael ruby"},
+{"name": "chelsea case"},
+{"name": "spring weldon"},
+{"name": "charlie collins"},
+{"name": "pauline steinert"},
+{"name": "mohammad jamal"},
+{"name": "aaron williams"},
+{"name": "vonda lapointe"},
+{"name": "lisa helsel"},
+{"name": "vivian lindsay"},
+{"name": "matt mejstrik"},
+{"name": "kelsey moe"},
+{"name": "wayne darts"},
+{"name": "lori enriquez"},
+{"name": "al roberts"},
+{"name": "kyle d"},
+{"name": "martin mulroy"},
+{"name": "deborah w"},
+{"name": "adam simmons"},
+{"name": "jana straubhar"},
+{"name": "rachel sheffer"},
+{"name": "rick electronics"},
+{"name": "nikki church"},
+{"name": "kelly harris"},
+{"name": "michelle hartman"},
+{"name": "mark schwartz"},
+{"name": "chuck wiebe"},
+{"name": "marsha schattner"},
+{"name": "rebecca meetup"},
+{"name": "miles french"},
+{"name": "steve doherty"},
+{"name": "lawrence maxham"},
+{"name": "carol butters"},
+{"name": "roger link"},
+{"name": "matthew david"},
+{"name": "ali farhat"},
+{"name": "darrin brockenborough"},
+{"name": "tracey williams"},
+{"name": "marisela prieto"},
+{"name": "laurie w"},
+{"name": "josh cain"},
+{"name": "carolina korth"},
+{"name": "cathy duvall"},
+{"name": "kevin caldwell"},
+{"name": "beth neville"},
+{"name": "zack greenberg"},
+{"name": "rick srickirjarn"},
+{"name": "jennifer bisnauth"},
+{"name": "warren pope"},
+{"name": "gayle price"},
+{"name": "ellen shafer"},
+{"name": "everett mckeehan"},
+{"name": "brad rye"},
+{"name": "joslyn harmonson"},
+{"name": "willie george"},
+{"name": "anita mike"},
+{"name": "jim vavra"},
+{"name": "mike zavaleta"},
+{"name": "alex rodriguez"},
+{"name": "ben habte"},
+{"name": "henrietta becker"},
+{"name": "helen dzambazov"},
+{"name": "paul riggs"},
+{"name": "bernadette andy"},
+{"name": "harriette olsen"},
+{"name": "keith snyder"},
+{"name": "ken cert"},
+{"name": "veronica kemp"},
+{"name": "amanda montoy"},
+{"name": "christy pierce"},
+{"name": "ryan elwart"},
+{"name": "eric studio"},
+{"name": "andrew fios"},
+{"name": "maria gomez"},
+{"name": "mario radcliffe"},
+{"name": "john johnso"},
+{"name": "jonathan smithson"},
+{"name": "deidre brown"},
+{"name": "mike ling"},
+{"name": "terry nazareth"},
+{"name": "elise dallimore"},
+{"name": "sterling roberts"},
+{"name": "natalie stern"},
+{"name": "joshua baumgartner"},
+{"name": "kevin white"},
+{"name": "carly babe"},
+{"name": "linda gainsboro"},
+{"name": "marci stracener"},
+{"name": "robin pelton"},
+{"name": "tom weltzien"},
+{"name": "jerry wagner"},
+{"name": "scott modell"},
+{"name": "joe polanco"},
+{"name": "jerry gonzalez"},
+{"name": "david wurcel"},
+{"name": "nancy manriquez"},
+{"name": "chris gorman"},
+{"name": "kenya jones"},
+{"name": "roberta willis"},
+{"name": "glenn bermejo"},
+{"name": "jenny morrison"},
+{"name": "ted ryback"},
+{"name": "rosalie ip"},
+{"name": "chris macdougall"},
+{"name": "chuck christianson"},
+{"name": "james merchant"},
+{"name": "ken mazur"},
+{"name": "jordan davis"},
+{"name": "patti wallner"},
+{"name": "aaron older"},
+{"name": "diane sluka"},
+{"name": "willy tadekawa"},
+{"name": "nick hopper"},
+{"name": "lorrie drotts"},
+{"name": "brandon day"},
+{"name": "ryan garrison"},
+{"name": "paul chambre"},
+{"name": "noah sanchez"},
+{"name": "bart pruett"},
+{"name": "jeff brady"},
+{"name": "michael jordan"},
+{"name": "candice douglas"},
+{"name": "katie peacock"},
+{"name": "mark young"},
+{"name": "martin bryant"},
+{"name": "mary mcgary"},
+{"name": "john louf"},
+{"name": "ann helmers"},
+{"name": "jake sp"},
+{"name": "raul cruz"},
+{"name": "gary stanley"},
+{"name": "barry meyer"},
+{"name": "jay boy"},
+{"name": "tia lila"},
+{"name": "joy dun"},
+{"name": "joann digirolomo"},
+{"name": "jon deegler"},
+{"name": "joel fama"},
+{"name": "jay rhone"},
+{"name": "beth cosko"},
+{"name": "bradley basista"},
+{"name": "adam mermel"},
+{"name": "krystal devine"},
+{"name": "micah hendricks"},
+{"name": "leslie harris"},
+{"name": "mary clark"},
+{"name": "john wolcott"},
+{"name": "jessica ngyuen"},
+{"name": "marshall black"},
+{"name": "james melvin"},
+{"name": "dennis laughlin"},
+{"name": "stacy daisy"},
+{"name": "jason lamb"},
+{"name": "omar zavalza"},
+{"name": "joshua volinsky"},
+{"name": "peter knapp"},
+{"name": "herbert l"},
+{"name": "alex perifoy"},
+{"name": "paul o'neill"},
+{"name": "doug fresh"},
+{"name": "ericka c"},
+{"name": "dennis littlejohn"},
+{"name": "jeri johnson"},
+{"name": "mike matusz"},
+{"name": "david kong"},
+{"name": "matt cali"},
+{"name": "isaiah ford"},
+{"name": "dave celone"},
+{"name": "todd batchelor"},
+{"name": "megan huff"},
+{"name": "alex hahn"},
+{"name": "melanie holst"},
+{"name": "richard harms"},
+{"name": "steve baker"},
+{"name": "sarah burns"},
+{"name": "marvin torrez"},
+{"name": "lisa wren"},
+{"name": "maryanne zahn"},
+{"name": "robby tweater"},
+{"name": "scott hump"},
+{"name": "karen m"},
+{"name": "lori magby"},
+{"name": "james mckellar"},
+{"name": "ken matheson"},
+{"name": "joy branch"},
+{"name": "kirk parker"},
+{"name": "paul frances"},
+{"name": "libby kot"},
+{"name": "tim carter"},
+{"name": "brian covington"},
+{"name": "ken phebus"},
+{"name": "ernie goddard"},
+{"name": "ed mccloud"},
+{"name": "jack tipton"},
+{"name": "ali roos"},
+{"name": "sasha msklnko"},
+{"name": "gerald wesel"},
+{"name": "cheryl rude"},
+{"name": "clair biggins"},
+{"name": "mandy panasuk"},
+{"name": "ilene xxxxx"},
+{"name": "ciera moore"},
+{"name": "james so"},
+{"name": "ted collier"},
+{"name": "bob bleazner"},
+{"name": "paul jung"},
+{"name": "leslie minick"},
+{"name": "megan mariero"},
+{"name": "cody s"},
+{"name": "renee burse"},
+{"name": "jim kersey"},
+{"name": "tim bertoldi"},
+{"name": "peggy norton"},
+{"name": "felipe escamilla"},
+{"name": "loretta fung"},
+{"name": "andy luvisi"},
+{"name": "del sheils"},
+{"name": "tiffany sherlock"},
+{"name": "nick murreitta"},
+{"name": "tim hruza"},
+{"name": "bill mahoney"},
+{"name": "derrick gregory"},
+{"name": "kathy mekhayel"},
+{"name": "jay agosto"},
+{"name": "edwin vernon"},
+{"name": "daphine collier"},
+{"name": "karen meade"},
+{"name": "dorothy landes"},
+{"name": "joyce lin"},
+{"name": "bernie garcia"},
+{"name": "tyler rundel"},
+{"name": "alvin nuan"},
+{"name": "lisa comallotta"},
+{"name": "mike mitche"},
+{"name": "mark kaustinen"},
+{"name": "brad billiet"},
+{"name": "louis skelton"},
+{"name": "rick khan"},
+{"name": "kevin wu"},
+{"name": "agnes lin"},
+{"name": "serena mcgaha"},
+{"name": "george sullivan"},
+{"name": "ken tmobile"},
+{"name": "niki haris"},
+{"name": "eric hjerpe"},
+{"name": "stanley tech"},
+{"name": "mary sparks"},
+{"name": "stephanie t"},
+{"name": "dick hutchinson"},
+{"name": "chris cardello"},
+{"name": "steven larson"},
+{"name": "cassie wk"},
+{"name": "christine slopey"},
+{"name": "mallory haney"},
+{"name": "taylor black"},
+{"name": "joan macdonald"},
+{"name": "diana tourek"},
+{"name": "tommy thomson"},
+{"name": "katie brelsford"},
+{"name": "stewart clark"},
+{"name": "lindsay dowell"},
+{"name": "alan phlipot"},
+{"name": "charles garrison"},
+{"name": "peggy krause"},
+{"name": "rhonda cell"},
+{"name": "joel wheeler"},
+{"name": "robert arden"},
+{"name": "angela peachey"},
+{"name": "larry deguzman"},
+{"name": "kathy thomas"},
+{"name": "charles collins"},
+{"name": "greg mohler"},
+{"name": "greg tatko"},
+{"name": "lu cell"},
+{"name": "sara minor"},
+{"name": "beth hastings"},
+{"name": "jared sarfaty"},
+{"name": "sheri weigers"},
+{"name": "scottie deville"},
+{"name": "william harsey"},
+{"name": "rigoberto zavala"},
+{"name": "beth trumble"},
+{"name": "scott unger"},
+{"name": "marcus client"},
+{"name": "jeff aoki"},
+{"name": "maria tornez"},
+{"name": "eric kolodin"},
+{"name": "justin cecs"},
+{"name": "john barnhart"},
+{"name": "lindsay morine"},
+{"name": "nick pafico"},
+{"name": "steve rubenstein"},
+{"name": "reid schneider"},
+{"name": "carlton lewis"},
+{"name": "michele bianche"},
+{"name": "karla santi"},
+{"name": "julian sony"},
+{"name": "jason walker"},
+{"name": "charles home"},
+{"name": "dwayne cole"},
+{"name": "andrea loza"},
+{"name": "rick herman"},
+{"name": "gus bender"},
+{"name": "sara fliess"},
+{"name": "erik farley"},
+{"name": "steve czario"},
+{"name": "sharon file"},
+{"name": "howard hospital"},
+{"name": "brian branagan"},
+{"name": "bill blink"},
+{"name": "chris segal"},
+{"name": "martin lasher"},
+{"name": "nancy kummer"},
+{"name": "jonathan ezontheeyez"},
+{"name": "brian cochr"},
+{"name": "gary null"},
+{"name": "mike mitcher"},
+{"name": "victor hicks"},
+{"name": "mike couture"},
+{"name": "lewis uyeke"},
+{"name": "ricky carter"},
+{"name": "dave voss"},
+{"name": "grant vreeland"},
+{"name": "bill darnell"},
+{"name": "stormy martin"},
+{"name": "brian darty"},
+{"name": "tommy walters"},
+{"name": "cathy creswell"},
+{"name": "tisha hardy"},
+{"name": "phillip wu"},
+{"name": "mike pasilaban"},
+{"name": "liz kenny"},
+{"name": "justin sball"},
+{"name": "felix ilwu"},
+{"name": "jeff shelton"},
+{"name": "james evers"},
+{"name": "mike cloud"},
+{"name": "travis anderson"},
+{"name": "stacy mandrell"},
+{"name": "steve ranson"},
+{"name": "maryanne yenoli"},
+{"name": "nicole shows"},
+{"name": "patrick mcpherson"},
+{"name": "dean kyriakos"},
+{"name": "laura koklamanis"},
+{"name": "austin home"},
+{"name": "gary carter"},
+{"name": "randy gonzalez"},
+{"name": "luis ramous"},
+{"name": "theresa roberts"},
+{"name": "bobby caffiero"},
+{"name": "paul power"},
+{"name": "randy morrell"},
+{"name": "jill shafer"},
+{"name": "jim applegate"},
+{"name": "nicole meoli"},
+{"name": "laura mcdonald"},
+{"name": "brian towles"},
+{"name": "mark chauvin"},
+{"name": "alfredo yanes"},
+{"name": "lorna holmstead"},
+{"name": "charlie johnson"},
+{"name": "jim desigio"},
+{"name": "brian fuel"},
+{"name": "carrie paulus"},
+{"name": "emerson salcedo"},
+{"name": "wallace wessel"},
+{"name": "angie couzin"},
+{"name": "mark south"},
+{"name": "billy pollock"},
+{"name": "christy everhart"},
+{"name": "greg craft"},
+{"name": "keira bentley"},
+{"name": "ellen drake"},
+{"name": "judy engel"},
+{"name": "nancy cahill"},
+{"name": "heather cockson"},
+{"name": "marco mancini"},
+{"name": "randy lange"},
+{"name": "lynn gertsch"},
+{"name": "mike paz"},
+{"name": "pamela means"},
+{"name": "april hardee"},
+{"name": "russell lee"},
+{"name": "noma sushi"},
+{"name": "marcus goodman"},
+{"name": "jared lilly"},
+{"name": "greg apple"},
+{"name": "shawn kittleson"},
+{"name": "jamie hawkins"},
+{"name": "cheryl moorman"},
+{"name": "penny halvorsen"},
+{"name": "phil benson"},
+{"name": "tony saranita"},
+{"name": "william harris"},
+{"name": "jordan camps"},
+{"name": "jeff hd"},
+{"name": "steven stilson"},
+{"name": "doug moore"},
+{"name": "nick green"},
+{"name": "carolina t"},
+{"name": "victoria winters"},
+{"name": "chris abby"},
+{"name": "dave baquerizo"},
+{"name": "gregory jean"},
+{"name": "brett hartley"},
+{"name": "sondra nelson"},
+{"name": "jan leonard"},
+{"name": "dolly mathis"},
+{"name": "greg jons"},
+{"name": "ed justice"},
+{"name": "leatha revels"},
+{"name": "drew reposar"},
+{"name": "mark killick"},
+{"name": "sona mirzaian"},
+{"name": "chris brito"},
+{"name": "barbara jordan"},
+{"name": "stephanie stowe"},
+{"name": "ken marks"},
+{"name": "dave ferguson"},
+{"name": "ben c"},
+{"name": "roger ray"},
+{"name": "jill fuller"},
+{"name": "julie shama"},
+{"name": "melinda leblanc"},
+{"name": "andy gasbarro"},
+{"name": "thomas sullivan"},
+{"name": "cara welch"},
+{"name": "josh miles"},
+{"name": "kevin masters"},
+{"name": "teri erbe"},
+{"name": "marilyn son"},
+{"name": "carey cell"},
+{"name": "eric thompson"},
+{"name": "johnny bell"},
+{"name": "chance propps"},
+{"name": "sherry sim"},
+{"name": "walker church"},
+{"name": "david finger"},
+{"name": "michele peoples"},
+{"name": "phil griffith"},
+{"name": "shaun mcghen"},
+{"name": "evelyn weatherford"},
+{"name": "ed streit"},
+{"name": "jamie grundstrom"},
+{"name": "rich felbinger"},
+{"name": "adam ziraks"},
+{"name": "blake cameron"},
+{"name": "mark dinerstein"},
+{"name": "robert sanches"},
+{"name": "tim strazzo"},
+{"name": "bob goodman"},
+{"name": "mary abarca"},
+{"name": "brent kovach"},
+{"name": "johnnie blanks"},
+{"name": "sally martin"},
+{"name": "heidi herschede"},
+{"name": "deanna johnson"},
+{"name": "ernie hernandez"},
+{"name": "beverley grant"},
+{"name": "joseph wagness"},
+{"name": "matthew moschetti"},
+{"name": "chad convis"},
+{"name": "kim dd"},
+{"name": "jessie demille"},
+{"name": "isaac trumbo"},
+{"name": "sean young"},
+{"name": "gina roe"},
+{"name": "kevin klutz"},
+{"name": "lisa samuel"},
+{"name": "joe longo"},
+{"name": "jose luis"},
+{"name": "carly bistro"},
+{"name": "kim sponza"},
+{"name": "stormy cocks"},
+{"name": "brittany jordan"},
+{"name": "karen moore"},
+{"name": "hugo galvez"},
+{"name": "zack gilbreath"},
+{"name": "gabriel urias"},
+{"name": "scott kilvecki"},
+{"name": "nikki wilson"},
+{"name": "matt larson"},
+{"name": "lisa ledesma"},
+{"name": "rob gragg"},
+{"name": "zack rodlen"},
+{"name": "jennifer freeman"},
+{"name": "nancy owens"},
+{"name": "danny farkas"},
+{"name": "jeff brauer"},
+{"name": "clint pollock"},
+{"name": "bryan atkins"},
+{"name": "sun trust"},
+{"name": "audra sein"},
+{"name": "sarah belcher"},
+{"name": "tom chamblee"},
+{"name": "hugh garrison"},
+{"name": "mike knori"},
+{"name": "john giordano"},
+{"name": "sunday mom"},
+{"name": "sarita sanders"},
+{"name": "julie talley"},
+{"name": "tamara casey"},
+{"name": "michael milw"},
+{"name": "diane guiterrez"},
+{"name": "brian mckathrine"},
+{"name": "agnes kwok"},
+{"name": "tamara coleman"},
+{"name": "craig sherrod"},
+{"name": "blake moselle"},
+{"name": "john mccomber"},
+{"name": "george patterson"},
+{"name": "bob sully"},
+{"name": "brent faulk"},
+{"name": "callie johnson"},
+{"name": "matthew getz"},
+{"name": "lori abram"},
+{"name": "lee callahan"},
+{"name": "will nunnery"},
+{"name": "peter mauch"},
+{"name": "david shimkus"},
+{"name": "barry replogle"},
+{"name": "kim papageorge"},
+{"name": "ken mason"},
+{"name": "erica arns"},
+{"name": "jackie adams"},
+{"name": "mark knickrehm"},
+{"name": "nick chaconas"},
+{"name": "eric beelar"},
+{"name": "kevin mccoy"},
+{"name": "john packard"},
+{"name": "sean danforth"},
+{"name": "bill coibion"},
+{"name": "dan alexander"},
+{"name": "cody tcg"},
+{"name": "steve montgomery"},
+{"name": "mindy t"},
+{"name": "darrell macleod"},
+{"name": "david shewbridge"},
+{"name": "jim stieb"},
+{"name": "mike tork"},
+{"name": "laura wilburn"},
+{"name": "armando corral"},
+{"name": "john hobbie"},
+{"name": "debbie hanson"},
+{"name": "brian white"},
+{"name": "tom morran"},
+{"name": "tom corn"},
+{"name": "jake brownback"},
+{"name": "joe hangininknob"},
+{"name": "carolyn syversen"},
+{"name": "chuck curry"},
+{"name": "brian dean"},
+{"name": "vanessa corchado"},
+{"name": "shirley brockenborough"},
+{"name": "jennifer lane"},
+{"name": "ken hadley"},
+{"name": "erin kever"},
+{"name": "dan loher"},
+{"name": "doug mcvey"},
+{"name": "max levenstein"},
+{"name": "tom grosskopf"},
+{"name": "kayla mckenziee"},
+{"name": "jill collins"},
+{"name": "james rosedahl"},
+{"name": "brook atcons"},
+{"name": "aurora ritter"},
+{"name": "tom byrd"},
+{"name": "thomas casey"},
+{"name": "cesar martinez"},
+{"name": "abbie vaughn"},
+{"name": "matt daniels"},
+{"name": "ashleigh bricker"},
+{"name": "ken g"},
+{"name": "tommy snyder"},
+{"name": "amy michel"},
+{"name": "ryan adair"},
+{"name": "joe garza"},
+{"name": "ryan philly"},
+{"name": "greg miller"},
+{"name": "brandon marchioni"},
+{"name": "bob campbell"},
+{"name": "michael watts"},
+{"name": "kevin leon"},
+{"name": "jason bunch"},
+{"name": "kirk rhoton"},
+{"name": "evan grasse"},
+{"name": "jane seymore"},
+{"name": "curtis office"},
+{"name": "elizabeth vago"},
+{"name": "joe schlabach"},
+{"name": "cindy austraila"},
+{"name": "madison sanders"},
+{"name": "matt greene"},
+{"name": "andrea johnston"},
+{"name": "chris tiff"},
+{"name": "wayne owens"},
+{"name": "deborah garcia"},
+{"name": "jeff wexler"},
+{"name": "lawrence sanchez"},
+{"name": "monique torrez"},
+{"name": "cindy daily"},
+{"name": "maurice jones"},
+{"name": "jim cain"},
+{"name": "mae adams"},
+{"name": "jim lambreact"},
+{"name": "marguerite lowenhal"},
+{"name": "claudia gilbert"},
+{"name": "tom butowicz"},
+{"name": "britney wofford"},
+{"name": "marc robitaille"},
+{"name": "jerry cuellar"},
+{"name": "jo ferguson"},
+{"name": "tanya baldridge"},
+{"name": "jeff dad"},
+{"name": "sonja demuth"},
+{"name": "richard sugar"},
+{"name": "kim sheridan"},
+{"name": "julie beck"},
+{"name": "ben slota"},
+{"name": "jacob work"},
+{"name": "hollie nosworthy"},
+{"name": "susan jungkeit"},
+{"name": "liz jacques"},
+{"name": "anna gary"},
+{"name": "lisa coach"},
+{"name": "jim goldkamp"},
+{"name": "manuel andazola"},
+{"name": "mike roach"},
+{"name": "pat siegner"},
+{"name": "johnny ledesna"},
+{"name": "jennifer carson"},
+{"name": "gary grund"},
+{"name": "deeann reese"},
+{"name": "charmaine bautista"},
+{"name": "dave seigworth"},
+{"name": "monica lardis"},
+{"name": "randy miles"},
+{"name": "sonia bustamante"},
+{"name": "brandy wofford"},
+{"name": "chris lamaster"},
+{"name": "cole home"},
+{"name": "david blinn"},
+{"name": "andy serrao"},
+{"name": "julie heck"},
+{"name": "danny gaultierri"},
+{"name": "justin turrell"},
+{"name": "jake m"},
+{"name": "julie sumler"},
+{"name": "landon thompson"},
+{"name": "kevin fetter"},
+{"name": "bill boyd"},
+{"name": "anna may"},
+{"name": "danny conte"},
+{"name": "helen tran"},
+{"name": "alexandra welch"},
+{"name": "dena belfanti"},
+{"name": "clinton fu"},
+{"name": "victor coggi"},
+{"name": "bella spa"},
+{"name": "violeta cuz"},
+{"name": "elliott skrinjar"},
+{"name": "william long"},
+{"name": "david lieber"},
+{"name": "anne beving"},
+{"name": "lynne ritucci"},
+{"name": "tony garza"},
+{"name": "todd sines"},
+{"name": "michelle smith"},
+{"name": "von behren"},
+{"name": "cecilia almeida"},
+{"name": "antonio dimizio"},
+{"name": "grazyna kabat"},
+{"name": "matt silaff"},
+{"name": "michael lazo"},
+{"name": "tony perez"},
+{"name": "sam pina"},
+{"name": "ron stubbs"},
+{"name": "kelly o'neil"},
+{"name": "shawn hazlett"},
+{"name": "joe herring"},
+{"name": "mike dunn"},
+{"name": "tom dundon"},
+{"name": "doug frye"},
+{"name": "ray howel"},
+{"name": "samantha reali"},
+{"name": "scott hartestien"},
+{"name": "gerry menger"},
+{"name": "isabelle masse"},
+{"name": "jason barth"},
+{"name": "dani benmoshi"},
+{"name": "donna sparks"},
+{"name": "micheal diaz"},
+{"name": "scott wiscombe"},
+{"name": "dan fuson"},
+{"name": "stephanie andrews"},
+{"name": "joseph sam"},
+{"name": "bob carrillo"},
+{"name": "mike vallejo"},
+{"name": "crystal nguyen"},
+{"name": "harold jones"},
+{"name": "erica sheehan"},
+{"name": "michael metzger"},
+{"name": "jewel davidson"},
+{"name": "kay widmer"},
+{"name": "jessie wallace"},
+{"name": "bob verdue"},
+{"name": "walter kuemmerle"},
+{"name": "jonathan bridge"},
+{"name": "tim albritton"},
+{"name": "jenny gary"},
+{"name": "andrea blehm"},
+{"name": "joshua joseph"},
+{"name": "scot chastain"},
+{"name": "laura mcalister"},
+{"name": "lanny erickson"},
+{"name": "howard glover"},
+{"name": "mary laumer"},
+{"name": "matt milne"},
+{"name": "craig wen"},
+{"name": "kent krueger"},
+{"name": "david yarnell"},
+{"name": "christina riley"},
+{"name": "anita dha"},
+{"name": "lee lawson"},
+{"name": "derek hinton"},
+{"name": "jim strong"},
+{"name": "chris word"},
+{"name": "nick english"},
+{"name": "marcos charro"},
+{"name": "paul yang"},
+{"name": "jacki congdon"},
+{"name": "mike abt"},
+{"name": "chelsea sphor"},
+{"name": "barney pell"},
+{"name": "dave fms"},
+{"name": "bob store"},
+{"name": "joey byers"},
+{"name": "john herr"},
+{"name": "phil jerrels"},
+{"name": "gina morgan"},
+{"name": "leslie gryce"},
+{"name": "laura t"},
+{"name": "marlene arsenian"},
+{"name": "tasha hogroe"},
+{"name": "david latz"},
+{"name": "paul still"},
+{"name": "wes wheless"},
+{"name": "dennis rose"},
+{"name": "rick wright"},
+{"name": "jay chavez"},
+{"name": "carl valentine"},
+{"name": "david grenland"},
+{"name": "aaron morse"},
+{"name": "samantha salas"},
+{"name": "susan f"},
+{"name": "lisa mendez"},
+{"name": "samuel sahn"},
+{"name": "jason acoard"},
+{"name": "ashley ricks"},
+{"name": "johnny xbox"},
+{"name": "tim booras"},
+{"name": "anthony marino"},
+{"name": "kelly danahy"},
+{"name": "eddie mccolloug"},
+{"name": "joe duhaime"},
+{"name": "sylvie lavoie"},
+{"name": "lincoln poultry"},
+{"name": "dee chapel"},
+{"name": "rita fung"},
+{"name": "adam juda"},
+{"name": "terry allred"},
+{"name": "margot staplin"},
+{"name": "jeffrey yoshimine"},
+{"name": "mac mobile"},
+{"name": "dan neuwirth"},
+{"name": "amanda habiger"},
+{"name": "james sinclair"},
+{"name": "linda hayes"},
+{"name": "edwin grant"},
+{"name": "erin lipple"},
+{"name": "erica stevens"},
+{"name": "wallace sharon"},
+{"name": "greg wordowski"},
+{"name": "christopher key"},
+{"name": "shelley goodwin"},
+{"name": "jess pott"},
+{"name": "katie mcnutt"},
+{"name": "candice brown"},
+{"name": "trevor bryan"},
+{"name": "seth garner"},
+{"name": "marcia salkeld"},
+{"name": "dane dui"},
+{"name": "casey walker"},
+{"name": "jerry levey"},
+{"name": "tiffany phelps"},
+{"name": "joseph schneider"},
+{"name": "amber nerhus"},
+{"name": "jessica autrey"},
+{"name": "william rakoczy"},
+{"name": "omer home"},
+{"name": "erica knox"},
+{"name": "lauren mcmann"},
+{"name": "holly gangl"},
+{"name": "michael doyle"},
+{"name": "karen perkins"},
+{"name": "ross cunningham"},
+{"name": "dan coyne"},
+{"name": "jack cuthbert"},
+{"name": "mack hiyasat"},
+{"name": "dennis poppe"},
+{"name": "reva wadsworth"},
+{"name": "jeffrey crawford"},
+{"name": "ed martin"},
+{"name": "tammy stansbury"},
+{"name": "roy payne"},
+{"name": "mary love"},
+{"name": "deana hale"},
+{"name": "mel thompson"},
+{"name": "ashley campbell"},
+{"name": "julie curiel"},
+{"name": "delphine ndongmoh"},
+{"name": "dennis gonzalez"},
+{"name": "clark nelson"},
+{"name": "robert casillas"},
+{"name": "bart smith"},
+{"name": "ray nelson"},
+{"name": "darryl cragun"},
+{"name": "brandon thall"},
+{"name": "neely sessions"},
+{"name": "mike demetriou"},
+{"name": "alexis ames"},
+{"name": "barbara barnes"},
+{"name": "cheryl belisarius"},
+{"name": "tony nigro"},
+{"name": "ashley topic"},
+{"name": "jessica gordon"},
+{"name": "marshall young"},
+{"name": "jordan suh"},
+{"name": "gail toti"},
+{"name": "courtney ryan"},
+{"name": "cheryl jablonski"},
+{"name": "russ maughan"},
+{"name": "stacy sullivan"},
+{"name": "sabrina venskus"},
+{"name": "ben carlson"},
+{"name": "trish shaffstall"},
+{"name": "linda gutkind"},
+{"name": "ray reaume"},
+{"name": "mike pilkinton"},
+{"name": "don james"},
+{"name": "santos ray"},
+{"name": "william bryant"},
+{"name": "jillian bozart"},
+{"name": "roger o"},
+{"name": "nicolas bouchard"},
+{"name": "robert gonzalez"},
+{"name": "harley davison"},
+{"name": "virginia walker"},
+{"name": "jody renny"},
+{"name": "brad pastrami"},
+{"name": "jason fowler"},
+{"name": "ken anabeza"},
+{"name": "travis ocanas"},
+{"name": "mike rusche"},
+{"name": "gloria stingily"},
+{"name": "sierra shorter"},
+{"name": "justin robins"},
+{"name": "lori woods"},
+{"name": "jody sigmund"},
+{"name": "marc gauldrault"},
+{"name": "max hall"},
+{"name": "jim mills"},
+{"name": "jeff futch"},
+{"name": "laveta johnson"},
+{"name": "dustin schlakeness"},
+{"name": "rudy penteado"},
+{"name": "lori sotomayor"},
+{"name": "pat madden"},
+{"name": "brian schirmer"},
+{"name": "olive garden"},
+{"name": "justin jennings"},
+{"name": "carmen deleon"},
+{"name": "susan brock"},
+{"name": "chris rogers"},
+{"name": "jim faulk"},
+{"name": "diane ethan"},
+{"name": "angel serra"},
+{"name": "chris pentico"},
+{"name": "johnny a"},
+{"name": "rebecca short"},
+{"name": "mike jonikas"},
+{"name": "jason depue"},
+{"name": "ben baker"},
+{"name": "sandy khaund"},
+{"name": "cory loper"},
+{"name": "mary cruz"},
+{"name": "john harrel"},
+{"name": "brock williams"},
+{"name": "hailey williams"},
+{"name": "scott fowler"},
+{"name": "michelle cougar"},
+{"name": "rick dow"},
+{"name": "john ashley"},
+{"name": "pat read"},
+{"name": "bob manning"},
+{"name": "tim viole"},
+{"name": "vanessa vantage"},
+{"name": "carlos martinez"},
+{"name": "norma moreno"},
+{"name": "van harlow"},
+{"name": "moshe segal"},
+{"name": "angela metcalf"},
+{"name": "trinity wiring"},
+{"name": "quinn sivage"},
+{"name": "alysa webb"},
+{"name": "brady tke"},
+{"name": "jeff furman"},
+{"name": "ellis breeden"},
+{"name": "kristi gibbs"},
+{"name": "laura f"},
+{"name": "danny dorn"},
+{"name": "mike mejia"},
+{"name": "kim soteros"},
+{"name": "sarah rosenwinkel"},
+{"name": "craig perry"},
+{"name": "dave garrison"},
+{"name": "brian langum"},
+{"name": "pam cleveland"},
+{"name": "elizabeth kempski"},
+{"name": "harrison lee"},
+{"name": "dan tran"},
+{"name": "chet kuryliw"},
+{"name": "laurie dunn"},
+{"name": "mike rapetti"},
+{"name": "kelly services"},
+{"name": "mike indy"},
+{"name": "jamie spainhower"},
+{"name": "rich sandoval"},
+{"name": "joe jennings"},
+{"name": "rusty bucket"},
+{"name": "king food"},
+{"name": "elaine conzett"},
+{"name": "larry henry"},
+{"name": "kenneth pratt"},
+{"name": "howard finkle"},
+{"name": "van langen"},
+{"name": "ken frigerio"},
+{"name": "sean john"},
+{"name": "george atl"},
+{"name": "anne legrand"},
+{"name": "ross galin"},
+{"name": "jay beane"},
+{"name": "tonya twitchell"},
+{"name": "harry lim"},
+{"name": "colleen dettore"},
+{"name": "michelle berger"},
+{"name": "steve sheehan"},
+{"name": "jeff highlander"},
+{"name": "chris larsen"},
+{"name": "anne aamland"},
+{"name": "elizabeth hilfiger"},
+{"name": "les ransom"},
+{"name": "michelle fendrich"},
+{"name": "tim halteren"},
+{"name": "li miaw"},
+{"name": "salome julien"},
+{"name": "nelson joe"},
+{"name": "roland snow"},
+{"name": "mike cochrane"},
+{"name": "janet kraus"},
+{"name": "ashlie wilson"},
+{"name": "alisha sutton"},
+{"name": "george boka"},
+{"name": "yvonne owen"},
+{"name": "tom stiller"},
+{"name": "jason hart"},
+{"name": "dave woodbridge"},
+{"name": "jennifer bumstead"},
+{"name": "ann ackley"},
+{"name": "lauren freeman"},
+{"name": "john dublin"},
+{"name": "bruce scheer"},
+{"name": "jessica dalton"},
+{"name": "marina home"},
+{"name": "jack milheiras"},
+{"name": "matt harrison"},
+{"name": "henry ho"},
+{"name": "lupe tarasiewicz"},
+{"name": "norman teitelbaum"},
+{"name": "shawn shugrue"},
+{"name": "michael olatuja"},
+{"name": "ashley mo"},
+{"name": "don asay"},
+{"name": "scott pelton"},
+{"name": "glen andrade"},
+{"name": "sydney young"},
+{"name": "allen work"},
+{"name": "tim woo"},
+{"name": "jasmin work"},
+{"name": "mercedes rice"},
+{"name": "mike mechanic"},
+{"name": "christina tran"},
+{"name": "alex groves"},
+{"name": "bobby clark"},
+{"name": "sarah dixey"},
+{"name": "craig lopresto"},
+{"name": "mike fetterman"},
+{"name": "david chima"},
+{"name": "mark jacobstein"},
+{"name": "larry rabiner"},
+{"name": "chris dudley"},
+{"name": "glenn libby"},
+{"name": "jorge vargas"},
+{"name": "brian andrews"},
+{"name": "kristen hersett"},
+{"name": "jacque tax"},
+{"name": "sam owens"},
+{"name": "michelle deichler"},
+{"name": "ann clegg"},
+{"name": "billie jo"},
+{"name": "brian quattlebaum"},
+{"name": "ricky home"},
+{"name": "ronald lefton"},
+{"name": "ray baldwin"},
+{"name": "jon coronado"},
+{"name": "jen nie"},
+{"name": "eduardo vargas"},
+{"name": "victor reuss"},
+{"name": "bill boehn"},
+{"name": "marc resnick"},
+{"name": "tiffany street"},
+{"name": "douglas wallace"},
+{"name": "dustin korth"},
+{"name": "mark white"},
+{"name": "laura stiefle"},
+{"name": "carlos cordero"},
+{"name": "julie horobec"},
+{"name": "elyse rabb"},
+{"name": "jennifer bixler"},
+{"name": "amanda towner"},
+{"name": "rory snipes"},
+{"name": "dan wu"},
+{"name": "brian mealey"},
+{"name": "antonio dolar"},
+{"name": "anne edwards"},
+{"name": "ellen whelan"},
+{"name": "angelo paglione"},
+{"name": "philip strathy"},
+{"name": "sonja matson"},
+{"name": "greg wheeler"},
+{"name": "christy coston"},
+{"name": "celia wing"},
+{"name": "elizabeth altman"},
+{"name": "mary obrien"},
+{"name": "roy jackson"},
+{"name": "murray wakeboard"},
+{"name": "ron desilva"},
+{"name": "buster do's"},
+{"name": "michelle desanctus"},
+{"name": "jerry reuter"},
+{"name": "julia turner"},
+{"name": "sandy altman"},
+{"name": "jeff weidler"},
+{"name": "jillian sidoti"},
+{"name": "lou stoecklin"},
+{"name": "brian jurus"},
+{"name": "will sales"},
+{"name": "ron wangllin"},
+{"name": "matt church"},
+{"name": "charlie whitman"},
+{"name": "jonas brodie"},
+{"name": "ellis peters"},
+{"name": "rob kunin"},
+{"name": "alicia fillmore"},
+{"name": "mimi munoz"},
+{"name": "luke ogdan"},
+{"name": "marcia rust"},
+{"name": "ben mckissack"},
+{"name": "mike computer"},
+{"name": "randy ganiban"},
+{"name": "andre picou"},
+{"name": "marc modry"},
+{"name": "denise harvill"},
+{"name": "steven hughes"},
+{"name": "emily kallal"},
+{"name": "gregg densmore"},
+{"name": "andre jr"},
+{"name": "mary l"},
+{"name": "jeff cranstan"},
+{"name": "jon joslow"},
+{"name": "jenny lin"},
+{"name": "sharon hart"},
+{"name": "jim wilcox"},
+{"name": "diane dillard"},
+{"name": "marie pfeifer"},
+{"name": "daniel allio"},
+{"name": "josh molello"},
+{"name": "elise goldberg"},
+{"name": "todd locker"},
+{"name": "maria sanabria"},
+{"name": "todd benton"},
+{"name": "roderick harvey"},
+{"name": "jordan kvernevig"},
+{"name": "rebecca burgess"},
+{"name": "jonathan dearmont"},
+{"name": "harry davies"},
+{"name": "jeff boyd"},
+{"name": "ray stuart"},
+{"name": "lee kapaloski"},
+{"name": "ken ruttenburg"},
+{"name": "annie buck"},
+{"name": "amy hamilton"},
+{"name": "kelly christensen"},
+{"name": "katie gingrass"},
+{"name": "jimmy fallen"},
+{"name": "glenda tollman"},
+{"name": "marco papatheo"},
+{"name": "john bertsche"},
+{"name": "rebecca simmons"},
+{"name": "stuart gina"},
+{"name": "matt princing"},
+{"name": "elizabeth shank"},
+{"name": "abel brovo"},
+{"name": "angela olander"},
+{"name": "dee az"},
+{"name": "pablo antuna"},
+{"name": "jen carion"},
+{"name": "derek eck"},
+{"name": "mark giosso"},
+{"name": "jim seier"},
+{"name": "caroline caylor"},
+{"name": "shannon troyer"},
+{"name": "steven jones"},
+{"name": "debbie scanga"},
+{"name": "barbara bryant"},
+{"name": "kelsey hubbard"},
+{"name": "deborah womack"},
+{"name": "gary boren"},
+{"name": "james cameron"},
+{"name": "charlene harvey"},
+{"name": "norman patty"},
+{"name": "cindy yu"},
+{"name": "kelly perry"},
+{"name": "martin dionne"},
+{"name": "mike morgenson"},
+{"name": "pat @hagerstown"},
+{"name": "simon caldicott"},
+{"name": "lisa hackney"},
+{"name": "john buddy"},
+{"name": "ben parks"},
+{"name": "cindy lagomarsino"},
+{"name": "betsy stagg"},
+{"name": "gillian morris"},
+{"name": "heather uboldi"},
+{"name": "mike gelardi"},
+{"name": "david kutner"},
+{"name": "brian smit"},
+{"name": "alice frost"},
+{"name": "jon greaves"},
+{"name": "olivia loewy"},
+{"name": "jason hurlbut"},
+{"name": "dave plumber"},
+{"name": "nancy schellhase"},
+{"name": "bob myerson"},
+{"name": "kelly m"},
+{"name": "eunice sommers"},
+{"name": "megan block"},
+{"name": "julio alverez"},
+{"name": "jacob gursky"},
+{"name": "jay cote"},
+{"name": "christina defmo"},
+{"name": "kimberly q"},
+{"name": "donnell albert"},
+{"name": "chad wilson"},
+{"name": "tom cartmell"},
+{"name": "stephanie history"},
+{"name": "jason daskalos"},
+{"name": "jeff reis"},
+{"name": "jill kraus"},
+{"name": "krista gagyi"},
+{"name": "nichole eschelbrennan"},
+{"name": "daniel stowe"},
+{"name": "stephen feingold"},
+{"name": "mellisa kupier"},
+{"name": "jay gomez"},
+{"name": "theodore wilson"},
+{"name": "jerry silcox"},
+{"name": "anna williams"},
+{"name": "andrea cobb"},
+{"name": "dan solomito"},
+{"name": "william severne"},
+{"name": "joe loos"},
+{"name": "sha sha"},
+{"name": "caitlin miller"},
+{"name": "hugo steemers"},
+{"name": "casey avants"},
+{"name": "kevin tugas"},
+{"name": "gwyn morgan"},
+{"name": "reed meschefske"},
+{"name": "jason oppel"},
+{"name": "kevin thompson"},
+{"name": "anthony e"},
+{"name": "curt blarcom"},
+{"name": "mike trotter"},
+{"name": "ellen doyle"},
+{"name": "peggy taylor"},
+{"name": "ian trumbo"},
+{"name": "john riccio"},
+{"name": "tom kossomedes"},
+{"name": "rachelle ditmore"},
+{"name": "megan ess"},
+{"name": "paul w"},
+{"name": "doreen warrender"},
+{"name": "stewart bob"},
+{"name": "jessica prim"},
+{"name": "anthony pachelli"},
+{"name": "trevor willey"},
+{"name": "juan pettiford"},
+{"name": "trevor racer"},
+{"name": "bob huss"},
+{"name": "duncan berry"},
+{"name": "ola ayeni"},
+{"name": "david snow"},
+{"name": "jennifer chen"},
+{"name": "terry bielfelt"},
+{"name": "matthew vaughn"},
+{"name": "mary zammit"},
+{"name": "chad lancour"},
+{"name": "david brubaker"},
+{"name": "john macelhaney"},
+{"name": "sue mcgowen"},
+{"name": "michael amador"},
+{"name": "grady figart"},
+{"name": "sue fitzsimons"},
+{"name": "danny b"},
+{"name": "derek smith"},
+{"name": "marshall postnikoff"},
+{"name": "carol beatty"},
+{"name": "steve seals"},
+{"name": "tiffany ribera"},
+{"name": "robert lehrer"},
+{"name": "laurel muri"},
+{"name": "katie g"},
+{"name": "oscar mcclung"},
+{"name": "david record"},
+{"name": "lindy childers"},
+{"name": "john snowden"},
+{"name": "marlene schulte"},
+{"name": "joseph gandara"},
+{"name": "aida soto"},
+{"name": "ryan southwick"},
+{"name": "chris garrity"},
+{"name": "steve klaesius"},
+{"name": "brandon keener"},
+{"name": "chase wicker"},
+{"name": "steve kondonis"},
+{"name": "roger wade"},
+{"name": "kacie kanemoto"},
+{"name": "chester warfield"},
+{"name": "kristi springer"},
+{"name": "richard cherry"},
+{"name": "bob bleier"},
+{"name": "harold cohen"},
+{"name": "oscar solis"},
+{"name": "tom norris"},
+{"name": "clayton breidenstein"},
+{"name": "willie graf"},
+{"name": "deanna ayers"},
+{"name": "david wood"},
+{"name": "greg christiansen"},
+{"name": "larry hart"},
+{"name": "lauren butler"},
+{"name": "mark merrill"},
+{"name": "andrew brothers"},
+{"name": "doug imt"},
+{"name": "josh sep"},
+{"name": "vanessa maguire"},
+{"name": "virginia matney"},
+{"name": "kathleen mcneil"},
+{"name": "marlyn cayo"},
+{"name": "valerie miller"},
+{"name": "gregory tarr"},
+{"name": "fred rasmussen"},
+{"name": "kevin delano"},
+{"name": "ingrid leypoldt"},
+{"name": "sam kroll"},
+{"name": "nancy younan"},
+{"name": "hazel crest"},
+{"name": "angela hd"},
+{"name": "jared lucero"},
+{"name": "jeremy slutton"},
+{"name": "andrew cc"},
+{"name": "jose urbina"},
+{"name": "dick anderson"},
+{"name": "jean torchon"},
+{"name": "alex asercion"},
+{"name": "patsy darden"},
+{"name": "larry limbach"},
+{"name": "charlie aldave"},
+{"name": "steve strickland"},
+{"name": "teresa barros"},
+{"name": "stephanie elsworth"},
+{"name": "mark galis"},
+{"name": "ian richards"},
+{"name": "rich mcpherson"},
+{"name": "kitty cat"},
+{"name": "keri belmore"},
+{"name": "scott lemon"},
+{"name": "chris gonzales"},
+{"name": "aaron nadauld"},
+{"name": "brian uszak"},
+{"name": "deanna lynn"},
+{"name": "robyn winner"},
+{"name": "jim daniell"},
+{"name": "hazel wittenberg"},
+{"name": "todd decker"},
+{"name": "brandon c"},
+{"name": "hazel white"},
+{"name": "benny bar"},
+{"name": "ted french"},
+{"name": "mark wiggins"},
+{"name": "richard hwang"},
+{"name": "delia xxxxx"},
+{"name": "kim shah"},
+{"name": "rob skaricich"},
+{"name": "jeff newberry"},
+{"name": "kim mctheny"},
+{"name": "joie bar"},
+{"name": "rick steele"},
+{"name": "ryan timkee"},
+{"name": "carol mullin"},
+{"name": "jon leslie"},
+{"name": "becky cell"},
+{"name": "mario mejia"},
+{"name": "angie franklin"},
+{"name": "sommer rose"},
+{"name": "brian kahn"},
+{"name": "jason beer"},
+{"name": "rodney l"},
+{"name": "darrick talbot"},
+{"name": "kristen b"},
+{"name": "kim traver"},
+{"name": "daniel plasencia"},
+{"name": "anna banana"},
+{"name": "laurie pierson"},
+{"name": "john strong"},
+{"name": "sarah samere"},
+{"name": "carl lundeburg"},
+{"name": "daryl brasel"},
+{"name": "roy bennett"},
+{"name": "mary spengel"},
+{"name": "nick zerbe"},
+{"name": "shannon wyatt"},
+{"name": "jim massey"},
+{"name": "tony gbc"},
+{"name": "danny passousofy"},
+{"name": "kevin kay"},
+{"name": "dean richielieu"},
+{"name": "brock drew"},
+{"name": "carlos thrasher"},
+{"name": "pete hannan"},
+{"name": "lisa colon"},
+{"name": "michelle martinez"},
+{"name": "lauren willams"},
+{"name": "frank supply"},
+{"name": "michael allison"},
+{"name": "hal slager"},
+{"name": "randall miller"},
+{"name": "erin b"},
+{"name": "chris cancun"},
+{"name": "mathew johnstone"},
+{"name": "julie servodidio"},
+{"name": "paul tremblay"},
+{"name": "paul mormen"},
+{"name": "michael home"},
+{"name": "dennis hayes"},
+{"name": "mark thurow"},
+{"name": "josie valdez"},
+{"name": "tom hopcroft"},
+{"name": "pam moore"},
+{"name": "wendy tsujimoto"},
+{"name": "paul miranda"},
+{"name": "fernando benitez"},
+{"name": "glenda carter"},
+{"name": "janelle allen"},
+{"name": "dale frye"},
+{"name": "chase muratore"},
+{"name": "rod peterson"},
+{"name": "derrick taylor"},
+{"name": "marie toscano"},
+{"name": "megan welby"},
+{"name": "gonzalo higareda"},
+{"name": "walter dunn"},
+{"name": "rae singer"},
+{"name": "rick james"},
+{"name": "jenny b"},
+{"name": "dena kay"},
+{"name": "alejandro martinez"},
+{"name": "doug callahan"},
+{"name": "dan dan"},
+{"name": "joseph d'alessandro"},
+{"name": "ashlie v"},
+{"name": "tracy sullivant"},
+{"name": "joseph macak"},
+{"name": "jill shifris"},
+{"name": "katie johnson"},
+{"name": "justin mojos"},
+{"name": "stacy ceja"},
+{"name": "larry colton"},
+{"name": "shane lee"},
+{"name": "lorna smith"},
+{"name": "alex timko"},
+{"name": "tiffany compton"},
+{"name": "monique roman"},
+{"name": "ellen sedgwick"},
+{"name": "alexander figueras"},
+{"name": "bill fitzgerald"},
+{"name": "mark whittiker"},
+{"name": "eugene keeler"},
+{"name": "matt fergus"},
+{"name": "mike jett"},
+{"name": "ashley harris"},
+{"name": "page jim"},
+{"name": "sergio amador"},
+{"name": "connie petriglia"},
+{"name": "dave savage"},
+{"name": "matt regenstrief"},
+{"name": "jaime roberton"},
+{"name": "logan rothgeb"},
+{"name": "eric grimm"},
+{"name": "walter drummer"},
+{"name": "kirsten gowins"},
+{"name": "mary bruns"},
+{"name": "lane vicki"},
+{"name": "megan y"},
+{"name": "kevin giardini"},
+{"name": "john tinholt"},
+{"name": "john bergen"},
+{"name": "scott leach"},
+{"name": "christian patrick"},
+{"name": "murray mitchell"},
+{"name": "roxanne gonera"},
+{"name": "mandy kao"},
+{"name": "hillary applegate"},
+{"name": "steve reynolds"},
+{"name": "megan schub"},
+{"name": "kathy timmons"},
+{"name": "mozelle hayden"},
+{"name": "roy trio"},
+{"name": "anthony zenios"},
+{"name": "wayne lilly"},
+{"name": "natasha aspermonte"},
+{"name": "glen wagnitz"},
+{"name": "ron jereki"},
+{"name": "jan palmquist"},
+{"name": "mark baden"},
+{"name": "dorothy nelson"},
+{"name": "austin norfleet"},
+{"name": "lenore cox"},
+{"name": "lee robinson"},
+{"name": "mark lemm"},
+{"name": "kristin menson"},
+{"name": "cameron rahm"},
+{"name": "marissa ilharreguy"},
+{"name": "emily toccoli"},
+{"name": "nicholas bongianni"},
+{"name": "steven philpotts"},
+{"name": "betty abbie"},
+{"name": "robert quintero"},
+{"name": "bert mcintyre"},
+{"name": "jessica navarro"},
+{"name": "kim kubik"},
+{"name": "bobby brownfield"},
+{"name": "erica black"},
+{"name": "stephen bartelt"},
+{"name": "william hinson"},
+{"name": "calvin askew"},
+{"name": "troy donovan"},
+{"name": "justin cyr"},
+{"name": "douglas grant"},
+{"name": "pam king"},
+{"name": "tony coehlo"},
+{"name": "jim mcmillin"},
+{"name": "caitlin lyons"},
+{"name": "sandy rudek"},
+{"name": "kelly vernon"},
+{"name": "julia rodriguez"},
+{"name": "tiffany reilly"},
+{"name": "ed coonrad"},
+{"name": "matt kowalka"},
+{"name": "darren miller"},
+{"name": "jay snoddy"},
+{"name": "nicole weaver"},
+{"name": "nancy hall"},
+{"name": "mike shapiro"},
+{"name": "andy viehland"},
+{"name": "natalie work"},
+{"name": "jessie smeeks"},
+{"name": "jackie graniel"},
+{"name": "kathy larett"},
+{"name": "kathryn birkhahn"},
+{"name": "sarah smallwood"},
+{"name": "lai fong"},
+{"name": "harley sd"},
+{"name": "david shea"},
+{"name": "frank prykowski"},
+{"name": "haley cavanaugh"},
+{"name": "jake djembe"},
+{"name": "marissa weinstein"},
+{"name": "ryan arlooooooski"},
+{"name": "matt burke"},
+{"name": "jason lura"},
+{"name": "enrique garcia"},
+{"name": "dennis beringer"},
+{"name": "nick aaron"},
+{"name": "ed defrainne"},
+{"name": "frank roberts"},
+{"name": "bruce webber"},
+{"name": "thad kousser"},
+{"name": "jodi billingsley"},
+{"name": "stan windhorn"},
+{"name": "carl ford"},
+{"name": "tim bridgestreet"},
+{"name": "renee manwaring"},
+{"name": "ron henry"},
+{"name": "emily smith"},
+{"name": "tracy finlayson"},
+{"name": "amanda brennen"},
+{"name": "james roullier"},
+{"name": "michael daniel"},
+{"name": "jeremy dairyberry"},
+{"name": "tom probe"},
+{"name": "steven levine"},
+{"name": "chrystal bryant"},
+{"name": "george madray"},
+{"name": "melanie walker"},
+{"name": "dick lichti"},
+{"name": "nicole conseco"},
+{"name": "jayne williams"},
+{"name": "mike gervasi"},
+{"name": "kevin wilcox"},
+{"name": "sarah carr"},
+{"name": "jim legrand"},
+{"name": "chris dabu"},
+{"name": "marina younan"},
+{"name": "robert alexander"},
+{"name": "dawn mcclan"},
+{"name": "chris bieker"},
+{"name": "sheridan pool"},
+{"name": "johnny arevalo"},
+{"name": "josh turner"},
+{"name": "melanie ghoul"},
+{"name": "brian burke"},
+{"name": "jennifer cotner"},
+{"name": "troy bevan"},
+{"name": "deirdre mulligan"},
+{"name": "cedric bell"},
+{"name": "freddy castle"},
+{"name": "mike graziano"},
+{"name": "sue cline"},
+{"name": "dan mikalaki"},
+{"name": "bryan schultz"},
+{"name": "jed stremel"},
+{"name": "denise guenther"},
+{"name": "tim doan"},
+{"name": "ashley paige"},
+{"name": "roger gervais"},
+{"name": "derek frost"},
+{"name": "will job"},
+{"name": "alberto encina"},
+{"name": "sonja ip"},
+{"name": "michael scafuto"},
+{"name": "elliot williams"},
+{"name": "nick ilya"},
+{"name": "jimmy caldwell"},
+{"name": "eli randel"},
+{"name": "danny lo"},
+{"name": "joseph petersen"},
+{"name": "jill schwarting"},
+{"name": "julie warden"},
+{"name": "don kalkstein"},
+{"name": "patti robinson"},
+{"name": "shirley crites"},
+{"name": "james rayis"},
+{"name": "mike anisi"},
+{"name": "cheryl bruce"},
+{"name": "dee janson"},
+{"name": "molly working"},
+{"name": "cedrick large"},
+{"name": "candice wong"},
+{"name": "jared davis"},
+{"name": "andrew pentecost"},
+{"name": "matt lentz"},
+{"name": "kelle blount"},
+{"name": "charles cummings"},
+{"name": "diane conlan"},
+{"name": "ryan ogg"},
+{"name": "dan perez"},
+{"name": "victoria petty"},
+{"name": "dave hayse"},
+{"name": "amy stratmann"},
+{"name": "johnny lou"},
+{"name": "brenda alexander"},
+{"name": "jerry arledge"},
+{"name": "christie kercheval"},
+{"name": "angel robinson"},
+{"name": "katherine ferenti"},
+{"name": "carol szpara"},
+{"name": "heather ray"},
+{"name": "sandra rowe"},
+{"name": "miesha taylor"},
+{"name": "kai chu"},
+{"name": "sam seltzer's"},
+{"name": "robert lunsford"},
+{"name": "charles benedict"},
+{"name": "maria verdin"},
+{"name": "dirk nowitzki"},
+{"name": "steve farr"},
+{"name": "erik cell"},
+{"name": "erik laykin"},
+{"name": "sheryl ward"},
+{"name": "diana bradley"},
+{"name": "garret coman"},
+{"name": "karen lally"},
+{"name": "tom nguyen"},
+{"name": "neil ackerman"},
+{"name": "john schehr"},
+{"name": "ramona etwaroo"},
+{"name": "cindy lloyd"},
+{"name": "elsa ozuna"},
+{"name": "garrett turner"},
+{"name": "young deshawn"},
+{"name": "deb mueller"},
+{"name": "chris vip"},
+{"name": "dave ordonez"},
+{"name": "mark hladish"},
+{"name": "william rose"},
+{"name": "eli davis"},
+{"name": "marcus thompson"},
+{"name": "danielle nurse"},
+{"name": "holly jeffers"},
+{"name": "hong tran"},
+{"name": "brian taylor"},
+{"name": "bob famous"},
+{"name": "rick taylor"},
+{"name": "arthur aquino"},
+{"name": "pam witras"},
+{"name": "jared bennett"},
+{"name": "eric bryant"},
+{"name": "milford hough"},
+{"name": "ernie hohener"},
+{"name": "allan jacobs"},
+{"name": "don fields"},
+{"name": "bryan donnelly"},
+{"name": "chuck kessen"},
+{"name": "donna holston"},
+{"name": "ryan hammer"},
+{"name": "kyle bedran"},
+{"name": "tom stelter"},
+{"name": "clark t"},
+{"name": "tim takis"},
+{"name": "nathan jost"},
+{"name": "jim volgraff"},
+{"name": "kevin mccartin"},
+{"name": "martin sherry"},
+{"name": "james fales"},
+{"name": "danny bollinger"},
+{"name": "frank alan"},
+{"name": "beth carl"},
+{"name": "kirk dalmage"},
+{"name": "melinda johnson"},
+{"name": "judith felman"},
+{"name": "steven smirch"},
+{"name": "amanda burke"},
+{"name": "brian napper"},
+{"name": "byron unseld"},
+{"name": "nancy favill"},
+{"name": "brianne herman"},
+{"name": "karen cell"},
+{"name": "hanna kight"},
+{"name": "randy rohmer"},
+{"name": "betty schmidt"},
+{"name": "kiersten dirkes"},
+{"name": "lauren clayborne"},
+{"name": "adam lithia"},
+{"name": "jacqueline bierk"},
+{"name": "jerry ives"},
+{"name": "george nagle"},
+{"name": "so simon"},
+{"name": "bill mcnulty"},
+{"name": "molly scovel"},
+{"name": "jim bradley"},
+{"name": "susie langston"},
+{"name": "richard riddle"},
+{"name": "bruce duncan"},
+{"name": "jay white"},
+{"name": "daniel crago"},
+{"name": "lena vorob"},
+{"name": "karen yu"},
+{"name": "nancy gould"},
+{"name": "chris cano"},
+{"name": "joe beechill"},
+{"name": "dana dorsch"},
+{"name": "robert g"},
+{"name": "erin o'brian"},
+{"name": "neil caldeira"},
+{"name": "martha loya"},
+{"name": "danielle pente"},
+{"name": "caleb ngai"},
+{"name": "terry pittorino"},
+{"name": "john anhang"},
+{"name": "ken deb"},
+{"name": "shane yeager"},
+{"name": "calvin jennings"},
+{"name": "christopher needham"},
+{"name": "michael nopic"},
+{"name": "bob wiggins"},
+{"name": "marianne f"},
+{"name": "chris banares"},
+{"name": "vince craney"},
+{"name": "steve carpey"},
+{"name": "marie crisp"},
+{"name": "bruce weihrauch"},
+{"name": "kyle willard"},
+{"name": "jack reilly"},
+{"name": "danelle cox"},
+{"name": "mark leiter"},
+{"name": "nana rogers"},
+{"name": "jerry labonde"},
+{"name": "moshe haratz"},
+{"name": "gary vancleve"},
+{"name": "janet pritchard"},
+{"name": "ken diprima"},
+{"name": "leo brown"},
+{"name": "michael schmidt"},
+{"name": "suzi afuso"},
+{"name": "kim newton"},
+{"name": "tyler poteet"},
+{"name": "michael nichols"},
+{"name": "joe hallett"},
+{"name": "max mccullen"},
+{"name": "paul hartunian"},
+{"name": "darrin young"},
+{"name": "carlo levy"},
+{"name": "randy zinn"},
+{"name": "derrick cannon"},
+{"name": "erica newman"},
+{"name": "darren lo"},
+{"name": "colton r"},
+{"name": "abigail taylor"},
+{"name": "sterling robertson"},
+{"name": "mona sarah"},
+{"name": "boyd hawkes"},
+{"name": "daniel toro"},
+{"name": "james hodgkins"},
+{"name": "matt brueser"},
+{"name": "susan nabisco"},
+{"name": "henry baez"},
+{"name": "renee lapoint"},
+{"name": "heather history"},
+{"name": "lindsay gartner"},
+{"name": "jody morrison"},
+{"name": "daniel flakes"},
+{"name": "carolin ayvaz"},
+{"name": "kara island"},
+{"name": "joe obsorn"},
+{"name": "china taste"},
+{"name": "elizabeth severson"},
+{"name": "brian banks"},
+{"name": "angela hollis"},
+{"name": "richard nawracaj"},
+{"name": "sandy logsdon"},
+{"name": "david wong"},
+{"name": "alfredo gamboa"},
+{"name": "chad horner"},
+{"name": "victor garces"},
+{"name": "shannon pearce"},
+{"name": "judie pannetton"},
+{"name": "sam johnny"},
+{"name": "jerome currey"},
+{"name": "john whitlow"},
+{"name": "sean crowe"},
+{"name": "ed laughlin"},
+{"name": "elena caro"},
+{"name": "charlotte toyota"},
+{"name": "jon harris"},
+{"name": "michelle hudson"},
+{"name": "chris lenik"},
+{"name": "ismael barba"},
+{"name": "shawn davis"},
+{"name": "robert bostick"},
+{"name": "alan benezra"},
+{"name": "jana williams"},
+{"name": "lisa hagley"},
+{"name": "john wishman"},
+{"name": "bianca hereford"},
+{"name": "steven collins"},
+{"name": "mary kopakowski"},
+{"name": "joe menchaca"},
+{"name": "emma hottie"},
+{"name": "larry randa"},
+{"name": "mckinley school"},
+{"name": "adrian breelove"},
+{"name": "josh shannon"},
+{"name": "charles mcgowan"},
+{"name": "yvonne rhone"},
+{"name": "max gorringe"},
+{"name": "glen produce"},
+{"name": "justin hein"},
+{"name": "vi puhol"},
+{"name": "becky arnaiz"},
+{"name": "barry dasilva"},
+{"name": "dawn robertson"},
+{"name": "aaron godfred"},
+{"name": "theo schaeffer"},
+{"name": "melissa cataldo"},
+{"name": "travis friedman"},
+{"name": "ray kearney"},
+{"name": "kenny herin"},
+{"name": "luis calderon"},
+{"name": "blake dufer"},
+{"name": "angela morales"},
+{"name": "rusty lipscomb"},
+{"name": "edgar hertzka"},
+{"name": "brittney on"},
+{"name": "tom dougherty"},
+{"name": "arthur dunn"},
+{"name": "tom strowbridge"},
+{"name": "george manson"},
+{"name": "andy ec"},
+{"name": "noah jenkin"},
+{"name": "mike westcott"},
+{"name": "michelle marx"},
+{"name": "dan shay"},
+{"name": "connie niessink"},
+{"name": "john hegge"},
+{"name": "charles buschman"},
+{"name": "brandi williams"},
+{"name": "michelle sk"},
+{"name": "alex fowler"},
+{"name": "verla cell"},
+{"name": "louis young"},
+{"name": "cindy pierce"},
+{"name": "laura whitson"},
+{"name": "shawn bassin"},
+{"name": "mari baldukas"},
+{"name": "david meyer"},
+{"name": "gary rutherford"},
+{"name": "denise terry"},
+{"name": "ken galloway"},
+{"name": "austin cingular"},
+{"name": "marilyn lamar"},
+{"name": "mike santori"},
+{"name": "chris andrews"},
+{"name": "lee melvin"},
+{"name": "eric knechtel"},
+{"name": "brad smith"},
+{"name": "willie baker"},
+{"name": "steve zadig"},
+{"name": "amy sanders"},
+{"name": "maria fernandez"},
+{"name": "sue sue"},
+{"name": "pam walker"},
+{"name": "keisha cell"},
+{"name": "paul jonason"},
+{"name": "ryan headden"},
+{"name": "david fleming"},
+{"name": "annie sparks"},
+{"name": "dave morris"},
+{"name": "joey wellsfargo"},
+{"name": "kathy kissler"},
+{"name": "marion pedrow"},
+{"name": "belinda welch"},
+{"name": "thomas pajewski"},
+{"name": "robert noe"},
+{"name": "megan hammet"},
+{"name": "kathy weber"},
+{"name": "john z"},
+{"name": "erin o'shaughnessy"},
+{"name": "angie harwood"},
+{"name": "joann song"},
+{"name": "john battelle"},
+{"name": "pat campbell"},
+{"name": "ellen sukovich"},
+{"name": "erica natale"},
+{"name": "clark fidelity"},
+{"name": "anne radcliff"},
+{"name": "carol dunccan"},
+{"name": "dan soon"},
+{"name": "john clancy"},
+{"name": "bonnie tackett"},
+{"name": "ken brady"},
+{"name": "rebecca boeller"},
+{"name": "cheryl mickens"},
+{"name": "wendell baxter"},
+{"name": "ryan chico"},
+{"name": "kevin pomet"},
+{"name": "tony sund"},
+{"name": "sue kashner"},
+{"name": "andy alcarez"},
+{"name": "mike fedak"},
+{"name": "marilyn fuller"},
+{"name": "nicole givens"},
+{"name": "tom lal"},
+{"name": "eddie walker"},
+{"name": "karen kipnes"},
+{"name": "julia gips"},
+{"name": "lucille hunt"},
+{"name": "ian schafer"},
+{"name": "henry lopez"},
+{"name": "amy pope"},
+{"name": "matt tabor"},
+{"name": "tracy cook"},
+{"name": "tom buckley"},
+{"name": "maurice flakes"},
+{"name": "tina song"},
+{"name": "diane marino"},
+{"name": "jeffrey corder"},
+{"name": "gary krugman"},
+{"name": "alan balsamo"},
+{"name": "laura weidenfeld"},
+{"name": "adam kaniewski"},
+{"name": "tracy young"},
+{"name": "carly mac"},
+{"name": "matt walko"},
+{"name": "rebecca carman"},
+{"name": "rodney whittle"},
+{"name": "tu adsl"},
+{"name": "paul mackc"},
+{"name": "cecilia mo"},
+{"name": "april rost"},
+{"name": "john creamer"},
+{"name": "teri komer"},
+{"name": "andre mousseau"},
+{"name": "kattie farrier"},
+{"name": "robin inglese"},
+{"name": "john mccain"},
+{"name": "richard merritt"},
+{"name": "anthony dicarlo"},
+{"name": "le bal"},
+{"name": "karen barth"},
+{"name": "alex lopes"},
+{"name": "jeannie reniewicz"},
+{"name": "james grummons"},
+{"name": "martha silva"},
+{"name": "ray neighbor"},
+{"name": "damian shammas"},
+{"name": "candice kaiser"},
+{"name": "britt l"},
+{"name": "rich panopio"},
+{"name": "john angell"},
+{"name": "matt spencer"},
+{"name": "roosevelt field"},
+{"name": "troy eastlack"},
+{"name": "joel broussard"},
+{"name": "mary rhoades"},
+{"name": "crystal platt"},
+{"name": "mike likhov"},
+{"name": "rich wendt"},
+{"name": "mary burkhart"},
+{"name": "robert martinez"},
+{"name": "randy ridless"},
+{"name": "michael huber"},
+{"name": "rick selby"},
+{"name": "stephen bonnian"},
+{"name": "emily higby"},
+{"name": "anthony prietto"},
+{"name": "bret dempsey"},
+{"name": "tony kcal"},
+{"name": "vicki stout"},
+{"name": "michael mclemore"},
+{"name": "danny bowar"},
+{"name": "raymond jeff"},
+{"name": "heather burgess"},
+{"name": "matt breton"},
+{"name": "amanda webb"},
+{"name": "dan campbell"},
+{"name": "debbie kang"},
+{"name": "erin stevens"},
+{"name": "rico cell"},
+{"name": "jill masciarelli"},
+{"name": "rich czarniccki"},
+{"name": "elliot goldstein"},
+{"name": "justin greeenhaugh"},
+{"name": "michelle gonzalez"},
+{"name": "julie wilson"},
+{"name": "marvin unemployment"},
+{"name": "gary boatman"},
+{"name": "levi paradee"},
+{"name": "aaron mena"},
+{"name": "jeff namey"},
+{"name": "bobby williams"},
+{"name": "bryan semm"},
+{"name": "alison genota"},
+{"name": "bob woodard"},
+{"name": "brian t"},
+{"name": "jeff matthews"},
+{"name": "marty lozon"},
+{"name": "john scali"},
+{"name": "rachel gober"},
+{"name": "gordon mccreight"},
+{"name": "tom lund"},
+{"name": "royal drgn"},
+{"name": "debi vaughan"},
+{"name": "jim butcher"},
+{"name": "felicia carter"},
+{"name": "steve paladino"},
+{"name": "shay auerbach"},
+{"name": "brent williams"},
+{"name": "sharon asimakopoulos"},
+{"name": "lisa stewart"},
+{"name": "nelson salazar"},
+{"name": "lucas bruxvoort"},
+{"name": "heather slack"},
+{"name": "derek vanditmars"},
+{"name": "rosalyn chapman"},
+{"name": "todd cash"},
+{"name": "rick hilt"},
+{"name": "erica romeo"},
+{"name": "dave owens"},
+{"name": "nancy fogler"},
+{"name": "leone cou"},
+{"name": "ken brown"},
+{"name": "nestor ona"},
+{"name": "corey maciel"},
+{"name": "edith molina"},
+{"name": "mary groveton"},
+{"name": "richard gulbrandsen"},
+{"name": "dan jacoby"},
+{"name": "alicia mentell"},
+{"name": "catherine burdt"},
+{"name": "alyssa gluck"},
+{"name": "nan highstreet"},
+{"name": "george bandarian"},
+{"name": "marjorie shepherd"},
+{"name": "carol demarti"},
+{"name": "susan sorrick"},
+{"name": "craig nysven"},
+{"name": "darla aldridge"},
+{"name": "brandon mccray"},
+{"name": "mike gabaldon"},
+{"name": "dewitt cell"},
+{"name": "ken morris"},
+{"name": "alyson oc"},
+{"name": "roxy studio"},
+{"name": "nicole msi"},
+{"name": "stevie dante's"},
+{"name": "rudy ristich"},
+{"name": "myrna gettes"},
+{"name": "larry wheeler"},
+{"name": "bruce gerber"},
+{"name": "jimmy womble"},
+{"name": "pat keller"},
+{"name": "richard abbott"},
+{"name": "laurie mcfadden"},
+{"name": "jaymie rice"},
+{"name": "travis carter"},
+{"name": "don krohn"},
+{"name": "calvin p"},
+{"name": "harry klompas"},
+{"name": "eddie bandara"},
+{"name": "bob bettle"},
+{"name": "ruby xxxxx"},
+{"name": "jan francis"},
+{"name": "andrea ash"},
+{"name": "andrew raye"},
+{"name": "jodie tilley"},
+{"name": "garrett ratley"},
+{"name": "joel driskell"},
+{"name": "peggy lum"},
+{"name": "sara weeze"},
+{"name": "mathew schlissel"},
+{"name": "kevin beebe"},
+{"name": "michael kelley"},
+{"name": "erin kolata"},
+{"name": "tony balony"},
+{"name": "taylor couvreur"},
+{"name": "jude desti"},
+{"name": "tiffany lund"},
+{"name": "ginny ruggiero"},
+{"name": "tom grimme"},
+{"name": "wayne wada"},
+{"name": "jack nix"},
+{"name": "amy nolton"},
+{"name": "harley patricio"},
+{"name": "bill schwartz"},
+{"name": "carolina salvage"},
+{"name": "michael merchant"},
+{"name": "quinton bond"},
+{"name": "dave grannan"},
+{"name": "chris kominak"},
+{"name": "claretha fennick"},
+{"name": "jennifer mcgourin"},
+{"name": "kenneth hall"},
+{"name": "kathryn britton"},
+{"name": "jerry newman"},
+{"name": "pierre fournier"},
+{"name": "lance calamita"},
+{"name": "gina sabell"},
+{"name": "jacob menkler"},
+{"name": "bob satterfield"},
+{"name": "rene marinich"},
+{"name": "ryan tse"},
+{"name": "renae campbell"},
+{"name": "steve walker"},
+{"name": "garrett williams"},
+{"name": "sheri ridenour"},
+{"name": "giovanni milleni"},
+{"name": "peter foster"},
+{"name": "raymundo cordes"},
+{"name": "larisa smith"},
+{"name": "monica mayhem"},
+{"name": "jo jacobsen"},
+{"name": "bret maxwell"},
+{"name": "roy hofer"},
+{"name": "patrick harper"},
+{"name": "robert bruggeman"},
+{"name": "aileen santos"},
+{"name": "glenn benninger"},
+{"name": "cameron boswell"},
+{"name": "pete trucking"},
+{"name": "richard kassner"},
+{"name": "teresa grigsby"},
+{"name": "jerry meehan"},
+{"name": "roger iliff"},
+{"name": "bradford ramirez"},
+{"name": "caleb williams"},
+{"name": "ryan mcneil"},
+{"name": "gordon hodge"},
+{"name": "robert bunker"},
+{"name": "johnson roberts"},
+{"name": "vivian pitney"},
+{"name": "anthony alix"},
+{"name": "bill blankenbehler"},
+{"name": "lynwood brooks"},
+{"name": "rebecca merrill"},
+{"name": "rob hobson"},
+{"name": "kenneth pieczonka"},
+{"name": "alison corello"},
+{"name": "dana albina"},
+{"name": "david jocis"},
+{"name": "corinne bourque"},
+{"name": "aaron rosenburg"},
+{"name": "brad barnhorn"},
+{"name": "richard rosetti"},
+{"name": "jeni inabnet"},
+{"name": "keith cole"},
+{"name": "melissa collette"},
+{"name": "kerry crowell"},
+{"name": "patrick bauer"},
+{"name": "brandon yono"},
+{"name": "blaine couser"},
+{"name": "joel melissa"},
+{"name": "john stance"},
+{"name": "bradley mccoley"},
+{"name": "william brooklyn"},
+{"name": "jared steele"},
+{"name": "mary lund"},
+{"name": "morgan mccoy"},
+{"name": "david neig"},
+{"name": "steven dodds"},
+{"name": "ian carnochan"},
+{"name": "carl landis"},
+{"name": "kelly williams"},
+{"name": "marcia martinelle"},
+{"name": "stephan chriqui"},
+{"name": "craig sipes"},
+{"name": "jim bilau"},
+{"name": "ron winans"},
+{"name": "roger steele"},
+{"name": "stacy lanner"},
+{"name": "will griffin"},
+{"name": "paul guy"},
+{"name": "sara vurek"},
+{"name": "kelly duran"},
+{"name": "christine kumo"},
+{"name": "joel kelly"},
+{"name": "keli bright"},
+{"name": "sheryl paul"},
+{"name": "ryan apostalakis"},
+{"name": "dave lemmer"},
+{"name": "scott lynch"},
+{"name": "james kirlkland"},
+{"name": "daniel lau"},
+{"name": "ashleigh gay"},
+{"name": "chris cobb"},
+{"name": "carol lori"},
+{"name": "jon tennessee"},
+{"name": "tammy taylor"},
+{"name": "robert cavenaugh"},
+{"name": "ron childress"},
+{"name": "linda pierce"},
+{"name": "robin woo"},
+{"name": "byron stloukal"},
+{"name": "karen qc"},
+{"name": "belinda thomas"},
+{"name": "cynthia brito"},
+{"name": "keith klicker"},
+{"name": "larry gullum"},
+{"name": "christina cambell"},
+{"name": "steve dickens"},
+{"name": "jeff cherne"},
+{"name": "jeremy markis"},
+{"name": "katlyn riley"},
+{"name": "jamie lewandowski"},
+{"name": "mike session"},
+{"name": "opal clinic"},
+{"name": "norma wieczorek"},
+{"name": "bobby kim"},
+{"name": "teri wong"},
+{"name": "jeremy cline"},
+{"name": "tina tabbert"},
+{"name": "sean carey"},
+{"name": "claudia camacho"},
+{"name": "nick locomas"},
+{"name": "roger davidson"},
+{"name": "belinda bollman"},
+{"name": "patricia luper"},
+{"name": "alma serrato"},
+{"name": "lynn natapow"},
+{"name": "james mccaslin"},
+{"name": "noelle warner"},
+{"name": "clint waltman"},
+{"name": "greg barratt"},
+{"name": "robert morse"},
+{"name": "kim seegs"},
+{"name": "kyle packham"},
+{"name": "lisa tate"},
+{"name": "lisa sierra"},
+{"name": "randy ney"},
+{"name": "pam burleigh"},
+{"name": "shawn kelowna"},
+{"name": "larry dinkler"},
+{"name": "steve fahlmark"},
+{"name": "david michail"},
+{"name": "heather weiner"},
+{"name": "dustin h"},
+{"name": "bob pasqualle"},
+{"name": "pat kehoe"},
+{"name": "kevin fox"},
+{"name": "andrew sausage"},
+{"name": "brad countryman"},
+{"name": "donna artis"},
+{"name": "john geller"},
+{"name": "martin jones"},
+{"name": "edna broome"},
+{"name": "murray summons'"},
+{"name": "robert salguero"},
+{"name": "casey roberts"},
+{"name": "alan litwack"},
+{"name": "scott bordelove"},
+{"name": "anna stamatelatos"},
+{"name": "terry ty"},
+{"name": "marissa edinburg"},
+{"name": "lisa harris"},
+{"name": "kevin martin"},
+{"name": "kathleen lennon"},
+{"name": "bobby culver"},
+{"name": "brian kenna"},
+{"name": "constance bertha"},
+{"name": "kaylee lauden"},
+{"name": "jack butts"},
+{"name": "lisa isomura"},
+{"name": "heather sansom"},
+{"name": "brian hanlon"},
+{"name": "hector vanciale"},
+{"name": "josie susey"},
+{"name": "paul kurzawa"},
+{"name": "grace wambui"},
+{"name": "debbie larue"},
+{"name": "mary leggett"},
+{"name": "serena myspace"},
+{"name": "brian pa"},
+{"name": "greg welding"},
+{"name": "vince visa"},
+{"name": "courtney fieldin"},
+{"name": "jody tieszen"},
+{"name": "bob martinic"},
+{"name": "marc whittaker"},
+{"name": "laura pankievich"},
+{"name": "norris new"},
+{"name": "don wahle"},
+{"name": "jonathan blumberg"},
+{"name": "robert theissen"},
+{"name": "chris hootie"},
+{"name": "bernadette seariac"},
+{"name": "melissa bricker"},
+{"name": "noelia dominguez"},
+{"name": "monika skiba"},
+{"name": "christopher borchard"},
+{"name": "brett brown"},
+{"name": "damian vip"},
+{"name": "james gerber"},
+{"name": "sue boswell"},
+{"name": "tony herrera"},
+{"name": "dana robinson"},
+{"name": "esther martinez"},
+{"name": "craig swann"},
+{"name": "karla whitt"},
+{"name": "gerald adams"},
+{"name": "al faust"},
+{"name": "bob shennun"},
+{"name": "nan nolan"},
+{"name": "bruce vanderven"},
+{"name": "edward luka"},
+{"name": "scott bach"},
+{"name": "cindy danos"},
+{"name": "anthony larro"},
+{"name": "lauren donovan"},
+{"name": "dan dolan"},
+{"name": "sara maclean"},
+{"name": "jimmy hamlin"},
+{"name": "rudy dilieto"},
+{"name": "dwight johns"},
+{"name": "eugene colucci"},
+{"name": "nigel evans"},
+{"name": "sheryl carpenter"},
+{"name": "megan cuilla"},
+{"name": "jordan nassar"},
+{"name": "julie oelhafen"},
+{"name": "bob burr"},
+{"name": "dan cullinane"},
+{"name": "brendan hannegan"},
+{"name": "simon steve"},
+{"name": "mike mooney"},
+{"name": "ed bustos"},
+{"name": "mark fox"},
+{"name": "craig gubbels"},
+{"name": "kristina avant"},
+{"name": "michael mccarthy"},
+{"name": "michael gutzmann"},
+{"name": "jarod higguns"},
+{"name": "ryan mcqueary"},
+{"name": "kelly leich"},
+{"name": "danny palmer"},
+{"name": "sarah calloway"},
+{"name": "doug cooper"},
+{"name": "john rae"},
+{"name": "jason lacey"},
+{"name": "daniel ditoro"},
+{"name": "danny ord"},
+{"name": "andrew lewis"},
+{"name": "nancy good"},
+{"name": "ed fankhouser"},
+{"name": "dave ashby"},
+{"name": "linda thompson"},
+{"name": "joe mendenhall"},
+{"name": "mike graves"},
+{"name": "otis tuttle"},
+{"name": "david eskanos"},
+{"name": "peter lyons"},
+{"name": "erik eschliman"},
+{"name": "eric f"},
+{"name": "mike hadley"},
+{"name": "andrea terrell"},
+{"name": "brittney tmobile"},
+{"name": "whitley denson"},
+{"name": "gretta davey"},
+{"name": "spencer clark"},
+{"name": "rudy goodtimes"},
+{"name": "matt hay"},
+{"name": "tina nevills"},
+{"name": "dino guerero"},
+{"name": "janice madon"},
+{"name": "scott purcy"},
+{"name": "gary guarnotta"},
+{"name": "jerilyn lubitz"},
+{"name": "tony litto"},
+{"name": "dee lenore"},
+{"name": "zachary coffin"},
+{"name": "amanda mccollum"},
+{"name": "matt irwin"},
+{"name": "eddie pardo"},
+{"name": "cassie townsend"},
+{"name": "cynthia luna"},
+{"name": "annie collins"},
+{"name": "don sawade"},
+{"name": "sabrina jarman"},
+{"name": "neil levin"},
+{"name": "joyce wiggington"},
+{"name": "patrice work"},
+{"name": "kiley floor"},
+{"name": "maude bartok"},
+{"name": "michael fear"},
+{"name": "scott berg"},
+{"name": "ryan tucker"},
+{"name": "mike beacher"},
+{"name": "margaret mackenzie"},
+{"name": "lance jaeger"},
+{"name": "bob folden"},
+{"name": "alan office"},
+{"name": "nadine russell"},
+{"name": "kevin newman"},
+{"name": "mike odyne"},
+{"name": "tiffany hudson"},
+{"name": "rudy banuelos"},
+{"name": "johnathan linx"},
+{"name": "richard hermann"},
+{"name": "sharon ray"},
+{"name": "larry gibson"},
+{"name": "erich vivian"},
+{"name": "mike newton"},
+{"name": "kendall lasley"},
+{"name": "mark parris"},
+{"name": "dan brooks"},
+{"name": "billy z"},
+{"name": "lynn christensen"},
+{"name": "jason cardelino"},
+{"name": "jeff allison"},
+{"name": "samantha suzer"},
+{"name": "gertie battle"},
+{"name": "richard arns"},
+{"name": "mari r"},
+{"name": "kayla hebert"},
+{"name": "debbie potter"},
+{"name": "bob zbrudzewski"},
+{"name": "rich kaplan"},
+{"name": "jay hines"},
+{"name": "rose hagins"},
+{"name": "lloyd horton"},
+{"name": "art anderson"},
+{"name": "jenny blascovich"},
+{"name": "danielle white"},
+{"name": "eric tolley"},
+{"name": "alex holosound"},
+{"name": "heather jaq"},
+{"name": "tom maguire"},
+{"name": "cory l"},
+{"name": "roberto garcia"},
+{"name": "debbie ewing"},
+{"name": "penny kohlman"},
+{"name": "diamond sevenranch"},
+{"name": "stephan enri"},
+{"name": "eric chung"},
+{"name": "gigi johnston"},
+{"name": "lindsey mcbean"},
+{"name": "brandon burnett"},
+{"name": "leslie dooley"},
+{"name": "rick haynes"},
+{"name": "jacque friend"},
+{"name": "jason goudreau"},
+{"name": "paul santo"},
+{"name": "brandon vukelich"},
+{"name": "cary rome"},
+{"name": "nicholas sanders"},
+{"name": "sarah hollis"},
+{"name": "kenny burns"},
+{"name": "rob nakfour"},
+{"name": "jamie pressley"},
+{"name": "joe hoholick"},
+{"name": "ellen baker"},
+{"name": "david weiner"},
+{"name": "jen langher"},
+{"name": "dallas irvine"},
+{"name": "sidney lissner"},
+{"name": "rebecca harrison"},
+{"name": "allison williams"},
+{"name": "jeffrey engerman"},
+{"name": "mike tipton"},
+{"name": "donna kumar"},
+{"name": "chuck cuevas"},
+{"name": "karen thomas"},
+{"name": "lisa spencer"},
+{"name": "bryan lee"},
+{"name": "gary blabon"},
+{"name": "jennifer bissell"},
+{"name": "tom mckivor"},
+{"name": "kaitlyn kfc"},
+{"name": "hwa dill"},
+{"name": "javier macias"},
+{"name": "michael lachuk"},
+{"name": "erin young"},
+{"name": "lorri jenkins"},
+{"name": "herb brown"},
+{"name": "jordan girl"},
+{"name": "chris coes"},
+{"name": "kevin mcdonnell"},
+{"name": "steven ortiz"},
+{"name": "ben berkwtz"},
+{"name": "dalia gadelmawla"},
+{"name": "matt merrill"},
+{"name": "harry wrk"},
+{"name": "kris bundy"},
+{"name": "tim mertes"},
+{"name": "golden nugget"},
+{"name": "karan m"},
+{"name": "austin philips"},
+{"name": "holly rome"},
+{"name": "abraham martinez"},
+{"name": "devin lasker"},
+{"name": "michael heimos"},
+{"name": "john salvador"},
+{"name": "brad folkestad"},
+{"name": "latisha mullins"},
+{"name": "aaron irons"},
+{"name": "samuel parent"},
+{"name": "candace foust"},
+{"name": "chris mason"},
+{"name": "jen vaughn"},
+{"name": "constance teague"},
+{"name": "john wadsworth"},
+{"name": "will schreiber"},
+{"name": "lance reynolds"},
+{"name": "byron broker"},
+{"name": "bob shireman"},
+{"name": "anne evans"},
+{"name": "roy folger"},
+{"name": "eve chan"},
+{"name": "cassidy buelow"},
+{"name": "shalonda martin"},
+{"name": "adele mcdonald"},
+{"name": "jc hong"},
+{"name": "heidi mallet"},
+{"name": "blake graves"},
+{"name": "anne nest"},
+{"name": "marianne dawes"},
+{"name": "jill holm"},
+{"name": "amber nevels"},
+{"name": "tommy sporleder"},
+{"name": "david korones"},
+{"name": "judy millburn"},
+{"name": "jennifer andriesse"},
+{"name": "marty maleka"},
+{"name": "debbie zita"},
+{"name": "shawn phiips"},
+{"name": "gayle carline"},
+{"name": "manuel proda"},
+{"name": "scott graffix"},
+{"name": "magen weihorch"},
+{"name": "thomas davidson"},
+{"name": "sara marvin"},
+{"name": "kevin o'loughlin"},
+{"name": "karl grabin"},
+{"name": "sammie mawtin"},
+{"name": "ryan ben"},
+{"name": "mark furnace"},
+{"name": "wyatt cps"},
+{"name": "jeff hammersley"},
+{"name": "pauline salazar"},
+{"name": "stephanie pau"},
+{"name": "george soros"},
+{"name": "kirsten w"},
+{"name": "steve kysor"},
+{"name": "michelle lincoln"},
+{"name": "billy holton"},
+{"name": "vanessa albornoz"},
+{"name": "denise anderson"},
+{"name": "moshe rubin"},
+{"name": "janie stabfield"},
+{"name": "bill strong"},
+{"name": "jason starr"},
+{"name": "matt franzen"},
+{"name": "julie p"},
+{"name": "torrie gines"},
+{"name": "audie antoinette"},
+{"name": "kelly anderson"},
+{"name": "johanna kos"},
+{"name": "jessica tracy"},
+{"name": "alicia dorey"},
+{"name": "martha parks"},
+{"name": "patrick mccann"},
+{"name": "joe ruff"},
+{"name": "simon ireland"},
+{"name": "tony mccormick"},
+{"name": "donna hurtman"},
+{"name": "sean medina"},
+{"name": "julia williams"},
+{"name": "jessie jackstraw"},
+{"name": "adam vink"},
+{"name": "sandi villanueva"},
+{"name": "al baker"},
+{"name": "ashley caldwell"},
+{"name": "larry bailey"},
+{"name": "joel theirson"},
+{"name": "duane hinkley"},
+{"name": "lisa chan"},
+{"name": "dillon atwood"},
+{"name": "roma go"},
+{"name": "darrin xxxxx"},
+{"name": "mercedes useda"},
+{"name": "irene gibson"},
+{"name": "kelley lynn"},
+{"name": "john mcfarland"},
+{"name": "debra curry"},
+{"name": "garrett parker"},
+{"name": "allison gonzales"},
+{"name": "eric steffel"},
+{"name": "ray jacobs"},
+{"name": "brant finnegan"},
+{"name": "john cleary"},
+{"name": "don gates"},
+{"name": "ian grant"},
+{"name": "phil moulton"},
+{"name": "sean huntley"},
+{"name": "bill hubay"},
+{"name": "kenia tenorio"},
+{"name": "samantha rhea"},
+{"name": "linda willard"},
+{"name": "jay agnew"},
+{"name": "kimberly gibson"},
+{"name": "randy lefler"},
+{"name": "francisco didomedici"},
+{"name": "joe guida"},
+{"name": "angela hahn"},
+{"name": "adam gerard"},
+{"name": "candace morelock"},
+{"name": "jen good"},
+{"name": "angel robles"},
+{"name": "lana nornberg"},
+{"name": "barb cel"},
+{"name": "melissa nicol"},
+{"name": "cathy poniatowski"},
+{"name": "chuck mckinley"},
+{"name": "mel ackermann"},
+{"name": "rick cop"},
+{"name": "adam murphy"},
+{"name": "sabrina ramos"},
+{"name": "amanda burbank"},
+{"name": "tony rcc"},
+{"name": "jo charles"},
+{"name": "shannon clean"},
+{"name": "jamie nanny"},
+{"name": "marc ganek"},
+{"name": "timothy husom"},
+{"name": "sylvia smith"},
+{"name": "sparkle french"},
+{"name": "marie torres"},
+{"name": "jill layne"},
+{"name": "chris bowen"},
+{"name": "aaron jewel"},
+{"name": "dave eva"},
+{"name": "david cw"},
+{"name": "eric lim"},
+{"name": "mike harvey"},
+{"name": "vanessa pipes"},
+{"name": "jim koehler"},
+{"name": "carolyn borum"},
+{"name": "nick vonlintel"},
+{"name": "shane bras"},
+{"name": "kara emmons"},
+{"name": "justin stearman"},
+{"name": "amie ryan"},
+{"name": "lidia hernandez"},
+{"name": "john martini"},
+{"name": "rodney sullins"},
+{"name": "rex craig"},
+{"name": "sigrid mciver"},
+{"name": "donald putterman"},
+{"name": "kevin kimber"},
+{"name": "shelby chung"},
+{"name": "josh long"},
+{"name": "olivia l"},
+{"name": "bob allen"},
+{"name": "nicole hanna"},
+{"name": "joe sloat"},
+{"name": "bernie morrey"},
+{"name": "emma kimpton"},
+{"name": "dan gonzalez"},
+{"name": "gino larice"},
+{"name": "hazel o'leary"},
+{"name": "stefanie horowitz"},
+{"name": "anna parsons"},
+{"name": "chad brownfield"},
+{"name": "howard tobey"},
+{"name": "colleen patchin"},
+{"name": "michael dontzin"},
+{"name": "mike granuzzo"},
+{"name": "tracey stallings"},
+{"name": "jack bernstein"},
+{"name": "kyle pugh"},
+{"name": "john dalton"},
+{"name": "sue falkner"},
+{"name": "catherine henderson"},
+{"name": "john cassata"},
+{"name": "raymond whitlow"},
+{"name": "juana garcia"},
+{"name": "tori cleaveland"},
+{"name": "roberto garza"},
+{"name": "anna zeltsman"},
+{"name": "marvin soto"},
+{"name": "jane kopakowski"},
+{"name": "gail cameron"},
+{"name": "jeremiah linder"},
+{"name": "anna jablonski"},
+{"name": "jermaine young"},
+{"name": "roger hicks"},
+{"name": "donna nelson"},
+{"name": "yesenia castaneda"},
+{"name": "patrick nunn"},
+{"name": "mark canning"},
+{"name": "dave corlew"},
+{"name": "ed gunger"},
+{"name": "jen henderson"},
+{"name": "russ zimmerman"},
+{"name": "margo wilkerson"},
+{"name": "patti garrido"},
+{"name": "kevin burnett"},
+{"name": "barbara nectow"},
+{"name": "monica dionne"},
+{"name": "toya good"},
+{"name": "donnie mize"},
+{"name": "tony supine"},
+{"name": "jose andy"},
+{"name": "millie crutcher"},
+{"name": "andrew puccini"},
+{"name": "celeste lopez"},
+{"name": "bryan valerion"},
+{"name": "amber turner"},
+{"name": "denny brooks"},
+{"name": "robin kent"},
+{"name": "greg plotner"},
+{"name": "william vega"},
+{"name": "vincent dipietro"},
+{"name": "joe hopkins"},
+{"name": "angel adames"},
+{"name": "kevin lyons"},
+{"name": "mike elite"},
+{"name": "greg fisel"},
+{"name": "max ventura"},
+{"name": "maureen elia"},
+{"name": "cameron xxxxx"},
+{"name": "kurt carl"},
+{"name": "john song"},
+{"name": "mara levinsky"},
+{"name": "jim cornfield"},
+{"name": "john richardson"},
+{"name": "mike kline"},
+{"name": "connie springfield"},
+{"name": "chas bolton"},
+{"name": "bruce wrk"},
+{"name": "salvatore petetti"},
+{"name": "mickey evans"},
+{"name": "suzy turner"},
+{"name": "larry whipple"},
+{"name": "jeff carl"},
+{"name": "janna fraser"},
+{"name": "will xbox"},
+{"name": "chris naegeli"},
+{"name": "carol frey"},
+{"name": "jonathan jose"},
+{"name": "candi valleria"},
+{"name": "jeff frye"},
+{"name": "michael ham"},
+{"name": "robert williams"},
+{"name": "christie bonner"},
+{"name": "ken steiert"},
+{"name": "dana masters"},
+{"name": "sharon bill"},
+{"name": "ty o'neal"},
+{"name": "emily g"},
+{"name": "joseph cassick"},
+{"name": "nicki polinski"},
+{"name": "michael lance"},
+{"name": "chris west"},
+{"name": "dawn home"},
+{"name": "michael nesbitt"},
+{"name": "jose jiminez"},
+{"name": "byron betancourt"},
+{"name": "charlie jacobs"},
+{"name": "angie watson"},
+{"name": "andy cell"},
+{"name": "jeff goh"},
+{"name": "caroline boston"},
+{"name": "melissa groller"},
+{"name": "robert webb"},
+{"name": "jill kapson"},
+{"name": "keith meyer"},
+{"name": "javier wu"},
+{"name": "judy mills"},
+{"name": "kelsey hood"},
+{"name": "paul rothman"},
+{"name": "emily wang"},
+{"name": "ron bension"},
+{"name": "kathy grear"},
+{"name": "howard forman"},
+{"name": "catherine carruthers"},
+{"name": "loretta o'brien"},
+{"name": "randy stearns"},
+{"name": "tiffani elliott"},
+{"name": "julian maressa"},
+{"name": "stacy loghry"},
+{"name": "kelsey b"},
+{"name": "vera terracciano"},
+{"name": "ann client"},
+{"name": "dennis dasher"},
+{"name": "carson hill"},
+{"name": "terry ludwig"},
+{"name": "jay andino"},
+{"name": "pat jitka"},
+{"name": "pat bosco"},
+{"name": "marilyn harvey"},
+{"name": "chase linda"},
+{"name": "maria rey"},
+{"name": "steve wheat"},
+{"name": "crystal crenshaw"},
+{"name": "ed decker"},
+{"name": "bryce sacks"},
+{"name": "kia sayles"},
+{"name": "richard herrmann"},
+{"name": "stephanie padon"},
+{"name": "john sturm"},
+{"name": "joe plog"},
+{"name": "jeff ironside"},
+{"name": "robert reichek"},
+{"name": "betty peterson"},
+{"name": "george kulasa"},
+{"name": "brian shop"},
+{"name": "oscar padilla"},
+{"name": "steve mcanulty"},
+{"name": "brenda flores"},
+{"name": "kristin garcia"},
+{"name": "don myers"},
+{"name": "eric gomez"},
+{"name": "herb horowitz"},
+{"name": "kim petty"},
+{"name": "jackie dq"},
+{"name": "bill good"},
+{"name": "kelly realtor"},
+{"name": "joy price"},
+{"name": "david contois"},
+{"name": "tina brook"},
+{"name": "daniel waller"},
+{"name": "tamara brown"},
+{"name": "rick carlos"},
+{"name": "robert rajewski"},
+{"name": "bess gison"},
+{"name": "katie griffith"},
+{"name": "veronique dussault"},
+{"name": "gracie quintero"},
+{"name": "karen gersten"},
+{"name": "joe work"},
+{"name": "julio rodriguez"},
+{"name": "michael lerner"},
+{"name": "tony p"},
+{"name": "toni lister"},
+{"name": "anne frank"},
+{"name": "steven stegman"},
+{"name": "kevin boss"},
+{"name": "lauren gangl"},
+{"name": "manuel mora"},
+{"name": "martin cadillac"},
+{"name": "erica devries"},
+{"name": "lester rockwell"},
+{"name": "dave hoskin"},
+{"name": "mike drinnin"},
+{"name": "jonathan richardson"},
+{"name": "monte zarlingo"},
+{"name": "christa carpenter"},
+{"name": "jeff klein"},
+{"name": "cheryl granger"},
+{"name": "steve deroos"},
+{"name": "clay mangum"},
+{"name": "mary jack"},
+{"name": "lynette supercuts"},
+{"name": "heidi millman"},
+{"name": "frank deppe"},
+{"name": "hannah skgl"},
+{"name": "caitlin muldoon"},
+{"name": "john hershenberg"},
+{"name": "diana conlon"},
+{"name": "brian broeders"},
+{"name": "chris fitzsimmons"},
+{"name": "john shillingburg"},
+{"name": "shaun prevatt"},
+{"name": "gay edy"},
+{"name": "rodney stalker"},
+{"name": "donna callas"},
+{"name": "ellsworth matt"},
+{"name": "frank tyllia"},
+{"name": "dora teniente"},
+{"name": "margret cocksedge"},
+{"name": "chad vanhorn"},
+{"name": "laurie downum"},
+{"name": "caitlyn marquez"},
+{"name": "troy pautz"},
+{"name": "fabian rodriguez"},
+{"name": "lewis montarada"},
+{"name": "ben brennan"},
+{"name": "blair parkhill"},
+{"name": "kathy greene"},
+{"name": "doug black"},
+{"name": "jason atkins"},
+{"name": "gilbert malcolm"},
+{"name": "phil polich"},
+{"name": "linda bally"},
+{"name": "sean mccarty"},
+{"name": "chris perkins"},
+{"name": "will bisanz"},
+{"name": "mark gangeness"},
+{"name": "darren shanks"},
+{"name": "abby mcallisters"},
+{"name": "dan frank"},
+{"name": "hollie fieckert"},
+{"name": "alan roning"},
+{"name": "taylor dunn"},
+{"name": "alan benner"},
+{"name": "jodi weber"},
+{"name": "alex skaggs"},
+{"name": "stefan neighbor"},
+{"name": "brent stapley"},
+{"name": "laurie zabin"},
+{"name": "mike mcclure"},
+{"name": "kathy rhoades"},
+{"name": "eva victor"},
+{"name": "art rost"},
+{"name": "van yzerloo"},
+{"name": "michael ray"},
+{"name": "john mantey"},
+{"name": "todd radtke"},
+{"name": "alicia taylor"},
+{"name": "gene mckinney"},
+{"name": "peggy carlson"},
+{"name": "chris wiens"},
+{"name": "mike halleck"},
+{"name": "ryan kealy"},
+{"name": "art chang"},
+{"name": "nam tenis"},
+{"name": "mark sakino"},
+{"name": "rachael sweet"},
+{"name": "john solder"},
+{"name": "kristen vicelli"},
+{"name": "william hunter"},
+{"name": "nick carrone"},
+{"name": "donald olenick"},
+{"name": "william bg"},
+{"name": "paul bradley"},
+{"name": "solomon fulero"},
+{"name": "maggie kraft"},
+{"name": "suzanne fausett"},
+{"name": "steve pearse"},
+{"name": "ron metro"},
+{"name": "jamika king"},
+{"name": "kelly clavelle"},
+{"name": "dennis mobile"},
+{"name": "beth morris"},
+{"name": "julie bamford"},
+{"name": "keith orr"},
+{"name": "gaye jones"},
+{"name": "jason burns"},
+{"name": "sue dornan"},
+{"name": "brian dingman"},
+{"name": "mari bar"},
+{"name": "jerry nava"},
+{"name": "susan warren"},
+{"name": "alex biney"},
+{"name": "stephen fowler"},
+{"name": "greg wallace"},
+{"name": "nick amber"},
+{"name": "marco lucero"},
+{"name": "paul urbano"},
+{"name": "allison jacobs"},
+{"name": "marilyn curtis"},
+{"name": "veronica heuberger"},
+{"name": "tiffany kwan"},
+{"name": "pete mc"},
+{"name": "victoria kent"},
+{"name": "paula thompson"},
+{"name": "cynthia zou"},
+{"name": "joey pinion"},
+{"name": "victor hurtado"},
+{"name": "margot wetzel"},
+{"name": "keith hurley"},
+{"name": "daniel troyer"},
+{"name": "randy krystal"},
+{"name": "daniel pote"},
+{"name": "juan lowell"},
+{"name": "emma chaotica"},
+{"name": "lance mccord"},
+{"name": "seth miller"},
+{"name": "dusty weekly"},
+{"name": "terry fitzpatrick"},
+{"name": "denise tallman"},
+{"name": "dylan brandau"},
+{"name": "evan tensmeyer"},
+{"name": "chris deering"},
+{"name": "willie mobile"},
+{"name": "mollie young"},
+{"name": "jessica b"},
+{"name": "melissa massuco"},
+{"name": "bob kline"},
+{"name": "amanda elend"},
+{"name": "mike leary"},
+{"name": "jordan styrksy"},
+{"name": "lance chickasawa"},
+{"name": "kelly davidson"},
+{"name": "mark neighbor"},
+{"name": "rich green"},
+{"name": "carson feilds"},
+{"name": "anthony griggs"},
+{"name": "helena shuck"},
+{"name": "keith johnston"},
+{"name": "bob schwalbe"},
+{"name": "david martz"},
+{"name": "kenneth wooly"},
+{"name": "jim whittle"},
+{"name": "cecilia castro"},
+{"name": "lisa hengstler"},
+{"name": "esther kristie"},
+{"name": "suzette cell"},
+{"name": "stephanie raines"},
+{"name": "paul boss"},
+{"name": "erik e"},
+{"name": "meredith gilchrist"},
+{"name": "tanya cappel"},
+{"name": "adrienne xxxxx"},
+{"name": "daren mills"},
+{"name": "jared chandler"},
+{"name": "john trujillo"},
+{"name": "adrienne prassas"},
+{"name": "blake larsen"},
+{"name": "michelle phillips"},
+{"name": "emily benedek"},
+{"name": "enrique gutierrez"},
+{"name": "matthew sanchez"},
+{"name": "mark crawford"},
+{"name": "brian lafontaine"},
+{"name": "eileen haley"},
+{"name": "mike lyons"},
+{"name": "stephanie proulx"},
+{"name": "sheena cooper"},
+{"name": "edward french"},
+{"name": "david nystrom"},
+{"name": "lee rush"},
+{"name": "jackson shane"},
+{"name": "joe sacco"},
+{"name": "kristen guzman"},
+{"name": "alfonzo montoya"},
+{"name": "pat molinaro"},
+{"name": "jo arquillano"},
+{"name": "linda freeman"},
+{"name": "kelly losson"},
+{"name": "marcel zeventer"},
+{"name": "deanna hanoneh"},
+{"name": "ben boomer"},
+{"name": "angle manager"},
+{"name": "angela mitchell"},
+{"name": "jake hill"},
+{"name": "brandi holland"},
+{"name": "katie douglas"},
+{"name": "nancy silverfield"},
+{"name": "kaye cannon"},
+{"name": "pam diaz"},
+{"name": "george fink"},
+{"name": "dante salvati"},
+{"name": "josh ulrich"},
+{"name": "bill chaney"},
+{"name": "guy dobsch"},
+{"name": "renee brown"},
+{"name": "jim mattix"},
+{"name": "allison hoffman"},
+{"name": "lelah gray"},
+{"name": "patrick rail"},
+{"name": "sarina sablan"},
+{"name": "rick bassman"},
+{"name": "matt randal"},
+{"name": "john hartman"},
+{"name": "kim whatley"},
+{"name": "michelle krecklow"},
+{"name": "edwin jules"},
+{"name": "shelley davis"},
+{"name": "joe g"},
+{"name": "sherman vinizki"},
+{"name": "alana cardenas"},
+{"name": "kirk johnson"},
+{"name": "april roses"},
+{"name": "millicent gerni"},
+{"name": "william whiting"},
+{"name": "jonathan lucroy"},
+{"name": "william meyers"},
+{"name": "justin paintball"},
+{"name": "trevor wedding"},
+{"name": "angela whetstone"},
+{"name": "gary hughes"},
+{"name": "mike jordan"},
+{"name": "pam liddel"},
+{"name": "mike copeland"},
+{"name": "haley balzano"},
+{"name": "bill sawyer"},
+{"name": "matt costa"},
+{"name": "connie young"},
+{"name": "jan ferrer"},
+{"name": "nicole spencer"},
+{"name": "chance almonte"},
+{"name": "amy ballantini"},
+{"name": "will anderson"},
+{"name": "larry gelwix"},
+{"name": "mark podlin"},
+{"name": "robin dunn"},
+{"name": "mark stallings"},
+{"name": "reyna tornez"},
+{"name": "breanna mosch"},
+{"name": "kathy godley"},
+{"name": "tracy tamminga"},
+{"name": "sheldon sampson"},
+{"name": "walker frohlich"},
+{"name": "jaclyn miglio"},
+{"name": "lisa roberts"},
+{"name": "justin capen"},
+{"name": "doug svatos"},
+{"name": "james griffith"},
+{"name": "joy hospital"},
+{"name": "linda rich"},
+{"name": "jerry quigley"},
+{"name": "sam lieber"},
+{"name": "jenna minkley"},
+{"name": "mike morimoto"},
+{"name": "gary hillis"},
+{"name": "tony holm"},
+{"name": "stan vzw"},
+{"name": "edwin vazquez"},
+{"name": "jessie smith"},
+{"name": "maria aceves"},
+{"name": "dan mamatela"},
+{"name": "melissa seo"},
+{"name": "troy harnisch"},
+{"name": "joe morino"},
+{"name": "jay baranoski"},
+{"name": "doug chamberlain"},
+{"name": "andy kostos"},
+{"name": "denise mcnair"},
+{"name": "garrett uw"},
+{"name": "susie sandberg"},
+{"name": "lewis kpl"},
+{"name": "richard whittington"},
+{"name": "amy cornic"},
+{"name": "amy ulrich"},
+{"name": "matt rose"},
+{"name": "laurie pearson"},
+{"name": "john gilhooley"},
+{"name": "david medina"},
+{"name": "steve hey"},
+{"name": "monica brady"},
+{"name": "jake mallon"},
+{"name": "sandy mcdonald"},
+{"name": "greg hansen"},
+{"name": "marlene pritchard"},
+{"name": "johnson ins"},
+{"name": "wayne tyson"},
+{"name": "parker lee"},
+{"name": "thea phim"},
+{"name": "jennifer rush"},
+{"name": "nicole mcilveen"},
+{"name": "mary murray"},
+{"name": "devon wright"},
+{"name": "peter coskun"},
+{"name": "al stacks"},
+{"name": "melvin amio"},
+{"name": "michele cassou"},
+{"name": "allie smith"},
+{"name": "david hanson"},
+{"name": "brian reaves"},
+{"name": "hang up"},
+{"name": "kathryn green"},
+{"name": "rick willey"},
+{"name": "tatum sherie"},
+{"name": "kristen keough"},
+{"name": "jamie boyd"},
+{"name": "jenny glavey"},
+{"name": "leisa ayers"},
+{"name": "jim mabrey"},
+{"name": "lance mueller"},
+{"name": "natalia panzarini"},
+{"name": "janis jennings"},
+{"name": "steve keating"},
+{"name": "mike tyne"},
+{"name": "jackie nation"},
+{"name": "john lambros"},
+{"name": "rob trobridge"},
+{"name": "sara altukhaim"},
+{"name": "audrey lewis"},
+{"name": "joe eddy"},
+{"name": "bryan harrison"},
+{"name": "louis judd"},
+{"name": "victoria loran"},
+{"name": "barney wolf"},
+{"name": "jeff wright"},
+{"name": "sylvie rozon"},
+{"name": "bruce flatt"},
+{"name": "rae anne"},
+{"name": "ken hardy"},
+{"name": "james soto"},
+{"name": "donna bettencourt"},
+{"name": "tanya shina"},
+{"name": "ashley shanon"},
+{"name": "tony pitts"},
+{"name": "taylor fischer"},
+{"name": "chris stecklhiem"},
+{"name": "drew skillman"},
+{"name": "margie najera"},
+{"name": "judy carter"},
+{"name": "greg vogelpool"},
+{"name": "jason horton"},
+{"name": "carlos fsi"},
+{"name": "keith graves"},
+{"name": "michael perry"},
+{"name": "james clapsaddle"},
+{"name": "luke c"},
+{"name": "claudia martinez"},
+{"name": "josh motorcycle"},
+{"name": "ron kline"},
+{"name": "ted asian"},
+{"name": "barb dye"},
+{"name": "jonathan hospital"},
+{"name": "andrew kerekes"},
+{"name": "julie kang"},
+{"name": "kathy wolf"},
+{"name": "chad loveland"},
+{"name": "doris lastrappe"},
+{"name": "jason kimbrough"},
+{"name": "evan jackson"},
+{"name": "candy hughes"},
+{"name": "ryan rothacker"},
+{"name": "matt soares"},
+{"name": "leah wahl"},
+{"name": "dan buttry"},
+{"name": "mike culhane"},
+{"name": "john sauer"},
+{"name": "fred cee"},
+{"name": "robert swee"},
+{"name": "james luong"},
+{"name": "wallace p"},
+{"name": "james downey"},
+{"name": "nichol toomier"},
+{"name": "ai nakagawa"},
+{"name": "john haffner"},
+{"name": "robert sestak"},
+{"name": "jason kirby"},
+{"name": "lou halladay"},
+{"name": "mark bounds"},
+{"name": "bob knapp"},
+{"name": "jeff forsberg"},
+{"name": "james walsh"},
+{"name": "duane blood"},
+{"name": "terry stagman"},
+{"name": "tony locke"},
+{"name": "ryan wordeman"},
+{"name": "gabrielle haskins"},
+{"name": "clay johnson"},
+{"name": "david bayles"},
+{"name": "michael reali"},
+{"name": "todd morgan"},
+{"name": "frank divito"},
+{"name": "beau baldwin"},
+{"name": "pat gidwitz"},
+{"name": "michael dunn"},
+{"name": "david corwin"},
+{"name": "gary allen"},
+{"name": "lisa galjanic"},
+{"name": "sara silva"},
+{"name": "candace allred"},
+{"name": "lee alton"},
+{"name": "steve daniels"},
+{"name": "annette paparella"},
+{"name": "ty hidalgo"},
+{"name": "steve sarkisian"},
+{"name": "sherita green"},
+{"name": "brian stallings"},
+{"name": "lynn hollow"},
+{"name": "kerry pace"},
+{"name": "petra assoc"},
+{"name": "jared steenhoff"},
+{"name": "sarah berry"},
+{"name": "bert bandera"},
+{"name": "jim o'driscoll"},
+{"name": "richard wood"},
+{"name": "alex gruzen"},
+{"name": "stephanie ziebarth"},
+{"name": "jack kayajanian"},
+{"name": "brett shanbel"},
+{"name": "bianca ollila"},
+{"name": "gustavo lozada"},
+{"name": "luis alvarado"},
+{"name": "jerry dimtrov"},
+{"name": "noel younan"},
+{"name": "celine ostendorf"},
+{"name": "brad verthein"},
+{"name": "maggie may"},
+{"name": "rey rey"},
+{"name": "dennis thompson"},
+{"name": "kurt hagman"},
+{"name": "michael caron"},
+{"name": "larry grupp"},
+{"name": "john zaharis"},
+{"name": "steven foster"},
+{"name": "sarah gutierrez"},
+{"name": "fernando guerrero"},
+{"name": "erin bowen"},
+{"name": "steve grant"},
+{"name": "eric r"},
+{"name": "jeremy binder"},
+{"name": "andrew brannan"},
+{"name": "carol stewart"},
+{"name": "spencer murdock"},
+{"name": "sherry rials"},
+{"name": "erin baker"},
+{"name": "morris hill"},
+{"name": "curtis lg"},
+{"name": "joe six"},
+{"name": "cesar marciales"},
+{"name": "clyde sponsor"},
+{"name": "kelly oneil"},
+{"name": "chad canfield"},
+{"name": "ken maclean"},
+{"name": "emily alexander"},
+{"name": "carl whelan"},
+{"name": "gary mulholland"},
+{"name": "ward gilbert"},
+{"name": "mike wang"},
+{"name": "seth steib"},
+{"name": "aracely cousin"},
+{"name": "jane pryne"},
+{"name": "pat barron"},
+{"name": "margaret humiecki"},
+{"name": "carla haleem"},
+{"name": "julie strand"},
+{"name": "justin cash"},
+{"name": "megan scribner"},
+{"name": "michael weinberg"},
+{"name": "thomas tile"},
+{"name": "martin geminder"},
+{"name": "brian kennedy"},
+{"name": "ellis beesley"},
+{"name": "jim mcnamara"},
+{"name": "glenn tayler"},
+{"name": "lawrence waller"},
+{"name": "mike va"},
+{"name": "sharon jobity"},
+{"name": "david mcfadden"},
+{"name": "david baltazar"},
+{"name": "rick hetzel"},
+{"name": "max pegram"},
+{"name": "sally martinez"},
+{"name": "carrie allen"},
+{"name": "mary sarb"},
+{"name": "dino moshova"},
+{"name": "danny hebert"},
+{"name": "kathy david"},
+{"name": "mary lopez"},
+{"name": "arthur harwood"},
+{"name": "kevin mccarthy"},
+{"name": "crystal dread"},
+{"name": "chaz mark"},
+{"name": "eric schindler"},
+{"name": "nicole phillips"},
+{"name": "michele davis"},
+{"name": "mark ramps"},
+{"name": "lisa forbess"},
+{"name": "yolanda thompson"},
+{"name": "chris baliton"},
+{"name": "mary c"},
+{"name": "joe christian"},
+{"name": "rob bakewell"},
+{"name": "mike ortega"},
+{"name": "allen eisinger"},
+{"name": "robbin windows"},
+{"name": "andres madrigal"},
+{"name": "marcy feller"},
+{"name": "barbara royal"},
+{"name": "jane coakley"},
+{"name": "laura reyes"},
+{"name": "amanda satterfield"},
+{"name": "barbara florida"},
+{"name": "jackie barretta"},
+{"name": "shelley fossil"},
+{"name": "steve willett"},
+{"name": "raymond nathan"},
+{"name": "jerry cedrone"},
+{"name": "chris scasta"},
+{"name": "troy foster"},
+{"name": "steve guitar"},
+{"name": "bobbi leyes"},
+{"name": "dan carpenter"},
+{"name": "marcia schank"},
+{"name": "ty peterson"},
+{"name": "judith alcala"},
+{"name": "roy cell"},
+{"name": "inge hoffman"},
+{"name": "susan abell"},
+{"name": "jose javier"},
+{"name": "jeff mckay"},
+{"name": "dominic nee"},
+{"name": "larry gurule"},
+{"name": "mike gas"},
+{"name": "deena kriney"},
+{"name": "randy griffen"},
+{"name": "joseph rivett"},
+{"name": "gale vogt"},
+{"name": "dillon bastinni"},
+{"name": "dave teacher"},
+{"name": "denis maloney"},
+{"name": "troy vega"},
+{"name": "derek oi"},
+{"name": "lindsay kipnes"},
+{"name": "shelly liska"},
+{"name": "matt desmond"},
+{"name": "glen mccallum"},
+{"name": "howard gordon"},
+{"name": "claudio i"},
+{"name": "marilyn brown"},
+{"name": "dan doellinger"},
+{"name": "joe paplaczyk"},
+{"name": "paul christian"},
+{"name": "allison hayes"},
+{"name": "daryl hanna"},
+{"name": "bob mansbridge"},
+{"name": "doug brehm"},
+{"name": "mario taylor"},
+{"name": "melissa fischer"},
+{"name": "shaun dolon"},
+{"name": "amanda spajci"},
+{"name": "sydney blackmer"},
+{"name": "jenni fernandez"},
+{"name": "mark trim"},
+{"name": "ralph puente"},
+{"name": "faye mcneese"},
+{"name": "vicki kahler"},
+{"name": "james slape"},
+{"name": "holly wright"},
+{"name": "leah home"},
+{"name": "mac daniels"},
+{"name": "ross gube"},
+{"name": "annie lema"},
+{"name": "garry lyons"},
+{"name": "phil cereto"},
+{"name": "josh ryder"},
+{"name": "craig greene"},
+{"name": "beau wilson"},
+{"name": "david bearss"},
+{"name": "rebecca eaton"},
+{"name": "susan strick"},
+{"name": "lola sanchez"},
+{"name": "james voss"},
+{"name": "lawrence pollack"},
+{"name": "gail simmons"},
+{"name": "nga adm"},
+{"name": "tyler chandler"},
+{"name": "nick zimmerman"},
+{"name": "florida krakoff"},
+{"name": "lori king"},
+{"name": "brent klovstadt"},
+{"name": "wendy robbins"},
+{"name": "jim haine"},
+{"name": "sarah neal"},
+{"name": "george prichard"},
+{"name": "gene hill"},
+{"name": "martha aham"},
+{"name": "anthony battaglia"},
+{"name": "chris huff"},
+{"name": "barry yen"},
+{"name": "shane gaskill"},
+{"name": "mark lauseng"},
+{"name": "karina mysp"},
+{"name": "jake thiem"},
+{"name": "michael reuter"},
+{"name": "joe malliae"},
+{"name": "ron williams"},
+{"name": "brian apple"},
+{"name": "sue nielsen"},
+{"name": "gary bonifas"},
+{"name": "lauren derosa"},
+{"name": "terry wooten"},
+{"name": "dewayne williams"},
+{"name": "tim darr"},
+{"name": "nicole boggi"},
+{"name": "anna sanchez"},
+{"name": "michael yee"},
+{"name": "april coiteux"},
+{"name": "brian eberman"},
+{"name": "peter hyan"},
+{"name": "ellen shvetz"},
+{"name": "golden rod"},
+{"name": "lynn bussey"},
+{"name": "tammy fairchild"},
+{"name": "dan flannery"},
+{"name": "tammy lawver"},
+{"name": "nick paint"},
+{"name": "james long"},
+{"name": "sharon marche"},
+{"name": "kristen grone"},
+{"name": "chris fisher"},
+{"name": "ken nuernberg"},
+{"name": "tom kinney"},
+{"name": "jeff genz"},
+{"name": "daniela cabrera"},
+{"name": "greg petrillo"},
+{"name": "colin stenstrom"},
+{"name": "claire tart"},
+{"name": "jason fox"},
+{"name": "beth shelton"},
+{"name": "nikki nicolet"},
+{"name": "scott connolly"},
+{"name": "eddie dibenedetto"},
+{"name": "rudy camaro"},
+{"name": "erin wilson"},
+{"name": "joe mabrey"},
+{"name": "matt cara"},
+{"name": "nathan ellis"},
+{"name": "paul sandoval"},
+{"name": "dan rehbehn"},
+{"name": "harry falco"},
+{"name": "art cordova"},
+{"name": "lisa hoffert"},
+{"name": "ashley taylor"},
+{"name": "stanley hall"},
+{"name": "nick hatz"},
+{"name": "tim lytle"},
+{"name": "jenny keul"},
+{"name": "davida richardson"},
+{"name": "mike krause"},
+{"name": "billy clark"},
+{"name": "jay bridges"},
+{"name": "martin small"},
+{"name": "jesus gaona"},
+{"name": "rena p"},
+{"name": "jessica zalkind"},
+{"name": "don saxton"},
+{"name": "george cagala"},
+{"name": "deb farmer"},
+{"name": "tyler beck"},
+{"name": "clyde w"},
+{"name": "travis bible"},
+{"name": "ivan limongan"},
+{"name": "eva raphael"},
+{"name": "steve egan"},
+{"name": "darryl delaney"},
+{"name": "heather schlenker"},
+{"name": "matt guice"},
+{"name": "melissa stephens"},
+{"name": "heather parkinson"},
+{"name": "paul condry"},
+{"name": "jeff sharffe"},
+{"name": "ann gorka"},
+{"name": "chris grandparents"},
+{"name": "tim massaquoi"},
+{"name": "spencer bullivant"},
+{"name": "mike machak"},
+{"name": "libby russell"},
+{"name": "robert levack"},
+{"name": "steve ewart"},
+{"name": "rachael gortner"},
+{"name": "gary windham"},
+{"name": "mike cenat"},
+{"name": "barb young"},
+{"name": "richard turkanis"},
+{"name": "teresa oakley"},
+{"name": "chris hogervorst"},
+{"name": "mae bailey"},
+{"name": "andy r"},
+{"name": "kevin jamaica"},
+{"name": "logan fry"},
+{"name": "logan dickens"},
+{"name": "adam gone"},
+{"name": "rob hm"},
+{"name": "jimmy burgin"},
+{"name": "vivian standage"},
+{"name": "tracy fuller"},
+{"name": "amanda gracia"},
+{"name": "wendy alvarado"},
+{"name": "al bulenza"},
+{"name": "bryan kartzman"},
+{"name": "warren yoder"},
+{"name": "james d"},
+{"name": "bob minkus"},
+{"name": "marcus morrow"},
+{"name": "keith cockerham"},
+{"name": "larry western"},
+{"name": "david powers"},
+{"name": "richard mcgrath"},
+{"name": "willow daycare"},
+{"name": "rick conte"},
+{"name": "lolita booker"},
+{"name": "melissa morales"},
+{"name": "lauren blasi"},
+{"name": "alan kling"},
+{"name": "craig bishop"},
+{"name": "deanna drain"},
+{"name": "jeremy lo"},
+{"name": "nicole haine"},
+{"name": "annette k"},
+{"name": "darren scherer"},
+{"name": "kym storch"},
+{"name": "kelly opdycke"},
+{"name": "rubin harley"},
+{"name": "nadine lilley"},
+{"name": "lynne haudenschield"},
+{"name": "adrian lawson"},
+{"name": "suzie winkler"},
+{"name": "john martinelli"},
+{"name": "chris laisure"},
+{"name": "jimmy duckie"},
+{"name": "susan boothe"},
+{"name": "ron plesser"},
+{"name": "bruce nelson"},
+{"name": "myong kim"},
+{"name": "rachael tanner"},
+{"name": "edie yae"},
+{"name": "jessica bowles"},
+{"name": "elizabeth gogolewski"},
+{"name": "beth winneberger"},
+{"name": "lou northeastscape"},
+{"name": "kari hughes"},
+{"name": "aimee fitzgerald"},
+{"name": "tony redken"},
+{"name": "jason myers"},
+{"name": "oscar meza"},
+{"name": "johnny robertson"},
+{"name": "frank walston"},
+{"name": "nancy watkins"},
+{"name": "marty tomlinson"},
+{"name": "tai kvl"},
+{"name": "liz o'brien"},
+{"name": "dominque myrick"},
+{"name": "jeffery noice"},
+{"name": "allan krebs"},
+{"name": "bill gifford"},
+{"name": "pierre colas"},
+{"name": "matt specht"},
+{"name": "cynthia hilger"},
+{"name": "sara visser"},
+{"name": "john holmgren"},
+{"name": "lisa wong"},
+{"name": "harvey snitzer"},
+{"name": "jeff hill"},
+{"name": "jeremiah wann"},
+{"name": "jane rasmussen"},
+{"name": "jeff everage"},
+{"name": "seymour temkin"},
+{"name": "cheyenne meriweather"},
+{"name": "mark h"},
+{"name": "omar teke"},
+{"name": "krysta murphy"},
+{"name": "daniel walpole"},
+{"name": "trina earle"},
+{"name": "jessica shade"},
+{"name": "jesse mandel"},
+{"name": "rusty hughes"},
+{"name": "herman rusche"},
+{"name": "ryan terrebonne"},
+{"name": "ezra sesser"},
+{"name": "caroline biancamano"},
+{"name": "frank gomez"},
+{"name": "john fernandez"},
+{"name": "hector macias"},
+{"name": "nancy alvarez"},
+{"name": "jamie alvarez"},
+{"name": "michael dimarcangelo"},
+{"name": "ashley sugg"},
+{"name": "sean morse"},
+{"name": "william chan"},
+{"name": "lance landis"},
+{"name": "kevin wall"},
+{"name": "angela konopinski"},
+{"name": "doug ervin"},
+{"name": "harvey neighbor"},
+{"name": "mary neupauer"},
+{"name": "troy sneed"},
+{"name": "heather dale"},
+{"name": "donita cole"},
+{"name": "ashley artopolous"},
+{"name": "janet kwan"},
+{"name": "rick landlord"},
+{"name": "linda rehrig"},
+{"name": "keith buter"},
+{"name": "denise nguyen"},
+{"name": "joseph darby"},
+{"name": "emily kliner"},
+{"name": "quinn gardner"},
+{"name": "phil brock"},
+{"name": "gerry smith"},
+{"name": "steven douglass"},
+{"name": "troy harrison"},
+{"name": "scott mcmanus"},
+{"name": "erica morgan"},
+{"name": "dave trance"},
+{"name": "candy redmond"},
+{"name": "david henderson"},
+{"name": "doug wattenschaidt"},
+{"name": "greg kyander"},
+{"name": "kelly combs"},
+{"name": "doug myers"},
+{"name": "annie clark"},
+{"name": "derek stanton"},
+{"name": "will fidler"},
+{"name": "judy aguayo"},
+{"name": "jack wong"},
+{"name": "keith tanner"},
+{"name": "rob kelley"},
+{"name": "lori p"},
+{"name": "maria guevara"},
+{"name": "kimberly dickens"},
+{"name": "john baily"},
+{"name": "dave badger"},
+{"name": "dan chaphalkar"},
+{"name": "patricia wells"},
+{"name": "john werback"},
+{"name": "carolyn sinnard"},
+{"name": "gary bowker"},
+{"name": "wilson rivas"},
+{"name": "ralph tomas"},
+{"name": "aaron sykes"},
+{"name": "chad hutshko"},
+{"name": "winston catering"},
+{"name": "ryan turman"},
+{"name": "mason harrison"},
+{"name": "clark gilbert"},
+{"name": "daphne venerable"},
+{"name": "lori stushek"},
+{"name": "jim laird"},
+{"name": "robin waterhouse"},
+{"name": "wendy walker"},
+{"name": "kelly rakowski"},
+{"name": "steve yost"},
+{"name": "daniel ceola"},
+{"name": "howard cardin"},
+{"name": "jamie wesselman"},
+{"name": "rachel swarthout"},
+{"name": "gary stevenson"},
+{"name": "monica music"},
+{"name": "meghan opa"},
+{"name": "jan mooshagian"},
+{"name": "michelle tracy"},
+{"name": "teri lynn"},
+{"name": "nathan rutledge"},
+{"name": "shondra wygal"},
+{"name": "john priestman"},
+{"name": "joe jugovic"},
+{"name": "arthur simrel"},
+{"name": "in boise"},
+{"name": "greg dann"},
+{"name": "mary osborn"},
+{"name": "crystal hayes"},
+{"name": "doug bass"},
+{"name": "gail banaszak"},
+{"name": "johnny clark"},
+{"name": "devin warner"},
+{"name": "richard sosnovy"},
+{"name": "ed perry"},
+{"name": "jason pace"},
+{"name": "david v"},
+{"name": "daisy blood"},
+{"name": "sam young"},
+{"name": "jerry aufox"},
+{"name": "lauren fortuni"},
+{"name": "alex marshal"},
+{"name": "susan james"},
+{"name": "sean downey"},
+{"name": "bill ragle"},
+{"name": "brandon luna"},
+{"name": "amy sasser"},
+{"name": "amy stagner"},
+{"name": "jaime hill"},
+{"name": "jenna fischer"},
+{"name": "michael eugene"},
+{"name": "patty darnell"},
+{"name": "mike tarala"},
+{"name": "tina rudasill"},
+{"name": "dana perea"},
+{"name": "lorena mejia"},
+{"name": "paula light"},
+{"name": "jean viallet"},
+{"name": "stefan williams"},
+{"name": "aaron ritter"},
+{"name": "teresa tibbs"},
+{"name": "pearl nguyen"},
+{"name": "blake blumquist"},
+{"name": "jarrett posner"},
+{"name": "richard leano"},
+{"name": "debra aharonian"},
+{"name": "shawn baker"},
+{"name": "chris nguyen"},
+{"name": "jenny decarlo"},
+{"name": "chad tracy"},
+{"name": "don fitzgerald"},
+{"name": "cris alcanatara"},
+{"name": "john korellis"},
+{"name": "yolanda rivera"},
+{"name": "gene wells"},
+{"name": "erin lesser"},
+{"name": "kate geo"},
+{"name": "ken pellett"},
+{"name": "brandon baxley"},
+{"name": "joel broader"},
+{"name": "jennifer lara"},
+{"name": "leanna wilson"},
+{"name": "phung tien"},
+{"name": "christine kennedy"},
+{"name": "mark flanders"},
+{"name": "lloyd alterman"},
+{"name": "kristine pruett"},
+{"name": "alex thomas"},
+{"name": "dwayne stoltz"},
+{"name": "dexter doctor"},
+{"name": "nick allen"},
+{"name": "bob bryant"},
+{"name": "dennis patton"},
+{"name": "linda voidt"},
+{"name": "tommy wood"},
+{"name": "judy ziegler"},
+{"name": "richard himmelfarb"},
+{"name": "micheal riche"},
+{"name": "jenny church"},
+{"name": "todd schleibaum"},
+{"name": "mario martinez"},
+{"name": "toby fowler"}
+]
diff --git a/tests/auto/daemon/map-join-sourceuuids.json b/tests/auto/daemon/map-join-sourceuuids.json
new file mode 100644
index 00000000..ae319568
--- /dev/null
+++ b/tests/auto/daemon/map-join-sourceuuids.json
@@ -0,0 +1,60 @@
+[
+ {
+ "_type": "_schemaType",
+ "name": "MagicView",
+ "schema": {
+ "type": "object",
+ "extends": "View"
+ }
+ },
+ {
+ "_type": "_schemaType",
+ "name": "Foo",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "magic": {
+ "type": "string",
+ "indexed": true
+ }
+ }
+ }
+ },
+ {
+ "_type": "_schemaType",
+ "name": "Bar",
+ "schema": {
+ "type": "object",
+ "extends": "Foo"
+ }
+ },
+ {
+ "_type": "Map",
+ "sourceType": "Foo",
+ "targetType": "MagicView",
+ "map": " \
+ function map(obj, context) { \
+ var foo, bar; \
+ if (!context) { \
+ foo = obj; \
+ jsondb.lookup('magic', foo.magic, foo); \
+ } else { \
+ foo = context; \
+ bar = obj; \
+ if (bar._type === 'Bar') { // Needed until the lookup API changes to include the _type \
+ jsondb.emitViewObject(foo.magic, { foo: foo._uuid, bar: bar._uuid, barExtra: bar.extra }); \
+ } else { \
+ // Got Foo actually \
+ } \
+ } \
+ } "
+ },
+ {
+ "_type": "Bar",
+ "magic": "xyzzy"
+ },
+ {
+ "_type": "Foo",
+ "magic": "xyzzy"
+ }
+]
diff --git a/tests/auto/daemon/map-join.json b/tests/auto/daemon/map-join.json
new file mode 100644
index 00000000..36effabb
--- /dev/null
+++ b/tests/auto/daemon/map-join.json
@@ -0,0 +1,77 @@
+[
+ {
+ "name": "John",
+ "_type": "Person"
+ },
+ {
+ "name": "Robert",
+ "_type": "Person"
+ },
+ {
+ "name": "Ben",
+ "_type": "Person"
+ },
+ {
+ "name": "Sam",
+ "_type": "Person"
+ },
+ {
+ "name": "Frank",
+ "_type": "Person"
+ },
+ {
+ "name": "Steve",
+ "_type": "Person"
+ },
+ {
+ "name": "Gary",
+ "_type": "Person"
+ },
+ {
+ "name": "Bruce",
+ "_type": "Person"
+ },
+ {
+ "name": "Paul",
+ "_type": "Person"
+ },
+ {
+ "name": "George",
+ "_type": "Person"
+ },
+ {
+ "_type": "_schemaType",
+ "name": "FoafPerson",
+ "schema": {
+ "_type": "object",
+ "extends": "View",
+ "properties": {
+ "value" : {
+ "type": "object",
+ "properties": {
+ "friend": {
+ "type": "string",
+ "indexed": true
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "_type": "Map",
+ "sourceType": "Person",
+ "targetType": "FoafPerson",
+ "map": " \
+ function map(p, context) { \
+ if (!context) { \
+ if ((p.friend === undefined) || (p.friend === null)) \
+ jsondb.emitViewObject(p.name, { friend: null }); \
+ else \
+ jsondb.lookupWithType('_uuid', p.friend, 'Person', { person: p }); \
+ } else { \
+ jsondb.emitViewObject(context.person.name, { friend: context.person.friend, foaf: p.friend }); \
+ } \
+ }"
+ }
+]
diff --git a/tests/auto/daemon/map-reduce-schema.json b/tests/auto/daemon/map-reduce-schema.json
new file mode 100644
index 00000000..9893b98a
--- /dev/null
+++ b/tests/auto/daemon/map-reduce-schema.json
@@ -0,0 +1,92 @@
+[
+ {
+ "_type": "Contact",
+ "displayName": "Joe Smith",
+ "name": {
+ "firstName": "joe",
+ "lastName": "smith"
+ },
+ "preferredNumber": "+15555551212",
+ "phoneNumbers": [
+ {
+ "type": "mobile",
+ "number": "+15555551212"
+ },
+ {
+ "type": "work",
+ "number": "+17812232323"
+ },
+ {
+ "type": "home",
+ "number": "+16174532300"
+ }
+ ]
+ },
+ {
+ "_type": "Contact",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "doe"
+ },
+ "preferredNumber": "+14567891234",
+ "phoneNumbers": [
+ {
+ "type": "mobile",
+ "number": "+14567891234"
+ },
+ {
+ "type": "home",
+ "number": "+16174532300"
+ }
+ ]
+ },
+ {
+ "_type": "_schemaType",
+ "name": "Phone",
+ "schema": {
+ "type": "object",
+ "extends": "View",
+ "properties": {
+ "value": {
+ "type": "object",
+ "properties": {
+ "displayName": { "type":"string", "required": true }
+ }
+ }
+ }
+ }
+ },
+ {
+ "_type": "_schemaType",
+ "name": "PhoneCount",
+ "schema": {
+ "type": "object",
+ "extends": "View",
+ "properties": {
+ "value": {
+ "type": "object",
+ "properties": {
+ "count": { "type":"integer", "required": true }
+ }
+ }
+ }
+ }
+ },
+ {
+ "_type": "Map",
+ "targetType": "Phone",
+ "sourceType": "Contact",
+ "brokenMap": "function map (c) { for (var i in c.phoneNumbers) { var phone = c.phoneNumbers[i]; jsondb.emitViewObject(phone.number, { name: c.displayName }); }}",
+ "map": "function map (c) { for (var i in c.phoneNumbers) { var phone = c.phoneNumbers[i]; jsondb.emitViewObject(phone.number, { displayName: c.displayName}); }}"
+ },
+ {
+ "_type": "Reduce",
+ "targetType": "PhoneCount",
+ "sourceType": "Phone",
+ "sourceKeyName": "key",
+ "brokenAdd": "function add (k, z, c) { if (!z) {z = { phoneCount: 0 }}; z.phoneCount += 1; return z;}",
+ "add": "function add (k, z, c) { if (!z) {z = { count: 0 }}; z.count += 1; return z;}",
+ "subtract": "function subtract (k, z, c) { if (!z) {z = { count: 0 }}; z.count -= 1; if (z.count > 0) return z;}"
+ }
+]
diff --git a/tests/auto/daemon/map-reduce.json b/tests/auto/daemon/map-reduce.json
new file mode 100644
index 00000000..2fd3165c
--- /dev/null
+++ b/tests/auto/daemon/map-reduce.json
@@ -0,0 +1,74 @@
+[
+ {
+ "_type": "Contact",
+ "displayName": "Joe Smith",
+ "name": {
+ "firstName": "joe",
+ "lastName": "smith"
+ },
+ "preferredNumber": "+15555551212",
+ "phoneNumbers": [
+ {
+ "type": "mobile",
+ "number": "+15555551212"
+ },
+ {
+ "type": "work",
+ "number": "+17812232323"
+ },
+ {
+ "type": "home",
+ "number": "+16174532300"
+ }
+ ]
+ },
+ {
+ "_type": "Contact",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "doe"
+ },
+ "preferredNumber": "+14567891234",
+ "phoneNumbers": [
+ {
+ "type": "mobile",
+ "number": "+14567891234"
+ },
+ {
+ "type": "home",
+ "number": "+16174532322"
+ }
+ ]
+ },
+ {
+ "_type": "_schemaType",
+ "name": "Phone",
+ "schema": {
+ "type": "object",
+ "extends": "View"
+ }
+ },
+ {
+ "_type": "_schemaType",
+ "name": "PhoneCount",
+ "schema": {
+ "type": "object",
+ "extends": "View"
+ }
+ },
+ {
+ "_type": "Map",
+ "targetType": "Phone",
+ "sourceType": "Contact",
+ "map": "function map (c) { for (var i in c.phoneNumbers) { var phone = c.phoneNumbers[i]; jsondb.emitViewObject(phone.number, c.displayName); }}"
+ },
+ {
+ "_type": "Reduce",
+ "targetType": "PhoneCount",
+ "sourceType": "Phone",
+ "sourceKeyName": "key",
+ "add": "function add (k, z, c) { if (!z) {z = {count: 0}}; z.count += 1; return z;}",
+ "subtract": "function subtract (k, z, c) { if (!z) {z = {count: 0}}; z.count -= 1; if (z.count) return z;}"
+ }
+]
diff --git a/tests/auto/daemon/map-sametarget.json b/tests/auto/daemon/map-sametarget.json
new file mode 100644
index 00000000..174b6321
--- /dev/null
+++ b/tests/auto/daemon/map-sametarget.json
@@ -0,0 +1,62 @@
+[
+ {
+ "_type": "_schemaType",
+ "name": "ContactView",
+ "schema": {
+ "type": "object",
+ "extends": "View"
+ }
+ },
+ {
+ "_type": "_schemaType",
+ "name": "ContactView2",
+ "schema": {
+ "type": "object",
+ "extends": "View"
+ }
+ },
+ {
+ "_type": "Map",
+ "targetType": "ContactView",
+ "sourceType": "Contact2",
+ "map": "function map (c) { jsondb.emitViewObject(c.name.lastName, { displayName: c.displayName }); }"
+ },
+ {
+ "_type": "Map",
+ "targetType": "ContactView",
+ "sourceType": "Contact3",
+ "map": "function map (c) { jsondb.emitViewObject(c.name.lastName, { displayName: c.displayName, firstName: c.name.firstName }); }"
+ },
+ {
+ "_type": "Contact2",
+ "displayName": "Joe Smith",
+ "name": {
+ "firstName": "joe",
+ "lastName": "smith"
+ }
+ },
+ {
+ "_type": "Contact3",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "doe"
+ }
+ },
+ {
+ "_type": "Contact2",
+ "displayName": "Joe Johnson",
+ "name": {
+ "firstName": "joe",
+ "lastName": "johnson"
+ }
+ },
+ {
+ "_type": "Contact3",
+ "displayName": "Nancy Jones",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "jones"
+ }
+ }
+]
diff --git a/tests/auto/daemon/pk-capability.json b/tests/auto/daemon/pk-capability.json
new file mode 100644
index 00000000..0570b51d
--- /dev/null
+++ b/tests/auto/daemon/pk-capability.json
@@ -0,0 +1,12 @@
+{
+ "_type": "Capability",
+ "name": "foobar",
+ "accessRules": {
+ "read": {
+ "read": ["[?_type=\"Contact\"]"]
+ },
+ "write": {
+ "write": ["[?_type=\"Contact\"]"]
+ }
+ }
+}
diff --git a/tests/auto/daemon/reduce-array.json b/tests/auto/daemon/reduce-array.json
new file mode 100644
index 00000000..144513a4
--- /dev/null
+++ b/tests/auto/daemon/reduce-array.json
@@ -0,0 +1,52 @@
+[
+ {
+ "_type": "_schemaType",
+ "name": "ArrayView",
+ "schema": {
+ "type": "object",
+ "extends": "View",
+ "properties": {
+ "arrayProp": { "type": "array" }
+ }
+ }
+ },
+ {
+ "_type": "Reduce",
+ "sourceType": "Human",
+ "sourceKeyName": "lastName",
+ "targetType": "ArrayView",
+ "add": " \
+ function add(key, previous, value) { \
+ if (!previous) previous = { firstNames: [] } \
+ previous.firstNames.push(value.firstName); \
+ return previous; \
+ } ",
+ "subtract": " \
+ function subtract(key, previous, value) { \
+ var idx; \
+ if ((idx = previous.firstNames.indexOf(value.firstName)) >= 0) \
+ previous.firstNames.splice(idx, 1); \
+ return previous; \
+ } "
+ },
+ {
+ "_type": "Human",
+ "firstName": "Bob",
+ "lastName": "Smith"
+ },
+ {
+ "_type": "Human",
+ "firstName": "Hank",
+ "lastName": "Jones"
+ },
+ {
+ "_type": "Human",
+ "firstName": "Roger",
+ "lastName": "Smith"
+ },
+ {
+ "_type": "Human",
+ "firstName": "Julio",
+ "lastName": "Jones"
+ }
+]
diff --git a/tests/auto/daemon/reduce-data.json b/tests/auto/daemon/reduce-data.json
new file mode 100644
index 00000000..810bf973
--- /dev/null
+++ b/tests/auto/daemon/reduce-data.json
@@ -0,0 +1,62 @@
+[
+ {
+ "_type": "MyContact",
+ "firstName": "John",
+ "lastName": "Smith"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Harry",
+ "lastName": "Smith"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "John",
+ "lastName": "Jones"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Tom",
+ "lastName": "Jones"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Roger",
+ "lastName": "Moore"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "John",
+ "lastName": "Moore"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Tom",
+ "lastName": "Smith"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "John",
+ "lastName": "Roberts"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Robert",
+ "lastName": "Johns"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Robert",
+ "lastName": "Smith"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Robert",
+ "lastName": "Thomas"
+ },
+ {
+ "_type": "MyContact",
+ "firstName": "Thomas",
+ "lastName": "Roberts"
+ }
+]
diff --git a/tests/auto/daemon/reduce-subprop.json b/tests/auto/daemon/reduce-subprop.json
new file mode 100644
index 00000000..a5002853
--- /dev/null
+++ b/tests/auto/daemon/reduce-subprop.json
@@ -0,0 +1,58 @@
+[
+ {
+ "_type": "Contact",
+ "displayName": "Joe Smith",
+ "name": {
+ "firstName": "joe",
+ "lastName": "smith"
+ }
+ },
+ {
+ "_type": "Contact",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "doe"
+ }
+ },
+ {
+ "_type": "Contact",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "joe",
+ "lastName": "harrison"
+ }
+ },
+ {
+ "_type": "Contact",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "nancy",
+ "lastName": "williams"
+ }
+ },
+ {
+ "_type": "Contact",
+ "displayName": "Nancy Doe",
+ "name": {
+ "firstName": "doug",
+ "lastName": "johnson"
+ }
+ },
+ {
+ "_type": "_schemaType",
+ "name": "NameCount",
+ "schema": {
+ "type": "object",
+ "extends": "View"
+ }
+ },
+ {
+ "_type": "Reduce",
+ "targetType": "NameCount",
+ "sourceType": "Contact",
+ "sourceKeyName": "name.firstName",
+ "add": "function add (k, z, c) { if (!z) { z = { count: 0 } }; z.count += 1; return z;}",
+ "subtract": "function subtract (k, z, c) { if (!z) {z = {count: 0}}; z.count -= 1; if (z.count) return z;}"
+ }
+]
diff --git a/tests/auto/daemon/reduce.json b/tests/auto/daemon/reduce.json
new file mode 100644
index 00000000..182f9c93
--- /dev/null
+++ b/tests/auto/daemon/reduce.json
@@ -0,0 +1,23 @@
+[
+ {
+ "_type": "_schemaType",
+ "name": "MyContactCount",
+ "schema": {
+ "type": "object",
+ "extends": "View",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ {
+ "_type": "Reduce",
+ "targetType": "MyContactCount",
+ "sourceType": "MyContact",
+ "sourceKeyName": "firstName",
+ "add": "function add (k, z, c) { if (!z) {z = {count: 0}}; z.count += 1; return z;}",
+ "subtract": "function subtract (k, z, c) { if (!z) {z = {count: 0}}; z.count -= 1; if (z.count) return z;}"
+ }
+]
diff --git a/tests/auto/daemon/schemas/TestView.json b/tests/auto/daemon/schemas/TestView.json
new file mode 100644
index 00000000..9f37750e
--- /dev/null
+++ b/tests/auto/daemon/schemas/TestView.json
@@ -0,0 +1,10 @@
+{
+ "type": "object",
+ "extends": "View",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ }
+}
+
diff --git a/tests/auto/daemon/schemas/address.json b/tests/auto/daemon/schemas/address.json
new file mode 100644
index 00000000..76f5bdce
--- /dev/null
+++ b/tests/auto/daemon/schemas/address.json
@@ -0,0 +1,17 @@
+{
+ "type": "object",
+ "properties": {
+ "name": {
+ "properties": {
+ "street": {
+ "indexed": true,
+ "type": "string"
+ },
+ "number": {
+ "type": "number"
+ }
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/daemon/schemas/contact.json b/tests/auto/daemon/schemas/contact.json
new file mode 100644
index 00000000..168ef20b
--- /dev/null
+++ b/tests/auto/daemon/schemas/contact.json
@@ -0,0 +1,18 @@
+{
+ "type": "object",
+ "properties": {
+ "name": {
+ "properties": {
+ "first": {
+ "indexed": true,
+ "type": "string"
+ },
+ "last": {
+ "indexed": true,
+ "type": "string"
+ }
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/daemon/schemas/ephemeral.json b/tests/auto/daemon/schemas/ephemeral.json
new file mode 100644
index 00000000..a065a976
--- /dev/null
+++ b/tests/auto/daemon/schemas/ephemeral.json
@@ -0,0 +1,19 @@
+{
+ "type": "object",
+ "ephemeral": "true",
+ "properties": {
+ "name": {
+ "properties": {
+ "first": {
+ "indexed": true,
+ "type": "string"
+ },
+ "last": {
+ "indexed": true,
+ "type": "string"
+ }
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/daemon/testjsondb.cpp b/tests/auto/daemon/testjsondb.cpp
new file mode 100644
index 00000000..bb0b6150
--- /dev/null
+++ b/tests/auto/daemon/testjsondb.cpp
@@ -0,0 +1,3924 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QByteArray>
+#include <QFile>
+#include <QFileInfo>
+#include <QDir>
+#include <QTime>
+#include <QUuid>
+
+#ifdef USE_VALGRIND
+#include <valgrind/memcheck.h>
+#else
+#define VALGRIND_DO_LEAK_CHECK
+#endif
+
+#include "json.h"
+
+#include "jsondb.h"
+
+#include <QtJsonDbQson/private/qson_p.h>
+#include <QtJsonDbQson/private/qsonparser_p.h>
+#include <QtJsonDbQson/private/qsonstrings_p.h>
+
+#include "jsondb.h"
+#include "aodb.h"
+#include "objecttable.h"
+#include "jsondbbtreestorage.h"
+#include "jsondbindex.h"
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+
+#include "../../shared/util.h"
+
+namespace QtAddOn { namespace JsonDb {
+extern bool gValidateSchemas;
+extern bool gDebug;
+extern bool gVerbose;
+} } // end namespace QtAddOn::JsonDb
+
+#ifndef QT_NO_DEBUG_OUTPUT
+#define DBG() if (gDebug) qDebug()
+#else
+#define DBG() if (0) qDebug()
+#endif
+
+Q_USE_JSONDB_NAMESPACE
+
+static QString kContactStr = "com.noklab.nrcc.jsondb.unittest.contact";
+
+/*
+ Ensure that a good result object contains the correct fields
+ */
+
+#define verifyGoodResult(result) \
+{ \
+ QsonMap __result = result; \
+ QVERIFY(__result.contains(JsonDbString::kErrorStr)); \
+ QVERIFY2(__result.isNull(JsonDbString::kErrorStr), __result.subObject(JsonDbString::kErrorStr).valueString("message").toLocal8Bit()); \
+ QVERIFY(__result.contains(JsonDbString::kResultStr)); \
+}
+
+// QsonMap result, QString field, QVariant expectedValue
+#define verifyResultField(result, field, expectedValue) \
+{ \
+ QsonMap map = result.subObject(JsonDbString::kResultStr); \
+ QVERIFY(map.contains(field)); \
+ QCOMPARE(qsonToVariant(map.value<QsonElement>(field)), QVariant(expectedValue)); \
+}
+
+/*
+ Ensure that a error result contains the correct fields
+ */
+
+#define verifyErrorResult(result) \
+{\
+ QVERIFY(result.contains(JsonDbString::kErrorStr)); \
+ if (result.valueType(JsonDbString::kErrorStr) != QsonObject::MapType ) \
+ qDebug() << "verifyErrorResult" << result; \
+ QCOMPARE(result.valueType(JsonDbString::kErrorStr), QsonObject::MapType ); \
+ QVariantMap errormap = qsonToVariant(result.value<QsonMap>(JsonDbString::kErrorStr)).toMap(); \
+ QVERIFY(errormap.contains(JsonDbString::kCodeStr)); \
+ QCOMPARE(errormap.value(JsonDbString::kCodeStr).type(), QVariant::LongLong ); \
+ QVERIFY(errormap.contains(JsonDbString::kMessageStr)); \
+ QCOMPARE(errormap.value(JsonDbString::kMessageStr).type(), QVariant::String ); \
+ QVERIFY(result.contains(JsonDbString::kResultStr)); \
+ QVERIFY(result.subObject(JsonDbString::kResultStr).isEmpty() \
+ || (result.subObject(JsonDbString::kResultStr).contains("count") \
+ && result.subObject(JsonDbString::kResultStr).valueInt("count", 0) == 0)); \
+}
+
+class TestJsonDb: public QObject
+{
+ Q_OBJECT
+public:
+ TestJsonDb();
+
+public slots:
+ void notified(const QString, QsonMap, const QString);
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void cleanup();
+
+ void reopen();
+
+ void create();
+
+ void update();
+ void update2();
+ void update3();
+ void update4();
+
+ void remove();
+ void remove2();
+ void remove3();
+ void remove4();
+
+ void schemaValidation_data();
+ void schemaValidation();
+ void schemaValidationExtends_data();
+ void schemaValidationExtends();
+ void schemaValidationExtendsArray_data();
+ void schemaValidationExtendsArray();
+ void schemaValidationLazyInit();
+
+ void createList();
+ void updateList();
+
+ void mapDefinition();
+ void mapDefinitionInvalid();
+ void reduceDefinition();
+ void reduceDefinitionInvalid();
+ void mapInvalidMapFunc();
+ void reduceInvalidAddSubtractFuncs();
+ void map();
+ void mapDuplicateSourceAndTarget();
+ void mapRemoval();
+ void mapUpdate();
+ void mapJoin();
+ void mapSelfJoinSourceUuids();
+ void mapMapFunctionError();
+ void mapSchemaViolation();
+ void mapEmptyKey();
+ void reduce();
+ void reduceRemoval();
+ void reduceUpdate();
+ void reduceDuplicate();
+ void reduceFunctionError();
+ void reduceSchemaViolation();
+ void reduceSubObjectProp();
+ void reduceArray();
+ void changesSinceCreate();
+
+ void capabilities();
+ void allowAll();
+
+#if 0
+ void testAccessControl();
+ void testFindAccessControl();
+ void permissionsCleared();
+#endif
+
+ void addIndex();
+ void addSchema();
+ void duplicateSchema();
+ void removeSchema();
+ void removeViewSchema();
+ void updateSchema();
+ void parseQuery();
+ void orQuery_data();
+ void orQuery();
+ void unindexedFind();
+ void find1();
+ void find2();
+ void findFields();
+ void testNotify1();
+
+ void findLikeRegexp_data();
+ void findLikeRegexp();
+ void findInContains();
+
+ void wildcardIndex();
+ void uuidJoin();
+
+ void orderedFind1_data();
+ void orderedFind1();
+ void orderedFind2_data();
+ void orderedFind2();
+
+ void findByName();
+ void findEQ();
+ void find10();
+
+ void testPrimaryKey();
+ void testStoredProcedure();
+
+ void startsWith();
+ void comparison();
+
+ void removedObjects();
+ void partition();
+ void arrayIndexQuery();
+ void deindexError();
+ void expectedOrder();
+ void indexQueryOnCommonValues();
+
+public:
+ void createContacts();
+
+private:
+ void dumpObjects();
+ void addSchema(const QString &schemaName, QsonMap &schemaObject);
+
+ QsonObject readJsonFile(const QString &filename);
+ QsonObject readJson(const QByteArray& json);
+ void removeDbFiles();
+
+private:
+ JsonDb *mJsonDb;
+ JsonDbBtreeStorage *mJsonDbStorage;
+ QStringList mNotificationsReceived;
+ QList<QsonMap> mContactList;
+ JsonDbOwner *mOwner;
+};
+
+const char *kFilename = "testdatabase";
+//const char *kFilename = ":memory:";
+const QString kReplica1Name = QString("replica1");
+const QString kReplica2Name = QString("replica2");
+const QStringList kReplicaNames = (QStringList() << kReplica1Name << kReplica2Name);
+
+TestJsonDb::TestJsonDb()
+ : mJsonDb(NULL), mJsonDbStorage(0), mOwner(0)
+{
+}
+
+void TestJsonDb::removeDbFiles()
+{
+ QStringList filters;
+ filters << QLatin1String("*.db")
+ << "objectFile.bin" << "objectFile2.bin";
+ QStringList lst = QDir().entryList(filters);
+ foreach (const QString &fileName, lst)
+ QFile::remove(fileName);
+}
+
+void TestJsonDb::initTestCase()
+{
+ qsrand(QDateTime::currentDateTime().toTime_t());
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("testjsondb");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ removeDbFiles();
+ gVerbose = false;
+ mJsonDb = new JsonDb(kFilename, this);
+ mOwner = new JsonDbOwner(this);
+ mOwner->setOwnerId("com.noklab.nrcc.JsonDbTest");
+
+ mJsonDb->open();
+}
+
+void TestJsonDb::cleanupTestCase()
+{
+ VALGRIND_DO_LEAK_CHECK
+ if (mJsonDb) {
+ mJsonDb->close();
+ delete mJsonDb;
+ mJsonDb = 0;
+ }
+ removeDbFiles();
+}
+
+void TestJsonDb::cleanup()
+{
+// QCOMPARE(mJsonDb->mStorage->mTransactionDepth, 0);
+ //QVERIFY(mJsonDb->checkValidity());
+}
+
+void TestJsonDb::reopen()
+{
+ int counter = 1;
+ for (int i = 0; i < 10; ++i, ++counter) {
+ QsonMap item;
+ item.insert(QLatin1String("_type"), QLatin1String("reopentest"));
+ item.insert("create-string", QString("string"));
+ QsonMap result = mJsonDb->create(mOwner, item);
+
+ mJsonDb->close();
+ delete mJsonDb;
+
+ mJsonDb = new JsonDb(kFilename, this);
+ mJsonDb->open();
+
+ QsonMap request;
+ request.insert("query", QLatin1String("[?_type=\"reopentest\"]"));
+ result = mJsonDb->find(mOwner, request);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(counter));
+ QCOMPARE(result.subObject("result").subList("data").size(), counter);
+ }
+}
+
+void TestJsonDb::createContacts()
+{
+ if (!mContactList.isEmpty())
+ return;
+
+VALGRIND_DO_LEAK_CHECK
+
+ QFile contactsFile(findFile(SRCDIR, "largeContactsTest.json"));
+ QVERIFY2(contactsFile.exists(), "Err: largeContactsTest.json doesn't exist!");
+
+ contactsFile.open(QIODevice::ReadOnly);
+ QByteArray json = contactsFile.readAll();
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok)
+ qDebug() << parser.errorString();
+ QVariantList contactList = parser.result().toList();
+ QList<QsonMap> newContactList;
+ foreach (QVariant v, contactList) {
+ QsonMap contact(variantToQson(v.toMap()));
+ QString name = contact.valueString("name");
+ QStringList names = name.split(" ");
+ QsonMap nameObject;
+ nameObject.insert("first", names[0]);
+ nameObject.insert("last", names[names.size()-1]);
+ contact.insert("name", nameObject);
+ contact.insert(JsonDbString::kTypeStr, QString("contact"));
+ verifyGoodResult(mJsonDb->create(mOwner, contact));
+ newContactList.append(QsonParser::fromRawData(contact.data()).toMap());
+ }
+ mContactList = newContactList;
+
+ mJsonDb->addIndex(QLatin1String("name"));
+ mJsonDb->addIndex(QLatin1String("name.first"));
+ mJsonDb->addIndex(QLatin1String("name.last"));
+ mJsonDb->addIndex(QLatin1String("_type"));
+
+VALGRIND_DO_LEAK_CHECK
+
+}
+
+void TestJsonDb::addSchema(const QString &schemaName, QsonMap &schemaObject)
+{
+ QsonObject schema = readJsonFile(QString("schemas/%1.json").arg(schemaName));
+ schemaObject = QsonMap();
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", schemaName);
+ schemaObject.insert("schema", schema);
+
+ QsonMap result = mJsonDb->create(mOwner, schemaObject);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::duplicateSchema()
+{
+ QsonObject schema = readJsonFile("schemas/address.json");
+ QsonMap schemaObject;
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", QLatin1String("Address"));
+ schemaObject.insert("schema", schema);
+
+ QsonMap result = mJsonDb->create(mOwner, schemaObject);
+ verifyGoodResult(result);
+
+ QsonMap schemaObject2;
+ schemaObject2.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject2.insert("name", QLatin1String("Address"));
+ schemaObject2.insert("schema", schema);
+ result = mJsonDb->create(mOwner, schemaObject2);
+ verifyErrorResult(result);
+
+ result = mJsonDb->remove(mOwner, schemaObject);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::removeSchema()
+{
+ QsonObject schema = readJsonFile("schemas/address.json");
+ QsonMap schemaObject;
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", QLatin1String("Address"));
+ schemaObject.insert("schema", schema);
+
+ QsonMap result = mJsonDb->create(mOwner, schemaObject);
+ verifyGoodResult(result);
+
+ QsonMap address;
+ address.insert(JsonDbString::kTypeStr, QLatin1String("Address"));
+ address.insert("street", QLatin1String("Main Street"));
+ address.insert("number", 1);
+
+ result = mJsonDb->create(mOwner, address);
+ verifyGoodResult(result);
+
+ result = mJsonDb->remove(mOwner, schemaObject);
+ verifyErrorResult(result);
+
+ result = mJsonDb->remove(mOwner, address);
+ verifyGoodResult(result);
+
+ result = mJsonDb->remove(mOwner, schemaObject);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::removeViewSchema()
+{
+ QsonList objects = readJsonFile("reduce.json").toList();
+ QsonObject schema;
+ QsonObject reduce;
+ for (int i = 0; i < objects.size(); ++i) {
+ QsonMap object = objects.at<QsonMap>(i);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Reduce")
+ reduce = object;
+ else
+ schema = object;
+ }
+
+ QsonMap result = mJsonDb->remove(mOwner, schema);
+ verifyErrorResult(result);
+
+ result = mJsonDb->remove(mOwner, reduce);
+ verifyGoodResult(result);
+
+ result = mJsonDb->remove(mOwner, schema);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::updateSchema()
+{
+ QsonMap schema = readJsonFile("schemas/address.json").toMap();
+ QsonMap schemaObject;
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", QLatin1String("Address"));
+ schemaObject.insert("schema", schema);
+
+ QsonMap schemaResult = mJsonDb->create(mOwner, schemaObject);
+ verifyGoodResult(schemaResult);
+
+ QsonMap address;
+ address.insert(JsonDbString::kTypeStr, QLatin1String("Address"));
+ address.insert("street", QLatin1String("Main Street"));
+ address.insert("number", 1);
+
+ QsonMap result = mJsonDb->create(mOwner, address);
+ verifyGoodResult(result);
+
+ schema.insert("streetNumber", schema.subObject("number"));
+ schemaObject.insert("schema", schema);
+ result = mJsonDb->update(mOwner, schemaObject);
+ verifyErrorResult(result);
+
+ result = mJsonDb->remove(mOwner, address);
+ verifyGoodResult(result);
+
+ result = mJsonDb->update(mOwner, schemaObject);
+ verifyGoodResult(result);
+
+ result = mJsonDb->remove(mOwner, schemaObject);
+ verifyGoodResult(result);
+}
+
+/*
+ * Create an item
+ */
+void TestJsonDb::create()
+{
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QString("create-test-type"));
+ item.insert("create-test", 22);
+ item.insert("create-string", QString("string"));
+
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ qDebug() << "create result" << result;
+
+ QsonMap map = result.value<QsonMap>(JsonDbString::kResultStr);
+ QVERIFY(map.contains(JsonDbString::kUuidStr));
+ QVERIFY(!map.valueString(JsonDbString::kUuidStr).isEmpty());
+ QCOMPARE(map.valueType(JsonDbString::kUuidStr), QsonObject::StringType);
+
+ QVERIFY(map.contains(JsonDbString::kVersionStr));
+ QVERIFY(!map.valueString(JsonDbString::kVersionStr).isEmpty());
+ QCOMPARE(map.valueType(JsonDbString::kVersionStr), QsonObject::StringType);
+
+ QsonMap query;
+ query.insert("query", QString("[?_uuid=\"%1\"]").arg(map.valueString(JsonDbString::kUuidStr)));
+ result = mJsonDb->find(mOwner, query);
+ QsonMap findMap = result.subObject("result");
+ QCOMPARE(findMap.valueInt("length"), qint64(1));
+ QCOMPARE(findMap.subList("data").size(), 1);
+ QCOMPARE(findMap.subList("data").objectAt(0).valueString(JsonDbString::kUuidStr), map.valueString(JsonDbString::kUuidStr));
+ QCOMPARE(findMap.subList("data").objectAt(0).valueString(JsonDbString::kVersionStr), map.valueString(JsonDbString::kVersionStr));
+}
+
+/*
+ * Verify translation of capabilities to access control policies.
+ */
+void TestJsonDb::capabilities()
+{
+ QsonList viewDefinitions(readJsonFile("capabilities-test.json").toList());
+ //qDebug() << "viewDefinitions" << viewDefinitions;
+ for (int i = 0; i < viewDefinitions.size(); ++i) {
+ QsonMap object = viewDefinitions.at<QsonMap>(i);
+ //qDebug() << "object" << object;
+ if (object.valueString("_type") == "CapabilitiesTest") {
+ QScopedPointer<JsonDbOwner> owner(new JsonDbOwner());
+ owner->setOwnerId(object.valueString("identifier"));
+ QsonMap capabilities(object.subObject("capabilities"));
+ owner->setCapabilities(capabilities, mJsonDb);
+ } else {
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ }
+ }
+}
+
+/*
+ * Verify the allowAll flag on owner
+ */
+void TestJsonDb::allowAll()
+{
+ // can delete me when this goes away
+ bool acp = gEnforceAccessControlPolicies;
+ gEnforceAccessControlPolicies = true;
+
+ JsonDbOwner *owner = new JsonDbOwner();
+ owner->setAllowedObjects("read", QStringList());
+ owner->setAllowedObjects("write", QStringList());
+ owner->setStorageQuota(-1);
+
+ QsonMap toPut;
+ toPut.insert("_type", QLatin1String("TestObject"));
+
+ QsonMap result = mJsonDb->create(owner, toPut);
+ verifyErrorResult(result);
+
+ QsonMap toPut2;
+ toPut2.insert("_type", QLatin1String("TestObject"));
+
+ owner->setAllowAll(true);
+ result = mJsonDb->create(owner, toPut2);
+ verifyGoodResult(result);
+
+ gEnforceAccessControlPolicies = acp;
+}
+
+/*
+ * Create an item and verify access control
+ */
+
+#if 0
+void TestJsonDb::testAccessControl()
+{
+ QSet<QString> emptySet;
+ QSet<QString> myTypes;
+ myTypes.insert("create-test-type");
+ QSet<QString> otherTypes;
+ otherTypes.insert("other-test-type");
+ QSet<QString> myDomains;
+ myDomains.insert("my-domain");
+ QSet<QString> otherDomains;
+ otherDomains.insert("other-domain");
+
+ //qDebug() << "isAllowed" << mOwner->isAllowed("create-test-type", mOwner->ownerId(), "create");
+
+ QStringList ops = (QStringList() /* << "read" */ << "write");
+ for (int k = 0; k < ops.size(); k++) {
+ QString op = ops[k];
+ for (int i = 0; i < 4; i++) {
+ mOwner->setAllowedTypes(op, ((i % 2) == 0) ? myTypes : otherTypes);
+ mOwner->setProhibitedTypes(op, emptySet);
+ if (i >= 2)
+ mOwner->setProhibitedTypes(op, ((i % 2) == 0) ? otherTypes : myTypes);
+
+ for (int j = 0; j < 4; j++) {
+ mOwner->setAllowedDomains(op, ((j % 2) == 0) ? myDomains : otherDomains);
+ mOwner->setProhibitedDomains(op, emptySet);
+ if (j >= 2)
+ mOwner->setProhibitedDomains(op, ((j % 2) == 0) ? otherDomains : myDomains);
+
+ //qDebug() << "isAllowed" << op << i << j << mOwner->isAllowed("create-test-type", mOwner->ownerId(), op);
+ QsonObject item;
+ QString type = "create-test-type";
+ QString domain = "my-domain";
+ item.insert(JsonDbString::kTypeStr, type);
+ item.insert(JsonDbString::kDomainStr, domain);
+ item.insert("create-test", 22);
+
+ QsonObject result = mJsonDb->create(mOwner, item);
+
+ if ((mOwner->allowedDomains("write").isEmpty() || mOwner->allowedDomains("write").contains(domain))
+ && !mOwner->prohibitedDomains("write").contains(domain)
+ && (mOwner->allowedTypes("write").isEmpty() || mOwner->allowedTypes("write").contains(type))
+ && !mOwner->prohibitedTypes("write").contains(type))
+ verifyGoodResult(result);
+ else
+ verifyErrorResult(result);
+
+ if (result.subObject(JsonDbString::kErrorStr).isEmpty()) {
+ //if (op != "create")
+ //item.insert(JsonDbString::kUuidStr, item.value(JsonDbString::kUuidStr));
+ result = mJsonDb->update(mOwner, item);
+ verifyGoodResult(result);
+
+ result = mJsonDb->remove(mOwner, item);
+ verifyGoodResult(result);
+ }
+ }
+ }
+
+ mOwner->setAllowedTypes(op, emptySet);
+ mOwner->setAllowedDomains(op, emptySet);
+ mOwner->setProhibitedTypes(op, emptySet);
+ mOwner->setProhibitedDomains(op, emptySet);
+ }
+}
+
+void TestJsonDb::testFindAccessControl()
+{
+ QSet<QString> emptySet;
+ QSet<QString> myTypes;
+ myTypes.insert("create-test-type");
+ QSet<QString> otherTypes;
+ otherTypes.insert("other-test-type");
+ QSet<QString> myDomains;
+ myDomains.insert("my-domain");
+ QSet<QString> otherDomains;
+ otherDomains.insert("other-owner-id");
+
+ QsonObject item;
+ item.insert(JsonDbString::kTypeStr, "create-test-type");
+ item.insert(JsonDbString::kDomainStr, "my-domain");
+ item.insert("create-test", 22);
+ QsonObject result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ QsonMap request;
+ request.insert(JsonDbString::kQueryStr, QString("[?%1=\"%2\"]").arg(JsonDbString::kTypeStr).arg("create-test-type"));
+
+ //qDebug() << "isAllowed" << mOwner->isAllowed("create-test-type", mOwner->ownerId(), "create");
+
+ QStringList ops = (QStringList() << "read");
+ for (int k = 0; k < ops.size(); k++) {
+ QString op = ops[k];
+ for (int i = 0; i < 4; i++) {
+ mOwner->setAllowedTypes(op, ((i % 2) == 0) ? myTypes : otherTypes);
+ mOwner->setProhibitedTypes(op, emptySet);
+ if (i >= 2)
+ mOwner->setProhibitedTypes(op, ((i % 2) == 0) ? otherTypes : myTypes);
+
+ for (int j = 0; j < 4; j++) {
+ mOwner->setAllowedDomains(op, ((j % 2) == 0) ? myDomains : otherDomains);
+ mOwner->setProhibitedDomains(op, emptySet);
+ if (j >= 2)
+ mOwner->setProhibitedDomains(op, ((j % 2) == 0) ? otherDomains : myDomains);
+
+ //qDebug() << "isAllowed" << op << i << j << mOwner->isAllowed("create-test-type", mOwner->ownerId(), op);
+ QsonObject result = mJsonDb->find(mOwner, request);
+ //if (op != "create")
+ //item.insert(JsonDbString::kUuidStr, item.value(JsonDbString::kUuidStr));
+ if (op == "update")
+ result = mJsonDb->update(mOwner, item);
+ if (op == "remove")
+ result = mJsonDb->remove(mOwner, item);
+ verifyGoodResult(result);
+ QsonObject map = result.value("result").toMap();
+ int length = (map.contains("length") ? map.value("length").toInt() : 0);
+ if (((i % 2) == 0) && ((j % 2) == 0)) {
+// if (!length) {
+// qDebug() << "isAllowed" << op << i << j << mOwner->isAllowed("create-test-type", mOwner->ownerId(), op);
+// qDebug() << result;
+// }
+ QVERIFY(map.contains("length"));
+ QVERIFY(map.value("length").toInt() >= 1);
+ } else {
+// if (length) {
+// qDebug() << "isAllowed" << op << i << j << mOwner->isAllowed("create-test-type", mOwner->ownerId(), op);
+// qDebug() << result;
+// qDebug() << "mOwner->allowedTypes(op)" << mOwner->allowedTypes(op);
+// qDebug() << "mOwner->allowedDomains(op)" << mOwner->allowedDomains(op);
+// qDebug() << "mOwner->prohibitedTypes(op)" << mOwner->prohibitedTypes(op);
+// qDebug() << "mOwner->prohibitedDomains(op)" << mOwner->prohibitedDomains(op);
+// }
+ QVERIFY(map.contains("length"));
+ QCOMPARE(map.value("length").toInt(), 0);
+ }
+ }
+ }
+
+// qDebug() << __FUNCTION__ << "Clearing permissions for op" << op;
+ emptySet = QSet<QString>();
+ mOwner->setAllowedTypes(op, emptySet);
+ mOwner->setAllowedDomains(op, emptySet);
+ mOwner->setProhibitedTypes(op, emptySet);
+ mOwner->setProhibitedDomains(op, emptySet);
+ }
+}
+
+void TestJsonDb::permissionsCleared()
+{
+ QStringList ops = (QStringList() << "find" << "create" << "update" << "remove");
+ for (int k = 0; k < ops.size(); k++) {
+ QString op = ops[k];
+ QSet<QString> emptySet;
+ mOwner->setAllowedTypes(op, emptySet);
+ mOwner->setAllowedDomains(op, emptySet);
+ mOwner->setProhibitedTypes(op, emptySet);
+ mOwner->setProhibitedDomains(op, emptySet);
+ }
+ for (int k = 0; k < ops.size(); k++) {
+ QString op = ops[k];
+ //qDebug() << __FUNCTION__ << op;
+ //qDebug() << "mOwner->allowedTypes(op)" << mOwner->allowedTypes(op);
+ QCOMPARE(mOwner->allowedTypes(op).size(), 0);
+ //qDebug() << "mOwner->allowedDomains(op)" << mOwner->allowedDomains(op);
+ QCOMPARE(mOwner->allowedDomains(op).size(), 0);
+ //qDebug() << "mOwner->prohibitedTypes(op)" << mOwner->prohibitedTypes(op);
+ QCOMPARE(mOwner->prohibitedTypes(op).size(), 0);
+ //qDebug() << "mOwner->prohibitedDomains(op)" << mOwner->prohibitedDomains(op);
+ QCOMPARE(mOwner->prohibitedDomains(op).size(), 0);
+ }
+}
+#endif
+
+/*
+ * Insert an item and then update it.
+ */
+
+void TestJsonDb::update()
+{
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("update-test-type"));
+ item.insert("update-test", 100);
+ item.insert("update-string", QLatin1String("update-test-100"));
+
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+ QString uuid = result.subObject(JsonDbString::kResultStr).valueString(JsonDbString::kUuidStr);
+
+ item.insert(JsonDbString::kUuidStr, uuid);
+ item.insert("update-test", 101);
+
+ result = mJsonDb->update(mOwner, item);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr,1);
+}
+
+/*
+ * Update an item which doesn't exist
+ */
+
+void TestJsonDb::update2()
+{
+ QsonMap item;
+ item.insert("update2-test", 100);
+ item.insert("_type", QString("update-from-null"));
+ item.generateUuid();
+
+ QsonMap result = mJsonDb->update(mOwner, item);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr,1);
+}
+
+/*
+ * Update an item which doesn't have a "uuid" field
+ */
+
+void TestJsonDb::update3()
+{
+ QsonMap item;
+ item.insert("update2-test", 100);
+
+ QsonMap result = mJsonDb->update(mOwner, item);
+ verifyErrorResult(result);
+}
+
+/*
+ * Update a stale copy of an item
+ */
+
+void TestJsonDb::update4()
+{
+ bool prev = gRejectStaleUpdates;
+ gRejectStaleUpdates = true;
+
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("update-test-type"));
+ item.insert("update-test", 100);
+ item.insert("update-string", QLatin1String("update-test-100"));
+
+ //qDebug(">>> CREATE");
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+ QString uuid = result.subObject(JsonDbString::kResultStr).valueString(JsonDbString::kUuidStr);
+
+ QString version1 = result.subObject(JsonDbString::kResultStr).valueString(JsonDbString::kVersionStr);
+ //qDebug() << "<<< CREATE, version is" << version1;
+
+ item.insert(JsonDbString::kUuidStr, uuid);
+ item.insert(JsonDbString::kVersionStr, version1);
+ item.insert("update-test", 101);
+
+ //qDebug(">>> UPDATE");
+ result = mJsonDb->update(mOwner, item);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr,1);
+ verifyResultField(result,JsonDbString::kUuidStr, uuid);
+
+ QString version2 = result.subObject(JsonDbString::kResultStr).valueString(JsonDbString::kVersionStr);
+ QVERIFY(version1 != version2);
+
+ //qDebug() << "<<< UPDATE, version is" << version2;
+
+ //qDebug() << ">>> REREAD" << uuid;
+ QsonMap query;
+ query.insert("query", QString("[?_uuid=\"%1\"]").arg(uuid));
+ result = mJsonDb->find(mOwner, query);
+ QsonMap findMap = result.subObject("result");
+ //qDebug() << "re-read after update" << findMap;
+ QCOMPARE(findMap.valueInt("length"), qint64(1));
+ QCOMPARE(findMap.subList("data").size(), 1);
+ QCOMPARE(findMap.subList("data").objectAt(0).valueString(JsonDbString::kUuidStr), uuid);
+ QCOMPARE(findMap.subList("data").objectAt(0).valueString(JsonDbString::kVersionStr), version2);
+ //qDebug() << "<<< REREAD" << uuid;
+
+
+ // replay
+ //qDebug(">>> REPLAY");
+ item.insert(JsonDbString::kVersionStr, version1);
+ result = mJsonDb->update(mOwner, item);
+ verifyGoodResult(result);
+ verifyResultField(result, JsonDbString::kCountStr,1);
+ verifyResultField(result, JsonDbString::kUuidStr, uuid);
+ verifyResultField(result, JsonDbString::kVersionStr, version2);
+ //qDebug() << "<<< REPLAY";
+
+ // conflict
+ item.insert(JsonDbString::kVersionStr, version1);
+ item.insert("update-test", 102);
+ //qDebug(">>> CONFLICT");
+ result = mJsonDb->update(mOwner, item);
+ qDebug() << result;
+ verifyErrorResult(result);
+ //qDebug("<<< CONFLICT");
+
+ // conflict as replication
+ item.insert(JsonDbString::kVersionStr, version1);
+ item.insert("update-test", 102);
+ //qDebug(">>> REPLICATE");
+ result = mJsonDb->update(mOwner, item, QString(), true);
+ verifyGoodResult(result);
+
+ query.insert("query", QString("[?_uuid=\"%1\"]").arg(uuid));
+ result = mJsonDb->find(mOwner, query);
+ findMap = result.subObject("result");
+ QCOMPARE(findMap.valueInt("length"), qint64(1));
+ QCOMPARE(findMap.subList("data").size(), 1);
+
+ QsonMap conflict = findMap.subList("data").objectAt(0);
+ //qDebug() << "Object with conflict embedded" << conflict;
+ QCOMPARE(conflict.valueString(JsonDbString::kUuidStr), uuid);
+ QCOMPARE(conflict.subObject(QsonStrings::kMetaStr).subList(QsonStrings::kConflictsStr).size(), 1);
+ //qDebug("<<< REPLICATE");
+
+ gRejectStaleUpdates = prev;
+}
+
+/*
+ * Create an item and immediately remove it
+ */
+
+void TestJsonDb::remove()
+{
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("remove-test-type"));
+ item.insert("remove-test", 100);
+
+ QsonMap response = mJsonDb->create(mOwner, item);
+ verifyGoodResult(response);
+ QsonMap result = response.value<QsonMap>(JsonDbString::kResultStr);
+
+ QString uuid = result.valueString(JsonDbString::kUuidStr);
+ QString version = result.valueString(JsonDbString::kVersionStr);
+
+ item.insert(JsonDbString::kUuidStr, uuid);
+ item.insert(JsonDbString::kVersionStr, uuid);
+
+ result = mJsonDb->remove(mOwner, item);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr, 1);
+
+ QsonMap query;
+ query.insert("query", QString("[?_uuid=\"%1\"]").arg(uuid));
+ result = mJsonDb->find(mOwner, query);
+ QsonMap findMap = result.subObject("result");
+ QCOMPARE(findMap.valueInt("length"), qint64(0));
+ QCOMPARE(findMap.subList("data").size(), 0);
+}
+
+/*
+ * Try to remove an item which doesn't exist
+ */
+
+void TestJsonDb::remove2()
+{
+ QsonMap item;
+ item.insert("remove2-test", 100);
+ item.insert(JsonDbString::kTypeStr, QLatin1String("Remove2Type"));
+ item.insert(JsonDbString::kUuidStr, QUuid::createUuid().toString());
+
+ QsonMap result = mJsonDb->remove(mOwner, item);
+ verifyErrorResult(result);
+}
+
+/*
+ * Don't include a 'uuid' field
+ */
+
+void TestJsonDb::remove3()
+{
+ QsonMap item;
+ item.insert("remove3-test", 100);
+
+ QsonMap result = mJsonDb->remove(mOwner, item);
+ verifyErrorResult(result);
+}
+
+/*
+ * Try to remove an item which existed before but was removed
+ */
+void TestJsonDb::remove4()
+{
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("remove-test-type"));
+ item.insert("remove-test", 100);
+
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+ QString uuid = result.value<QsonMap>(JsonDbString::kResultStr).valueString(JsonDbString::kUuidStr);
+ item.insert(JsonDbString::kUuidStr, uuid);
+
+ result = mJsonDb->remove(mOwner, item);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr, 1);
+
+ result = mJsonDb->remove(mOwner, item);
+ verifyErrorResult(result);
+ result = mJsonDb->remove(mOwner, item);
+ verifyErrorResult(result);
+}
+
+void TestJsonDb::schemaValidation_data()
+{
+ QTest::addColumn<QByteArray>("schema");
+ QTest::addColumn<QByteArray>("object");
+ QTest::addColumn<bool>("result"); // is an object valid against a schema?
+
+ QByteArray schema, object;
+ bool result;
+
+ const QString dataDir = QString::fromLatin1(":/json-validation/");
+ QDir dir(dataDir);
+ QStringList schemaNames = dir.entryList(QStringList() << "*-schema.json");
+
+ Q_ASSERT_X(schemaNames.count(), Q_FUNC_INFO, "Tests not found");
+
+ foreach (const QString &schemaFileName, schemaNames) {
+ QFile schemeFile(dataDir + schemaFileName);
+ schemeFile.open(QIODevice::ReadOnly);
+ schema = schemeFile.readAll();
+ const QString testName = schemaFileName.mid(0, schemaFileName.length() - 12); // chop "-schema.json"
+ QStringList tests = dir.entryList(QStringList() << (testName + "*"));
+ foreach (const QString &test, tests) {
+ if (test.endsWith("-schema.json"))
+ continue;
+
+ QFile objectFile(dataDir + test);
+ objectFile.open(QIODevice::ReadOnly);
+ object = objectFile.readAll();
+ result = !test.endsWith("invalid.json");
+ QTest::newRow(test.toLatin1().data()) << schema << object << result;
+ }
+ }
+}
+
+void TestJsonDb::schemaValidation()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ QFETCH(QByteArray, schema);
+ QFETCH(QByteArray, object);
+ QFETCH(bool, result);
+
+ static uint id = 0;
+ id++;
+ QString schemaName = QLatin1String("schemaValidationSchema") + QString::number(id);
+
+ QsonMap schemaBody = readJson(schema);
+ QsonMap schemaObject;
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", schemaName);
+ schemaObject.insert("schema", schemaBody);
+
+ QsonMap qResult = mJsonDb->create(mOwner, schemaObject);
+ verifyGoodResult(qResult);
+
+ QsonMap item = readJson(object);
+ item.insert(JsonDbString::kTypeStr, schemaName);
+
+ // Create an item that matches the schema
+ qResult = mJsonDb->create(mOwner, item);
+ if (result) {
+ verifyGoodResult(qResult);
+ } else {
+ verifyErrorResult(qResult);
+ }
+ if (result) {
+ qResult = mJsonDb->remove(mOwner, item);
+ verifyGoodResult(qResult);
+ }
+ qResult = mJsonDb->remove(mOwner, schemaObject);
+ verifyGoodResult(qResult);
+
+
+ gValidateSchemas = validate;
+}
+
+void TestJsonDb::schemaValidationExtends_data()
+{
+ QTest::addColumn<QByteArray>("item");
+ QTest::addColumn<bool>("isPerson");
+ QTest::addColumn<bool>("isAdult");
+
+ QTest::newRow("empty")
+ << QByteArray("{}") << true << true;
+ QTest::newRow("40 and 4")
+ << QByteArray("{ \"name\":\"40 and 4\" }") << true << true;
+ QTest::newRow("Alice")
+ << QByteArray("{ \"name\":\"Alice\", \"age\": 5}") << true << false;
+ QTest::newRow("Alice's mother")
+ << QByteArray("{ \"name\":\"Alice's mother\", \"age\": 32}") << true << true;
+ QTest::newRow("Alice's grandmother")
+ << QByteArray("{ \"name\":\"Alice's grandmother\", \"age\": 100}") << true << true;
+ QTest::newRow("Alice's great-grandmother")
+ << QByteArray("{ \"name\":\"Alice's great-grandmother\", \"age\": 130}") << false << false;
+}
+
+void TestJsonDb::schemaValidationExtends()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ QFETCH(QByteArray, item);
+ QFETCH(bool, isPerson);
+ QFETCH(bool, isAdult);
+
+ static int id = 0; // schema name id
+ ++id;
+ const QString personSchemaName = QString::fromLatin1("person") + QString::number(id);
+ const QString adultSchemaName = QString::fromLatin1("adult") + QString::number(id);
+
+ // init schemas
+ QsonMap qResult;
+ {
+ const QByteArray person =
+ "{"
+ " \"description\": \"A person\","
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"name\": {\"type\": \"string\"},"
+ " \"age\" : {\"type\": \"integer\", \"maximum\": 125 }"
+ " }"
+ "}";
+ const QByteArray adult = QString::fromLatin1(
+ "{"
+ " \"description\": \"An adult\","
+ " \"properties\": {\"age\": {\"minimum\": 18}},"
+ " \"extends\": {\"$ref\":\"person%1\"}"
+ "}").arg(QString::number(id)).toLatin1();
+ QsonMap personSchemaBody = readJson(person);
+ QsonMap adultSchemaBody = readJson(adult);
+
+ QsonMap personSchemaObject;
+ personSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ personSchemaObject.insert("name", personSchemaName);
+ personSchemaObject.insert("schema", personSchemaBody);
+
+ QsonMap adultSchemaObject;
+ adultSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ adultSchemaObject.insert("name", adultSchemaName);
+ adultSchemaObject.insert("schema", adultSchemaBody);
+
+ qResult = mJsonDb->create(mOwner, personSchemaObject);
+ verifyGoodResult(qResult);
+ qResult = mJsonDb->create(mOwner, adultSchemaObject);
+ verifyGoodResult(qResult);
+ }
+
+ {
+ QsonMap object = readJson(item);
+ object.insert("testingForPerson", isPerson);
+ object.insert(JsonDbString::kTypeStr, personSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+// qDebug() << "person: " << qResult << isPerson << isAdult;
+ if (isPerson) {
+ verifyGoodResult(qResult);
+ } else {
+ verifyErrorResult(qResult);
+ }
+ }
+
+ {
+ QsonMap object = readJson(item);
+ object.insert("testingForAdult", isAdult);
+ object.insert(JsonDbString::kTypeStr, adultSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+// qDebug() << "adult: " << qResult << isPerson << isAdult;
+ if (isAdult) {
+ verifyGoodResult(qResult);
+ } else {
+ verifyErrorResult(qResult);
+ }
+ }
+
+ gValidateSchemas = validate;
+}
+
+
+void TestJsonDb::schemaValidationExtendsArray_data()
+{
+ QTest::addColumn<QByteArray>("item");
+ QTest::addColumn<bool>("isValid");
+
+ QTest::newRow("empty")
+ << QByteArray("{}") << false;
+ QTest::newRow("fiat 125p")
+ << QByteArray("{ \"landSpeed\": 5}") << false;
+ QTest::newRow("bavaria 44")
+ << QByteArray("{ \"waterSpeed\": 6}") << false;
+ QTest::newRow("orukter amphibolos")
+ << QByteArray("{ \"waterSpeed\":10, \"landSpeed\": 10}") << true;
+ QTest::newRow("batmans car")
+ << QByteArray("{ \"waterSpeed\":100, \"landSpeed\": 100, \"airSpeed\": 100}") << true;
+}
+
+void TestJsonDb::schemaValidationExtendsArray()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ QFETCH(QByteArray, item);
+ QFETCH(bool, isValid);
+
+ static int id = 0; // schema name id
+ ++id;
+ const QString amphibiousSchemaName = QString::fromLatin1("amphibious") + QString::number(id);
+ const QString carSchemaName = QString::fromLatin1("car") + QString::number(id);
+ const QString boatSchemaName = QString::fromLatin1("boat") + QString::number(id);
+
+ // init schemas
+ QsonMap qResult;
+ {
+ const QByteArray car =
+ "{"
+ " \"description\": \"A car\","
+ " \"properties\": {\"landSpeed\": {\"required\": true}}"
+ "}";
+
+ const QByteArray boat =
+ "{"
+ " \"description\": \"A boat\","
+ " \"properties\": {\"waterSpeed\": {\"required\": true}}"
+ "}";
+
+ const QByteArray amphibious = QString::fromLatin1(
+ "{"
+ " \"description\": \"A amphibious\","
+ " \"extends\": [{\"$ref\":\"car%1\"}, {\"$ref\":\"boat%1\"}]"
+ "}").arg(QString::number(id)).toLatin1();
+
+ QsonMap amphibiousSchemaBody = readJson(amphibious);
+ QsonMap carSchemaBody = readJson(car);
+ QsonMap boatSchemaBody = readJson(boat);
+
+
+ QsonMap carSchemaObject;
+ carSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ carSchemaObject.insert("name", carSchemaName);
+ carSchemaObject.insert("schema", carSchemaBody);
+
+ QsonMap boatSchemaObject;
+ boatSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ boatSchemaObject.insert("name", boatSchemaName);
+ boatSchemaObject.insert("schema", boatSchemaBody);
+
+ QsonMap amphibiousSchemaObject;
+ amphibiousSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ amphibiousSchemaObject.insert("name", amphibiousSchemaName);
+ amphibiousSchemaObject.insert("schema", amphibiousSchemaBody);
+
+ qResult = mJsonDb->create(mOwner, carSchemaObject);
+ verifyGoodResult(qResult);
+ qResult = mJsonDb->create(mOwner, boatSchemaObject);
+ verifyGoodResult(qResult);
+ qResult = mJsonDb->create(mOwner, amphibiousSchemaObject);
+ verifyGoodResult(qResult);
+ }
+
+ {
+ QsonMap object = readJson(item);
+ object.insert("testingForAmphibious", isValid);
+ object.insert(JsonDbString::kTypeStr, amphibiousSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+ if (isValid) {
+ verifyGoodResult(qResult);
+ } else {
+ verifyErrorResult(qResult);
+ }
+ }
+
+ gValidateSchemas = validate;
+}
+
+void TestJsonDb::schemaValidationLazyInit()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ const QByteArray person =
+ "{"
+ " \"description\": \"A person\","
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"name\": {\"type\": \"string\", \"required\": true},"
+ " \"age\" : {\"type\": \"integer\", \"maximum\": 125 }"
+ " }"
+ "}";
+ const QByteArray adult =
+ "{"
+ " \"description\": \"An adult\","
+ " \"properties\": {\"age\": {\"minimum\": 18}},"
+ " \"extends\": {\"$ref\":\"personLazyInit\"}"
+ "}";
+
+ const QString personSchemaName = QString::fromLatin1("personLazyInit");
+ const QString adultSchemaName = QString::fromLatin1("adultLazyInit");
+
+ QsonMap personSchemaBody = readJson(person);
+ QsonMap adultSchemaBody = readJson(adult);
+
+ QsonMap personSchemaObject;
+ personSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ personSchemaObject.insert("name", personSchemaName);
+ personSchemaObject.insert("schema", personSchemaBody);
+
+ QsonMap adultSchemaObject;
+ adultSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ adultSchemaObject.insert("name", adultSchemaName);
+ adultSchemaObject.insert("schema", adultSchemaBody);
+
+ // Without lazy compilation this operation fails, because adult schema referece unexisting yet
+ // person schema
+ QsonMap qResult;
+ qResult = mJsonDb->create(mOwner, adultSchemaObject);
+ verifyGoodResult(qResult);
+ qResult = mJsonDb->create(mOwner, personSchemaObject);
+ verifyGoodResult(qResult);
+
+ // Insert some objects to force full schema compilation
+ {
+ const QByteArray item = "{ \"name\":\"Nierob\", \"age\":99 }";
+ QsonMap object = readJson(item);
+ object.insert(JsonDbString::kTypeStr, adultSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+ verifyGoodResult(qResult);
+ }
+ {
+ const QByteArray item = "{ \"name\":\"Nierob\", \"age\":12 }";
+ QsonMap object = readJson(item);
+ object.insert(JsonDbString::kTypeStr, adultSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+ verifyErrorResult(qResult);
+ }
+ {
+ const QByteArray item = "{ \"age\":19 }";
+ QsonMap object = readJson(item);
+ object.insert(JsonDbString::kTypeStr, adultSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+ verifyErrorResult(qResult);
+ }
+ {
+ const QByteArray item = "{ \"name\":\"Nierob\", \"age\":12 }";
+ QsonMap object = readJson(item);
+ object.insert(JsonDbString::kTypeStr, personSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+ verifyGoodResult(qResult);
+ }
+ {
+ const QByteArray item = "{ \"age\":12 }";
+ QsonMap object = readJson(item);
+ object.insert(JsonDbString::kTypeStr, personSchemaName);
+ qResult = mJsonDb->create(mOwner, object);
+ verifyErrorResult(qResult);
+ }
+
+ gValidateSchemas = validate;
+}
+
+/*
+ * Create a list of items
+ */
+
+#define LIST_TEST_ITEMS 6
+
+void TestJsonDb::createList()
+{
+ QsonList list;
+ for (int i = 0 ; i < LIST_TEST_ITEMS ; i++ ) {
+ QsonMap map;
+ map.insert(JsonDbString::kTypeStr, QLatin1String("create-list-type"));
+ map.insert("create-list-test", i + 100);
+ list.append(map);
+ }
+
+ QsonMap result = mJsonDb->createList(mOwner, list);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr, LIST_TEST_ITEMS);
+}
+
+/*
+ * Create a list of items and then update them
+ */
+
+void TestJsonDb::updateList()
+{
+ QsonList list;
+ for (int i = 0 ; i < LIST_TEST_ITEMS ; i++ ) {
+ QsonMap map;
+ map.insert(JsonDbString::kTypeStr, QLatin1String("update-list-type"));
+ map.insert("update-list-test", i + 100);
+ QsonMap result = mJsonDb->create(mOwner, map);
+ verifyGoodResult(result);
+ QString uuid = result.value<QsonMap>(JsonDbString::kResultStr).valueString(JsonDbString::kUuidStr);
+ map.insert(JsonDbString::kUuidStr, uuid);
+ map.insert("fuzzyduck", QLatin1String("Duck test"));
+ list.append(map);
+ }
+
+ QsonMap result = mJsonDb->updateList(mOwner, list);
+ verifyGoodResult(result);
+ verifyResultField(result,JsonDbString::kCountStr, LIST_TEST_ITEMS);
+}
+
+void TestJsonDb::mapDefinition()
+{
+ // we need a schema that extends View for our targetType
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QLatin1String("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QLatin1String("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QLatin1String("object"));
+ schemaSub.insert("extends", QLatin1String("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap mapDefinition;
+ mapDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Map"));
+ mapDefinition.insert("targetType", QLatin1String("MyViewType"));
+ mapDefinition.insert("sourceType", QLatin1String("Contact"));
+ mapDefinition.insert("map", QLatin1String("function map (c) { }"));
+
+ QsonMap res = mJsonDb->create(mOwner, mapDefinition);
+ verifyGoodResult(res);
+
+ verifyGoodResult(mJsonDb->remove(mOwner, mapDefinition));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::mapDefinitionInvalid()
+{
+ // we need a schema that extends View for our targetType
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QLatin1String("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QLatin1String("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QLatin1String("object"));
+ schemaSub.insert("extends", QLatin1String("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap mapDefinition;
+ mapDefinition.insert(JsonDbString::kTypeStr, JsonDbString::kMapTypeStr);
+ mapDefinition.insert("sourceType", QLatin1String("Contact"));
+ mapDefinition.insert("map", QLatin1String("function map (c) { }"));
+ QsonMap res = mJsonDb->create(mOwner, mapDefinition);
+ verifyErrorResult(res);
+
+ mapDefinition = QsonMap();
+ mapDefinition.insert(JsonDbString::kTypeStr, JsonDbString::kMapTypeStr);
+ mapDefinition.insert("targetType", QLatin1String("MyViewType"));
+ mapDefinition.insert("map", QLatin1String("function map (c) { }"));
+ res = mJsonDb->create(mOwner, mapDefinition);
+ verifyErrorResult(res);
+
+ mapDefinition = QsonMap();
+ mapDefinition.insert(JsonDbString::kTypeStr, JsonDbString::kMapTypeStr);
+ mapDefinition.insert("targetType", QLatin1String("MyViewType"));
+ mapDefinition.insert("sourceType", QLatin1String("Contact"));
+ res = mJsonDb->create(mOwner, mapDefinition);
+ verifyErrorResult(res);
+
+ // fail because targetType doesn't extend View
+ mapDefinition = QsonMap();
+ mapDefinition.insert(JsonDbString::kTypeStr, JsonDbString::kMapTypeStr);
+ mapDefinition.insert("targetType", QLatin1String("MyViewType2"));
+ mapDefinition.insert("sourceType", QLatin1String("Contact"));
+ mapDefinition.insert("map", QLatin1String("function map (c) { }"));
+ res = mJsonDb->create(mOwner, mapDefinition);
+ verifyErrorResult(res);
+ QVERIFY(res.subObject("error").valueString(JsonDbString::kMessageStr).contains("View"));
+
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::reduceDefinition()
+{
+ // we need a schema that extends View for our targetType
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QLatin1String("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QLatin1String("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QLatin1String("object"));
+ schemaSub.insert("extends", QLatin1String("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap reduceDefinition;
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { }"));
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ QsonMap res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyGoodResult(res);
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduceDefinition));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::reduceDefinitionInvalid()
+{
+ // we need a schema that extends View for our targetType
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QLatin1String("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QLatin1String("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QLatin1String("object"));
+ schemaSub.insert("extends", QLatin1String("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap reduceDefinition;
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { }"));
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ QsonMap res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyErrorResult(res);
+
+ reduceDefinition = QsonMap();
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { }"));
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyErrorResult(res);
+
+ reduceDefinition = QsonMap();
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { }"));
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyErrorResult(res);
+
+ reduceDefinition = QsonMap();
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyErrorResult(res);
+
+ reduceDefinition = QsonMap();
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { }"));
+ res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyErrorResult(res);
+
+ // fail because targetType doesn't extend View
+ reduceDefinition = QsonMap();
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType2"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { }"));
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyErrorResult(res);
+ QVERIFY(res.subObject("error").valueString(JsonDbString::kMessageStr).contains("View"));
+
+ //schemaRes.subObject("result")
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::mapInvalidMapFunc()
+{
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QLatin1String("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QLatin1String("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QLatin1String("object"));
+ schemaSub.insert("extends", QLatin1String("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap mapDefinition;
+ mapDefinition.insert(JsonDbString::kTypeStr, JsonDbString::kMapTypeStr);
+ mapDefinition.insert("targetType", QLatin1String("MyViewType"));
+ mapDefinition.insert("sourceType", QLatin1String("Contact"));
+ mapDefinition.insert("map", QLatin1String("function map (c) { ;")); // non-parsable map function
+
+ QsonMap defRes = mJsonDb->create(mOwner, mapDefinition);
+ verifyGoodResult(defRes);
+ QString uuid = defRes.subObject("result").valueString("_uuid");
+
+ // force the view to be updated
+ mJsonDb->updateView("MyViewType");
+
+ // now check for an error
+ QsonMap res = mJsonDb->getObject("_uuid", uuid, JsonDbString::kMapTypeStr);
+ QVERIFY(res.valueInt("count") > 0);
+ mapDefinition = res.subList("result").objectAt(0);
+ QVERIFY(!mapDefinition.isNull(JsonDbString::kActiveStr) && !mapDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(!mapDefinition.valueString(JsonDbString::kErrorStr).isEmpty());
+
+ verifyGoodResult(mJsonDb->remove(mOwner, mapDefinition));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::reduceInvalidAddSubtractFuncs()
+{
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QLatin1String("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QLatin1String("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QLatin1String("object"));
+ schemaSub.insert("extends", QLatin1String("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap reduceDefinition;
+ reduceDefinition.insert(JsonDbString::kTypeStr, QLatin1String("Reduce"));
+ reduceDefinition.insert("targetType", QLatin1String("MyViewType"));
+ reduceDefinition.insert("sourceType", QLatin1String("Contact"));
+ reduceDefinition.insert("sourceKeyName", QLatin1String("phoneNumber"));
+ reduceDefinition.insert("add", QLatin1String("function add (k, z, c) { ;")); // non-parsable add function
+ reduceDefinition.insert("subtract", QLatin1String("function subtract (k, z, c) { }"));
+ QsonMap res = mJsonDb->create(mOwner, reduceDefinition);
+ verifyGoodResult(res);
+
+ mJsonDb->updateView("MyViewType");
+
+ res = mJsonDb->getObject("_uuid", res.subObject("result").valueString("_uuid"));
+ reduceDefinition = res.subList("result").objectAt(0);
+ QVERIFY(!reduceDefinition.isNull(JsonDbString::kActiveStr) && !reduceDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(!reduceDefinition.valueString(JsonDbString::kErrorStr).isEmpty());
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduceDefinition));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::map()
+{
+ mJsonDb->addIndex(QLatin1String("phoneNumber"));
+
+ //gVerbose = true;
+ //gDebug = true;
+ QsonList objects(readJsonFile("map-reduce.json").toList());
+
+ //qDebug() << "viewDefinitions" << viewDefinitions;
+ QsonList mapsReduces;
+ QsonList schemas;
+ QMap<QString, QsonMap> toDelete;
+ for (int i = 0; i < objects.size(); ++i) {
+ QsonMap object = objects.objectAt(i);
+ //qDebug() << "object" << object;
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+
+ if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kMapTypeStr ||
+ object.valueString(JsonDbString::kTypeStr) == JsonDbString::kReduceTypeStr)
+ mapsReduces.append(object);
+ else if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kSchemaTypeStr)
+ schemas.append(object);
+ else
+ toDelete.insert(object.valueString("_uuid"), object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"Phone\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 5);
+
+ // now remove one of the source items
+ QsonMap query2;
+ query2.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"Contact\"][?displayName=\"Nancy Doe\"]"));
+ result = mJsonDb->find(mOwner, query2);
+ QsonMap firstItem = result.subObject("result").subList("data").at<QsonMap>(0);
+ QVERIFY(!firstItem.valueString("_uuid").isEmpty());
+ toDelete.remove(firstItem.valueString("_uuid"));
+ result = mJsonDb->remove(mOwner, firstItem);
+ verifyGoodResult(result);
+
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 3);
+
+ QsonMap query3;
+ query3.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"PhoneCount\"][/key]"));
+ result = mJsonDb->find(mOwner, query3);
+ verifyGoodResult(result);
+ if (gVerbose)
+ foreach (const QVariant v, qsonToVariant(result.subObject("result").subList("data")).toList()) {
+ qDebug() << " " << v;
+ }
+ QCOMPARE(result.subObject("result").subList("data").size(), 3);
+
+ for (int i = 0; i < mapsReduces.size(); ++i) {
+ QsonObject object = mapsReduces.at<QsonMap>(i);
+ verifyGoodResult(mJsonDb->remove(mOwner, object));
+ }
+ for (int i = 0; i < schemas.size(); ++i) {
+ QsonObject object = schemas.at<QsonMap>(i);
+ verifyGoodResult(mJsonDb->remove(mOwner, object));
+ }
+ foreach (QsonMap map, toDelete.values())
+ verifyGoodResult(mJsonDb->removeList(mOwner, map));
+}
+
+void TestJsonDb::mapDuplicateSourceAndTarget()
+{
+ QsonList objects(readJsonFile("map-sametarget.json"));
+ QsonList toDelete;
+ QsonList maps;
+
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Map")
+ maps.append(object);
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"ContactView\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 4);
+
+ int firstNameCount = 0;
+ QsonList data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++)
+ if (!data.objectAt(ii).subObject("value").valueString("firstName").isEmpty())
+ firstNameCount++;
+ QCOMPARE(firstNameCount, 2);
+
+ for (int ii = 0; ii < maps.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, maps.objectAt(ii)));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+}
+
+void TestJsonDb::mapRemoval()
+{
+ QsonList objects(readJsonFile("map-sametarget.json"));
+
+ QList<QsonMap> maps;
+ QList<QsonMap> toDelete;
+
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Map")
+ maps.append(object);
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"ContactView\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 4);
+
+ // remove a map
+ result = mJsonDb->remove(mOwner, maps.takeAt(0));
+ verifyGoodResult(result);
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+
+ // an now the other
+ result = mJsonDb->remove(mOwner, maps.takeAt(0));
+ verifyGoodResult(result);
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ for (int ii = 0; ii < maps.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, maps.at(ii)));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.at(ii)));
+}
+
+void TestJsonDb::mapUpdate()
+{
+ QsonList objects(readJsonFile("map-sametarget.json"));
+
+ QsonList maps;
+ QsonList toDelete;
+
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Map")
+ maps.append(object);
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"ContactView\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 4);
+
+ // tinker with a map
+ QsonMap map = maps.objectAt(0);
+ map.insert("targetType", QString("ContactView2"));
+ result = mJsonDb->update(mOwner, map);
+ verifyGoodResult(result);
+
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"ContactView2\"]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+
+ for (int ii = 0; ii < maps.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, maps.objectAt(ii)));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+
+}
+
+void TestJsonDb::mapJoin()
+{
+ QsonList objects(readJsonFile("map-join.json").toList());
+
+ QsonMap map;
+ QsonMap schema;
+ QsonList people;
+
+ for (int i = 0; i < objects.size(); ++i) {
+ QsonMap object = objects.at<QsonMap>(i);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ object.insert(JsonDbString::kUuidStr, result.subObject("result").valueString(JsonDbString::kUuidStr));
+
+ if (object.valueString(JsonDbString::kTypeStr) == "Map")
+ map = object;
+ else if (object.valueString(JsonDbString::kTypeStr) == "_schemaType")
+ schema = object;
+ else
+ people.append(object);
+ }
+ mJsonDb->addIndex("value.friend", "string", "FoafPerson");
+ mJsonDb->addIndex("value.foaf", "string", "FoafPerson");
+
+ QsonMap result = mJsonDb->getObject(JsonDbString::kTypeStr, "FoafPerson");
+ QCOMPARE(result.value<int>(JsonDbString::kCountStr), people.count());
+
+ // set some friends
+ QString previous;
+ for (int i = 0; i < people.size(); ++i) {
+ QsonMap person = people.at<QsonMap>(i);
+ if (!previous.isEmpty())
+ person.insert("friend", previous);
+
+ previous = person.valueString(JsonDbString::kUuidStr);
+ //qDebug() << "person" << person.valueString("name") << person.valueString(JsonDbString::kUuidStr) << "friend" << person.valueString("friend");
+ verifyGoodResult(mJsonDb->update(mOwner, person));
+ }
+
+ result = mJsonDb->getObject(JsonDbString::kTypeStr, "Person");
+ QsonList peopleWithFriends = result.value<QsonList>("result");
+
+ QsonMap queryFoafPerson;
+ // sort the list by key to make ordering deterministic
+ queryFoafPerson.insert("query", QString::fromLatin1("[?_type=\"FoafPerson\"][?value.foaf exists][/key]"));
+ QsonMap findResult = mJsonDb->find(mOwner, queryFoafPerson).subObject("result");
+ QCOMPARE(findResult.value<int>(JsonDbString::kLengthStr), people.count()-2); // one has no friend and one is friends with the one with no friends
+
+ QsonList resultList = findResult.subList("data");
+ for (int i = 0; i < resultList.size(); ++i) {
+ QsonMap person = resultList.at<QsonMap>(i);
+ QStringList sources = person.value<QsonList>("sourceUuids").toStringList();
+ //qDebug() << "foafPerson" << i << person.valueString("key") << person.subObject("value");
+ QVERIFY(sources.count() == 1 || sources.contains(person.subObject("value").valueString("friend")));
+ }
+
+ // take the last person, find his friend, and remove that friend's friend property
+ // then make sure the foaf is updated
+ QsonMap p = resultList.at<QsonMap>(resultList.size()-1);
+ if (p.subObject("value").isNull("foaf"))
+ qDebug() << "p" << p << endl;
+ QVERIFY(!p.subObject("value").isNull("foaf"));
+
+ QsonMap fr;
+ for (int i = 0; i < peopleWithFriends.size(); ++i) {
+ QsonMap f = peopleWithFriends.at<QsonMap>(i);
+ if (f.valueString(JsonDbString::kUuidStr) == p.subObject("value").valueString("friend")) {
+ fr = f;
+ break;
+ }
+ }
+
+ QVERIFY(fr.valueString(JsonDbString::kUuidStr) == p.subObject("value").valueString("friend"));
+ fr.insert("friend", QsonObject::NullValue);
+ verifyGoodResult(mJsonDb->update(mOwner, fr));
+
+ QsonMap foafRes = mJsonDb->getObject(JsonDbString::kTypeStr, "FoafPerson");
+ QsonList foafs = foafRes.subList("result");
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"FoafPerson\"][?key=\"%1\"]").arg(p.valueString("key")));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").value<int>("length"), 1);
+
+ p = result.subObject("result").subList("data").at<QsonMap>(0);
+ QVERIFY(!p.subObject("value").valueString("friend").isEmpty());
+ QVERIFY(p.subObject("value").isNull("foaf"));
+
+ query = QsonMap();
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"FoafPerson\"][/key]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ if (0) {
+ qDebug() << endl << result.subObject("result").value<int>("length");
+ for (int i = 0; i < result.subObject("result").value<int>("length"); i++) {
+ QsonMap foaf = result.subObject("result").subList("data").objectAt(i);
+ qDebug() << "unsorted foaf" << foaf.valueString("key") << foaf;
+ }
+ qDebug() << endl;
+ }
+ //QCOMPARE(result.subObject("result").value<int>("length"), 10);
+
+ query = QsonMap();
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"FoafPerson\"][/value.friend]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ if (0) {
+ qDebug() << endl << result.subObject("result").value<int>("length");
+ for (int i = 0; i < result.subObject("result").value<int>("length"); i++) {
+ qDebug() << "sorted foaf" << result.subObject("result").subList("data").objectAt(i);
+ }
+ qDebug() << endl;
+ }
+ QCOMPARE(result.subObject("result").value<int>("length"), 8); // two have no friends
+
+ verifyGoodResult(mJsonDb->remove(mOwner, map));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+ for (int i = 0; i < people.size(); ++i) {
+ QsonMap object = people.at<QsonMap>(i);
+ if (object == map || object == schema)
+ continue;
+ mJsonDb->remove(mOwner, object);
+ }
+}
+
+void TestJsonDb::mapSelfJoinSourceUuids()
+{
+ mJsonDb->addIndex("magic", "string");
+
+ QsonList objects(readJsonFile("map-join-sourceuuids.json").toList());
+ QsonList toDelete;
+ QsonMap toUpdate;
+
+ for (int i = 0; i < objects.size(); ++i) {
+ QsonMap object = objects.at<QsonMap>(i);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ object.insert(JsonDbString::kUuidStr, result.subObject("result").valueString(JsonDbString::kUuidStr));
+ toDelete.append(object);
+
+ if (object.valueString(JsonDbString::kTypeStr) == "Bar")
+ toUpdate = object;
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MagicView\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).subList("sourceUuids").count(), 2);
+
+ toUpdate.insert("extra", QString("123123"));
+ verifyGoodResult(mJsonDb->update(mOwner, toUpdate));
+
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).subList("sourceUuids").count(), 2);
+ for (int i = toDelete.count() - 1; i >= 0; i--)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.at<QsonMap>(i)));
+}
+
+void TestJsonDb::mapMapFunctionError()
+{
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QString("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QString("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QString("object"));
+ schemaSub.insert("extends", QString("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap mapDefinition;
+ mapDefinition.insert(JsonDbString::kTypeStr, QString("Map"));
+ mapDefinition.insert("targetType", QString("MyViewType"));
+ mapDefinition.insert("sourceType", QString("Contact"));
+ mapDefinition.insert("map", QString("function map (c) { invalidobject.fail(); };")); // error in map function
+
+ QsonMap defRes = mJsonDb->create(mOwner, mapDefinition);
+ verifyGoodResult(defRes);
+
+ QsonMap contact;
+ contact.insert(JsonDbString::kTypeStr, QString("Contact"));
+ QsonMap res = mJsonDb->create(mOwner, contact);
+
+ // trigger the view update
+ mJsonDb->updateView("MyViewType");
+
+ // see if the map definition is still active
+ res = mJsonDb->getObject("_uuid", defRes.subObject("result").valueString("_uuid"));
+ mapDefinition = res.subList("result").objectAt(0);
+ QVERIFY(!mapDefinition.isNull(JsonDbString::kActiveStr) && !mapDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(mapDefinition.valueString(JsonDbString::kErrorStr).contains("invalidobject"));
+
+ verifyGoodResult(mJsonDb->remove(mOwner, mapDefinition));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::mapSchemaViolation()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ QsonMap contactsRes = mJsonDb->getObject(JsonDbString::kTypeStr, "Contact");
+ if (contactsRes.valueInt("count") > 0)
+ verifyGoodResult(mJsonDb->removeList(mOwner, contactsRes.subList("result")));
+
+ QsonList objects(readJsonFile("map-reduce-schema.json"));
+ QsonList toDelete;
+ QString workingMap;
+ QsonMap map;
+
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ if (object.valueString(JsonDbString::kTypeStr) != JsonDbString::kReduceTypeStr) {
+
+ // use the broken Map function that creates schema violations
+ if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kMapTypeStr) {
+ workingMap = object.valueString("map");
+ object.insert("map", object.valueString("brokenMap"));
+ }
+
+ QsonMap result = mJsonDb->create(mOwner, object);
+ if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kMapTypeStr) {
+ map = object;
+ }
+
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) != JsonDbString::kMapTypeStr)
+ toDelete.append(object);
+ }
+ }
+
+ mJsonDb->updateView(map.valueString("targetType"));
+
+ QsonMap mapDefinition = mJsonDb->getObject("_uuid", map.valueString(JsonDbString::kUuidStr));
+ QCOMPARE(mapDefinition.subList("result").size(), 1);
+ mapDefinition = mapDefinition.subList("result").objectAt(0);
+ QVERIFY(!mapDefinition.isNull(JsonDbString::kActiveStr) && !mapDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(mapDefinition.valueString(JsonDbString::kErrorStr).contains("Schema"));
+
+ QsonMap res = mJsonDb->getObject(JsonDbString::kTypeStr, "Phone");
+ QCOMPARE(res.value<int>(JsonDbString::kCountStr), 0);
+ // fix the map function
+ map.insert("map", workingMap);
+ map.insert(JsonDbString::kActiveStr, true);
+ map.insert(JsonDbString::kErrorStr, QsonObject::NullValue);
+
+ verifyGoodResult(mJsonDb->update(mOwner, map));
+
+ mJsonDb->updateView(map.valueString("targetType"));
+
+ mapDefinition = mJsonDb->getObject("_uuid", map.valueString(JsonDbString::kUuidStr));
+ mapDefinition = mapDefinition.subList("result").objectAt(0);
+ QVERIFY(mapDefinition.isNull(JsonDbString::kActiveStr)|| mapDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(mapDefinition.isNull(JsonDbString::kErrorStr) || mapDefinition.valueString(JsonDbString::kErrorStr).isEmpty());
+
+ res = mJsonDb->getObject(JsonDbString::kTypeStr, "Phone");
+ QCOMPARE(res.value<int>(JsonDbString::kCountStr), 5);
+
+ verifyGoodResult(mJsonDb->remove(mOwner, map));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+
+ gValidateSchemas = validate;
+}
+
+void TestJsonDb::mapEmptyKey()
+{
+ QsonMap schema;
+ schema.insert(JsonDbString::kTypeStr, QString("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, QString("MyViewType"));
+ QsonMap schemaSub;
+ schemaSub.insert("type", QString("object"));
+ schemaSub.insert("extends", QString("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap map;
+ map.insert(JsonDbString::kTypeStr, QString("Map"));
+ map.insert("targetType", QString("MyViewType"));
+ map.insert("sourceType", QString("MyContact"));
+ map.insert("map", QString("function map (c) { jsondb.emitViewObject('', { name: c.name} );}"));
+
+ QsonMap res = mJsonDb->create(mOwner, map);
+ verifyGoodResult(res);
+
+ QsonMap contact;
+ contact.insert(JsonDbString::kTypeStr, QString("MyContact"));
+ contact.insert("name", QString("Bob Smith"));
+
+ verifyGoodResult(mJsonDb->create(mOwner, contact));
+
+ mJsonDb->updateView("MyViewType");
+
+ QsonMap mapDefinition = mJsonDb->getObject("_uuid", map.valueString(JsonDbString::kUuidStr));
+ mapDefinition = mapDefinition.subList("result").objectAt(0);
+ QVERIFY(!mapDefinition.isNull(JsonDbString::kActiveStr) && !mapDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(mapDefinition.valueString(JsonDbString::kErrorStr).contains("Empty key"));
+
+ verifyGoodResult(mJsonDb->remove(mOwner, contact));
+ verifyGoodResult(mJsonDb->remove(mOwner, map));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::reduce()
+{
+ QsonList objects(readJsonFile("reduce-data.json"));
+
+ QsonList toDelete;
+ QsonList reduces;
+
+ QHash<QString, int> firstNameCount;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ firstNameCount[object.valueString("firstName")]++;
+ toDelete.append(object);
+ }
+
+ objects = readJsonFile("reduce.json");
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Reduce")
+ reduces.append(object);
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query, result;
+ QsonList data;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MyContactCount\"]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), firstNameCount.keys().count());
+
+ data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++) {
+ QCOMPARE(data.objectAt(ii).subObject("value").value<int>("count"), firstNameCount[data.objectAt(ii).valueString("key")]);
+ }
+ for (int ii = 0; ii < reduces.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, reduces.objectAt(ii)));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+}
+
+void TestJsonDb::reduceRemoval()
+{
+ QsonList objects(readJsonFile("reduce-data.json"));
+
+ QsonList toDelete;
+ QHash<QString, int> firstNameCount;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ firstNameCount[object.valueString("firstName")]++;
+ toDelete.append(object);
+ }
+
+ objects = readJsonFile("reduce.json");
+ QsonMap reduce;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Reduce")
+ reduce = object;
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MyContactCount\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), firstNameCount.keys().count());
+
+ result = mJsonDb->remove(mOwner, reduce);
+ verifyGoodResult(result);
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+}
+
+void TestJsonDb::reduceUpdate()
+{
+ QsonList objects(readJsonFile("reduce-data.json"));
+
+ QsonList toDelete;
+ QHash<QString, int> firstNameCount;
+ QHash<QString, int> lastNameCount;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ firstNameCount[object.valueString("firstName")]++;
+ lastNameCount[object.valueString("lastName")]++;
+ toDelete.append(object);
+ }
+
+ objects = readJsonFile("reduce.json");
+ QsonMap reduce;
+ QsonMap schema;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Reduce")
+ reduce = object;
+ else if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kSchemaTypeStr)
+ schema = object;
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MyContactCount\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QsonList data = result.subObject("result").subList("data");
+ QCOMPARE(data.size(), firstNameCount.keys().count());
+
+ for (int ii = 0; ii < data.size(); ii++)
+ QCOMPARE(data.objectAt(ii).subObject("value").value<int>("count"), firstNameCount[data.objectAt(ii).valueString("key")]);
+
+ reduce.insert("sourceKeyName", QString("lastName"));
+ result = mJsonDb->update(mOwner, reduce);
+
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MyContactCount\"]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ data = result.subObject("result").subList("data");
+
+ QCOMPARE(result.subObject("result").subList("data").size(), lastNameCount.keys().count());
+
+ data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++)
+ QCOMPARE(data.objectAt(ii).subObject("value").value<int>("count"), lastNameCount[data.objectAt(ii).valueString("key")]);
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduce));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::reduceDuplicate()
+{
+ QsonList objects(readJsonFile("reduce-data.json"));
+
+ QsonList toDelete;
+ QHash<QString, int> firstNameCount;
+ QHash<QString, int> lastNameCount;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ firstNameCount[object.valueString("firstName")]++;
+ lastNameCount[object.valueString("lastName")]++;
+ toDelete.append(object);
+ }
+
+ objects = readJsonFile("reduce.json");
+ QsonMap reduce;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ if (object.valueString(JsonDbString::kTypeStr) == "Reduce")
+ reduce = object;
+ else
+ toDelete.append(object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MyContactCount\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), firstNameCount.keys().count());
+
+ QsonList data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++) {
+ QsonMap object = data.objectAt(ii);
+ QCOMPARE(object.subObject("value").value<int>("count"), firstNameCount[object.valueString("key")]);
+ }
+
+ QsonMap reduce2;
+ reduce2.insert(JsonDbString::kTypeStr, reduce.valueString(JsonDbString::kTypeStr));
+ reduce2.insert("targetType", reduce.valueString("targetType"));
+ reduce2.insert("sourceType", reduce.valueString("sourceType"));
+ reduce2.insert("sourceKeyName", QString("lastName"));
+ reduce2.insert("add", reduce.valueString("add"));
+ reduce2.insert("subtract", reduce.valueString("subtract"));
+ result = mJsonDb->create(mOwner, reduce2);
+ verifyGoodResult(result);
+
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"MyContactCount\"]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), lastNameCount.keys().count() + firstNameCount.keys().count());
+
+ data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++) {
+ QsonMap object = data.objectAt(ii);
+ QVERIFY(object.subObject("value").value<int>("count") == firstNameCount[object.valueString("key")]
+ || object.subObject("value").value<int>("count") == lastNameCount[object.valueString("key")]);
+ }
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduce));
+ verifyGoodResult(mJsonDb->remove(mOwner, reduce2));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+}
+
+void TestJsonDb::reduceFunctionError()
+{
+ QsonMap schema;
+ QString viewTypeStr("ReduceFunctionErrorView");
+ schema.insert(JsonDbString::kTypeStr, QString("_schemaType"));
+ schema.insert(JsonDbString::kNameStr, viewTypeStr);
+ QsonMap schemaSub;
+ schemaSub.insert("type", QString("object"));
+ schemaSub.insert("extends", QString("View"));
+ schema.insert("schema", schemaSub);
+ QsonMap schemaRes = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(schemaRes);
+
+ QsonMap reduceDefinition;
+ reduceDefinition.insert(JsonDbString::kTypeStr, QString("Reduce"));
+ reduceDefinition.insert("targetType", viewTypeStr);
+ reduceDefinition.insert("sourceType", QString("Contact"));
+ reduceDefinition.insert("sourceKeyName", QString("phoneNumber"));
+ reduceDefinition.insert("add", QString("function add (k, z, c) { invalidobject.test(); }")); // invalid add function
+ reduceDefinition.insert("subtract", QString("function subtract (k, z, c) { }"));
+ QsonMap defRes = mJsonDb->create(mOwner, reduceDefinition);
+ verifyGoodResult(defRes);
+
+ QsonMap contact;
+ contact.insert(JsonDbString::kTypeStr, QString("Contact"));
+ contact.insert("phoneNumber", QString("+1234567890"));
+ QsonMap res = mJsonDb->create(mOwner, contact);
+ verifyGoodResult(res);
+
+ mJsonDb->updateView(viewTypeStr);
+ res = mJsonDb->getObject("_uuid", defRes.subObject("result").valueString("_uuid"), JsonDbString::kReduceTypeStr);
+ reduceDefinition = res.subList("result").objectAt(0);
+ QVERIFY(!reduceDefinition.valueBool(JsonDbString::kActiveStr, false));
+ QVERIFY(reduceDefinition.valueString(JsonDbString::kErrorStr).contains("invalidobject"));
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduceDefinition));
+ verifyGoodResult(mJsonDb->remove(mOwner, schema));
+}
+
+void TestJsonDb::reduceSchemaViolation()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ QsonList objects(readJsonFile("map-reduce-schema.json"));
+
+ QsonList toDelete;
+ QsonMap map;
+ QsonMap reduce;
+ QString workingAdd;
+
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap object = objects.objectAt(ii);
+
+ if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kReduceTypeStr) {
+ // use the broken add function that creates schema violations
+ workingAdd = object.valueString("add");
+ object.insert("add", object.valueString("brokenAdd"));
+ }
+
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+
+ if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kMapTypeStr) {
+ map = object;
+ } else if (object.valueString(JsonDbString::kTypeStr) == JsonDbString::kReduceTypeStr) {
+ reduce = object;
+ } else if (object.valueString(JsonDbString::kTypeStr) != JsonDbString::kMapTypeStr &&
+ object.valueString(JsonDbString::kTypeStr) != JsonDbString::kMapTypeStr)
+ toDelete.append(object);
+
+ }
+
+ mJsonDb->updateView(reduce.valueString("targetType"));
+
+ QsonMap reduceDefinition = mJsonDb->getObject("_uuid", reduce.valueString(JsonDbString::kUuidStr));
+ QCOMPARE(reduceDefinition.subList("result").size(), 1);
+ reduceDefinition = reduceDefinition.subList("result").objectAt(0);
+ QVERIFY(!reduceDefinition.isNull(JsonDbString::kActiveStr) && !reduceDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(reduceDefinition.valueString(JsonDbString::kErrorStr).contains("Schema"));
+
+ QsonMap res = mJsonDb->getObject(JsonDbString::kTypeStr, "PhoneCount");
+ QCOMPARE(res.value<int>(JsonDbString::kCountStr), 0);
+
+ // fix the add function
+ reduce.insert("add", workingAdd);
+ reduce.insert(JsonDbString::kActiveStr, true);
+ reduce.insert(JsonDbString::kErrorStr, QsonObject::NullValue);
+
+ verifyGoodResult(mJsonDb->update(mOwner, reduce));
+
+ mJsonDb->updateView(reduce.valueString("targetType"));
+
+ reduceDefinition = mJsonDb->getObject("_uuid", reduce.valueString(JsonDbString::kUuidStr));
+ reduceDefinition = reduceDefinition.subList("result").objectAt(0);
+ QVERIFY(reduceDefinition.isNull(JsonDbString::kActiveStr)|| reduceDefinition.valueBool(JsonDbString::kActiveStr));
+ QVERIFY(reduceDefinition.isNull(JsonDbString::kErrorStr) || reduceDefinition.valueString(JsonDbString::kErrorStr).isEmpty());
+
+ res = mJsonDb->getObject(JsonDbString::kTypeStr, "PhoneCount");
+ QCOMPARE(res.value<int>(JsonDbString::kCountStr), 4);
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduce));
+ verifyGoodResult(mJsonDb->remove(mOwner, map));
+ for (int ii = 0; ii < toDelete.size(); ii++)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.objectAt(ii)));
+
+ gValidateSchemas = validate;
+}
+
+void TestJsonDb::reduceSubObjectProp()
+{
+ QsonList objects(readJsonFile("reduce-subprop.json").toList());
+
+ QsonList toDelete;
+ QsonObject reduce;
+
+ QHash<QString, int> firstNameCount;
+ for (int i = 0; i < objects.size(); ++i) {
+ QsonMap object = objects.at<QsonMap>(i);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+
+ if (object.valueString(JsonDbString::kTypeStr) == "Reduce") {
+ reduce = object;
+ } else {
+ if (object.valueString(JsonDbString::kTypeStr) == "Contact")
+ firstNameCount[object.subObject("name").valueString("firstName")]++;
+ toDelete.append(object);
+ }
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"NameCount\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), firstNameCount.keys().count());
+
+ QsonList data = result.subObject("result").subList("data");
+ for (int i = 0; i < data.size(); ++i) {
+ QsonMap object = data.at<QsonMap>(i);
+ QCOMPARE(object.subObject("value").value<int>("count"), firstNameCount[object.valueString("key")]);
+ }
+
+ verifyGoodResult(mJsonDb->remove(mOwner, reduce));
+ for (int i = 0; i < toDelete.size(); ++i) {
+ QsonMap object = toDelete.at<QsonMap>(i);
+ verifyGoodResult(mJsonDb->remove(mOwner, object));
+ }
+}
+
+void TestJsonDb::reduceArray()
+{
+ QsonList objects(readJsonFile("reduce-array.json").toList());
+ QsonList toDelete;
+
+ QsonMap human;
+
+ for (int i = 0; i < objects.count(); i++) {
+ QsonMap object = objects.at<QsonMap>(i);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ object.insert(JsonDbString::kUuidStr, result.subObject("result").valueString(JsonDbString::kUuidStr));
+ toDelete.append(object);
+
+ if (object.valueString("firstName") == "Julio")
+ human = object;
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ArrayView\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+
+ QsonList results = result.subObject("result").subList("data");
+ QCOMPARE(results.count(), 2);
+
+ for (int i = 0; i < results.count(); i++) {
+ QsonList firstNames = results.at<QsonMap>(i).subObject("value").subList("firstNames");
+ QCOMPARE(firstNames.count(), 2);
+
+ for (int j = 0; j < firstNames.count(); j++)
+ QVERIFY(!firstNames.at<QString>(j).isEmpty());
+ }
+
+ human.insert("lastName", QString("Johnson"));
+ verifyGoodResult(mJsonDb->update(mOwner, human));
+
+ query.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ArrayView\"][?key=\"Jones\"]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+
+ results = result.subObject("result").subList("data");
+ QCOMPARE(results.at<QsonMap>(0).subObject("value").subList("firstNames").count(), 1);
+
+ for (int i = toDelete.count() - 1; i >= 0; i--)
+ verifyGoodResult(mJsonDb->remove(mOwner, toDelete.at<QsonMap>(i)));
+}
+
+void TestJsonDb::changesSinceCreate()
+{
+ QsonMap csReq;
+ csReq.insert("stateNumber", 0);
+ QsonMap csRes = mJsonDb->changesSince(mOwner, csReq);
+ verifyGoodResult(csRes);
+ int state = csRes.subObject("result").value<int>("currentStateNumber");
+ QVERIFY(state >= 0);
+
+ QsonMap toCreate;
+ toCreate.insert("_type", QString("TestContact"));
+ toCreate.insert("firstName", QString("John"));
+ toCreate.insert("lastName", QString("Doe"));
+
+ QsonMap crRes = mJsonDb->create(mOwner, toCreate);
+ verifyGoodResult(crRes);
+
+ csReq.insert("stateNumber", state);
+ csRes = mJsonDb->changesSince(mOwner, csReq);
+ verifyGoodResult(csRes);
+
+ QVERIFY(csRes.subObject("result").value<int>("currentStateNumber") > state);
+ QCOMPARE(csRes.subObject("result").value<int>("count"), 1);
+
+ QsonMap after = csRes.subObject("result").subList("changes").objectAt(0).subObject("after");
+ QCOMPARE(after.valueString("_type"), toCreate.valueString("_type"));
+ QCOMPARE(after.valueString("firstName"), toCreate.valueString("firstName"));
+ QCOMPARE(after.valueString("lastName"), toCreate.valueString("lastName"));
+}
+
+void TestJsonDb::addIndex()
+{
+ QsonMap result = mJsonDb->addIndex(QLatin1String("subject"));
+ QVERIFY(!result.contains(JsonDbString::kErrorStr));
+
+ QsonMap indexObject;
+ indexObject.insert(JsonDbString::kTypeStr, QLatin1String("Index"));
+ indexObject.insert("fieldName", QLatin1String("predicate"));
+ indexObject.insert("fieldType", QLatin1String("string"));
+
+ result = mJsonDb->create(mOwner, indexObject);
+ verifyGoodResult(result);
+ QVERIFY(mJsonDb->findPartition("default")->findObjectTable(JsonDbString::kSchemaTypeStr)->indexSpec("predicate") != 0);
+}
+
+void TestJsonDb::addSchema()
+{
+ QsonMap s;
+ addSchema("contact", s);
+ verifyGoodResult(mJsonDb->remove(mOwner, s));
+}
+
+void TestJsonDb::unindexedFind()
+{
+ QsonMap item;
+ item.insert("_type", QLatin1String("unindexedFind"));
+ item.insert("subject", QString("Programming Languages"));
+ item.insert("bar", 10);
+ QsonMap createResult = mJsonDb->create(mOwner, item);
+ verifyGoodResult(createResult);
+
+ QsonMap request;
+ request.insert("query", QString("[?bar=10]"));
+ QsonMap result = mJsonDb->find(mOwner, request);
+ int extraneous = 0;
+ QsonList data = result.subList("data");
+ for (int i = 0; i < data.size(); ++i) {
+ QsonMap map = data.at<QsonMap>(i);
+ if (!map.contains("bar") || (map.value<int>("bar") != 10)) {
+ extraneous++;
+ }
+ }
+
+ verifyGoodResult(result);
+ QsonMap map = result.subObject(JsonDbString::kResultStr);
+ QVERIFY(map.contains("length"));
+ QVERIFY((map.value<int>("length") >= 1) && !extraneous);
+}
+
+
+void TestJsonDb::find1()
+{
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QString("Find1Type"));
+ item.insert("find1", QString("Foobar!"));
+ mJsonDb->create(mOwner, item);
+
+ QsonMap query;
+ query.insert("query", QString(".*"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+
+ verifyGoodResult(result);
+ QsonMap map = result.subObject(JsonDbString::kResultStr);
+ QVERIFY(map.contains("length"));
+ QVERIFY(map.value<int>("length") >= 1);
+ QVERIFY(map.contains("data"));
+ QVERIFY(map.subList("data").size() >= 1);
+}
+
+void TestJsonDb::find2()
+{
+ mJsonDb->addIndex(QLatin1String("name"));
+ mJsonDb->addIndex(QLatin1String("_type"));
+
+ QsonList toDelete;
+
+ QsonMap item;
+ item.insert("name", QString("Wilma"));
+ item.insert(JsonDbString::kTypeStr, QString(__FUNCTION__));
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+ toDelete.append(item);
+
+ item = QsonObject();
+ item.insert("name", QString("Betty"));
+ item.insert(JsonDbString::kTypeStr, QString(__FUNCTION__));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+ toDelete.append(item);
+
+ int extraneous;
+
+ QsonMap query;
+ query.insert("query", QString("[?name=\"Wilma\"][?_type=%type]"));
+ QsonMap bindings;
+ bindings.insert("type", QString(__FUNCTION__));
+ query.insert("bindings", bindings);
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+
+ extraneous = 0;
+ foreach (QVariant item, qsonToVariant(result.subList("data")).toList()) {
+ QsonMap map = QsonMap(variantToQson(item));
+ if (!map.contains("name") || (map.valueString("name") != QLatin1String("Wilma")))
+ extraneous++;
+ }
+ verifyGoodResult(result);
+ QsonMap map = result.subObject(JsonDbString::kResultStr);
+ QVERIFY(map.contains("length"));
+ QVERIFY(map.value<int>("length") >= 1);
+ QVERIFY(!extraneous);
+
+
+ query.insert("query", QString("[?_type=%type]"));
+ result = mJsonDb->find(mOwner, query);
+
+ extraneous = 0;
+ foreach (QVariant item, qsonToVariant(result.subList("data")).toList()) {
+ QsonMap map = QsonMap(variantToQson(item));
+ if (!map.contains(JsonDbString::kTypeStr) || (map.valueString(JsonDbString::kTypeStr) != kContactStr))
+ extraneous++;
+ }
+ verifyGoodResult(result);
+ map = result.subObject(JsonDbString::kResultStr);
+ QVERIFY(map.contains("length"));
+ QVERIFY(map.value<int>("length") >= 1);
+ QVERIFY(!extraneous);
+
+ query.insert("query", QString("[?name=\"Wilma\"][?%1=\"%2\"]").arg(JsonDbString::kTypeStr).arg(__FUNCTION__));
+ result = mJsonDb->find(mOwner, query);
+
+ extraneous = 0;
+ foreach (QVariant item, qsonToVariant(result.subList("data")).toList()) {
+ QsonMap map = QsonMap(variantToQson(item.toMap()));
+ if (!map.contains("name") || (map.valueString("name") != QLatin1String("Wilma"))
+ || !map.contains(JsonDbString::kTypeStr) || (map.valueString(JsonDbString::kTypeStr) != kContactStr)
+ )
+ extraneous++;
+ }
+
+ verifyGoodResult(result);
+ map = result.subObject(JsonDbString::kResultStr);
+ QVERIFY(map.contains("length"));
+ QVERIFY(map.value<int>("length") >= 1);
+ QVERIFY(!extraneous);
+
+ for (int ii = 0; ii < toDelete.size(); ii++) {
+ mJsonDb->remove(mOwner, toDelete.objectAt(ii));
+ }
+}
+
+
+QStringList strings = (QStringList()
+ << "abc"
+ << "def"
+ << "deaf"
+ << "leaf"
+ << "DEAF"
+ << "LEAF"
+ << "ghi"
+ << "foo/bar");
+
+QStringList patterns = (QStringList()
+ );
+
+void TestJsonDb::findLikeRegexp_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QString>("modifiers");
+ QTest::newRow("/de.*/") << "de.*" << "";
+ QTest::newRow("/.*a.*/") << ".*a.*" << "";
+ QTest::newRow("/de*/wi") << "de*" << "wi";
+ QTest::newRow("/*a*/w") << "*a*" << "w";
+ QTest::newRow("/de*/wi") << "de*" << "wi";
+ QTest::newRow("/*a*/wi") << "*a*" << "wi";
+ QTest::newRow("/*a*/wi") << "*a*" << "wi";
+ QTest::newRow("/*a/wi") << "*a" << "wi";
+ QTest::newRow("/a*/wi") << "a*" << "wi";
+ QTest::newRow("/c*/wi") << "c*" << "wi";
+ QTest::newRow("/c*/wi") << "c*" << "wi";
+ QTest::newRow("/*a*/w") << "*a*" << "w";
+ QTest::newRow("/*a/w") << "*a" << "w";
+ QTest::newRow("/a*/w") << "a*" << "w";
+ QTest::newRow("/a+/w") << "a+" << "w";
+ QTest::newRow("/c*/w") << "c*" << "w";
+ QTest::newRow("/c*/w") << "c*" << "w";
+ QTest::newRow("/.*foo.*\\/.*/i") << ".*foo.*\\/.*" << "i";
+ QTest::newRow("|.*foo.*/.*|i") << ".*foo.*\\/.*" << "i";
+
+ foreach (QString s, strings) {
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QString("FindLikeRegexpData"));
+ item.insert(__FUNCTION__, QString("Find Me!"));
+ item.insert("key", s);
+ mJsonDb->create(mOwner, item);
+ }
+}
+
+void TestJsonDb::findLikeRegexp()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QString, modifiers);
+ QString q = QString("[?_type=\"%1\"][?key =~ \"/%2/%3\"]").arg("FindLikeRegexpData").arg(pattern).arg(modifiers);
+ Qt::CaseSensitivity cs = (modifiers.contains("i") ? Qt::CaseInsensitive : Qt::CaseSensitive);
+ QRegExp::PatternSyntax ps = (modifiers.contains("w") ? QRegExp::Wildcard : QRegExp::RegExp);
+ QRegExp re(pattern, cs, ps);
+ QStringList expectedMatches;
+ foreach (QString s, strings) {
+ if (re.exactMatch(s))
+ expectedMatches << s;
+ }
+ expectedMatches.sort();
+
+ QsonMap query;
+ query.insert("query", q);
+ QsonMap result = mJsonDb->find(mOwner, query);
+ int length = result.subObject("result").value<int>(QLatin1String("length"));
+ verifyGoodResult(result);
+
+ QStringList matches;
+ foreach (QVariant v, qsonToVariant(result.subObject("result").subList("data")).toList()) {
+ QVariantMap m = v.toMap();
+ matches << m.value("key").toString();
+ }
+ matches.sort();
+ if (matches != expectedMatches) {
+ qDebug() << "query" << q;
+ qDebug() << "expectedMatches" << expectedMatches;
+ qDebug() << "matches" << matches;
+ }
+ QCOMPARE(matches, expectedMatches);
+ QCOMPARE(length, expectedMatches.size());
+}
+
+void TestJsonDb::findInContains()
+{
+ QList<QStringList> stringLists;
+ stringLists << (QStringList() << "fred" << "barney");
+ stringLists << (QStringList() << "wilma" << "betty");
+ QVariantList intLists;
+ intLists << QVariant(QVariantList() << 1 << 22);
+ intLists << QVariant(QVariantList() << 42 << 17);
+
+ for (int i = 0; i < qMin(stringLists.size(), intLists.size()); i++) {
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QString(__FUNCTION__));
+ item.insert(__FUNCTION__, QString("Find Me!"));
+ item.insert("stringlist", variantToQson(stringLists[i]));
+ item.insert("intlist", variantToQson(intLists[i]));
+ item.insert("str", variantToQson(stringLists[i][0]));
+ item.insert("i", variantToQson(intLists[i].toList().at(0)));
+ mJsonDb->create(mOwner, item);
+ }
+
+ QStringList queries = (QStringList()
+ << "[?stringlist contains \"fred\"]"
+ << "[?intlist contains 22]"
+ << "[?str in [\"fred\", \"barney\"]]"
+ << "[?i in [\"1\", \"22\"]]"
+ );
+
+ foreach (QString q, queries) {
+ QsonMap query;
+ query.insert("query", q);
+ QsonMap result = mJsonDb->find(mOwner, query);
+ //qDebug() << "result.length" << result.value("result").toMap().value(QLatin1String("length")).toInt();
+
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::findFields()
+{
+ mJsonDb->addIndex(QLatin1String("name"));
+ mJsonDb->addIndex(QLatin1String("_type"));
+
+ QsonMap item;
+ item.insert("firstName", QString("Wilma"));
+ item.insert("lastName", QString("Flintstone"));
+ item.insert(JsonDbString::kTypeStr, kContactStr);
+ mJsonDb->create(mOwner, item);
+
+ item = QsonObject();
+ item.insert("firstName", QString("Betty"));
+ item.insert("lastName", QString("Rubble"));
+ item.insert(JsonDbString::kTypeStr, kContactStr);
+ mJsonDb->create(mOwner, item);
+
+ QsonMap query, result, map;
+
+ query.insert("query", QString("[?firstName=\"Wilma\"][=firstName]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ result = result.subObject("result");
+ QCOMPARE(result.value<int>("length"), 1);
+ QCOMPARE(result.subList("data").stringAt(0), QString("Wilma"));
+
+ query.insert("query", QString("[?firstName=\"Wilma\"][= [firstName,lastName]]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ result = result.subObject("result");
+ QCOMPARE(result.value<int>("length"), 1);
+ QCOMPARE(result.subList("data").size(), 1);
+ QsonList data = result.subList("data").listAt(0);
+ QCOMPARE(result.subList("data").size(), 1);
+ QCOMPARE(data.stringAt(0), QString("Wilma"));
+ QCOMPARE(data.stringAt(1), QString("Flintstone"));
+}
+
+void TestJsonDb::orderedFind1_data()
+{
+ QTest::addColumn<QString>("order");
+ QTest::newRow("asc") << "/";
+ QTest::newRow("desc") << "\\";
+
+ mJsonDb->addIndex(QLatin1String("orderedFindName"));
+ mJsonDb->addIndex(QLatin1String("_type"));
+
+ QsonMap item1;
+ item1.insert("orderedFindName", QString("Wilma"));
+ item1.insert(JsonDbString::kTypeStr, QLatin1String("orderedFind1"));
+ mJsonDb->create(mOwner, item1);
+
+ QsonMap item2;
+ item2.insert("orderedFindName", QString("BamBam"));
+ item2.insert(JsonDbString::kTypeStr, QLatin1String("orderedFind1"));
+ mJsonDb->create(mOwner, item2);
+
+ QsonMap item3;
+ item3.insert("orderedFindName", QString("Betty"));
+ item3.insert(JsonDbString::kTypeStr, QLatin1String("orderedFind1"));
+ mJsonDb->create(mOwner, item3);
+}
+
+void TestJsonDb::orderedFind1()
+{
+ QFETCH(QString, order);
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"orderedFind1\"][%3orderedFindName]").arg(order));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QVERIFY(result.subObject("result").value<int>(QLatin1String("length")) > 0);
+
+ QStringList names;
+ QsonList data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++) {
+ names.append(data.objectAt(ii).valueString("orderedFindName"));
+ }
+ QStringList orderedNames = names;
+ qSort(orderedNames.begin(), orderedNames.end());
+ QStringList disorderedNames = names;
+ qSort(disorderedNames.begin(), disorderedNames.end(), qGreater<QString>());
+ if (order == "/") {
+ QVERIFY(names == orderedNames);
+ QVERIFY(names != disorderedNames);
+ } else {
+ QVERIFY(names != orderedNames);
+ QVERIFY(names == disorderedNames);
+ }
+}
+
+void TestJsonDb::orderedFind2_data()
+{
+ QTest::addColumn<QString>("order");
+ QTest::addColumn<QString>("field");
+ QTest::newRow("asc uuid") << "/" << "_uuid";
+ QTest::newRow("asc foobar") << "/" << "foobar";
+ QTest::newRow("desc uuid") << "\\" << "_uuid";
+ QTest::newRow("desc foobar") << "\\" << "foobar";
+
+ for (char prefix = 'z'; prefix >= 'a'; prefix--) {
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("orderedFind2"));
+ item.insert(QLatin1String("foobar"), QString("%1_orderedFind2").arg(prefix));
+ QsonMap r = mJsonDb->create(mOwner, item);
+ }
+}
+
+void TestJsonDb::orderedFind2()
+{
+ QFETCH(QString, order);
+ QFETCH(QString, field);
+
+ //mJsonDb->checkValidity();
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"orderedFind2\"][%1%2]").arg(order).arg(field));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QVERIFY(result.subObject("result").value<int>(QLatin1String("length")) > 0);
+
+ QStringList names;
+ QsonList data = result.subObject("result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++) {
+ names.append(data.objectAt(ii).valueString(field));
+ }
+ QStringList orderedNames = names;
+ qSort(orderedNames.begin(), orderedNames.end());
+ QStringList disorderedNames = names;
+ qSort(disorderedNames.begin(), disorderedNames.end(), qGreater<QString>());
+ if (order == "/") {
+ if (!(names == orderedNames)
+ || !(names != disorderedNames))
+ mJsonDb->findPartition("default")->checkIndex(field);
+ QVERIFY(names == orderedNames);
+ QVERIFY(names != disorderedNames);
+ } else {
+ if (!(names != orderedNames)
+ || !(names == disorderedNames))
+ mJsonDb->findPartition("default")->checkIndex(field);
+ QVERIFY(names != orderedNames);
+ QVERIFY(names == disorderedNames);
+ }
+}
+
+void TestJsonDb::wildcardIndex()
+{
+ mJsonDb->addIndex("telephoneNumbers.*.number");
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, kContactStr);
+ item.insert("name", QString("BamBam"));
+
+ QsonMap mobileNumber;
+ QString mobileNumberString = "+15515512323";
+ mobileNumber.insert("type", QString("mobile"));
+ mobileNumber.insert("number", mobileNumberString);
+ QsonList telephoneNumbers;
+ telephoneNumbers.append(mobileNumber);
+ item.insert("telephoneNumbers", telephoneNumbers);
+
+ mJsonDb->create(mOwner, item);
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QString("[?telephoneNumbers.*.number=\"%1\"]").arg(mobileNumberString));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+
+ query.insert(JsonDbString::kQueryStr, QString("[?%1=\"%2\"][= .telephoneNumbers[*].number]").arg(JsonDbString::kTypeStr).arg(kContactStr));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::uuidJoin()
+{
+ mJsonDb->addIndex("name");
+ mJsonDb->addIndex("thumbnailUuid");
+ mJsonDb->addIndex("url");
+ QString thumbnailUrl = "file:thumbnail.png";
+ QsonMap thumbnail;
+ thumbnail.insert(JsonDbString::kTypeStr, QString("com.noklab.nrcc.jsondb.thumbnail"));
+ thumbnail.insert("url", thumbnailUrl);
+ mJsonDb->create(mOwner, thumbnail);
+ QString thumbnailUuid = thumbnail.valueString("_uuid");
+
+ QsonMap item;
+ item.insert("_type", QString(__FUNCTION__));
+ item.insert("name", QString("Pebbles"));
+ item.insert(JsonDbString::kTypeStr, kContactStr);
+ //qDebug() << item;
+ mJsonDb->create(mOwner, item);
+
+ QsonMap item2;
+ item2.insert("_type", QString(__FUNCTION__));
+ item2.insert("name", QString("Wilma"));
+ item2.insert("thumbnailUuid", thumbnailUuid);
+ item2.insert(JsonDbString::kTypeStr, kContactStr);
+ //qDebug() << item2;
+ mJsonDb->create(mOwner, item2);
+
+ QsonMap betty;
+ betty.insert("_type", QString(__FUNCTION__));
+ betty.insert("name", QString("Betty"));
+ betty.insert("thumbnailUuid", thumbnailUuid);
+ betty.insert(JsonDbString::kTypeStr, kContactStr);
+ //qDebug() << betty;
+ QsonMap r = mJsonDb->create(mOwner, betty);
+ QString bettyUuid = r.subObject("result").valueString("_uuid");
+
+ QsonMap bettyRef;
+ bettyRef.insert("_type", QString(__FUNCTION__));
+ bettyRef.insert("bettyUuid", bettyUuid);
+ bettyRef.insert("thumbnailUuid", thumbnailUuid);
+ r = mJsonDb->create(mOwner, bettyRef);
+
+ QsonMap query, result;
+ query.insert(JsonDbString::kQueryStr, QString("[?thumbnailUuid->url=\"%1\"]").arg(thumbnailUrl));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QVERIFY(result.subObject("result").subList("data").size() > 0);
+ QCOMPARE(result.subObject("result").subList("data").objectAt(0).valueString("thumbnailUuid"), thumbnailUuid);
+
+ query.insert(JsonDbString::kQueryStr, QString("[?_type=\"%1\"][?thumbnailUuid->url=\"%2\"]").arg(__FUNCTION__).arg(thumbnailUrl));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QVERIFY(result.subObject("result").subList("data").size() > 0);
+ QCOMPARE(result.subObject("result").subList("data").objectAt(0).valueString("thumbnailUuid"), thumbnailUuid);
+
+ QString queryString = QString("[?name=\"Betty\"][= [ name, thumbnailUuid->url ]]");
+ query.insert(JsonDbString::kQueryStr, queryString);
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").listAt(0).stringAt(1), thumbnailUrl);
+
+ queryString = QString("[?_type=\"%1\"][= [ name,thumbnailUuid->url ]]").arg(__FUNCTION__);
+ query.insert(JsonDbString::kQueryStr, queryString);
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QsonList data = result.subObject("Result").subList("data");
+ for (int ii = 0; ii < data.size(); ii++) {
+ QsonList item = data.listAt(ii);
+ QString name = item.stringAt(0);
+ QString url = item.stringAt(1);
+ if (name == "Pebbles")
+ QVERIFY(url.isEmpty());
+ else
+ QCOMPARE(url, thumbnailUrl);
+ }
+
+ queryString = QString("[?_type=\"%1\"][= { name: name, url: thumbnailUuid->url } ]").arg(__FUNCTION__);
+ query.insert(JsonDbString::kQueryStr, queryString);
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+
+ data = result.subObject("result").subList("da2ta");
+ for (int ii = 0; ii < data.size(); ii++) {
+ QsonMap item = data.objectAt(ii);
+ QString name = item.valueString("name");
+ QString url = item.valueString("url");
+ if (name == "Pebbles")
+ QVERIFY(url.isEmpty());
+ else
+ QCOMPARE(url, thumbnailUrl);
+ }
+
+ query.insert(JsonDbString::kQueryStr, QString("[?bettyUuid exists][= bettyUuid->thumbnailUuid]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").stringAt(0),
+ thumbnailUuid);
+
+ query.insert(JsonDbString::kQueryStr, QString("[?bettyUuid exists][= bettyUuid->thumbnailUuid->url]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").stringAt(0), thumbnail.valueString("url"));
+ //qDebug() << result;
+
+}
+
+
+void TestJsonDb::testNotify1()
+{
+ QString query = QString("[?%1=\"%2\"]").arg(JsonDbString::kTypeStr).arg(kContactStr);
+
+ QsonList actions;
+ actions.append(QLatin1String("create"));
+
+ QsonMap notification;
+ notification.insert(JsonDbString::kTypeStr, JsonDbString::kNotificationTypeStr);
+ notification.insert(QLatin1String("query"), query);
+ notification.insert(QLatin1String("actions"), actions);
+
+ QsonMap result = mJsonDb->create(mOwner, notification);
+ QVERIFY(result.contains(JsonDbString::kResultStr));
+ QVERIFY(result.subObject(JsonDbString::kResultStr).contains(JsonDbString::kUuidStr));
+ QString uuid = result.subObject(JsonDbString::kResultStr).valueString(JsonDbString::kUuidStr);
+
+ if (!connect(mJsonDb, SIGNAL(notified(const QString, QsonMap, const QString)),
+ this, SLOT(notified(const QString, QsonMap, const QString))))
+ qDebug() << __FUNCTION__ << "failed to connect SIGNAL(notified)";
+
+ mNotificationsReceived.clear();
+
+ QsonMap item;
+ item.insert("name", QString("Wilma"));
+ item.insert(JsonDbString::kTypeStr, kContactStr);
+ mJsonDb->create(mOwner, item);
+
+ QVERIFY(mNotificationsReceived.contains(uuid));
+
+ result = mJsonDb->remove(mOwner, notification);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::notified(const QString nid, QsonMap o, const QString action)
+{
+// static int c = 0;
+// if (c++ < 1)
+// qDebug() << "TestJsonDb::notified" << nid << o << action;
+ Q_UNUSED(o);
+ Q_UNUSED(action);
+ mNotificationsReceived.append(nid);
+}
+
+QStringList sTestQueries = (QStringList()
+ << "[?foo exists]"
+ << "[?foo->bar exists]"
+ << "[?foo->bar->baz exists]"
+ << "[?foo=\"bar\"]"
+ << "[?foo= %bar ]"
+ << "[?foo= %bar]"
+ << "[?foo=%bar]"
+ << "[?foo=\"bar\" | foo=\"baz\"]"
+ << "[?foo=\"bar\"][/foo]"
+ << "[?foo=\"bar\"][= a ]"
+ << "[?foo =~ \"/a\\//\"]"
+ << "[?foo=\"bar\"][= a,b,c]"
+ << "[?foo=\"bar\"][= a->foreign,b,c]"
+ << "[?foo=\"bar\"][=[ a,b,c]]"
+ << "[?foo=\"bar\"][={ a:x, b:y, c:z}]"
+ << "[?foo=\"bar\"][={ a:x->foreign, b:y, c:z}]"
+ << "[?foo=\"bar\"][= _uuid, name.first, name.last ]"
+ << "[?_type=\"contact\"][= { uuid: _uuid, first: name.first, last: name.last } ]"
+ << "[?telephoneNumbers.*.number=\"6175551212\"]"
+ << "[?_type=\"contact\"][= .telephoneNumbers[*].number]"
+ );
+
+void TestJsonDb::parseQuery()
+{
+#if 1
+ QSKIP("This is manual test, skipping", SkipAll);
+#else
+ foreach (QString query, sTestQueries) {
+ qDebug() << endl << endl << "query" << query;
+ QsonMap bindings;
+ bindings.insert("bar", QString("barValue"));
+ JsonDbQuery result = JsonDbQuery::parse(query, bindings);
+ const QList<OrQueryTerm> &orQueryTerms = result.queryTerms;
+ for (int i = 0; i < orQueryTerms.size(); i++) {
+ const OrQueryTerm orQueryTerm = orQueryTerms[i];
+ const QList<QueryTerm> &terms = orQueryTerm.terms();
+ QString sep = "";
+ if (terms.size() > 1) {
+ qDebug() << " (";
+ sep = " ";
+ }
+ foreach (const QueryTerm &queryTerm, terms) {
+ qDebug() << QString(" %6%5%4%1 %2 %3 ").arg(queryTerm.fieldName()).arg(queryTerm.op()).arg(JsonWriter().toString(queryTerm.value()))
+ .arg(queryTerm.joinField().size() ? " -> " : "").arg(queryTerm.joinField())
+ .arg(sep);
+ sep = "| ";
+ }
+ if (terms.size() > 1)
+ qDebug() << " )";
+ }
+ QList<OrderTerm> &orderTerms = result.orderTerms;
+ for (int i = 0; i < orderTerms.size(); i++) {
+ const OrderTerm &orderTerm = orderTerms[i];
+ qDebug() << QString(" %1 %2 ").arg(orderTerm.fieldName).arg(orderTerm.ascending);
+ }
+ qDebug() << "mapKeys" << result.mapKeyList.join(", ");
+ qDebug() << "mapExprs" << result.mapExpressionList.join(", ");
+ qDebug() << "explanation" << result.queryExplanation;
+ }
+#endif
+}
+
+void TestJsonDb::orQuery_data()
+{
+ QTest::addColumn<QString>("field1");
+ QTest::addColumn<QString>("value1");
+ QTest::addColumn<QString>("field2");
+ QTest::addColumn<QString>("value2");
+ QTest::addColumn<QString>("ordering");
+ QTest::newRow("[? key1 = \"red\" | key1 = \"green\" ]")
+ << "key1" << "red" << "key1" << "green" << "";
+ QTest::newRow("[? key1 = \"red\" | key2 = \"bar\" ]")
+ << "key1" << "red" << "key2" << "bar" << "";
+ QTest::newRow("[? key1 = \"red\" | key1 = \"green\"][/key1]")
+ << "key1" << "red" << "key1" << "green" << "[/key1]";
+ QTest::newRow("[? key1 = \"red\" | key2 = \"bar\" ][/key1]")
+ << "key1" << "red" << "key2" << "bar" << "[/key1]";
+ QTest::newRow("[? key1 = \"red\" | key1 = \"green\"][/key2]")
+ << "key1" << "red" << "key1" << "green" << "[/key2]";
+ QTest::newRow("[? key1 = \"red\" | key2 = \"bar\" ][/key2]")
+ << "key1" << "red" << "key2" << "bar" << "[/key2]";
+ QTest::newRow("[? _type = \"RedType\" | _type = \"BarType\" ]")
+ << "_type" << "RedType" << "_type" << "BarType" << "";
+
+ mJsonDb->addIndex(QLatin1String("key1"));
+
+ QStringList keys1 = QStringList() << "red" << "green" << "blue";
+ QStringList keys2 = QStringList() << "foo" << "bar" << "baz";
+ foreach (QString key1, keys1) {
+ foreach (QString key2, keys2) {
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QString("OrQueryTestType"));
+ item.insert("key1", key1);
+ item.insert("key2", key2);
+ mJsonDb->create(mOwner, item);
+
+ key1[0] = key1[0].toUpper();
+ key2[0] = key2[0].toUpper();
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QString("%1Type").arg(key1));
+ item.insert("notUsed1", key1);
+ item.insert("notUsed2", key2);
+ mJsonDb->create(mOwner, item);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QString("%1Type").arg(key2));
+ item.insert("notUsed1", key1);
+ item.insert("notUsed2", key2);
+ mJsonDb->create(mOwner, item);
+ }
+ }
+}
+
+void TestJsonDb::orQuery()
+{
+ QFETCH(QString, field1);
+ QFETCH(QString, value1);
+ QFETCH(QString, field2);
+ QFETCH(QString, value2);
+ QFETCH(QString, ordering);
+ QsonMap request;
+ QString typeQuery = "[?_type=\"OrQueryTestType\"]";
+ QString queryString = (QString("%6[? %1 = \"%2\" | %3 = \"%4\" ]%5")
+ .arg(field1).arg(value1)
+ .arg(field2).arg(value2)
+ .arg(ordering).arg(((field1 != "_type") && (field2 != "_type")) ? typeQuery : ""));
+ request.insert("query", queryString);
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QsonList objects = result.subObject("result").subList("data");
+ int count = 0;
+ for (int ii = 0; ii < objects.size(); ii++) {
+ QsonMap o = objects.objectAt(ii);
+ QVERIFY((o.valueString(field1) == value1) || (o.valueString(field2) == value2));
+ count++;
+ }
+ QVERIFY(count > 0);
+ //qDebug() << result;
+ //qDebug() << "verified objects" << count << endl;
+}
+
+void TestJsonDb::findByName()
+{
+ createContacts();
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QsonMap request;
+
+ //int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ int itemNumber = 0;
+ QsonMap item(mContactList.at(itemNumber).toMap());;
+ request.insert("query",
+ QString("[?name=\"%1\"]")
+ .arg(item.valueString("name")));
+ if (!item.contains("name"))
+ qDebug() << "no name in item" << item;
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::findEQ()
+{
+ createContacts();
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QsonMap request;
+
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item(mContactList.at(itemNumber).toMap());
+ request.insert("query",
+ QString("[?name.first=\"%1\"][?name.last=\"%2\"][?_type=\"contact\"]")
+ .arg(JsonDb::propertyLookup(item, "name.first").toString())
+ .arg(JsonDb::propertyLookup(item, "name.last").toString()));
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QVERIFY(result.subObject("result").contains("length"));
+ QCOMPARE(result.subObject("result").value<int>("length"), 1);
+ QVERIFY(result.subObject("result").contains("data"));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+}
+
+void TestJsonDb::find10()
+{
+ createContacts();
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QsonMap request;
+ QsonMap result;
+
+ int itemNumber = count / 2;
+ QsonMap item(mContactList.at(itemNumber).toMap());
+ request.insert("limit", 10);
+ request.insert("query",
+ QString("[?name.first<=\"%1\"][?_type=\"contact\"]")
+ .arg(JsonDb::propertyLookup(item, "name.first").toString()));
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QsonMap map = result.subObject(JsonDbString::kResultStr);
+ QVERIFY(map.contains("length"));
+ QCOMPARE(map.value<int>("length"), 10);
+ QVERIFY(map.contains("data"));
+ QCOMPARE(map.subList("data").size(), 10);
+}
+
+QsonObject TestJsonDb::readJsonFile(const QString& filename)
+{
+ QString filepath = findFile(SRCDIR, filename);
+ QFile jsonFile(filepath);
+ jsonFile.open(QIODevice::ReadOnly);
+ QByteArray json = jsonFile.readAll();
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok) {
+ qDebug() << filepath << parser.errorString();
+ }
+ QVariant v = parser.result();
+ return variantToQson(v);
+}
+
+QsonObject TestJsonDb::readJson(const QByteArray& json)
+{
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok) {
+ qDebug() << parser.errorString();
+ }
+ QVariant v = parser.result();
+ return variantToQson(v);
+}
+
+void TestJsonDb::testPrimaryKey()
+{
+ QsonMap capability = readJsonFile("pk-capability.json").toMap();
+ QsonMap replay(capability);
+
+ QsonMap result1 = mJsonDb->create(mOwner, capability).toMap();
+ verifyGoodResult(result1);
+
+ QsonMap result2 = mJsonDb->create(mOwner, replay).toMap();
+ verifyGoodResult(result2);
+
+ if (gVerbose) qDebug() << 1 << result1;
+ if (gVerbose) qDebug() << 2 << result2;
+
+ QCOMPARE(result1, result2);
+}
+
+void TestJsonDb::testStoredProcedure()
+{
+ QsonMap notification;
+ notification.insert(JsonDbString::kTypeStr, JsonDbString::kNotificationTypeStr);
+ QString query = QString("[?%1=\"%2\"]").arg(JsonDbString::kTypeStr).arg(__FUNCTION__);
+ QVariantList actions;
+ actions.append(QLatin1String("create"));
+ notification.insert(JsonDbString::kQueryStr, query);
+ notification.insert(JsonDbString::kActionsStr, variantToQson(actions));
+ notification.insert("script", QLatin1String("function foo (v) { return \"hello world\";}"));
+ QsonObject result = mJsonDb->create(mOwner, notification);
+
+
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QString(__FUNCTION__));
+ result = mJsonDb->create(mOwner, item);
+
+ notification.insert("script", QString("function foo (v) { return jsondb.find({'query':'[?_type=\"%1\"]'}); }").arg(__FUNCTION__));
+ result = mJsonDb->update(mOwner, notification);
+
+ QsonMap item2;
+ item2.insert(JsonDbString::kTypeStr, QString(__FUNCTION__));
+ result = mJsonDb->create(mOwner, item2);
+}
+
+void TestJsonDb::dumpObjects()
+{
+// HdbCursor cursor(mJsonDbStorage->mHdb);
+// bool debug = gDebug;
+// gDebug = true;
+// quint32 lastObjectKey = 0;
+// QString lastUuid;
+// QByteArray baKey, baValue;
+// while (cursor.next(baKey, baValue)) {
+// quint32 objectKey = qFromLittleEndian<quint32>((const uchar *)baKey.data());
+// QsonObject object = mJsonDbStorage->deserialize(baValue).toMap();
+// QString uuid = object.value(JsonDbString::kUuidStr).toString();
+// DBG() << baKey.toHex() << objectKey;
+// DBG() << object;
+// QVERIFY(objectKey > lastObjectKey);
+// QVERIFY(uuid > lastUuid);
+// lastObjectKey = objectKey;
+// lastUuid = uuid;
+// }
+// gDebug = debug;
+}
+
+void TestJsonDb::startsWith()
+{
+ mJsonDb->addIndex(QLatin1String("name"));
+
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("startsWithTest"));
+ item.insert("name", QLatin1String("Wilma"));
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QLatin1String("startsWithTest"));
+ item.insert("name", QLatin1String("Betty"));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QLatin1String("startsWithTest"));
+ item.insert("name", QLatin1String("Bettina"));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QLatin1String("startsWithTest"));
+ item.insert("name", QLatin1String("Benny"));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"startsWithTest\"][?name startsWith \"Zelda\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(0));
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"startsWithTest\"][?name startsWith \"Wilma\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"startsWithTest\"][?name startsWith \"B\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(3));
+ QCOMPARE(result.subObject("result").subList("data").size(), 3);
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"startsWithTest\"][?name startsWith \"Bett\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(2));
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+}
+
+void TestJsonDb::comparison()
+{
+ mJsonDb->addIndex(QLatin1String("latitude"));
+
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("comparison"));
+ item.insert("latitude", qint64(10));
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QLatin1String("comparison"));
+ item.insert("latitude", qint64(42));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QLatin1String("comparison"));
+ item.insert("latitude", qint64(0));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ item = QsonMap();
+ item.insert(JsonDbString::kTypeStr, QLatin1String("comparison"));
+ item.insert("latitude", qint64(-64));
+ result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"comparison\"][?latitude > 10]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).valueInt("latitude"), qint64(42));
+
+ query.insert("query", QString("[?_type=\"comparison\"][?latitude >= 10]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(2));
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).valueInt("latitude"), qint64(10));
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(1).valueInt("latitude"), qint64(42));
+
+ query.insert("query", QString("[?_type=\"comparison\"][?latitude < 0]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).valueInt("latitude"), qint64(-64));
+}
+
+void TestJsonDb::removedObjects()
+{
+ mJsonDb->addIndex(QLatin1String("foo"));
+ QsonMap item;
+ item.insert(JsonDbString::kTypeStr, QLatin1String("removedObjects"));
+ item.insert("foo", QLatin1String("bar"));
+ QsonMap result = mJsonDb->create(mOwner, item);
+ verifyGoodResult(result);
+
+ QsonMap object = result.subObject("result");
+ object.insert(JsonDbString::kTypeStr, QLatin1String("removedObjects"));
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"removedObjects\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).valueString("foo"), QLatin1String("bar"));
+
+ // update the object
+ item = object;
+ item.insert("name", QLatin1String("anna"));
+ result = mJsonDb->update(mOwner, item);
+ verifyGoodResult(result);
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"removedObjects\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QVERIFY(!result.subObject("result").subList("data").at<QsonMap>(0).contains("foo"));
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).valueString("name"), QLatin1String("anna"));
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"removedObjects\"][/name]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(1));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QVERIFY(!result.subObject("result").subList("data").at<QsonMap>(0).contains("foo"));
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).valueString("name"), QLatin1String("anna"));
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"removedObjects\"][/foo]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(0));
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ // remove the object
+ result = mJsonDb->remove(mOwner, object);
+ verifyGoodResult(result);
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"removedObjects\"]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(0));
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ query = QsonMap();
+ query.insert("query", QString("[?_type=\"removedObjects\"][/foo]"));
+ result = mJsonDb->find(mOwner, query);
+ QCOMPARE(result.subObject("result").valueInt("length", 0), qint64(0));
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+}
+
+void TestJsonDb::partition()
+{
+ QsonMap map;
+ map.insert(QLatin1String("_type"), QLatin1String("Partition"));
+ map.insert(QLatin1String("name"), QLatin1String("private"));
+ QsonMap result = mJsonDb->create(mOwner, map);
+ verifyGoodResult(result);
+
+ map = QsonMap();
+ map.insert(QLatin1String("_type"), QLatin1String("partitiontest"));
+ map.insert(QLatin1String("foo"), QLatin1String("bar"));
+ result = mJsonDb->create(mOwner, map);
+ verifyGoodResult(result);
+
+ map = QsonMap();
+ map.insert(QLatin1String("_type"), QLatin1String("partitiontest"));
+ map.insert(QLatin1String("foo"), QLatin1String("asd"));
+ result = mJsonDb->create(mOwner, map, "private");
+ verifyGoodResult(result);
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"partitiontest\"]"));
+
+ result = mJsonDb->find(mOwner, query, "default");
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).value<QString>("foo"), QLatin1String("bar"));
+
+ result = mJsonDb->find(mOwner, query, "private");
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ QCOMPARE(result.subObject("result").subList("data").at<QsonMap>(0).value<QString>("foo"), QLatin1String("asd"));
+
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+ QStringList values = (QStringList() << QLatin1String("asd") << QLatin1String("bar"));
+ QVERIFY(values.contains(result.subObject("result").subList("data").at<QsonMap>(0).value<QString>("foo")));
+ QVERIFY(values.contains(result.subObject("result").subList("data").at<QsonMap>(1).value<QString>("foo")));
+
+ query.insert("query", QString("[?_type=\"partitiontest\"][/foo]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+ QVERIFY(result.subObject("result").subList("data").at<QsonMap>(0).value<QString>("foo")
+ < result.subObject("result").subList("data").at<QsonMap>(1).value<QString>("foo"));
+
+ query.insert("query", QString("[?_type=\"partitiontest\"][\\foo]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+ QVERIFY(result.subObject("result").subList("data").at<QsonMap>(0).value<QString>("foo")
+ > result.subObject("result").subList("data").at<QsonMap>(1).value<QString>("foo"));
+
+}
+
+void TestJsonDb::arrayIndexQuery()
+{
+ mJsonDb->addIndex(QLatin1String("phoneNumber"));
+
+ QsonList objects(readJsonFile("array.json").toList());
+ QMap<QString, QsonMap> toDelete;
+ for (int i = 0; i < objects.size(); ++i) {
+ QsonMap object = objects.objectAt(i);
+ QsonMap result = mJsonDb->create(mOwner, object);
+ verifyGoodResult(result);
+ toDelete.insert(object.valueString("_uuid"), object);
+ }
+
+ QsonMap query;
+ query.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"]"));
+ QsonMap result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+
+ QsonMap queryListMember;
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?phoneNumbers.0.number =~\"/*789*/wi\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?phoneNumbers.0.validTime.0.timeFrom =\"09:00\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?phoneNumbers.0.validTime.0.timeFrom =\"10:00\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?phoneNumbers.0.validTime.0.timeTo =\"13:00\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?phoneNumbers.0.validTime.10.timeTo =\"13:00\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?phoneNumbers.10.validTime.10.timeTo =\"13:00\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 0);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?foo.0.0.bar =\"val00\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 2);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?test.45 =\"joe\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+
+ queryListMember = QsonMap();
+ queryListMember.insert(JsonDbString::kQueryStr, QLatin1String("[?_type=\"ContactInArray\"][?test2.56.firstName =\"joe\"]"));
+ result = mJsonDb->find(mOwner, queryListMember);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+
+ foreach(QsonMap object, toDelete.values()) {
+ verifyGoodResult(mJsonDb->remove(mOwner, object));
+ }
+
+}
+
+void TestJsonDb::deindexError()
+{
+ QsonMap result;
+
+ // create document with a property "name"
+ QsonMap foo;
+ foo.insert("_type", QLatin1String("Foo"));
+ foo.insert("name", QLatin1String("fooo"));
+ result = mJsonDb->create(mOwner, foo);
+ verifyGoodResult(result);
+
+ // create a schema object (has 'name' property)
+ QsonMap schema;
+ schema.insert("_type", QLatin1String("_schemaType"));
+ schema.insert("name", QLatin1String("ArrayObject"));
+ QsonMap s;
+ s.insert("type", QLatin1String("object"));
+ //s.insert("extends", QLatin1String("View"));
+ schema.insert("schema", s);
+ result = mJsonDb->create(mOwner, schema);
+ verifyGoodResult(result);
+
+ // create instance of ArrayView (defined by the schema)
+ QsonMap arrayView;
+ arrayView.insert("_type", QLatin1String("ArrayView"));
+ arrayView.insert("name", QLatin1String("fooo"));
+ result = mJsonDb->create(mOwner, arrayView);
+ verifyGoodResult(result);
+
+ mJsonDb->addIndex(QLatin1String("name"));
+
+ // now remove some objects that have "name" property
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"Foo\"]"));
+ result = mJsonDb->find(mOwner, query);
+ verifyGoodResult(result);
+ QsonList objs = result.value<QsonMap>("result").value<QsonList>("data");
+ QVERIFY(!objs.isEmpty());
+ result = mJsonDb->removeList(mOwner, objs);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::expectedOrder()
+{
+ QStringList list;
+ QStringList uuids;
+
+ // Bug occurs when there is a string A and multiple other strings that are longer
+ // than A but the first A.length characters are exactly the same as A's.
+ const int count = 100;
+ for (int i = 0; i < count; ++i) {
+ int r = qrand();
+ QString str0 = QString::number(r);
+ QString str1 = str0 + QString(str0[0]);
+ QString str2 = str0 + QString(str0[0]) + QString(str0[0]);
+ list.append(str0);
+ list.append(str1);
+ list.append(str2);
+ }
+
+ foreach (const QString &str, list) {
+ QsonMap item;
+ item.insert("_type", QLatin1String(__FUNCTION__));
+ item.insert("order", str);
+ QsonMap result = mJsonDb->create(mOwner, item);
+ QVERIFY(result.value<QsonMap>("error").isEmpty());
+ uuids << result.value<QsonMap>("result").valueString("_uuid");
+ }
+
+ // This is the order we expect from the query
+ list.sort();
+
+ QsonMap query;
+ query.insert("query", QString("[?_type=\"%1\"][/order]").arg(__FUNCTION__));
+ QsonMap findResult = mJsonDb->find(mOwner, query);
+
+ QVERIFY(findResult.contains("result"));
+ QsonMap resultMap = findResult.subObject("result");
+
+ QVERIFY(resultMap.contains("data"));
+ QsonList dataList = resultMap.subList("data");
+
+ QCOMPARE(dataList.size(), list.size());
+
+ for (int i = 0; i < dataList.size(); ++i) {
+ QCOMPARE(dataList.typeAt(i), QsonMap::MapType);
+ QsonMap obj = dataList.at<QsonMap>(i);
+ QVERIFY(obj.contains("order"));
+ QCOMPARE(obj.valueString("order"), list.at(i));
+ }
+}
+
+void TestJsonDb::indexQueryOnCommonValues()
+{
+ // Specific indexing bug when you have records inserted that only differ
+ // by their _type
+ createContacts();
+
+ for (int ii = 0; ii < mContactList.size(); ii++) {
+ QsonMap data(mContactList.at(ii).toMap());
+ QsonMap chaff;
+ chaff.insert(JsonDbString::kTypeStr, QString("com.noklab.nrcc.ContactChaff"));
+ QStringList skipKeys = (QStringList() << JsonDbString::kUuidStr << JsonDbString::kVersionStr << JsonDbString::kTypeStr);
+ foreach (QString key, data.keys()) {
+ if (!skipKeys.contains(key))
+ chaff.insert(key, data.value<QsonElement>(key));
+ }
+
+ QsonMap result = mJsonDb->create(mOwner, chaff);
+ verifyGoodResult(result);
+ }
+
+ int count = mContactList.size();
+
+ QCOMPARE(count > 0, true);
+
+ QsonMap request;
+
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+
+ QsonMap item(mContactList.at(itemNumber).toMap());
+ QString first = JsonDb::propertyLookup(item, "name.first").toString();
+ QString last = JsonDb::propertyLookup(item, "name.last").toString();
+ request.insert("query",
+ QString("[?name.first=\"%1\"][?name.last=\"%2\"][?_type=\"contact\"]")
+ .arg(first)
+ .arg(last) );
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+
+ QVERIFY(result.subObject("result").contains("length"));
+ QCOMPARE(result.subObject("result").value<int>("length"), 1);
+ QVERIFY(result.subObject("result").contains("data"));
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+}
+
+QTEST_MAIN(TestJsonDb)
+#include "testjsondb.moc"
diff --git a/tests/auto/jsondb-listmodel/jsondb-listmodel.pro b/tests/auto/jsondb-listmodel/jsondb-listmodel.pro
new file mode 100644
index 00000000..16ee012f
--- /dev/null
+++ b/tests/auto/jsondb-listmodel/jsondb-listmodel.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+TARGET = tst_jsondb-listmodel
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT = core network testlib declarative jsondb-private jsondbqson-private
+CONFIG -= app_bundle
+
+include($$PWD/../../../src/3rdparty/qjson/qjson.pri)
+
+DEFINES += JSONDB_DAEMON_BASE=\\\"$$QT.jsondb.bins\\\"
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+INCLUDEPATH += $$PWD/../../../src/imports/jsondb
+HEADERS += $$PWD/../../../src/imports/jsondb/jsondb-listmodel.h
+SOURCES += $$PWD/../../../src/imports/jsondb/jsondb-listmodel.cpp
+
+HEADERS += test-jsondb-listmodel.h
+SOURCES += test-jsondb-listmodel.cpp
+
+check.target = check
+check.commands = rm -f *.db* && LD_LIBRARY_PATH=$$PWD/../../../lib QT_QPA_PLATFORM=minimal ./tst_jsondb-listmodel -xunitxml -silent > ../../../tst_jsondb-listmodel.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/auto/jsondb-listmodel/list-objects.json b/tests/auto/jsondb-listmodel/list-objects.json
new file mode 100644
index 00000000..09bdb0da
--- /dev/null
+++ b/tests/auto/jsondb-listmodel/list-objects.json
@@ -0,0 +1,39 @@
+[
+ {
+ "_type":"com.nokia.mp.social.ApplicationFeatures",
+ "features":[
+ {
+ "feature":"provide Facebook",
+ "objectType":"com.nokia.mp.accounts.Account",
+ "properties":[
+ {
+ "allowMultiple":false,
+ "description":"Facebook account provider",
+ "iconUrl":"accounts.facebookprovider.png"
+ }],
+ "supported":["share"]
+ }],
+ "features-file-version":1,
+ "identifier":"accounts.facebookprovider",
+ "name":"Facebook"
+ },
+ {
+ "_type":"com.nokia.mp.social.ApplicationFeatures",
+ "features":[
+ {
+ "feature":"provide Gmail",
+ "objectType":"com.nokia.mp.accounts.Account",
+ "properties":[
+ {
+ "allowMultiple":false,
+ "description":"Gmail account provider",
+ "iconUrl":"accounts.gmailprovider.png"
+ }],
+ "supported":["share"]
+ }],
+ "features-file-version":1,
+ "identifier":"accounts.gmailprovider",
+ "name":"Gmail"
+ }
+]
+
diff --git a/tests/auto/jsondb-listmodel/test-jsondb-listmodel.cpp b/tests/auto/jsondb-listmodel/test-jsondb-listmodel.cpp
new file mode 100644
index 00000000..343c8f94
--- /dev/null
+++ b/tests/auto/jsondb-listmodel/test-jsondb-listmodel.cpp
@@ -0,0 +1,803 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define QT_GUI_LIB // cause QTEST_MAIN to use QGuiApplication, which is need for QDeclarativeEngine()
+
+#include <QtTest/QtTest>
+#include <QJSEngine>
+#include "test-jsondb-listmodel.h"
+
+#include "../../shared/util.h"
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+#include <QDeclarativeContext>
+#include <QDir>
+#include "json.h"
+
+static const char dbfile[] = "dbFile-jsondb-listmodel";
+ModelData::ModelData(): engine(0), component(0), model(0)
+{
+}
+
+ModelData::~ModelData()
+{
+ if (model)
+ delete model;
+ if (component)
+ delete component;
+ if (engine)
+ delete engine;
+}
+
+TestJsonDbListModel::TestJsonDbListModel()
+ : mClient(NULL), mCode(0),
+ mWaitingForNotification(false), mWaitingForDataChange(false), mWaitingForRowsRemoved(false)
+{
+ QDeclarativeEngine *engine = new QDeclarativeEngine();
+ QStringList pluginPaths = engine->importPathList();
+ for (int i=0; (i<pluginPaths.count() && mPluginPath.isEmpty()); i++) {
+ QDir dir(pluginPaths[i]+"/QtJsonDb");
+ dir.setFilter(QDir::Files | QDir::NoSymLinks);
+ QFileInfoList list = dir.entryInfoList();
+ for (int i = 0; i < list.size(); ++i) {
+ QString error;
+ if (engine->importPlugin(list.at(i).absoluteFilePath(), QString("QtJsonDb"), &error)) {
+ mPluginPath = list.at(i).absoluteFilePath();
+ break;
+ }
+ }
+ }
+ delete engine;
+}
+
+TestJsonDbListModel::~TestJsonDbListModel()
+{
+}
+
+void TestJsonDbListModel::deleteDbFiles()
+{
+ // remove all the test files.
+ QDir currentDir;
+ QStringList nameFilter;
+ nameFilter << QString("*.db");
+ nameFilter << "objectFile.bin" << "objectFile2.bin";
+ QFileInfoList databaseFiles = currentDir.entryInfoList(nameFilter, QDir::Files);
+ foreach (QFileInfo fileInfo, databaseFiles) {
+ //qDebug() << "Deleted : " << fileInfo.fileName();
+ QFile file(fileInfo.fileName());
+ file.remove();
+ }
+}
+
+QVariant TestJsonDbListModel::readJsonFile(const QString& filename)
+{
+ QString filepath = findFile(SRCDIR, filename);
+ QFile jsonFile(filepath);
+ jsonFile.open(QIODevice::ReadOnly);
+ QByteArray json = jsonFile.readAll();
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok) {
+ qDebug() << filepath << parser.errorString();
+ }
+ return parser.result();
+}
+
+void TestJsonDbListModel::connectListModel(JsonDbListModel *model)
+{
+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
+ connect(model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)));
+ connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+}
+
+void TestJsonDbListModel::initTestCase()
+{
+ // make sure there is no old db files.
+ deleteDbFiles();
+
+ QString socketName = QString("testjsondb_%1").arg(getpid());
+ mProcess = launchJsonDbDaemon(JSONDB_DAEMON_BASE, socketName, QStringList() << dbfile);
+
+ mClient = new JsonDbClient(this);
+ connect( mClient, SIGNAL(notified(const QString&, const QVariant&, const QString&)),
+ this, SLOT(notified(const QString&, const QVariant&, const QString&)));
+ connect( mClient, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(response(int, const QVariant&)));
+ connect( mClient, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(error(int, int, const QString&)));
+}
+
+JsonDbListModel *TestJsonDbListModel::createModel()
+{
+ ModelData *newModel = new ModelData();
+ newModel->engine = new QDeclarativeEngine();
+ QString error;
+ if (!newModel->engine->importPlugin(mPluginPath, QString("QtJsonDb"), &error)) {
+ qDebug()<<"Unable to load the plugin :"<<error;
+ delete newModel->engine;
+ return 0;
+ }
+ newModel->component = new QDeclarativeComponent(newModel->engine);
+ newModel->component->setData("import QtQuick 2.0\nimport QtJsonDb 1.0 as JsonDb \n JsonDb.JsonDbListModel {id: contactsModel}", QUrl());
+ newModel->model = newModel->component->create();
+ if (newModel->component->isError())
+ qDebug() << newModel->component->errors();
+ mModels.append(newModel);
+ return (JsonDbListModel*)(newModel->model);
+}
+
+void TestJsonDbListModel::deleteModel(JsonDbListModel *model)
+{
+ for (int i = 0; i < mModels.count(); i++) {
+ if (mModels[i]->model == model) {
+ ModelData *modelData = mModels.takeAt(i);
+ delete modelData;
+ return;
+ }
+ }
+}
+
+void TestJsonDbListModel::cleanupTestCase()
+{
+ if (mProcess) {
+ mProcess->kill();
+ mProcess->waitForFinished();
+ delete mProcess;
+ }
+
+ deleteDbFiles();
+}
+
+void TestJsonDbListModel::notified( const QString& notifyUuid,
+ const QVariant& object,
+ const QString& action )
+{
+ mNotificationId = notifyUuid;
+ mNotifications << Notification( notifyUuid, object, action );
+ if (mWaitingForNotification && mId.isValid())
+ mEventLoop.exit(0);
+}
+
+void TestJsonDbListModel::response( int id, const QVariant& data )
+{
+ mId = id;
+ mData = data;
+ mLastUuid = data.toMap().value("_uuid").toString();
+ if (!mWaitingForNotification || mNotificationId.isValid())
+ mEventLoop.exit(0);
+}
+
+void TestJsonDbListModel::error( int id, int code, const QString& message )
+{
+ qDebug() << Q_FUNC_INFO << id << code << message;
+ mId = id;
+ mCode = code;
+ mMessage = message;
+ mEventLoop.exit(0);
+}
+
+void TestJsonDbListModel::waitForResponse(QVariant id, int code, QVariant notificationId)
+{
+ mNotificationId = QVariant();
+ mId = QVariant();
+ mMessage = QString();
+ mCode = -1;
+ mData = QVariant();
+ mWaitingForNotification = notificationId.isValid();
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(id, mId);
+ if (notificationId.isValid())
+ QCOMPARE(notificationId, mNotificationId);
+ QCOMPARE(mCode, code);
+}
+
+void TestJsonDbListModel::waitForItemsCreated(int items)
+{
+ mItemsCreated = 0;
+ while(mItemsCreated != items)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+}
+
+// Create items in the model.
+void TestJsonDbListModel::createItem()
+{
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ int id = mClient->create(item);
+
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ QCOMPARE(listModel->count(), 0);
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->count(), 1);
+
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Baker");
+ id = mClient->create(item);
+ waitForResponse(id);
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->count(), 2);
+ deleteModel(listModel);
+}
+
+// Create an item and then update it.
+void TestJsonDbListModel::updateItemClient()
+{
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ int id = mClient->create(item);
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ QCOMPARE(listModel->rowCount(), 0);
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->rowCount(), 1);
+
+ item.insert("_uuid", mLastUuid);
+ item.insert("name", "Baker");
+
+ mWaitingForDataChange = true;
+
+ id = mClient->update(item);
+ waitForResponse(id);
+
+ while (mWaitingForDataChange)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->count(), 1);
+ QCOMPARE(listModel->get(0, "_uuid").toString(), mLastUuid);
+ QCOMPARE(listModel->get(0, "_type").toString(), QLatin1String(__FUNCTION__));
+ QCOMPARE(listModel->get(0, "name").toString(), QLatin1String("Baker"));
+ deleteModel(listModel);
+}
+
+// Create an item and then update it.
+void TestJsonDbListModel::updateItemSet()
+{
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("phone", "123456789");
+ int id = mClient->create(item);
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name" << "phone");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ QCOMPARE(listModel->rowCount(), 0);
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->rowCount(), 1);
+
+ QJSEngine engine;
+ QJSValue value = engine.newObject();
+
+ value.setProperty("name", "Baker");
+ value.setProperty("phone", "987654321");
+
+ mWaitingForDataChange = true;
+
+ listModel->set(0,value);
+
+ while (mWaitingForDataChange)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->count(), 1);
+ QCOMPARE(listModel->get(0, "_type").toString(), QLatin1String(__FUNCTION__));
+ QCOMPARE(listModel->get(0, "name").toString(), QLatin1String("Baker"));
+ QCOMPARE(listModel->get(0, "phone").toString(), QLatin1String("987654321"));
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::updateItemSetProperty()
+{
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("phone", "123456789");
+ int id = mClient->create(item);
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name" << "phone");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ QCOMPARE(listModel->rowCount(), 0);
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->rowCount(), 1);
+
+ mWaitingForDataChange = true;
+
+ listModel->setProperty(0,"phone","987654321");
+
+ while (mWaitingForDataChange)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->count(), 1);
+ QCOMPARE(listModel->get(0, "_type").toString(), QLatin1String(__FUNCTION__));
+ QCOMPARE(listModel->get(0, "name").toString(), QLatin1String("Charlie"));
+ QCOMPARE(listModel->get(0, "phone").toString(), QLatin1String("987654321"));
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::deleteItem()
+{
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ int id = mClient->create(item);
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->rowCount(), 1);
+
+ item.insert("name", "Baker");
+ id = mClient->create(item);
+ waitForResponse(id);
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->rowCount(), 2);
+
+ mWaitingForRowsRemoved = true;
+ item.insert("_uuid", mLastUuid);
+ id = mClient->remove(item);
+ waitForResponse(id);
+ while(mWaitingForRowsRemoved)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->rowCount(), 1);
+ QCOMPARE(listModel->get(0, "_type").toString(), QLatin1String(__FUNCTION__));
+ QCOMPARE(listModel->get(0, "name").toString(), QLatin1String("Charlie"));
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::sortedQuery()
+{
+ int id = 0;
+ for (int i = 0; i < 1000; i++) {
+ QVariantMap item;
+ item.insert("_type", "RandNumber");
+ item.insert("number", i);
+ id = mClient->create(item);
+ waitForResponse(id);
+ }
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+
+ connectListModel(listModel);
+
+ QStringList rolenames;
+ rolenames << "_uuid" << "_type" << "number";
+ listModel->setRoleNames(rolenames);
+
+ listModel->setQuery("[?_type=\"RandNumber\"][/number]");
+
+ mEventLoop.exec(QEventLoop::AllEvents);
+ QCOMPARE(listModel->count(), 1000);
+ for (int i = 0; i < 1000; i++)
+ QCOMPARE(listModel->get(i,"number").toInt(), i);
+
+ listModel->setQuery("[?_type=\"RandNumber\"][\\number]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+ for (int i = 0; i < 1000; i++)
+ QCOMPARE(listModel->get(i,"number").toInt(), 999-i);
+
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::ordering()
+{
+ for (int i = 9; i >= 1; --i) {
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("order", QString::number(i));
+ int id = mClient->create(item);
+ waitForResponse(id);
+ }
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"][/order]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name" << "order");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ QCOMPARE(listModel->rowCount(), 0);
+
+ mEventLoop.exec( QEventLoop::AllEvents );
+
+ QStringList expectedOrder = QStringList() << "1" << "2" << "3" << "4" <<
+ "5" << "6" << "7" << "8" << "9";
+ QCOMPARE(getOrderValues(listModel), expectedOrder);
+ mWaitingForDataChange = true;
+ {
+ QVariant uuid = listModel->get(4, "_uuid");
+ QVERIFY(!uuid.toString().isEmpty());
+
+ QVariantMap item;
+ item.insert("_uuid", uuid);
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("order", "99"); // move it to the end
+ int id = mClient->update(item);
+ waitForResponse(id);
+ }
+
+ while (mWaitingForDataChange)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ expectedOrder = QStringList() << "1" << "2" << "3" <<
+ "4" << "6" << "7" << "8" << "9" << "99";
+ QCOMPARE(getOrderValues(listModel), expectedOrder);
+ mWaitingForDataChange = true;
+ {
+ QVariant uuid = listModel->get(8, "_uuid");
+ QVERIFY(!uuid.toString().isEmpty());
+
+ QVariantMap item;
+ item.insert("_uuid", uuid);
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("order", "22"); // move it after "2"
+ int id = mClient->update(item);
+ waitForResponse(id);
+ }
+
+ while (mWaitingForDataChange)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ expectedOrder = QStringList() << "1" << "2" << "22" << "3" <<
+ "4" << "6" << "7" << "8" << "9";
+ QCOMPARE(getOrderValues(listModel), expectedOrder);
+ mWaitingForDataChange = true;
+ {
+ QVariant uuid = listModel->get(5, "_uuid");
+ QVERIFY(!uuid.toString().isEmpty());
+
+ QVariantMap item;
+ item.insert("_uuid", uuid);
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("order", "0"); // move it to the beginning
+ int id = mClient->update(item);
+ waitForResponse(id);
+ }
+
+ while (mWaitingForDataChange)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+
+ expectedOrder = QStringList() << "0" << "1" << "2" << "22" << "3" <<
+ "4" << "7" << "8" << "9";
+ QCOMPARE(getOrderValues(listModel), expectedOrder);
+ deleteModel(listModel);
+
+}
+
+void TestJsonDbListModel::itemNotInCache()
+{
+ QVariantList itemList;
+ for (int i = 0; i < 1000; i++) {
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Number");
+ item.insert("order", i);
+ itemList << item;
+ }
+ int id = mClient->create(itemList);
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ connectListModel(listModel);
+ listModel->setLimit(80);
+ listModel->setQuery(QString("[?_type=\"%1\"][/order]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name" << "order");
+ listModel->setRoleNames(roleNames);
+ listModel->componentComplete();
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->rowCount(), 1000);
+
+ // Make sure that the first items in the list is in the cache.
+ QVariant result = listModel->data(listModel->index(10,0), listModel->roleFromString("order"));
+ QVERIFY(result.isValid());
+ QCOMPARE(result.toInt(), 10);
+ // This item should not be in the cache now.
+ QVariant res = listModel->data(listModel->index(960,0), listModel->roleFromString("order"));
+ QCOMPARE(res.toInt(), 960);
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::roles()
+{
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("name", "Charlie");
+ item.insert("phone", "123456789");
+ int id = mClient->create(item);
+
+ waitForResponse(id);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "name" << "phone");
+ listModel->setRoleNames(roleNames);
+ connectListModel(listModel);
+
+ // now start it working
+ listModel->componentComplete();
+ mEventLoop.exec( QEventLoop::AllEvents );
+ QCOMPARE(listModel->count(), 1);
+
+ QVariantMap roles = listModel->roleNames().toMap();
+ QCOMPARE(roles.size(), 4);
+ QVERIFY(roles.contains("name")) ;
+ QVERIFY(roles.contains("phone"));
+ QCOMPARE(listModel->roleFromString("_type"), 0);
+ QCOMPARE(listModel->roleFromString("_uuid"), 1);
+ QCOMPARE(listModel->roleFromString("name"), 2);
+ QCOMPARE(listModel->roleFromString("phone"), 3);
+ QCOMPARE(listModel->toString(0), QLatin1String("_type"));
+ QCOMPARE(listModel->toString(1), QLatin1String("_uuid"));
+ QCOMPARE(listModel->toString(2), QLatin1String("name"));
+ QCOMPARE(listModel->toString(3), QLatin1String("phone"));
+ QCOMPARE(listModel->toString(4), QLatin1String(""));
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::totalRowCount()
+{
+ int id = 0;
+ QVariantList insertedItems;
+ for (int i = 0; i < 10; i++) {
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("order", i);
+ id = mClient->create(item);
+ waitForResponse(id);
+ insertedItems << mData;
+ }
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel)
+ return;
+ connectListModel(listModel);
+
+ listModel->setLimit(10);
+ listModel->setQuery(QString("[?_type=\"%1\"]").arg(__FUNCTION__));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "order");
+ listModel->setRoleNames(roleNames);
+ listModel->componentComplete();
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->rowCount(), 10);
+
+ for (int i = 10; i < 50; i++) {
+ QVariantMap item;
+ item.insert("_type", __FUNCTION__);
+ item.insert("order", i);
+ mClient->create(item);
+ }
+
+ waitForItemsCreated(40);
+ QCOMPARE(listModel->rowCount(), 50);
+
+ // Change query
+ listModel->setQuery(QString("[?_type=\"%1\"][\\order]").arg(__FUNCTION__));
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->rowCount(), 50);
+
+ // Delete the first 10 items
+ foreach (QVariant item, insertedItems) {
+ mWaitingForRowsRemoved = true;
+ id = mClient->remove(item.toMap());
+ while(mWaitingForRowsRemoved)
+ mEventLoop.processEvents(QEventLoop::AllEvents);
+ }
+
+ QCOMPARE(listModel->rowCount(), 40);
+
+ deleteModel(listModel);
+}
+
+void TestJsonDbListModel::listProperty()
+{
+ QVariant jsonData = readJsonFile("list-objects.json");
+ QVariantList itemList = jsonData.toList();
+ int id = 0;
+ for (int i = 0; i < itemList.count(); i++) {
+ id = mClient->create(itemList[i].toMap());
+ waitForResponse(id);
+ }
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel)
+ return;
+ connectListModel(listModel);
+ QString type = itemList[0].toMap()["_type"].toString();
+ listModel->setLimit(10);
+ listModel->setQuery(QString("[?_type=\"%1\"][/features.0.properties.0.description]").arg(type));
+ QStringList roleNames = (QStringList() << "_type" << "_uuid" << "features.0.properties.0.description"<< "features.0.feature");
+ listModel->setRoleNames(roleNames);
+ listModel->componentComplete();
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->count(), itemList.count());
+ QCOMPARE(listModel->get(0, "_type").toString(), type);
+ QCOMPARE(listModel->get(0, "features.0.properties.0.description").toString(), QLatin1String("Facebook account provider"));
+ QCOMPARE(listModel->get(0, "features.0.feature").toString(), QLatin1String("provide Facebook"));
+ QCOMPARE(listModel->get(1, "_uuid").toString(), mLastUuid);
+ QCOMPARE(listModel->get(1, "_type").toString(), type);
+ QCOMPARE(listModel->get(1, "features.0.properties.0.description").toString(), QLatin1String("Gmail account provider"));
+ QCOMPARE(listModel->get(1, "features.0.feature").toString(), QLatin1String("provide Gmail"));
+
+ deleteModel(listModel);
+
+ listModel = createModel();
+ if (!listModel)
+ return;
+ connectListModel(listModel);
+ type = itemList[0].toMap()["_type"].toString();
+ listModel->setLimit(10);
+ listModel->setQuery(QString("[?_type=\"%1\"][/features.0.properties.0.description]").arg(type));
+ roleNames.clear();
+ roleNames = (QStringList() << "_type" << "_uuid" << "features[0].properties[0].description"<< "features[0].supported[0]");
+ listModel->setRoleNames(roleNames);
+ listModel->componentComplete();
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QCOMPARE(listModel->count(), itemList.count());
+ QCOMPARE(listModel->get(0, "_type").toString(), type);
+ QCOMPARE(listModel->get(0, "features[0].properties[0].description").toString(), QLatin1String("Facebook account provider"));
+ QCOMPARE(listModel->get(0, "features[0].supported[0]").toString(), QLatin1String("share"));
+ QCOMPARE(listModel->get(1, "_type").toString(), type);
+ QCOMPARE(listModel->get(1, "features[0].properties[0].description").toString(), QLatin1String("Gmail account provider"));
+ QCOMPARE(listModel->get(1, "features[0].supported[0]").toString(), QLatin1String("share"));
+
+ deleteModel(listModel);
+}
+
+
+QStringList TestJsonDbListModel::getOrderValues(const JsonDbListModel *listModel)
+{
+ QStringList vals;
+ for (int i = 0; i < listModel->count(); ++i)
+ vals << listModel->get(i, "order").toString();
+
+ return vals;
+}
+
+void TestJsonDbListModel::modelReset()
+{
+ //qDebug() << "TestJsonDbListModel::modelReset";
+ mEventLoop.exit(0);
+}
+void TestJsonDbListModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ Q_UNUSED(topLeft);
+ Q_UNUSED(bottomRight);
+ //qDebug() << "TestJsonDbListModel::dataChanged";
+ mWaitingForDataChange = false;
+}
+void TestJsonDbListModel::rowsInserted(const QModelIndex &parent, int first, int last)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(first);
+ Q_UNUSED(last);
+ mItemsCreated++;
+ //qDebug() << "TestJsonDbListModel::rowsInserted";
+ mEventLoop.exit(0);
+}
+void TestJsonDbListModel::rowsRemoved(const QModelIndex &parent, int first, int last)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(first);
+ Q_UNUSED(last);
+ mWaitingForRowsRemoved = false;
+ //qDebug() << "TestJsonDbListModel::rowsRemoved";
+}
+void TestJsonDbListModel::rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row )
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
+ Q_UNUSED(destination);
+ Q_UNUSED(row);
+ //qDebug() << "TestJsonDbListModel::rowsMoved";
+}
+
+QTEST_MAIN(TestJsonDbListModel)
+
diff --git a/tests/auto/jsondb-listmodel/test-jsondb-listmodel.h b/tests/auto/jsondb-listmodel/test-jsondb-listmodel.h
new file mode 100644
index 00000000..c0242566
--- /dev/null
+++ b/tests/auto/jsondb-listmodel/test-jsondb-listmodel.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TestJsonDbListModel_H
+#define TestJsonDbListModel_H
+
+#include <QCoreApplication>
+#include <QList>
+#include <QTest>
+#include <QFile>
+#include <QProcess>
+#include <QEventLoop>
+#include <QDebug>
+#include <QLocalSocket>
+
+#include <jsondb-client.h>
+#include <jsondb-error.h>
+
+#include "jsondb-listmodel.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+class Notification {
+public:
+ Notification( const QString& notifyUuid, const QVariant& object, const QString& action )
+ : mNotifyUuid(notifyUuid), mObject(object), mAction(action) {}
+
+ QString mNotifyUuid;
+ QVariant mObject;
+ QString mAction;
+};
+
+class QDeclarativeEngine;
+class QDeclarativeComponent;
+class JsonDbListModel;
+
+class ModelData {
+public:
+ ModelData();
+ ~ModelData();
+ QDeclarativeEngine *engine;
+ QDeclarativeComponent *component;
+ QObject *model;
+};
+
+class TestJsonDbListModel: public QObject
+{
+ Q_OBJECT
+public:
+ TestJsonDbListModel();
+ ~TestJsonDbListModel();
+
+ void deleteDbFiles();
+ void connectListModel(JsonDbListModel *model);
+
+public slots:
+ void notified(const QString& notifyUuid, const QVariant& object, const QString& action );
+ void response(int id, const QVariant& data);
+ void error( int id, int code, const QString& message );
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void rowsInserted(const QModelIndex &parent, int first, int last);
+ void rowsRemoved(const QModelIndex &parent, int first, int last);
+ void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row );
+ void modelReset();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void createItem();
+ void updateItemClient();
+ void updateItemSet();
+ void updateItemSetProperty();
+ void deleteItem();
+ void sortedQuery();
+ void ordering();
+ void itemNotInCache();
+ void roles();
+ void totalRowCount();
+ void listProperty();
+
+private:
+ void waitForResponse(QVariant id, int code=-1, QVariant notificationId=QVariant());
+ void waitForItemsCreated(int items);
+ QStringList getOrderValues(const JsonDbListModel *listModel);
+ JsonDbListModel *createModel();
+ void deleteModel(JsonDbListModel *model);
+ QVariant readJsonFile(const QString &filename);
+
+private:
+ QEventLoop mEventLoop;
+ QProcess *mProcess;
+ JsonDbClient *mClient;
+ QStringList mNotificationsReceived;
+ QList<ModelData*> mModels;
+ QString mPluginPath;
+
+ // Response values
+ QString mMessage;
+ QString mLastUuid;
+ int mCode;
+ int mItemsCreated;
+ QVariant mId, mData, mNotificationId;
+ bool mWaitingForNotification;
+ bool mWaitingForDataChange;
+ bool mWaitingForRowsRemoved;
+ QList<Notification> mNotifications;
+};
+
+#endif
diff --git a/tests/auto/qsonstream/qsonstream.pro b/tests/auto/qsonstream/qsonstream.pro
new file mode 100644
index 00000000..86d34ee4
--- /dev/null
+++ b/tests/auto/qsonstream/qsonstream.pro
@@ -0,0 +1,12 @@
+TARGET = tst_qsonstream
+
+QT = core testlib network declarative jsondbqson-private
+CONFIG -= app_bundle
+
+include($$PWD/../../../src/common/common.pri)
+
+SOURCES += test-qsonstream.cpp
+
+check.target = check
+check.commands = ./tst_qsonstream -xunitxml -silent > ../../../tst_qsonstream.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/auto/qsonstream/test-qsonstream.cpp b/tests/auto/qsonstream/test-qsonstream.cpp
new file mode 100644
index 00000000..6b35ecbf
--- /dev/null
+++ b/tests/auto/qsonstream/test-qsonstream.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest/QtTest>
+
+#include <qsonstream.h>
+#include <QLocalServer>
+#include <QLocalSocket>
+
+#include <QDebug>
+
+using namespace QtAddOn::JsonDb;
+
+class TestQsonStream: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void handleSocketConnection();
+ void receiveStream(const QsonObject &qson);
+
+private slots:
+ void testQsonStream();
+
+private:
+ QLocalServer *server;
+ bool serverOk;
+ int receiverOk;
+};
+
+void TestQsonStream::testQsonStream()
+{
+ serverOk = false;
+ receiverOk = 0;
+
+ QLocalServer::removeServer("testQsonStream");
+ server = new QLocalServer(this);
+ connect(server, SIGNAL(newConnection()), this, SLOT(handleSocketConnection()));
+ QVERIFY(server->listen("testQsonStream"));
+
+ QLocalSocket *device = new QLocalSocket(this);
+ device->connectToServer("testQsonStream");
+ QVERIFY(device->waitForConnected());
+ QVERIFY(device->state() == QLocalSocket::ConnectedState);
+
+ QsonStream *stream = new QsonStream(device, this);
+
+ connect(stream, SIGNAL(receive(const QsonObject&)),
+ this, SLOT(receiveStream(const QsonObject&)));
+
+ qApp->processEvents();
+ qApp->processEvents();
+ qApp->processEvents();
+ QVERIFY(serverOk);
+ QCOMPARE(receiverOk, 1);
+}
+
+void TestQsonStream::handleSocketConnection()
+{
+ qDebug() << "handleSocketConnection";
+ serverOk = true;
+ QsonStream sender(server->nextPendingConnection());
+
+ QsonMap qson;
+ qson.insert("hello", QString("world"));
+ sender.send(qson);
+}
+
+void TestQsonStream::receiveStream(const QsonObject &incoming)
+{
+ qDebug() << "receiveStream";
+ QsonMap qson(incoming);
+ receiverOk++;
+ QCOMPARE(qson.size(), 1);
+ QCOMPARE(qson.valueString("hello"), QString("world"));
+}
+
+
+QTEST_MAIN(TestQsonStream)
+#include "test-qsonstream.moc"
diff --git a/tests/auto/tests.xml b/tests/auto/tests.xml
new file mode 100644
index 00000000..27b76f6e
--- /dev/null
+++ b/tests/auto/tests.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<testdefinition version="0.1">
+ <suite domain="Functional" name="autotests" timeout="2000">
+ <set description=" Simple JSON DB auto tests " feature="JSONDB" level="System" name="jsondb-autotests" type="Functional" timeout="2000">
+ <case name="tst_bdb" requirement="RAT" component="qt5jsondb" timeout="300">
+ <description>BDB tests</description>
+ <step>cd /usr/lib/qt5jsondb-tests/auto/bdb;date &amp;&amp; ./tst_bdb &amp;&amp; date</step>
+ </case>
+ <case name="tst_client" requirement="RAT" component="qt5jsondb" timeout="100">
+ <description>Client library tests</description>
+ <step>cd /usr/lib/qt5jsondb-tests/auto/client;date &amp;&amp; ./tst_client&amp;&amp; date</step>
+ </case>
+ <case name="tst_common" requirement="RAT" component="qt5jsondb" timeout="100">
+ <description>Common functionality tests</description>
+ <step>cd /usr/lib/qt5jsondb-tests/auto/common;date &amp;&amp; ./tst_common &amp;&amp; date</step>
+ </case>
+ <case name="tst_daemon" requirement="RAT" component="qt5jsondb" timeout="2000">
+ <description> JsonDb daemon tests</description>
+ <step>cd /usr/lib/qt5jsondb-tests/auto/daemon;date &amp;&amp; ./tst_daemon &amp;&amp; date</step>
+ </case>
+ <case name="tst_jsondb-listmodel" requirement="RAT" component="qt5jsondb" timeout="2000">
+ <description>QML JsonDbListModel tests</description>
+ <step>cd /usr/lib/qt5jsondb-tests/auto/jsondb-listmodel;date &amp;&amp; ./tst_jsondb-listmodel -platform minimal&amp;&amp; date</step>
+ </case>
+ <case name="tst_qsonstream" requirement="RAT" component="qt5jsondb" timeout="2000">
+ <description>Client-Server IPC tests</description>sphone
+ <step>cd /usr/lib/qt5jsondb-tests/auto/qsonstream;date &amp;&amp; ./tst_qsonstream &amp;&amp; date</step>
+ </case>
+ </set>
+ </suite>
+</testdefinition>
diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro
new file mode 100644
index 00000000..213bc62b
--- /dev/null
+++ b/tests/benchmarks/benchmarks.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += daemon jsondb-listmodel client
diff --git a/tests/benchmarks/client/client-benchmark.cpp b/tests/benchmarks/client/client-benchmark.cpp
new file mode 100644
index 00000000..158c29de
--- /dev/null
+++ b/tests/benchmarks/client/client-benchmark.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include "client-benchmark.h"
+#include <json.h>
+
+#include "util.h"
+
+static const char dbfile[] = "dbFile-test-jsondb";
+
+int gMany = ::getenv("BENCHMARK_MANY") ? ::atoi(::getenv("BENCHMARK_MANY")) : 1000;
+
+TestJson::TestJson()
+ : mProcess(0)
+{
+}
+
+TestJson::~TestJson()
+{
+}
+
+void TestJson::removeDbFiles()
+{
+ // remove all the test files.
+ QDir currentDir;
+ QStringList nameFilter;
+ nameFilter << QString("*.db");
+ nameFilter << "objectFile.bin" << "objectFile2.bin";
+ QFileInfoList databaseFiles = currentDir.entryInfoList(nameFilter, QDir::Files);
+ foreach (QFileInfo fileInfo, databaseFiles) {
+ //qDebug() << "Deleted : " << fileInfo.fileName();
+ QFile file(fileInfo.fileName());
+ file.remove();
+ }
+}
+
+void TestJson::initTestCase()
+{
+#ifndef DONT_START_SERVER
+ removeDbFiles();
+ QString socketName = QString("testjsondb_%1").arg(getpid());
+ mProcess = launchJsonDbDaemon(JSONDB_DAEMON_BASE, socketName, QStringList() << dbfile);
+#endif
+
+ connectToServer();
+
+ QByteArray friendJson("{\"type\": \"object\", \"properties\": {\"name\": {\"type\": \"string\", \"indexed\": true}}}");
+
+ JsonReader reader;
+
+ // Create schemas for the items
+ reader.parse(friendJson);
+ QVariantMap friendSchema;
+ friendSchema.insert("name", "Friends");
+ friendSchema.insert("schema", reader.result());
+ friendSchema.insert("_type", "_schemaType");
+ int id = mClient->create(friendSchema);
+ waitForResponse1(id);
+
+ // Create alot of items in the database
+ for (int k = 0; k < gMany; k += 100) {
+ QVariantList friendsList;
+ for (int i = k; i < k+100; i++) {
+ QVariantMap item;
+ item.insert("_type", "Friends");
+ item.insert("name", QString("Name-%1").arg(i));
+ item.insert("phone",QString("%1").arg(qrand()));
+ friendsList << item;
+ }
+ id = mClient->create(friendsList);
+ waitForResponse1(id);
+ }
+
+ for (int k = 0; k < gMany; k += 100) {
+ QVariantList imageList;
+ for (int i = k; i < k+100; i++) {
+ QVariantMap item;
+ item.insert("_type", "Image");
+ item.insert("name", QString("Name-%1.jpg").arg(qrand()));
+ item.insert("location",QString("/home/qt/Pictures/Myfolder-%1").arg(i));
+ imageList << item;
+ }
+ id = mClient->create(imageList);
+ waitForResponse1(id);
+ }
+
+ for (int k = 0; k < gMany; k += 100) {
+ QVariantList numberList;
+ for (int i = k; i < k+100; i++) {
+ QVariantMap item;
+ item.insert("_type", "randNumber");
+ item.insert("number", qrand()%gMany);
+ item.insert("idNumber", i);
+ numberList << item;
+ }
+ id = mClient->create(numberList);
+ waitForResponse1(id);
+ }
+}
+
+void TestJson::cleanupTestCase()
+{
+ if (mClient) {
+ delete mClient;
+ mClient = NULL;
+ }
+
+ if (mProcess) {
+ mProcess->kill();
+ mProcess->waitForFinished();
+ delete mProcess;
+ mProcess = NULL;
+ }
+
+ removeDbFiles();
+}
+
+void TestJson::createOneItem()
+{
+ QVariantMap item;
+ item.insert("_type", "Contact");
+ item.insert("name", "Charlie");
+ item.insert("phone","123456789");
+
+ QBENCHMARK {
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ }
+}
+
+
+void TestJson::createThousandItems()
+{
+ QBENCHMARK {
+ for (int i = 0; i < gMany; ++i) {
+ QVariantMap item;
+ item.insert("_type", "randNumber");
+ item.insert("number", qrand()%100);
+ item.insert("idNumber", i);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ }
+ }
+}
+
+void TestJson::findOneItem()
+{
+ QVariantMap item;
+ item.insert("query","[?_type=\"Friends\"][?name=\"Name-49\"]");
+
+ QBENCHMARK {
+ int id = mClient->find(item);
+ waitForResponse1(id);
+ }
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QVERIFY(items.count() == 1);
+}
+
+void TestJson::findThousandItems()
+{
+ QVariantMap item;
+ item.insert("query","[?_type=\"Friends\"]");
+
+ QBENCHMARK {
+ int id = mClient->find(item);
+ waitForResponse1(id);
+ }
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QVERIFY(items.count() >= gMany);
+}
+
+void TestJson::findThousandItemsSorted()
+{
+ QVariantMap item;
+ item.insert("query","[?_type=\"Friends\"][/name]");
+
+ QBENCHMARK {
+ int id = mClient->find(item);
+ waitForResponse1(id);
+ }
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QVERIFY(items.count() >= gMany);
+}
+
+void TestJson::queryOneItem()
+{
+ QString queryString("[?_type=\"Friends\"][?name=\"Name-49\"]");
+ QBENCHMARK {
+ int id = mClient->query(queryString);
+ waitForResponse1(id);
+ }
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QVERIFY(items.count() == 1);
+}
+
+void TestJson::queryThousandItems_data()
+{
+ QTest::addColumn<QString>("queryString");
+ QTest::newRow("Friends") << QString("[?_type=\"Friends\"]");
+ QTest::newRow("Friends[=_uuid]") << QString("[?_type=\"Friends\"][=_uuid]");
+ QTest::newRow("Friends[={_uuid:_uuid}]") << QString("[?_type=\"Friends\"][={_uuid:_uuid}]");
+}
+
+void TestJson::queryThousandItems()
+{
+ QFETCH(QString, queryString);
+ QBENCHMARK {
+ int id = mClient->query(queryString);
+ waitForResponse1(id);
+ }
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QVERIFY(items.count() >= gMany);
+}
+
+void TestJson::updateOneItem()
+{
+ QVariantMap item;
+ item.insert("_type", "Contact");
+ item.insert("name", "Markus");
+ item.insert("phone","123456789");
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ item.insert("phone","111122223");
+ item.insert("_uuid", mLastUuid);
+
+ QBENCHMARK {
+ int id = mClient->update(item);
+ waitForResponse1(id);
+ }
+}
+
+void TestJson::updateThousandItems()
+{
+ // create thousand items
+ for (int i = 0; i < gMany; i++) {
+ QVariantMap item;
+ item.insert("_type", "updateThousandItems");
+ item.insert("number", qrand()%gMany);
+ item.insert("idNumber", i);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ }
+
+ QBENCHMARK {
+ QString queryString("[?_type=\"updateThousandItems\"]");
+ int id = mClient->query(queryString);
+ waitForResponse1(id);
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QCOMPARE(items.count(), gMany);
+ for (int i = 0; i < gMany; i++) {
+ QVariantMap mapItem = items.at(i).toMap();
+ mapItem.insert("number",gMany+i);
+ int id = mClient->update(mapItem);
+ waitForResponse1(id);
+ }
+ }
+
+ // remove those items
+ QString queryString("[?_type=\"updateThousandItems\"]");
+ int id = mClient->remove(queryString);
+ waitForResponse1(id);
+}
+
+void TestJson::removeOneItem()
+{
+ QVariantMap item;
+ item.insert("_type", "Contact");
+ item.insert("name", "Marius");
+ item.insert("phone","123456789");
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ item.insert("_uuid", mLastUuid);
+ QBENCHMARK_ONCE {
+ int id = mClient->remove(item);
+ waitForResponse1(id);
+ }
+}
+
+void TestJson::removeThousandItems()
+{
+ for (int i = 0; i < gMany; i++) {
+ QVariantMap item;
+ item.insert("_type", "removeThousandItems");
+ item.insert("number", qrand()%gMany);
+ item.insert("idNumber", i);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ }
+
+ QString queryString("[?_type=\"removeThousandItems\"]");
+ QBENCHMARK_ONCE {
+ int id = mClient->query(queryString);
+ waitForResponse1(id);
+
+ QVariantMap mapResponse = mData.toMap();
+ QVariantList items = mapResponse.value("data").toList();
+ QCOMPARE(items.count(), gMany);
+ for (int i = 0; i < gMany; i++) {
+ QVariantMap mapItem = items.at(i).toMap();
+ int id = mClient->remove(mapItem);
+ waitForResponse1(id);
+ }
+ }
+}
+
+void TestJson::removeWithQuery()
+{
+ for (int i = 0; i < gMany; i++) {
+ QVariantMap item;
+ item.insert("_type", "removeThousandItems");
+ item.insert("number", qrand()%gMany);
+ item.insert("idNumber", i);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+ }
+
+ QString queryString("[?_type=\"removeThousandItems\"]");
+ QBENCHMARK_ONCE {
+ int id = mClient->remove(queryString);
+ waitForResponse1(id);
+ }
+
+ QVariantMap mapResponse = mData.toMap();
+ QCOMPARE(mapResponse.value("count").toInt(), gMany);
+ QVariantList items = mapResponse.value("data").toList();
+ QVERIFY(items.count() >= gMany);
+}
+
+void TestJson::notifyUpdateOneItem()
+{
+ QVariantMap item;
+ item.insert("_type", "Friends");
+ item.insert("name", "Malte");
+ item.insert("phone","123456789");
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ QString itemUuid = mLastUuid;
+
+ QVariantMap item2;
+ item2.insert("_type","notification");
+ QString queryString;
+ queryString = QString("[?_uuid=\"%1\"]").arg(mLastUuid);
+ item2.insert("query",queryString);
+ QVariantList actions;
+ actions << "update";
+ item2.insert("actions",actions);
+ id = mClient->create(item2);
+ waitForResponse1(id);
+
+ QString notifyUuid = mLastUuid;
+ QVERIFY(!notifyUuid.isEmpty());
+
+ item.insert("phone","111122223");
+ item.insert("_uuid", itemUuid );
+
+ int i = 0;
+ QBENCHMARK {
+ item.insert("phone",QString("11112%1").arg(i++, 4));
+ int id = mClient->update(item);
+ waitForResponse4(id, -1, notifyUuid, 1);
+ }
+
+ // remove notification object
+ item2.insert("_uuid",notifyUuid);
+ id = mClient->remove(item2);
+ waitForResponse1(id);
+}
+
+void TestJson::notifyCreateOneItem()
+{
+ QVariantMap item;
+ QVariantList actions;
+ actions << "create";
+ item.insert("_type","notification");
+ item.insert("query","[?_type=\"Friends\"]");
+ item.insert("actions",actions);
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ QString notifyUuid = mLastUuid;
+ QVERIFY(!notifyUuid.isEmpty());
+
+ QVariantMap item2;
+ item2.insert("_type", "Friends");
+ item2.insert("name", "Marve");
+ item2.insert("phone","123456789");
+
+ QBENCHMARK {
+ int id = mClient->create(item2);
+ waitForResponse4(id, -1, notifyUuid, 1);
+ }
+
+ // remove notification object
+ item.insert("_uuid",notifyUuid);
+ id = mClient->remove(item);
+ waitForResponse1(id);
+}
+
+void TestJson::notifyRemoveOneItem()
+{
+ QVariantMap item;
+ item.insert("_type", "Friends");
+ item.insert("name", "Micke");
+ item.insert("phone","123456789");
+ int id = mClient->create(item);
+ waitForResponse1(id);
+
+ QString itemUuid = mLastUuid;
+ QVERIFY(!itemUuid.isEmpty());
+
+ QVariantMap item2;
+ QVariantList actions;
+ actions << "remove";
+ item2.insert("_type","notification");
+ item2.insert("query","[?_type=\"Friends\"]");
+ item2.insert("actions",actions);
+ id = mClient->create(item2);
+ waitForResponse1(id);
+
+ QString notifyUuid = mLastUuid;
+ QVERIFY(!notifyUuid.isEmpty());
+
+ item.insert("_uuid", itemUuid);
+
+ QBENCHMARK_ONCE {
+ int id = mClient->remove(item);
+ waitForResponse4(id, -1, notifyUuid, 1);
+ }
+
+ // remove notification object
+ item2.insert("_uuid",notifyUuid);
+ id = mClient->remove(item2);
+ waitForResponse1(id);
+}
+
+QTEST_MAIN(TestJson)
diff --git a/tests/benchmarks/client/client-benchmark.h b/tests/benchmarks/client/client-benchmark.h
new file mode 100644
index 00000000..bdaa6a6a
--- /dev/null
+++ b/tests/benchmarks/client/client-benchmark.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLIENT_BENCHMARK_H
+#define CLIENT_BENCHMARK_H
+
+#include <QCoreApplication>
+#include <QProcess>
+#include <QTest>
+#include <QDebug>
+
+#include <QEventLoop>
+#include <QLocalSocket>
+
+#include <jsondb-client.h>
+#include <jsondb-error.h>
+#include <private/jsondb-connection_p.h>
+
+#include "clientwrapper.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+class TestJson: public ClientWrapper
+{
+ Q_OBJECT
+public:
+ TestJson();
+ ~TestJson();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void createOneItem();
+ void createThousandItems();
+ void findOneItem();
+ void findThousandItems();
+ void findThousandItemsSorted();
+ void queryOneItem();
+ void queryThousandItems_data();
+ void queryThousandItems();
+ void updateOneItem();
+ void updateThousandItems();
+ void removeOneItem();
+ void removeThousandItems();
+ void removeWithQuery();
+ void notifyUpdateOneItem();
+ void notifyCreateOneItem();
+ void notifyRemoveOneItem();
+
+private:
+ QProcess *mProcess;
+
+ void removeDbFiles();
+};
+
+#endif
diff --git a/tests/benchmarks/client/client.pro b/tests/benchmarks/client/client.pro
new file mode 100644
index 00000000..c9acd04c
--- /dev/null
+++ b/tests/benchmarks/client/client.pro
@@ -0,0 +1,25 @@
+TEMPLATE = app
+TARGET = tst_bench_client
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT = core network testlib jsondb jsondb-private
+
+DEFINES += JSONDB_DAEMON_BASE=\\\"$$QT.jsondb.bins\\\"
+
+INCLUDEPATH += "../../../src/common"
+INCLUDEPATH += "../../../src/3rdparty/qjson/src"
+SOURCES += ../../../src/3rdparty/qjson/src/json.cpp
+
+CONFIG += qtestlib
+CONFIG -= app_bundle
+
+include($$PWD/../../shared/shared.pri)
+
+# Input
+HEADERS += client-benchmark.h
+SOURCES += client-benchmark.cpp
+
+check.target = check
+check.commands = LD_LIBRARY_PATH=../../../lib ./tst_bench_client -xunitxml -silent > ../../../tst_bench_client.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/benchmarks/daemon/bench_daemon.cpp b/tests/benchmarks/daemon/bench_daemon.cpp
new file mode 100644
index 00000000..29276d48
--- /dev/null
+++ b/tests/benchmarks/daemon/bench_daemon.cpp
@@ -0,0 +1,986 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QByteArray>
+#include <QFile>
+#include <QFileInfo>
+#include <QDir>
+#include <QTime>
+
+#include "json.h"
+
+#include <QtJsonDbQson/private/qson_p.h>
+
+#include "jsondb.h"
+#include "jsondbbtreestorage.h"
+#include "jsondbindex.h"
+#include "jsondb-strings.h"
+#include "jsondb-error.h"
+
+#include "../../shared/util.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+Q_DECLARE_METATYPE(QsonList)
+Q_DECLARE_METATYPE(QsonMap)
+
+class TestJsonDb: public QObject
+{
+ Q_OBJECT
+public:
+ TestJsonDb();
+
+private slots:
+ void init();
+ void initTestCase();
+ void cleanupTestCase();
+ void cleanup();
+ void contactListChaff();//moved from auto/daemon
+ void qsonListCreate();
+ void qsonMapCreate();
+
+ void qsonListReadValue_data();
+ void qsonListReadValue();
+ void qsonMapReadValue_data();
+ void qsonMapReadValue();
+
+ void qsonListInsertValue();
+ void qsonMapInsertValue();
+
+ void benchmarkCreate();
+ void benchmarkFileAppend();
+ void benchmarkFileAppend2();
+ void benchmarkParseQuery_data();
+ void benchmarkParseQuery();
+ void benchmarkFieldMatch();
+ void benchmarkTokenizer();
+ void benchmarkForwardKeyCmp();
+ void benchmarkParsedQuery();
+
+ void benchmarkSchemaValidation_data();
+ void benchmarkSchemaValidation();
+
+ void benchmarkFind();
+ void benchmarkFindByName();
+ void benchmarkFindEQ();
+ void benchmarkFindLE();
+ void benchmarkFind10();
+ void benchmarkFind20();
+ void benchmarkFindUnindexed();
+ void benchmarkFindReindexed();
+ void benchmarkFindNames();
+ void findNamesMapL();
+ void benchmarkFindNamesMapL();
+ void findNamesMapO();
+ void benchmarkFindNamesMapO();
+ void benchmarkCursorCount();
+ void benchmarkQueryCount();
+ void benchmarkScriptEngineCreation();
+
+private:
+ QsonObject readJsonFile(const QString &filename);
+ QsonObject readJson(const QByteArray &json);
+ void removeDbFiles();
+ void addSchema(const QString &schemaName, QsonMap &schemaObject);
+
+private:
+ JsonDb *mJsonDb;
+ QsonList mContactList;
+ JsonDbOwner *mOwner;
+};
+
+#define verifyGoodResult(result) \
+{ \
+ QsonMap __result = result; \
+ QVERIFY(__result.contains(JsonDbString::kErrorStr)); \
+ QVERIFY2(__result.isNull(JsonDbString::kErrorStr), __result.subObject(JsonDbString::kErrorStr).valueString("message").toLocal8Bit()); \
+ QVERIFY(__result.contains(JsonDbString::kResultStr)); \
+}
+
+const char *kFilename = "testdatabase";
+
+TestJsonDb::TestJsonDb()
+ : mJsonDb(NULL), mOwner(0)
+{
+}
+
+void TestJsonDb::removeDbFiles()
+{
+ QStringList filters;
+ filters << QString::fromLatin1(kFilename)+QLatin1Char('*');
+ filters << QString("*.db") << "objectFile.bin" << "objectFile2.bin";
+ QStringList lst = QDir().entryList(filters);
+ foreach (const QString &fileName, lst)
+ QFile::remove(fileName);
+}
+
+void TestJsonDb::initTestCase()
+{
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("TestJsonDb");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ removeDbFiles();
+ gVerbose = false;
+ mJsonDb = new JsonDb(kFilename, this);
+ mJsonDb->open();
+ mOwner = new JsonDbOwner(this);
+ mOwner->setOwnerId("com.noklab.nrcc.JsonDbTest");
+
+ QFile contactsFile(findFile(SRCDIR, "../../auto/daemon/largeContactsTest.json"));
+ if (!contactsFile.exists()) {
+ qDebug() << "Err: largeContactsTest.json doesn't exist!";
+ return;
+ }
+ contactsFile.open(QIODevice::ReadOnly);
+ QByteArray json = contactsFile.readAll();
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok)
+ qDebug() << parser.errorString();
+ QVariantList contactList = parser.result().toList();
+ QsonList newContactList;
+ foreach (QVariant v, contactList) {
+ QsonMap contact = QsonMap(variantToQson(v.toMap()));
+ QString name = contact.valueString("name");
+ QStringList names = name.split(" ");
+ QsonMap nameObject;
+ nameObject.insert("first", names[0]);
+ nameObject.insert("last", names[names.size()-1]);
+ contact.insert("name", nameObject);
+ contact.insert(JsonDbString::kTypeStr, QString("contact"));
+ newContactList.append(contact);
+ }
+ mContactList = newContactList;
+
+ mJsonDb->addIndex(QLatin1String("name"));
+ mJsonDb->addIndex(QLatin1String("name.first"));
+ mJsonDb->addIndex(QLatin1String("name.last"));
+ mJsonDb->addIndex(QLatin1String("_type"));
+
+ qDebug() << "Creating" << mContactList.size() << "contacts...";
+
+ QElapsedTimer time;
+ time.start();
+ int count = 0;
+ for (; count < mContactList.size(); count++) {
+ QsonMap contact = mContactList.objectAt(count);
+ mJsonDb->create(mOwner, contact);
+ }
+
+ long elapsed = time.elapsed();
+ qDebug() << "done. Time per item (ms):" << (double)elapsed / count << "count" << count << "elapsed" << elapsed << "ms";
+}
+
+void TestJsonDb::init()
+{
+}
+
+void TestJsonDb::cleanupTestCase()
+{
+ if (mJsonDb) {
+ mJsonDb->close();
+ delete mJsonDb;
+ mJsonDb = 0;
+ }
+ removeDbFiles();
+}
+
+void TestJsonDb::cleanup()
+{
+ foreach(JsonDbBtreeStorage *storage, mJsonDb->mStorages)
+ QCOMPARE(storage->mTransactionDepth, 0);
+ //QVERIFY(mJsonDb->checkValidity());
+}
+
+void TestJsonDb::addSchema(const QString &schemaName, QsonMap &schemaObject)
+{
+ QsonObject schema = readJsonFile(QString("../../auto/daemon/schemas/%1.json").arg(schemaName));
+ schemaObject = QsonMap();
+ schemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ schemaObject.insert("name", schemaName);
+ schemaObject.insert("schema", schema);
+
+ QsonMap result = mJsonDb->create(mOwner, schemaObject);
+ verifyGoodResult(result);
+}
+
+void TestJsonDb::qsonListCreate()
+{
+ QBENCHMARK {
+ QsonList list;
+ }
+}
+
+void TestJsonDb::qsonMapCreate()
+{
+ QBENCHMARK {
+ QsonMap map;
+ }
+}
+
+void TestJsonDb::qsonListReadValue_data()
+{
+ QTest::addColumn<QsonList>("list");
+ QTest::addColumn<int>("index");
+ QTest::addColumn<int>("value");
+
+ QsonList data2;
+ data2.append(123);
+ data2.append(133);
+ data2.append(323);
+ QTest::newRow("small list") << data2 << 2 << 323;
+
+ QsonList data3;
+ for (int i = 0; i < 256; ++i)
+ data3.append(i);
+ QTest::newRow("large list") << data3 << 12 << 12;
+}
+
+void TestJsonDb::qsonListReadValue()
+{
+ QFETCH(QsonList, list);
+ QFETCH(int, index);
+ QFETCH(int, value);
+
+ QBENCHMARK {
+ QCOMPARE(list.at<int>(index), value);
+ }
+}
+
+void TestJsonDb::qsonMapReadValue_data()
+{
+ QTest::addColumn<QsonMap>("map");
+ QTest::addColumn<QString>("property");
+ QTest::addColumn<int>("value");
+
+ QsonMap data1;
+ data1.insert(QString::number(1), 123);
+ data1.insert(QString::number(12), 133);
+ data1.insert(QString::number(123), 323);
+ QTest::newRow("small map") << data1 << QString::number(123) << 323;
+
+ QsonMap data2;
+ for (int i = 0; i < 256; ++i)
+ data2.insert(QString::number(i), i);
+ QTest::newRow("large map") << data2 << QString::number(12) << 12;
+}
+
+void TestJsonDb::qsonMapReadValue()
+{
+ QFETCH(QsonMap, map);
+ QFETCH(QString, property);
+ QFETCH(int, value);
+
+ QBENCHMARK {
+ QCOMPARE(map.value<int>(property), value);
+ }
+}
+
+void TestJsonDb::qsonListInsertValue()
+{
+ QBENCHMARK {
+ QsonList list;
+ for (int i = 0; i < 1024; ++i)
+ list.append(i);
+ }
+}
+
+void TestJsonDb::qsonMapInsertValue()
+{
+ const int iterations = 1024;
+ QVarLengthArray<QString, iterations> names;
+
+ for (int i = 0; i < iterations; ++i)
+ names.append(QString::number(i));
+
+ QBENCHMARK {
+ QsonMap map;
+ for (int i = 0; i < iterations; ++i)
+ map.insert(names[i], i);
+ }
+}
+
+void TestJsonDb::benchmarkCreate()
+{
+ QsonList contacts(readJsonFile("../../auto/daemon/largeContactsTest.json"));
+ QBENCHMARK {
+ QsonMap contact = contacts.objectAt(0);
+ mJsonDb->create(mOwner, contact);
+ }
+}
+
+void TestJsonDb::benchmarkFileAppend()
+{
+ QsonList contacts(readJsonFile("../../auto/daemon/largeContactsTest.json"));
+ QFile objectFile("objectFile.bin");
+ objectFile.open(QIODevice::ReadWrite);
+
+ QBENCHMARK {
+ objectFile.write(contacts.objectAt(0).data());
+ objectFile.flush();
+ fsync(objectFile.handle());
+ }
+}
+
+void TestJsonDb::benchmarkFileAppend2()
+{
+ QsonObject bson(readJsonFile("../../auto/daemon/largeContactsTest.json"));
+ QsonList contacts(bson);
+ QFile objectFile("objectFile.bin");
+ objectFile.open(QIODevice::ReadWrite);
+ QFile objectFile2("objectFile2.bin");
+ objectFile2.open(QIODevice::ReadWrite);
+
+ QBENCHMARK {
+ objectFile.write(contacts.objectAt(0).data());
+ objectFile.flush();
+ objectFile2.write(contacts.objectAt(0).data());
+ objectFile2.flush();
+ fsync(objectFile2.handle());
+ fsync(objectFile.handle());
+ }
+}
+
+void TestJsonDb::benchmarkParseQuery_data()
+{
+ QTest::addColumn<QString>("query");
+ QTest::newRow("1") << "[?foo exists]";
+ QTest::newRow("2") << "[?foo->bar exists]";
+ QTest::newRow("3") << "[?foo->bar->baz exists]";
+ QTest::newRow("4") << "[?foo=\"bar\"]";
+ QTest::newRow("5") << "[?foo= %bar ]";
+ QTest::newRow("6") << "[?foo= %bar]";
+ QTest::newRow("7") << "[?foo=%bar]";
+ QTest::newRow("8") << "[?foo=\"bar\" | foo=\"baz\"]";
+ QTest::newRow("9") << "[?foo=\"bar\"][/foo]";
+ QTest::newRow("10") << "[?foo=\"bar\"][= a ]";
+ QTest::newRow("11") << "[?foo =~ \"/a\\//\"]";
+ QTest::newRow("12") << "[?foo=\"bar\"][= a,b,c]";
+ QTest::newRow("13") << "[?foo=\"bar\"][= a->foreign,b,c]";
+ QTest::newRow("14") << "[?foo=\"bar\"][=[ a,b,c]]";
+ QTest::newRow("15") << "[?foo=\"bar\"][={ a:x, b:y, c:z}]";
+ QTest::newRow("16") << "[?foo=\"bar\"][={ a:x->foreign, b:y, c:z}]";
+ QTest::newRow("17") << "[?foo=\"bar\"][= _uuid, name.first, name.last ]";
+ QTest::newRow("18") << "[?_type=\"contact\"][= { uuid: _uuid, first: name.first, last: name.last } ]";
+ QTest::newRow("19") << "[?telephoneNumbers.*.number=\"6175551212\"]";
+ QTest::newRow("20") << "[?_type=\"contact\"][= .telephoneNumbers[*].number]";
+ QTest::newRow("21") << "[?_type=\"contact\"][?foo startsWith \"bar\"]";
+}
+
+void TestJsonDb::benchmarkParseQuery()
+{
+ QFETCH(QString, query);
+ QsonMap bindings;
+ bindings.insert("bar", QString("barValue"));
+ QBENCHMARK {
+ JsonDbQuery::parse(query, bindings);
+ }
+}
+
+void TestJsonDb::benchmarkFieldMatch()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ QString query =
+ QString("[?%1=\"%2\"][?name<=\"%3\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(item.valueString("name"));
+ QRegExp fieldMatch("^\\[\\?\\s*([^\\[\\]]+)\\s*\\](.*)");
+ QBENCHMARK {
+ fieldMatch.exactMatch(query);
+ }
+}
+
+void TestJsonDb::benchmarkTokenizer()
+{
+ QStringList queries = (QStringList()
+ << "[?abc=\"def\"]"
+ << "[ ? abc = \"def\" \t]"
+ << "[?abc.def=\"ghi\"]"
+ << "[?abc->def=\"ghi\"]"
+ << "[?abc.def=\"ghi\"][/abc.def]"
+ << "[?abc.def=\"ghi\"][\\foo]"
+ << "[?abc.def=\"ghi\"][=foo]"
+ << "[?abc.def=\"ghi\"][=foo,bar]"
+ << "[?abc.def=\"ghi\"][=.foo,.bar]"
+ << "[?abc.def=\"ghi\"][=[.foo,.bar]]"
+ << "[?abc.def=\"ghi\"][={foo:Foo,bar:Bar}][/foo]"
+ );
+ foreach (QString query, queries) {
+ QBENCHMARK {
+ JsonDbQueryTokenizer tokenizer(query);
+ //qDebug() << "query" << query;
+ //int i = 0;
+ QString token;
+ while (!(token = tokenizer.pop()).isEmpty()) {
+ //qDebug() << QString(" token[%1] %2 ").arg(i++).arg(token);
+ }
+ }
+ }
+}
+
+namespace QtAddOn { namespace JsonDb {
+extern QByteArray makeForwardKey(const QVariant &fieldValue, const ObjectKey &objectKey);
+extern int forwardKeyCmp(const char *aptr, size_t asiz, const char *bptr, size_t bsiz, void *op);
+} } // end namespace QtAddOn::JsonDb
+
+void TestJsonDb::benchmarkForwardKeyCmp()
+{
+ int count = mContactList.size();
+
+ QVector<QByteArray> keys;
+ for (int ii = 0; ii < mContactList.size(); ii++) {
+ QsonMap object = mContactList.objectAt(ii);
+ QString typeName = object.valueString(JsonDbString::kTypeStr);
+ //int typeNumber = ((JsonDbBtreeStorage *)mJsonDb->mStorage)->getTypeNumber(typeName);
+ QVariant fullname = QVariant(object.valueString("fullname"));
+ QByteArray key = makeForwardKey(fullname, ObjectKey());
+ keys.append(key);
+ }
+
+ QBENCHMARK {
+ for (int j = 0; j < count; j++) {
+ QByteArray key1 = keys[j];
+ for (int i = 0; i < count; i++) {
+ QByteArray key2 = keys[i];
+ int cmp = forwardKeyCmp(key1.constData(), key1.size(), key2.constData(), key2.size(), 0);
+ if (i == j)
+ QVERIFY(cmp == 0);
+ /* Note: this fails horrible but I guess it shouldn't
+ else
+ QVERIFY(cmp != 0);
+ */
+ }
+ }
+ }
+}
+
+void TestJsonDb::benchmarkParsedQuery()
+{
+#warning skipping
+ return;
+
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+
+ QString query =
+ QString("[?%1=\"%2\"][?name<=\"%3\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(item.valueString("name"));
+ QsonMap bindings;
+ JsonDbQuery parsedQuery = JsonDbQuery::parse(query, bindings);
+
+ QBENCHMARK {
+ QsonMap request;
+ //QVariantList queryTerms = parseResult.value("queryTerms").toList();
+ //QVariantList orderTerms = parseResult.value("orderTerms").toList();
+ int limit = 1;
+ int offset = 0;
+ QsonMap result = mJsonDb->findPartition("default")->queryPersistentObjects(mOwner, parsedQuery, limit, offset);
+ if (result.value<int>("length") != 1) {
+ qDebug() << "result length" << result.value<int>("length");
+ qDebug() << "item" << item;
+ qDebug() << "itemNumber" << itemNumber;
+ }
+ QCOMPARE(result.value<int>("length"), 1);
+ // qDebug() << "result.keys()" << result.keys();
+ }
+}
+
+void TestJsonDb::benchmarkSchemaValidation_data()
+{
+ QTest::addColumn<QByteArray>("item");
+ QTest::addColumn<bool>("isPerson");
+ QTest::addColumn<bool>("isAdult");
+
+ QTest::newRow("empty")
+ << QByteArray("{}") << true << true;
+ QTest::newRow("40 and 4")
+ << QByteArray("{ \"name\":\"40 and 4\" }") << true << true;
+ QTest::newRow("Alice")
+ << QByteArray("{ \"name\":\"Alice\", \"age\": 5}") << true << false;
+ QTest::newRow("Alice's mother")
+ << QByteArray("{ \"name\":\"Alice's mother\", \"age\": 32}") << true << true;
+ QTest::newRow("Alice's grandmother")
+ << QByteArray("{ \"name\":\"Alice's grandmother\", \"age\": 100}") << true << true;
+ QTest::newRow("Alice's great-grandmother")
+ << QByteArray("{ \"name\":\"Alice's great-grandmother\", \"age\": 130}") << false << false;
+}
+
+void TestJsonDb::benchmarkSchemaValidation()
+{
+ bool validate = gValidateSchemas;
+ gValidateSchemas = true;
+
+ QFETCH(QByteArray, item);
+ QFETCH(bool, isPerson);
+ QFETCH(bool, isAdult);
+ Q_UNUSED(isAdult);
+
+ const QByteArray person =
+ "{"
+ " \"description\": \"A person\","
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"name\": {\"type\": \"string\"},"
+ " \"age\" : {\"type\": \"integer\", \"maximum\": 125 }"
+ " }"
+ "}";
+ static int schemaId = 0;
+ const QString personSchemaName = QString::fromLatin1("personBenchmark") + QString::number(++schemaId);
+
+ QsonMap qResult;
+ QsonMap personSchemaBody = readJson(person);
+ QsonMap personSchemaObject;
+ personSchemaObject.insert(JsonDbString::kTypeStr, JsonDbString::kSchemaTypeStr);
+ personSchemaObject.insert("name", personSchemaName);
+ personSchemaObject.insert("schema", personSchemaBody);
+ qResult = mJsonDb->create(mOwner, personSchemaObject);
+ verifyGoodResult(qResult);
+
+
+ // Prepare items
+ const uint numberOfIterations = 1000;
+ QList<QsonMap> objects;
+ objects.reserve(numberOfIterations);
+ for (uint i = 0; i < numberOfIterations; ++i) {
+ QsonMap object = readJson(item);
+ object.insert("testingForAdult", i);
+ object.insert(JsonDbString::kTypeStr, personSchemaName);
+ objects.append(object);
+ }
+
+ QBENCHMARK_ONCE {
+ foreach (QsonMap object, objects) {
+ qResult = mJsonDb->validateSchema(personSchemaName, object);
+
+ if (isPerson) {
+ QVERIFY(qResult.isEmpty());
+ } else {
+ QVERIFY(!qResult.isEmpty());
+ }
+ }
+ }
+
+ gValidateSchemas = validate;
+}
+
+void TestJsonDb::benchmarkFind()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QBENCHMARK {
+ QsonMap request;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ request.insert("query",
+ QString("[?name=\"%3\"][?%1=\"%2\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(item.valueString("name")));
+ request.insert("limit", 1);
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFindByName()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QBENCHMARK {
+ QsonMap request;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ if (!item.contains("name"))
+ qDebug() << "no name in item" << item;
+ request.insert("query",
+ QString("[?name=\"%1\"]")
+ .arg(item.valueString("name")));
+ request.insert("limit", 1);
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFindEQ()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QsonMap request;
+
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ request.insert("query",
+ QString("[?name.first=\"%3\"][?%1=\"%2\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(JsonDb::propertyLookup(item, "name.first").toString()));
+ QBENCHMARK {
+ QsonMap result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFindLE()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ request.insert("query",
+ QString("[?name.first<=\"%3\"][?%1=\"%2\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(JsonDb::propertyLookup(item, "name.first").toString()));
+ request.insert("limit", 1);
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFind10()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ request.insert("limit", 10);
+ request.insert("query",
+ QString("[?name.first<=\"%3\"][?%1=\"%2\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(JsonDb::propertyLookup(item, "name.first").toString()));
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFind20()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ request.insert("limit", 20);
+ request.insert("query",
+ QString("[?name.first<=\"%3\"][?%1=\"%2\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(JsonDb::propertyLookup(item, "name.first").toString()));
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFindUnindexed()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ //qDebug() << item.value("firstName").toString();
+ request.insert("query",
+ QString("[?%1=\"%2\"][?firstName=\"%3\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(item.valueString("firstName")));
+ //request.insert("limit", 1);
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFindReindexed()
+{
+ int count = mContactList.size();
+ if (!count)
+ return;
+
+ //qDebug() << "Adding index for lastName";
+ mJsonDb->addIndex("lastName");
+ //qDebug() << "Done adding index for lastName";
+
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ int itemNumber = (int)((double)qrand() * count / RAND_MAX);
+ QsonMap item = mContactList.objectAt(itemNumber);
+ //qDebug() << item.value("firstName").toString();
+ request.insert("query",
+ QString("[?%1=\"%2\"][?lastName=\"%3\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact")
+ .arg(item.valueString("lastName")));
+ //request.insert("limit", 1);
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ }
+}
+
+void TestJsonDb::benchmarkFindNames()
+{
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ QVariantList items;
+ request.insert("query",
+ QString("[?%1=\"%2\"]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact"));
+ request.insert("limit", 1);
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ result = result.subObject("result");
+ int length = result.value<int>("length");
+ if (false && (length > 0)) {
+ QsonList data = result.subList("data");
+ qDebug() << JsonWriter().toString(data.stringAt(0));
+ }
+ }
+}
+
+void TestJsonDb::findNamesMapL()
+{
+ QBENCHMARK_ONCE {
+ QsonMap request;
+ QsonMap result;
+
+ request.insert("query",
+ QString("[?%1=\"%2\"][= [_uuid, name.first, name.last] ]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact"));
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").value<int>("length"), 1000);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1000);
+ }
+}
+
+void TestJsonDb::benchmarkFindNamesMapL()
+{
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ request.insert("query",
+ QString("[?%1=\"%2\"][= [_uuid, name.first, name.last] ]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact"));
+ request.insert("limit", 1);
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").value<int>("length"), 1);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ }
+}
+
+
+void TestJsonDb::findNamesMapO()
+{
+ QBENCHMARK_ONCE {
+ QsonMap request;
+ QsonMap result;
+ request.insert("query",
+ QString("[?%1=\"%2\"][= { uuid: _uuid, first: name.first, last: name.last } ]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact"));
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").value<int>("length"), 1000);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1000);
+ }
+}
+
+void TestJsonDb::benchmarkFindNamesMapO()
+{
+ QBENCHMARK {
+ QsonMap request;
+ QsonMap result;
+ request.insert("query",
+ QString("[?%1=\"%2\"][= { uuid: _uuid, first: name.first, last: name.last } ]")
+ .arg(JsonDbString::kTypeStr)
+ .arg("contact"));
+ request.insert("limit", 1);
+ result = mJsonDb->find(mOwner, request);
+ verifyGoodResult(result);
+ QCOMPARE(result.subObject("result").value<int>("length"), 1);
+ QCOMPARE(result.subObject("result").subList("data").size(), 1);
+ }
+}
+
+void TestJsonDb::benchmarkCursorCount()
+{
+ QStringList queries = (QStringList()
+ << "[/name.first]"
+ << "[/name.first][?_type=\"contact\"]"
+ );
+ QsonMap bindings;
+ foreach (QString query, queries) {
+ JsonDbQuery parsedQuery = JsonDbQuery::parse(query, bindings);
+ IndexQuery *indexQuery = mJsonDb->findPartition("default")->compileIndexQuery(mOwner, parsedQuery);
+ int count = 0;
+ //qDebug() << "query" << query;
+ QBENCHMARK {
+ int mycount = 0;
+ for (QsonMap object = indexQuery->first();
+ object.size() > 0;
+ object = indexQuery->next()) {
+ mycount++;
+ }
+ count = mycount;
+ }
+ }
+}
+
+void TestJsonDb::benchmarkQueryCount()
+{
+ QStringList queries = (QStringList()
+ << "[/name.first]"
+ << "[/name.first][?_type=\"contact\"]"
+ );
+ foreach (QString query, queries) {
+ QsonMap request;
+ request.insert("query", QString("%1[count]").arg(query));
+ QBENCHMARK {
+ QsonMap result = mJsonDb->find(mOwner, request);
+ }
+ }
+}
+
+QsonObject TestJsonDb::readJsonFile(const QString& filename)
+{
+ QString filepath = findFile(SRCDIR, filename);
+ QFile jsonFile(filepath);
+ jsonFile.open(QIODevice::ReadOnly);
+ QByteArray json = jsonFile.readAll();
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok) {
+ qDebug() << filepath << parser.errorString();
+ }
+ QVariant v = parser.result();
+ return variantToQson(v);
+}
+
+QsonObject TestJsonDb::readJson(const QByteArray& json)
+{
+ JsonReader parser;
+ bool ok = parser.parse(json);
+ if (!ok) {
+ qDebug() << parser.errorString();
+ }
+ QVariant v = parser.result();
+ return variantToQson(v);
+}
+
+void TestJsonDb::benchmarkScriptEngineCreation()
+{
+ QJSValue result;
+ QBENCHMARK {
+ QJSEngine *engine = new QJSEngine();
+ engine->setParent(0);
+ QJSValue globalObject = engine->globalObject();
+ result =
+ engine->evaluate(QString("var reduce = function(k, v, s) { s.count = s.count + v.count; return s; };"));
+ engine = 0;
+ }
+}
+
+void TestJsonDb::contactListChaff()
+{
+ QBENCHMARK {
+ for (int ii = 0; ii < mContactList.size(); ii++) {
+ QsonMap data = mContactList.objectAt(ii);
+ QsonMap chaff;
+ chaff.insert(JsonDbString::kTypeStr, QString("com.noklab.nrcc.ContactChaff"));
+ QStringList skipKeys = (QStringList() << JsonDbString::kUuidStr << JsonDbString::kVersionStr << JsonDbString::kTypeStr);
+ foreach (QString key, data.keys()) {
+ if (!skipKeys.contains(key))
+ chaff.insert(key, data.value<QsonElement>(key));
+ }
+
+ QsonMap result = mJsonDb->create(mOwner, chaff);
+ verifyGoodResult(result);
+ }
+ }
+}
+
+QTEST_MAIN(TestJsonDb)
+#include "bench_daemon.moc"
diff --git a/tests/benchmarks/daemon/daemon.pro b/tests/benchmarks/daemon/daemon.pro
new file mode 100644
index 00000000..7598c8b1
--- /dev/null
+++ b/tests/benchmarks/daemon/daemon.pro
@@ -0,0 +1,19 @@
+TARGET = tst_bench_daemon
+
+QT = network declarative testlib jsondbqson-private
+CONFIG -= app_bundle
+
+INCLUDEPATH += $$PWD/../../../src/daemon
+LIBS += -L$$QT.jsondb.libs
+!mac:LIBS += -lssl -lcrypto
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include($$PWD/../../../src/daemon/daemon.pri)
+
+SOURCES += \
+ bench_daemon.cpp \
+
+check.target = check
+check.commands = rm -f *.db* && LD_LIBRARY_PATH=$$PWD/../../../lib QT_QPA_PLATFORM=xcb ./tst_bench_daemon -xunitxml -silent > ../../../tst_bench_daemon.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/benchmarks/jsondb-listmodel/jsondb-listmodel.pro b/tests/benchmarks/jsondb-listmodel/jsondb-listmodel.pro
new file mode 100644
index 00000000..babba345
--- /dev/null
+++ b/tests/benchmarks/jsondb-listmodel/jsondb-listmodel.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+TARGET = tst_bench_listmodel
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT = core network testlib declarative jsondb-private jsondbqson-private
+CONFIG -= app_bundle
+
+include($$PWD/../../../src/3rdparty/qjson/qjson.pri)
+
+DEFINES += JSONDB_DAEMON_BASE=\\\"$$QT.jsondb.bins\\\"
+
+INCLUDEPATH += $$PWD/../../../src/imports/jsondb
+HEADERS += $$PWD/../../../src/imports/jsondb/jsondb-listmodel.h
+SOURCES += $$PWD/../../../src/imports/jsondb/jsondb-listmodel.cpp
+
+# Input
+HEADERS += listmodel-benchmark.h
+SOURCES += listmodel-benchmark.cpp
+
+check.target = check
+check.commands = QT_QPA_PLATFORM=minimal ./tst_bench_listmodel -xunitxml -silent > ../../../tst_bench_listmodel.xml
+QMAKE_EXTRA_TARGETS = check
diff --git a/tests/benchmarks/jsondb-listmodel/listmodel-benchmark.cpp b/tests/benchmarks/jsondb-listmodel/listmodel-benchmark.cpp
new file mode 100644
index 00000000..dfa66f0f
--- /dev/null
+++ b/tests/benchmarks/jsondb-listmodel/listmodel-benchmark.cpp
@@ -0,0 +1,582 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define QT_GUI_LIB // cause QTEST_MAIN to use QGuiApplication, which is need for QDeclarativeEngine()
+
+#include <QtTest/QtTest>
+#include <QJSEngine>
+#include "listmodel-benchmark.h"
+
+#include "../../shared/util.h"
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+#include <QDeclarativeContext>
+
+static const char dbfile[] = "dbFile-test-jsondb";
+ModelData::ModelData(): engine(0), component(0), model(0)
+{
+}
+
+ModelData::~ModelData()
+{
+ if (model)
+ delete model;
+ if (component)
+ delete component;
+ if (engine)
+ delete engine;
+}
+
+TestListModel::TestListModel()
+ : mClient(0), mProcess(0), mId(0)
+{
+ QDeclarativeEngine *engine = new QDeclarativeEngine();
+ QStringList pluginPaths = engine->importPathList();
+ for (int i=0; (i<pluginPaths.count() && mPluginPath.isEmpty()); i++) {
+ QDir dir(pluginPaths[i]+"/QtJsonDb");
+ dir.setFilter(QDir::Files | QDir::NoSymLinks);
+ QFileInfoList list = dir.entryInfoList();
+ for (int i = 0; i < list.size(); ++i) {
+ QString error;
+ if (engine->importPlugin(list.at(i).absoluteFilePath(), QString("QtJsonDb"), &error)) {
+ mPluginPath = list.at(i).absoluteFilePath();
+ break;
+ }
+ }
+ }
+ delete engine;
+}
+
+TestListModel::~TestListModel()
+{
+}
+
+void TestListModel::connectJsonDbClient()
+{
+ connect( mClient, SIGNAL(notified(const QString&, const QVariant&, const QString&)),
+ this, SLOT(notified(const QString&, const QVariant&, const QString&)));
+ connect( mClient, SIGNAL(response(int, const QVariant&)),
+ this, SLOT(response(int, const QVariant&)));
+ connect( mClient, SIGNAL(error(int, int, const QString&)),
+ this, SLOT(error(int, int, const QString&)));
+ connect( mClient, SIGNAL(disconnected()),
+ this, SLOT(disconnected()));
+}
+
+void TestListModel::connectListModel(JsonDbListModel *model)
+{
+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this , SLOT(dataChanged(QModelIndex,QModelIndex)));
+ connect(model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(model, SIGNAL(layoutChanged()), this, SLOT(layoutChanged()));
+ connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(rowsInserted(QModelIndex, int, int)));
+ connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(rowsRemoved(QModelIndex, int, int)));
+ connect(model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this, SLOT(rowsMoved(QModelIndex, int, int, QModelIndex, int)));
+}
+
+void TestListModel::deleteDbFiles()
+{
+ // remove all the test files.
+ QDir currentDir;
+ QStringList nameFilter;
+ nameFilter << QString("*.db");
+ QFileInfoList databaseFiles = currentDir.entryInfoList(nameFilter, QDir::Files);
+ foreach (QFileInfo fileInfo, databaseFiles) {
+ //qDebug() << "Deleted : " << fileInfo.fileName();
+ QFile file(fileInfo.fileName());
+ file.remove();
+ }
+}
+
+void TestListModel::initTestCase()
+{
+ // make sure there is no old db files.
+ deleteDbFiles();
+
+ QString socketName = QString("testjsondb_%1").arg(getpid());
+ mProcess = launchJsonDbDaemon(JSONDB_DAEMON_BASE, socketName, QStringList() << dbfile);
+
+ mClient = new JsonDbClient(this);
+ QVERIFY(mClient!= 0);
+ connectJsonDbClient();
+
+ // Create alot of items in the database
+ QVariantList friendsList;
+ for (int i=0; i<1000; i++) {
+ QVariantMap item;
+ item.insert("_type", "Friends");
+ item.insert("name", QString("Name-%1").arg(i));
+ item.insert("phone",QString("%1").arg(qrand()));
+ friendsList << item;
+ }
+ mId = mClient->create(friendsList);
+
+ QVariantList ImageList;
+ for (int i=0; i<1000; i++) {
+ QVariantMap item;
+ item.insert("_type", "Image");
+ item.insert("name", QString("Name-%1.jpg").arg(i));
+ item.insert("location",QString("/home/qt/Pictures/Myfolder-%1").arg(i));
+ ImageList << item;
+ }
+ mId = mClient->create(ImageList);
+
+ QVariantList numberList;
+ for (int i=0; i<1000; i++) {
+ QVariantMap item;
+ item.insert("_type", "RandNumber");
+ item.insert("number", qrand()%100);
+ numberList << item;
+ }
+ mId = mClient->create(numberList);
+
+ QVariantList trollList;
+ for (int i=0; i<100; i++) {
+ QVariantMap item;
+ item.insert("_type", "Troll");
+ item.insert("age", i);
+ item.insert("name", QString("Troll-%1").arg(i));
+ trollList << item;
+ }
+ mId = mClient->create(trollList);
+
+ mEventLoop.exec(QEventLoop::AllEvents);
+}
+
+JsonDbListModel *TestListModel::createModel()
+{
+ ModelData *newModel = new ModelData();
+ newModel->engine = new QDeclarativeEngine();
+ QString error;
+ if (!newModel->engine->importPlugin(mPluginPath, QString("QtJsonDb"), &error)) {
+ qDebug()<<"Unable to load the plugin :"<<error;
+ delete newModel->engine;
+ return 0;
+ }
+ newModel->component = new QDeclarativeComponent(newModel->engine);
+ newModel->component->setData("import QtQuick 2.0\nimport QtJsonDb 1.0 as JsonDb \n JsonDb.JsonDbListModel {id: contactsModel}", QUrl());
+ newModel->model = newModel->component->create();
+ mModels.append(newModel);
+ return (JsonDbListModel*)(newModel->model);
+}
+
+void TestListModel::deleteModel(JsonDbListModel *model)
+{
+ for (int i = 0; i < mModels.count(); i++) {
+ if (mModels[i]->model == model) {
+ ModelData *modelData = mModels.takeAt(i);
+ delete modelData;
+ return;
+ }
+ }
+}
+
+void TestListModel::cleanupTestCase()
+{
+ if (mClient) {
+ delete mClient;
+ mClient = NULL;
+ }
+
+ if (mProcess) {
+ mProcess->kill();
+ mProcess->waitForFinished();
+ delete mProcess;
+ mProcess = NULL;
+ }
+ deleteDbFiles();
+}
+
+void TestListModel::disconnected()
+{
+ qDebug() << "Disconnected";
+}
+
+void TestListModel::notified(const QString& notifyUuid, const QVariant& object, const QString& action)
+{
+ Q_UNUSED(notifyUuid);
+ Q_UNUSED(object);
+ Q_UNUSED(action);
+ //qDebug() << Q_FUNC_INFO << "notifyUuid=" << notifyUuid << "action=" << action << "object=" << object;
+ //mEventLoop.exit(0);
+}
+
+void TestListModel::response(int id, const QVariant& data)
+{
+ //qDebug() << Q_FUNC_INFO << "id: " << id << data;
+ QMap<QString,QVariant> map = data.toMap();
+ mLastUuid = map.value("_uuid").toString();
+ mLastResponseData = data;
+ if (mId == id)
+ mEventLoop.exit(0);
+}
+
+void TestListModel::error(int id, int code, const QString& message)
+{
+ qDebug() << Q_FUNC_INFO << "id:" << id << "code:" << code << "message:" << message;
+ if (mId == id)
+ mEventLoop.exit(0);
+}
+
+void TestListModel::dataChanged(QModelIndex, QModelIndex)
+{
+ //qDebug() << "dataChanged(QModelIndex,QModelIndex)";
+ mEventLoop.exit(0);
+}
+
+void TestListModel::modelReset()
+{
+ //qDebug() << "modelReset()";
+ mEventLoop.exit(0);
+}
+
+void TestListModel::layoutChanged()
+{
+ //qDebug() << "layoutChanged()";
+ mEventLoop.exit(0);
+}
+
+void TestListModel::rowsInserted(QModelIndex parent, int start , int end)
+{
+ Q_UNUSED(parent);
+ qDebug() << QString("rowsInserted(QModelIndex, %1, %2)").arg(start).arg(end);
+ mEventLoop.exit(0);
+}
+
+void TestListModel::rowsRemoved(QModelIndex parent, int start, int end)
+{
+ Q_UNUSED(parent);
+ qDebug() << QString("rowsRemoved(QModelIndex, %1, %2)").arg(start).arg(end);
+ mEventLoop.exit(0);
+}
+
+void TestListModel::rowsMoved(QModelIndex sourceParent, int sourceStart, int sourceEnd, QModelIndex destinationParent, int destinationRow)
+{
+ Q_UNUSED(sourceParent);
+ Q_UNUSED(destinationParent);
+ qDebug() << QString("rowsMoved(QModelIndex, %1, %2, QModelIndex, %3)").arg(sourceStart).arg(sourceEnd).arg(destinationRow);
+ mEventLoop.exit(0);
+}
+
+void TestListModel::createListModelHundredItems()
+{
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+
+ connectListModel(listModel);
+ QStringList rolenames;
+ rolenames << "age" << "name" << "_type";
+ listModel->setRoleNames(rolenames);
+
+ QBENCHMARK {
+ listModel->setQuery("[?_type=\"Troll\"]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+
+void TestListModel::createListModelThousandItems()
+{
+ JsonDbListModel *listModel = createModel();
+
+ connectListModel(listModel);
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type";
+ listModel->setRoleNames(rolenames);
+
+ QBENCHMARK {
+ listModel->setQuery("[?_type=\"Friends\"]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::createListModelGroupedQuery()
+{
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+
+ connectListModel(listModel);
+ QStringList rolenames;
+ rolenames << "_uuid" << "_type" << "number";
+ listModel->setRoleNames(rolenames);
+
+ QBENCHMARK {
+ listModel->setQuery("[?_type=\"RandNumber\"][?number=77]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+
+void TestListModel::createListModelSortedQuery()
+{
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+
+ connectListModel(listModel);
+
+ QStringList rolenames;
+ rolenames << "_uuid" << "_type" << "number";
+ listModel->setRoleNames(rolenames);
+
+ QBENCHMARK {
+ listModel->setQuery("[?_type=\"RandNumber\"][/number]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::changeOneItemClient()
+{
+
+ QString queryString("[?_type=\"Friends\"][?name=\"Name-1\"]");
+ mId = mClient->query(queryString);
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QVariantMap mapResponse = mLastResponseData.toMap();
+ QVariantMap item = mapResponse.value("data").toList().at(0).toMap();
+ int i = mapResponse.value("length").toInt();
+ QVERIFY(i == 1);
+ item.insert("phone","111122223");
+
+ // Make sure that we only exit the eventloop
+ // on listmodel updates.
+ disconnect(mClient, 0, this, 0);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type";
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Friends\"][/name]");
+ connectListModel(listModel);
+
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QBENCHMARK {
+ mId = mClient->update(item);
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+
+ connectJsonDbClient();
+
+ mEventLoop.processEvents();
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::changeOneItemSet()
+{
+ // Make sure that we only exit the eventloop
+ // on listmodel updates.
+ disconnect(mClient, 0, this, 0);
+ mEventLoop.processEvents();
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type";
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Friends\"][/name]");
+ connectListModel(listModel);
+
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QJSEngine engine;
+ QJSValue value = engine.newObject();
+ value.setProperty("phone", "987654321");
+
+ QBENCHMARK {
+ listModel->set(0,value);
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+
+ QVERIFY(listModel->get(0, "phone") == "987654321");
+ deleteModel(listModel);
+}
+
+void TestListModel::changeOneItemSetProperty()
+{
+ // Make sure that we only exit the eventloop
+ // on listmodel updates.
+ disconnect(mClient, 0, this, 0);
+ mEventLoop.processEvents();
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type";
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Friends\"]");
+ connectListModel(listModel);
+
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QBENCHMARK {
+ listModel->setProperty(1, "phone", "111122223");
+ mEventLoop.exec(QEventLoop::AllEvents);
+ }
+
+ connectJsonDbClient();
+
+ mEventLoop.processEvents();
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::getOneItemInCache()
+{
+ disconnect(mClient, 0, this, 0);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ connectListModel(listModel);
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type" ;
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Friends\"]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QBENCHMARK {
+ QVariant res = listModel->data(listModel->index(10,0), listModel->roleFromString("name"));
+ // Since it is in the cache the fetch value should be valid at this point.
+ QVERIFY(res.isValid());
+ }
+
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::getOneItemNotInCache()
+{
+ disconnect(mClient, 0, this, 0);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ connectListModel(listModel);
+ listModel->setLimit(80);
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type";
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Friends\"][/name]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ bool flip = true; // so we can run multiple benchmarks
+
+ QBENCHMARK {
+ QVariant res;
+ if (flip)
+ res = listModel->data(listModel->index(960,0), listModel->roleFromString("name"));
+ else
+ res = listModel->data(listModel->index(10,0), listModel->roleFromString("name"));
+
+ flip = !flip;
+ }
+
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::getOneItemNotInCacheThousandItems()
+{
+ disconnect(mClient, 0, this, 0);
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ connectListModel(listModel);
+ listModel->setLimit(80);
+ QStringList rolenames;
+ rolenames << "name" << "location" << "_type";
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Image\"][/name]");
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ QVERIFY(listModel->count() == 1000);
+
+ bool flip = true; // so we can run multiple benchmarks
+
+ QBENCHMARK {
+ QVariant res;
+ if (flip)
+ res = listModel->data(listModel->index(980,0), listModel->roleFromString("name"));
+ else
+ res = listModel->data(listModel->index(10,0), listModel->roleFromString("name"));
+
+ flip = !flip;
+ }
+
+ QCoreApplication::instance()->processEvents();
+ deleteModel(listModel);
+}
+
+void TestListModel::scrollThousandItems()
+{
+ disconnect(mClient, 0, this, 0);
+ mEventLoop.processEvents();
+
+ JsonDbListModel *listModel = createModel();
+ if (!listModel) return;
+ QStringList rolenames;
+ rolenames << "name" << "phone" << "_uuid" << "_type";
+ listModel->setRoleNames(rolenames);
+ listModel->setQuery("[?_type=\"Friends\"][/name]");
+ listModel->setLimit(80);
+ connectListModel(listModel);
+
+ mEventLoop.exec(QEventLoop::AllEvents);
+
+ int rowCount = listModel->rowCount();
+
+ QBENCHMARK {
+ for( int i=0 ; i<rowCount; i++)
+ foreach(QString role, rolenames)
+ listModel->data(listModel->index(i,0), listModel->roleFromString(role));
+ }
+ deleteModel(listModel);
+}
+
+
+QTEST_MAIN(TestListModel)
diff --git a/tests/benchmarks/jsondb-listmodel/listmodel-benchmark.h b/tests/benchmarks/jsondb-listmodel/listmodel-benchmark.h
new file mode 100644
index 00000000..2ddb2074
--- /dev/null
+++ b/tests/benchmarks/jsondb-listmodel/listmodel-benchmark.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LISTMODEL_BENCHMARK_H
+#define LISTMODEL_BENCHMARK_H
+
+#include <QCoreApplication>
+#include <QProcess>
+#include <QTest>
+#include <QDebug>
+
+#include <QEventLoop>
+#include <QLocalSocket>
+
+#include <jsondb-client.h>
+#include <jsondb-error.h>
+
+#include "jsondb-listmodel.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeComponent;
+class JsonDbListModel;
+
+class ModelData {
+public:
+ ModelData();
+ ~ModelData();
+ QDeclarativeEngine *engine;
+ QDeclarativeComponent *component;
+ QObject *model;
+};
+
+class TestListModel: public QObject
+{
+ Q_OBJECT
+public:
+ TestListModel();
+ ~TestListModel();
+
+ void deleteDbFiles();
+ void connectJsonDbClient();
+ void connectListModel(JsonDbListModel *model);
+
+public slots:
+ void notified(const QString& notifyUuid, const QVariant& object, const QString& action);
+ void response(int id, const QVariant& data);
+ void error(int id, int code, const QString& message);
+ void disconnected();
+
+ void dataChanged(QModelIndex,QModelIndex);
+ void modelReset();
+ void layoutChanged();
+ void rowsInserted(QModelIndex, int, int);
+ void rowsRemoved(QModelIndex, int, int);
+ void rowsMoved(QModelIndex, int, int, QModelIndex, int);
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void createListModelHundredItems();
+ void createListModelThousandItems();
+ void createListModelGroupedQuery();
+ void createListModelSortedQuery();
+ void changeOneItemClient();
+ void changeOneItemSet();
+ void changeOneItemSetProperty();
+ void getOneItemInCache();
+ void getOneItemNotInCache();
+ void getOneItemNotInCacheThousandItems();
+ void scrollThousandItems();
+private:
+ JsonDbListModel *createModel();
+ void deleteModel(JsonDbListModel *model);
+private:
+ JsonDbClient *mClient;
+ QProcess *mProcess;
+ QEventLoop mEventLoop;
+ QString mLastUuid;
+ QVariant mLastResponseData;
+ int mId;
+ QList<ModelData*> mModels;
+ QString mPluginPath;
+};
+
+#endif
diff --git a/tests/benchmarks/tests.xml b/tests/benchmarks/tests.xml
new file mode 100644
index 00000000..9bc5dd42
--- /dev/null
+++ b/tests/benchmarks/tests.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<testdefinition version="0.1">
+ <suite domain="Performance" name="benchmarks" timeout="15000">
+ <set description=" Simple JSON DB performance tests " feature="JSONDB" level="System" name="jsondb-benchmarks" type="Integration" timeout="10000">
+ <case name="tst_bench_client" timeout="5000" component="qt5jsondb">
+ <description>Client API performance 01</description>
+ <step>cd /usr/lib/qt5jsondb-tests/benchmarks/client; date &amp;&amp; ./tst_bench_client &amp;&amp; date</step>
+ </case>
+ <case name="tst_bench_daemon" timeout="5000" component="qt5jsondb">
+ <description>Server-side performance</description>
+ <step>cd /usr/lib/qt5jsondb-tests/benchmarks/daemon; date &amp;&amp; ./tst_bench_daemon &amp;&amp; date</step>
+ </case>
+ <case name="tst_bench_listmodel" timeout="5000" component="qt5jsondb">
+ <description>JsonDbListModel performance</description>
+ <step>cd /usr/lib/qt5jsondb-tests/benchmarks/jsondb-listmodel; date &amp;&amp; ./tst_bench_listmodel -platform minimal &amp;&amp; date</step>
+ </case>
+ </set>
+ </suite>
+</testdefinition>
diff --git a/tests/manual/bits/bits.pro b/tests/manual/bits/bits.pro
new file mode 100644
index 00000000..85d613b5
--- /dev/null
+++ b/tests/manual/bits/bits.pro
@@ -0,0 +1,11 @@
+DESTDIR = bin
+
+CONFIG -= app_bundle
+CONFIG -= qt
+CONFIG += debug
+
+include($$PWD/../../../src/3rdparty/btree/btree.pri)
+
+SOURCES += \
+ main.cpp \
+
diff --git a/tests/manual/bits/build.sh b/tests/manual/bits/build.sh
new file mode 100755
index 00000000..f0dee328
--- /dev/null
+++ b/tests/manual/bits/build.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -f bin/bits32 bin/bits64
+rm -f btree.o main.o
+qmake TARGET=bits64 && make
+rm -f btree.o main.o
+qmake TARGET=bits32 -spec linux-g++-32 && make
diff --git a/tests/manual/bits/main.cpp b/tests/manual/bits/main.cpp
new file mode 100644
index 00000000..5e51b0e1
--- /dev/null
+++ b/tests/manual/bits/main.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "btree.h"
+
+int main(int, char **)
+{
+ struct btree *bt = btree_open("database.db", BT_NOSYNC, 0644);
+ if (!bt) {
+ fprintf(stderr, "Couldn't open database\n");
+ return 0;
+ }
+ const struct btree_stat *s = btree_stat(bt);
+ fprintf(stderr, "\tentries: %llu\n", s->entries);
+ fprintf(stderr, "\tpsize: %d\n", s->psize);
+ fprintf(stderr, "\ttag: %d\n", s->tag);
+
+ btval key, value;
+ key.free_data = 0;
+ if (sizeof(long) == 8)
+ key.data = (void *)"foo64";
+ else
+ key.data = (void *)"foo32";
+ key.size = 5;
+ key.mp = 0;
+ value.free_data = 0;
+ if (sizeof(long) == 8)
+ value.data = (void *)"bar64";
+ else
+ value.data = (void *)"bar32";
+ value.size = 5;
+ value.mp = 0;
+ int ret = btree_put(bt, &key, &value, 0);
+ if (ret != BT_SUCCESS) {
+ fprintf(stderr, "failed to put %s\n", (const char *)key.data);
+ return 0;
+ }
+ btval_reset(&key);
+ btval_reset(&value);
+
+ struct cursor *c = btree_cursor_open(bt);
+ ret = btree_cursor_get(c, &key, &value, BT_FIRST);
+ if (ret != BT_SUCCESS) {
+ fprintf(stderr, "failed to seek to first entry\n");
+ return 0;
+ }
+ char *k = strndup((const char *)key.data, key.size);
+ char *v = strndup((const char *)value.data, value.size);
+ fprintf(stderr, "%s : %s\n", k, v);
+ btval_reset(&key);
+ btval_reset(&value);
+ free(k);
+ free(v);
+
+ while (true) {
+ int ret = btree_cursor_get(c, &key, &value, BT_NEXT);
+ if (ret != BT_SUCCESS)
+ break;
+ char *k = strndup((const char *)key.data, key.size);
+ char *v = strndup((const char *)value.data, value.size);
+ fprintf(stderr, "%s : %s\n", k, v);
+ btval_reset(&key);
+ btval_reset(&value);
+ free(k);
+ free(v);
+ }
+ btree_close(bt);
+ return 1;
+}
diff --git a/tests/shared/clientwrapper.cpp b/tests/shared/clientwrapper.cpp
new file mode 100644
index 00000000..f2794b78
--- /dev/null
+++ b/tests/shared/clientwrapper.cpp
@@ -0,0 +1 @@
+#include "clientwrapper.h"
diff --git a/tests/shared/clientwrapper.h b/tests/shared/clientwrapper.h
new file mode 100644
index 00000000..5c841d21
--- /dev/null
+++ b/tests/shared/clientwrapper.h
@@ -0,0 +1,134 @@
+#ifndef CLIENTWRAPPER_H
+#define CLIENTWRAPPER_H
+
+#include <QEventLoop>
+
+#include "private/jsondb-connection_p.h"
+#include "jsondb-client.h"
+
+#define waitForResponse(eventloop, result, id_, code, notificationId, count) \
+{ \
+ int givenid_ = (id_); \
+ (result)->mNotificationId = QVariant(); \
+ (result)->mNeedId = (givenid_ != -1); \
+ (result)->mId = QVariant(); \
+ (result)->mMessage = QString(); \
+ (result)->mCode = -1; \
+ (result)->mData = QVariant(); \
+ (result)->mNotificationWaitCount = count; \
+ (result)->mLastUuid = QString(); \
+ \
+ QTimer timer; \
+ QObject::connect(&timer, SIGNAL(timeout()), &eventloop, SLOT(quit())); \
+ timer.start(10000); \
+ eventloop.exec(QEventLoop::AllEvents); \
+ if (debug_output) { \
+ qDebug() << "waitForResponse" << "expected id" << givenid_ << "got id" << (result)->mId; \
+ qDebug() << "waitForResponse" << "expected code" << int(code) << "got code" << (result)->mCode; \
+ qDebug() << "waitForResponse" << "expected notificationId" << notificationId << "got notificationId" << (result)->mNotificationId; \
+ } \
+ if ((result)->mNeedId) QVERIFY2(!(result)->mId.isNull(), "Failed to receive an answer from the db server"); \
+ if ((result)->mNeedId) QCOMPARE((result)->mId, QVariant(givenid_)); \
+ if ((result)->mNotificationId != QVariant(notificationId)) { \
+ if ((result)->mNotificationId.isNull()) { \
+ QVERIFY2(false, "we expected notification but did not get it :("); \
+ } else { \
+ QString data = JsonWriter().toString((result)->mNotifications.last().mObject); \
+ QByteArray ba = QString("we didn't expect notification but got it. %1").arg(data).toLatin1(); \
+ QVERIFY2(false, ba.constData()); \
+ } \
+ } \
+ QCOMPARE((result)->mNotificationId, QVariant(notificationId)); \
+ if ((result)->mCode != int(code)) \
+ qDebug() << (result)->mMessage; \
+ QCOMPARE((result)->mCode, int(code)); \
+}
+#define waitForResponse1(id) waitForResponse(mEventLoop, this, id, -1, QVariant(), 0)
+#define waitForResponse2(id, code) waitForResponse(mEventLoop, this, id, code, QVariant(), 0)
+#define waitForResponse3(id, code, notificationId) waitForResponse(mEventLoop, this, id, code, notificationId, 0)
+#define waitForResponse4(id, code, notificationId, count) waitForResponse(mEventLoop, this, id, code, notificationId, count)
+
+class Notification
+{
+public:
+ Notification(const QString &notifyUuid, const QVariant &object, const QString &action)
+ : mNotifyUuid(notifyUuid), mObject(object), mAction(action) {}
+
+ QString mNotifyUuid;
+ QVariant mObject;
+ QString mAction;
+};
+
+class ClientWrapper : public QObject
+{
+ Q_OBJECT
+public:
+ ClientWrapper(QObject *parent = 0)
+ : QObject(parent), debug_output(false),
+ mConnection(0), mClient(0), mCode(0), mNeedId(false), mNotificationWaitCount(0)
+ {
+ }
+
+ void connectToServer()
+ {
+ mConnection = new Q_ADDON_JSONDB_PREPEND_NAMESPACE(JsonDbConnection)(this);
+ mConnection->connectToServer();
+ mClient = new Q_ADDON_JSONDB_PREPEND_NAMESPACE(JsonDbClient)(mConnection, this);
+ connect(mClient, SIGNAL(response(int,QVariant)),
+ this, SLOT(response(int,QVariant)));
+ connect(mClient, SIGNAL(error(int,int,QString)),
+ this, SLOT(error(int,int,QString)));
+ connect(mClient, SIGNAL(notified(QString,QVariant,QString)),
+ this, SLOT(notified(QString,QVariant,QString)));
+ }
+
+ bool debug_output;
+
+ Q_ADDON_JSONDB_PREPEND_NAMESPACE(JsonDbConnection) *mConnection;
+ Q_ADDON_JSONDB_PREPEND_NAMESPACE(JsonDbClient) *mClient;
+
+ QEventLoop mEventLoop;
+ QString mMessage;
+ int mCode;
+ bool mNeedId;
+ QVariant mId, mData, mNotificationId;
+ QString mLastUuid;
+ int mNotificationWaitCount;
+ QList<Notification> mNotifications;
+
+protected slots:
+ virtual void notified(const QString &notifyUuid, const QVariant &object, const QString &action)
+ {
+ mNotificationId = notifyUuid;
+ mNotifications << Notification(notifyUuid, object, action);
+ mNotificationWaitCount -= 1;
+ if (mId.isValid() && !mNotificationWaitCount)
+ mEventLoop.quit();
+ if (!mNeedId && !mNotificationWaitCount)
+ mEventLoop.quit();
+ }
+
+ virtual void response(int id, const QVariant &data)
+ {
+ mId = id;
+ mData = data;
+ mLastUuid = data.toMap().value("_uuid").toString();
+ if (mId.isValid() && !mNotificationWaitCount)
+ mEventLoop.quit();
+ if (!mNeedId && !mNotificationWaitCount)
+ mEventLoop.quit();
+ }
+
+ virtual void error(int id, int code, const QString &message)
+ {
+ mId = id;
+ mCode = code;
+ mMessage = message;
+ mEventLoop.quit();
+ }
+ virtual void disconnected()
+ {
+ }
+};
+
+#endif // CLIENTWRAPPER_H
diff --git a/tests/shared/shared.pri b/tests/shared/shared.pri
new file mode 100644
index 00000000..20b59054
--- /dev/null
+++ b/tests/shared/shared.pri
@@ -0,0 +1,4 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/util.h $$PWD/clientwrapper.h
+SOURCES += $$PWD/clientwrapper.cpp
diff --git a/tests/shared/util.h b/tests/shared/util.h
new file mode 100644
index 00000000..59d9c35f
--- /dev/null
+++ b/tests/shared/util.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <QFile>
+#include <QDir>
+#include <QCoreApplication>
+#include <QProcess>
+#include <QLocalSocket>
+#include <qtestsystem.h>
+
+inline QString findFile(const char *srcdir, const QString &filename)
+{
+ QString file = QString::fromLocal8Bit(srcdir) + QDir::separator() + filename;
+ if (QFile::exists(file))
+ return file;
+ file = QCoreApplication::arguments().at(0) + QDir::separator() + filename;
+ if (QFile::exists(file))
+ return file;
+ return QDir::currentPath() + QDir::separator() + filename;
+}
+
+inline QString findFile(const char *srcdir, const char *filename)
+{
+ return findFile(srcdir, QString::fromLocal8Bit(filename));
+}
+
+inline QProcess *launchJsonDbDaemon(const char *prefix, const QString &socketName, const QStringList &args)
+{
+ static bool dontlaunch = qgetenv("AUTOTEST_DONT_LAUNCH_JSONDB").toInt() == 1;
+ if (dontlaunch)
+ return 0;
+ QString jsondb_app = QString::fromLocal8Bit(prefix) + QDir::separator() + "jsondb";
+ if (!QFile::exists(jsondb_app))
+ jsondb_app = QLatin1String("jsondb"); // rely on the PATH
+
+ QProcess *process = new QProcess;
+ process->setProcessChannelMode( QProcess::ForwardedChannels );
+
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("JSONDB_SOCKET", socketName);
+ process->setProcessEnvironment(env);
+ ::setenv("JSONDB_SOCKET", qPrintable(socketName), 1);
+ qDebug() << "Starting process" << jsondb_app << args << "with socket" << socketName;
+ process->start(jsondb_app, args);
+
+ if (!process->waitForStarted())
+ qFatal("Unable to start jsondb database process");
+
+ /* Wait until the jsondb is accepting connections */
+ int tries = 0;
+ bool connected = false;
+ while (!connected && tries++ < 10) {
+ QLocalSocket socket;
+ socket.connectToServer(socketName);
+ if (socket.waitForConnected())
+ connected = true;
+ QTest::qWait(250);
+ }
+ if (!connected)
+ qFatal("Unable to connect to jsondb process");
+ return process;
+}
+
+#endif // UTIL_H
diff --git a/tests/tests.pro b/tests/tests.pro
new file mode 100644
index 00000000..ada5d0f9
--- /dev/null
+++ b/tests/tests.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += auto benchmarks
+
diff --git a/tools/adb-dump/adb-dump.pro b/tools/adb-dump/adb-dump.pro
new file mode 100644
index 00000000..454f3a85
--- /dev/null
+++ b/tools/adb-dump/adb-dump.pro
@@ -0,0 +1,19 @@
+include($$PWD/../../src/3rdparty/btree/btree.pri)
+
+TARGET = adb-dump
+DESTDIR = $$QT.jsondb.bins
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+QT = core
+
+mac:CONFIG -= app_bundle
+
+!mac:LIBS += -lcrypto
+
+INCLUDEPATH += ../../src/daemon
+
+HEADERS += ../../src/daemon/aodb.h
+
+SOURCES += main.cpp ../../src/daemon/aodb.cpp
diff --git a/tools/adb-dump/main.cpp b/tools/adb-dump/main.cpp
new file mode 100644
index 00000000..7978c829
--- /dev/null
+++ b/tools/adb-dump/main.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation
+ */
+
+#include "aodb.h"
+#include <iostream>
+#include <QCoreApplication>
+#include <QStringList>
+#include <QDebug>
+
+QString progname;
+bool gCompact = false;
+
+/***************************************************************************/
+
+using namespace std;
+
+static void usage()
+{
+ cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [<.db filename>]" << endl
+ << endl << "OPTIONS:" << endl
+ << "-compact\tcompacts the db file before dumping." << endl << endl;
+ exit(0);
+}
+
+
+int main(int argc, char * argv[])
+{
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("adb-dump");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+
+ progname = args.takeFirst();
+ while (args.size()) {
+ QString arg = args.at(0);
+ if (!arg.startsWith("-"))
+ break;
+ args.removeFirst();
+ if ( arg == "-help")
+ usage();
+ else if ( arg == "-compact")
+ gCompact = true;
+ /*else if (arg == "-load") {
+ if (args.isEmpty()) {
+ cout << "Invalid argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ loadFile = args.at(0);
+ args.removeFirst();
+ }*/ else {
+ cout << "Unknown argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ }
+
+ AoDb aoDB;
+ while (args.size()) {
+ QString adbFileName = args.takeFirst();
+ qDebug();
+ if (gCompact) {
+ qDebug() << "Compacting...";
+ aoDB.open(adbFileName, AoDb::NoSync);
+ aoDB.compact();
+ }
+ else
+ aoDB.open(adbFileName, AoDb::ReadOnly|AoDb::NoSync);
+
+ qDebug () << "Dumping file: " << adbFileName;
+ qDebug () << "=============================================================";
+ aoDB.dump();
+ qDebug (); qDebug ();
+ aoDB.close();
+ }
+
+ return 0;
+}
diff --git a/tools/aodbread/aodbread.pro b/tools/aodbread/aodbread.pro
new file mode 100644
index 00000000..f86af6f1
--- /dev/null
+++ b/tools/aodbread/aodbread.pro
@@ -0,0 +1,19 @@
+TARGET = aodbread
+
+QT = network declarative testlib
+CONFIG -= app_bundle
+CONFIG += debug
+
+include($$PWD/../../src/common/common.pri)
+
+INCLUDEPATH += $$PWD/../../src/daemon
+LIBS += -L$$QT.jsondb.libs
+!mac:LIBS += -lssl -lcrypto
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include($$PWD/../../src/daemon/daemon.pri)
+
+SOURCES += \
+ main.cpp \
+
diff --git a/tools/aodbread/main.cpp b/tools/aodbread/main.cpp
new file mode 100644
index 00000000..d45eb757
--- /dev/null
+++ b/tools/aodbread/main.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+
+#include "aodb.h"
+#include "btree.h"
+
+#include "qson/qson.h"
+#include "qson/qsonparser.h"
+
+#include "json.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+QString printable(const QByteArray &ba)
+{
+ QByteArray array = ba;
+
+ if (ba.startsWith("QSN")) {
+ QVariant obj = qsonToVariant(QsonParser::fromRawData(ba));
+ JsonWriter writer;
+// writer.setAutoFormatting(true);
+ return QString("QSN:") +writer.toString(obj);
+ }
+
+ // check if it is a number
+ bool isNumber = true;
+ for (int i = 0; i < array.size(); ++i) {
+ if (array.at(i) < 0 || array.at(i) > 9) {
+ isNumber = false;
+ break;
+ }
+ }
+ if (isNumber) {
+ for (int i = 0; i < array.size(); ++i) {
+ array[i] = array.at(i)+'0';
+ }
+ return QString("N:") +QString::fromLatin1(array);
+ }
+
+ // check if utf-16 latin string
+ bool utf16 = true;
+ for (int i = 0; i < array.size(); ++i) {
+ if (i % 2 == 0) {
+ if (!isprint(array.at(i))) {
+ utf16 = false;
+ break;
+ }
+ } else {
+ if (array.at(i) != 0) {
+ utf16 = false;
+ break;
+ }
+ }
+ }
+ if (utf16) {
+ return QString("U:") + QString::fromUtf16((const ushort *)array.constData(), array.size()/2);
+ }
+
+ for (int i = 0; i < array.size(); ++i) {
+ if (array.at(i) == 0)
+ array[i] = '_';
+ }
+
+ bool isprintable = true;
+ for (int i = 0; i < array.size(); ++i) {
+ if (!isprint(array.at(i))) {
+ isprintable = false;
+ break;
+ }
+ }
+ if (isprintable) {
+ return QString("S:") + QString::fromLatin1(array);
+ }
+
+ if (ba.size() == 5 && ba.at(4) == 'S') {
+ // state change
+ quint32 state = qFromBigEndian<quint32>((const uchar *)ba.mid(0, 4).constData());
+ return QString("State:") + QString::number(state);
+ }
+ array = ba.toHex();
+ return QString("x:") + QString::fromLatin1(array);
+}
+
+void makePrintable(const QByteArray &key, QString &keyString, const QByteArray &value, QString &valueString)
+{
+ if (key.size() == 5 && key.at(4) == 'S') {
+ // state change
+ quint32 state = qFromBigEndian<quint32>((const uchar *)key.mid(0, 4).constData());
+ keyString = QString("State:") + QString::number(state);
+
+ QStringList changes;
+ const uchar *data = (const uchar *)value.constData();
+ for (int i = 0; i < value.size() / 16; ++i) {
+ quint32 startKey = qFromBigEndian<quint32>(&data[16 * i]);
+ quint32 startTypeNumber = qFromBigEndian<quint32>(&data[16 * i + 4]);
+ quint32 endKey = qFromBigEndian<quint32>(&data[16 * i + 8]);
+ quint32 endTypeNumber = qFromBigEndian<quint32>(&data[16 * i + 12]);
+ changes << QString("objectTypeKey %2->%4, objectKey %1->%3").arg(startKey).arg(startTypeNumber).arg(endKey).arg(endTypeNumber);
+ }
+ valueString = changes.join(",");
+ return;
+ }
+
+ keyString = printable(key);
+ valueString = printable(value);
+}
+
+bool gStat = false;
+bool gDump = false;
+bool gWantCompact = false;
+bool gShowAll = false;
+bool gShowAllReversed = false;
+quint32 gShowState = 0;
+qint64 gDumpPage = 0;
+
+void usage()
+{
+ qDebug() << QCoreApplication::arguments().at(0)
+ << "[--dump-page num] [--stat] [--dump] [--compact] [--all|--all-reversed] [--state num] database_file";
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QStringList args = app.arguments();
+ args.pop_front();
+
+ if (args.isEmpty()) {
+ usage();
+ return 0;
+ }
+
+ for (; args.size() > 1; ) {
+ QString arg = args.takeFirst();
+ if (arg == QLatin1String("--stat")) {
+ gStat = true;
+ } else if (arg == QLatin1String("--dump")) {
+ gDump = true;
+ } else if (arg == QLatin1String("--compact")) {
+ gWantCompact = true;
+ } else if (arg == QLatin1String("--all")) {
+ gShowAll = true;
+ } else if (arg == QLatin1String("--all-reversed")) {
+ gShowAllReversed = true;
+ } else if (arg == QLatin1String("--state")) {
+ bool ok = false;
+ gShowState = args.takeFirst().toInt(&ok);
+ if (!ok) {
+ usage();
+ return 0;
+ }
+ } else if (arg == QLatin1String("--dump-page")) {
+ bool ok = false;
+ gDumpPage = args.takeFirst().toInt(&ok);
+ if (!ok) {
+ usage();
+ return 0;
+ }
+ } else {
+ usage();
+ return 0;
+ }
+ }
+
+ if (args.isEmpty())
+ return 0;
+
+ QString filename = args.at(0);
+
+ if (gDumpPage > 0) {
+ return btree_dump_page(filename.toLocal8Bit().constData(), gDumpPage);
+ } else if (gDumpPage < 0) {
+ uint32_t page = 1;
+ while (btree_dump_page(filename.toLocal8Bit().constData(), page))
+ ++page;
+ return 1;
+ }
+
+ AoDb db;
+ if (!db.open(filename, AoDb::ReadOnly)) {
+ qDebug() << "cannot open" << filename;
+ usage();
+ return 0;
+ }
+
+ if (gStat) {
+ const struct btree_stat *bs = db.stat();
+ qDebug() << "stat:";
+ qDebug() << "\thits:" << bs->hits;
+ qDebug() << "\treads:" << bs->reads;
+ qDebug() << "\tmax_cache:" << bs->max_cache;
+ qDebug() << "\tbranch_pages:" << bs->branch_pages;
+ qDebug() << "\tleaf_pages:" << bs->leaf_pages;
+ qDebug() << "\toverflow_pages:" << bs->overflow_pages;
+ qDebug() << "\trevisions:" << bs->revisions;
+ qDebug() << "\tdepth:" << bs->depth;
+ qDebug() << "\tentries:" << bs->entries;
+ qDebug() << "\tpsize:" << bs->psize;
+ qDebug() << "\tcreated_at:" << bs->created_at << "(" << QDateTime::fromTime_t(bs->created_at) << ")";
+ qDebug() << "\ttag:" << bs->tag;
+ qDebug() << "";
+ }
+ if (gDump) {
+ db.dump();
+ }
+
+ if (gShowState != 0) {
+#if 0
+ AoDb statedb;
+ QFileInfo fi(filename);
+ if (!statedb.open(QString("%1/%2-States.db").arg(fi.dir().path()).arg(fi.baseName()), AoDb::ReadOnly)) {
+ qDebug() << "cannot open" << filename;
+ usage();
+ return 0;
+ }
+ ObjectCursor cursor(&statedb, &db);
+ bool ok = cursor.first(gShowState);
+ if (!ok) {
+ qDebug() << "Could not seek to" << gShowState;
+ return 0;
+ }
+ QByteArray key, value;
+ for (int i = 0; ok && cursor.current(key, value); ok = cursor.next(), ++i) {
+ QString keyString, valueString;
+ makePrintable(key, keyString, value, valueString);
+ qDebug() << i << ":" << keyString << ":" << valueString;
+ }
+#endif
+ }
+
+ if (gShowAllReversed) {
+ AoDbCursor cursor(&db);
+ QByteArray key, value;
+ int i = 0;
+ for (bool ok = cursor.last(); ok && cursor.current(key, value); ok = cursor.prev(), ++i) {
+ QString keyString, valueString;
+ makePrintable(key, keyString, value, valueString);
+ qDebug() << i << ":" << keyString << ":" << valueString;
+ }
+ } else if (gShowAll) {
+ AoDbCursor cursor(&db);
+ QByteArray key, value;
+ int i = 0;
+ for (bool ok = cursor.first(); ok && cursor.current(key, value); ok = cursor.next(), ++i) {
+ QString keyString, valueString;
+ makePrintable(key, keyString, value, valueString);
+ qDebug() << i << ":" << keyString << ":" << valueString;
+ }
+ }
+
+ if (gWantCompact) {
+ db.close();
+ db.open(filename);
+ if (db.compact()) {
+ qDebug() << "compacted.";
+ } else {
+ qDebug() << "failed to compact" << filename;
+ }
+ db.close();
+ }
+ return 1;
+}
diff --git a/tools/jsondb-client/client.cpp b/tools/jsondb-client/client.cpp
new file mode 100644
index 00000000..1e674bcb
--- /dev/null
+++ b/tools/jsondb-client/client.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QSocketNotifier>
+#include <QCoreApplication>
+#include <QStringBuilder>
+#include <QMetaObject>
+#include <QThread>
+#include <QVariant>
+#include <QDir>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#include "json.h"
+
+#include "client.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+extern bool gDebug;
+
+const char* InputThread::commands[] = { "changesSince",
+ "create {\"",
+ "find",
+ "help",
+ "notify create [?",
+ "notify remove [?",
+ "notify update [?",
+ "query [?",
+ "quit",
+ "remove",
+ "update",
+ 0 };
+
+InputThread *InputThread::threadInstance = 0;
+
+InputThread *InputThread::instance()
+{
+ if (!threadInstance)
+ threadInstance = new InputThread;
+ return threadInstance;
+}
+
+InputThread::~InputThread()
+{
+ if (hist && !historyFile.isEmpty())
+ history(hist, 0, H_SAVE, historyFile.toLocal8Bit().constData());
+ if (hist) {
+ history_end(hist);
+ hist = 0;
+ }
+}
+
+char const* InputThread::prompt(EditLine *e)
+{
+ Q_UNUSED(e);
+ char const* string = "jclient> ";
+ return string;
+}
+
+QString InputThread::longestCommonPrefix(const QStringList &list)
+{
+ if (list.size() > 1) {
+ QChar temp;
+ int pos = 0;
+ for (bool roundComplete = true; roundComplete; pos++) {
+ for (int i = 0; i < list.size(); i++) {
+ QString entry = list[i];
+ if (entry.length() <= pos) {
+ roundComplete = false;
+ break;
+ } else if (i == 0)
+ temp = list[i][pos];
+ else {
+ if (temp != list[i][pos]) {
+ roundComplete = false;
+ break;
+ }
+ }
+ }
+ }
+ return list[0].left(pos-1);
+ } else if (list.size() == 1)
+ return list[0];
+ else
+ return QString();
+}
+
+unsigned char InputThread::console_tabkey(EditLine * el, int ch)
+{
+ Q_UNUSED(ch);
+ QStringList matches;
+ const LineInfo *lineInfo = el_line(el);
+ for (int i = 0; commands[i] != 0; i++) {
+ int compare = qstrncmp(commands[i], lineInfo->buffer, lineInfo->lastchar-lineInfo->buffer);
+ if (compare == 0) {
+ matches << QString::fromLocal8Bit(commands[i]);
+ }
+ }
+
+ int m = matches.size();
+ if (m == 1) {
+ QString missing = matches[0].remove(0,lineInfo->lastchar-lineInfo->buffer);
+ el_insertstr(el, qPrintable(missing));
+ return CC_REFRESH;
+ } else if (m > 1) {
+ instance()->async_print("\n" % matches.join("\n"));
+ QString missing = longestCommonPrefix(matches).remove(0,lineInfo->lastchar-lineInfo->buffer);
+ el_insertstr(el, qPrintable(missing));
+ return CC_REFRESH;
+ }
+ return CC_ARGHACK;
+}
+
+void InputThread::run()
+{
+ int count;
+ const char *line;
+ HistEvent ev;
+
+ el = el_init("jsondb-client", stdin, stdout, stderr);
+ el_set(el, EL_PROMPT, &prompt);
+ el_set(el, EL_EDITOR, "emacs");
+ hist = history_init();
+ el_set(el, EL_ADDFN, "tab-key", "TAB KEY PRESS", console_tabkey);
+ if (hist == 0) {
+ qDebug() << "initializing the history failed.";
+ exit(-1);
+ }
+ history(hist, &ev, H_SETSIZE, 800);
+ historyFile = QDir::homePath() + QDir::separator() + QLatin1String(".jsondb/history");
+ history(hist, &ev, H_LOAD, historyFile.toLocal8Bit().constData());
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_BIND, "\t", "tab-key", NULL);
+
+ while (true) {
+ line = el_gets(el, &count);
+
+ if (count > 0) {
+ QString cmd = QString(line).trimmed();
+ if (cmd == "quit")
+ break;
+ else if (!cmd.isEmpty()) {
+ emit (commandReceived(cmd));
+ history(hist, &ev, H_ENTER, line);
+ }
+ }
+ }
+
+ history(hist, &ev, H_SAVE, historyFile.toLocal8Bit().constData());
+ history_end(hist);
+ hist = 0;
+ el_end(el);
+
+ exit(0);
+}
+
+void InputThread::print(const QString &message)
+{
+ if (threadInstance) {
+ instance()->async_print(message);
+ } else {
+ std::cout << qPrintable(message) << std::endl;
+ }
+}
+
+void InputThread::async_print(const QString &message)
+{
+ QString clear(strlen(prompt(0)), QChar('\b'));
+ std::cout << qPrintable(clear) << qPrintable(message) << std::endl;
+ el_set(el, EL_REFRESH);
+}
+
+Client::Client( QObject *parent )
+ : QObject(parent), mNotifier(NULL), mInputThread(NULL)
+{
+}
+
+Client::~Client()
+{
+ if (mInputThread) {
+ mInputThread->terminate();
+ mInputThread->wait(1000);
+ delete mInputThread;
+ mInputThread = 0;
+ }
+}
+
+bool Client::connectToServer()
+{
+ QString socketName = ::getenv("JSONDB_SOCKET");
+ if (socketName.isEmpty()) {
+ mConnection = new QtAddOn::JsonDb::JsonDbClient(this);
+ } else {
+ mConnection = new QtAddOn::JsonDb::JsonDbClient(socketName, this);
+ }
+
+ connect(mConnection, SIGNAL(disconnected()), this, SLOT(disconnected()));
+ connect(mConnection, SIGNAL(response(int,QVariant)),
+ this, SLOT(response(int,QVariant)));
+ connect(mConnection, SIGNAL(error(int,int,QString)),
+ this, SLOT(error(int,int,QString)));
+ connect(mConnection, SIGNAL(notified(QString,QVariant,QString)),
+ this, SLOT(notified(QString,QVariant,QString)));
+
+ if (!mConnection->isConnected()) {
+ qCritical() << "Unable to connect to server";
+ return false;
+ }
+ return true;
+}
+
+void Client::interactiveMode()
+{
+ mInputThread = InputThread::instance();
+ connect(mInputThread, SIGNAL(commandReceived(QString)), this, SLOT(processCommand(QString)));
+ connect(mInputThread, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit()));
+ mInputThread->start();
+}
+
+void Client::disconnected()
+{
+ qCritical() << "Lost connection to the server";
+ QCoreApplication::exit(0);
+}
+
+void Client::notified(const QString &notify_uuid, const QVariant &object, const QString &action)
+{
+ JsonWriter writer;
+ writer.setAutoFormatting(true);
+ QString buf = writer.toString(object);
+
+ QString message = "Received notification: type " % action
+ % " for " % notify_uuid % " object:\n" % buf;
+ InputThread::print(message);
+
+ if (!mInputThread)
+ QCoreApplication::exit(0); // Non-interactive mode just stops
+}
+
+void Client::response(int id, const QVariant &msg)
+{
+ Q_UNUSED(id);
+ JsonWriter writer;
+ writer.setAutoFormatting(true);
+ QString buf = writer.toString(msg);
+
+ QString message = "Received message: " % buf;
+ InputThread::print(message);
+
+ mRequests.remove(id);
+ if (mRequests.isEmpty())
+ emit requestsProcessed();
+
+ if (!mInputThread)
+ QCoreApplication::exit(0); // Non-interactive mode just stops
+}
+
+void Client::error(int, int code, const QString &msg)
+{
+ QString message = "Received error " % QString().setNum(code) % ":" % msg;
+ InputThread::print(message);
+
+ if (!mInputThread)
+ QCoreApplication::exit(0); // Non-interactive mode just stops
+}
+
+void Client::usage()
+{
+ std::stringstream out;
+ out << "Valid commands:" << std::endl
+ << std::endl
+ << "Direct database commands - these take an explict object" << std::endl
+ << " create OBJECT" << std::endl
+ << " update OBJECT" << std::endl
+ << " remove OBJECT" << std::endl
+ << " remove QUERY" << std::endl
+ << " find QUERY" << std::endl
+ << " changesSince STATENUMBER [type1 type2 ...]" << std::endl
+ << std::endl
+ << "Convenience functions" << std::endl
+ << " query STRING [offset [limit]]" << std::endl
+ << " find {\"query\": STRING}" << std::endl
+ << " notify ACTIONS QUERY" << std::endl
+ << " create { \"_type\": \"notification\"," << std::endl
+ << " \"query\": QUERY," << std::endl
+ << " \"actions\": ACTIONS }" << std::endl
+ << " help" << std::endl
+ << " quit" << std::endl
+ << std::endl
+ << "ACTIONS: comma separated list. Valid values: create, update, remove" << std::endl
+ << "OBJECT: Valid JSON object" << std::endl
+ << "QUERY: Valid JSONQuery command" << std::endl
+ << std::endl
+ << "Sample commands: " << std::endl
+ << " create {\"_type\": \"duck\", \"name\": \"Fred\"}" << std::endl
+ << " query [?_type=\"duck\"]" << std::endl
+ << " notify create,remove [?_type=\"duck\"]" << std::endl;
+
+ QString usageInfo = QString::fromStdString(out.str());
+ InputThread::print(usageInfo);
+}
+
+bool Client::processCommand(const QString &command)
+{
+ QString cmd = command.trimmed();
+ QString rest;
+
+ int space = command.indexOf(' ');
+ if (space > 0) {
+ cmd = command.left(space);
+ rest = command.mid(space+1).trimmed();
+ }
+
+ gDebug = true;
+
+ if (cmd == "quit") {
+ exit(0);
+ } else if (cmd == "help") {
+ usage();
+ } else if (cmd == "query") {
+ int offset = 0, limit = -1;
+ int idx = rest.lastIndexOf(']');
+ if (idx != -1) {
+ QStringList list = rest.mid(idx+1).split(' ');
+ int i = 0;
+ for (; i < list.size(); ++i) {
+ if (!list.at(i).trimmed().isEmpty()) {
+ offset = list.at(i).toInt();
+ break;
+ }
+ }
+ for (++i; i < list.size(); ++i) {
+ if (!list.at(i).trimmed().isEmpty()) {
+ limit = list.at(i).toInt();
+ break;
+ }
+ }
+ rest.truncate(idx+1);
+ }
+ if (gDebug)
+ qDebug() << "Sending query:" << QVariant(rest);
+ mRequests << mConnection->query(rest, offset, limit);
+ } else if (cmd == "notify") {
+ int s = rest.indexOf(' ');
+ if (s <= 0)
+ return false;
+ QStringList alist = rest.left(s).split(QRegExp(","), QString::SkipEmptyParts);
+ QtAddOn::JsonDb::JsonDbClient::NotifyTypes actions;
+ foreach (const QString &s, alist) {
+ JsonDbClient::NotifyType type = JsonDbClient::NotifyType(0);
+ if (s == QLatin1String("create"))
+ type = JsonDbClient::NotifyCreate;
+ if (s == QLatin1String("remove"))
+ type = JsonDbClient::NotifyRemove;
+ if (s == QLatin1String("update"))
+ type = JsonDbClient::NotifyUpdate;
+ if (type == JsonDbClient::NotifyType(0)) {
+ InputThread::print("uknown notification type" % s);
+ return false;
+ }
+ actions |= type;
+ }
+ QString query = rest.mid(s+1).trimmed();
+ if (gDebug)
+ qDebug() << "Creating notification:" << alist << ":" << query;
+ mRequests << mConnection->notify(actions, query);
+ } else if (cmd == "remove") {
+ rest = rest.trimmed();
+ bool isquery = false;
+ int i = 0;
+ const int len = rest.length();
+ if (i < len) {
+ if (rest.at(i++) == QLatin1Char('[')) {
+ while (i < len && rest.at(i) == QLatin1Char(' ')) ++i;
+ if (i < len && rest.at(i) == QLatin1Char('?'))
+ isquery = true;
+ }
+ }
+ if (isquery) {
+ // if not json format, then it is a query
+ if (gDebug)
+ qDebug() << "Sending remove for:" << rest;
+ mRequests << mConnection->remove(rest);
+ } else {
+ JsonReader parser;
+ bool ok = parser.parse(rest);
+ if (!ok) {
+ InputThread::print("Unable to parse: " % rest);
+ usage();
+ return false;
+ }
+ QVariant arg = parser.result();
+ if (gDebug)
+ qDebug() << "Sending remove:" << arg;
+ mRequests << mConnection->remove(QVariant(arg));
+ }
+ } else if (cmd == "create" || cmd == "update" || cmd == "find" ) {
+ JsonReader parser;
+ bool ok = parser.parse(rest);
+ if (!ok) {
+ InputThread::print("Unable to parse: " % rest);
+ usage();
+ return false;
+ }
+ QVariant arg = parser.result();
+ if (gDebug)
+ qDebug() << "Sending" << cmd << ":" << arg;
+ int id = 0;
+ QMetaObject::invokeMethod(mConnection, cmd.toLatin1(), Q_RETURN_ARG(int, id), Q_ARG(QVariant, arg));
+ mRequests << id;
+ } else if (cmd == "changesSince") {
+ int stateNumber = 0;
+ QStringList types;
+ QStringList args = rest.split(" ");
+
+ if (args.isEmpty()) {
+ InputThread::print("Must specify the state number");
+ usage();
+ return false;
+ }
+
+ stateNumber = args.takeFirst().trimmed().toInt();
+
+ if (!args.isEmpty())
+ types = args;
+
+ if (gDebug)
+ qDebug() << "Sending changesSince: " << stateNumber << "types: " << types;
+
+ mRequests << mConnection->changesSince(stateNumber, types);
+ } else if (!cmd.isEmpty()) {
+ InputThread::print("Unrecognized command: " % cmd);
+ usage();
+ return false;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool Client::loadJsonFile(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ if (gDebug)
+ qDebug() << "Couldn't load file" << fileName;
+ return false;
+ }
+ JsonReader parser;
+ bool ok = parser.parse(file.readAll());
+ file.close();
+ if (!ok) {
+ std::cout << "Unable to parse the content of the file" << qPrintable(fileName) << ":"
+ << qPrintable(parser.errorString()) << std::endl;
+ return false;
+ }
+ QVariant arg = parser.result();
+ mRequests << mConnection->create(arg);
+ return true;
+}
diff --git a/tools/jsondb-client/client.h b/tools/jsondb-client/client.h
new file mode 100644
index 00000000..1c2f839d
--- /dev/null
+++ b/tools/jsondb-client/client.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <QObject>
+#include <QThread>
+#include <QStringList>
+#include <QLocalSocket>
+#include <QSocketNotifier>
+#include <QFile>
+
+#include <histedit.h>
+
+#include "jsondb-client.h"
+
+
+
+class InputThread : public QThread {
+ Q_OBJECT
+public:
+ static InputThread *instance();
+ ~InputThread();
+ void run();
+ void async_print(const QString &);
+ static void print(const QString &);
+ static char const* prompt(EditLine *e);
+ static unsigned char console_tabkey(EditLine * el, int ch);
+signals:
+ void commandReceived(QString);
+private:
+ EditLine *el;
+ History *hist;
+ QString historyFile;
+ InputThread(QObject *parent = 0) : QThread(parent), el(0), hist(0) {}
+ static QString longestCommonPrefix(const QStringList &list);
+ static InputThread *threadInstance;
+ static const char *commands[];
+};
+
+class Client : public QObject
+{
+ Q_OBJECT
+public:
+ Client(QObject *parent = 0);
+ ~Client();
+
+ bool connectToServer();
+ void interactiveMode();
+
+public slots:
+ bool processCommand(const QString &); // true if we're waiting for a response
+ bool loadJsonFile(const QString &fileName);
+
+protected slots:
+ void disconnected();
+
+ void response(int, const QVariant &map);
+ void error(int id, int code, const QString &message);
+ void notified(const QString &notify_uuid, const QVariant &object, const QString &action);
+
+signals:
+ void requestsProcessed();
+
+private:
+ void usage();
+
+ QSocketNotifier *mNotifier;
+ QFile *mInput;
+ QtAddOn::JsonDb::JsonDbClient *mConnection;
+ QSet<int> mRequests;
+ InputThread *mInputThread;
+};
+
+
+#endif // CLIENT_H
diff --git a/tools/jsondb-client/jsondb-client.pro b/tools/jsondb-client/jsondb-client.pro
new file mode 100644
index 00000000..a1b1ef9a
--- /dev/null
+++ b/tools/jsondb-client/jsondb-client.pro
@@ -0,0 +1,16 @@
+TARGET = jsondb-client
+DESTDIR = $$QT.jsondb.bins
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+QT = core network declarative jsondb
+
+LIBS += -ledit -lcurses
+
+include(../../src/3rdparty/qjson/qjson.pri)
+
+mac:CONFIG -= app_bundle
+
+HEADERS += client.h
+SOURCES += main.cpp client.cpp
diff --git a/tools/jsondb-client/main.cpp b/tools/jsondb-client/main.cpp
new file mode 100644
index 00000000..a6cc6482
--- /dev/null
+++ b/tools/jsondb-client/main.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <iostream>
+#include "client.h"
+
+QString progname;
+bool gDebug;
+
+/***************************************************************************/
+
+using namespace std;
+
+static void usage()
+{
+ cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [command]" << endl
+ << endl
+ << " -debug" << endl
+ << " -load file.json Load objects from a json file" << endl
+ << endl
+ << " where command is valid JsonDb command object" << endl;
+ exit(0);
+}
+
+
+int main(int argc, char * argv[])
+{
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("jclient");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+ QString loadFile;
+
+ progname = args.takeFirst();
+ while (args.size()) {
+ QString arg = args.at(0);
+ if (!arg.startsWith("-"))
+ break;
+ args.removeFirst();
+ if ( arg == "-help")
+ usage();
+ else if ( arg == "-debug")
+ gDebug = true;
+ else if (arg == "-load") {
+ if (args.isEmpty()) {
+ cout << "Invalid argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ loadFile = args.at(0);
+ args.removeFirst();
+ } else {
+ cout << "Unknown argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ }
+
+ Client client;
+ if (!client.connectToServer())
+ return 0;
+
+ bool interactive = !args.size();
+ if (!interactive)
+ QObject::connect(&client, SIGNAL(requestsProcessed()), &app, SLOT(quit()));
+
+ if (!loadFile.isEmpty()) {
+ client.loadJsonFile(loadFile);
+ } else if (!args.size()) {
+ client.interactiveMode();
+ } else {
+ if (!client.processCommand(args.join(" ")))
+ return 0;
+ }
+ return app.exec();
+}
diff --git a/tools/tools.pro b/tools/tools.pro
new file mode 100644
index 00000000..d6211f9a
--- /dev/null
+++ b/tools/tools.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += jsondb-client adb-dump
+