diff --git a/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInChildEntities.aql b/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInChildEntities.aql index fadf0217a..f3ce61cc0 100644 --- a/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInChildEntities.aql +++ b/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInChildEntities.aql @@ -9,15 +9,15 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "deliveryContents": ( FOR v_deliveryContent1 - IN (IS_LIST(v_delivery1.`deliveryContents`) ? v_delivery1.`deliveryContents` : []) + IN v_delivery1.`deliveryContents`[*] RETURN { "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_deliveryContent1.`items`) ? v_deliveryContent1.`items` : []) + IN v_deliveryContent1.`items`[*] RETURN { "subItems": ( FOR v_deliveryItem2 - IN (IS_LIST(v_deliveryItem1.`subItems`) ? v_deliveryItem1.`subItems` : []) + IN v_deliveryItem1.`subItems`[*] SORT (v_deliveryItem2.`itemNumber`) DESC RETURN { "itemNumber": v_deliveryItem2.`itemNumber` diff --git a/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInCollect.aql b/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInCollect.aql index eabfb8550..887aa82d3 100644 --- a/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInCollect.aql +++ b/spec/regression/collect/tests/nested-field-traversal/aql/childEntitiesInCollect.aql @@ -13,7 +13,7 @@ RETURN { RETURN { "subItems": ( FOR v_deliveryItem1 - IN (IS_LIST(v_item1.`subItems`) ? v_item1.`subItems` : []) + IN v_item1.`subItems`[*] SORT (v_deliveryItem1.`itemNumber`) DESC RETURN { "itemNumber": v_deliveryItem1.`itemNumber` diff --git a/spec/regression/collect/tests/nested-field-traversal/aql/collectInChildEntities.aql b/spec/regression/collect/tests/nested-field-traversal/aql/collectInChildEntities.aql index af95c09ee..91a2b84a9 100644 --- a/spec/regression/collect/tests/nested-field-traversal/aql/collectInChildEntities.aql +++ b/spec/regression/collect/tests/nested-field-traversal/aql/collectInChildEntities.aql @@ -9,11 +9,11 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "deliveryContents": ( FOR v_deliveryContent1 - IN (IS_LIST(v_delivery1.`deliveryContents`) ? v_delivery1.`deliveryContents` : []) + IN v_delivery1.`deliveryContents`[*] RETURN { "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_deliveryContent1.`items`) ? v_deliveryContent1.`items` : []) + IN v_deliveryContent1.`items`[*] RETURN { "subSubItems": ( FOR v_item1 diff --git a/spec/regression/logistics/tests/add-child-entity/aql/add.aql b/spec/regression/logistics/tests/add-child-entity/aql/add.aql index 5b6031ca3..e1eccbd3c 100644 --- a/spec/regression/logistics/tests/add-child-entity/aql/add.aql +++ b/spec/regression/logistics/tests/add-child-entity/aql/add.aql @@ -24,16 +24,12 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/add-child-entity/aql/query.aql b/spec/regression/logistics/tests/add-child-entity/aql/query.aql index f1e695697..4e77e618d 100644 --- a/spec/regression/logistics/tests/add-child-entity/aql/query.aql +++ b/spec/regression/logistics/tests/add-child-entity/aql/query.aql @@ -7,14 +7,10 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/add-root-entity/aql/query.aql b/spec/regression/logistics/tests/add-root-entity/aql/query.aql index 8aaf91b2d..eff12f70b 100644 --- a/spec/regression/logistics/tests/add-root-entity/aql/query.aql +++ b/spec/regression/logistics/tests/add-root-entity/aql/query.aql @@ -5,16 +5,12 @@ RETURN { SORT (v_country1.`isoCode`) RETURN { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] } ) } -// Peak memory usage: 65536 bytes +// Peak memory usage: 32768 bytes diff --git a/spec/regression/logistics/tests/aliases/aql/aliases.aql b/spec/regression/logistics/tests/aliases/aql/aliases.aql index 311ecfc94..1d3096e9f 100644 --- a/spec/regression/logistics/tests/aliases/aql/aliases.aql +++ b/spec/regression/logistics/tests/aliases/aql/aliases.aql @@ -15,25 +15,16 @@ LET v_delivery3 = FIRST(( RETURN { "aDelivery": (IS_NULL(v_delivery1) ? null : { "nr": v_delivery1.`deliveryNumber`, - "oneItem": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - FILTER (v_deliveryItem1.`itemNumber` == @var5) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ), - "items": ( - FOR v_deliveryItem2 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem2.`itemNumber` - } - ) + "oneItem": v_delivery1.`items`[* FILTER (CURRENT.`itemNumber` == @var5) RETURN { + "itemNumber": CURRENT.`itemNumber` + }], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }), "anotherDelivery": (IS_NULL(v_delivery3) ? null : { "nr": v_delivery3.`deliveryNumber` }) } -// Peak memory usage: 131072 bytes +// Peak memory usage: 32768 bytes diff --git a/spec/regression/logistics/tests/create-many/aql/create.aql b/spec/regression/logistics/tests/create-many/aql/create.aql index 4803ba643..eafdabe92 100644 --- a/spec/regression/logistics/tests/create-many/aql/create.aql +++ b/spec/regression/logistics/tests/create-many/aql/create.aql @@ -228,41 +228,29 @@ RETURN ( "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ), + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }], "handlingUnits": ( FOR v_handlingUnit1 IN OUTBOUND v_delivery1 @@deliveries_handlingUnits @@ -275,7 +263,7 @@ RETURN ( } ) -// Peak memory usage: 262144 bytes +// Peak memory usage: 163840 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/create-many/aql/query.aql b/spec/regression/logistics/tests/create-many/aql/query.aql index b6f7163de..50fc2ebe7 100644 --- a/spec/regression/logistics/tests/create-many/aql/query.aql +++ b/spec/regression/logistics/tests/create-many/aql/query.aql @@ -25,41 +25,29 @@ RETURN { "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ), + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }], "handlingUnits": ( FOR v_handlingUnit1 IN OUTBOUND v_delivery1 @@deliveries_handlingUnits @@ -73,4 +61,4 @@ RETURN { ) } -// Peak memory usage: 229376 bytes +// Peak memory usage: 98304 bytes diff --git a/spec/regression/logistics/tests/create/aql/create.aql b/spec/regression/logistics/tests/create/aql/create.aql index 438b69d4e..a8352f89d 100644 --- a/spec/regression/logistics/tests/create/aql/create.aql +++ b/spec/regression/logistics/tests/create/aql/create.aql @@ -60,44 +60,32 @@ RETURN (IS_NULL(v_delivery1) ? null : { "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 196608 bytes +// Peak memory usage: 32768 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/create/aql/query.aql b/spec/regression/logistics/tests/create/aql/query.aql index 4237bff1f..d3f54f4d9 100644 --- a/spec/regression/logistics/tests/create/aql/query.aql +++ b/spec/regression/logistics/tests/create/aql/query.aql @@ -24,43 +24,31 @@ RETURN { "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] } ) } -// Peak memory usage: 196608 bytes +// Peak memory usage: 65536 bytes diff --git a/spec/regression/logistics/tests/entity-extensions/aql/afterUpdate.aql b/spec/regression/logistics/tests/entity-extensions/aql/afterUpdate.aql index 8934ab2f3..8861628fa 100644 --- a/spec/regression/logistics/tests/entity-extensions/aql/afterUpdate.aql +++ b/spec/regression/logistics/tests/entity-extensions/aql/afterUpdate.aql @@ -9,7 +9,7 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "dgInfo": { "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] } }) } diff --git a/spec/regression/logistics/tests/entity-extensions/aql/before.aql b/spec/regression/logistics/tests/entity-extensions/aql/before.aql index 5c401af3d..b46dee836 100644 --- a/spec/regression/logistics/tests/entity-extensions/aql/before.aql +++ b/spec/regression/logistics/tests/entity-extensions/aql/before.aql @@ -16,15 +16,15 @@ RETURN { "withValue": (IS_NULL(v_delivery1) ? null : { "dgInfo": { "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] } }), "withoutValue": (IS_NULL(v_delivery3) ? null : { "dgInfo": { "unNumber": v_delivery3.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery3.`dgInfo`.`notices`) ? v_delivery3.`dgInfo`.`notices` : []) + "notices": v_delivery3.`dgInfo`.`notices`[*] } }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/entity-extensions/aql/createWithNull.aql b/spec/regression/logistics/tests/entity-extensions/aql/createWithNull.aql index 6fb05737f..fe674fff5 100644 --- a/spec/regression/logistics/tests/entity-extensions/aql/createWithNull.aql +++ b/spec/regression/logistics/tests/entity-extensions/aql/createWithNull.aql @@ -12,7 +12,7 @@ LET v_delivery1 = DOCUMENT(@@deliveries, @v_newEntityId1) RETURN (IS_NULL(v_delivery1) ? null : { "dgInfo": { "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] } }) diff --git a/spec/regression/logistics/tests/entity-extensions/aql/createWithValue.aql b/spec/regression/logistics/tests/entity-extensions/aql/createWithValue.aql index 6b433e9f0..3659b9b35 100644 --- a/spec/regression/logistics/tests/entity-extensions/aql/createWithValue.aql +++ b/spec/regression/logistics/tests/entity-extensions/aql/createWithValue.aql @@ -43,7 +43,7 @@ LET v_delivery1 = DOCUMENT(@@deliveries, @v_newEntityId1) RETURN (IS_NULL(v_delivery1) ? null : { "dgInfo": { "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] } }) diff --git a/spec/regression/logistics/tests/entity-extensions/aql/update.aql b/spec/regression/logistics/tests/entity-extensions/aql/update.aql index 143bd37d9..6a7b9daf2 100644 --- a/spec/regression/logistics/tests/entity-extensions/aql/update.aql +++ b/spec/regression/logistics/tests/entity-extensions/aql/update.aql @@ -31,7 +31,7 @@ LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { "dgInfo": { "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []), + "notices": v_delivery1.`dgInfo`.`notices`[*], "details": { "expiryDate": v_delivery1.`dgInfo`.`details`.`expiryDate` } diff --git a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/empty.aql b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/empty.aql index 83bdaaf24..3a04323d3 100644 --- a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/empty.aql +++ b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/empty.aql @@ -6,9 +6,9 @@ RETURN { SORT (v_delivery1.`deliveryNumber`) RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []) + "serialNumbers": v_delivery1.`serialNumbers`[*] } ) } -// Peak memory usage: 65536 bytes +// Peak memory usage: 32768 bytes diff --git a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/init.aql b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/init.aql index ab38480eb..9e85cea04 100644 --- a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/init.aql +++ b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/init.aql @@ -25,7 +25,7 @@ WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []) + "serialNumbers": v_delivery1.`serialNumbers`[*] }) // Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/none.aql b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/none.aql index 573275eed..72f8487cf 100644 --- a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/none.aql +++ b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/none.aql @@ -15,7 +15,7 @@ RETURN { SORT (v_delivery1.`deliveryNumber`) RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []) + "serialNumbers": v_delivery1.`serialNumbers`[*] } ) } diff --git a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/not_empty.aql b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/not_empty.aql index 2c7f593b0..35a86fe50 100644 --- a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/not_empty.aql +++ b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/not_empty.aql @@ -6,9 +6,9 @@ RETURN { SORT (v_delivery1.`deliveryNumber`) RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []) + "serialNumbers": v_delivery1.`serialNumbers`[*] } ) } -// Peak memory usage: 65536 bytes +// Peak memory usage: 32768 bytes diff --git a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/some.aql b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/some.aql index 2133f22f1..2e7a3200a 100644 --- a/spec/regression/logistics/tests/filter-empty-scalar-list/aql/some.aql +++ b/spec/regression/logistics/tests/filter-empty-scalar-list/aql/some.aql @@ -15,7 +15,7 @@ RETURN { SORT (v_delivery1.`deliveryNumber`) RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []) + "serialNumbers": v_delivery1.`serialNumbers`[*] } ) } diff --git a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nString.aql b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nString.aql index f3f7f34c8..036e19915 100644 --- a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nString.aql +++ b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nString.aql @@ -9,7 +9,7 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) + IN v_delivery1.`items`[*] FILTER (FIRST( FOR v_item1 IN ( diff --git a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithCorrectLanguage.aql b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithCorrectLanguage.aql index 18a306712..9bf724bd0 100644 --- a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithCorrectLanguage.aql +++ b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithCorrectLanguage.aql @@ -9,7 +9,7 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) + IN v_delivery1.`items`[*] FILTER (FIRST( FOR v_item1 IN ( diff --git a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithIncorrectLanguage.aql b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithIncorrectLanguage.aql index 18a306712..9bf724bd0 100644 --- a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithIncorrectLanguage.aql +++ b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithIncorrectLanguage.aql @@ -9,7 +9,7 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) + IN v_delivery1.`items`[*] FILTER (FIRST( FOR v_item1 IN ( diff --git a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithNullValueForI18nString.aql b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithNullValueForI18nString.aql index 18a306712..9bf724bd0 100644 --- a/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithNullValueForI18nString.aql +++ b/spec/regression/logistics/tests/filter-stringmap-in-child-entities/aql/filterI18nStringWithNullValueForI18nString.aql @@ -9,7 +9,7 @@ RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) + IN v_delivery1.`items`[*] FILTER (FIRST( FOR v_item1 IN ( diff --git a/spec/regression/logistics/tests/flex-search-in-memory/aql/offset_date_time.aql b/spec/regression/logistics/tests/flex-search-in-memory/aql/offset_date_time.aql index 22041a10a..0faf11258 100644 --- a/spec/regression/logistics/tests/flex-search-in-memory/aql/offset_date_time.aql +++ b/spec/regression/logistics/tests/flex-search-in-memory/aql/offset_date_time.aql @@ -10,7 +10,7 @@ RETURN { SORT (v_delivery1.`deliveryNumber`) , (v_delivery1.`createdAt`) DESC, (v_delivery1._key) DESC RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), + "serialNumbers": v_delivery1.`serialNumbers`[*], "dispatchDate": v_delivery1.`dispatchDate` } ) diff --git a/spec/regression/logistics/tests/flex-search-in-memory/aql/string_aggregation.aql b/spec/regression/logistics/tests/flex-search-in-memory/aql/string_aggregation.aql index 6c2d1fe35..0a1855061 100644 --- a/spec/regression/logistics/tests/flex-search-in-memory/aql/string_aggregation.aql +++ b/spec/regression/logistics/tests/flex-search-in-memory/aql/string_aggregation.aql @@ -10,7 +10,7 @@ RETURN { SORT (v_delivery1.`deliveryNumber`) , (v_delivery1.`createdAt`) DESC, (v_delivery1._key) DESC RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []) + "serialNumbers": v_delivery1.`serialNumbers`[*] } ) } diff --git a/spec/regression/logistics/tests/query-all/aql/allCountries.aql b/spec/regression/logistics/tests/query-all/aql/allCountries.aql index 4f5c081d2..7c6ca230b 100644 --- a/spec/regression/logistics/tests/query-all/aql/allCountries.aql +++ b/spec/regression/logistics/tests/query-all/aql/allCountries.aql @@ -6,14 +6,10 @@ RETURN { RETURN { "id": v_country1._key, "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] } ) } diff --git a/spec/regression/logistics/tests/reference-to-id/aql/referenceToExistingID.aql b/spec/regression/logistics/tests/reference-to-id/aql/referenceToExistingID.aql index e4eaf7f51..1a4029ef3 100644 --- a/spec/regression/logistics/tests/reference-to-id/aql/referenceToExistingID.aql +++ b/spec/regression/logistics/tests/reference-to-id/aql/referenceToExistingID.aql @@ -10,7 +10,7 @@ RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) + IN v_delivery1.`items`[*] LET v_handlingUnit1 = (IS_NULL(v_deliveryItem1.`handlingUnit`) ? null : FIRST(( FOR v_handlingUnit2 IN @@handlingUnits diff --git a/spec/regression/logistics/tests/reference-to-id/aql/referenceToWrongID.aql b/spec/regression/logistics/tests/reference-to-id/aql/referenceToWrongID.aql index 6cd7b7949..dc53a2be5 100644 --- a/spec/regression/logistics/tests/reference-to-id/aql/referenceToWrongID.aql +++ b/spec/regression/logistics/tests/reference-to-id/aql/referenceToWrongID.aql @@ -10,7 +10,7 @@ RETURN { "deliveryNumber": v_delivery1.`deliveryNumber`, "items": ( FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) + IN v_delivery1.`items`[*] LET v_handlingUnit1 = (IS_NULL(v_deliveryItem1.`handlingUnit`) ? null : FIRST(( FOR v_handlingUnit2 IN @@handlingUnits diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/addSome.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/addSome.aql index 7dce4da28..142b1a3f0 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/addSome.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/addSome.aql @@ -24,17 +24,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/addUpdateAndDelete.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/addUpdateAndDelete.aql index d7ad63acf..1579d4c19 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/addUpdateAndDelete.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/addUpdateAndDelete.aql @@ -52,17 +52,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateMultiple.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateMultiple.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateMultiple.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateMultiple.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateOne.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateOne.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateOne.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/afterUpdateOne.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/end.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/end.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/end.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/end.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/updateMultiple.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/updateMultiple.aql index 15764e84c..abab80529 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/updateMultiple.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/updateMultiple.aql @@ -63,17 +63,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities-dict/aql/updateOne.aql b/spec/regression/logistics/tests/update-child-entities-dict/aql/updateOne.aql index 9fec2a7d9..0edc23f98 100644 --- a/spec/regression/logistics/tests/update-child-entities-dict/aql/updateOne.aql +++ b/spec/regression/logistics/tests/update-child-entities-dict/aql/updateOne.aql @@ -43,17 +43,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities/aql/addSome.aql b/spec/regression/logistics/tests/update-child-entities/aql/addSome.aql index 7dce4da28..142b1a3f0 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/addSome.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/addSome.aql @@ -24,17 +24,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities/aql/addUpdateAndDelete.aql b/spec/regression/logistics/tests/update-child-entities/aql/addUpdateAndDelete.aql index 77946c0ff..5d23c5255 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/addUpdateAndDelete.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/addUpdateAndDelete.aql @@ -35,17 +35,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateMultiple.aql b/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateMultiple.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateMultiple.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateMultiple.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateOne.aql b/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateOne.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateOne.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/afterUpdateOne.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-child-entities/aql/end.aql b/spec/regression/logistics/tests/update-child-entities/aql/end.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/end.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/end.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-child-entities/aql/updateMultiple.aql b/spec/regression/logistics/tests/update-child-entities/aql/updateMultiple.aql index 5dedad06e..9c6833211 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/updateMultiple.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/updateMultiple.aql @@ -46,17 +46,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-child-entities/aql/updateOne.aql b/spec/regression/logistics/tests/update-child-entities/aql/updateOne.aql index aedb30bd4..0b83ced79 100644 --- a/spec/regression/logistics/tests/update-child-entities/aql/updateOne.aql +++ b/spec/regression/logistics/tests/update-child-entities/aql/updateOne.aql @@ -31,17 +31,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterClear.aql b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterClear.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterClear.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterClear.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterUpdateMultiple.aql b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterUpdateMultiple.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterUpdateMultiple.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/afterUpdateMultiple.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/clearItems.aql b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/clearItems.aql index 553d355c0..30481df64 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/clearItems.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/clearItems.aql @@ -29,17 +29,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/updateMultiple.aql b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/updateMultiple.aql index f5c8ba12e..e2fdc38a3 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/updateMultiple.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list-dict/aql/updateMultiple.aql @@ -59,17 +59,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterClear.aql b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterClear.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterClear.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterClear.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterUpdateMultiple.aql b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterUpdateMultiple.aql index fe72af49a..bbefcdc34 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterUpdateMultiple.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/afterUpdateMultiple.aql @@ -7,15 +7,11 @@ LET v_delivery1 = FIRST(( )) RETURN { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/clearItems.aql b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/clearItems.aql index 553d355c0..30481df64 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/clearItems.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/clearItems.aql @@ -29,17 +29,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/updateMultiple.aql b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/updateMultiple.aql index 807a69b1c..e0bcc75b4 100644 --- a/spec/regression/logistics/tests/update-empty-child-entities-list/aql/updateMultiple.aql +++ b/spec/regression/logistics/tests/update-empty-child-entities-list/aql/updateMultiple.aql @@ -43,17 +43,13 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "id": v_deliveryItem1.`id`, - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "id": CURRENT.`id`, + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-many/aql/create.aql b/spec/regression/logistics/tests/update-many/aql/create.aql index e4432d92b..ef799ac79 100644 --- a/spec/regression/logistics/tests/update-many/aql/create.aql +++ b/spec/regression/logistics/tests/update-many/aql/create.aql @@ -220,41 +220,29 @@ RETURN ( "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ), + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }], "handlingUnits": ( FOR v_handlingUnit1 IN OUTBOUND v_delivery1 @@deliveries_handlingUnits @@ -267,7 +255,7 @@ RETURN ( } ) -// Peak memory usage: 262144 bytes +// Peak memory usage: 163840 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/logistics/tests/update-many/aql/query.aql b/spec/regression/logistics/tests/update-many/aql/query.aql index b6f7163de..50fc2ebe7 100644 --- a/spec/regression/logistics/tests/update-many/aql/query.aql +++ b/spec/regression/logistics/tests/update-many/aql/query.aql @@ -25,41 +25,29 @@ RETURN { "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ), + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }], "handlingUnits": ( FOR v_handlingUnit1 IN OUTBOUND v_delivery1 @@deliveries_handlingUnits @@ -73,4 +61,4 @@ RETURN { ) } -// Peak memory usage: 229376 bytes +// Peak memory usage: 98304 bytes diff --git a/spec/regression/namespaced_logistics/tests/add-child-entity/aql/add.aql b/spec/regression/namespaced_logistics/tests/add-child-entity/aql/add.aql index 224223bef..d8d996cab 100644 --- a/spec/regression/namespaced_logistics/tests/add-child-entity/aql/add.aql +++ b/spec/regression/namespaced_logistics/tests/add-child-entity/aql/add.aql @@ -24,16 +24,12 @@ RETURN ( WITH @@deliveries LET v_delivery1 = DOCUMENT(@@deliveries, @var1) RETURN (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/namespaced_logistics/tests/add-child-entity/aql/query.aql b/spec/regression/namespaced_logistics/tests/add-child-entity/aql/query.aql index 1bb8add35..6ac1ad324 100644 --- a/spec/regression/namespaced_logistics/tests/add-child-entity/aql/query.aql +++ b/spec/regression/namespaced_logistics/tests/add-child-entity/aql/query.aql @@ -9,16 +9,12 @@ RETURN { "logistics": { "delivery": { "Delivery": (IS_NULL(v_delivery1) ? null : { - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }) } } } -// Peak memory usage: 32768 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/namespaced_logistics/tests/add-root-entity/aql/query.aql b/spec/regression/namespaced_logistics/tests/add-root-entity/aql/query.aql index 364156bd8..71a51bc93 100644 --- a/spec/regression/namespaced_logistics/tests/add-root-entity/aql/query.aql +++ b/spec/regression/namespaced_logistics/tests/add-root-entity/aql/query.aql @@ -6,17 +6,13 @@ RETURN { SORT (v_country1.`isoCode`) RETURN { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] } ) } } -// Peak memory usage: 65536 bytes +// Peak memory usage: 32768 bytes diff --git a/spec/regression/namespaced_logistics/tests/aliases/aql/aliases.aql b/spec/regression/namespaced_logistics/tests/aliases/aql/aliases.aql index 1f246ef2c..9a02ad13d 100644 --- a/spec/regression/namespaced_logistics/tests/aliases/aql/aliases.aql +++ b/spec/regression/namespaced_logistics/tests/aliases/aql/aliases.aql @@ -17,21 +17,12 @@ RETURN { "delivery": { "aDelivery": (IS_NULL(v_delivery1) ? null : { "nr": v_delivery1.`deliveryNumber`, - "oneItem": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - FILTER (v_deliveryItem1.`itemNumber` == @var5) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ), - "items": ( - FOR v_deliveryItem2 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem2.`itemNumber` - } - ) + "oneItem": v_delivery1.`items`[* FILTER (CURRENT.`itemNumber` == @var5) RETURN { + "itemNumber": CURRENT.`itemNumber` + }], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }), "anotherDelivery": (IS_NULL(v_delivery3) ? null : { "nr": v_delivery3.`deliveryNumber` @@ -40,4 +31,4 @@ RETURN { } } -// Peak memory usage: 131072 bytes +// Peak memory usage: 0 bytes diff --git a/spec/regression/namespaced_logistics/tests/create/aql/create.aql b/spec/regression/namespaced_logistics/tests/create/aql/create.aql index 557f66399..a3e41e74b 100644 --- a/spec/regression/namespaced_logistics/tests/create/aql/create.aql +++ b/spec/regression/namespaced_logistics/tests/create/aql/create.aql @@ -29,44 +29,32 @@ RETURN (IS_NULL(v_delivery1) ? null : { "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] }) -// Peak memory usage: 196608 bytes +// Peak memory usage: 32768 bytes // ---------------------------------------------------------------- diff --git a/spec/regression/namespaced_logistics/tests/create/aql/query.aql b/spec/regression/namespaced_logistics/tests/create/aql/query.aql index fa24f7131..4ea21e987 100644 --- a/spec/regression/namespaced_logistics/tests/create/aql/query.aql +++ b/spec/regression/namespaced_logistics/tests/create/aql/query.aql @@ -26,45 +26,33 @@ RETURN { "city": v_delivery1.`consignee`.`city`, "country": (IS_NULL(v_country1) ? null : { "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] }), "street": v_delivery1.`consignee`.`street` }), - "contentInfo": ( - FOR v_translation2 - IN (IS_LIST(v_delivery1.`contentInfo`) ? v_delivery1.`contentInfo` : []) - RETURN { - "translation": v_translation2.`translation`, - "languageIsoCode": v_translation2.`languageIsoCode` - } - ), + "contentInfo": v_delivery1.`contentInfo`[* RETURN { + "translation": CURRENT.`translation`, + "languageIsoCode": CURRENT.`languageIsoCode` + }], "destinationCountry": (IS_NULL(v_country3) ? null : { "isoCode": v_country3.`isoCode` }), "dgInfo": { "flashpoint": v_delivery1.`dgInfo`.`flashpoint`, "unNumber": v_delivery1.`dgInfo`.`unNumber`, - "notices": (IS_LIST(v_delivery1.`dgInfo`.`notices`) ? v_delivery1.`dgInfo`.`notices` : []) + "notices": v_delivery1.`dgInfo`.`notices`[*] }, - "serialNumbers": (IS_LIST(v_delivery1.`serialNumbers`) ? v_delivery1.`serialNumbers` : []), - "items": ( - FOR v_deliveryItem1 - IN (IS_LIST(v_delivery1.`items`) ? v_delivery1.`items` : []) - RETURN { - "itemNumber": v_deliveryItem1.`itemNumber` - } - ) + "serialNumbers": v_delivery1.`serialNumbers`[*], + "items": v_delivery1.`items`[* RETURN { + "itemNumber": CURRENT.`itemNumber` + }] } ) } } } -// Peak memory usage: 196608 bytes +// Peak memory usage: 65536 bytes diff --git a/spec/regression/namespaced_logistics/tests/query-all/aql/queryAll.aql b/spec/regression/namespaced_logistics/tests/query-all/aql/queryAll.aql index 258b624f7..2e71cda3d 100644 --- a/spec/regression/namespaced_logistics/tests/query-all/aql/queryAll.aql +++ b/spec/regression/namespaced_logistics/tests/query-all/aql/queryAll.aql @@ -7,14 +7,10 @@ RETURN { RETURN { "id": v_country1._key, "isoCode": v_country1.`isoCode`, - "description": ( - FOR v_translation1 - IN (IS_LIST(v_country1.`description`) ? v_country1.`description` : []) - RETURN { - "languageIsoCode": v_translation1.`languageIsoCode`, - "translation": v_translation1.`translation` - } - ) + "description": v_country1.`description`[* RETURN { + "languageIsoCode": CURRENT.`languageIsoCode`, + "translation": CURRENT.`translation` + }] } ) } diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersHavingACertainLiteraturReferences.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersHavingACertainLiteraturReferences.aql index 14957994a..338102f69 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersHavingACertainLiteraturReferences.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersHavingACertainLiteraturReferences.aql @@ -8,7 +8,7 @@ RETURN { "key": v_paper1.`key`, "literatureReferences": ( FOR v_literatureReference1 - IN (IS_LIST(v_paper1.`literatureReferences`) ? v_paper1.`literatureReferences` : []) + IN v_paper1.`literatureReferences`[*] SORT (v_literatureReference1.`title`) , (v_literatureReference1.`pages`.`startPage`) RETURN { "title": v_literatureReference1.`title` diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferences.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferences.aql index 4416a9923..35e0aa5c2 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferences.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferences.aql @@ -17,7 +17,7 @@ RETURN { "key": v_paper1.`key`, "literatureReferences": ( FOR v_literatureReference1 - IN (IS_LIST(v_paper1.`literatureReferences`) ? v_paper1.`literatureReferences` : []) + IN v_paper1.`literatureReferences`[*] SORT (v_literatureReference1.`title`) , (v_literatureReference1.`pages`.`startPage`) RETURN { "title": v_literatureReference1.`title` @@ -27,4 +27,4 @@ RETURN { ) } -// Peak memory usage: 98304 bytes +// Peak memory usage: 131072 bytes diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferencesLike.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferencesLike.aql index f013e9557..d7e3faef0 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferencesLike.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersHavingLiteraturReferencesLike.aql @@ -18,7 +18,7 @@ RETURN { "key": v_paper1.`key`, "literatureReferences": ( FOR v_literatureReference1 - IN (IS_LIST(v_paper1.`literatureReferences`) ? v_paper1.`literatureReferences` : []) + IN v_paper1.`literatureReferences`[*] SORT (v_literatureReference1.`title`) , (v_literatureReference1.`pages`.`startPage`) RETURN { "title": v_literatureReference1.`title` @@ -28,4 +28,4 @@ RETURN { ) } -// Peak memory usage: 98304 bytes +// Peak memory usage: 131072 bytes diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersNotInOneOfTheseCategories.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersNotInOneOfTheseCategories.aql index 068598c44..e5811ea15 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersNotInOneOfTheseCategories.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersNotInOneOfTheseCategories.aql @@ -6,7 +6,7 @@ RETURN { SORT (v_paper1.`key`) RETURN { "key": v_paper1.`key`, - "categories": (IS_LIST(v_paper1.`categories`) ? v_paper1.`categories` : []) + "categories": v_paper1.`categories`[*] } ) } diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersOfSomeCategories.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersOfSomeCategories.aql index 0924894d6..db5a9c182 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersOfSomeCategories.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersOfSomeCategories.aql @@ -6,7 +6,7 @@ RETURN { SORT (v_paper1.`key`) RETURN { "key": v_paper1.`key`, - "categories": (IS_LIST(v_paper1.`categories`) ? v_paper1.`categories` : []) + "categories": v_paper1.`categories`[*] } ) } diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersWhichHaveOnlyOneOfTheseCategories.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersWhichHaveOnlyOneOfTheseCategories.aql index 47ae06e85..41860cd6c 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersWhichHaveOnlyOneOfTheseCategories.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersWhichHaveOnlyOneOfTheseCategories.aql @@ -6,7 +6,7 @@ RETURN { SORT (v_paper1.`key`) RETURN { "key": v_paper1.`key`, - "categories": (IS_LIST(v_paper1.`categories`) ? v_paper1.`categories` : []) + "categories": v_paper1.`categories`[*] } ) } diff --git a/spec/regression/papers/tests/quantifiers/aql/allPapersWihoutLiteraturReferences.aql b/spec/regression/papers/tests/quantifiers/aql/allPapersWihoutLiteraturReferences.aql index 1a4e123a2..44d585a68 100644 --- a/spec/regression/papers/tests/quantifiers/aql/allPapersWihoutLiteraturReferences.aql +++ b/spec/regression/papers/tests/quantifiers/aql/allPapersWihoutLiteraturReferences.aql @@ -17,7 +17,7 @@ RETURN { "key": v_paper1.`key`, "literatureReferences": ( FOR v_literatureReference1 - IN (IS_LIST(v_paper1.`literatureReferences`) ? v_paper1.`literatureReferences` : []) + IN v_paper1.`literatureReferences`[*] SORT (v_literatureReference1.`title`) , (v_literatureReference1.`pages`.`startPage`) RETURN { "title": v_literatureReference1.`title` @@ -27,4 +27,4 @@ RETURN { ) } -// Peak memory usage: 98304 bytes +// Peak memory usage: 131072 bytes diff --git a/spec/regression/papers/tests/references/aql/references.aql b/spec/regression/papers/tests/references/aql/references.aql index de8a9c66f..ef581336a 100644 --- a/spec/regression/papers/tests/references/aql/references.aql +++ b/spec/regression/papers/tests/references/aql/references.aql @@ -7,7 +7,7 @@ RETURN { "title": v_paper1.`title`, "literatureReferences": ( FOR v_literatureReference1 - IN (IS_LIST(v_paper1.`literatureReferences`) ? v_paper1.`literatureReferences` : []) + IN v_paper1.`literatureReferences`[*] LET v_paper2 = (IS_NULL(v_literatureReference1.`paper`) ? null : FIRST(( FOR v_paper3 IN @@papers @@ -20,16 +20,16 @@ RETURN { "title": v_paper2.`title`, "publishDate": v_paper2.`publishDate`, "isPublished": v_paper2.`isPublished`, - "tags": (IS_LIST(v_paper2.`tags`) ? v_paper2.`tags` : []) + "tags": v_paper2.`tags`[*] }), - "authors": (IS_LIST(v_literatureReference1.`authors`) ? v_literatureReference1.`authors` : []), + "authors": v_literatureReference1.`authors`[*], "pages": (IS_NULL(v_literatureReference1.`pages`) ? null : { "startPage": v_literatureReference1.`pages`.`startPage`, "endPage": v_literatureReference1.`pages`.`endPage` }) } ), - "tags": (IS_LIST(v_paper1.`tags`) ? v_paper1.`tags` : []) + "tags": v_paper1.`tags`[*] } ) } diff --git a/spec/regression/root-fields/tests/root-and-parent-with-collect/aql/q.aql b/spec/regression/root-fields/tests/root-and-parent-with-collect/aql/q.aql index 608dc1904..4568d4b71 100644 --- a/spec/regression/root-fields/tests/root-and-parent-with-collect/aql/q.aql +++ b/spec/regression/root-fields/tests/root-and-parent-with-collect/aql/q.aql @@ -28,13 +28,14 @@ RETURN { "rootGrandchildren": ( FOR v_root2, v_edge1, v_path1 IN @var5..@var6 OUTBOUND v_root21 @@root2s_roots FILTER v_root2._key != null + LET v_root3 = NOEVAL({ + "name": v_root2.`name` + }) FOR v_item1 IN v_root2.`children`[*].`children`[*][** RETURN { value: { "name": CURRENT.`name`, "parent": { __cruddl_runtime_error_code: @var7, __cruddl_runtime_error: @var8 }, - "root": { - "name": v_root2.`name` - } + "root": v_root3 }, sortValues: [ CURRENT.`name` @@ -44,15 +45,16 @@ RETURN { RETURN v_item1.value ), "rootExtensionGrandchildren": ( - FOR v_root3, v_edge2, v_path2 IN @var9..@var10 OUTBOUND v_root21 @@root2s_roots - FILTER v_root3._key != null - FOR v_item2 IN v_root3.`children`[*].`extension`.`children`[*][** RETURN { + FOR v_root4, v_edge2, v_path2 IN @var9..@var10 OUTBOUND v_root21 @@root2s_roots + FILTER v_root4._key != null + LET v_root5 = NOEVAL({ + "name": v_root4.`name` + }) + FOR v_item2 IN v_root4.`children`[*].`extension`.`children`[*][** RETURN { value: { "name": CURRENT.`name`, "parent": { __cruddl_runtime_error_code: @var11, __cruddl_runtime_error: @var12 }, - "root": { - "name": v_root3.`name` - } + "root": v_root5 }, sortValues: [ CURRENT.`name` diff --git a/spec/regression/root-fields/tests/root-and-parent/aql/test.aql b/spec/regression/root-fields/tests/root-and-parent/aql/test.aql index 2db01ba22..73fd68813 100644 --- a/spec/regression/root-fields/tests/root-and-parent/aql/test.aql +++ b/spec/regression/root-fields/tests/root-and-parent/aql/test.aql @@ -6,49 +6,42 @@ RETURN { RETURN { "name": v_root1.`name`, "children": ( + LET v_root2 = NOEVAL({ + "name": v_root1.`name` + }) FOR v_child1 - IN (IS_LIST(v_root1.`children`) ? v_root1.`children` : []) + IN v_root1.`children`[*] RETURN { "name": v_child1.`name`, - "children": ( - FOR v_grandchild1 - IN (IS_LIST(v_child1.`children`) ? v_child1.`children` : []) - RETURN { - "name": v_grandchild1.`name`, + "children": v_child1.`children`[* RETURN { + "name": CURRENT.`name`, + "parent": { + "name": v_child1.`name`, "parent": { - "name": v_child1.`name`, + "name": v_root1.`name` + }, + "children": v_child1.`children`[* RETURN { + "name": CURRENT.`name`, "parent": { - "name": v_root1.`name` - }, - "children": ( - FOR v_grandchild2 - IN (IS_LIST(v_child1.`children`) ? v_child1.`children` : []) - RETURN { - "name": v_grandchild2.`name`, - "parent": { - "name": v_child1.`name`, - "parent": { - "name": v_root1.`name` - } - } + "name": v_child1.`name`, + "parent": { + "name": v_root1.`name` } - ) - }, - "root": { - "name": v_root1.`name` - } + } + }] + }, + "root": { + "name": v_root1.`name` } - ), + }], "parent": { "name": v_root1.`name` }, - "root": { - "name": v_root1.`name` - } + "root": v_root2 } ) } ) } -// Peak memory usage: 655360 bytes +// Peak memory usage: 360448 bytes diff --git a/spec/regression/root-fields/tests/root-with-collect/aql/filter.aql b/spec/regression/root-fields/tests/root-with-collect/aql/filter.aql index 61a1cd28a..25296fc22 100644 --- a/spec/regression/root-fields/tests/root-with-collect/aql/filter.aql +++ b/spec/regression/root-fields/tests/root-with-collect/aql/filter.aql @@ -43,12 +43,13 @@ RETURN { "rootGrandchildren": ( FOR v_root2, v_edge1, v_path1 IN @var11..@var12 OUTBOUND v_root21 @@root2s_roots FILTER v_root2._key != null + LET v_root3 = NOEVAL({ + "name": v_root2.`name` + }) FOR v_item3 IN v_root2.`children`[*].`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var13)) == @var14) RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root2.`name` - } + "root": v_root3 }, sortValues: [ CURRENT.`name` @@ -61,9 +62,9 @@ RETURN { "count": FIRST( FOR v_item4 IN ( - FOR v_root3, v_edge2, v_path2 IN @var16..@var17 OUTBOUND v_root21 @@root2s_roots - FILTER v_root3._key != null - FOR v_item5 IN v_root3.`children`[*].`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var18)) == @var19)] + FOR v_root4, v_edge2, v_path2 IN @var16..@var17 OUTBOUND v_root21 @@root2s_roots + FILTER v_root4._key != null + FOR v_item5 IN v_root4.`children`[*].`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var18)) == @var19)] RETURN v_item5 ) COLLECT WITH COUNT INTO v_count3 @@ -71,14 +72,15 @@ RETURN { ) }, "rootExtensionGrandchildren": ( - FOR v_root4, v_edge3, v_path3 IN @var20..@var21 OUTBOUND v_root21 @@root2s_roots - FILTER v_root4._key != null - FOR v_item6 IN v_root4.`children`[*].`extension`.`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var22)) == @var23) RETURN { + FOR v_root5, v_edge3, v_path3 IN @var20..@var21 OUTBOUND v_root21 @@root2s_roots + FILTER v_root5._key != null + LET v_root6 = NOEVAL({ + "name": v_root5.`name` + }) + FOR v_item6 IN v_root5.`children`[*].`extension`.`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var22)) == @var23) RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root4.`name` - } + "root": v_root6 }, sortValues: [ CURRENT.`name` @@ -91,9 +93,9 @@ RETURN { "count": FIRST( FOR v_item7 IN ( - FOR v_root5, v_edge4, v_path4 IN @var25..@var26 OUTBOUND v_root21 @@root2s_roots - FILTER v_root5._key != null - FOR v_item8 IN v_root5.`children`[*].`extension`.`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var27)) == @var28)] + FOR v_root7, v_edge4, v_path4 IN @var25..@var26 OUTBOUND v_root21 @@root2s_roots + FILTER v_root7._key != null + FOR v_item8 IN v_root7.`children`[*].`extension`.`children`[*][** FILTER (RIGHT(CURRENT.`name`, LENGTH(@var27)) == @var28)] RETURN v_item8 ) COLLECT WITH COUNT INTO v_count4 diff --git a/spec/regression/root-fields/tests/root-with-collect/aql/order.aql b/spec/regression/root-fields/tests/root-with-collect/aql/order.aql index dfca0674e..451926558 100644 --- a/spec/regression/root-fields/tests/root-with-collect/aql/order.aql +++ b/spec/regression/root-fields/tests/root-with-collect/aql/order.aql @@ -12,60 +12,65 @@ RETURN { SORT (v_root1.`name`) RETURN { "grandchildren": ( + LET v_root2 = NOEVAL({ + "name": v_root1.`name` + }) FOR v_item1 IN v_root1.`children`[*].`children`[*][**] SORT (v_item1.`name`) RETURN { "name": v_item1.`name`, - "root": { - "name": v_root1.`name` - } + "root": v_root2 } ), "grandchildrenReverse": ( + LET v_root3 = NOEVAL({ + "name": v_root1.`name` + }) FOR v_item2 IN v_root1.`children`[*].`children`[*][**] SORT (v_item2.`name`) DESC RETURN { "name": v_item2.`name`, - "root": { - "name": v_root1.`name` - } + "root": v_root3 } ), "extensionGrandchildren": ( + LET v_root4 = NOEVAL({ + "name": v_root1.`name` + }) FOR v_item3 IN v_root1.`children`[*].`extension`.`children`[*][**] SORT (v_item3.`name`) RETURN { "name": v_item3.`name`, - "root": { - "name": v_root1.`name` - } + "root": v_root4 } ), "extensionGrandchildrenReverse": ( + LET v_root5 = NOEVAL({ + "name": v_root1.`name` + }) FOR v_item4 IN v_root1.`children`[*].`extension`.`children`[*][**] SORT (v_item4.`name`) DESC RETURN { "name": v_item4.`name`, - "root": { - "name": v_root1.`name` - } + "root": v_root5 } ) } ), "rootGrandchildren": ( - FOR v_root2, v_edge1, v_path1 IN @var1..@var2 OUTBOUND v_root21 @@root2s_roots - FILTER v_root2._key != null - FOR v_item5 IN v_root2.`children`[*].`children`[*][** RETURN { + FOR v_root6, v_edge1, v_path1 IN @var1..@var2 OUTBOUND v_root21 @@root2s_roots + FILTER v_root6._key != null + LET v_root7 = NOEVAL({ + "name": v_root6.`name` + }) + FOR v_item5 IN v_root6.`children`[*].`children`[*][** RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root2.`name` - } + "root": v_root7 }, sortValues: [ CURRENT.`name` @@ -75,14 +80,15 @@ RETURN { RETURN v_item5.value ), "rootGrandchildrenReverse": ( - FOR v_root3, v_edge2, v_path2 IN @var3..@var4 OUTBOUND v_root21 @@root2s_roots - FILTER v_root3._key != null - FOR v_item6 IN v_root3.`children`[*].`children`[*][** RETURN { + FOR v_root8, v_edge2, v_path2 IN @var3..@var4 OUTBOUND v_root21 @@root2s_roots + FILTER v_root8._key != null + LET v_root9 = NOEVAL({ + "name": v_root8.`name` + }) + FOR v_item6 IN v_root8.`children`[*].`children`[*][** RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root3.`name` - } + "root": v_root9 }, sortValues: [ CURRENT.`name` @@ -92,14 +98,15 @@ RETURN { RETURN v_item6.value ), "rootExtensionGrandchildren": ( - FOR v_root4, v_edge3, v_path3 IN @var5..@var6 OUTBOUND v_root21 @@root2s_roots - FILTER v_root4._key != null - FOR v_item7 IN v_root4.`children`[*].`extension`.`children`[*][** RETURN { + FOR v_root10, v_edge3, v_path3 IN @var5..@var6 OUTBOUND v_root21 @@root2s_roots + FILTER v_root10._key != null + LET v_root11 = NOEVAL({ + "name": v_root10.`name` + }) + FOR v_item7 IN v_root10.`children`[*].`extension`.`children`[*][** RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root4.`name` - } + "root": v_root11 }, sortValues: [ CURRENT.`name` @@ -109,14 +116,15 @@ RETURN { RETURN v_item7.value ), "rootExtensionGrandchildrenReverse": ( - FOR v_root5, v_edge4, v_path4 IN @var7..@var8 OUTBOUND v_root21 @@root2s_roots - FILTER v_root5._key != null - FOR v_item8 IN v_root5.`children`[*].`extension`.`children`[*][** RETURN { + FOR v_root12, v_edge4, v_path4 IN @var7..@var8 OUTBOUND v_root21 @@root2s_roots + FILTER v_root12._key != null + LET v_root13 = NOEVAL({ + "name": v_root12.`name` + }) + FOR v_item8 IN v_root12.`children`[*].`extension`.`children`[*][** RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root5.`name` - } + "root": v_root13 }, sortValues: [ CURRENT.`name` @@ -129,4 +137,4 @@ RETURN { ) } -// Peak memory usage: 1114112 bytes +// Peak memory usage: 622592 bytes diff --git a/spec/regression/root-fields/tests/root-with-collect/aql/q.aql b/spec/regression/root-fields/tests/root-with-collect/aql/q.aql index ab322d321..865909f13 100644 --- a/spec/regression/root-fields/tests/root-with-collect/aql/q.aql +++ b/spec/regression/root-fields/tests/root-with-collect/aql/q.aql @@ -26,12 +26,13 @@ RETURN { "rootGrandchildren": ( FOR v_root2, v_edge1, v_path1 IN @var1..@var2 OUTBOUND v_root21 @@root2s_roots FILTER v_root2._key != null + LET v_root3 = NOEVAL({ + "name": v_root2.`name` + }) FOR v_item1 IN v_root2.`children`[*].`children`[*][** RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root2.`name` - } + "root": v_root3 }, sortValues: [ CURRENT.`name` @@ -41,14 +42,15 @@ RETURN { RETURN v_item1.value ), "rootExtensionGrandchildren": ( - FOR v_root3, v_edge2, v_path2 IN @var3..@var4 OUTBOUND v_root21 @@root2s_roots - FILTER v_root3._key != null - FOR v_item2 IN v_root3.`children`[*].`extension`.`children`[*][** RETURN { + FOR v_root4, v_edge2, v_path2 IN @var3..@var4 OUTBOUND v_root21 @@root2s_roots + FILTER v_root4._key != null + LET v_root5 = NOEVAL({ + "name": v_root4.`name` + }) + FOR v_item2 IN v_root4.`children`[*].`extension`.`children`[*][** RETURN { value: { "name": CURRENT.`name`, - "root": { - "name": v_root3.`name` - } + "root": v_root5 }, sortValues: [ CURRENT.`name` @@ -61,4 +63,4 @@ RETURN { ) } -// Peak memory usage: 393216 bytes +// Peak memory usage: 425984 bytes diff --git a/spec/regression/traversal-performance/model/model.graphqls b/spec/regression/traversal-performance/model/model.graphqls index b4c047eba..6d57bd461 100644 --- a/spec/regression/traversal-performance/model/model.graphqls +++ b/spec/regression/traversal-performance/model/model.graphqls @@ -12,7 +12,20 @@ type Root @rootEntity { children: [Child] grandchildren: [Grandchild] @collect(path: "children.children") extensionGrandchildren: [ExtensionGrandchild] @collect(path: "children.extension.children") + + # 5 MB random string. Should not be queried because it's not stable + # it's just used to we see whether the reduce-extraction-to-projection optimization works payload: String + + # 100 KB predictable string. Can be queried. + predictablePayload: String + + # can be queried to make sure the reduce-extraction-to-projection optimization is not applied + fieldA: String + fieldB: String + fieldC: String + fieldD: String + fieldE: String } type Child @childEntity { diff --git a/spec/regression/traversal-performance/test-data.ts b/spec/regression/traversal-performance/test-data.ts index 69aad5881..5bce03226 100644 --- a/spec/regression/traversal-performance/test-data.ts +++ b/spec/regression/traversal-performance/test-data.ts @@ -18,6 +18,7 @@ export default async function init(context: InitTestDataContext) { createRoots: [...Array(10).keys()].map((rootIndex) => ({ key: `root${rootIndex}`, payload: generateRandomString(5_000_000), + predictablePayload: predictableRandomString, children: [...Array(10).keys()].map((childIndex) => ({ key: `child${rootIndex}_${childIndex}`, })), @@ -28,3 +29,7 @@ export default async function init(context: InitTestDataContext) { }, ); } + +// chosen by fair dice roll. +// guaranteed to be random. +const predictableRandomString = `4dcf8e0692a607eac1a57899572b31741387a715dace82cac4eb83748e1ed68058f927df649dcc7884961bd6d9d977922b70023fd57cf50bf2e9cae11f0e9639f74cbecbf0f487c954d989ba8d678f677e1ef775ae371f5a33ee5178385be8b35f01756abd685c97686261c13b7113f2bc6bc30195c390339a6978ecd9d4f3458f9e6c29d3d1f7e32a584e1c999e5e9167dd636177b53db216e4bdba486ccf86bea70496880c6d6c597e1136ef0a71e7d9288f29918afd4eea7b7bb2bdbc7b1af35199b8ece7f470807cd23eef40830de3feacd19bb20d6dc86fd428b5a385aba2d9067b95f1ae3337af20682e56933db9ba41385e1d4c35552627cee50288c75a5611b726c856ff22ca68d3eb342b563bec277162f5980226e5b46833c55b8fc8d89cb1394094bc74367287cd1eb68441284d4b9fa28c7a1316788fa7df04cb9dce281619c97debbfca0cb51b64ea54bf535c3283c6bb6193bbc73956c4374a63f358749e0ba7bae23599e52960cc8f2479542e1352a75f855bf14536093df3db61d4024b29c3eccf1e92fe5f22809fcfa55bed2f94ab15ff9e8038600e13741ead7e7bf0ecf437fd7aaad10e5545e34ec62f67ec17b38070a42b20c738ccf31ebefb54b5a5614f1dfd7b8843032bdb11ea1dc97cb2ed8ddd875e3f0c0ea575b56a77593e3a75facb3f8909c61aafa1f07ece5c34fbe357f9c2b32e09bd7b727e4cc524c5304060efb4f03ea95b479c1776a726a519c59f77e65c6e8e793f69530bd601919fe693ce178a712ca2f25a739fdc18c3cf9148a55b510e45ba1b75c838b9d341912465e07dd2a560702ffa75a1c8cbfa602db8c4a818618987cb6f712f08020c028c9ea955c152ebc70ce8f83af6f211b6a915560e7d1ea2124dd8a95ab67de2d0ceeeb1a3917293750211e99b973d9145ae9f18602be95029726986f72ff362d17447962bf85f0b0a036b60a74f60f50d2b0d1d018b1234e9df166e7d3fe010be5c718204dcda877da1e6e98b0bc20545699ce4998457753166fe7bfbf812018f93f6ba838feec3a153ca45e04ac0aee36fb59ee83394d80ba80a574b0c808dac322a79ed85c89aacc6df1f1fc7b87779eda22d0cace7c02ea3644ac239dbd0884747f23cb01d1d10f09c0f1119d2039a97967a484c3d705bca38e80ef390a96df0311507c42cd7f9067893f675e53047144be05b3f3fc585d8b1c99b4d083219469f12cbe92491a8e169755a64b171c00e3689d5b117d49fd1048812e1acc077cd50d595a85829d242e40143bd83a260190261ab70878593483bd3cf5d59e6dff5c39caaa53bb8008abdce0fd53e230f876b3a69efae7a4245e80ebe52a9b04e8a9900c7c56baaac9a0028af2365f0c41d8516793f5e81aa1cc96f9b6fe226ee2677d3df0e5141878c671718aa9fcbbc8d8a8c80ef0f84850bdcf5fcee5ed7ee0d238acb330eb22369d0c6c51dade2e645389123fb18c68e4f00ce5536838e8769eb7655e76b86d78be0284bc32b5dbff36415d33312e3262fe28a47ad27cf3e64d7054e8ac1cdd1bfbeee6cf82b1bdb8422c02cc6dd39a08d943a45d623057cd9472361689ad8a349a5948e24582ddbdbb96e9fe9b480080385140b50893aea94b76c9750adacabb15d00b26c3f2f0e37d99329b2b849094782b2e5ad5c04f928d36560033f8b9143af5eea839cbcb33e00e0ccbfa54daff28d297362e3c85182df2943f2eb95cc44da1fb15b9ebe0ea4ccca7f48286995aa85e6f349fab3e594c5266861e7695ac48820e0a32772cf22972e219e16d1fabdfddb3f9c19363b19bd06826c5a5269f740cb0cd4491cf65d3e38fb45de26df7b904b509be9d85a4e00bdf5ee9db626f19d2cfe41413b51552be794360df3dba17b84bed889d74131d55c5742fd21bcb1ee3697be15160eff9dfa04b63c4fdbcf7dd90ceedfa2a27f1aec7b6747874e4e030343192cf34fe7e6a191f98399d03a8d86082d8080a29a0730490322228088cb31e052db4f040c55fb6ca30024edf412c6672bf87135228dbe41cb65957e2e61150f7b93b56a0a3e00fc11296ce4bdb8b1150aefb5888d557266f515e41e93aee9660366ce91a390b42090da96c9c4fb1205c14423db51b5c0fabcd4def15b859e79e47a4ddac99e37ee8f3828ec232d2e73f0dbb9245a85de3d690871b8a838595fd594cf34808fb0969ce88782271a9f537b48fcb4d2e541a68309d5c9cd61158e34a296f44bb0f1a7db5f71baec67c81ecc85e4e6e6585fa93487d5f4f30538c2de07435201c6b65df5b9e2c4e5ba0e5c23971feb7fac26622e52874b49672d13a74477d3f19af61d438f308b585f97cce35e13abcae654fa23d7d23373154332cf252a17cc42e51a4945b7cc2072a0cf46f5bf23f790931515fad4d34a71d142fbdf2d964c7e255e1e64f96938d7b30c2217ecb5bd02f3a5279386a66abae3632820f0a2b41e1fe073b763589cfe135bcccd58d66acd7ec4b1c72aa4ac4d407b733a963452b0ec5260d9b5768f2357a643e17f535955040695d18ebca005ad606248cecc378c11fa635d5583586bcad7c6799e1df0cf33f963aabfa648398a7c864f36bf5cfb5f95ad3f649dfe625359d4721cd03127f3e27ca9bdac175e712fd0c232e3af5e1672719b8634f353fc91fee99ba5aa13b2858bd30b6678a37e91115df263e977f34ade7d107f257fd52594a030868903bb7f2b59b2b8d65ebf5e586f31b22fb734bded9766d9a961d07c4be53476ab20c3fcce40f76cc04224aa10dea7fa924ba254fb4c63f949f9812380764614d03b4aee717f78318f61862d7abd997515812629860454f1601e7a7750aea4ead43bc70c02f97e49ed9ba7b3facfcf2809ce0dbf9531289a2ee88084886835e8e897ce8e6c9a8e9975b39e868fdaf72c147ce7de6b58a894a489b9d1a5cc224fcf01592866e185de4b9054baa4d218ed679a2e6dc0fd9ba9d19d0b5fe4bc03ded9323949867775f70fbd5cbe817af785d8eac7873b7b1d0305a36ad6a534b3aca8ee9eb4ce937c19c20f4d4c778ea3e1eb2db2daed55f8df8474769f4fe1e1480e9a6ae438e153fa4927251b840ff989cfd29d49d2cf6d182f4ab492eb1f41d0123d34fbbad06de8c4afb072644101343dacb8b1fc19a326032777931a31effcac9f66f238f85a87e9af9ee1cb6e842b7b695d9fb264fd4cb96ca772f74d9bb9ae79c9b9fc0631e53c3d6b6140db8813d7723c6fc764733aa15a0e28666ae80d2a29d4cb2994dd79e760aa639480771a55f80a1c96b9e9d58e9c74a9f2b88cec9808e9ce2190adc31b055cd60f136b45e86329792e8294aa0ba323e97b03d08f38b91159961711f2872395aebde6f2dd176a41b24fb9c2c0953c1fdcca588d6bd2f68732f2e4a438c5fd0ef77d672defd32676e1951043ba507876676143f8fc1c3da2b0a985caca59cd5ee9eeb4bfd225e7228366b0a9267c204cc5a6e8118c031ef2696dc4c8fe513b3ad2c0b869f7d737dee3da393bc53fa90df8218489c4a68902b71a782df96724d848f5b3caeaa69e1e9bf4f988c2ee46129768611e70c8a9e4eaca5abd40b59e8d1ef215d800d7e2f4de3ba004a6e34c3bce64c63a83b83b2bc98986546452c1f3cb995772afdd22c441da3a4937b365e2c94b0ab1813c44f11a8fdf1e23c93412bb3e0fa5ac3efa07350f67f5f5cc608483201363b7b04c65a034b1c7ffb98ada1692f952dfcffd985f0a058f03d2085603656c004d270b70a39c2fe5f3ee133c81eb4cd6c1b1ddd5efcc40ca182575d02cc2d64c087ecac9302b3eaf5c9492279488da506c62a6c14f05551af3468536e15921747c80afa2c1845a89d89fe49ffc988a94954d02eaf281a651c6ae580233ef0e95697604519576ce4a95a5b64ebb682b80d4bfb59c674f679ae1812c0bd725f7d52dbfbf3667f55eb9f0d3975cdef3a200403d85078ea3fb3ce804f973b4fff32d60cb62b6ba30c4566436d93d1688b77221b12b94be1b857a8e4beb33029c854a8df1168afe1b4cb355e7875ed80e21a29fd8962f8db46aa86d7f2d2afb11cb64bb1739abe37a120abea91acbc2c7df61feda7a75637b880f544c26157f40c5f1be1acb3810a521b09e72aafde157ebb781c8cf00b0089493b676f9c9df65a2b2f1ea2385c9477f9dfe0aeca214b87ebf75ad583d77051421cfe6a9261282d26aec2bd68112e424b7b4b9d90df3a0030f6850387192a16d69484d4ab64ae40325e6e22a5405683b2dcec5cc6fec81712c267c73a882d55cad6218e9e2e5964d1c832328f0c7416120c0ee893def909051a2f18ee6e06e5117f36b8a39bb7d3ccac707de0fd8c63914f932a0f42506ae853425731baed4d794f235b10d0138ebcb25cbb90dcdd5c9785a10ac5e2f4f744ddbfb951878b1b1d8e18336ddb836405ea5e933c8ca8c46509427d9d3bdeb8a8b99f9a60ed5ae37f89346de14f9672dfa62ae2a41b9cc6ddc91b1881f0a70979cf6fa4c1a9059f7e2da42b543a79eb84d79118ab1518db68f412e810505bc147694798e65c92109d9fc3dd6fa7ccb9bd287f6dd5ebc3210f5bca1701284cf16d276ee6b4e01ae42752865e0c2174fba894b2cc8bd8cf74a8902b20d0674df9d32a841f4c9386eb400c64d19aab47354731ac568faaa79999061cafc2af8f6c5c80c7493889330d0003b91d5bc0b4a0a163af327d85dafc902c4b238419b5c42305e85499ebbfc31593c87fd7c6deefdc5b5e425784857d0a6bd3cda6d606c72c897471ca0e2410eaecb60d72236a9ad99538839d1a23d52ac558626316e2b71dcab2a93a6319aedb4e37ba0931c30cffa60141aec78ed8fff6d08125bab4fabd9f377f95263f84c8f1868296e0f99699073fb702bd7fe09dc6e552cb15acb513ccd0e9635efa8815e1f2a02d3de76efc9a553286d4e1735ba41eda59405a014e5723ae3877b360b1da6468c37e6559a82376d3a999479b6977c1d3b98b87129cda31e6b979a4f64626dac94d0461f825220c56170cbdf4c28d6134f21fc2e5884db28fca3e93882cbad14640ef8c31a0dba4e34cef205ffcf4b10c390133dca20ea8b86ef1e8d3b712f97b9e0d6fee79b1095885fccbb2fa5282703b148f63d97f1e9c9ec762b328bcc99884bf3647a209e1c979ca2a546eed63f9a32419530b6beebfaec1a09b133ad36bdd3003edba67f1b7e3298598f499402bfeee46bdccc8197f5b7c0dda27a319aba610b23ca7439e7da71024688b9a8433f71f3d14cbbe73e160e91b8a47f2f2e6a0c653af86ed5f4c5f160bc99f8b66d9feac5e9c1269ef6d2503eb94e8a793d930c8bc820874a1dd78217ef63e742a639efaaae5fc11f85a2c7d64632764122b9beb641304b625678644dafb5ea8a2b791dff2ab590c615170a690db95608fe306f4ef99c5c0f9d95bb6c89832ccc0ac3182873a447bdce9317902969ff2a8c896ceb5242d61b4b0485f764b86f94ba2cd9b10469d2ff362280b1942d4096bd13e48620bcc0a150e91c4bab64ca715ca2e881250d89b537cee642d2f520342ad81a3066987246c743d2a9d549a832a5f8a7f5906317a0f4f6029dcdc21a1bb48f96b40c40ad66e97a27d3b2a60933231d88fd36d82284a5d3cc6128458764f64e451af23456d15cef183b749f190ce71c8aa0802be6f0ff8818cd66f389229869cc2aa8381480c65a79dfc318b0bdd7d95f342e153ba1bdff3584bfba85739a2b432d7374ea5aca082a3184b39c5377b32ae9967f0ff41d59bc8821e029a54f37f894ac84472431f664ba341fff70662737f551b79412dd6a13d762caa81dd7d7d901db664cb0fe0dba2135312d50082d6bbfca13b2986ca267fc8f32134b58f60267e5441b827e3fa022eb076068ebdde0e36dd6b3f85826a8780fee2ea841227396aeb8be2491e52ce3ed9aedd71ce5991ed07ca83796343753ccf8d285da572468f97bebff4cfcf72423543d6bdcd23f934f82fe4ca1c6bf26105686b35fa3d6293d036b29404d18fe5e4c58a854e6598850bfa331d9b061fe2647cdb24d8a670acfa97397b5ceeda871b85d0ca179bfcb5ffdf524dbd08c19f05d303ece99e069bc465fedd4e2207c1273e2dfd10d1ffef2b307523c751480e8dd3560eded2ce0d631ee80ee15d6d74a3f3eb5c6f07fe8df9a9e003ef6b8011284245cf4d43f60c100cf4c79812767351348e4257b608fa11cdb5ccf6e2d4eb42b7328719eae29055568867dbd0f918876ce624c6147e9c8cfae3e3d3873c0084a0dae8553869b1eb4ee104b80332fb802889c84618edc1e83c1db5e8e654541c1754a187363be7fec74464589c8b3fa23a6342ca52433d0f0f3d7618362e3c29c543e6e92fab6d166deac88baf87da7032abcd2ac06f7d90b19e74e29c2ae8749a88f157326cf586ae52a98333eb0d1b47e1c929a506cee62157e6f1b6d56d97dd440561fffe25c2d585a59f195e3ed2a913c5a83a44e37f4c2d54c348e2499f9e836b91fdecd02415561d508919c379d27134fdfd71cac06d969152cc25078d10252e70def6ecc9d62e93f062d15ed20c6afc4fcad2327b14ea5bd1fab846cc8f317dfafb0926e3ed4e9595bc88b53acd5f7d564bd980e102f3767e8827b07dcb5e52fd639b97ba2c9a9a7c96c91c87c66f3572226421fd2f865cb6ab10414f9f76bc942c3f894c1792187e41a5472a82d005fab6377fff6226fe4ad08ce88a6b684ceed4b58f7b50b633ea7c70f4d2c14595314a39b3f69b0e2c4669391e1edd4cf27e05ed4ed1ce8f9b8e5cdd0a74da40c022b14e7a5b22129a0a056ab5655af451309d7d3914e15c66362efe694040e37eb8d4c24c75213eb87a2e221fdcef76d19374d2197b4ae279147ae358a8be68265dcb110ca49b0c50eeac50a230e202385169af9ae5c5b1e975e13e6a54e9873d838573ee9386f1c73a4d66ff7df1bdfa5c73cfed44f86f69127cfed22de91619dc4c5e6051ff399ec79d5e12ec5e6afff8c128cdcb936ea67319212d9f399bfe4d1e100f3f0a8f69c46dd0b69eb4f7ea0bab2e63b368629acccdde437ba5ff96c139bc9015a9627a4fa1686e59561d7e9581cef98fcc81a4552629dde76ad2cac657b3cf54c19413011395292afee564d398a2d080a552eed290263b8ba5bfbfe29007b96f881ad4dc5569595a6da5fec9bd0eea4972579f672ed8bd7ecd64771afeb49e526bb844553dae9ca0fbe6dba2f3c6ae7daabeb4d2d3b6885a217e24402d0c4571c2f9c9bb0cb17292a628d3633e59d453bcff228ce4a6613c78d76287b0b0622da00fe42498449285e1500086aa6ad70ae38c11d2a523b7bccb6b1ddd1a1153c35c5290c51c30007f6f50063ba6d927fcf6efae2eabe24cb297fbd6a632843ec2dfb84cb3c63ae1b4d9e6b50907e11929d2b207de4d0719fff598476859348d26bd8d38c6203f96e9f3ae2b9f09a34958456764d89f06673ead97544690907a49928621fe44fbd1b270d08a8a449eadd1d8eff4119d11a2d1d72626caac47d8f8a29593b38874dd8ad9b3e1e77e82092ce687b911d32f4193f8c0ae3809b6d5a861ba87f3e12e842a0481b7004b45ea85ec7b95e25f003a558e3142212c45bd7ee3e8c80818b1be698212ecdefc8b748a5847738bf1f21671d4cc221d8178f92ae8209d720d3e855da9df679902dbb453da533e5635c59bf5b17d9fdd22a9eac9be893eb740dcc0dca3e3aab3259411c22cbc586feee16722eb9fb45ac488b8901e14f99f6319a00c6a759fa4bdf47259328dab808be6d2e950a3c9a0e5154213e88cdab5e9810af2929d56fbb74d56f9a42c926e907ade37154c34a03aa3bc47836a3751838995f443973f59bfe0403fbb489bbc9faf2dbeddb9aefecda66ce72c7bfee511835b37804a505a043519664fe30ae91517f441f3216aaa738d9f4b2bd742f3c769ea2aed77df53cdb74dfd336163aac5d966b387da5b7882d51b089ce4fe4cd826118ca200e27e54c3dcfd2f2b057dc010cbea0de457caae5ee3f34ad6df987de16619c01bd2fa9cdc0ed683dc4d3beeacd8bc96d240ea27953d07d36e368de87d192da2a9d646c46ba41faa23a04c658525c7d3bfe1e16007fd73079809a51187ef033b17c48394e8372ce6dc64cdedcecb59de5f12ce5bebc5a55e76c81d30bd8a054b17e156e02d376451c3a6c4fdb79033150afbee91eb8b48dc85734cc85c86f0a4b0db3350f90ec8ccf87338973a1b02cd929115000e4472ea5829fc05566eac1de63d65224c30cdca04926e4ef3aaa70c530a964fdde4be429fa020ae26dcd22ab6962d96dd48b254865e0306c068b453c6dfef88cf63d99159b43fb894ba3a42afa4c7ab203868ff6d37eafce97ec6907f849f0ae7a73059aec6f634a0b81faac69525326bdb44d5c5cec3409ff08217e905c80e27f6d47c2efbd45f4f74af7801da83d81e53dfcdbb5e012b969f8ccbfc3981a6c2a2d45d33fc7a858bcb31222a08a907b1b99e98b8e7f45af80290b7d9c8e414d93f2c471922731106cbbf20e6b03364d3b5b9d8c841383b86912e2f2723bdc51cda749afbed0d5d32767e1ca7f728fc225ea4aa4c21892cf4d1407b3a919caaeb000af6c2e1696c4e112e35c27a075988e705f197344c719de0e0e9e522e7c84e42fc44a3e09ffa7f6730d118ebf1923511bcdb5825abd21e69bb385e30d24128c2272052523abef49ae9b6658af6b4d23af300d42fb3e4ce5b63d9b9fd5e21f8f0a03a2607ec00ddc29e65d979b51c1abaa952ebd825abc90856af10eee8c0010f81c91c68fcf1e4c3d8ace2814468dd7d7cde1a80599e85019ce8cdd66284fa15bd023cd80e30b04f0ad206554952e3430182c8162456a4933d38b8d8ba1e64d24be4e0f95a87631a8f2284dad6eee1b66da0374013af62d39d97057487073d2db568db8e14317efdf03735800599632a17f26cea6ef1dfedf5125b28bf9f125b47edb8ac72f5a30ef3ae661e7d898a45cc8900bef0c4a90ffd093eeec758295575121074c7395a21f790f9666c5a32db3ba3d1c5ac25c86ec6ce968481cbb8d7efc607b0a10b429e1c5c896cc0b9b9fd51df8db169ff283b1a7b5b9965c51032e0b855bae331a641d7f309fe6fd3700e07c972048e19a920f265dc77c04f6c9dc22e3c428ed9c876cde51be8df89c2ec793977759dc8c74ba6acca72fbdf06b289faf0bbffa42a5c623a7338ce18e8dbde12ed2eb9bdb45b10b23e3e47b4cc91429258d4e4df993558fb526c71b4072769eb6b30b91cc5e245c0f8af50223cc30ee449de38591963317b3c992f17b5c9905e24e05bf6800f269d7787cc34e912f9f995435a51e822abd83eac72f05eaec2fdc876a8dfe435cfe079a996bf468dd28cae8c49d0a83df82bde01759479ae551c8506eafb9cb99b66d3e9db75e4123fd648135adf13d8233153e24f8684094ee4cdf650d37e801fba7f062608c88fa59b7e5f8028c5855f6ce51cb23f936c5945c8593a53cdbecc8cea6dca14149f37767957fed4e08bf804c8bf480387bdcd1a859469f17ef8033c831dc59901a45cc5071e6347ec6e0813224c141737ee3ac94cda27824d96314101ac217880fdb4cf749f7f9481e7ba813d6ac8fdf460beb7b73d700ab3ea9aa45d679500462c8a4fbaf4240ae0bc3b1d7f732026efeb80b4b5263cf8e22e883a7545e7c9949f97666b4f0ae389a44a1d5a284455f676aacf56b9441fa5b3eb9a56ea28fb45bd30783a9b527f7b8e47caff6593cbe8c6b24b0fb3c485339f16706e2fa57567492af9fcd39b469eef82f632a0594717d4dcfd6967def7ef86c912ad0af92387fca36cda664036d820b028bb37a3e7a0f86aa2b33b8871485c003bde2274ddc9e762e7f767faa757318bd20dd03131fd6df8526e9e819f0ce6a5f6c16ee3a1833ccf3792915a8e92674a1eed499b20461d6143fdf0a0fdb1d3770dfcce98e34488b5d38a774d9f020cbebb7cb74f192944c0e095d9ea28f4590b7da8b5275a78178e8dd2cecd725235d5812dd02c55f9fa1bbdffcb9fddd84b86320ca4e454c42f751fe17a50a5b691c67fea43c1f95cd17e6ee0017f79a452265ef6b8dd38b45990d3c04409d28ad678fe4afa34c12414c767d73feec58497cec6de23b29eea0ce0992e5ef31428814a73322b4b5f113e0eff9b16bb2946c6b29d57427a668ab2e1d7a041f4759a9e5cc2e738d4d3cf23ccdf92bff2d8c0c71bdbee9e6b8efd5bff0da7a9a94e052d192b054be8023ca6786ce95aeca06a64c10095a9bbff0edac53c6843a74b5e1769550cac65a74e79a8203ad57e92b50659842b7a7965b1b17cb3cafa4128bda1a11463bbf5f63a311566711f77575fa0a3749eedad32066a54afed3152ec717c55d7595f6e6775ff70fc55ab623d3a3653bcfc3878f072601b4125b1299282886a6c0a2d74ad5587e0b86f92cc7c4e755c843d1c5719096c20dd4830afc554a4c15032577a72847245dcf02c92f2c9405100120cb8a13a24806c0fa04b54e45d55a048e9f5f6218e6a63c71e308949bbdef82079d26d18d5b1ccd30af888a977ad9695b5ddafc136ed752d53f3e85623d12ca017d6d1639e1551443408b703a9482ebf4c6daf02683e1acb3696780c3e6260ccc78f759cb0b4fa9591c6ed66760484f9909b7fbbcc4aa427133d678b199050a680deb95b7c031d5e23f617bd5b9993334d1f30a21d720a62c9bfac20e583f4a4ae965faee45df42eefe9dfa06cac54af76c2f78fd6d455d31f8790e73e3912a99eaf986dae602532a396688b7870954c220f6c18a0ece5640b7ec94f99399f6de1cb913849b58cd764ee703c21d3f1162a73ee7d25a98fd7fed9d7db616deab6bb957487c3d3c9fa3df182f333661ff79645a9224426b9246800ed3e91feff2a3a3c12109dcd14f274c20569317a857ab8cf3c1d98413106bea9c42897daabae5c8e0451658bec8bd40129cf6ec0f4dd6f0c9dff1a1286c6beedc841ad798190a7e99c0fcb2072e6e93eeee25922067a14127ac9da875b9f2e1a600dcfa4b1cc897127804abcab76318f02f27d34e23c866069ecaa0fac884bcca504fa873c02e952c7bb457d93103a415b305cf429a17fe3fce8b7933a082794c0d09386f3ec31d0d728cffd598b0beb8a8d07353de0154a39a5025ce2247d753816d6d29b1702b094511f747204292d80184fc6bd2035089f98080fa71ee82db62fe707ac475b981a0e021857ddf1d9e93a9990bd35aeddf43c4f89581d4d7514adef7fcbf2d16abd5ac2bcc06f886eca23d3f3a0154894dfc6579549908b388600742daa9b9775d3ac52a6ece7813efc05cbcf3de22221a4ce558261b104089047620f5a2b1844110d2d5fc3a0ebcd0afa1aabe3e8413ced9307541150ab427448454c873a03a076d716e24a896349b7d45d828511f19798b0222c5a04ae562339da6ca0a04d836eeef8ee62ebfdc42413ca90f4c6b09907dc6451da5504a001a0244bb3a1488c3a92e5ceae11d29a00dcfd29de8d3271a32807d9840f6a6dd19998c8829ffd82227478468b7a77f46419d1bcd4eed27971be9064f2bb41ff4c9ae5772fc6289fb6efd8c99baeeaba9c1830e235d1d87efd7304d971c96ae281e8052aa084c8420cd392b5786a05fcf638cbe588f1a7b275b9587b0b9cfc1513793ca7f78866710c2d2fae99c9aca8e1389dd0b2f96dc35ab940a2900f3648c104dddad31482ba6b8e1dba874a36d12a2d1c14077663505abd69933778bc43a9adef8d79df79225cf715c7405e5bcd6e43d7aebb282ca0f9eebe209510572c3e18e1fe7aaddaf3b5237e9d69b3fd8d4276858422b4bb189d6e1418ee53e19e658acc1b227ef99348059e013ce66097fbddb1db80931ef6e8374d5b4ce21742891fd02a067a9a60bd4bbeecf772b8484c3dc54b9a36419cbd72bb9d601951640aac1c6f6304467a49c2212d1bcdd8437b527526e72a08036cc7fffc2aeebd4dbb93cd680ddf3030d20d87298f4e7a66457f687af67bfb1f3eb04485b990b014c5a0d3a6dc649e21cdc997356c9f58412943f41c0d71307ff2790e6042be2097550f68256cc4711f19a13cc20ea6f994b0c7960628b762ab9314dea825045308a2adc167498168bc2961d39a43582c09535c6aedf9b2ff3bff93782611c71db7ab6b06ead99636410ceab8d9e8d02aa3c8de5924beb8273192615ea8c8d81f71e0ea3f352cbc18e8ceb143a1ec0d93859d45a6ec36482c4a6713bc73eb9451ba56bfd41b7be2c1fda95aea8a74e1416e9d50d5ee246a77003adf9e1cc20f06f69caf5ab3e52424f94d3c99026d158a6f44dbd0b6d216457752c4ae4b4673d7e515fce8f21c0359a125895ffda9519da74142c7c7dc3df78b650259be9d8ad1708cdab6ecc671cc0697b7a6fa003bd8fc12c0dc2937c6efc965d6518643df84f311cfc55044ca8766d0175002800139ce35b240abe1098848603bfc114025348544c57f53d401406f9c794446b750a2eb1497a5e3a12b2c4691b942a7342dffaa69cba57173bd49788634151295609607909d5c2100dc6f856d73c40dd2da0069272e2c7819dfd22f02d9b404f9e8fb80ddedaa29c0377ca003d30c816113980722f70728aa41ad9f78f21ed5bb6af8911575887a842e085dc2991beaadc1b97a993f0eceff212fa7c37ca2ad5f03cbc22393e82a70cdf5c7fc03ba9f77810ec0c519c07b77413f0a94d2e573b20ce1d39639ff4bf11490ad96715d2f0c7a372f1728ee82836bc638f26737aaaeb2a28029914e4ac1629f4f495878ff8b0c9688a2975d1efdd545d0e7ce11d9d4a6e28844941e9d81cfc3febf7c9b03b8790587fe7de8576264d0c310e5a4216da9bb5df9ad5db55dcd13b0b9102a0148fccc78dfd3d184f1967a99fe24097826882e85be18452c7dcab545731a3e5612d9df1bf6934faad774e307b09ecae6c885dcbb7f3f2cfe735c4dc4cde619c5c93c36fd7d49a7aee96c63513285a792164ec430f90df5fe18f4eb18b8c057076d1c3aff90ccc60aa00aafbf2fe355f014436e3321309673489f1427a9ee608f60f01a8b6cd063985c1de0af07b9988a0c6663667994dff7dc2f00aef81c435abdb3396d20e3483c4c330ea24ccaae008ff3e3048f67962d59b3732d7a28314b9928a9a8c50e3dddfe965ac5ee6c52f1dc8eff1e63c39c3aaf43f9d452fc09d36c1f00abb63bf58da4a64962d85401f495986f931bcced19905fe582704a9c771fcbf2c8b6664e600b251b0efa929c037ce07bd9ceef23e8e89d892b5a943f5a0b47db14bbcd89e5d155ebc819d7c03833c55331ba3d138346d109a2c9161e84e20f2e0524f41885cae243c6693430bbbb54211cb252eaa775e45b928b12340018e0b43d19fbbe9889ff2e461e8fc92089b805671a9524dcea3dab86263f50646e6eb64650404796c08589275103d0f13d376d97402380c6caafff948086abe6d2c7958bebabb6eced6f322d3a8fe3d0e1badbbfa98aef94690c2d268e00322c4dd20afc11b83b4af6f045dfddd86b71773def47430fd475142efc60172f95770f3690be1bc0f04672a5d221d41defe271dc5e1007dd46d06103a3705a5695209e36c838ecdec61f3a920e28ae6c73a46098a4945deb19184f433579b8843fe7a73c10d53746c7090601d0ecb4950816f70de1c40ccf5083875a2662decef156a40d2e5e4a4010acade4ba2d8cdb97d575fe80e0d9c393b3ab661fc342514fca0f0d1a57dbcef1206c09f8ce9e823eff3e3678969420623707c72e16591c142ba79141539a8df3b92076c83f2bc0fbb115e46712a9bd9833ca0d01e4320037fd4db13f57f0cbb8a381dfc6d08cba7ccdfb0a83114d93f9ac223dbbcf9914aa84e7461be90c7b2d537373bebf9d8975509591f907620fc1e93b0a1e5b6756880d51eb8fa407c1d2e55a25bfd3f69deb2ca95225cbbf8d34b0f430d9e6bb8c4af3a59ad0ea351f1be826dd252d7900fc6348bc42820e1ff60e3947d27833cc39ca8b1ab153bfe6af661cc5d013957451ed6d9e01bcf8c2eb1d671931e0c7590d22892ddea8f0a24afbd165b1495bd7a37bec7765fb72511b60623443a2a03f4d0a3430ca2c99c7108276c6133b00bf9d000e75060bfd35bcbe34e95a539789b34a458299bb7c58c59a649cdb49b4e7f86a153c44c17d07830761f759777a9fb8ee6ef6724e3e99846cdd86b13ab49c7726f85bcfca4d18d3b0ca46e2bbcee198ae903d8b5e73ccf88bebd0c3507a772f6cb9bfdbf95aa2735890a4f4fb3930a4a81fdb791d50e6a7a3c3a595cee78276cb3a360f13f51596b78832976c6b5cf449cbe875f71ecabef807cc6a6a3cedf91ef069f2387ed4fd042d0367d516f40a5bff343cf52dadb400036cda487cf2ba35746c0f47770128138a8444d3cbd0b949339822ebe900a78e84fd98d2b17f7a92ff1491e075393292d93d985ddbc1a54dcbe60b6dd812768c50f0ad2fc059c133b522719712518a45bb7b40e43e76bb16a29b1fee03a4fe1c9645b2ed9503e95453d977a6168f07e7849477be101d127cb261d5b2248340db846aaa51afc23c78e53cb9a9100e9bf8e3904c8d5826ba1524f4549838666432262cefcb1f8714a57620c103ac40329973cb95c44802b22a539921ab8c423af3781bce043bfe62c78834631d1cefcc808d01409bfde1f1229ef04e6bd498f06a2b8b6451dc5e34412e101278810864462b7edda068ab79d0b119c30fed017796746c6c42304936739b84eb1888bd674b7c1ce2990dfd8d6c81520eed3e7f73cfb8558b74affc945e64891811270881ebf0a5cedf312b6352ac6e8986e45c525be47240604df41320348481d1e5b9ced433de1f4623f4a8ee0c3b49ee7bdd5f314fbbd413f2b9e2d94ff4f174202a8391304aed8e667a36c8933a2eaa6f57bdcfc4efe1c094478056bea8b7668a8c0a7aabaadd045c3d22f7bff7018fce8c8541091dd159f0b766a4daaf0f46d07497d1ab18eda69eebe85a2fb94418adef946029d3ad9ee6a687c41a396bf757f2febe262cecf7d9f39d873f361f1fdb94c59d701adfa1e8602cc76242e779dfb5c96851bcc9c9480683c2ee5550519d79e4385422f48b5589be6774a29748d9bb92ab05a819d117a58c2dada8d94ae2390587a037f6334c572323771eb1d43892de1e3da2fd6329fd15e22e2e05ae7a0b49052bded8370409ab88806a875a38bfda55d84d254c1d9e4f297586e6b7e6d9e0f35db4c0c0ce8ad5bbea3c18c0948717e69365091125dec3fb1260c1a23cf921e5cfc8125171f54be1ce27bb6faa4e935fd72561a7ceb9be3f5b243cd0b866c5ab5e9988e7d357ccf9d9949a0b6229d340c0c5783d07d8f5c905920620f64afc05e15397f30509aad0b91a71e4bf54b3b5951575e70baee3c046f2e770e18b7f9e94877b7dee96ff766a0057ff3e3079410cd6a755701680a6af885d2d0af04c24c6292c926b29719a499e486aff8779bb899bd62b28f5355ece17ce27962be7533fbdd16baa81401ad132a729e02c5d1365a2642022a0b1b5c9e73934a18fe998d646886c85bc5c2004beb2399d1bfbb2bc51c7350b9b8042555efb6e08ab37af0997eb7e80d31b0e5be27f5e3af2f363b7df0ad3f6667e49f0c18d21636d6050e86d049dbac3bf0f13a5f6d7bff544d8754669d084df3034c2b4bdd3a239f920e97340cde944a52e9cdf03c55fa318fc016dce68b5064f179b05b05b3cda9566eb303886a2c5f9aacc67a39ef9c02cee76656946cd099e905f2addd9d59cb16cbd6510a5873bd6ecc6aff7984c60ef7d987aba467d39ffeefbc5ca4cc2bf6e82a508174fac5a16c27a45556d02bed99f108c1f382a19c3c114647b239319fc6ccefea0d3c5025cc654c3e19d9f87cd3fda7495e90687c7475f2cebbc294348499d4ddec668acab0cd1889563b2fbea86a9b72ab84cd73a2a9b40f8e926f4b5a23af92a06317c827e99bb08b2d77208295fa3320063e8db8f9d6f1705feeb71db653aabd75f8d34bf041a759d26fb3515a0963bea9bcb8b52d50b6273d64f4da2bf896bc1eaebbb9246ed9b3aabd25043dd743278e7ecf1efbabfc879f5f83909f8a7be12e1c2bb9e00dcaa9577eb1ec9c7d0d1c967913d975b41d544e05a9602b77290c146756095a54bad923d15359d34815d990500b70d529bdfd1af8fd05aa49793a4dfb9086d62067d5fcd5b9bb10357a1b808e5d6a7f6abd8cadac7a2ca1225abb7a792765696b91af7d3c06899432a8f5771ea1ad6e5b350914bc04fede83b15d3e85f6f79ef977fc89ed211efc931dba5263a1f944a3d8c8110d2b4073a0684a481f52a0ab1638a6a8a0fa5f2026f0dfd5b40ca7528a689576f3a55b71b31c0e5a091fa3a3d0a93465c9bc6d85794ee8ebfc901c159473fff0f3c7fe9d013a1020ced2e1c435aab7d79edb20c44c22f1059e6efc12d920a77e3e2b10da8f002eee5fd51fc63b1dae2de191008496d0b1a067bb3950c1e3c9a51720d49df4ff2d9e414b78828ebbfc9b52cddfcf9d8f8055ced05d155358d3eaa938bd594cd0c6eb6d2213ed8cd17371625bf596a32ed6772c2ce3e7dd6a2ca03810b95a5010529ae5572a4723efd1841a34c3a8f795f50ffc47e4e5623a551c1bc305a38b7d6e4c347b2178015dbedf41960130e1d4f541adb543eca13daed845e2a36002edfcac3474f77eb89964ba6eeef864f3ae0a4eb9811a38f3649ed54c2b1b0d9af9ea70bb8137e1846001280dd3a9425655e06760176d152d8b00baba85852b76bf6cb67387befa9109094c539d9d7653d4116b9948d049b26b690bf071a403377e9626f773ee9796273dc72d9acf0a4701b2330ca6d5bc55ad9ac98db480702a20ba2c6a5b29e87aafebc78674251b5d0a6fc15138550a2e23ad3757b9b3cfb3d0db82270a9769ae138e3961e9444b63013e9faf6600c874646cdb3d5ca8d130e2ee45e18fc39109c3b374d6ff69dcf7fae4abd206aa9757ad70bf40c2d6207bbc0417be9a97f81fadf200a888ba65bbf124b81050e1c34d05b10c3952ee6bb44d9e4d3a03a7798f6699788fd6698e4d7cfa6f7261a865e2778368d3ab615f4142291b91d089ac41e9ecb7693059a5a752aaac45d4bfd73f8c364a4e1b3fea5c36046f71c062ce929aaf84a8b2aa57c64af4ff46af7db7590356b12ada95dddb02443c6a13b8f06cd7f636d91c61dc53ca633dfd048dbc75bb775d9b4ab7ca69116950ddcd74813a0e91ceb20bb3946531c5e8d7d7dbed7c06d186841ef025c3f76cb1f89b61ab20d8e0800a659fb1f3ff833c12f9a5fb6c12d4d2a7237d47bff5fad456f7ab81189ead6be1fc70de8ad64a0b35b2b70bfa911143de3fad9bafdfc3fb22433abf19aa0603b08a8c478e13b70c943dcd0988dc38fb9bb60f5204e882dbd4da086f02f76645cc132acf433bb634d1af77b53329390d854a04935ecc0ff939037fa976b6197e963042093a95b1b8e1b93c1b654201f21fdcfac8a36fc6950b42193dc34874ed23104a5a08dafcc66865f7d4330b712c69be9a92f0addda01a8bfef527820552845115c8ff23330eed2875163ec0abfd365ebb85800bff030189378b5ad7632dfc65c971171c3f38fe1b68dac3f57d6246cb2091b4939ef6652dd3819e60b838997976e3eb59b491c376b8d525137f0a44f46f746d357fc7822298419ee9f10e085d4757b1249873251ad82a3464e41b3be65b215798ec460c3266b0addb76525e5926db6545f6c763173879e3f70f6b7c62f1125a10d672af5ba36403a8fb10c216334bf6fcaf5c859f82daa914b03fa01f327db0c1f3bcd9c53234ebf2c704acf7336cb1071911f32f0dc7338078a9746e70c794802870ee42c5a1ddec5b29ad8bf99f6016830627c1cb479de7b252abfdc264bc1511955b5d2c967467fd4c75011037a3a36c29dbc63675cc1b7a858f0662711a6924e4d7406adf27222b8bedbad042bdddb1df349fd3160da3a00b70015ecb058ec6b1fdcef0cb83d757d7c93c66ce1c64b2276f087f654934a366cf9c87beada538953428485f563169d159a77de0721e0116d67ae5372db0894b64bf0b44e650e2a6f51ef8325db0f06c3db0a84e0c540db5b481980313a47c1132858c9ae77a2ce74787d584afd16262e075dd0e326cc2b48e46fe239a70f9a72ee8cb9f0c346dc6ad0f876b366a0a99c6e2142e572cb6401b6a4b9d6f4864dd06117ca7ef9bc628adca655d05c80c431934233b6857dc6e2d8139c3233397e118e204a00919618c58f3a8a976ffc527a1c8a8b5247771f69d9e5b37cdaa3fe5f93572c0aea54b8fa01f1711b645af0b4cd89d9db5b315164cffa2d1aa6baccee201415647e91c3687b77eebd79f71ff932fe775e811db98ad0222c93c480636e460a16d6dc3ddff607a19a08aee1299b9b2bad1b6b640cf80f4736fc373ec1987db095f7f582912604588f0d33670fc62d2a2d5556ddd332a489f7e970c16f12cc540ee1ab98f8485ed9f0025f080c2c81fd50fadd0857c2211f2f485f8ba8abe0701e2a19ae3c530b4b5a5cd6559ed2a21dff5145dcf1871bcf8a8fd0b76305788f05230891154f17e54358646b1c4b2013357c342f919417ac8931a6afdf3097778ecbcccfcb222414c98f13d1aa59b297ee85400b9a7c596459a6bb2e30c42e265eda3221542c37026e511052b61c6e2366d8dbfddca9950582907e322f9439954928290c587b6b04e9148432748fec0fb0879fbcbf0b00c3995038a5247cb87aabaf2d05eca4fd07d322bda2bbd0de617a8dc280293182a21bdfd2cd574959d548384d2ee06de48e77d7bcb69631b25962ca90907926e336db8cade34c12585caef3005305714659947a3056abe178d0350ce62c6f484a6b35c724c87276ad46006cc397850faeb12187667fe82280d03ff1be83d2704e2527fe0af28da932743c13105da33a9966477c444504e9ec3ffa5a329604510662bdac85127e08bc871ea3a683ac7743d04d33c8c796ee9926c5470198854532b9a0cd3e245df0848c4fa4f1be0325806a19c71d524db9f0ca8d4fe2aab99d2e7abf2a6f44ea2b4b42e55273bce305bd9b2ce92747ff18f4d2ded83f382e51d5571ebfc103dd63cb902ce8e8e5f419de65cdebcc58f3dec7485f01d114ab928a8bd3779f9e55c1c1ce1c4e77ff38c271834874afb7278b6483bbbf90fb672bd66a7a5467c171cac3c1065f19bf634661e63f2a077dee45ace04220b0e4e6d95e816e8e6138bcbb6065a348c35611ed153c00ea7bedd9c35981b750070bd1624d6001da25a851dec89ba87325450202c985d13a3320c6c097e5fbb5a25a7355bbe5a7f6dfaa4a9714091c6631639aa6eab6d65b602206a6b57944cc46de2d2635db81174a61b98dd01bda5e1a943665f5acd0edc31ed129cbe9b6a72e47cf99ec66d5a9d45c7278f91670256c8e4252cc2bd70d31952424819b61d2742265d051bc3d71adc1daf3f29b8d5fc4644a564a22b163612791cddc60688bd723f19ff61da8d8bd9df8d5ec6a112e65d39f5fa92124817cd5d31c86a272ff6de5f71521da0d58325e56eea533fc7535a0584867fb2d648131abbd275a973b6bf546b0faa4c151c71cb9c60e73b93bc20b79ce9770f203e514924d760a0026acb7a5284c7df1e47b6e7314d623826d5433bd894f6d1c62f8222a93a200768d2d72013cb121309f8e128bd5282aa6d643c93c4ca0ec3d03d0da94d0f5b8366c2650ddd1fbe199b5d161c45f7db71a9081e1d316f891f8d1962d7ea2ee892ec9d51078f4e7ca093b2496afc07ad79ea9758ed563ebc399d9773b7552e0defada519f1e837cc70cc51fdf129e503c224d5146712d4826d5cc6fc960c3160090d741c68e05b0ace4daccc876db010964016f24254ba239e298bd11c3f45a6ce4ca9e16ef1114c07379311f6278481eed7d6b5de70951575252946ff2e5737d7e341a3eadaf8148f30fda15346eac3debd19e3c21ef3bdd2f992233a6eac449bdc27ca2a4abcee3e870b15ce015f5bae6eceeeb157d8658d2a64800145629962f34cc530538613cfd6032d5d6c7ec0e6d5d38545407d1b4f7b46653bdfdef0e0060ac8b383675e7a33ffeb77546ea0b842d90ffcaad16036a09b5c94d341991b4a9b42d06c829ad52099f759b19b256c237b8644794e373a74f3600cc02dd343c2a65488a1c5a02564a9cc17c1d03cc0f2cb33e146e1e49ac2b5c385275bd31f8aa5a0ecb2a1304776359de920f5641c131dfcd3d9fd498dd47e8c960f4114bab3bbd5d6ca6433fa91d6fb49a532c047587847adfc380e19030a2fb8f8d2d981cb1584d9cbf0db99f3a17dbb5a7ec26aa6da369491b0a3e4ac853e3fe9538536448057d83d7eeeb485417140f76473d78778dbfa2e5d31af42dc4bf765dc65902724c4a7d6f2d6a6659cf6b8335d838008aa20aa28047c01652842e0d3142c303f993c23ebeca7090f4fb263891023a4f81c1c9bd7724849679db44837e8d2e65fafabbffa0e9b0768d0433edef798baeac99221a420abfba5917b910154658edbd9e5e231d3e48be2af51d0630850b0287b9d2142eb11316a6973299680b13fbc9bedf138c1486223ad7bcecd714ecd14b273887ff6fe7f5890863ac13118b29c51c611a16b6f17c0e966726ddc82bd5381cbedc1bb0b834f9de9997466cced3f3f0b8950dba93ed8f59387d2b16560c2d8e163decfcdfab82e622ffdac1b8e16cd7315b585f9bc60cdf23fc5ccd3fe1d22bdb274c94fd1347a83db340c7b58a70c451abf0821dc243c9829b07c61cec01f3a998387472faf91bdc47032775ca22fc8bc5b916f4acb0b32974a1ab6276cc5c155d6657ec32983e36504e1a8a179a395212a949407f5d5f6055a9ac3b906f397a59118f00e0a93770f0308d872bc0803f7178c7662da9cfe65f6d9c986a3dc1e10f2dc69a203077644c63d80310f099147f363d9c4423166a6b927b2a1fa14dc0f53e19a933b98e4f1a563225ff608cc7fbdbc5d45b203079f77aaa9559fae191b18a985801c7fae62107c5433182cf3c146410b50e1c249f6623aac5a13a08ea7816ef0bb6a01878ff87c6c8aa34a5cdb8745ca7d42d8c261c6c2632a7ad49b9b4123b741148c3c75f9040789e8103e741cb5eadaefd21545070a10e2ab1ffe1be32da0ff3dc6638a3b3588eaf8a6412ca13e0cbd41de7ab2a22489f1a7d9327cfc2333fd671d9dfff9cbd3c91788f2bfff871c030de5d6e0cc4da50396a7533da4b6dfe53ed4b6883586f00e213d38945583511370af6c4780a01d47f80d94b8e145e8c4d608b7e795f13c695140463d6c8215db7c550aca7e2c5f74137004a3304e9f6b1e2dd306fb335739e0d386f03ceaebdaf57994d7eca5541ffef3df37fd546803cfd2ed537f6c7674cc70aefd9dfc1fbf358b13a8566c71922de77cad884755b579de5ce2c2ce5baee7ea3077a3eb1040ad605a472fd8a6e88d63a391f3ee4b0ab719f9b5b207837dff60585c30aa0d82f92bfe2b8eb2db5cafe0b04ae44703cc7c4ea79793c26ae409ebf190b51d73b546e122566eba365c64ae2e2244de00e1028dcfd9f2786b06fe9d8a59b9defaed99f41a3b0279dd3a5e18071c73c4ac8ffda57514d58407c590e20405766c919303d1ed2405e1f04ee77ee0901ca64d22aa826a458d4cd2ae817a14d6e1eded76dddebbbb9281b232a20ee8307de14b0d6198d6d515fa9afc0106b79956f955607fd2f4890648e75c13df1d184978ae12e9debbe1393157a879a58c4a932eb3db77f3753ec6bfaceb2b724c48954b1128f5e232c651e7660a50f395b06f55c6313d40cb0b4e9a09394fdf8180a60eef21de43fe854d092b34580682b956c969c1e24d01d925458f6e65ed9dc4104d7f5afa31efdef92b5afeddd397a219e28001d741aed9affb50324204878e81f92d6b37c7318c0d3e0852ae1fb959af8b054134b6786d0413ec758a3e3fb296136ff19a0598de3332d222f94ee32e51d27eb081ad4027a61694a7e93484e3dfcc8bc9bd4c715708aaddcf8615d165b496f1bd082fc59e0d19885c1666eda82e4b7303413a644fb2bb6c7d9b0d744695aae2a1eff7bd715578fa8329b3d9ab69f8ac4ce5831eaa11127c45b6fc0f2e24570d45383fd3171522c276f475dba1b2617cf90e197151036cdfa0a875296ec4cbeba4d92c4c2251f33697d2f5946577131d6c8eff04f68e1074ee305ad1877e533ccfb6fff05f4fa961265a932d370c4a00968de1dbbeb24c2b459f1480bf29205ac1a490a27cf59525bfbd5fb43eb79867d30705455447b76458d3a0bbebe918e65e207a27fb6c9f25ec6b41c8ee0c4b179ed3d36c46e51aa92b3566c10e3a4c33f3b85926e926f839ff89cc238f7774bb157bf52b692118881389dae365f8021f6ba431532fc441bc832a2f4ab5d3109423d9002b7939c9e86e259dfbafbeb4355155991d957e313f64f79dd35a564ec2420816521791a8cd74280a5d2a6474c47c9d41a0cd4825a3b3e2ed21a277133200729a4f9879eeae5b74d27fb9d25d0c466b34c38bcc14e58256b8d60153ce6861191bd892bfccffb10f21bdc701bb64d3394030eedc3db92a07ebc56fc0bdc139a89367a69bce358b3050265a4cec844e1002addb14fab7ba5e4314bf0815e99ff0745b04f57a016575b47941b286c89ac8a5a023a96e0da88a693900536dc304b84b34a5dca8f9367d9eba4e797d69175083c5cb56156f19d5d1060f81c3ff61010585d643a3602a8bc2e975da03e53d7d13a15c81e7814fa9a4e9c1236a389f3cf89c3d6c32b37d0db574551603557ab32932ea114357ddce9963d78c83b94117ef3f64561975be2b54ace57622e6160cae1c46ac8095c1efc91bc035bc73cb7887c7f858937d4b10392a747991eedfeb71be8d1767e19f82fcfb32ac1540a24d704be4917741211409ae5c3fea8ad4c5c048d971babc6c6c0231bd707c84e779de85cebe7b97d55607118e8e764c8cacc26300cad784df2a57915f4ab9987253b8759fe7f1672f205bb67838391f0bf094c0a58c50cda23fdd2c5d4067ed23296c6f59bb7e101850e41132a990889e9d9b8e9eebf6f7f089710a6daba5af1e0ecc18a35583ba0a75834738f2f38f23f79464760965282d35925c526293550765be90d6855a70c4744f34293071bf291055984ff8ccb6da4ca19e853692fd4e370c6ecd998e34916f8b158a8c7a579cea0b74b33e774d5f937e0040eec608db910232986c0ea42dab2706d35f2d11716765a42c9f1d1418b85b096aa4a139524c43b194d220125870ea7ba03c455c36f9648bcbbbd93ffff6352c5bf4f64f892c841337b96b54266ea539a2ace79932529259b678389d64096a7a77196054065c4ba3db3223ee8b798f813a4120d7e9610705526ce79a07e77060f3277b58b3d923e4f647733db8bdebe1ff9e2cc7b003bf7939e7151a136167242a223248eb8a6f9e1a623fd40c426402ee069d84ba6eeb060c900a6d146475a0568f37eff6d7e350798da28b359e8a370a79a7c93bf1b7a4c0ac28056bc0c3bc90c67ef918be71b49f98424acf193ccfd34cd882b4acc554fdc89c39f3bd1deb25ba7c32822a9ae5ff70d220a4cdbe3866071c691ec5f7dfddf9c5871bc5bd6410a31e227ba12dd84b17a2b16f7610846b783097ecc005e03ec62c6516239e02e6da6d210618a3a48eadc042f2ffe0579145679651ef370b96d500a95663d57c8e456c6bb49243f5d70d93edb3531a5cfe770f9ff93fbf6e41ff595532969d266b8eee251ad6a3f5998e5821756152ab4361856f4c79dee4838d0c5722185efc21d5cf6828a89c339af41bcaa26d9d3d0c136f7d89edd8e0a17bc3899d83e5ebc35a9bc7bd22f0fd7e24ea3893bc15bf67e4ebe71c791d2af72b44892cfef68a2febe21c69fa5b2eef41bd1a9e549998053d95baf1ef34464ad3b6f31a604f4d64279f509398246b76863100e53ef274f95ac2ea8dc530375f625decac37a39ba7095bdd2715f21cbeb74110e16f52dacfc440d098938b7458196363b992ce99faebcfd80756995c21d37fe06fbb198dde867b678ffb19428e8b3b974fa0cf20d433ec537c8b5f4ed7cdaf77e4ff2dfa9571df6c969809b7796a6ae4fae954da2f01c91135e62876f49370c70aacc3cbaae44f9bbfbca9a3f4102f41a328822c2d1acedfca7936f87b2af1a0533a9b7bc77bd955edb0b7aa9c7da46db5ae0379f4a83b5edc0e728d6e7068aaf332ca5de62ab95b1841326e1de6690570dc0681ad7610cc532468ae3d81092bf1cf6c9c8d33a82ff074e04ef1f41374a47ba23e937e7534f7410b875c53789d86df520e4d64667a59067d31bc71955cdd56a3c646eca8c99f9bb5bfd2633bdbd6fa90ddae3787bb5eed6d4c12bd7951624d743eb708d1129bf1a69a6f26216f4e35670f834615bc88b68a2b74a2a6c5148ede4a12a5f331c72707a55af23e61ab28773d7882985314d6a6fc65065fb9c142bf66bad9955344e5e96387b4ecdecb9cd99507f9b791051893b5af9cdf97c64f1978de315102a8a39ad1bd4a3a9cde949f63a2cbea93e2b236a4d6073be34de042790721a77079378f3fb7fe2adb20fd31ec9d14c0b8ad22b05ea7175a7d43a6a33391902c71f6997a8ae22cd1bdf664c92b035c2447d2ff16e4e533fdc33d110194202b40232419c6a5518524d6d4adabf3054676a919a5692291804a02b266eecd3e263e1b477f3e66d8fe4a88b0eee98151dcc800e98b40ffb1d301c4c9d1ffa1a5bb144acf22f0dc932021955d8efbf8b222c63f01e0548b7d25aefeabb217303918837538204ad574d1e4590931567fc19b0241290457e97f4f8b46650332cf5844de6b1f3cb9167dd3e0fd350dc779e44576159df513482fc9d9ee52ef6540bcb65b6484d5590af4c4a7f3c83274c73289730e82bacc365d8f7a3b63b69084237ef42661c9ca31430a4bbc7328ab25fb151b323f579aed6784092a5ee9be6607d64f574dd2fe7e815e5c951222bc8471ceaba85402df539d05fd55c7e944c741c35d333aa332aad2d6fa0556a171bdd1d5dfbb8c44cfc53a623e28a22338dc93c761221b3fadbd08ed08452ab0a8fc125238203f7caf95bce21d1d0a07da3b3e977232a940116e313d1ef9e978767bff9e158a1ee1afaa2b83a9f75757a3a2a011c79317cbaeda64f3d2415ebc4d4fb8df5595584d957560b8fedc9dadf078247d5df77b4192caee539d7e1907813afb49d42d27ac59f4ccf2c64fd001337385c217333c4c4437397d416a87aeb2b9fd8b3e1b9357355f619a2b8b8e447373c19681da6fcb2a0faa40b4b2a8417f97654a84ccc87169d16dc50162853a9644f19b8fb5e03f385c9bc4cac6bb573c8f5d4864a59c58dad0e6fa39ceac310fd22e763efe5c2aaea8e5b320bec5a8503970d9609a6f372862b598c08c59040a2f93b3fd7c98aae624c81fa0f8dde556544094e24de9cbfa17e22ad6873f08b5db8fb74e7c0b5585efcd24f3fd5c2d28b803725e8beec69815b654f8b69169c4b374028cf23fea277225a465598d11ff114ae46a64fb93792237589207c7d9174e33c9714892a67e100cdd472666d33ef6bc6c553089e29bb4303fee68997d014087499fbe5954e9ba49901d5b8ac0f73c179592928e7900b6030a258ebe37a83ad6485412e013543b9e7f082e1e2ac5d89bd524799b0df2609a8360f59f5934a269841007ba5712ea22df282e6bafa768ce05579a5b87843a157beb58fe201aab983b2eaa3b108a0de940394e36384c1486354ea9dfcb83d3dd835fa5e49ba273a295108c22825efa7a07b7587544292d5c619b95d162d3c52c7a6365ccc1085f646738ad9e4485cda269e408c1571f62d27158e2ac9618d5a156c1a9102b95f9179b91ef53ddb70bb355149478829c75297089e1d27c8e08ba0c86ec08452d915692f666a3e326a0691cb82f07b7fb4136271e601791e1ecc0c2aa4ed96c00edbd43a94e70335ec7e53ae01c68656b269f997d188d19cd0f3a42796a55b5d47d9b39ca493330810da38ed4a1468d5b5df10a37d67c27e8b185dbde4fd962fb765be14de432b6c75dc1dd984323e1ccacd734533b6199f199473854a0706e9faef62723af10f8178e665c2736031f4aec59566a5f21c1c0b72d896590d24c96b476a6a279973099646ef7ebe9f91c3b4f89e8fb249e7c9ab61828a7c0719bbac8375ee3180c78ef5e738646e9864b8826df70d13364c77df70bd1a8cc29d4dc7193b0747e8bea9fef35b930302ac8762ad42dcdc9ae48e7891a0295cebaed2241776289dcd58238cce6f1011a0dfcc64fdfbbbfc4d43cead7e75fcf4aa3b65630612cc1ec4c6b8cc3bd75d90e3930cc770107a07b7c6012a601a611214f73a8f2076a79968c4c1e0bf0962f508d34df2e7318492ef93bcc52805dde6fee08fb160bbf9629de9ae6450fb152aa784cc4118732216e85c0890cd5bb2ac7dcbe8c6b65de799bf9dea168d09357effe7bb8db483e52ea5f51f983542ceb399525b5cfb9099fe2c3fb19cd7efb3f97f800463d8b4825925f0236d5c56eb4619512c9d872357b8ec22ce8c4d26a9079ac4c6d3860b435f25a2dbb51d5e5fa34b5b5dbe99099cf2abff1f7cc8dfd66af908dbd680bff2732c7372ec1c3bc6504247153acd7d46c4f690c1e20d86851993bd47127af8cc6846bfdb0e6d2a1bb0b00d4449c757282a33c1135ee09afccd1d1928e67db8dabfc119ff3363442105370f21fb1fea96561f638123a6f42fa8aa46d467530182d5ecd0b7dae413e9bfe3fcc6f59bbc4adb2e65df37a18f220d0d1850548a77fb524037dbd163b7f4b32e1035ddce2970fb29008b24c19ac29e65b1e814ef643fed9d43b17764eaba93bf30fd1d3b1093375d3db0298c9ee3d9e82f78f4cbedecb772f90355e2d3ff1aa73824f370c52b80f31a7183c9789786fc7426d53343d49fa19b4af4fd425bcb7b33ea4ab8d8d1936b36de5bdbd5b21d13dcba5eb2c2c5cb4b80008a84695eb2e8316b09d0b2197ed9712a0004a751d438f0c5c2d5468511aba7596d5b1c14c365a795ef13f8965dc06f18260c200c52b2de1493992528a4414dee91d02ca757cd9632b8ffdadd63b62ad6907f9722654c36ee9146092c05617fbfe5a482da0aa412fe23e9fc9d6616e8ef4644e869d8ad2f9208beef5ec9a47e51ed4546f3723a41c3780f286c61413ebbb04c8b8b02db424f4fc29c53ff79a2f714ae99c2059aa990e66b9309b2707d3a025b66ced726ce16ac1668891168ecd4d5f44372ee5440adfc3dd6eb5432205ada13c5775504ca452639ef0f188fc7ecbc452444eec69464c36fd9af7b4e2dcd3a2cf7285d9fa769bd6db4d45592cd843b78a07fe4eb49de7bbcfb2f930a515b385923ecf1df24a1a77381f1ac510ee3ea1a6940bd1ed61674821e54c126f51f6ffb9a6d282a32ce3ce9236bf1fa5a533384e7c5fba64219df30b55801b0e2e6dfd1a6b7940b4ce606ab73b52bf24443ff8200e510cfb7187bc1b3c1196fe2d584872e0cf66bf80a6dc0da0b7917cc572c4eefc5a9292368a545e6496a53403c8fa0006e365bf6f4d41407c9ed94660afaae8835111d5cdf4f5fc025deb997a57666bd2291783935b0402230f6c56d2cd60985411c5640a1568e5d73461a6180fe2677a5f25daf47a1f7606cf059f0e7a64c35aaa816b1ce1bef4224adf1c2504539cb604ffac93fe13ae9f7858c79de5d2ed397da481dd979b47ed379ae97c5dccdac1274dbb86fbf2d4e8a87423ffc45cc8fb8e2bc441efaf7510d8573a77efc19f38417eb40e7faf733163085fc424e43a3d99c724dc1601e13c2b97632f7d4c7f206c30874ce4849c5591b23c19f9526394e0c741d4bb6f1aabca4613dc825885e0ff57dd66e442888e8d884dd1d9b1ec08b7d64afcd83718799847a4673fe8353c29255cf1d7638f2752bc4f76234384393a77f0c8335f50b25aa6d2676e648bf8180a66ee22a50e1ca5ca1516542e22dc2ecbc5e2a5a551937fefa8dcb36333d350f774c4265c2f8907a51303180d09cc6253e260b1c236d73d6ecffb4016a37208e56e6d80f9fa44eaddab859ff405bfddd18eef13dd3f373f44c6a55386db1788dcd9893df3b72c640210352bdc4437dc6a0bb341d55bc4402c287368238304831a2f180ec877aedcf82b19497ed98a388d1bff38f18b2eea4c5c3c9f4f87401518b3ebf240dc2560e21ce60c175ba386b953e28dcd029039afc1f6bca162f17004b9ba58ed4a4a71b025dd69e1084b5d25e06eff95057dafb9839e0810671758e55327f845c081e04a352a888794eafebbe28a9c8d73a5320ca09ea1db45c8f14423e7ccafcf2a1559e2008269b81dc997783d331080bf776e30ba290b22f9aeacf825e63863b00d1d1d660e20b34a1410a3eb2b6619be8c758d8d1a986144896877f6f987b89e2ea376ace81ac8075d049cb63bbd205022e2c79ed625e5bdda67f7b2a1dc728426ca8e1a349b0cd1d80a0fc4c1d84470f002d2e61939a0f0cd852d13e7547b283db6ac8be62cb40f70f4043b40c85d52dcf93f9a2331217e005a44a96b24ebcd231fd6888d29fd4f7969b0b4ad3cb6d1fb4a40845edfba61e4506436cbe8d91321891223676bb596a5fb7277e4394ecebf22a88f9cb64dc694b516489c71bb0a2bf0ad0e435521c306945f8dc3d6e9058ad2a653e75fba8101401492fca992dcb6678f659f859c4e0d470345d0a2686de793517191ca977c67bd177260f9cd632c14765951ca7cf067dd90bdec1fbfb02e439177666f016af3262d15448e1b05c1bf234b7d6b1c36d818b76dff0fed8697e040ef72e82c01416fd3c2006b76c2660a5a522c3418fcefff83c288698b3f97e787cf9b40ae134906821cfe81de669fcd7b6853058b2376d2c0ef83df4779f7b154ece5bc2dcc159c4b76c8a7edc74d932fda42b880da2113946da1934f8b5154c7fd0e089de151c388028a8efc8bc7ad59a2e692ca14d17ac68054c434b1554371f994ba19ea96d64b4a874588793ad153d9d31d5fd9b5879b0b3e5ea3f28d74d018c6275959d722a696a115a91bef9e3b669109b4148b108e7ea9cda8e19659a9e6c0d3057e199a80fd23135bd51597e78a51f7e68d985084820962d7ca9c423944a9ccf225bf731dcddb0be075c6eb9d0879cc664cc2c2c1ba83676e3dd6e268de36cb8dfa7b4be42e37e317e9a009cf3e1545326a6be0713fb09c1740b9cbe3800fa688f27f5d3b3e6c46bfcbd4e8b0b11ab120fd8faa89fcf307ec4fdca8f5446c5ce322527473c2061414cbbe8409a55b918b97163326ac5f33f3369dfd1077839889580c906ddb243c192512668591c81b9d5a89029d890af25a2644b6faa50cc9275cb96e8951683cb67a4d5972736f69457c6375095a3eb58b9ae1680564e8c7252dfc479170ad54e3159ef503e55de432264204a3f9c26d59cd627d6f7ba5a603b8670ee8fa9aa1ece22d8b536337d0d7c96fa92f22351a6c46982e48fd0e90328a5b2b07f9b6743ab5d85d49089bf75c3f9b0ac0115ef9d9f0776e2caa50518e92ca66767b5c884e602545fb1efeec6d8973f3e1e551549f38a696e55054fbdb6450e6a7bbb3fc77dcc4e5dad89af8e68a3274ee9616976c8c58b8be1f06ac68d4f048a897b3f6b486a3e4eec9ed5882403e42fbcdc9b3b130ecf0ab32e65f7dcb150a245d3ae3e1b85f54181f4ee049ebc15baf97602db1e1a044086af087cd4e003c8aa3af32d40e6c0ae69c993d82782691a7ee4f4a32198a40ebd68e385f1afa25514dffcd3df9df2cac3218a578c0c52f5845f0e101f063dd2fb377161ea85ece9512ef82d255673b8f97d00d884f1c60d407e308f5bd1e01ee532cbbbe49c892fccb8c9f4a1286fe5bf25b804ff0ba386a8569ad798be464cd9c14cc01ee5d09382826b275cb4e23b9dfe236b93606f5774d5831b7afde209636fd3c04c6af63245579cdf4ee5010adfeb8970452b32a0a562c271fd8a6846d5033bd75674bb36bc521eb2c133699f757db3fd47530a2387f374352b878e3e460bdb35afd685d752c09b7a33cc31f4a4237fc819f228d3cdbc2fc5d5e2cf33d739ad2a56cd675629d43106fd83614aef65edff3d9213bb5d8507e8fd45acba795984604616f84c190fea7ef1bdd38e39ebf5bf30e04abeda43d4f9e48252d7fe6bda7a9a12085f69d69dad5603a3a4a07f41975d9c4d4bf77915a364635e6a6468e7dbad2276a4e06e382f52547b3d8b62e856edcb9b28810d900bf7c9ee9374ab6886325313d1c22cca8e31c74f30816af80b8f0ac601e0c8269083697ab0d7d492ae8261ab54eb16aefcfb9cea91faa19138619c8912e59f40fe31f44bc027eb5e602c4c2ca85dff58cca5d6042b6ffaae085863dc149fb2cf058864e3180de17b582efcfdcbbb93da6cfb97b05601a25a348273010e4618375cfd8ec71cd025523c6c55a68e4724552a18a8da6712d99579bc98329867c6f59236a40749b60e91ad515e86b14052fab609a84acb2e51f9d89a4eab19543081a06b839585dccc9be0b97c4b4c50ac9fdf79559e7a76d254dfd5b127a38346043ea02967b54c09d0bc5c55cf9f9274704d599b7c9783c872fa0b6328d662c92412efd0c2d4a626f2580f1b5b99ebaf1c02b0562eee41c011247fe2c378c1f0cac3243a9fe0f07e27ce8653aa11fe167e20146601fb016fc091e7616ccf2e3ca6e1aa0c07ecd21f862f71641686fc95114d23c83bd5cb4c0bf9e81f1119d2d06033fe946860a9b48bfc2b9c5cf15691eedb8a6faf0c5ee9c9313c1fcae01d60984be6973bec7573a360f80b83b633cf6c900176fa0f5991af019304d993ba3e9e91a0638e56398307235dae08ce4cde5f8f1866255d7fb0a598274bb09c3fd580f90026ac8c2b25e9fe269bb1e4073fe8d79f3b3c6abedd20cefabdef1b7d7f077ce7cc6d6977a452624a578aef95810be812e3f004f8babe36fa8e918e000af2d4010590e4c29a983dcf2c800b1941d55babbc2b44ad9776d8a3d4766d85c60cd365db9586f331f978c95f53fdddb31aee6a55ac99b78591efa675cfde4e8cbf73003de126b6a22c10bec279a858fd7b77475c967bf28ff16a2cd698de0c132f02885e7a985b387e36c47fde6923f83550fd7dbc4ac048e740c6d91762d1d2b5940fb2665774115f013f6e5364fab574a649008a03032a608b0a3c65219c4fd62ab8848d2bd2eb11fd077cb2d3e393cb5acc4204887f341dede2b19252bb51340695debcc6b215075169e0716db6d9ccc9c0c8e427a20ca5bacd83ac2de9fd160ec4314a71c12a0a0a736bb638bc002c37e017a218245baf146869637d29aec51104d7ff548e81589a0c038326139edfbc209b3fea06f35907900dce371d0c5de8dd2e81ed51badb7ed1d5b1870927440e499504e1f94d42e6ae7dc0c9cc295cd5d16fc8d417ae1afb779d64dbcae87fe2f5efa9397bf5528ec62612781d4b9c4bdf944b3121acb2c4fb59d005bd6b1870edefc05af8338da656b0040812573668500d983da24fe6025b1a9589a70270fe23d29ec9c1e8248e07d7e93a8c994876d662d8b858ad24b4cfc042a06ea1183bb16b45f77de4f2b4b6e4fbf9829ea7241bafbbf02f777bf199de372aa388616cae9c3bc9494853e06656865ff2b200051bc2abf86aba67fc42ebd45db76cfbf4b1eec0db87a370c670377ccf016f5268df34c69c8a3b41f9395957e0fcda6f7bbc1f069ef755a0784a0fde268ce94a20ba6243141d54a1477bc368b2acabd44e171c71b3ea2adcfd26b5a0d30ee905bba0abf0218770b2cc54b254a1018bfb8e7f65b45deb947c025c6fd52fd5f15001a97b504bab52f761aa5fc34957fe26afbc615801fd8fc6ddcdc9455082259b5c9d048abb56280d9d6109cd183afdccbecd93bef2b5ccaeb11871e8735996a3b3ef631c257052d724b47179492db3c53098954a070ac03413d91cbe52f018b94a143d5a81a76d3051c16b2c1d5be44586179199428d7c7f4e446bee3fcfd5c5a710d24216eac9ffdfb1bdb56fd5012f59466964dea93c3c19b2999f43fde1fee714b62fed6e1eb061299e7eb37b52033115708dcfa3c37f975058b930aeaa03cbfcbea732059419d02c70c030ac4e41223a5641636512d4b154d9bef107de87ba471a9dc1705a9f10befc32b906d9969a6cf0d970df3a9219771e3c623a689a766ce5b7bac818a2d154d192b33fcdef2bdb9cb2abb907b5dd2053c6348dc588f677f6ae85df9c66bcb433a910f83f0329c6ea327b2017cd8eabbf9a0962cbe59b3b38cc375e1ce0679dbbc976f5ac24b3c0749bc950684c11e0669885a0401f60829ad3bad7569834ebf56658494565f261196fe52db3b9cc775519adf766581e3dda3d24ced37e70ed7085ad77aac674c4d4841a7e72ddf13beef126b7bbe260861b2e34fdba713e3cbf591d0ccd7dcc497181f6562e4e0eb1add1a6483a974daef8640e13e3eaee315f9e1811243a0efbd04dd4bc32a9baa8b0e8c7003e188c7d0e0b54b20433213afd019c95cb670a36b87f474e89157362b97d417fe412a23a10877cf512992862ebbe22b87a64dd95456972acda54caa94b2c9c0142bf748777803758e9130e59e7db8680d31e59be07df442fbed959fbd85fcf076f389974904587eade1ce8c7996f1dda1a056251275b0763372f6969ec3424382175f5a28f57dd1a4f4139c7e08b21f583d3bd795d794e07564b90ed63f67126359c7b0b81cdb317a8d43ed1e0cabac0544dd32057ebe6e7c514a0203a830bb43be40d19f9766c793fa247f25a6b61d6fd9b83c83bcb4addd4fd1ebdeaddb4a22b88bc78ba29c028c9fe7a7c39a8bd503c93074226c0c06ff032fd34dfa000eea5feea50035851ac7157409d2929c93593237f3fb19b1b8fb339c80dd9d657c57889281327b2efe68ad2df1de3fb3dce1b001c1e1029833bf49b5c3ce7f406ac0fbf2f72109a74e503311eaf875ee0326946d1e57036495e93553441973f975b0fae0c6ee0d1224150c340670e155246973d53c08d27f5cf6c7caafeff66eeaabac1cb0940780ae2225233a01b82c8e223f820de1d2d7973d215e8a3ebfd441f7d1ad661d2e9eed830f6521ac9cbb80ba9ad7f30d94fe0a78947d46f91502a04dbc9e65ceb27c0274af27722fd1bcbe058c2b3df57cff52f27a4e158a892774006a60a4aec3cb5cf8f8056648938f1e9b299c655bece1f00a2b63511d75e0ba2256dc201e9d7c093ebdc09dba982f76d0d4028baf7a7227128a302d8e331c7cfefcbb0c2a85ee95332210b547246a5aba8fcc457144724d17d77d47616582586e2ae5c149a5bc922ccc688ae52512a5259e1bb96de10af105e9172fb6d52de44c3b4cc78bb45986caeadad3df5fe0c9495a18754462a36be5cf5fa1957f10b907739e00d1610ed932cefaea2bd02f2af3a8a9cbe11c2c21d4d2ee2063a089a6ac530dff6f462f357a6a6983ef9fb10205ecc3487a44429e16f309abed48a8045de72482160887b13ff150bc43c452f71707ded0d14dda657b3cce0ccfa567cd9bf5a58327769beda44007158cdbc1acf5ac74024ec4002e7325d617f278b048239a97d1ba7eb43be140830a3eb8cebde7275e616a477497495e4324e8fa476252c0ba6396f2a744c130582aa979443389eb9506298d96d4859bfb989b69765546af7e9b3e997ec3ea99d6be5f0222d3e50f6971c08b7605197e5e69217f274dc0c69f17ed0dcdce1f26cd8e81db3b6bd6dbb0588bb46de992058ccd0babd2f7248ad6f1f07959c20e83ff6f1b1f96a4801bb1ed8361c156b0b14eb29b02d72da5bfa5c8cb3b3fa38cd1fa459e01390d6eedda6fcd6845228b3815b128c05491e27eac827b6eb6451c8791693c2a0753894fea2fd2f2a4df09a75ca58a03c12788b166a2bac07776e945e0a1ce2a55a402f99a01365b1ed5da62fd4985880dffd8cffa86d5de4281aceddae157ee73c96de1f2713a966d2b90f83b3e5c09414140b123dc2c3effb9d0f6e33f8ed0ccadc7b10422868bb39db11b4d63f1795ff81494aaf8e8527fcc4760f5f2bf451799d9519d7b7a2919e0bc76b1e1808cb67d1e964ba71a293f2970f7114f59c408c41cf0b2a3f56604270aa175f24dbbbdad2f263208f019609dd7a0e596c967e8b89befd8b2dd1c2cd5956ff7ab31256f08ee384d141dda1f68cd96c3aec475f0ccd795bfcde771bdb8e5b8719422129b71441fb7bd6c467d6536f9d6cc97915e44a8459e5998b29ca3c7d0ddbdcd24d1db82941f5b2fec3ccbeb109ce815daa204ece726846f53a38aeebaef11854b7d5d02c423247282a531139c44c196ee5e5ccbbbeede26b1f4126c04c0a9a9b55501f28b12bc9237613a04229b69367c0958696964d35bb93321374751870b449d2d70ec0020fc8487d7126221b2626d9df781538bed2899ca604206846bb275e9557ce57754f95a5b64c1e24976a2b3bf824ad8e063eaaf12d30c32c189c04f536cb091f4172552b0fd032646228b7446a00c79b94d7084cc9ca3b82ac3c0dd03849805f9c9b1738d467c90aeab499ad9931549a5e979181fc6eecbd20fe83bd07dc7b10014749a2039013f74555a4f27a935351f1055fb3afe8288b9658a4177f6d45c0a4a516fd10d7839d9621707289ecb706a0ddc2ce4a38829fb0b0c260dcbf554d139a5cf17e4f7eb1b624f2d794e3c378b43f04596f05bbcff2c7a8985ad8e18ce43b3f79cf5d64c93fc096dffd46e2d972785aaa8469a1acada51f23dcdaf4f9e2e6154760e55a4eecb6fcbdba734b358665ac8dec1f3dd34f1f0bd2311bc9a36e7c5d8086ee4c50b094b9f3f78cc6603e7b287df8deece8fe1e4329f4f37de93e6670b60c0ed3bfceff862630bcea1eb9ac5753d01e2783a5274895483d0a22ebe1f98549a90fa7dfe12a764454e22b71cc38e7819156bd46dacdf6c85b3c11c2684e1c033a22c5114c84b51b2a800060162125caa633fe3fc83bd0fbbc84235dc753c20e70dfab0a0499a2f0201996e70487ddbef862edfb5fdedfac53ec9bedc8e4785de095b75c446e4af234ed8f6ea5128696327da3f4e35de01d81a2ad0bde0606640746bd1f641c47041d4b0019a810144d3a5c611cd841dcd68c592a33447b758f6b1807c2d25905de143718a0f5b70a92ef3df0da0ddaa5b2e872b1724e3fbd5d2a47545b568ce7e909ae782c26ef73b0d97066f8c2fdaaef60c148b7248f020f17aeeb2bdbd6ede4f0b3dbb934de166c2c9776d7b742d17d2e0bb97ba06a5eabd4663866898be1546a4841fd2d1ca93fb6430b8b5df2f5ac1e9833613fb34594c55e79b319a14f8b274e02fe684385e1e0f66925e4a8f5fba50990eb33e4284e3fe13a6f3b280750aa35e644ac5ebbad1460ab5eea740fcb65509be215a5b9b3c3dd2d3d90e9a536ec2a696e4d8570f267f013408fc57c9dc347e9dde80321afcdae6b06f25e0140e73b9cb36277b39159ae3343d7bddfb5c8dbf2fc37369cd93e1e2fc276ea8ae4ed7712612a8996b65998b0d8b24c57edb5b2dd91dff11814453a20a8a68cd1dc7a78e1fa6e6d6f20a8f09580cdbe003e630cc951e07b890b4b8534c0ab168a445c374feb9da057dc5331811b7bfbdfa7a2787a0f598a8cf0ad50845668d42f829a8efd5208f6bf609396c271dbe62f7cb5249323cad773dc774c68ef3cb7a38d8d44435c1491c68f8ba6bb6ca41743813f5776a0f58f3ded0ea88df6e500229a9741e160bd944597871ba65acddad050fdd466a7f1921e080dd8c1fbb1bf769c2c3c7620ba53d36dc5bbb518d68d74de37821d0bc4a0c988c72c4fc8f11d38268562858892907e53b429f15f480a6e8a7c07ec8e2a0f62c551dfa1d24410a0f1b88d8244ed64f9067205f0bd43d8e01347f75d1f4b9234859249aeb022f27738053f00775d29319959de1d346d17f156e9a9bca6f2d5af91cb9dbe4a186179cfce834f92ca857e81c4213fff68a53517c9e39a0b53d90197c80a1bd8797e2b02cfb2f26b9fc88a8d8dcb583630423ee6acd926bd39746341359215d493b1f873aaf44704dfd0726ebb2c28adbc6347a7292a6763d8f4d8db3d9b78322ec1209fb6753d5146c2a370ac3f40b4dac984ed005a3f059d957573be66150644d77804c5ce4bdaab56e37e7bb082a9b22943064cf4e79d3166743433850ede64dbf2f4d06df2521fd7b15fbb66ab5f13a8945f5a909f64c2c54e80d5dd81d3943af60eb133a05f1f9141b0d6f8e30fcec6e4ab387e9fc4eef5c63c380be8182bf7680cdbbea7a4c62764913f34fef541f158b915fb0bda8aab101d05f62678d3fb538d3eabfb71eac6952b6039aee77881b52bc68939654d391ae5a4185a10aeaec0c9fbbb84872443549ce65fb08fc329ad74d900f6bfeebc13006bd15011ecf21a100b1c4779ebe96ed8424fde53d634facd218a49abb69952aa0e0cc285482e89407193903c330970566c2a973920a6e1de086f32a5fc8baf8b09360040ea0b97d153d8214ef31c80a08295491743dfb18d26e74b3086d1fa4b3dc623e1e89b814d08125073ac926f14c9945e6e8d285294ac4c622770d353a005f1d501d91bce514c4dce8fc4bb2f34eaeccb0f58bae39e112595520c9fcd70c7f8e645aa84c3f1dac16426f19b16047fcaad981514bfeac92d5af34bece109b87f3dae7a57465544569681578d39c8bc22d8dd759110f96b5161a4ea0ae6b560a1ddaf178ad7094f4989369b111a5ed78dfaffc75b78027a993a035c43c507fdf62b7261156c989ad0f8c9229800e9d837adec954f40d79dc9c66d91b768e2dd6561dcbb6afa4dcfa82d51a856bb3474872192a11559715e2c00b36d6abf918b32527231247fcfec3f92693998ed6be7f8f7e49120d854200af390ccf9d19d7054ddbd5f881117d33ecc95eae944b811f2db51a88e92f6a697871d161cb0370be46b5fe8b6d520ea9f5eadba87a9973b745ca26c5a6b5a4e39cae484f80a01e5f1dcb855557c93df9e2128fe24d445c58282b433f51334d33b9e6d6239eeb3d741377681ff6bdfc3e2460db8a2b0ab327b38c7d2be866e2f455c961d24905f02c4a84726b0e7691c3a75578054aa1099038fc89718fa3e3cd3815c9ef4358883cd9ea35c9e427d96983496c48267f3efc004b2372864d4928a6d7efa8eca8b4fff4386024e927bd01b94c01f208dfc246ec12d36456baadef29e4c68a76834829f408fafb5d8744ea2643c195d00a74cdba69dab0e25b6900a0cff1941b05505f189e078a0d0718033aca83ce02cd613c6b7bab09530e7590d3e08d66eabd3eaf41c8cbdb827c2b38267314d4819d3bc3531430f41df0ad53e6e2ea0cc1687e42c49bc5496d313383e2f906208ddbe0f8f8bae2f1d1c26b212a4a166a2d611bcbcb4a8a0516b38edf63ec4572dbb77f2f1131f60b931aff579793ff5e7b862dfc81656c65626386cec82e61e5ed143a6302c93c62c64961ac1a8c2b38749a82a1133d0070ae51f95fc8935547ce8496440d3e11445376dd9883263817edc4af7b66359c35bfbb6964da56d6d046c9d89e274d06c20470110804eb2e765318d5a55936ec4f457e3052e5b040283269dec59f86c319edae7f95b096863d47a7a8d1c8be95294145997a606f3be3d8cf9e5b1187dd463f2b0959b744914accd6e5b9242bcb60b11acd73d7d40ad9885d7a449803eef38db5b137615bbc42d63b4ff6e77b51adbf199188760dcf7a58efbeb46f3a0de128007dbc1707220d2f247333538f19c54f0ac5dedd0114c7f2805885c074056e3530070de7d6ca2f58a402bc36d95b333726423a9180fd506ce86fd69cff32763fec67af7e8974ad9c123ed4bf8307379428f45106896fad123a01e5e67a3eb804aa912d2da31ace5d6c2a50ff83236e01b5ffb562882431c53415d2c446f9b12f51de18bad6c633a35fbf3daca9922e8dad2d99fa4868b3cd08cdf4713a4d6e4aaf54ecaea3ad1ff9ff0f68fdc0d43478a3ad2dd4a7612286a28b3bc4b9825c66de941553ed56f770079b1e9721ce6bceb7ae32735565958abc049a9b865272f7880d54ab637dadec47bd0fa634631a0197d407ba33912f8f0c29be422971681b309fe7f321df52728713abe72ddb29820ba6193ac63e33f4bc55ac4a693630733edbea55adc435d92e9c7e7283cf01e41df97518df4cb7bfb843761d3df67bb3f978f3ad5eeb2c712994a834800f4f91f29751182f710ef4b3f375de8fd303ee87bd35bf2d0973055a9e60e12e8adfecd5c6c2e495996171ce633d2ee0a1301813e7dd6938e077c83fa2af24659942930ed301a12982af04f7f2c881e4d6b48a6744b9fec332d0b70d755cf6e90c40efe8616bdccac6ec5f71645823548e3f95a70ac199c2befdb43c60a9d678e116e4fc5a472c376a1ffab52a1b546644cbf82a3e3eb48e334eeba3cf1541a6c33be04225e949f8fbadb94031f32f2d260aedb386e008c1c7ddf39036109f99b334fb67f3a61349cd0669e4ed225ffb83162e4f141d0b10d2ded15bbcd1bad2ec2b5555604429b3ee97be18f93125d020401023baa040a25268b4e1c2e8ee2832984afb5dc0c8f617a23967b55e64575cc32576a482dc4f71c1986d9c015e3441feb7a5c8f3b8d0317cc4d6d2137ce3b9b4f61b63c612afb408040f930264e4300a0cd887181f1debac8a3f313edaa5546142afb7ce63d313ab0f66ef15d513f9a932343e4b06fe09b67106c9e0d77bf4c86560121e994f5fb4fad34f7a9982b69828daa4ea53de2e7dc654d8ec3d97946ad91cf8f19576dbb66425f73686940e7a2b1da5b69dd8d49c590d7002d9e129c2ed8e5780b5f9e889f86554fe1b22ac4d91ed3cb53395197fc19ae77402b74a17ba988581360f45dbc1aae8ca9ab3cc2948a7ac33cd3f50ba29298b697c257dd106168918c650d1668bd885ebd970dceeca88c55ebd8794d674418ef9fdbd0ed4e438a50d7c943da5b50e2b2c2037ca63170dd25eb5ae9ecb25ca6ea09f8d72c3873ae75c6c4451bc0955f914bde4c9e35ce9f746a12621747230f25487f81447f282b15ec830b9b0fd6da22e5f7cb144cb5f14080c741ac5b5d4ddef36a6780227606fa4edcebb281bfb5edd894cd0d47d3665dc5eaffd34f7aac111ae93f96c31e66762dc509203a920f8a8b595e1309f35803c67d26a02714e06c8f9e7e470db3856a9c80ae8323afe70305037fbb1ac7f558e5fcf3c6ae1ae3c23d284a889e7eb5401bcd4c9b6d8612f579c1e29de2fdc9683921100ab5abc6fb05dd2ec13527aa6124b0c92a5aad704885102808b3b1f4ef7787d78a9346ccae070a9cb6750e7aa83a1f88ba3e68983a0ac645ea20bce160c31be6a3e3672d3ac0b35e1a3bc76d6b462e3dce0281b5d86f3661e2e08a0865370f618318605a79664630dbd3d31f60fb893159f5c8e98df69ad654c13336fd79984176d330737386f9dcbc8363e0ba82eabab9f484ee3568edb25af8b7efa4cd9522cf5d07a9847cb32b366335d199e4e1ca706fc1922a22009a5d4c02b986185abc407d2bdc8002308183fbdbf7afacf6012ddd9efc7b27bf1ea2b4c986848bc0fc705762f6b4f8d4d467ed9bc11900e66001a4972dbcdb55d29811a068471afbfec7ab1e07c21a86a1b6741f72cde6afc5196c8c18e98b3d462582b1fc7eaffa31530868379cd2f98b1619fb98433e0ed7b433628075c722f62b67d5dc85acbf17fcba986fda264c7d8b81a28b34773913cae20671a13f0c0e188c8201701a89020d56716e2b19e5572f9b2894b73aa15c203c9e1f2e49ccca3a45242cb2866c87c2ba76e0b8a872f651129ab812038772922fb27d85d6fdd844459efe6b155d7137d913825942f877033e0f42e03ce8f73dff016e8317f1f0788e16108279c780eb10c9f08e10199918f77cec59f90ddca83ad3b3e2f4bbc9dd3f7af741e3f46f80ecaa45bc16a5376c6e83c93f05109cceb6382494792bb7917f2bcc8ef6e779ee3a35f24f1c48bc4968130992658e99447a613d2632fc090470858531b9180daf1460f7b4681fca8c7fb8ba0392359ed1871b6648343d0cb2007448c283c6f2e63e6572da51b66b0fec1135cb992fd343496884dd774b7b8ce3ac74f9bb254f240c5de78ee2106e0e57712e8d805a8557258f3ba32973a2b086a68d833a3ad9c2cf058e5e27dda38aabfe5d31dce1400644749b2fce63e598509b049548633a9c09a0f4b4dcc99c4ecd10624bda16f19e22aef10e15a3d4ae0893a276da40444f313835010da867408e2b2ff375d3573cbc4a1ebbcffcd6170ceb8c15521050c89a913805ebdca947e5d8adcd0aa607f271d901d8ca477bd22edf9931555dfd1af17b1d775d5305e5e66990d22f2f7d313d1af035a24a9218cf8890646c0f6e8f92f7c52b610c21f11bc260fe79b8ce4a71dcf61f5d4304b724f77c9aac216a3e13c3b1d44895f12ba7e263be17a395c50a958a603c6141f78b2575814dd2c0e94d7bbe5485c76bfd5ef42b286609f2b208b499b18b2dee1213407f789740cf759dbe9b92593ef4c3cadc29cdeb931302c7e83e27b77609474e959f990a5082c67155b54720ca641ee64d9d3cb027d440cd205409c8de51923be70781030a6a6b059398bddc1f96d8fe35ac8c4811b6df70d6edb59f49dc532154b46ca6e208da5ce4da7576e6e59ba3c32e4a32bde900b1f995230314c0c684e7a4a7b1f64e7a7a7443e32249d5b427b1b198e24af5a0495cc885682a1a75432d25a14e64149f92b6a18e1aa17f15fd94f9a029af83691774aa5589950852573d5586ec319e913f8931868476a68d5b3a172549df577a44563b915d34993198444a1ef79ceb960a944edaa7aa31c29935695dcd44430078c85df0082902a8b6b1aba9b923f9149e845cb98517e9123cb08698c5cc15d1cc678700deef1b29a34335400e14991f09e5a2581ba0554e6ce6a036ee48a4d4bc7b9d87ecefbce303c95abe9173ca777512d4853643af276a35830d31e7c9b3a8db4f334b223623e46841d4e6eda52b3956f5b5dcf58759ba75117f265594cdf8a4ecdc601e4cf1b90886352d69ed147ac0499710d6dad90c0b0c047f5560de326f5ef9d97a09fe5ccd1de08224a4492487b782b2098475e79ae57fe837a7958bc6ae769517d5aad97883252d251a8055c850c91792e708bc462e568468acaffe687d568fff50ad8b2f748ea0df02971847d648b7954ac24da2e7ac15a806e788728162d3fb3366c0582747e8a5b2a8c86e0aabed96d0fca3f956a4fe0dc48bdcaa697b6129c50262d288ec00cac54151669c1800017cce4a28513fa572c94f07b6d966ea80ee57b00af19c6bcb4f17c27eaff995399ea8541e9eef9dde46cf03a93821b9f2f3af5789662599aeca6c469ae8fc31903ba0d001b09c9d034c0a2a54ce0009cfc1d69c5550bb986037898603559219d20b55584ddf6c291d1729293a2dfe97e2e9794c283606e70718cc8cd1590fd97aa0c07e2ddc39f7ce9f6aebd019bea9a34d81ff2b4ba7a2f674cb11269f01307b9b8edd392346c90bc7999e516acf7cf0b0a6bb10bbbfbfac56fd1dbb2a93daefa137568008f044ec811160ed7149ed0628775f2f4c8f7bc54251d0358d1a32d7c87e321b282c97757e63d3517140939c89daf196781ead9c23c7689c2d0296b09984715196897b193815675dea0de0bfcc317ae387d9dfe0677b514a95a7b1d9c1642e4b38c50c04b88cd5ea5b46e40fb1b24366ebeb79c817ba1fa57247ef05578538039473176570e2700592f76c4f59cf75e97c3ca930f04b14a5387029a79e2bc5c5a586823eb33cb4547043d7195225e592bb6470ce3a1a87033daa1c33953400268e0df4fcc5bc35234ad601e2cf950712fd6e70c3b0fa7c30ef4b5e4e0f121cd0562a3425442dfad07fc967fe0d21f6529563535d0b3080ed0bade44715c67c93230d4a1faad8ced89e12f39409e61e32c60d3af61ebdd459cdd7427da26017d61fe9cc389cee6655c70688d8c6754dffb2aec905647d611c17bbe6085e6368200e3492f40c16e85ad8e867233c70170f392470d3c8faf806c6fe0d3ab0e9cb882835c78e837dc998bfd8df62f2eae64cdda646a22fe84aa78c2d4abf497fe4940364fe3977f49919100bb69b0b3278a56a4f46960de22540279b42f908d6090271cbcb4a14e8b5671076bb7536b19a9feff3f4a90bc73374f2c9e968e467f581f2da70e51050611469352f6a788d9213bf93b4498889816410a9c647c53a46dcbd84957b5a86b27553f3fbd01bbbfe08909938a83dac2990a47ec95a3e3bef6f8d4f68b9316078f0dd1cdc185faa70bf7f44063e93ebead32b54e783220a3d26bd20e757abcc84a1314c85db96c3aa4b06e5e7da13c1d9b43b9d99af98b8737c4c2bb8fd9bae746c6b3038aa23c2d71b222ce35f116ba0d8b1f699c62368a37ad901cea014f52867f5ebe71c34cc410e0729c795ad831f62084c362841d34ec272b0ccab53b62588377cf6acc8152a1530326cb49d51647fa25f947d93cc2e1c2aab001b2036b23c813553046bdc041e35815e9aee50efbe3b10b1530d4843e232f0ab6f40297b0273a4b1acd1063e49cbe8e41b94e717de6bb4072653ca48f3a2e3dc4bcea78435a2d1583d418befb3fed613f846963d67c1a81e4deeae5c6ccd38ba0fc4e34bc2636d9975481f23c09a391ed0939873b9444f3cb4770fee3d601c5135d30d598e60550855bf7c701b3d0682f84848b38e3735fb2a5fc91d313c7e994409fce9cfedbcf5fe02e9e98df80f250d13001c69b9e8736b74867ee63879cb41e4173bfcf77a6c903f841dd8f7afdd33dc3296d8fe8df4110288d9c904772db3b3e9300833a93fad14c8e6560eac0d1b0a14d3c1c499002a3b3af76cfc20a0a8b4f8ef2173039d3cbfc817286b8b234864d16a1e92cb6ab88401101d57a6b7afb47fe86e92ad9a043c0ab009e7bffff8011412bb6ee2f65fd037d374ef21bb67fa89a50d42782ec5c43824fc17a25f55d06cc2115cd619af51ab7c0a43ecb6c275ef040c1c8e159e12528cc9d09c1e7d57e21dc1225ef486d2e30fe7e84a22b31803a4eb2194abc5392a266fb8e527fb9b7b0fb6d4fc3e3205522a35a1f04bd0d26b714bbc87b6e8b7b80ba5f5c9b53b787bf254d325fcf3c21ce71020e90157d79bd08c4f4e4f0f8547c4e01149100b78370c223e3c54d073c8d61644ecc8bddaad280aae418a55788be20efaff1873819f1ef5602e03119723a6ce37d30247277bf052f914d0f78303b3e1f3f84bf55614c33040030e134aa3e89577ad350afa537d69d36cc33bc8725aa598cf22aa76c3d46f0f7b4804df8750d9d97f7cf7eac78ba6a486ce3d05307ab3a6b94629b101cc0e1307fae7ad8d9d78d0d7c9052692521f0fd14af7ae8e85b09d7524ea49f6b612e5db43e7dd3565b4f1974cb39e0468b14d7c8c595418cfe74357f18ddd2a78b4167083c654ee0fc494c4870bac34de3d3804c07d417e51a15d0eb5e8329e3a4266cf15af21cef5940029191d15a417922c6a674f0409707dd1a5e7893beaaff50834e924b7a7958de0474c69d7cf19f282c29e60a404bea762dbc21b7ede50895ca34dce787002e0fe5c24ed286d6d5fcf6962d237a47ace3fe6b0dd2e3c60fff477ca6e339ccfd589d565f62a39dbb0f14e60a2830d3f194ae758db564cced25af0cfb0291a84e9cf4929a1f49f466330ea6ea126bb4c4a1a62bf0ec16e274ec931ed61360a340a9463ce18cbf20044bbe879ee321cf423e97987540eb91febadac2ea3821cc08cab07412e8ea3c075900600490b3e8c0419019a18d5d27dcda5a867adb6346577e313697f3257870c929a782c20c739bee16d3482ca0b6db524315ec0f8d2df33e34912265831c0abeb68ce04c71554d2ea74c09f562de2abdd8b12ab124fa65753be6753d7177387a69fdcdad4c8ce6351468bf2487e88afd9f860426f0451f6c12d47622941611e239a6986eef379a291535f60405d4bd7778fbfb4c5bc7d5ef79f618d9019d279345dad579db34e18d76c843d9360b3525d1dbe23e147f3ff3eba0854ebf0a6f693a09da58167edb909387c11c76c826d54966669aaf2d972a27428eb43c524a2889a8a9a0a5854efcb18180ff644bc07321c1a85b89915b93039c1f933db544ef7c43e7ea78b706597cb473a5d2818df0ef9ffb6c941b8f95b245e6b4180f2a6d979e69e3dcf5a3dce0052eee1b0a69ea6e276bc61e997b32faf379a35ac39aac14086cf8cb55976b874732e9c7ae0aaea37d74545d73559014b3fba07672f4578571407d618ca1174bf3cf31834342ad1b33820e8cd9e81e03a6318cc96c5edd1c2d969f95ebc3b8b440d8e957901e2dbe63cb2b591f2ec789ea96c294220e5802e624d396cc4818f959879d45f4796902de82130354eaf23faa7bcd3073e98f4944021e09abe61ebdedb3e93ed15f708f0029ec5c57a73a6ae0a519c2399c5d3250635f6e0c6ecc7c04e57b77c376a83cc77b1e063322d877ad96847e79562362b72dbaac01c7db490bb04be452a7023a45355608459ad7d91434934a0e5d3f5570b4c546229969307422033701fb85eecc05b04a246faec19d095fd82c34bd11ac19cd2b9dc7e941d755cc4896e0b51c317ae6468badd06a27a96efb7a417aa5f41059dbc6bcdb999d83164a796b79799934c60cfb9384323d8b6e379c9124f8a17f2668d1da28ee54c1a6f3abafe56d5c62956eed053336617c769d326454b9ab23ae1d362638ac317771ae526ae90f704c0390012842e8d3b81870b13a9c501d22ba718ffcade928ad75b89792667ea687918d96f734d349deae531cad89af4eb24fb7c476f814ddd4fa5e9bbdf6879f68fd1641e85a9645a0d3bbee8c787e7c6b2adea65a37f32c61bd72b799ad1f43d7c0e0cfee2ff05ea4fb71d6ea5250a3ac75e94e46b09d3adc8cc51282d2f7b85f40db1a74893935b60a059f68bed64fb86b1fc84d9c066872ef14913f51fb2fe6a51a18077aec3b2fd34258539d099224082637869d191c604c270b0fdf1248f6fc3001b24e9dda0b4b44bb39b1583b37b07d6c030fee32215b0a5d34264aab1eec02629f79906f81ebc52cd7de348eb96b0d58d8f2cc609e824be4a847c712b728521bf8698fe365b2b77c365d2db326e94260eeae3f6e6700390389bfd53ba0890cc0d5b055a6d6de0f8b52c057fa5a574c1922ae70ba9d7e47a7b768d4c1fbc2c10a204c85c8c2c0b8a4af0877c0e5e985f758977f64b203799b1957cea95f338ec9a94dc89cad58431b901df4879e8dac89e0a4ee81c26466414b22228efc6f161632be6d43f8ab32ecaecfb3ebc6664cadf95aaf9647423636f4fefad89ef9f3905f78f527ba9aa504e8e985aa68fd49d040a6be3c7f1ff15ce1ac6813e705c24ed34d73df8df2564828181ce69f52ebaaaab26dd9f9e1c300426c9d585ba341d4bd5770acbf044fcfbb943cf4e741e834ca71a75426d78b1348bad98b17266eb4cc6d200128bdd44e7573f018c38a2a48e25fab4d55f66c05901d00ea6499081a79a9d52b63573891b675753bfbb10b0eda7da46262e0586a9a57ce67b5507804f8ae420c167ee37bb20eaf350314c8bacf5a1f823b978aa47813720ebf51b110f15b018679246dffdb177ea2409127674c9951f9802a34f671d26b6f38d1e09b719da056f3e19b44d96f1c9174d52905504c68c95871f5c0565b41d480e46ac1b652cbdba16c05ac747424bab79de26ef11c585b52c6789a18b302e3a8cf06b807a8fa176e0b095d1fca1341e4be8ee96af60fb34ae8557e36239733d2710615c58efd114d17ff8d1cb4fdaf8fdca9f79ca6e1985f12fbee7bb0ad103da0a8f0cc7d93f635be7aee7ebfb5dd54c9d19f1af6780af01a61bae2758db27f0d40d919dca18cbef19fa8f5f90462170f8cb51b4e78e72f64fe5ec514434cb98a3974f4a5aaf482ddbd68e6f2d698fff5419e2893c92391e68f19cc98a465bef7b362e784894983937407866230348cca10171e854669a8c18f0e7b51278f03bbb388fa5f16b21ec3c61234987e9bf7a07754d68abbf09d72c6e112cb48349cd10b3ae680adc97e729801ec0caff249cf5315929299ca6b3a384fe1b405b01bbb58b1272af253886a076be6e2821f87531e5364b9cb1057f7ce355d0f3c10375d3e864d2d8e008cb0c5af0786e2ca0a7066e1f981a36d82bed9d19b9520bf1b01ea822e1c19290be215d601a0f8901eba7e56e08a70dc7a7289a009cd78a0e44654a28186602c38351c776a8fe43ab1563f6fe7daa264c3b4b0f2c28dd8af605cb062dfedeb57ad9fab731402ab038c6463ba7a2c29632ec2edcd07413d95ec218b85e9480436709c2e722c965aa2d4d87a112cbf4c3762ec560fd8166161f0d8a01d6dfaa8a4f9fd659fad4529fd3664340572dfb0946f5e5d7c3ef12bff588de692a798dd37a109743596dd375f90e757957d89c89ade7fc3edac16a1ed3552c64e4c337431b69a60a30715636aea7ff05e242220bc76bbe7f4238ddcd72328bfe926bd5bc35ff70b8c741f98fa0404209ce6900fc3e5ae496d9f2dae2ad94a15458d41d40332149676dc642442d912e34399734be962a2a7f9872f0a3a03058db7a0911e8de2ffc989d6469aa5a23cb95522240b5fa09de14599d3257c2b33cb7a506582b692a3059671a76ec166c9693a28d5b210aa252d95917353e3160161627c70a38c738e34d4f90ed13aeb03598f231b5138d93994b963006a0b4dfc3da4d531160581a3238624b6281a1397b4a1e8b0659af63cd1fba5a52fb6318620e052336e80d46de33f85ef5b67d144b986f987899c542a4bfd42c68cf6993ee180073f38184c955171a0b3097146d016ff27bde6d8fa3558d438f9c1b54f41445f24fc26f0902ca2092c7c2b36538363da10699cb3f0b02aa4fff9d03fa0e9afabbbf31013b16b6a2cf32873c02287a95b62a32f25492984c4436333dbeeb31562e375796cd70aafb911f4a996b1edbfba515514352d605722540ec9038efc6e884a17ff98806377d8f7e6e5250f507a911ac48d170223af6eaaed964ad3344ca7bcb6f5c1ad9a74fc18d145a9aeab2e80901cdcaa00c4570b9861c09795bff9661494c6631e47d799b7ae14435043d5df990d9a7ee9c7bb051d7a867e409084a4d813ac3fe0b0e307334759ded08a4e8e1f0e6d512bb6c6c94af97d166730dfa9e14d41185fa8b8d8453bd32fd20ebbfca2abe1edbe66fc4fd94cf29d1c44e44d83d647cb25748383c6a60cb156c29c2a0325d01d5ecc681c92a3c5425fe1baedea464a9a0372c5ca92179af16e18ba71b272092c38675f5dfb9a0f7c39e47cb30eb7a2fae187edf77f9e27f6501efc5afea86d9cfdd98002a356c13bca5b4cbe37a7bf99e0039a7558c5ec778b6c9fedbdf8ac71187e41fc6a08f9f3323827463f67ecc2020781cfdb3ffceaabe343c2d4548034e80644db5bf92e5015878d3df0aaa7c118e75bdd05eae0cd546cd16874757988c3051785cec3c0dbe7e628487cd82ab14793a7af664bb8bf73cbced08975c57cdfc3f16df670c9bc66426c6c627ac2850be01539ecf04c6534aeef22a4da8383bdebd7285cb36e3efad41fce9ab8ccc665b9e33f74612110129f9abf93f9b332b9396695d586f715a48190810f97405c655e3f0d10cb45e0de7e5375f15ae8a37bfc77b420bb1b91c53cffdbea5e02c489a37bf0d1327c43d765d138cd124b968106534c3c8ceba4d59fd3d3f6e71058248bc3becf75fca7d8dd10ed576830d0880fde9117a5947e21c17fa8aac196fd587ed5cde8b81e05cf72f530cf528da739fae116d749a007aa61b08b3d9d009fd4b087e49bc803c909cddae2838d8318f8b0b8c9256a0d7dfb35492f5adebb2524d6c1c51cf0ddc8663020c8d27a3e77e720346d746fd4f10f5330efa587748bac42bc9d6b23c06b3b6641c40a7eaafcfa4ef541700671f21900b5b24e3d1ea8d5d98c4684a6ec0659b7723d2f6cef88bf4c6d53c38745a51ec32b8774bc35a657c0d7fde0636b9cd805df38945d06a2f9d1310423c16fe665cd4e188e7a748823412690a500e5be1f5abd86756b69f5eb4a186d7f2199e351533da58fbb3874a687fdd762959cfb6b3974d60718f097b8077c329e7a06b3287c3f015fbd35c96a63c6402da85c8566a066fb0a4ca147fbf68b92cf5877a052f9a8117849ad5c2c35195998aad929fc414adc932ab689068690f34d092211d94793c13a33b21d80631b7d37f076781447bda4d6f3db057fcd5616f1b97457dbf3257fb617c5b54ca8a6e47a6c0420e558d6a7422c34acb04765ffbbadb44d405453e3e3170bebfb64dd32e2ed84e849ad62532d223aeebc2d738bdc024c82303cf04e9fa358190a954e1661661ca2471bc00b473f2ac26758dfeddc885067089b9e94df9146c9d01916e40fe488a7bba7979e2fa068cc5b46d4a2cbe60363be0dc4d2701187011d1ec16b6f2a61f5e41659692e655fac49c99c6f239d65082b3badbac01f3b1f8b8723a24f7ebd92d4de575771ceb29c8f04b6a4353b55c71e095e5017aa9bc9c5988c275925e59c531330db843b0e6941c285abedf883605723c92f08a1f8784422ad22b324c03a06b65603ff12c3cef3ab7655691a4fe5f9dfa556111cc63a681376f70ea8ecd8b0e9d720f728e12861986dd88dce722c2e18a3a5cc084be13ed8e8e0bd96cbc70c5f084bbb97dc6d0db46e78e8e2cd88e3244664574fe0fc0bc308855bafb900662b187d1c299a07c8d1f15d29678fe3c218f28e737a0e85b4db4ae60e109f1dd6983c767ef7cae6974e2afc25727697199a12b967ce02ddef764ceba6afdbdbae4442cc1f2bc2866c7054ffa4eb54c97368666626d33f481e6fede2164f930b7a2642e7e0e7bf025f8441a09b53d77291f7f78d05cb92d39f5844d65aa962621df4c3d43d525c705089e997d23866e3a6b148ac5dce1caa6231f797979c8013d3f7fe094583f601cddf250ab6c5ff64068bc2e6de185618ae1c8d8876d3a227bed49d183a223126346aebd220f7f2a47196968ea19bcc997f2eada434c4dcade8bb59b08e972e4e5e00c11a17a2318f654fdd0437e2bdad5a72ed6c0315154fccaee24592eac36ec00064e7830c3f26460f59683b397a56954105edf99024df67230ec5d71f62321255260c29da32cda77ac82ed30f8ae1b43b0133082019cd647a9dfa66463f01d8990bc9ef3f75efb0943de0b9e927f9c99913936435b6928ef67539d9eccdd5150f6bf9e3f88e604cda88735bd0394c79d6513cd2c54a2a1c0ed4ddfca732402d09f235a257e5d6dfb672eb5f1a278571ea7c0dd86d6d472f602a6e0e70fda5ad2ef8b25bd8accee30759f40d40c10396b6afb6b5705241e8a3aa7769595bec491e6c0b27beefe927a851c33ae5883a431783d7812764568e937e5eb0dbfd9eb5a235059be7041a97a2b4daaf9130283d818a833d154343e34b05362bf6ea1f70cd7ee5d9f24c7e1ba2fc8a61c115f9c4e2c2dc343541d7ad08091c881a7c9d74087215087a9b70c3cc0d54454e3275ae60edcb9351e5805ae58d1309e37297f8fe876efeed37747b71579fc8a4b9db4081f2943c952d960cf4eb4b64e79d02eacfcb9bcb5811bb442adf5068d6b97ffb0e2e128a18b676ae81b386e152ff06d17b8c2da4a185148111b67ee29fba7a5de5b37663129aa5520178ee44e0e7f0bc3b85420f944366293ef788c4e114dd9cb3f2e110de4c8f430469cae785b1d44ef36463b9e12088671579fbfa3fa949d6042e8da9bf76a8e31cedb3012d134cd94394a788da25cfbaea525c19a690ed30bc660219f0fb72aaf48b0530d673b2902d5bc078a00ee2b462901a0bf47cf84c7210ec87a1280eb49ee29a322ffab1bfed6d5db09905fb61cec0683ec413566cb8696d757491cece0b1526ea548a015eb4ce08183775cb1ee0375c63aedbb7c36fe380384ba3c5fbc4f02666ad6005039cb25243511288aa12f323a88eb6f255a11c0533858f0cd235d6d58e65025808315524bf80de526b79d9c5ac3f558d1ee18aedad19858a3cbf0b5d325f641d357131905d50899995ad4daed9d0ac98d072fbf944016ade9701531770dceadad495aebfc54657cc9e0ca62a118681b44aba4e0fa3721323cdc5ac39c29e2595b6d3e0ce35d537413f1a17f993cd6c869a93e50ff8efba75873516fa3a80450635b23d713d71ba79e11cb2e7d75b8cd76df12a45d98597f17c2a88fdeb1deff4a275ac37b1d77c8e3feb86b41458bd34b6ebb65371dd45e230b692cb2501e3af6e6b43eb797e6999496d4c005967b2348f283c1969cd44f56bf1242d9872db3a332443009a5da14f4f667c721edc199458ac23dba5f345245840b2363fe29d52fb179786cef0c8de7afa0003e682fae14e9c673e1657cfd321e90981c825c29a8fae186a9fdd422df78b4ecffbde3dc422425daf40e9fc358b8ca4fee9f7d1730b64214e0991087d3d0ed6541998d640447b3235500383a24321f18585a4dcde1486ad6023368fc01eca8970985805338795fabea441674f9c7e4f9c3f7ed413cbe295556dc90f349838fcc3e488669c85df6e43adbc710f0fa8be76f436021ef2693f331a27a3195ed319569eb3771630316b4d39fb783ea7c6c58e4d00fb2a086a047408fdce52e1ec8847493945d9dcf67c12fae4c9522d0b257bda6b723670118c7689838650fd9d03a4b225466cc6f349247f5a9ac93b4c0181242eaf7bb7fa1778b5d8537faff77995281d3c10bc533b5901de03043b066d276252329a77b2e4856f2055ce9129a96fe9ab6f19153dde50608d2c1e5a836822cd3c0b302256b6386b99b3ad17a17249c5db571024a7f8fd05363ea550c29514f2457f1f1849c982dca187c1415cb75d93811587603444e8ea85b62cd712bacccddb9b9edc45f705416e820c8ffef4ab84e179bf05c37023d2d6f64a4f1e032cb8b7a928222b99372cffb70a13024bfb0e5619c27f47c504b445ce040a0055f7121b8542038b5c7d0b0b305c1bc4f662249318615b05fd04538cff4e5afef4456dcd08ea8cc54661a82800bc5e4f3cdece30a3164e144fac557c866121136232495b7d4c7479a062e44077d7ebac11946f4bfdc5cbf2f8b1f7c883fe478bb2ee2c6792004a32838f7738542a38f653ee8bc9505967dc4416f80c527decf5ad75228a5c9b8d0642ff1b1ca8e3ab70d1523438a0e8adbb312a2aeef771805e9fe2158badece6abbef7c259762b8a7bfd7a05bffac6e54a0fea52900f43e8ba0f3381e5fa5a16210d7b3b36718a907e6e6ceb01a793ee46b2b5ae2de0023f7f2e65c85b8bbd6210a91ec92ad160ca9992be2a0332f2f422daa2bbca865a7445d97e74f0f6a48e0da7eb1291cf389c28f604a4f47fc02bf7ad6a0d862ace22d706962b89ad59058ba4d92c3e32ae21a2c1311b854870423996697f91fc3be5c2b8c4fbc7c77873c4dcb501918041ed7fc693aac766f0b9735cae88dfc69ed26bee89d2c6622270b1fa19deb1ef33eea4aef2918fef664b2510a48d8eb2c98fda2ec68a4508fe5dea4b3a9f69cf400d42b934ddeb361b2d1f99441fb3bbd8ca67574df68be0e50127e7ed7256302e500a0a0320fb67d2e691d048a99913455765576beeb63acffe87c622a85c9b5d1421080ead927518b4953d637f216c6c44f9e20b55f344223df293e08ce0f01afd32751f1e6fc994a4f3f860109a6491028dad8e9991f29c7c610a491dace032dd133b74b2fb6e231b58143a778f6656f5577cf92957b6011d7b9e77a46574f96355d7467f282e963c627a35088c78c2cd8caa95fc1ed3b8fbda2dc6f14933ac54ff4245714dfb50b444c694880bae26017ec82c724ca644d21371680d7497c315bc908a417ce552757c3aeb02ab0aaa7236eef63b0d044246e18679dbda1a1fb2d5194b08c0bc608bd1cc9591da1029cfdab70e67c3be2dd4bb290fe82b6105847ac5825705feacd40bb1ec71ee5e50bc4270375853f505db735666cbc3732a881e562dde4cf59afbbf113272d5711c1b7df2cb30eca1ad4adc993f3fe07ac44244ff21690c1e6d74e432a17c2314c13e682d3f5cd769e31bb0c162745d1e7e60e4479c0e682bc2fe31e8658c99e4a149a20bb9e89ab97fdd5d74fd9423aec590e45bd9c13849ed77147f5b56f3ff770048f945f9a9446d570c8284d695d7bca1afb068ad848f6670aa78fe3e21b658c0b66b12905fcf8a8a98c76a46dba520cc25b9db11cd7b1652183d967638fb9d10a867af282b29632f7df53fe1255fe2d84c55259f917332fbbd046b70abec0fcc6d46a0e866b3c7077cd651aa764ca26f29dadf7caa635efd13ea0d1c1393ecd7205febaa2d3b319b57f46d7d72f3066cf2f07d8b8719aa1e2276f07c468a4ab86da0f5ee0cfbb6a6804f078ba33ac5f9153eacd50f6e73a2f845570487749b8ad6c53d6ebbf676645fc83080679a3841a891bf49ea2283987081d696752d53092321948ca4ca89257d9d31318a9b75401e394fd8bb134290dcee6a4cc46f96120ee1005257fc316cd2494a5ff25d7b0351bf44baa6157fb6a03d7e25227edfa71ba71edb83b8b4969daf855f691a30e4f353b134c2326b0e097637e8164fc3bfac81b6218745d8921b037f738ff509cfcd206cd4869823860e1e9c19de415ae95dd7aa7fdd786f6c8d52e70d60e4b30380b7c368ef4d43f428bc89ecd118b4d263cf70072b9432c91cf91ea6a6b1fe2f9e42c3f9327381fba15c5b7e462e8f3b00dd700e7448d5c0dc4934b028f15f87a8ff9a76b367a44d09e0b1bf5f2fd8f4f98bc6aab42ab04afaf16875758c49e984562419f1ac269d540de8bc975a7166ccea69cb4478a786e3b6f32129f4ad5d6ed57cb260eefc3fcc8c6436b946c1baa5be795debe7004a4716daff4d60f4f798c791e50e8c5dd22e9e6f9f603d8478de6567b0663d23bfe93ee69089ea2a6a1061357dbd6445880d4ad71d68d36b15bbb6f731d5756ea95d307ceb3825bc0c0f86e098a3b33039e5a5771bd00bf36a340c564123ba3be59a137da44adad0bebb71111d2c20dee21384bc7e0062edc41ba1af43d2f6befb39deafa2d6db5e52a5b933baebb54d3e7a33c2e7a09b2d3c5758e8c943163a1a263542f1e7ee949656ae79690089866d851fbf36c4a25d9da0834055dc48ec13f6541bd7a57042352cf696e30de7f026b2cff68b1af9875cc7027584ea04b9df1e60f1874ea520417b928adbc45b7279acc08eebe95eda8c19e532a86781fc971cab72cd1e0e3d22af8fba8d4498fab7920ebdeecf972f80402f27f61fd6fd2d6ac358515dcebf0c7c210952ffd139957ff9b92dfe6e47e5375744236cd4cbb79588aa566e7d4e01cfc71143767e89e323bfb0a36765cb98e074fcc4fa3b31177f725fb77abb26d3c60172f08e2868c1f0cd0072498c045ad2f24d25b47291d0ee7fd314bfb641b00115e507395f284b1c5e10f9ac10f57cf14f8e96b6d9c30d4aef488f63c9f6313940b35a3c774f2a85b158b6754e2a817ee7563edc2096d5d1399cf6fcad42d538c9ce3ed666df86bf4a8edd35d35f09b71e1ec6ab774f48b4a8f97c8637528636b6caba18c959d3172dcf3fa1113378c8d94dfeb3165873ad85623955bc694e0e2d120b1955e72f5f62d2acb40404461fc0697e4df26f1ff1c46a035a50fd581459ffbd7a42400ee4d0a38e4778dd18bf80a8531e158193cc911298298b03ff261a8a19d6c15d72c4a18cecd7cebfec1e345d4971562590c597938bd279ad6b107f662d6e5d5b28d535198359951f030382fa07c1e7ff09a5a09df207db1dc37a5ec8b930b50eaff748d116a9a2d0d40fe91913d2bbdc21449622fdb4e7df45b9d7c662d5bfa5d5b0ee78369c38b29da9698e99df071f36066d4ee8c447ada4d8799cf60690e3740be48d8f900f62f20e783d40b7ef8443b2b44fb0d925f9238679592909586ac4142420009c3cf50da928e0c016124012333d841e0fb7ba1fb8aa0d2ff34e3ac8145e10b99ea36bf50f66e7ee64e26e89422a3f7b7754300a3f05cb3711f1c9ba83a190f6cfb9cfa489289d7943f83873fc4e2eb93ec605dd4245afadccd35ac5e2e797a9efeb76911f7789fda66a77b3629deb43c31ba76a175e6b78c43f0f9f1ca225068695616a7761b3e1167710fe19a5141c34f114d0d6aaa2361c383a6c291513c09759ca24b8010295e160fc97305daf25247d2d034c9ef37b34da4a0089cb25037bae7e693913860a79936e6663b9caca20611efccbdec8d7ecca5c831e7ebd7078aa1cf7aa1911d382ce04588713cd26774873ef7a1770871c671e868fab9cf64d6a4a47945af4f706172399f6f58f46d4324ad25b5543109007a88fec244d4c3c4bb74de8b4aaf5c3457d3acb2c1229d5704dc170ce434b44d8e3d1b6379136050a8ea676c1dafaa4df971434de508da3491200a97a12d2307f0f5ba060dcae39ee23d8719172d0c54b8d73a38d21ecd76b20bc24d2575ffca355361d60102ddcefbde0ef5d35005c54579982cbefe0ba2b681bf395528e45b4c39f1d6a384f84c1901a3c766426446f6bb0ab12c8e0c7742686f78f192c7d2266e8b748592d9f84fcd7181693403f5a0eff3eff56fd813b577eec3d9c0f567b8cac1627467d613c97e008459ffb9fda21eb9db8111d6e43b9d81e2a7df6523fcc179639e78b5c2b1ff1259fc5b31ba21502e6db1a2956f9a070714fb0e02539f403054345908dcf09ca7daa665161dcf4e81eea34c4063270bf8a601826f29ec4b00da12517765fe9ec9f73d570d421971470230fc5ad7da67712295393f3f6c9694d5057426da5ccd8915a7b9c0ff5d8ed70219d6345c2b8ab437953387025ea6f2d562c84c8eba4ae57ef22a00ba9268d09463d84e11fce2445d412a3204bf31713e9378261779ad0a617f35adbdbf56ebd37cd0382bdd777a698da9b10f654462d9defe58422188db877df2e955ca464ab149c3878622e5ea5e39b42d83703b2da489c1a11fe6dc081b35ba5fb9816f88085bc6427070dc2a1cec5325419992af2846ca9d16a6e14b343a709abb0f2739e692b661c36212ac4eea33929ba4401f060e7cdace6cfc2be2101f3bb73ebe317798600e4ebbb11e884a6ddca81f6f6cd34561f034d92beaf9b29480d082dac969a36eee63e114e6238fc314cae9de43737f00f1d8cfc765dba4fbcbe4a7b1f974c335b5886e98561bdd4b9c4bfd50aeb71fb6965444dbdbbbe66c064092881e5c30eb1d198dc59f0ec53615a5a122b6068f8926d6abb9bb53d0c6c4186f9910ca3f582b5615682c695bfff334394dda5e9a5e0eae3f26c2366b480b0aefe60e858f911e8130878944cef1458917cf27c7fa91c86c59a911eeb651664c366bb1ed9b9b2b3e33a9cc50370321922a95df452c69a553bb908be5e7e90f6801217b85180ee0981e8502739a1d97d29ddad5f4a4514b9d8596e43fd421329648ced02c64a61336f5bae64380d6148ab60fe7caa229704a87bf8d4a3f43d3efc444765db745000fca4c850cecf58942dbe42c28175a5ed95be8410d65a8a92b27bed754ad56db3e84b43bb13757c02c82a2adde0f511fa083c170240a530858296da220e9efb27ef34337c7f27294abf098eb8011fa7d887ad55cdf14bc690988607161634aae1121713895e94eee171095d15d6b2a26a4dcc8a54346d974295fc5eb928e42065a071121445fdd35483cca0741f48947e4615d8c53867e3da54cbf3b9763c6917b505d226c8fb32781b57bf277a51cc2a6b65da1c6ae3ca9e32069affceab5b60e57c1f7ab435807a63cd0660ae90f1b4a0436f3d52c8af58fc7f487c638e1fc45ad265f9e563e9168dcd646e59d86026c2ff38a4bb1d52e51b37d5b740320b22cd83eb156625b50bcad06bab155805e95054df15a88f1215b020db2b10f51dea6703d770eced2e34e342b1f96f3f5fb4c38e1b19550a487c0d08ef0ff9907530e4873a1277e5de23bf14908b96fc1b1f1034270b93fc3046fdd5310ac5a1eb69a21a58b4c8fe667f6d781dd4dc9629f1fb7ceba1b0e600b94b9c7d1ceb764db1506c8ff04cfca99e60fc459f36652d34f2e1f52f1665ab37d2297f01f7bf4ed73f7e0a6f863b3dfef6f41d25034fd56215eb05d3474136eec362d0558bb457cff072a10412b0d42ef5ed7d9f9f63eed3e9887319e62fc1262c33819fcd46969d2edb024d0358f723c73dc475676802c1535a321ede790a9159c68c650932773dc55c6ebefdb7bd3988c60d6cfa967764279bb0ee4f367492e57b157338e596b381c4a89c7dd0b892d3f8186c211bdf4c6956c6e06fc131663aa95586d2c1e928534e98a6afc862f3a650401a5407c9a1c4c846f2e380fda34fa1b6cf819c693d750e813a2c7b400e51a8179040483a0f390f34a50204b6902ecf43746e18603052514c0151013c064cfeabcb5e0fa754eb5fecaade34421d72d963bdbc9a0b495f499dd0b504b666225cac6869b627f7a5a2c40858b3d2d6cca82ebcc21d8edf9193833fdd0b6cbee3e93bee8bd147efc8a16b3c74a4193bdb03467bcef076328057d3ce715ffdaf32aa041f9eb217ed351ccf177518820b480567db3b789689aa2345bf9ead5f28e8fa422452f89ebcf64e22a00c8f1a7a1445d6f6ca37a49abf627e23f32dd08a4801e1e0e698889d65a9b86c2f92b04c7e98b9f8c4ae83a0e711ae0aa9cc0584e3ed8fae8e8c906c6ca5ee333b0254db39dbf2f74cab75bfca34110a8cc50cc8979d7291155e568710dda5490a1301a87b6a93ba72593d47ee25d398cc3641f96c4415f99aa959046cfc94e088b7c92f8fdd1ae316ba7b066bb1cbf469c6c0a912334f1d8aa8ee6e50d316c5fce17bb796f2328d1763bf46db9dfd3c8b2f66c69c5fb831bd5cf39a383a43ccb94dc081a6c8a9514ab59b3d1eda030c9710daf0677760094d588fa4f4ca84231e3e1cb1cfe1156ec3df3f0edcecab736c62b001f562290fd45587be2c3f40912eec416cd3bcfab9164dcff3ec200cfc0cdd8b0eda702d452c8639255a3728c579ad272faa00da4c7eed84f67d5e86b3ce63efa5837b36cc3d57d96e4c927f82b4864b35a65a877627babdd14ba2055f631fcb46e86e0ea38aaf928e9b503ca057edb14b31b73c30a841f22f31c09991aefcb437da2a2cd409d6adb3c43382406bea6afb3b7f25c42b4eae73d9e694ee1ea8ce3e71c229b5df41107d18982af9c2953a74eb2d48006e4a2475cb1dd9ab9579ebe7dbdf20756e1ee08ecc4b4426242b4c62ffb371fb4dd788a63974faa66e78dfce9d939409e23df60c637462428ecb595dfb058cc58c2d57ad917507d8fa0212808b4d6ffeab3cc37bde9db17e871699b21227afb282d285fe3b4a34cfe36872f43c6944e7c44106a2d8a63d970a497443b27d01ce7f0b54bef2177cf7fdc19d937b470f8193ee1a63de0100bcb4c7c7a2d0e6f6829653d2a5e0385133dd66edee5d54bc5c1fb8f507bbb579b0ee62967972c0e4046790c447898ffcefcfe1d08418dd2cf2f37c8c0afcab4bcb465736328990774499f5e4798fccb97ce3152e9299995398a44be2826a738744bd54085c1263135b0ae6a8a837614cb8226695e4cce3b36025c281cbb9a6f289100bc67b90f0703e9248b94519194189ff8425df06fa623943e27feaaa688464e72a41896aa93739389ed477ada4d6b24bfeabe371eaeab2ef191c299d6979cdb5f48eb3ff8a4496cb6ffac179e151eea8aac00d6d4789e4b4f9f9f2058064ff88c69faa62fde92343c3627acbe341112581c49ac52516a85d1c87a2044314fc23c6b5242030753ae5ed0c3a5c450a7086ec020cb11198cd35531a82bccc765e7db93b67becef45a3db3ebeb5b71fb927891e3688a6a21b2e02b1697c52a15cede5bbcebb5c1f002e5e0eb419f51063065d8fad5fc235cfd11188104c857df587d006fe1bbead397cec5aa8e1a5fddabc1efa0fb5a5070ba529e3045d1983fb764b866dd250e05d8c746ffe04534531263587ca11318d3e078fb2578c145dac8449f376236fbccbcb32784080fc71d4b43a48073e7a54559d548678d605acde017f0ffb3027bdd3a66aad4add9cc0f55e2365cccfe8faf3e0a5326f1d56a39ba8d6ec80cbd001bf033c0792c24365b7b8e381e197d463fec2789e0863614c8a20dcc06fc9bacb0a83948dfed9d0226a3dfe5f2ec93ad79e312a0b6d0ea52cbb8b74086cc3447651ddf362850f1d3c6940b89f92eb4342bf30a01b8a124c3704b6da06ef8fc37c325b385b266381548bd8b6ed301a07f2f5be86681209885cf6f1ed33ae925909f30935231f95ffe828b65b73e6d24536b919a6b6e11e37051cb7f0e244a12f8e6c028a07194461b2c47f851e9b7a3dac12e19a6839abb89b4b4477507b780c4ba7fb93f62083f81e673904c1baf4b1498c4e4d1c46f9be987f2dd151057741f015af2376fc5be8583c9c9fc02773281d971110bda04cf3c09c70d45d6bcc5d22330e219f8e311cc449a94d1d6e48c36d3e4af2c35e06d4452a75c87fde0496e1dab79c9e1ed1272b40b384d0bc528d0d35a3c6d41d35ffd645a6ed1aa157abeaf646313e50060438dc4445cc4f0a9628ef8235ab389bf458e13666135a7b219e272617aca7b159db1222bea58b67c377f57e1e096537003517849192b0925034cc7e4df4966c16a125db62fe565e8123365be73683c7df5887e85b2411d5ace752ebfb8e92da04d66572a378ab1c80e99aa46a84d38c790e23555fea9a3474bf561af57d516f42402d0b95a11935547a1ec373b9e9f84ef85724f7893c8749df6ffac140b6ea1be1fdaa1c4c44dd7b797cc1aac1d1906ed4f7300ffcc45abafd2d458342a296556d57e6cb4e556171d6d4ace235b79f7ea1decda3efa6f90726131af8a58a46e869cecd0380066181c1a29ce130e14bcdd53e90fb647e877cd59d2320ab6827aaa22a74d82378ac56d6fcb7c5aae678a8a76c086b3ab789eba84a5438d989175ab26276a47e7c403fff7fcdf13efad60fcda952cc70911e92c5eda2bdea2931d3915b1aa6e4efb954964147c768d0aba364e817f7ba5aa1e361c7ad9acf57d19b107aa840f578ea8f9c301bf8ffdd4b61f72a2245639a86e4b561d09d8727afa9fbabf6cc894bd9fb9a505362e9fa2353f933b54f617eb3942ab874f3caee1bf384ef27c0731507d4662302d62b709c484ea52e93186d68d5ec3dac68d9ba426a9270a66b17ea72f3ef7a7f01ff1efbc895323db04e8a8fc0d8337905031ef6b4a670f36fe458f1e76c7f7fdffa545c40e72f9268b4e6c47142259ff6fb3240afc1a111d89026ffe69e413fcac02d091a28eee5e551103e4d9269b6741723976a7a85ed0faf7e8e71e58d0eb715242412db070983fd6e132f3cde988abcfc81458b15bbac71bd857f18076352d0d81adeffcd47cc9555dcebadb2eb9ec1965a4e904d126cd7ae6d03f849197b40bddb25ad978b31e5f575c2d4c8990577274bfe7bd6f276cfff7ea626547c6a78567aa089a8b86372f8b68bded78588238bde66498b8459b0595e436032acd3a154aad6bba3be1949659ae52b8308e61022248363b837aae10db16900124f1572555ceb7a0e9fe243ea99077c199801f95047e1d6fc0bfe974a679e7ffdbf42554e832fa6fc3ee2d056648494f153a287c080552e0c54cd32ab4bd490fb5c49b27aa77f39376fa10c1497386332a2826b57c8d83b3b5c091a8788e385c754b57699df319ddef83fb445ef2a0ddcb5de25a05016da70878359e828fdd2d0a6a5dda910786fce698c70ee7cb8cfc9ff4690bd96737c8989db60d435264ea1688935504ae2c9da3b2d1c4274c613616eb29191b84db81699560f9a15ab35f6006da69dcc85620861424046963b26eaa17e407a06834f113e63047bf585ee7cb8bf644d0ebf57a462290600a5357e60764f8c5dead06222618f2f070fcb9ba7ee9f443d9d4559b200362fd57905a3c0ce25f4b0c204a31529d41c3653acf53f2b927311eb06a1d1740bc62160f33830f83b01522a362d162740f73f7f6d272cf9405abce8fbcfb8d8ab1436b171ddad0894f57d5de9f2637f2fcdbe68aa107d9339e0e6075bee93cd1ebbdfe90318142bc3a72932dcf08c9de89c7e483ada9dbd747453028c8f7c0b8e6865c4d1cc45bae887b1071c7fc7489415befbe1e525b5e01b775cc2d5696f946fde9c3a101a002132b97efe78fd9185dec1d1d8decd6992a8fd16958d5f290dd75c8e39b5f0b092b96090ebf364c0a21b4ded45795d8317edb21898113d29893d43b51823b4196bc7efde314c928503ee228f1595a5ba5bea499ff702dbe0d2dc2b7c0ad7082a29f12384703206d1f9e4d0d1cedc6fc4d0d6c85e9564cdd39c3758311041d6165f19854257e67e143fdd361da8a2fd6004b9a0620d902415c6e85ce90316c3c735d2db4850534eb18e89e043d319f7d93f0f45c34aabba34a8b2e25ccf08887b36aaaa86aed28c0242925006285a172dd52c699582903996c0610c4fa94e3efc65b668b6b9891f60179db9848686500cab866e88ef980f78d21d4aef003c0e0334a3943b027dc4d2b7bbb2a6feca97e0a6c1ea6f8c41c03e1631b65887c867b7faedf127049f6e95bdbb502217c6c1cf6c5e000bd2e818549f43f2c5603a158d50f2fe4e5480864d5233ed75f945d297b8c9307b944fd0d5078c9ccbdbb9d947508b28af064b9e2e0edf6dac7f1718c5026e828b231d839ee2d301f516a87d7ead73f9cc5ebcfb1ec7a7c90534ce3ce4cb4f63609e9a202fa8c720831967ca8c60f6cee3346fd951083cd2da30a211923a4c4c8ede53b1b33199bae3f024f2f0c97284d062d0a8d3b2414b4557b507845a0dba5d5deef1105203bcf28d2090591f0c472fd4abc6b77b9b36b1021bf4cc1e947021f2893146c25633cae460395c261e1cae6a01b98876921012b5db3112e19e44952733dc492a1b3d6bec472a3c358ae4dc0aacc8c401e25b0dd677e3416244f7f6c83696793262e452cabd1bbcadb6847d20d463061820e196e36b976da67aa560b34931fd2078e8995ff031fd7370736463e9bdcff4ceef84be0650abefc527e534a7a0f66ad6faf00e54618154c2fe7d3eea01265df2c226ac34ab7e3010b8f1f8daf699aa71d41a7e3a3160e1f71dc6a41e70f0f0cfd97f4f569b8241ef98dc2cc4c61cb3286e8b7caf79ad9d435172f1108007b4a1f2d2d98bc6902db3d17e24a5e00481bd3d7a15c4abfb50c5d68b9ca0429ab945d3403ed075c25b3e5011e0f89760ec0bfd7463c13ef8ac083f760d19791b15e7768a9c05edf8aa7436309cb0da07b5f57649b297fb5eb55e97c582fc2fd4c3e29fdebfe3f01a435bcd27be03e131c1af126ce608eca36c83c9e72815475c4d4f81882b0db4f4fa3de51d46fe64a42ff3733c55f2a515bb3ffbb159ca3b1def90bcb7c8fddda30e4632ee08717eddb728935c9b2becf09090045e6b7f1a6215748770adeb57fcd3651d088643c199215c8a4eb46b270fe54739ccf0804c5f9a224fe54a6025512b85e98a20a99db2f7b3a623bd82b359c9c38f7b32edc4088a06db716553f65176e1583cfb96dc05d684cce211c8d1343dc85dca0a1d4496f2231e65366c07fdae5ac0e65d86aa38bf0790db71e900193dba9288bdfea9f205b2122401ea6c556c09a2e0ddc9f04ae4a5f6d0d9d1cbff4405f0f484c557674ee5c337b8d6c045bcd11a6607acd919fec37a2d6ed31ac91bea68b17b78b30cc1d06426760b895c227b1de31a0bdfe29d2a4106af43ebe5f9792989bcba6c744298343b26e6d811a991dd821fb2fe7d55f7043a37637a1587efe444432efb33de725f41ecab5b99692ec83b2113cf4e6dfcc42023c3a85358b648a661a24b33399af1719643abd51930e19e4b537c30a46e65cd933382709de44b1c226b65d67f2ab82102f39a8e713a62ce3edb782848a19e60b452be3a9c9c8a7ec07aab44c0e20e30e893dbc6b3de8084413ed4094c6bb42225314a285f73985fc9948c9a6922ddd43ceb17da50e1dda2f374feb79ecb444fad874b1f6807450a13c136dc1d8b8a64413b7593831ee4cadc4742ff5d3bb0a051c3e7d0a84a8eb289c673f94b28e76d1bcd1675e35298cb83076b952c110923a7b92f3015e797fdf0a7db59cf1302e379e121461d307b9ae22610bc1cd1fbc6e7633135dcf4872e84dad0d791ec6af2028c7cac9bc24684961ade9f21ed3a14f45cb19b390c620cf09a16d706c8b394b37b0c6c39fa6b6e4d08e4523c95d35066f5122f3c1ba4e1f90b572a13745d1719dc0fa27b34a2352cd7c44c7ecc825116a655df34e453fa8288417b2ed3b148f9dfeeca14dba195e5566309361eab36b98dfa75d7c5a14ed4807af805318d76aeeb6ddaf558193f6e6c6a8eeb31012d49a6960c5b22b3e556999f597cca99f17977b54357431a1a3ee5338d2bf7ba273ce5a984a6deb8a04d450c45cc3c8a19138d582002b386131232d50e53fcf79a8ba1057d1555974c91b16b3a3c2c07969c4c9b39293ca0305afb393c371cdbaee870dd048982171c06be2b03108ce4c567db63338755ac8950be9616b3b5fa85eb9b7aaa1c85045373a667353a8a4f9dfeaebd820e45228624abf1fb80e381dfad18acc3c4ee10dc688007795f59968d79a5d0a70ac64965916e9b67953145b66a61de8637b442585186e3889d71da53823374bdc2e0da10e37b99f30d78cf92b67ebff5c835e7ac92cca972deb302410a00a63eac69a107fb05f45aab047873ec1250463c240b7723c973c8d280d244349bd68d4009f4e433e21aa14f558da9213323e5c7f68b988ff1368381c0eaab9f3e76d695291bcbc9aa4917b4e81166ab2b6b4c0075719b000d271b236bd289045812304eb05d6b87f99404204717ab25feb66ad1dec5a61c9ad50a1e9bad07fecf1205329f6362de715fce8b1a91e927d91ccc92e6a235fb9975491ec10c1ce03b1d5255d613e829973029ef7be886d8382843c3cc01354f8c75c30164206d64e0a98fa622067c7f3d3413874c35cd91117220cdd7523cc537b068b1bbf770b0f90dc5698bd6834caba0a40e97407dd9a269b3475d2346addde0f7c1c0c95665134e3db681e6fc323ade507b1a15c800bd708ebd481a3247e0048b122d9626bc553f4461aa71adb0a40c6c6f6133ec6dcc03e50e848db750eea14672dd08bef318d91dc3d186424eeceb6ffb6fe3541074334449e2478038abab402bb1177a57a8ae4a82a56343100758b32c9221a43c504c185b8071f3651783b6adfc93c9e51fb617f7f61d2c4165702b72baca6c4f11d59037059e17d7e0a29bc3fbd576ca28253cd03407407f4928f58a5286e036d7f624d3342af7b0b322d151663167df0385127756f7df96332529589704df3f3afc2833d102aa5b5810de543eff8b7b7b8a08a32468fd92eb4328fada1ff566f2a51a60bbd6349f51cd3d0e3899161515e7f5ae4c7777c167f46f4735f4f7526b1b8077d4382eb32f545a6a0940b191db7f078d59a51d38d921f9acc8699e6bdfc3ba897dd197bcbc59e14db302ab3f71c79839ff810a297ca277e7fea0d78b514f8a9ac3583242aa3298f54560d9df8480b5bf1ce6015ccc1905c69023f6ab9318b95a35701585e7b209959f789c709b9b09fb9d49467d817327bd277675dd72fee15418f9cfcb1d3438feccce6e472ee0ad8ce9b308012f74d44d96a6aa2a65ce425475312ab03f991aa2514c43b8773b83c88f8ef4fcfe4a272bef72fa4e42c41d9590f1b1cfdbe50ea26c7966d0e793100dcb12c639fcee370ff264d61fa752eaa1b245ac3c75cdce73a7a421b124d30ac9905cfe864880c321e8c55d59a4c022bacc418a73d054fccb34cf70d0faee70f3da9aeabd103c128c31fcda41ef6f018e60548743ef590cc058c9431f60faa7e5f5fffa7fbce2451c53454e3f80e0c5bc1a0b744249f2aaa3d29770fe169330b1e6aee758becf8cdbe804ac48341f8eff7804fefb8c09e756c2a7ab5719032d22b98d356f8d6282360103e883f253305dc7a23053625af0001b1004a2ecda372b8a98a1df02cde2dae592294e934694dd47aec0a5f6985a6b74b32ff817deca313f96a8cd89558576816fc115105ce9a1180e536f0a520767810d620e5222eddeb60bbde743f3b1359f7f28e83484776e33f0e339b46d479928d717bf2b7276c85304d068c77d9e74b25557b4ae847379269f36faa592cdf527b63e4a4fae23f956ac2e08c66205946041fde681b79aebfe1dd205fd5b7abd7fbcb9c235ec51ce8df9d1c0a328e5956dbd889b30fbd35331860f288b0efd17cc276f13d5765213a5b881a9b7645a7c0622918f3a4e94c7b8e95340721ef4f004e5018b86278454802bb61dff67d842341be7961cfff6cbfb6aab78fe412674a6273752fab4a40afe788c5ac3f946a4f061639f53190910fd10548622f204482472377ebf3a7875296be8460c99b4a7c21ddb71bf029da9680b07c3b53201d77504ce09621c16ed604df871d2998324627669dea5f9d7bd43705d1e852a7ad34dc85d588e663ca6179d420434715c65d8fe176570b5ecbd94009ef5f4e78f90629764bb3317ff05ceaf8ba13a9900a5bc63684f391193e51f04b8406dd7d6c9a0311598e854c617a451f3783b0d0878ceef14a332bf78a2998536a8a7f284c32963eb2bd1fb7e2aeb4dbe6fdfc138418b7b4f0d418df028f22f9d459563dba1b57b128f86d998c1b5394a2baacd64130ad3b2f2f7b4769e8a7a74b245d073be92e44e86c8cf8dff46e8784cc6f092f41c38a0561f011a8c90f3106533df3eb01c4e0fe75420c902d25461a42c62513c69873dcc0deb3cb2afadb042b3b406f854e5fc94d51ff96689cce700260a47a848a3dfde3506c1864e2290c4c872b0adaa1ed824ef085c0d520637cfca05c85b0c7f5a48c27eb075605132c7063cee80a510761ce8a8da658d81a12589f7cf1bcdd46b290968ac811fc2cc774fe7d5ee6c3329bb7b6f643c3762f4bf49c1f2dc07ac876be34f88d5b90bde9e97f74e8a6243e6ad729c9ec31e1dcaf407681336e1f4f6df886fde34df79d18af07f3d2e9fcdb6af25dc3938f80adf9c6f6aa8b36ad8fcf7f70d2dcd0778eac536b3b8c181707ebde0476577cde0e20da59ba63b3623c0e7e0669cc2cd3f4d0786ec30c212e354b96339d01a8fbccb8a5ea627192e00af947a8791435303c443fe7e471534c1525df652c91af79b86d2f4a8dc3e7da23460446a2dfd5fc01c18d1b8fdebb71bbf4d2985748b8bc772b0a8d6614ce4b53635c97c2aced4a941de5e9a3be4d42be5eb72ee17ae03ea84d6b27eac551249720b1a1ffd15207f83e1fdec4648b6775580cb532bc614566c56105768a95b5b2e56d8e8ca7a03fd2d991bcac01355d151fe889df41ac50fdcdb8d46caea690a5aaa1df60448ec93b1738b1ea2d5f8146e048b4955b1c2eed470d9610fae1d24ba79d7b8ba3946f10eb36d3dc59424665fa7c286f5bb61c9344dd8844578871b88ef6d553793e26a62b7b6df82fe44faccb0c1428baa6f1f1157d7c65d228bd9dd1c661592a404d801afbb5c90e57961ae6206ad8c5a7715a7b2918f9f5fdac94a3acec8657380f06c8508b5c6a55c0d8fa534b42d3021df2cb60e89d5d8a714f319f1d1028f5619cf566811e4f7cb68ae673caa927a0cc4b1d594e142365701a7a363ce73ec34282a0557f700d41a3aa7f50d4c28c3840f9a56f62a0ed999d7f0369a0b758c21768e1b613f323a8daf38c10ffcaa6fbd432ecc72f3e8e1e106c1c0dec3c82734668d81b2889009acb815597ed0c94d042133163d3f361d2225d63e0b38dccfeea3b36e0b8c64f4ac44cccd737f3f19278b33a6e3543127ac95df5649e1daac8ee8a21be1c42425ef220cae5dc34f7946561042346b3525538222c88087cb7eab07fb1e2c68c428e9582d28bc79d4df3224b932ed192a6f53d64d06704d9521a955b4d9ac55148bdd0c4d97ca18a8458508e355c24be68e3d13a756b2f51c46f9a9233a2b5ba8a9ef60833c0f1dd7c5e83d27ae7354697d1463828264554a0bb072c29bff7384a8c6502761e7a270b5562364e5e7219004c7fd50b4e957be2f43c9f18a95224df89b0e56d6b62ed6d8cb2f968c470dd48367a3c4cad0ef70da7befdad4ad5cae68e2784c4383dcfee3b54514e812901660fdf905b4fe08b31f04aa3cb7f2fe9bce36feca45a380cc40e7eec41c9978aa7d8bb7b83ad2597c253e3e3897136533199248e8f137b59dead25887e428dbab446949a47e869fa2522ea5208a49ca3eb9e27d6178e05ec19c308f1d3a14c2b98bf255a9e3e695032bad17967dff9f100f424a092d65e524770f6e24cabfd43977db5733ea92e87362c41d8153da8253e9e4170d57ea988ebad62fd8480e8b4d9237186c363cf756ad85b128e693f1bba24fc96e55d6331a2ce4f5e6faa6b742c2eb59d275d9d8fef07b2a56b8a6b25c8dca13e856dd6aa9e5bcfc1c153b51e97405db4db1097bfd0598d38df3ab969c72bb0e3fb034efa8393ee4e1ee7d4a4ee0ba4fa3ab2c9b45592675cb8683cb91eac708657064a8a3521332a060a2e6f7583086a13244cf2299931a50ae40fb5e3304b455c4c603450e59db2f84204a88626edc42a8032bd095d9a1a988e18abeefacef7bff1de2f28e0aeb0eec5b40dd64de56115f1a70be8a502673cc59793b39e4f68bb7868213edd3074a1b41c0f87a940d4e99acae1d60b1b82bf7ae17c08869d40533d1b3570ac1434ba4266734acc8bb31314bcee23aa11060cfaed7ba108cef2a182baf8a8e5b7ac7f6117023348bca50de7f56ae441bc06b731760e36442c6f1a2c357986c80b3f094269bc64f19ff8ba668b39ebf4077b440cd030626f07fbb092da46a64c2a9be9655ca182ea8b26b864efa36b5eeee64270d383c4e0d0460e002df6c7a46f2c042bf2b62dc011d69802d60e57bab4b1bdb59c4e164a56c3f13ac058d0d50bc44cc897e77160c34ad556851173ab0a57343c4059cea50434f0109810e23a2770ce54906348c14506ab04bae702af39425ff0b561f4f3b15abd4a4ab35f047da30f741b8745d02bb75830fc43fffe357aa08a149fa8b68ae18319ba6dd727d2637cda792e1fe1f1033fb1d0d853be59b1b587494eefbd3c7ce77ce00408d4d2b625ea471409588d732732d7f78f9bb4b211e7a5bd4751c4f213cfbe592a2230b20481100e1249ff3cedf10df50ebafb4b10f4eb15decda37fe8e9308b8174ac0f1e1bed16acd500994d34e18c4a18a166c08649c90a03af40eb672126930f6ebae3a3e216999d4cfa688774dd711c089b2890a5e4d989452cffa4af8310a059a2da180562ed841814d64fa4af1e665ae042f489d6e85ec3fb5276b9ce20f98777b6f36434dabe3ff2eb76870391e3204beaeae6e4cc5df76720b259e1570ee44f694bce449f3b1e11b1b4916f5873bd630b75539e5ccfdbb04da9cd1c3334e95cfe9bcfa512b32d3e75521779f724a31cf19e8981cd2991853714adeb644ebb3bafa8af83e5aebed9f4b50dbfc73ee82dda3d5cd2e00133340d7e572575c0afaaf706300baf6b81a7eceeacc1e212c3d8baa9860f070a64f66e2319839c371062fff8c65afb0ae639f93ea9eca6227acc9752bb554b0fd6a0d8e9e686672d0a58e3b87f2b4365985a27f9bdf50fe82fdd68f5ee12b7f64112e1bebe074473d39835101a5b7cc5210084af616f27dc58e74e31e7630da0d04dd082c811944dc7950f823fd3ee3bb8c10028af1bdab759384bf31f62df4cf8cea30a04cfada97270fb9278fda6824f913214281d912d9cdb1d46282054e5722df3d8641546e6123e89867298acb5d0e5e19582479befb24e770772657a36db1da062b1268709ba34d24bc2660d6d04fc377001b69724020e0e89ce3efdf88dc99143b9b1fdd3f3d3c74be20f1b9517cec32b5c8495eed2b189c7a5f14548d9456c6db38e68299de8ae9483b0b515d65634010d87fe823a44f020344b63c23c6bdcb2c7a3f034690cb6f1fed3776694cd5977f0108a5a0a72851a3c2fa9e8563f5c34f3ec5769c6e72d5d576ff9c0a5deeadf45f6ab86f1c24df722e5156f27128647f551130624a44d2fc9336dd4409f0f03a550ea2f238c2f8ae7bb6a157bcee9fa650844b705b43dd35595303e7854fc86d43041c6facf3767570dace282fc33cd7414a8e306a272a33ed44c7fc8d9b1902b5e837011c503bf982bcfd5a554f6b75c4c64dc571422b01ec9b565d59b11bb85920b78d5bcc1824aa3de7f36142dbd03e6645b928a52a2264aa1c8355d684a9c0e1e583a280a9e131449916f614ddaa3fd7e5737c3a41133a724dac9ae1f8485d49ba7e23dfee388ab7214f150c9420bcaec4d88bc4f972acbb63c01cdd74c548669106f3f21cb95384d873f64455a8acd995a9de892031aadbd731202b5d54c3635cb0eccd03795bd920126d4583dcc705ba63e5567a68d66257e41bf80c17b53b41e9d3172221dcd991a0d6be32833903cb2b4ba6830bf948651f8416e45220976f2b930af5039859bff68599c0ee5f84919ec058fd6b7254cd898f445ed042f9bbaadcfa0261c4fb8cff3a0ac2f1ba3027e884f8394ef4b4fb6b24a4dda6457879ddfe79e02fc374decce05c20332b896b38c7a94ea32f6812d9d250fc4f806d593abf34d23a9828a38234ec025835a610d4fd2fe22c1ab4efa5b8e87c081c76c71f43af76e564a0a7dd5617902a2a72a3f031134a1c75b0c03142d218a5889bf88a39f54efe6c7da10e1033f595912b27f1da2e8ff4e390eb4f18a0e49506f70849d3a0565a5013bb23ef17815fa34fb65c98661752a8a81e5fa46399f96de4d1932926df11a64e721f0b43f184e62b67306f9632c009efd30b7f454a929536d5b9965b576c41b1078d32c21bd72794b29fc3592e050c5d8759d4713b53beb84e6d5269df54583c92ca8a28e4ba8b32435f6109c0ddea0633a9091f2a5af00a2b32a4897c4a2f60a1613e2e51b4b7f4ccb228c70d375b08706ab4aa2d70ac155d797140bed661febf5560696b1635d8d1208f64759d9ac3f5dea5e28da8bd7a0e461f3a626fc1dce61c9b6f295b53fd39129e624a39b44c6840db6b5e99b7046b107597274a243e9b5a85147e163fd99741a8ccc2c3b2362b4fc899e1b55450ad9af772fa493cda912db19a34356643226cdef4061007024e789b2ce401e99d3cbc8338cb9a049fa2b4dbcf8a119dcd7255fa6b5aedca87bcdc0010831f5b4a6bb145a22fbf7d3c4a127d656509a3fcb6b2c3f1044dfee40af264b257309a245473484d147fc3939605fdf01c61ccf41279a0356cc9038fdb6caa6f1422d1ccd0afb372f958be19cec47b215ab3dbb83d10814831e2f591eb72e14960ccac44e791250c3d16a0273f355a6282cf86c8d7cddebd39c7489210f350914f7066eb5dfe1a5b29c6453c6fd8db978d33e33a33a48c287b9d5ad3ce375b044fa5fccb5b031c69276f895c5feec2e813398c728d19c5a4d6e3b2f0144a53a1e559171523eac07fe92ebeeb38d3c4a8ab88ad98ea80af95a14d981067f7a893ddb88d8b3520deb1cbbbda940c7bb3e05643a025c043312a784a7d8e9f26ac9bfad5a17b8c420033642ad76df6ab457d621238e320c6d4f1a0f5f1617442262b5c7467eccac63d97160efa1c17fa497b273ac0eb8006c4ca6c7cc480ef224f9931f757fe22f852d1042481b22347ffcac896607e535db9c4ce5383d8ba8d959941d940f1f8e3261c8172c402f0a3b78ed0557a0aafea7e96a7236ed1aefd77b3f74b966dd76cf85c64cf3d5e271bc1b76f53fb59186904b42d8b984801514949e97f099e8203338fdd46b46ec21f3a95d02e32058776edc6037ac8ff87ea3d3ce740b1cbb8c97d0a9f300a291e3b065cc8238b0c55605463c27b27f4dcf97b79753970714b88e616806da16224563b5f999aa3ab23535afd93b659d8b8ec2b6eeeffa717ca1fd5fdba1f35f1b5ce065a98b0beaf5f8de733ddb62653bd252ab3c13f7bfd4cf57d67875e69d8ae7162c8586849723120cbd8aefd093c2ec2a8cade3915b44d4798567040fc81d7dc8334a846ef27cc2516b2858355e064dfbc46794aa76c39a4e4162a3e2504f35d6d6f149e4ab90e27b771c74567dbc6c62a857415b940fb93c5e8dd7c39e44833200abd36d87e7d1fd1d7a1147d303a58997cf96d680c1b672d74a802eae69073fa9b379f045e19c054b665e13b0ff9f6072bae9acbf731adb992fa6dfdad045596752255866aabc6058a74a9de4e5ee536bb81a03fbcd2b19b372aa5c8a30051ac5b70fcc9dbee2b88dc21d89275e3924188a795ca116a8f76bd2702b9b15a3c48b36269588245600bccc2f23bae4b898fb051fe7defdd16aaaa057d9264c2509a2abf4426bc0d22abfffb96abb9da9c3034428c2832c84783669b28e17c8f6298a8c413a7e5f88`; diff --git a/spec/regression/traversal-performance/tests/root-and-sub-children/aql/fieldTraversal_andChildEntitiesWithArrayExpansion.aql b/spec/regression/traversal-performance/tests/root-and-sub-children/aql/fieldTraversal_andChildEntitiesWithArrayExpansion.aql new file mode 100644 index 000000000..9ae1c953b --- /dev/null +++ b/spec/regression/traversal-performance/tests/root-and-sub-children/aql/fieldTraversal_andChildEntitiesWithArrayExpansion.aql @@ -0,0 +1,22 @@ +LET v_root1 = FIRST(( + FOR v_root2 + IN @@roots + FILTER (v_root2.`key` == @var1) + LIMIT @var2 + RETURN v_root2 +)) +RETURN { + "Root": (IS_NULL(v_root1) ? null : { + "predictablePayload": v_root1.`predictablePayload`, + "children": v_root1.`children`[* RETURN { + "root": { + "key": v_root1.`key` + }, + "children": CURRENT.`children`[* RETURN { + "key": CURRENT.`key` + }] + }] + }) +} + +// Peak memory usage: 10190848 bytes diff --git a/spec/regression/traversal-performance/tests/root-and-sub-children/aql/fieldTraversal_andChildEntitiesWithSubquery.aql b/spec/regression/traversal-performance/tests/root-and-sub-children/aql/fieldTraversal_andChildEntitiesWithSubquery.aql new file mode 100644 index 000000000..70a911402 --- /dev/null +++ b/spec/regression/traversal-performance/tests/root-and-sub-children/aql/fieldTraversal_andChildEntitiesWithSubquery.aql @@ -0,0 +1,32 @@ +LET v_root1 = FIRST(( + FOR v_root2 + IN @@roots + FILTER (v_root2.`key` == @var1) + LIMIT @var2 + RETURN v_root2 +)) +RETURN { + "Root": (IS_NULL(v_root1) ? null : { + "predictablePayload": v_root1.`predictablePayload`, + "children": ( + LET v_root3 = NOEVAL({ + "key": v_root1.`key` + }) + FOR v_child1 + IN v_root1.`children`[*] + RETURN { + "root": v_root3, + "children": ( + FOR v_grandchild1 + IN v_child1.`children`[*] + SORT (v_grandchild1.`key`) + RETURN { + "key": v_grandchild1.`key` + } + ) + } + ) + }) +} + +// Peak memory usage: 15335424 bytes diff --git a/spec/regression/traversal-performance/tests/root-and-sub-children/context.json b/spec/regression/traversal-performance/tests/root-and-sub-children/context.json new file mode 100644 index 000000000..fb12a4966 --- /dev/null +++ b/spec/regression/traversal-performance/tests/root-and-sub-children/context.json @@ -0,0 +1,5 @@ +{ + "authRoles": ["user"], + // we request the payload here. Pay close attention to actual memory usage in the .aql files + "queryMemoryLimit": "100000000" +} diff --git a/spec/regression/traversal-performance/tests/root-and-sub-children/result.json b/spec/regression/traversal-performance/tests/root-and-sub-children/result.json new file mode 100644 index 000000000..d30a55228 --- /dev/null +++ b/spec/regression/traversal-performance/tests/root-and-sub-children/result.json @@ -0,0 +1,140 @@ +{ + "fieldTraversal_andChildEntitiesWithArrayExpansion": { + "data": { + "Root": { + "predictablePayload": "4dcf8e0692a607eac1a57899572b31741387a715dace82cac4eb83748e1ed68058f927df649dcc7884961bd6d9d977922b70023fd57cf50bf2e9cae11f0e9639f74cbecbf0f487c954d989ba8d678f677e1ef775ae371f5a33ee5178385be8b35f01756abd685c97686261c13b7113f2bc6bc30195c390339a6978ecd9d4f3458f9e6c29d3d1f7e32a584e1c999e5e9167dd636177b53db216e4bdba486ccf86bea70496880c6d6c597e1136ef0a71e7d9288f29918afd4eea7b7bb2bdbc7b1af35199b8ece7f470807cd23eef40830de3feacd19bb20d6dc86fd428b5a385aba2d9067b95f1ae3337af20682e56933db9ba41385e1d4c35552627cee50288c75a5611b726c856ff22ca68d3eb342b563bec277162f5980226e5b46833c55b8fc8d89cb1394094bc74367287cd1eb68441284d4b9fa28c7a1316788fa7df04cb9dce281619c97debbfca0cb51b64ea54bf535c3283c6bb6193bbc73956c4374a63f358749e0ba7bae23599e52960cc8f2479542e1352a75f855bf14536093df3db61d4024b29c3eccf1e92fe5f22809fcfa55bed2f94ab15ff9e8038600e13741ead7e7bf0ecf437fd7aaad10e5545e34ec62f67ec17b38070a42b20c738ccf31ebefb54b5a5614f1dfd7b8843032bdb11ea1dc97cb2ed8ddd875e3f0c0ea575b56a77593e3a75facb3f8909c61aafa1f07ece5c34fbe357f9c2b32e09bd7b727e4cc524c5304060efb4f03ea95b479c1776a726a519c59f77e65c6e8e793f69530bd601919fe693ce178a712ca2f25a739fdc18c3cf9148a55b510e45ba1b75c838b9d341912465e07dd2a560702ffa75a1c8cbfa602db8c4a818618987cb6f712f08020c028c9ea955c152ebc70ce8f83af6f211b6a915560e7d1ea2124dd8a95ab67de2d0ceeeb1a3917293750211e99b973d9145ae9f18602be95029726986f72ff362d17447962bf85f0b0a036b60a74f60f50d2b0d1d018b1234e9df166e7d3fe010be5c718204dcda877da1e6e98b0bc20545699ce4998457753166fe7bfbf812018f93f6ba838feec3a153ca45e04ac0aee36fb59ee83394d80ba80a574b0c808dac322a79ed85c89aacc6df1f1fc7b87779eda22d0cace7c02ea3644ac239dbd0884747f23cb01d1d10f09c0f1119d2039a97967a484c3d705bca38e80ef390a96df0311507c42cd7f9067893f675e53047144be05b3f3fc585d8b1c99b4d083219469f12cbe92491a8e169755a64b171c00e3689d5b117d49fd1048812e1acc077cd50d595a85829d242e40143bd83a260190261ab70878593483bd3cf5d59e6dff5c39caaa53bb8008abdce0fd53e230f876b3a69efae7a4245e80ebe52a9b04e8a9900c7c56baaac9a0028af2365f0c41d8516793f5e81aa1cc96f9b6fe226ee2677d3df0e5141878c671718aa9fcbbc8d8a8c80ef0f84850bdcf5fcee5ed7ee0d238acb330eb22369d0c6c51dade2e645389123fb18c68e4f00ce5536838e8769eb7655e76b86d78be0284bc32b5dbff36415d33312e3262fe28a47ad27cf3e64d7054e8ac1cdd1bfbeee6cf82b1bdb8422c02cc6dd39a08d943a45d623057cd9472361689ad8a349a5948e24582ddbdbb96e9fe9b480080385140b50893aea94b76c9750adacabb15d00b26c3f2f0e37d99329b2b849094782b2e5ad5c04f928d36560033f8b9143af5eea839cbcb33e00e0ccbfa54daff28d297362e3c85182df2943f2eb95cc44da1fb15b9ebe0ea4ccca7f48286995aa85e6f349fab3e594c5266861e7695ac48820e0a32772cf22972e219e16d1fabdfddb3f9c19363b19bd06826c5a5269f740cb0cd4491cf65d3e38fb45de26df7b904b509be9d85a4e00bdf5ee9db626f19d2cfe41413b51552be794360df3dba17b84bed889d74131d55c5742fd21bcb1ee3697be15160eff9dfa04b63c4fdbcf7dd90ceedfa2a27f1aec7b6747874e4e030343192cf34fe7e6a191f98399d03a8d86082d8080a29a0730490322228088cb31e052db4f040c55fb6ca30024edf412c6672bf87135228dbe41cb65957e2e61150f7b93b56a0a3e00fc11296ce4bdb8b1150aefb5888d557266f515e41e93aee9660366ce91a390b42090da96c9c4fb1205c14423db51b5c0fabcd4def15b859e79e47a4ddac99e37ee8f3828ec232d2e73f0dbb9245a85de3d690871b8a838595fd594cf34808fb0969ce88782271a9f537b48fcb4d2e541a68309d5c9cd61158e34a296f44bb0f1a7db5f71baec67c81ecc85e4e6e6585fa93487d5f4f30538c2de07435201c6b65df5b9e2c4e5ba0e5c23971feb7fac26622e52874b49672d13a74477d3f19af61d438f308b585f97cce35e13abcae654fa23d7d23373154332cf252a17cc42e51a4945b7cc2072a0cf46f5bf23f790931515fad4d34a71d142fbdf2d964c7e255e1e64f96938d7b30c2217ecb5bd02f3a5279386a66abae3632820f0a2b41e1fe073b763589cfe135bcccd58d66acd7ec4b1c72aa4ac4d407b733a963452b0ec5260d9b5768f2357a643e17f535955040695d18ebca005ad606248cecc378c11fa635d5583586bcad7c6799e1df0cf33f963aabfa648398a7c864f36bf5cfb5f95ad3f649dfe625359d4721cd03127f3e27ca9bdac175e712fd0c232e3af5e1672719b8634f353fc91fee99ba5aa13b2858bd30b6678a37e91115df263e977f34ade7d107f257fd52594a030868903bb7f2b59b2b8d65ebf5e586f31b22fb734bded9766d9a961d07c4be53476ab20c3fcce40f76cc04224aa10dea7fa924ba254fb4c63f949f9812380764614d03b4aee717f78318f61862d7abd997515812629860454f1601e7a7750aea4ead43bc70c02f97e49ed9ba7b3facfcf2809ce0dbf9531289a2ee88084886835e8e897ce8e6c9a8e9975b39e868fdaf72c147ce7de6b58a894a489b9d1a5cc224fcf01592866e185de4b9054baa4d218ed679a2e6dc0fd9ba9d19d0b5fe4bc03ded9323949867775f70fbd5cbe817af785d8eac7873b7b1d0305a36ad6a534b3aca8ee9eb4ce937c19c20f4d4c778ea3e1eb2db2daed55f8df8474769f4fe1e1480e9a6ae438e153fa4927251b840ff989cfd29d49d2cf6d182f4ab492eb1f41d0123d34fbbad06de8c4afb072644101343dacb8b1fc19a326032777931a31effcac9f66f238f85a87e9af9ee1cb6e842b7b695d9fb264fd4cb96ca772f74d9bb9ae79c9b9fc0631e53c3d6b6140db8813d7723c6fc764733aa15a0e28666ae80d2a29d4cb2994dd79e760aa639480771a55f80a1c96b9e9d58e9c74a9f2b88cec9808e9ce2190adc31b055cd60f136b45e86329792e8294aa0ba323e97b03d08f38b91159961711f2872395aebde6f2dd176a41b24fb9c2c0953c1fdcca588d6bd2f68732f2e4a438c5fd0ef77d672defd32676e1951043ba507876676143f8fc1c3da2b0a985caca59cd5ee9eeb4bfd225e7228366b0a9267c204cc5a6e8118c031ef2696dc4c8fe513b3ad2c0b869f7d737dee3da393bc53fa90df8218489c4a68902b71a782df96724d848f5b3caeaa69e1e9bf4f988c2ee46129768611e70c8a9e4eaca5abd40b59e8d1ef215d800d7e2f4de3ba004a6e34c3bce64c63a83b83b2bc98986546452c1f3cb995772afdd22c441da3a4937b365e2c94b0ab1813c44f11a8fdf1e23c93412bb3e0fa5ac3efa07350f67f5f5cc608483201363b7b04c65a034b1c7ffb98ada1692f952dfcffd985f0a058f03d2085603656c004d270b70a39c2fe5f3ee133c81eb4cd6c1b1ddd5efcc40ca182575d02cc2d64c087ecac9302b3eaf5c9492279488da506c62a6c14f05551af3468536e15921747c80afa2c1845a89d89fe49ffc988a94954d02eaf281a651c6ae580233ef0e95697604519576ce4a95a5b64ebb682b80d4bfb59c674f679ae1812c0bd725f7d52dbfbf3667f55eb9f0d3975cdef3a200403d85078ea3fb3ce804f973b4fff32d60cb62b6ba30c4566436d93d1688b77221b12b94be1b857a8e4beb33029c854a8df1168afe1b4cb355e7875ed80e21a29fd8962f8db46aa86d7f2d2afb11cb64bb1739abe37a120abea91acbc2c7df61feda7a75637b880f544c26157f40c5f1be1acb3810a521b09e72aafde157ebb781c8cf00b0089493b676f9c9df65a2b2f1ea2385c9477f9dfe0aeca214b87ebf75ad583d77051421cfe6a9261282d26aec2bd68112e424b7b4b9d90df3a0030f6850387192a16d69484d4ab64ae40325e6e22a5405683b2dcec5cc6fec81712c267c73a882d55cad6218e9e2e5964d1c832328f0c7416120c0ee893def909051a2f18ee6e06e5117f36b8a39bb7d3ccac707de0fd8c63914f932a0f42506ae853425731baed4d794f235b10d0138ebcb25cbb90dcdd5c9785a10ac5e2f4f744ddbfb951878b1b1d8e18336ddb836405ea5e933c8ca8c46509427d9d3bdeb8a8b99f9a60ed5ae37f89346de14f9672dfa62ae2a41b9cc6ddc91b1881f0a70979cf6fa4c1a9059f7e2da42b543a79eb84d79118ab1518db68f412e810505bc147694798e65c92109d9fc3dd6fa7ccb9bd287f6dd5ebc3210f5bca1701284cf16d276ee6b4e01ae42752865e0c2174fba894b2cc8bd8cf74a8902b20d0674df9d32a841f4c9386eb400c64d19aab47354731ac568faaa79999061cafc2af8f6c5c80c7493889330d0003b91d5bc0b4a0a163af327d85dafc902c4b238419b5c42305e85499ebbfc31593c87fd7c6deefdc5b5e425784857d0a6bd3cda6d606c72c897471ca0e2410eaecb60d72236a9ad99538839d1a23d52ac558626316e2b71dcab2a93a6319aedb4e37ba0931c30cffa60141aec78ed8fff6d08125bab4fabd9f377f95263f84c8f1868296e0f99699073fb702bd7fe09dc6e552cb15acb513ccd0e9635efa8815e1f2a02d3de76efc9a553286d4e1735ba41eda59405a014e5723ae3877b360b1da6468c37e6559a82376d3a999479b6977c1d3b98b87129cda31e6b979a4f64626dac94d0461f825220c56170cbdf4c28d6134f21fc2e5884db28fca3e93882cbad14640ef8c31a0dba4e34cef205ffcf4b10c390133dca20ea8b86ef1e8d3b712f97b9e0d6fee79b1095885fccbb2fa5282703b148f63d97f1e9c9ec762b328bcc99884bf3647a209e1c979ca2a546eed63f9a32419530b6beebfaec1a09b133ad36bdd3003edba67f1b7e3298598f499402bfeee46bdccc8197f5b7c0dda27a319aba610b23ca7439e7da71024688b9a8433f71f3d14cbbe73e160e91b8a47f2f2e6a0c653af86ed5f4c5f160bc99f8b66d9feac5e9c1269ef6d2503eb94e8a793d930c8bc820874a1dd78217ef63e742a639efaaae5fc11f85a2c7d64632764122b9beb641304b625678644dafb5ea8a2b791dff2ab590c615170a690db95608fe306f4ef99c5c0f9d95bb6c89832ccc0ac3182873a447bdce9317902969ff2a8c896ceb5242d61b4b0485f764b86f94ba2cd9b10469d2ff362280b1942d4096bd13e48620bcc0a150e91c4bab64ca715ca2e881250d89b537cee642d2f520342ad81a3066987246c743d2a9d549a832a5f8a7f5906317a0f4f6029dcdc21a1bb48f96b40c40ad66e97a27d3b2a60933231d88fd36d82284a5d3cc6128458764f64e451af23456d15cef183b749f190ce71c8aa0802be6f0ff8818cd66f389229869cc2aa8381480c65a79dfc318b0bdd7d95f342e153ba1bdff3584bfba85739a2b432d7374ea5aca082a3184b39c5377b32ae9967f0ff41d59bc8821e029a54f37f894ac84472431f664ba341fff70662737f551b79412dd6a13d762caa81dd7d7d901db664cb0fe0dba2135312d50082d6bbfca13b2986ca267fc8f32134b58f60267e5441b827e3fa022eb076068ebdde0e36dd6b3f85826a8780fee2ea841227396aeb8be2491e52ce3ed9aedd71ce5991ed07ca83796343753ccf8d285da572468f97bebff4cfcf72423543d6bdcd23f934f82fe4ca1c6bf26105686b35fa3d6293d036b29404d18fe5e4c58a854e6598850bfa331d9b061fe2647cdb24d8a670acfa97397b5ceeda871b85d0ca179bfcb5ffdf524dbd08c19f05d303ece99e069bc465fedd4e2207c1273e2dfd10d1ffef2b307523c751480e8dd3560eded2ce0d631ee80ee15d6d74a3f3eb5c6f07fe8df9a9e003ef6b8011284245cf4d43f60c100cf4c79812767351348e4257b608fa11cdb5ccf6e2d4eb42b7328719eae29055568867dbd0f918876ce624c6147e9c8cfae3e3d3873c0084a0dae8553869b1eb4ee104b80332fb802889c84618edc1e83c1db5e8e654541c1754a187363be7fec74464589c8b3fa23a6342ca52433d0f0f3d7618362e3c29c543e6e92fab6d166deac88baf87da7032abcd2ac06f7d90b19e74e29c2ae8749a88f157326cf586ae52a98333eb0d1b47e1c929a506cee62157e6f1b6d56d97dd440561fffe25c2d585a59f195e3ed2a913c5a83a44e37f4c2d54c348e2499f9e836b91fdecd02415561d508919c379d27134fdfd71cac06d969152cc25078d10252e70def6ecc9d62e93f062d15ed20c6afc4fcad2327b14ea5bd1fab846cc8f317dfafb0926e3ed4e9595bc88b53acd5f7d564bd980e102f3767e8827b07dcb5e52fd639b97ba2c9a9a7c96c91c87c66f3572226421fd2f865cb6ab10414f9f76bc942c3f894c1792187e41a5472a82d005fab6377fff6226fe4ad08ce88a6b684ceed4b58f7b50b633ea7c70f4d2c14595314a39b3f69b0e2c4669391e1edd4cf27e05ed4ed1ce8f9b8e5cdd0a74da40c022b14e7a5b22129a0a056ab5655af451309d7d3914e15c66362efe694040e37eb8d4c24c75213eb87a2e221fdcef76d19374d2197b4ae279147ae358a8be68265dcb110ca49b0c50eeac50a230e202385169af9ae5c5b1e975e13e6a54e9873d838573ee9386f1c73a4d66ff7df1bdfa5c73cfed44f86f69127cfed22de91619dc4c5e6051ff399ec79d5e12ec5e6afff8c128cdcb936ea67319212d9f399bfe4d1e100f3f0a8f69c46dd0b69eb4f7ea0bab2e63b368629acccdde437ba5ff96c139bc9015a9627a4fa1686e59561d7e9581cef98fcc81a4552629dde76ad2cac657b3cf54c19413011395292afee564d398a2d080a552eed290263b8ba5bfbfe29007b96f881ad4dc5569595a6da5fec9bd0eea4972579f672ed8bd7ecd64771afeb49e526bb844553dae9ca0fbe6dba2f3c6ae7daabeb4d2d3b6885a217e24402d0c4571c2f9c9bb0cb17292a628d3633e59d453bcff228ce4a6613c78d76287b0b0622da00fe42498449285e1500086aa6ad70ae38c11d2a523b7bccb6b1ddd1a1153c35c5290c51c30007f6f50063ba6d927fcf6efae2eabe24cb297fbd6a632843ec2dfb84cb3c63ae1b4d9e6b50907e11929d2b207de4d0719fff598476859348d26bd8d38c6203f96e9f3ae2b9f09a34958456764d89f06673ead97544690907a49928621fe44fbd1b270d08a8a449eadd1d8eff4119d11a2d1d72626caac47d8f8a29593b38874dd8ad9b3e1e77e82092ce687b911d32f4193f8c0ae3809b6d5a861ba87f3e12e842a0481b7004b45ea85ec7b95e25f003a558e3142212c45bd7ee3e8c80818b1be698212ecdefc8b748a5847738bf1f21671d4cc221d8178f92ae8209d720d3e855da9df679902dbb453da533e5635c59bf5b17d9fdd22a9eac9be893eb740dcc0dca3e3aab3259411c22cbc586feee16722eb9fb45ac488b8901e14f99f6319a00c6a759fa4bdf47259328dab808be6d2e950a3c9a0e5154213e88cdab5e9810af2929d56fbb74d56f9a42c926e907ade37154c34a03aa3bc47836a3751838995f443973f59bfe0403fbb489bbc9faf2dbeddb9aefecda66ce72c7bfee511835b37804a505a043519664fe30ae91517f441f3216aaa738d9f4b2bd742f3c769ea2aed77df53cdb74dfd336163aac5d966b387da5b7882d51b089ce4fe4cd826118ca200e27e54c3dcfd2f2b057dc010cbea0de457caae5ee3f34ad6df987de16619c01bd2fa9cdc0ed683dc4d3beeacd8bc96d240ea27953d07d36e368de87d192da2a9d646c46ba41faa23a04c658525c7d3bfe1e16007fd73079809a51187ef033b17c48394e8372ce6dc64cdedcecb59de5f12ce5bebc5a55e76c81d30bd8a054b17e156e02d376451c3a6c4fdb79033150afbee91eb8b48dc85734cc85c86f0a4b0db3350f90ec8ccf87338973a1b02cd929115000e4472ea5829fc05566eac1de63d65224c30cdca04926e4ef3aaa70c530a964fdde4be429fa020ae26dcd22ab6962d96dd48b254865e0306c068b453c6dfef88cf63d99159b43fb894ba3a42afa4c7ab203868ff6d37eafce97ec6907f849f0ae7a73059aec6f634a0b81faac69525326bdb44d5c5cec3409ff08217e905c80e27f6d47c2efbd45f4f74af7801da83d81e53dfcdbb5e012b969f8ccbfc3981a6c2a2d45d33fc7a858bcb31222a08a907b1b99e98b8e7f45af80290b7d9c8e414d93f2c471922731106cbbf20e6b03364d3b5b9d8c841383b86912e2f2723bdc51cda749afbed0d5d32767e1ca7f728fc225ea4aa4c21892cf4d1407b3a919caaeb000af6c2e1696c4e112e35c27a075988e705f197344c719de0e0e9e522e7c84e42fc44a3e09ffa7f6730d118ebf1923511bcdb5825abd21e69bb385e30d24128c2272052523abef49ae9b6658af6b4d23af300d42fb3e4ce5b63d9b9fd5e21f8f0a03a2607ec00ddc29e65d979b51c1abaa952ebd825abc90856af10eee8c0010f81c91c68fcf1e4c3d8ace2814468dd7d7cde1a80599e85019ce8cdd66284fa15bd023cd80e30b04f0ad206554952e3430182c8162456a4933d38b8d8ba1e64d24be4e0f95a87631a8f2284dad6eee1b66da0374013af62d39d97057487073d2db568db8e14317efdf03735800599632a17f26cea6ef1dfedf5125b28bf9f125b47edb8ac72f5a30ef3ae661e7d898a45cc8900bef0c4a90ffd093eeec758295575121074c7395a21f790f9666c5a32db3ba3d1c5ac25c86ec6ce968481cbb8d7efc607b0a10b429e1c5c896cc0b9b9fd51df8db169ff283b1a7b5b9965c51032e0b855bae331a641d7f309fe6fd3700e07c972048e19a920f265dc77c04f6c9dc22e3c428ed9c876cde51be8df89c2ec793977759dc8c74ba6acca72fbdf06b289faf0bbffa42a5c623a7338ce18e8dbde12ed2eb9bdb45b10b23e3e47b4cc91429258d4e4df993558fb526c71b4072769eb6b30b91cc5e245c0f8af50223cc30ee449de38591963317b3c992f17b5c9905e24e05bf6800f269d7787cc34e912f9f995435a51e822abd83eac72f05eaec2fdc876a8dfe435cfe079a996bf468dd28cae8c49d0a83df82bde01759479ae551c8506eafb9cb99b66d3e9db75e4123fd648135adf13d8233153e24f8684094ee4cdf650d37e801fba7f062608c88fa59b7e5f8028c5855f6ce51cb23f936c5945c8593a53cdbecc8cea6dca14149f37767957fed4e08bf804c8bf480387bdcd1a859469f17ef8033c831dc59901a45cc5071e6347ec6e0813224c141737ee3ac94cda27824d96314101ac217880fdb4cf749f7f9481e7ba813d6ac8fdf460beb7b73d700ab3ea9aa45d679500462c8a4fbaf4240ae0bc3b1d7f732026efeb80b4b5263cf8e22e883a7545e7c9949f97666b4f0ae389a44a1d5a284455f676aacf56b9441fa5b3eb9a56ea28fb45bd30783a9b527f7b8e47caff6593cbe8c6b24b0fb3c485339f16706e2fa57567492af9fcd39b469eef82f632a0594717d4dcfd6967def7ef86c912ad0af92387fca36cda664036d820b028bb37a3e7a0f86aa2b33b8871485c003bde2274ddc9e762e7f767faa757318bd20dd03131fd6df8526e9e819f0ce6a5f6c16ee3a1833ccf3792915a8e92674a1eed499b20461d6143fdf0a0fdb1d3770dfcce98e34488b5d38a774d9f020cbebb7cb74f192944c0e095d9ea28f4590b7da8b5275a78178e8dd2cecd725235d5812dd02c55f9fa1bbdffcb9fddd84b86320ca4e454c42f751fe17a50a5b691c67fea43c1f95cd17e6ee0017f79a452265ef6b8dd38b45990d3c04409d28ad678fe4afa34c12414c767d73feec58497cec6de23b29eea0ce0992e5ef31428814a73322b4b5f113e0eff9b16bb2946c6b29d57427a668ab2e1d7a041f4759a9e5cc2e738d4d3cf23ccdf92bff2d8c0c71bdbee9e6b8efd5bff0da7a9a94e052d192b054be8023ca6786ce95aeca06a64c10095a9bbff0edac53c6843a74b5e1769550cac65a74e79a8203ad57e92b50659842b7a7965b1b17cb3cafa4128bda1a11463bbf5f63a311566711f77575fa0a3749eedad32066a54afed3152ec717c55d7595f6e6775ff70fc55ab623d3a3653bcfc3878f072601b4125b1299282886a6c0a2d74ad5587e0b86f92cc7c4e755c843d1c5719096c20dd4830afc554a4c15032577a72847245dcf02c92f2c9405100120cb8a13a24806c0fa04b54e45d55a048e9f5f6218e6a63c71e308949bbdef82079d26d18d5b1ccd30af888a977ad9695b5ddafc136ed752d53f3e85623d12ca017d6d1639e1551443408b703a9482ebf4c6daf02683e1acb3696780c3e6260ccc78f759cb0b4fa9591c6ed66760484f9909b7fbbcc4aa427133d678b199050a680deb95b7c031d5e23f617bd5b9993334d1f30a21d720a62c9bfac20e583f4a4ae965faee45df42eefe9dfa06cac54af76c2f78fd6d455d31f8790e73e3912a99eaf986dae602532a396688b7870954c220f6c18a0ece5640b7ec94f99399f6de1cb913849b58cd764ee703c21d3f1162a73ee7d25a98fd7fed9d7db616deab6bb957487c3d3c9fa3df182f333661ff79645a9224426b9246800ed3e91feff2a3a3c12109dcd14f274c20569317a857ab8cf3c1d98413106bea9c42897daabae5c8e0451658bec8bd40129cf6ec0f4dd6f0c9dff1a1286c6beedc841ad798190a7e99c0fcb2072e6e93eeee25922067a14127ac9da875b9f2e1a600dcfa4b1cc897127804abcab76318f02f27d34e23c866069ecaa0fac884bcca504fa873c02e952c7bb457d93103a415b305cf429a17fe3fce8b7933a082794c0d09386f3ec31d0d728cffd598b0beb8a8d07353de0154a39a5025ce2247d753816d6d29b1702b094511f747204292d80184fc6bd2035089f98080fa71ee82db62fe707ac475b981a0e021857ddf1d9e93a9990bd35aeddf43c4f89581d4d7514adef7fcbf2d16abd5ac2bcc06f886eca23d3f3a0154894dfc6579549908b388600742daa9b9775d3ac52a6ece7813efc05cbcf3de22221a4ce558261b104089047620f5a2b1844110d2d5fc3a0ebcd0afa1aabe3e8413ced9307541150ab427448454c873a03a076d716e24a896349b7d45d828511f19798b0222c5a04ae562339da6ca0a04d836eeef8ee62ebfdc42413ca90f4c6b09907dc6451da5504a001a0244bb3a1488c3a92e5ceae11d29a00dcfd29de8d3271a32807d9840f6a6dd19998c8829ffd82227478468b7a77f46419d1bcd4eed27971be9064f2bb41ff4c9ae5772fc6289fb6efd8c99baeeaba9c1830e235d1d87efd7304d971c96ae281e8052aa084c8420cd392b5786a05fcf638cbe588f1a7b275b9587b0b9cfc1513793ca7f78866710c2d2fae99c9aca8e1389dd0b2f96dc35ab940a2900f3648c104dddad31482ba6b8e1dba874a36d12a2d1c14077663505abd69933778bc43a9adef8d79df79225cf715c7405e5bcd6e43d7aebb282ca0f9eebe209510572c3e18e1fe7aaddaf3b5237e9d69b3fd8d4276858422b4bb189d6e1418ee53e19e658acc1b227ef99348059e013ce66097fbddb1db80931ef6e8374d5b4ce21742891fd02a067a9a60bd4bbeecf772b8484c3dc54b9a36419cbd72bb9d601951640aac1c6f6304467a49c2212d1bcdd8437b527526e72a08036cc7fffc2aeebd4dbb93cd680ddf3030d20d87298f4e7a66457f687af67bfb1f3eb04485b990b014c5a0d3a6dc649e21cdc997356c9f58412943f41c0d71307ff2790e6042be2097550f68256cc4711f19a13cc20ea6f994b0c7960628b762ab9314dea825045308a2adc167498168bc2961d39a43582c09535c6aedf9b2ff3bff93782611c71db7ab6b06ead99636410ceab8d9e8d02aa3c8de5924beb8273192615ea8c8d81f71e0ea3f352cbc18e8ceb143a1ec0d93859d45a6ec36482c4a6713bc73eb9451ba56bfd41b7be2c1fda95aea8a74e1416e9d50d5ee246a77003adf9e1cc20f06f69caf5ab3e52424f94d3c99026d158a6f44dbd0b6d216457752c4ae4b4673d7e515fce8f21c0359a125895ffda9519da74142c7c7dc3df78b650259be9d8ad1708cdab6ecc671cc0697b7a6fa003bd8fc12c0dc2937c6efc965d6518643df84f311cfc55044ca8766d0175002800139ce35b240abe1098848603bfc114025348544c57f53d401406f9c794446b750a2eb1497a5e3a12b2c4691b942a7342dffaa69cba57173bd49788634151295609607909d5c2100dc6f856d73c40dd2da0069272e2c7819dfd22f02d9b404f9e8fb80ddedaa29c0377ca003d30c816113980722f70728aa41ad9f78f21ed5bb6af8911575887a842e085dc2991beaadc1b97a993f0eceff212fa7c37ca2ad5f03cbc22393e82a70cdf5c7fc03ba9f77810ec0c519c07b77413f0a94d2e573b20ce1d39639ff4bf11490ad96715d2f0c7a372f1728ee82836bc638f26737aaaeb2a28029914e4ac1629f4f495878ff8b0c9688a2975d1efdd545d0e7ce11d9d4a6e28844941e9d81cfc3febf7c9b03b8790587fe7de8576264d0c310e5a4216da9bb5df9ad5db55dcd13b0b9102a0148fccc78dfd3d184f1967a99fe24097826882e85be18452c7dcab545731a3e5612d9df1bf6934faad774e307b09ecae6c885dcbb7f3f2cfe735c4dc4cde619c5c93c36fd7d49a7aee96c63513285a792164ec430f90df5fe18f4eb18b8c057076d1c3aff90ccc60aa00aafbf2fe355f014436e3321309673489f1427a9ee608f60f01a8b6cd063985c1de0af07b9988a0c6663667994dff7dc2f00aef81c435abdb3396d20e3483c4c330ea24ccaae008ff3e3048f67962d59b3732d7a28314b9928a9a8c50e3dddfe965ac5ee6c52f1dc8eff1e63c39c3aaf43f9d452fc09d36c1f00abb63bf58da4a64962d85401f495986f931bcced19905fe582704a9c771fcbf2c8b6664e600b251b0efa929c037ce07bd9ceef23e8e89d892b5a943f5a0b47db14bbcd89e5d155ebc819d7c03833c55331ba3d138346d109a2c9161e84e20f2e0524f41885cae243c6693430bbbb54211cb252eaa775e45b928b12340018e0b43d19fbbe9889ff2e461e8fc92089b805671a9524dcea3dab86263f50646e6eb64650404796c08589275103d0f13d376d97402380c6caafff948086abe6d2c7958bebabb6eced6f322d3a8fe3d0e1badbbfa98aef94690c2d268e00322c4dd20afc11b83b4af6f045dfddd86b71773def47430fd475142efc60172f95770f3690be1bc0f04672a5d221d41defe271dc5e1007dd46d06103a3705a5695209e36c838ecdec61f3a920e28ae6c73a46098a4945deb19184f433579b8843fe7a73c10d53746c7090601d0ecb4950816f70de1c40ccf5083875a2662decef156a40d2e5e4a4010acade4ba2d8cdb97d575fe80e0d9c393b3ab661fc342514fca0f0d1a57dbcef1206c09f8ce9e823eff3e3678969420623707c72e16591c142ba79141539a8df3b92076c83f2bc0fbb115e46712a9bd9833ca0d01e4320037fd4db13f57f0cbb8a381dfc6d08cba7ccdfb0a83114d93f9ac223dbbcf9914aa84e7461be90c7b2d537373bebf9d8975509591f907620fc1e93b0a1e5b6756880d51eb8fa407c1d2e55a25bfd3f69deb2ca95225cbbf8d34b0f430d9e6bb8c4af3a59ad0ea351f1be826dd252d7900fc6348bc42820e1ff60e3947d27833cc39ca8b1ab153bfe6af661cc5d013957451ed6d9e01bcf8c2eb1d671931e0c7590d22892ddea8f0a24afbd165b1495bd7a37bec7765fb72511b60623443a2a03f4d0a3430ca2c99c7108276c6133b00bf9d000e75060bfd35bcbe34e95a539789b34a458299bb7c58c59a649cdb49b4e7f86a153c44c17d07830761f759777a9fb8ee6ef6724e3e99846cdd86b13ab49c7726f85bcfca4d18d3b0ca46e2bbcee198ae903d8b5e73ccf88bebd0c3507a772f6cb9bfdbf95aa2735890a4f4fb3930a4a81fdb791d50e6a7a3c3a595cee78276cb3a360f13f51596b78832976c6b5cf449cbe875f71ecabef807cc6a6a3cedf91ef069f2387ed4fd042d0367d516f40a5bff343cf52dadb400036cda487cf2ba35746c0f47770128138a8444d3cbd0b949339822ebe900a78e84fd98d2b17f7a92ff1491e075393292d93d985ddbc1a54dcbe60b6dd812768c50f0ad2fc059c133b522719712518a45bb7b40e43e76bb16a29b1fee03a4fe1c9645b2ed9503e95453d977a6168f07e7849477be101d127cb261d5b2248340db846aaa51afc23c78e53cb9a9100e9bf8e3904c8d5826ba1524f4549838666432262cefcb1f8714a57620c103ac40329973cb95c44802b22a539921ab8c423af3781bce043bfe62c78834631d1cefcc808d01409bfde1f1229ef04e6bd498f06a2b8b6451dc5e34412e101278810864462b7edda068ab79d0b119c30fed017796746c6c42304936739b84eb1888bd674b7c1ce2990dfd8d6c81520eed3e7f73cfb8558b74affc945e64891811270881ebf0a5cedf312b6352ac6e8986e45c525be47240604df41320348481d1e5b9ced433de1f4623f4a8ee0c3b49ee7bdd5f314fbbd413f2b9e2d94ff4f174202a8391304aed8e667a36c8933a2eaa6f57bdcfc4efe1c094478056bea8b7668a8c0a7aabaadd045c3d22f7bff7018fce8c8541091dd159f0b766a4daaf0f46d07497d1ab18eda69eebe85a2fb94418adef946029d3ad9ee6a687c41a396bf757f2febe262cecf7d9f39d873f361f1fdb94c59d701adfa1e8602cc76242e779dfb5c96851bcc9c9480683c2ee5550519d79e4385422f48b5589be6774a29748d9bb92ab05a819d117a58c2dada8d94ae2390587a037f6334c572323771eb1d43892de1e3da2fd6329fd15e22e2e05ae7a0b49052bded8370409ab88806a875a38bfda55d84d254c1d9e4f297586e6b7e6d9e0f35db4c0c0ce8ad5bbea3c18c0948717e69365091125dec3fb1260c1a23cf921e5cfc8125171f54be1ce27bb6faa4e935fd72561a7ceb9be3f5b243cd0b866c5ab5e9988e7d357ccf9d9949a0b6229d340c0c5783d07d8f5c905920620f64afc05e15397f30509aad0b91a71e4bf54b3b5951575e70baee3c046f2e770e18b7f9e94877b7dee96ff766a0057ff3e3079410cd6a755701680a6af885d2d0af04c24c6292c926b29719a499e486aff8779bb899bd62b28f5355ece17ce27962be7533fbdd16baa81401ad132a729e02c5d1365a2642022a0b1b5c9e73934a18fe998d646886c85bc5c2004beb2399d1bfbb2bc51c7350b9b8042555efb6e08ab37af0997eb7e80d31b0e5be27f5e3af2f363b7df0ad3f6667e49f0c18d21636d6050e86d049dbac3bf0f13a5f6d7bff544d8754669d084df3034c2b4bdd3a239f920e97340cde944a52e9cdf03c55fa318fc016dce68b5064f179b05b05b3cda9566eb303886a2c5f9aacc67a39ef9c02cee76656946cd099e905f2addd9d59cb16cbd6510a5873bd6ecc6aff7984c60ef7d987aba467d39ffeefbc5ca4cc2bf6e82a508174fac5a16c27a45556d02bed99f108c1f382a19c3c114647b239319fc6ccefea0d3c5025cc654c3e19d9f87cd3fda7495e90687c7475f2cebbc294348499d4ddec668acab0cd1889563b2fbea86a9b72ab84cd73a2a9b40f8e926f4b5a23af92a06317c827e99bb08b2d77208295fa3320063e8db8f9d6f1705feeb71db653aabd75f8d34bf041a759d26fb3515a0963bea9bcb8b52d50b6273d64f4da2bf896bc1eaebbb9246ed9b3aabd25043dd743278e7ecf1efbabfc879f5f83909f8a7be12e1c2bb9e00dcaa9577eb1ec9c7d0d1c967913d975b41d544e05a9602b77290c146756095a54bad923d15359d34815d990500b70d529bdfd1af8fd05aa49793a4dfb9086d62067d5fcd5b9bb10357a1b808e5d6a7f6abd8cadac7a2ca1225abb7a792765696b91af7d3c06899432a8f5771ea1ad6e5b350914bc04fede83b15d3e85f6f79ef977fc89ed211efc931dba5263a1f944a3d8c8110d2b4073a0684a481f52a0ab1638a6a8a0fa5f2026f0dfd5b40ca7528a689576f3a55b71b31c0e5a091fa3a3d0a93465c9bc6d85794ee8ebfc901c159473fff0f3c7fe9d013a1020ced2e1c435aab7d79edb20c44c22f1059e6efc12d920a77e3e2b10da8f002eee5fd51fc63b1dae2de191008496d0b1a067bb3950c1e3c9a51720d49df4ff2d9e414b78828ebbfc9b52cddfcf9d8f8055ced05d155358d3eaa938bd594cd0c6eb6d2213ed8cd17371625bf596a32ed6772c2ce3e7dd6a2ca03810b95a5010529ae5572a4723efd1841a34c3a8f795f50ffc47e4e5623a551c1bc305a38b7d6e4c347b2178015dbedf41960130e1d4f541adb543eca13daed845e2a36002edfcac3474f77eb89964ba6eeef864f3ae0a4eb9811a38f3649ed54c2b1b0d9af9ea70bb8137e1846001280dd3a9425655e06760176d152d8b00baba85852b76bf6cb67387befa9109094c539d9d7653d4116b9948d049b26b690bf071a403377e9626f773ee9796273dc72d9acf0a4701b2330ca6d5bc55ad9ac98db480702a20ba2c6a5b29e87aafebc78674251b5d0a6fc15138550a2e23ad3757b9b3cfb3d0db82270a9769ae138e3961e9444b63013e9faf6600c874646cdb3d5ca8d130e2ee45e18fc39109c3b374d6ff69dcf7fae4abd206aa9757ad70bf40c2d6207bbc0417be9a97f81fadf200a888ba65bbf124b81050e1c34d05b10c3952ee6bb44d9e4d3a03a7798f6699788fd6698e4d7cfa6f7261a865e2778368d3ab615f4142291b91d089ac41e9ecb7693059a5a752aaac45d4bfd73f8c364a4e1b3fea5c36046f71c062ce929aaf84a8b2aa57c64af4ff46af7db7590356b12ada95dddb02443c6a13b8f06cd7f636d91c61dc53ca633dfd048dbc75bb775d9b4ab7ca69116950ddcd74813a0e91ceb20bb3946531c5e8d7d7dbed7c06d186841ef025c3f76cb1f89b61ab20d8e0800a659fb1f3ff833c12f9a5fb6c12d4d2a7237d47bff5fad456f7ab81189ead6be1fc70de8ad64a0b35b2b70bfa911143de3fad9bafdfc3fb22433abf19aa0603b08a8c478e13b70c943dcd0988dc38fb9bb60f5204e882dbd4da086f02f76645cc132acf433bb634d1af77b53329390d854a04935ecc0ff939037fa976b6197e963042093a95b1b8e1b93c1b654201f21fdcfac8a36fc6950b42193dc34874ed23104a5a08dafcc66865f7d4330b712c69be9a92f0addda01a8bfef527820552845115c8ff23330eed2875163ec0abfd365ebb85800bff030189378b5ad7632dfc65c971171c3f38fe1b68dac3f57d6246cb2091b4939ef6652dd3819e60b838997976e3eb59b491c376b8d525137f0a44f46f746d357fc7822298419ee9f10e085d4757b1249873251ad82a3464e41b3be65b215798ec460c3266b0addb76525e5926db6545f6c763173879e3f70f6b7c62f1125a10d672af5ba36403a8fb10c216334bf6fcaf5c859f82daa914b03fa01f327db0c1f3bcd9c53234ebf2c704acf7336cb1071911f32f0dc7338078a9746e70c794802870ee42c5a1ddec5b29ad8bf99f6016830627c1cb479de7b252abfdc264bc1511955b5d2c967467fd4c75011037a3a36c29dbc63675cc1b7a858f0662711a6924e4d7406adf27222b8bedbad042bdddb1df349fd3160da3a00b70015ecb058ec6b1fdcef0cb83d757d7c93c66ce1c64b2276f087f654934a366cf9c87beada538953428485f563169d159a77de0721e0116d67ae5372db0894b64bf0b44e650e2a6f51ef8325db0f06c3db0a84e0c540db5b481980313a47c1132858c9ae77a2ce74787d584afd16262e075dd0e326cc2b48e46fe239a70f9a72ee8cb9f0c346dc6ad0f876b366a0a99c6e2142e572cb6401b6a4b9d6f4864dd06117ca7ef9bc628adca655d05c80c431934233b6857dc6e2d8139c3233397e118e204a00919618c58f3a8a976ffc527a1c8a8b5247771f69d9e5b37cdaa3fe5f93572c0aea54b8fa01f1711b645af0b4cd89d9db5b315164cffa2d1aa6baccee201415647e91c3687b77eebd79f71ff932fe775e811db98ad0222c93c480636e460a16d6dc3ddff607a19a08aee1299b9b2bad1b6b640cf80f4736fc373ec1987db095f7f582912604588f0d33670fc62d2a2d5556ddd332a489f7e970c16f12cc540ee1ab98f8485ed9f0025f080c2c81fd50fadd0857c2211f2f485f8ba8abe0701e2a19ae3c530b4b5a5cd6559ed2a21dff5145dcf1871bcf8a8fd0b76305788f05230891154f17e54358646b1c4b2013357c342f919417ac8931a6afdf3097778ecbcccfcb222414c98f13d1aa59b297ee85400b9a7c596459a6bb2e30c42e265eda3221542c37026e511052b61c6e2366d8dbfddca9950582907e322f9439954928290c587b6b04e9148432748fec0fb0879fbcbf0b00c3995038a5247cb87aabaf2d05eca4fd07d322bda2bbd0de617a8dc280293182a21bdfd2cd574959d548384d2ee06de48e77d7bcb69631b25962ca90907926e336db8cade34c12585caef3005305714659947a3056abe178d0350ce62c6f484a6b35c724c87276ad46006cc397850faeb12187667fe82280d03ff1be83d2704e2527fe0af28da932743c13105da33a9966477c444504e9ec3ffa5a329604510662bdac85127e08bc871ea3a683ac7743d04d33c8c796ee9926c5470198854532b9a0cd3e245df0848c4fa4f1be0325806a19c71d524db9f0ca8d4fe2aab99d2e7abf2a6f44ea2b4b42e55273bce305bd9b2ce92747ff18f4d2ded83f382e51d5571ebfc103dd63cb902ce8e8e5f419de65cdebcc58f3dec7485f01d114ab928a8bd3779f9e55c1c1ce1c4e77ff38c271834874afb7278b6483bbbf90fb672bd66a7a5467c171cac3c1065f19bf634661e63f2a077dee45ace04220b0e4e6d95e816e8e6138bcbb6065a348c35611ed153c00ea7bedd9c35981b750070bd1624d6001da25a851dec89ba87325450202c985d13a3320c6c097e5fbb5a25a7355bbe5a7f6dfaa4a9714091c6631639aa6eab6d65b602206a6b57944cc46de2d2635db81174a61b98dd01bda5e1a943665f5acd0edc31ed129cbe9b6a72e47cf99ec66d5a9d45c7278f91670256c8e4252cc2bd70d31952424819b61d2742265d051bc3d71adc1daf3f29b8d5fc4644a564a22b163612791cddc60688bd723f19ff61da8d8bd9df8d5ec6a112e65d39f5fa92124817cd5d31c86a272ff6de5f71521da0d58325e56eea533fc7535a0584867fb2d648131abbd275a973b6bf546b0faa4c151c71cb9c60e73b93bc20b79ce9770f203e514924d760a0026acb7a5284c7df1e47b6e7314d623826d5433bd894f6d1c62f8222a93a200768d2d72013cb121309f8e128bd5282aa6d643c93c4ca0ec3d03d0da94d0f5b8366c2650ddd1fbe199b5d161c45f7db71a9081e1d316f891f8d1962d7ea2ee892ec9d51078f4e7ca093b2496afc07ad79ea9758ed563ebc399d9773b7552e0defada519f1e837cc70cc51fdf129e503c224d5146712d4826d5cc6fc960c3160090d741c68e05b0ace4daccc876db010964016f24254ba239e298bd11c3f45a6ce4ca9e16ef1114c07379311f6278481eed7d6b5de70951575252946ff2e5737d7e341a3eadaf8148f30fda15346eac3debd19e3c21ef3bdd2f992233a6eac449bdc27ca2a4abcee3e870b15ce015f5bae6eceeeb157d8658d2a64800145629962f34cc530538613cfd6032d5d6c7ec0e6d5d38545407d1b4f7b46653bdfdef0e0060ac8b383675e7a33ffeb77546ea0b842d90ffcaad16036a09b5c94d341991b4a9b42d06c829ad52099f759b19b256c237b8644794e373a74f3600cc02dd343c2a65488a1c5a02564a9cc17c1d03cc0f2cb33e146e1e49ac2b5c385275bd31f8aa5a0ecb2a1304776359de920f5641c131dfcd3d9fd498dd47e8c960f4114bab3bbd5d6ca6433fa91d6fb49a532c047587847adfc380e19030a2fb8f8d2d981cb1584d9cbf0db99f3a17dbb5a7ec26aa6da369491b0a3e4ac853e3fe9538536448057d83d7eeeb485417140f76473d78778dbfa2e5d31af42dc4bf765dc65902724c4a7d6f2d6a6659cf6b8335d838008aa20aa28047c01652842e0d3142c303f993c23ebeca7090f4fb263891023a4f81c1c9bd7724849679db44837e8d2e65fafabbffa0e9b0768d0433edef798baeac99221a420abfba5917b910154658edbd9e5e231d3e48be2af51d0630850b0287b9d2142eb11316a6973299680b13fbc9bedf138c1486223ad7bcecd714ecd14b273887ff6fe7f5890863ac13118b29c51c611a16b6f17c0e966726ddc82bd5381cbedc1bb0b834f9de9997466cced3f3f0b8950dba93ed8f59387d2b16560c2d8e163decfcdfab82e622ffdac1b8e16cd7315b585f9bc60cdf23fc5ccd3fe1d22bdb274c94fd1347a83db340c7b58a70c451abf0821dc243c9829b07c61cec01f3a998387472faf91bdc47032775ca22fc8bc5b916f4acb0b32974a1ab6276cc5c155d6657ec32983e36504e1a8a179a395212a949407f5d5f6055a9ac3b906f397a59118f00e0a93770f0308d872bc0803f7178c7662da9cfe65f6d9c986a3dc1e10f2dc69a203077644c63d80310f099147f363d9c4423166a6b927b2a1fa14dc0f53e19a933b98e4f1a563225ff608cc7fbdbc5d45b203079f77aaa9559fae191b18a985801c7fae62107c5433182cf3c146410b50e1c249f6623aac5a13a08ea7816ef0bb6a01878ff87c6c8aa34a5cdb8745ca7d42d8c261c6c2632a7ad49b9b4123b741148c3c75f9040789e8103e741cb5eadaefd21545070a10e2ab1ffe1be32da0ff3dc6638a3b3588eaf8a6412ca13e0cbd41de7ab2a22489f1a7d9327cfc2333fd671d9dfff9cbd3c91788f2bfff871c030de5d6e0cc4da50396a7533da4b6dfe53ed4b6883586f00e213d38945583511370af6c4780a01d47f80d94b8e145e8c4d608b7e795f13c695140463d6c8215db7c550aca7e2c5f74137004a3304e9f6b1e2dd306fb335739e0d386f03ceaebdaf57994d7eca5541ffef3df37fd546803cfd2ed537f6c7674cc70aefd9dfc1fbf358b13a8566c71922de77cad884755b579de5ce2c2ce5baee7ea3077a3eb1040ad605a472fd8a6e88d63a391f3ee4b0ab719f9b5b207837dff60585c30aa0d82f92bfe2b8eb2db5cafe0b04ae44703cc7c4ea79793c26ae409ebf190b51d73b546e122566eba365c64ae2e2244de00e1028dcfd9f2786b06fe9d8a59b9defaed99f41a3b0279dd3a5e18071c73c4ac8ffda57514d58407c590e20405766c919303d1ed2405e1f04ee77ee0901ca64d22aa826a458d4cd2ae817a14d6e1eded76dddebbbb9281b232a20ee8307de14b0d6198d6d515fa9afc0106b79956f955607fd2f4890648e75c13df1d184978ae12e9debbe1393157a879a58c4a932eb3db77f3753ec6bfaceb2b724c48954b1128f5e232c651e7660a50f395b06f55c6313d40cb0b4e9a09394fdf8180a60eef21de43fe854d092b34580682b956c969c1e24d01d925458f6e65ed9dc4104d7f5afa31efdef92b5afeddd397a219e28001d741aed9affb50324204878e81f92d6b37c7318c0d3e0852ae1fb959af8b054134b6786d0413ec758a3e3fb296136ff19a0598de3332d222f94ee32e51d27eb081ad4027a61694a7e93484e3dfcc8bc9bd4c715708aaddcf8615d165b496f1bd082fc59e0d19885c1666eda82e4b7303413a644fb2bb6c7d9b0d744695aae2a1eff7bd715578fa8329b3d9ab69f8ac4ce5831eaa11127c45b6fc0f2e24570d45383fd3171522c276f475dba1b2617cf90e197151036cdfa0a875296ec4cbeba4d92c4c2251f33697d2f5946577131d6c8eff04f68e1074ee305ad1877e533ccfb6fff05f4fa961265a932d370c4a00968de1dbbeb24c2b459f1480bf29205ac1a490a27cf59525bfbd5fb43eb79867d30705455447b76458d3a0bbebe918e65e207a27fb6c9f25ec6b41c8ee0c4b179ed3d36c46e51aa92b3566c10e3a4c33f3b85926e926f839ff89cc238f7774bb157bf52b692118881389dae365f8021f6ba431532fc441bc832a2f4ab5d3109423d9002b7939c9e86e259dfbafbeb4355155991d957e313f64f79dd35a564ec2420816521791a8cd74280a5d2a6474c47c9d41a0cd4825a3b3e2ed21a277133200729a4f9879eeae5b74d27fb9d25d0c466b34c38bcc14e58256b8d60153ce6861191bd892bfccffb10f21bdc701bb64d3394030eedc3db92a07ebc56fc0bdc139a89367a69bce358b3050265a4cec844e1002addb14fab7ba5e4314bf0815e99ff0745b04f57a016575b47941b286c89ac8a5a023a96e0da88a693900536dc304b84b34a5dca8f9367d9eba4e797d69175083c5cb56156f19d5d1060f81c3ff61010585d643a3602a8bc2e975da03e53d7d13a15c81e7814fa9a4e9c1236a389f3cf89c3d6c32b37d0db574551603557ab32932ea114357ddce9963d78c83b94117ef3f64561975be2b54ace57622e6160cae1c46ac8095c1efc91bc035bc73cb7887c7f858937d4b10392a747991eedfeb71be8d1767e19f82fcfb32ac1540a24d704be4917741211409ae5c3fea8ad4c5c048d971babc6c6c0231bd707c84e779de85cebe7b97d55607118e8e764c8cacc26300cad784df2a57915f4ab9987253b8759fe7f1672f205bb67838391f0bf094c0a58c50cda23fdd2c5d4067ed23296c6f59bb7e101850e41132a990889e9d9b8e9eebf6f7f089710a6daba5af1e0ecc18a35583ba0a75834738f2f38f23f79464760965282d35925c526293550765be90d6855a70c4744f34293071bf291055984ff8ccb6da4ca19e853692fd4e370c6ecd998e34916f8b158a8c7a579cea0b74b33e774d5f937e0040eec608db910232986c0ea42dab2706d35f2d11716765a42c9f1d1418b85b096aa4a139524c43b194d220125870ea7ba03c455c36f9648bcbbbd93ffff6352c5bf4f64f892c841337b96b54266ea539a2ace79932529259b678389d64096a7a77196054065c4ba3db3223ee8b798f813a4120d7e9610705526ce79a07e77060f3277b58b3d923e4f647733db8bdebe1ff9e2cc7b003bf7939e7151a136167242a223248eb8a6f9e1a623fd40c426402ee069d84ba6eeb060c900a6d146475a0568f37eff6d7e350798da28b359e8a370a79a7c93bf1b7a4c0ac28056bc0c3bc90c67ef918be71b49f98424acf193ccfd34cd882b4acc554fdc89c39f3bd1deb25ba7c32822a9ae5ff70d220a4cdbe3866071c691ec5f7dfddf9c5871bc5bd6410a31e227ba12dd84b17a2b16f7610846b783097ecc005e03ec62c6516239e02e6da6d210618a3a48eadc042f2ffe0579145679651ef370b96d500a95663d57c8e456c6bb49243f5d70d93edb3531a5cfe770f9ff93fbf6e41ff595532969d266b8eee251ad6a3f5998e5821756152ab4361856f4c79dee4838d0c5722185efc21d5cf6828a89c339af41bcaa26d9d3d0c136f7d89edd8e0a17bc3899d83e5ebc35a9bc7bd22f0fd7e24ea3893bc15bf67e4ebe71c791d2af72b44892cfef68a2febe21c69fa5b2eef41bd1a9e549998053d95baf1ef34464ad3b6f31a604f4d64279f509398246b76863100e53ef274f95ac2ea8dc530375f625decac37a39ba7095bdd2715f21cbeb74110e16f52dacfc440d098938b7458196363b992ce99faebcfd80756995c21d37fe06fbb198dde867b678ffb19428e8b3b974fa0cf20d433ec537c8b5f4ed7cdaf77e4ff2dfa9571df6c969809b7796a6ae4fae954da2f01c91135e62876f49370c70aacc3cbaae44f9bbfbca9a3f4102f41a328822c2d1acedfca7936f87b2af1a0533a9b7bc77bd955edb0b7aa9c7da46db5ae0379f4a83b5edc0e728d6e7068aaf332ca5de62ab95b1841326e1de6690570dc0681ad7610cc532468ae3d81092bf1cf6c9c8d33a82ff074e04ef1f41374a47ba23e937e7534f7410b875c53789d86df520e4d64667a59067d31bc71955cdd56a3c646eca8c99f9bb5bfd2633bdbd6fa90ddae3787bb5eed6d4c12bd7951624d743eb708d1129bf1a69a6f26216f4e35670f834615bc88b68a2b74a2a6c5148ede4a12a5f331c72707a55af23e61ab28773d7882985314d6a6fc65065fb9c142bf66bad9955344e5e96387b4ecdecb9cd99507f9b791051893b5af9cdf97c64f1978de315102a8a39ad1bd4a3a9cde949f63a2cbea93e2b236a4d6073be34de042790721a77079378f3fb7fe2adb20fd31ec9d14c0b8ad22b05ea7175a7d43a6a33391902c71f6997a8ae22cd1bdf664c92b035c2447d2ff16e4e533fdc33d110194202b40232419c6a5518524d6d4adabf3054676a919a5692291804a02b266eecd3e263e1b477f3e66d8fe4a88b0eee98151dcc800e98b40ffb1d301c4c9d1ffa1a5bb144acf22f0dc932021955d8efbf8b222c63f01e0548b7d25aefeabb217303918837538204ad574d1e4590931567fc19b0241290457e97f4f8b46650332cf5844de6b1f3cb9167dd3e0fd350dc779e44576159df513482fc9d9ee52ef6540bcb65b6484d5590af4c4a7f3c83274c73289730e82bacc365d8f7a3b63b69084237ef42661c9ca31430a4bbc7328ab25fb151b323f579aed6784092a5ee9be6607d64f574dd2fe7e815e5c951222bc8471ceaba85402df539d05fd55c7e944c741c35d333aa332aad2d6fa0556a171bdd1d5dfbb8c44cfc53a623e28a22338dc93c761221b3fadbd08ed08452ab0a8fc125238203f7caf95bce21d1d0a07da3b3e977232a940116e313d1ef9e978767bff9e158a1ee1afaa2b83a9f75757a3a2a011c79317cbaeda64f3d2415ebc4d4fb8df5595584d957560b8fedc9dadf078247d5df77b4192caee539d7e1907813afb49d42d27ac59f4ccf2c64fd001337385c217333c4c4437397d416a87aeb2b9fd8b3e1b9357355f619a2b8b8e447373c19681da6fcb2a0faa40b4b2a8417f97654a84ccc87169d16dc50162853a9644f19b8fb5e03f385c9bc4cac6bb573c8f5d4864a59c58dad0e6fa39ceac310fd22e763efe5c2aaea8e5b320bec5a8503970d9609a6f372862b598c08c59040a2f93b3fd7c98aae624c81fa0f8dde556544094e24de9cbfa17e22ad6873f08b5db8fb74e7c0b5585efcd24f3fd5c2d28b803725e8beec69815b654f8b69169c4b374028cf23fea277225a465598d11ff114ae46a64fb93792237589207c7d9174e33c9714892a67e100cdd472666d33ef6bc6c553089e29bb4303fee68997d014087499fbe5954e9ba49901d5b8ac0f73c179592928e7900b6030a258ebe37a83ad6485412e013543b9e7f082e1e2ac5d89bd524799b0df2609a8360f59f5934a269841007ba5712ea22df282e6bafa768ce05579a5b87843a157beb58fe201aab983b2eaa3b108a0de940394e36384c1486354ea9dfcb83d3dd835fa5e49ba273a295108c22825efa7a07b7587544292d5c619b95d162d3c52c7a6365ccc1085f646738ad9e4485cda269e408c1571f62d27158e2ac9618d5a156c1a9102b95f9179b91ef53ddb70bb355149478829c75297089e1d27c8e08ba0c86ec08452d915692f666a3e326a0691cb82f07b7fb4136271e601791e1ecc0c2aa4ed96c00edbd43a94e70335ec7e53ae01c68656b269f997d188d19cd0f3a42796a55b5d47d9b39ca493330810da38ed4a1468d5b5df10a37d67c27e8b185dbde4fd962fb765be14de432b6c75dc1dd984323e1ccacd734533b6199f199473854a0706e9faef62723af10f8178e665c2736031f4aec59566a5f21c1c0b72d896590d24c96b476a6a279973099646ef7ebe9f91c3b4f89e8fb249e7c9ab61828a7c0719bbac8375ee3180c78ef5e738646e9864b8826df70d13364c77df70bd1a8cc29d4dc7193b0747e8bea9fef35b930302ac8762ad42dcdc9ae48e7891a0295cebaed2241776289dcd58238cce6f1011a0dfcc64fdfbbbfc4d43cead7e75fcf4aa3b65630612cc1ec4c6b8cc3bd75d90e3930cc770107a07b7c6012a601a611214f73a8f2076a79968c4c1e0bf0962f508d34df2e7318492ef93bcc52805dde6fee08fb160bbf9629de9ae6450fb152aa784cc4118732216e85c0890cd5bb2ac7dcbe8c6b65de799bf9dea168d09357effe7bb8db483e52ea5f51f983542ceb399525b5cfb9099fe2c3fb19cd7efb3f97f800463d8b4825925f0236d5c56eb4619512c9d872357b8ec22ce8c4d26a9079ac4c6d3860b435f25a2dbb51d5e5fa34b5b5dbe99099cf2abff1f7cc8dfd66af908dbd680bff2732c7372ec1c3bc6504247153acd7d46c4f690c1e20d86851993bd47127af8cc6846bfdb0e6d2a1bb0b00d4449c757282a33c1135ee09afccd1d1928e67db8dabfc119ff3363442105370f21fb1fea96561f638123a6f42fa8aa46d467530182d5ecd0b7dae413e9bfe3fcc6f59bbc4adb2e65df37a18f220d0d1850548a77fb524037dbd163b7f4b32e1035ddce2970fb29008b24c19ac29e65b1e814ef643fed9d43b17764eaba93bf30fd1d3b1093375d3db0298c9ee3d9e82f78f4cbedecb772f90355e2d3ff1aa73824f370c52b80f31a7183c9789786fc7426d53343d49fa19b4af4fd425bcb7b33ea4ab8d8d1936b36de5bdbd5b21d13dcba5eb2c2c5cb4b80008a84695eb2e8316b09d0b2197ed9712a0004a751d438f0c5c2d5468511aba7596d5b1c14c365a795ef13f8965dc06f18260c200c52b2de1493992528a4414dee91d02ca757cd9632b8ffdadd63b62ad6907f9722654c36ee9146092c05617fbfe5a482da0aa412fe23e9fc9d6616e8ef4644e869d8ad2f9208beef5ec9a47e51ed4546f3723a41c3780f286c61413ebbb04c8b8b02db424f4fc29c53ff79a2f714ae99c2059aa990e66b9309b2707d3a025b66ced726ce16ac1668891168ecd4d5f44372ee5440adfc3dd6eb5432205ada13c5775504ca452639ef0f188fc7ecbc452444eec69464c36fd9af7b4e2dcd3a2cf7285d9fa769bd6db4d45592cd843b78a07fe4eb49de7bbcfb2f930a515b385923ecf1df24a1a77381f1ac510ee3ea1a6940bd1ed61674821e54c126f51f6ffb9a6d282a32ce3ce9236bf1fa5a533384e7c5fba64219df30b55801b0e2e6dfd1a6b7940b4ce606ab73b52bf24443ff8200e510cfb7187bc1b3c1196fe2d584872e0cf66bf80a6dc0da0b7917cc572c4eefc5a9292368a545e6496a53403c8fa0006e365bf6f4d41407c9ed94660afaae8835111d5cdf4f5fc025deb997a57666bd2291783935b0402230f6c56d2cd60985411c5640a1568e5d73461a6180fe2677a5f25daf47a1f7606cf059f0e7a64c35aaa816b1ce1bef4224adf1c2504539cb604ffac93fe13ae9f7858c79de5d2ed397da481dd979b47ed379ae97c5dccdac1274dbb86fbf2d4e8a87423ffc45cc8fb8e2bc441efaf7510d8573a77efc19f38417eb40e7faf733163085fc424e43a3d99c724dc1601e13c2b97632f7d4c7f206c30874ce4849c5591b23c19f9526394e0c741d4bb6f1aabca4613dc825885e0ff57dd66e442888e8d884dd1d9b1ec08b7d64afcd83718799847a4673fe8353c29255cf1d7638f2752bc4f76234384393a77f0c8335f50b25aa6d2676e648bf8180a66ee22a50e1ca5ca1516542e22dc2ecbc5e2a5a551937fefa8dcb36333d350f774c4265c2f8907a51303180d09cc6253e260b1c236d73d6ecffb4016a37208e56e6d80f9fa44eaddab859ff405bfddd18eef13dd3f373f44c6a55386db1788dcd9893df3b72c640210352bdc4437dc6a0bb341d55bc4402c287368238304831a2f180ec877aedcf82b19497ed98a388d1bff38f18b2eea4c5c3c9f4f87401518b3ebf240dc2560e21ce60c175ba386b953e28dcd029039afc1f6bca162f17004b9ba58ed4a4a71b025dd69e1084b5d25e06eff95057dafb9839e0810671758e55327f845c081e04a352a888794eafebbe28a9c8d73a5320ca09ea1db45c8f14423e7ccafcf2a1559e2008269b81dc997783d331080bf776e30ba290b22f9aeacf825e63863b00d1d1d660e20b34a1410a3eb2b6619be8c758d8d1a986144896877f6f987b89e2ea376ace81ac8075d049cb63bbd205022e2c79ed625e5bdda67f7b2a1dc728426ca8e1a349b0cd1d80a0fc4c1d84470f002d2e61939a0f0cd852d13e7547b283db6ac8be62cb40f70f4043b40c85d52dcf93f9a2331217e005a44a96b24ebcd231fd6888d29fd4f7969b0b4ad3cb6d1fb4a40845edfba61e4506436cbe8d91321891223676bb596a5fb7277e4394ecebf22a88f9cb64dc694b516489c71bb0a2bf0ad0e435521c306945f8dc3d6e9058ad2a653e75fba8101401492fca992dcb6678f659f859c4e0d470345d0a2686de793517191ca977c67bd177260f9cd632c14765951ca7cf067dd90bdec1fbfb02e439177666f016af3262d15448e1b05c1bf234b7d6b1c36d818b76dff0fed8697e040ef72e82c01416fd3c2006b76c2660a5a522c3418fcefff83c288698b3f97e787cf9b40ae134906821cfe81de669fcd7b6853058b2376d2c0ef83df4779f7b154ece5bc2dcc159c4b76c8a7edc74d932fda42b880da2113946da1934f8b5154c7fd0e089de151c388028a8efc8bc7ad59a2e692ca14d17ac68054c434b1554371f994ba19ea96d64b4a874588793ad153d9d31d5fd9b5879b0b3e5ea3f28d74d018c6275959d722a696a115a91bef9e3b669109b4148b108e7ea9cda8e19659a9e6c0d3057e199a80fd23135bd51597e78a51f7e68d985084820962d7ca9c423944a9ccf225bf731dcddb0be075c6eb9d0879cc664cc2c2c1ba83676e3dd6e268de36cb8dfa7b4be42e37e317e9a009cf3e1545326a6be0713fb09c1740b9cbe3800fa688f27f5d3b3e6c46bfcbd4e8b0b11ab120fd8faa89fcf307ec4fdca8f5446c5ce322527473c2061414cbbe8409a55b918b97163326ac5f33f3369dfd1077839889580c906ddb243c192512668591c81b9d5a89029d890af25a2644b6faa50cc9275cb96e8951683cb67a4d5972736f69457c6375095a3eb58b9ae1680564e8c7252dfc479170ad54e3159ef503e55de432264204a3f9c26d59cd627d6f7ba5a603b8670ee8fa9aa1ece22d8b536337d0d7c96fa92f22351a6c46982e48fd0e90328a5b2b07f9b6743ab5d85d49089bf75c3f9b0ac0115ef9d9f0776e2caa50518e92ca66767b5c884e602545fb1efeec6d8973f3e1e551549f38a696e55054fbdb6450e6a7bbb3fc77dcc4e5dad89af8e68a3274ee9616976c8c58b8be1f06ac68d4f048a897b3f6b486a3e4eec9ed5882403e42fbcdc9b3b130ecf0ab32e65f7dcb150a245d3ae3e1b85f54181f4ee049ebc15baf97602db1e1a044086af087cd4e003c8aa3af32d40e6c0ae69c993d82782691a7ee4f4a32198a40ebd68e385f1afa25514dffcd3df9df2cac3218a578c0c52f5845f0e101f063dd2fb377161ea85ece9512ef82d255673b8f97d00d884f1c60d407e308f5bd1e01ee532cbbbe49c892fccb8c9f4a1286fe5bf25b804ff0ba386a8569ad798be464cd9c14cc01ee5d09382826b275cb4e23b9dfe236b93606f5774d5831b7afde209636fd3c04c6af63245579cdf4ee5010adfeb8970452b32a0a562c271fd8a6846d5033bd75674bb36bc521eb2c133699f757db3fd47530a2387f374352b878e3e460bdb35afd685d752c09b7a33cc31f4a4237fc819f228d3cdbc2fc5d5e2cf33d739ad2a56cd675629d43106fd83614aef65edff3d9213bb5d8507e8fd45acba795984604616f84c190fea7ef1bdd38e39ebf5bf30e04abeda43d4f9e48252d7fe6bda7a9a12085f69d69dad5603a3a4a07f41975d9c4d4bf77915a364635e6a6468e7dbad2276a4e06e382f52547b3d8b62e856edcb9b28810d900bf7c9ee9374ab6886325313d1c22cca8e31c74f30816af80b8f0ac601e0c8269083697ab0d7d492ae8261ab54eb16aefcfb9cea91faa19138619c8912e59f40fe31f44bc027eb5e602c4c2ca85dff58cca5d6042b6ffaae085863dc149fb2cf058864e3180de17b582efcfdcbbb93da6cfb97b05601a25a348273010e4618375cfd8ec71cd025523c6c55a68e4724552a18a8da6712d99579bc98329867c6f59236a40749b60e91ad515e86b14052fab609a84acb2e51f9d89a4eab19543081a06b839585dccc9be0b97c4b4c50ac9fdf79559e7a76d254dfd5b127a38346043ea02967b54c09d0bc5c55cf9f9274704d599b7c9783c872fa0b6328d662c92412efd0c2d4a626f2580f1b5b99ebaf1c02b0562eee41c011247fe2c378c1f0cac3243a9fe0f07e27ce8653aa11fe167e20146601fb016fc091e7616ccf2e3ca6e1aa0c07ecd21f862f71641686fc95114d23c83bd5cb4c0bf9e81f1119d2d06033fe946860a9b48bfc2b9c5cf15691eedb8a6faf0c5ee9c9313c1fcae01d60984be6973bec7573a360f80b83b633cf6c900176fa0f5991af019304d993ba3e9e91a0638e56398307235dae08ce4cde5f8f1866255d7fb0a598274bb09c3fd580f90026ac8c2b25e9fe269bb1e4073fe8d79f3b3c6abedd20cefabdef1b7d7f077ce7cc6d6977a452624a578aef95810be812e3f004f8babe36fa8e918e000af2d4010590e4c29a983dcf2c800b1941d55babbc2b44ad9776d8a3d4766d85c60cd365db9586f331f978c95f53fdddb31aee6a55ac99b78591efa675cfde4e8cbf73003de126b6a22c10bec279a858fd7b77475c967bf28ff16a2cd698de0c132f02885e7a985b387e36c47fde6923f83550fd7dbc4ac048e740c6d91762d1d2b5940fb2665774115f013f6e5364fab574a649008a03032a608b0a3c65219c4fd62ab8848d2bd2eb11fd077cb2d3e393cb5acc4204887f341dede2b19252bb51340695debcc6b215075169e0716db6d9ccc9c0c8e427a20ca5bacd83ac2de9fd160ec4314a71c12a0a0a736bb638bc002c37e017a218245baf146869637d29aec51104d7ff548e81589a0c038326139edfbc209b3fea06f35907900dce371d0c5de8dd2e81ed51badb7ed1d5b1870927440e499504e1f94d42e6ae7dc0c9cc295cd5d16fc8d417ae1afb779d64dbcae87fe2f5efa9397bf5528ec62612781d4b9c4bdf944b3121acb2c4fb59d005bd6b1870edefc05af8338da656b0040812573668500d983da24fe6025b1a9589a70270fe23d29ec9c1e8248e07d7e93a8c994876d662d8b858ad24b4cfc042a06ea1183bb16b45f77de4f2b4b6e4fbf9829ea7241bafbbf02f777bf199de372aa388616cae9c3bc9494853e06656865ff2b200051bc2abf86aba67fc42ebd45db76cfbf4b1eec0db87a370c670377ccf016f5268df34c69c8a3b41f9395957e0fcda6f7bbc1f069ef755a0784a0fde268ce94a20ba6243141d54a1477bc368b2acabd44e171c71b3ea2adcfd26b5a0d30ee905bba0abf0218770b2cc54b254a1018bfb8e7f65b45deb947c025c6fd52fd5f15001a97b504bab52f761aa5fc34957fe26afbc615801fd8fc6ddcdc9455082259b5c9d048abb56280d9d6109cd183afdccbecd93bef2b5ccaeb11871e8735996a3b3ef631c257052d724b47179492db3c53098954a070ac03413d91cbe52f018b94a143d5a81a76d3051c16b2c1d5be44586179199428d7c7f4e446bee3fcfd5c5a710d24216eac9ffdfb1bdb56fd5012f59466964dea93c3c19b2999f43fde1fee714b62fed6e1eb061299e7eb37b52033115708dcfa3c37f975058b930aeaa03cbfcbea732059419d02c70c030ac4e41223a5641636512d4b154d9bef107de87ba471a9dc1705a9f10befc32b906d9969a6cf0d970df3a9219771e3c623a689a766ce5b7bac818a2d154d192b33fcdef2bdb9cb2abb907b5dd2053c6348dc588f677f6ae85df9c66bcb433a910f83f0329c6ea327b2017cd8eabbf9a0962cbe59b3b38cc375e1ce0679dbbc976f5ac24b3c0749bc950684c11e0669885a0401f60829ad3bad7569834ebf56658494565f261196fe52db3b9cc775519adf766581e3dda3d24ced37e70ed7085ad77aac674c4d4841a7e72ddf13beef126b7bbe260861b2e34fdba713e3cbf591d0ccd7dcc497181f6562e4e0eb1add1a6483a974daef8640e13e3eaee315f9e1811243a0efbd04dd4bc32a9baa8b0e8c7003e188c7d0e0b54b20433213afd019c95cb670a36b87f474e89157362b97d417fe412a23a10877cf512992862ebbe22b87a64dd95456972acda54caa94b2c9c0142bf748777803758e9130e59e7db8680d31e59be07df442fbed959fbd85fcf076f389974904587eade1ce8c7996f1dda1a056251275b0763372f6969ec3424382175f5a28f57dd1a4f4139c7e08b21f583d3bd795d794e07564b90ed63f67126359c7b0b81cdb317a8d43ed1e0cabac0544dd32057ebe6e7c514a0203a830bb43be40d19f9766c793fa247f25a6b61d6fd9b83c83bcb4addd4fd1ebdeaddb4a22b88bc78ba29c028c9fe7a7c39a8bd503c93074226c0c06ff032fd34dfa000eea5feea50035851ac7157409d2929c93593237f3fb19b1b8fb339c80dd9d657c57889281327b2efe68ad2df1de3fb3dce1b001c1e1029833bf49b5c3ce7f406ac0fbf2f72109a74e503311eaf875ee0326946d1e57036495e93553441973f975b0fae0c6ee0d1224150c340670e155246973d53c08d27f5cf6c7caafeff66eeaabac1cb0940780ae2225233a01b82c8e223f820de1d2d7973d215e8a3ebfd441f7d1ad661d2e9eed830f6521ac9cbb80ba9ad7f30d94fe0a78947d46f91502a04dbc9e65ceb27c0274af27722fd1bcbe058c2b3df57cff52f27a4e158a892774006a60a4aec3cb5cf8f8056648938f1e9b299c655bece1f00a2b63511d75e0ba2256dc201e9d7c093ebdc09dba982f76d0d4028baf7a7227128a302d8e331c7cfefcbb0c2a85ee95332210b547246a5aba8fcc457144724d17d77d47616582586e2ae5c149a5bc922ccc688ae52512a5259e1bb96de10af105e9172fb6d52de44c3b4cc78bb45986caeadad3df5fe0c9495a18754462a36be5cf5fa1957f10b907739e00d1610ed932cefaea2bd02f2af3a8a9cbe11c2c21d4d2ee2063a089a6ac530dff6f462f357a6a6983ef9fb10205ecc3487a44429e16f309abed48a8045de72482160887b13ff150bc43c452f71707ded0d14dda657b3cce0ccfa567cd9bf5a58327769beda44007158cdbc1acf5ac74024ec4002e7325d617f278b048239a97d1ba7eb43be140830a3eb8cebde7275e616a477497495e4324e8fa476252c0ba6396f2a744c130582aa979443389eb9506298d96d4859bfb989b69765546af7e9b3e997ec3ea99d6be5f0222d3e50f6971c08b7605197e5e69217f274dc0c69f17ed0dcdce1f26cd8e81db3b6bd6dbb0588bb46de992058ccd0babd2f7248ad6f1f07959c20e83ff6f1b1f96a4801bb1ed8361c156b0b14eb29b02d72da5bfa5c8cb3b3fa38cd1fa459e01390d6eedda6fcd6845228b3815b128c05491e27eac827b6eb6451c8791693c2a0753894fea2fd2f2a4df09a75ca58a03c12788b166a2bac07776e945e0a1ce2a55a402f99a01365b1ed5da62fd4985880dffd8cffa86d5de4281aceddae157ee73c96de1f2713a966d2b90f83b3e5c09414140b123dc2c3effb9d0f6e33f8ed0ccadc7b10422868bb39db11b4d63f1795ff81494aaf8e8527fcc4760f5f2bf451799d9519d7b7a2919e0bc76b1e1808cb67d1e964ba71a293f2970f7114f59c408c41cf0b2a3f56604270aa175f24dbbbdad2f263208f019609dd7a0e596c967e8b89befd8b2dd1c2cd5956ff7ab31256f08ee384d141dda1f68cd96c3aec475f0ccd795bfcde771bdb8e5b8719422129b71441fb7bd6c467d6536f9d6cc97915e44a8459e5998b29ca3c7d0ddbdcd24d1db82941f5b2fec3ccbeb109ce815daa204ece726846f53a38aeebaef11854b7d5d02c423247282a531139c44c196ee5e5ccbbbeede26b1f4126c04c0a9a9b55501f28b12bc9237613a04229b69367c0958696964d35bb93321374751870b449d2d70ec0020fc8487d7126221b2626d9df781538bed2899ca604206846bb275e9557ce57754f95a5b64c1e24976a2b3bf824ad8e063eaaf12d30c32c189c04f536cb091f4172552b0fd032646228b7446a00c79b94d7084cc9ca3b82ac3c0dd03849805f9c9b1738d467c90aeab499ad9931549a5e979181fc6eecbd20fe83bd07dc7b10014749a2039013f74555a4f27a935351f1055fb3afe8288b9658a4177f6d45c0a4a516fd10d7839d9621707289ecb706a0ddc2ce4a38829fb0b0c260dcbf554d139a5cf17e4f7eb1b624f2d794e3c378b43f04596f05bbcff2c7a8985ad8e18ce43b3f79cf5d64c93fc096dffd46e2d972785aaa8469a1acada51f23dcdaf4f9e2e6154760e55a4eecb6fcbdba734b358665ac8dec1f3dd34f1f0bd2311bc9a36e7c5d8086ee4c50b094b9f3f78cc6603e7b287df8deece8fe1e4329f4f37de93e6670b60c0ed3bfceff862630bcea1eb9ac5753d01e2783a5274895483d0a22ebe1f98549a90fa7dfe12a764454e22b71cc38e7819156bd46dacdf6c85b3c11c2684e1c033a22c5114c84b51b2a800060162125caa633fe3fc83bd0fbbc84235dc753c20e70dfab0a0499a2f0201996e70487ddbef862edfb5fdedfac53ec9bedc8e4785de095b75c446e4af234ed8f6ea5128696327da3f4e35de01d81a2ad0bde0606640746bd1f641c47041d4b0019a810144d3a5c611cd841dcd68c592a33447b758f6b1807c2d25905de143718a0f5b70a92ef3df0da0ddaa5b2e872b1724e3fbd5d2a47545b568ce7e909ae782c26ef73b0d97066f8c2fdaaef60c148b7248f020f17aeeb2bdbd6ede4f0b3dbb934de166c2c9776d7b742d17d2e0bb97ba06a5eabd4663866898be1546a4841fd2d1ca93fb6430b8b5df2f5ac1e9833613fb34594c55e79b319a14f8b274e02fe684385e1e0f66925e4a8f5fba50990eb33e4284e3fe13a6f3b280750aa35e644ac5ebbad1460ab5eea740fcb65509be215a5b9b3c3dd2d3d90e9a536ec2a696e4d8570f267f013408fc57c9dc347e9dde80321afcdae6b06f25e0140e73b9cb36277b39159ae3343d7bddfb5c8dbf2fc37369cd93e1e2fc276ea8ae4ed7712612a8996b65998b0d8b24c57edb5b2dd91dff11814453a20a8a68cd1dc7a78e1fa6e6d6f20a8f09580cdbe003e630cc951e07b890b4b8534c0ab168a445c374feb9da057dc5331811b7bfbdfa7a2787a0f598a8cf0ad50845668d42f829a8efd5208f6bf609396c271dbe62f7cb5249323cad773dc774c68ef3cb7a38d8d44435c1491c68f8ba6bb6ca41743813f5776a0f58f3ded0ea88df6e500229a9741e160bd944597871ba65acddad050fdd466a7f1921e080dd8c1fbb1bf769c2c3c7620ba53d36dc5bbb518d68d74de37821d0bc4a0c988c72c4fc8f11d38268562858892907e53b429f15f480a6e8a7c07ec8e2a0f62c551dfa1d24410a0f1b88d8244ed64f9067205f0bd43d8e01347f75d1f4b9234859249aeb022f27738053f00775d29319959de1d346d17f156e9a9bca6f2d5af91cb9dbe4a186179cfce834f92ca857e81c4213fff68a53517c9e39a0b53d90197c80a1bd8797e2b02cfb2f26b9fc88a8d8dcb583630423ee6acd926bd39746341359215d493b1f873aaf44704dfd0726ebb2c28adbc6347a7292a6763d8f4d8db3d9b78322ec1209fb6753d5146c2a370ac3f40b4dac984ed005a3f059d957573be66150644d77804c5ce4bdaab56e37e7bb082a9b22943064cf4e79d3166743433850ede64dbf2f4d06df2521fd7b15fbb66ab5f13a8945f5a909f64c2c54e80d5dd81d3943af60eb133a05f1f9141b0d6f8e30fcec6e4ab387e9fc4eef5c63c380be8182bf7680cdbbea7a4c62764913f34fef541f158b915fb0bda8aab101d05f62678d3fb538d3eabfb71eac6952b6039aee77881b52bc68939654d391ae5a4185a10aeaec0c9fbbb84872443549ce65fb08fc329ad74d900f6bfeebc13006bd15011ecf21a100b1c4779ebe96ed8424fde53d634facd218a49abb69952aa0e0cc285482e89407193903c330970566c2a973920a6e1de086f32a5fc8baf8b09360040ea0b97d153d8214ef31c80a08295491743dfb18d26e74b3086d1fa4b3dc623e1e89b814d08125073ac926f14c9945e6e8d285294ac4c622770d353a005f1d501d91bce514c4dce8fc4bb2f34eaeccb0f58bae39e112595520c9fcd70c7f8e645aa84c3f1dac16426f19b16047fcaad981514bfeac92d5af34bece109b87f3dae7a57465544569681578d39c8bc22d8dd759110f96b5161a4ea0ae6b560a1ddaf178ad7094f4989369b111a5ed78dfaffc75b78027a993a035c43c507fdf62b7261156c989ad0f8c9229800e9d837adec954f40d79dc9c66d91b768e2dd6561dcbb6afa4dcfa82d51a856bb3474872192a11559715e2c00b36d6abf918b32527231247fcfec3f92693998ed6be7f8f7e49120d854200af390ccf9d19d7054ddbd5f881117d33ecc95eae944b811f2db51a88e92f6a697871d161cb0370be46b5fe8b6d520ea9f5eadba87a9973b745ca26c5a6b5a4e39cae484f80a01e5f1dcb855557c93df9e2128fe24d445c58282b433f51334d33b9e6d6239eeb3d741377681ff6bdfc3e2460db8a2b0ab327b38c7d2be866e2f455c961d24905f02c4a84726b0e7691c3a75578054aa1099038fc89718fa3e3cd3815c9ef4358883cd9ea35c9e427d96983496c48267f3efc004b2372864d4928a6d7efa8eca8b4fff4386024e927bd01b94c01f208dfc246ec12d36456baadef29e4c68a76834829f408fafb5d8744ea2643c195d00a74cdba69dab0e25b6900a0cff1941b05505f189e078a0d0718033aca83ce02cd613c6b7bab09530e7590d3e08d66eabd3eaf41c8cbdb827c2b38267314d4819d3bc3531430f41df0ad53e6e2ea0cc1687e42c49bc5496d313383e2f906208ddbe0f8f8bae2f1d1c26b212a4a166a2d611bcbcb4a8a0516b38edf63ec4572dbb77f2f1131f60b931aff579793ff5e7b862dfc81656c65626386cec82e61e5ed143a6302c93c62c64961ac1a8c2b38749a82a1133d0070ae51f95fc8935547ce8496440d3e11445376dd9883263817edc4af7b66359c35bfbb6964da56d6d046c9d89e274d06c20470110804eb2e765318d5a55936ec4f457e3052e5b040283269dec59f86c319edae7f95b096863d47a7a8d1c8be95294145997a606f3be3d8cf9e5b1187dd463f2b0959b744914accd6e5b9242bcb60b11acd73d7d40ad9885d7a449803eef38db5b137615bbc42d63b4ff6e77b51adbf199188760dcf7a58efbeb46f3a0de128007dbc1707220d2f247333538f19c54f0ac5dedd0114c7f2805885c074056e3530070de7d6ca2f58a402bc36d95b333726423a9180fd506ce86fd69cff32763fec67af7e8974ad9c123ed4bf8307379428f45106896fad123a01e5e67a3eb804aa912d2da31ace5d6c2a50ff83236e01b5ffb562882431c53415d2c446f9b12f51de18bad6c633a35fbf3daca9922e8dad2d99fa4868b3cd08cdf4713a4d6e4aaf54ecaea3ad1ff9ff0f68fdc0d43478a3ad2dd4a7612286a28b3bc4b9825c66de941553ed56f770079b1e9721ce6bceb7ae32735565958abc049a9b865272f7880d54ab637dadec47bd0fa634631a0197d407ba33912f8f0c29be422971681b309fe7f321df52728713abe72ddb29820ba6193ac63e33f4bc55ac4a693630733edbea55adc435d92e9c7e7283cf01e41df97518df4cb7bfb843761d3df67bb3f978f3ad5eeb2c712994a834800f4f91f29751182f710ef4b3f375de8fd303ee87bd35bf2d0973055a9e60e12e8adfecd5c6c2e495996171ce633d2ee0a1301813e7dd6938e077c83fa2af24659942930ed301a12982af04f7f2c881e4d6b48a6744b9fec332d0b70d755cf6e90c40efe8616bdccac6ec5f71645823548e3f95a70ac199c2befdb43c60a9d678e116e4fc5a472c376a1ffab52a1b546644cbf82a3e3eb48e334eeba3cf1541a6c33be04225e949f8fbadb94031f32f2d260aedb386e008c1c7ddf39036109f99b334fb67f3a61349cd0669e4ed225ffb83162e4f141d0b10d2ded15bbcd1bad2ec2b5555604429b3ee97be18f93125d020401023baa040a25268b4e1c2e8ee2832984afb5dc0c8f617a23967b55e64575cc32576a482dc4f71c1986d9c015e3441feb7a5c8f3b8d0317cc4d6d2137ce3b9b4f61b63c612afb408040f930264e4300a0cd887181f1debac8a3f313edaa5546142afb7ce63d313ab0f66ef15d513f9a932343e4b06fe09b67106c9e0d77bf4c86560121e994f5fb4fad34f7a9982b69828daa4ea53de2e7dc654d8ec3d97946ad91cf8f19576dbb66425f73686940e7a2b1da5b69dd8d49c590d7002d9e129c2ed8e5780b5f9e889f86554fe1b22ac4d91ed3cb53395197fc19ae77402b74a17ba988581360f45dbc1aae8ca9ab3cc2948a7ac33cd3f50ba29298b697c257dd106168918c650d1668bd885ebd970dceeca88c55ebd8794d674418ef9fdbd0ed4e438a50d7c943da5b50e2b2c2037ca63170dd25eb5ae9ecb25ca6ea09f8d72c3873ae75c6c4451bc0955f914bde4c9e35ce9f746a12621747230f25487f81447f282b15ec830b9b0fd6da22e5f7cb144cb5f14080c741ac5b5d4ddef36a6780227606fa4edcebb281bfb5edd894cd0d47d3665dc5eaffd34f7aac111ae93f96c31e66762dc509203a920f8a8b595e1309f35803c67d26a02714e06c8f9e7e470db3856a9c80ae8323afe70305037fbb1ac7f558e5fcf3c6ae1ae3c23d284a889e7eb5401bcd4c9b6d8612f579c1e29de2fdc9683921100ab5abc6fb05dd2ec13527aa6124b0c92a5aad704885102808b3b1f4ef7787d78a9346ccae070a9cb6750e7aa83a1f88ba3e68983a0ac645ea20bce160c31be6a3e3672d3ac0b35e1a3bc76d6b462e3dce0281b5d86f3661e2e08a0865370f618318605a79664630dbd3d31f60fb893159f5c8e98df69ad654c13336fd79984176d330737386f9dcbc8363e0ba82eabab9f484ee3568edb25af8b7efa4cd9522cf5d07a9847cb32b366335d199e4e1ca706fc1922a22009a5d4c02b986185abc407d2bdc8002308183fbdbf7afacf6012ddd9efc7b27bf1ea2b4c986848bc0fc705762f6b4f8d4d467ed9bc11900e66001a4972dbcdb55d29811a068471afbfec7ab1e07c21a86a1b6741f72cde6afc5196c8c18e98b3d462582b1fc7eaffa31530868379cd2f98b1619fb98433e0ed7b433628075c722f62b67d5dc85acbf17fcba986fda264c7d8b81a28b34773913cae20671a13f0c0e188c8201701a89020d56716e2b19e5572f9b2894b73aa15c203c9e1f2e49ccca3a45242cb2866c87c2ba76e0b8a872f651129ab812038772922fb27d85d6fdd844459efe6b155d7137d913825942f877033e0f42e03ce8f73dff016e8317f1f0788e16108279c780eb10c9f08e10199918f77cec59f90ddca83ad3b3e2f4bbc9dd3f7af741e3f46f80ecaa45bc16a5376c6e83c93f05109cceb6382494792bb7917f2bcc8ef6e779ee3a35f24f1c48bc4968130992658e99447a613d2632fc090470858531b9180daf1460f7b4681fca8c7fb8ba0392359ed1871b6648343d0cb2007448c283c6f2e63e6572da51b66b0fec1135cb992fd343496884dd774b7b8ce3ac74f9bb254f240c5de78ee2106e0e57712e8d805a8557258f3ba32973a2b086a68d833a3ad9c2cf058e5e27dda38aabfe5d31dce1400644749b2fce63e598509b049548633a9c09a0f4b4dcc99c4ecd10624bda16f19e22aef10e15a3d4ae0893a276da40444f313835010da867408e2b2ff375d3573cbc4a1ebbcffcd6170ceb8c15521050c89a913805ebdca947e5d8adcd0aa607f271d901d8ca477bd22edf9931555dfd1af17b1d775d5305e5e66990d22f2f7d313d1af035a24a9218cf8890646c0f6e8f92f7c52b610c21f11bc260fe79b8ce4a71dcf61f5d4304b724f77c9aac216a3e13c3b1d44895f12ba7e263be17a395c50a958a603c6141f78b2575814dd2c0e94d7bbe5485c76bfd5ef42b286609f2b208b499b18b2dee1213407f789740cf759dbe9b92593ef4c3cadc29cdeb931302c7e83e27b77609474e959f990a5082c67155b54720ca641ee64d9d3cb027d440cd205409c8de51923be70781030a6a6b059398bddc1f96d8fe35ac8c4811b6df70d6edb59f49dc532154b46ca6e208da5ce4da7576e6e59ba3c32e4a32bde900b1f995230314c0c684e7a4a7b1f64e7a7a7443e32249d5b427b1b198e24af5a0495cc885682a1a75432d25a14e64149f92b6a18e1aa17f15fd94f9a029af83691774aa5589950852573d5586ec319e913f8931868476a68d5b3a172549df577a44563b915d34993198444a1ef79ceb960a944edaa7aa31c29935695dcd44430078c85df0082902a8b6b1aba9b923f9149e845cb98517e9123cb08698c5cc15d1cc678700deef1b29a34335400e14991f09e5a2581ba0554e6ce6a036ee48a4d4bc7b9d87ecefbce303c95abe9173ca777512d4853643af276a35830d31e7c9b3a8db4f334b223623e46841d4e6eda52b3956f5b5dcf58759ba75117f265594cdf8a4ecdc601e4cf1b90886352d69ed147ac0499710d6dad90c0b0c047f5560de326f5ef9d97a09fe5ccd1de08224a4492487b782b2098475e79ae57fe837a7958bc6ae769517d5aad97883252d251a8055c850c91792e708bc462e568468acaffe687d568fff50ad8b2f748ea0df02971847d648b7954ac24da2e7ac15a806e788728162d3fb3366c0582747e8a5b2a8c86e0aabed96d0fca3f956a4fe0dc48bdcaa697b6129c50262d288ec00cac54151669c1800017cce4a28513fa572c94f07b6d966ea80ee57b00af19c6bcb4f17c27eaff995399ea8541e9eef9dde46cf03a93821b9f2f3af5789662599aeca6c469ae8fc31903ba0d001b09c9d034c0a2a54ce0009cfc1d69c5550bb986037898603559219d20b55584ddf6c291d1729293a2dfe97e2e9794c283606e70718cc8cd1590fd97aa0c07e2ddc39f7ce9f6aebd019bea9a34d81ff2b4ba7a2f674cb11269f01307b9b8edd392346c90bc7999e516acf7cf0b0a6bb10bbbfbfac56fd1dbb2a93daefa137568008f044ec811160ed7149ed0628775f2f4c8f7bc54251d0358d1a32d7c87e321b282c97757e63d3517140939c89daf196781ead9c23c7689c2d0296b09984715196897b193815675dea0de0bfcc317ae387d9dfe0677b514a95a7b1d9c1642e4b38c50c04b88cd5ea5b46e40fb1b24366ebeb79c817ba1fa57247ef05578538039473176570e2700592f76c4f59cf75e97c3ca930f04b14a5387029a79e2bc5c5a586823eb33cb4547043d7195225e592bb6470ce3a1a87033daa1c33953400268e0df4fcc5bc35234ad601e2cf950712fd6e70c3b0fa7c30ef4b5e4e0f121cd0562a3425442dfad07fc967fe0d21f6529563535d0b3080ed0bade44715c67c93230d4a1faad8ced89e12f39409e61e32c60d3af61ebdd459cdd7427da26017d61fe9cc389cee6655c70688d8c6754dffb2aec905647d611c17bbe6085e6368200e3492f40c16e85ad8e867233c70170f392470d3c8faf806c6fe0d3ab0e9cb882835c78e837dc998bfd8df62f2eae64cdda646a22fe84aa78c2d4abf497fe4940364fe3977f49919100bb69b0b3278a56a4f46960de22540279b42f908d6090271cbcb4a14e8b5671076bb7536b19a9feff3f4a90bc73374f2c9e968e467f581f2da70e51050611469352f6a788d9213bf93b4498889816410a9c647c53a46dcbd84957b5a86b27553f3fbd01bbbfe08909938a83dac2990a47ec95a3e3bef6f8d4f68b9316078f0dd1cdc185faa70bf7f44063e93ebead32b54e783220a3d26bd20e757abcc84a1314c85db96c3aa4b06e5e7da13c1d9b43b9d99af98b8737c4c2bb8fd9bae746c6b3038aa23c2d71b222ce35f116ba0d8b1f699c62368a37ad901cea014f52867f5ebe71c34cc410e0729c795ad831f62084c362841d34ec272b0ccab53b62588377cf6acc8152a1530326cb49d51647fa25f947d93cc2e1c2aab001b2036b23c813553046bdc041e35815e9aee50efbe3b10b1530d4843e232f0ab6f40297b0273a4b1acd1063e49cbe8e41b94e717de6bb4072653ca48f3a2e3dc4bcea78435a2d1583d418befb3fed613f846963d67c1a81e4deeae5c6ccd38ba0fc4e34bc2636d9975481f23c09a391ed0939873b9444f3cb4770fee3d601c5135d30d598e60550855bf7c701b3d0682f84848b38e3735fb2a5fc91d313c7e994409fce9cfedbcf5fe02e9e98df80f250d13001c69b9e8736b74867ee63879cb41e4173bfcf77a6c903f841dd8f7afdd33dc3296d8fe8df4110288d9c904772db3b3e9300833a93fad14c8e6560eac0d1b0a14d3c1c499002a3b3af76cfc20a0a8b4f8ef2173039d3cbfc817286b8b234864d16a1e92cb6ab88401101d57a6b7afb47fe86e92ad9a043c0ab009e7bffff8011412bb6ee2f65fd037d374ef21bb67fa89a50d42782ec5c43824fc17a25f55d06cc2115cd619af51ab7c0a43ecb6c275ef040c1c8e159e12528cc9d09c1e7d57e21dc1225ef486d2e30fe7e84a22b31803a4eb2194abc5392a266fb8e527fb9b7b0fb6d4fc3e3205522a35a1f04bd0d26b714bbc87b6e8b7b80ba5f5c9b53b787bf254d325fcf3c21ce71020e90157d79bd08c4f4e4f0f8547c4e01149100b78370c223e3c54d073c8d61644ecc8bddaad280aae418a55788be20efaff1873819f1ef5602e03119723a6ce37d30247277bf052f914d0f78303b3e1f3f84bf55614c33040030e134aa3e89577ad350afa537d69d36cc33bc8725aa598cf22aa76c3d46f0f7b4804df8750d9d97f7cf7eac78ba6a486ce3d05307ab3a6b94629b101cc0e1307fae7ad8d9d78d0d7c9052692521f0fd14af7ae8e85b09d7524ea49f6b612e5db43e7dd3565b4f1974cb39e0468b14d7c8c595418cfe74357f18ddd2a78b4167083c654ee0fc494c4870bac34de3d3804c07d417e51a15d0eb5e8329e3a4266cf15af21cef5940029191d15a417922c6a674f0409707dd1a5e7893beaaff50834e924b7a7958de0474c69d7cf19f282c29e60a404bea762dbc21b7ede50895ca34dce787002e0fe5c24ed286d6d5fcf6962d237a47ace3fe6b0dd2e3c60fff477ca6e339ccfd589d565f62a39dbb0f14e60a2830d3f194ae758db564cced25af0cfb0291a84e9cf4929a1f49f466330ea6ea126bb4c4a1a62bf0ec16e274ec931ed61360a340a9463ce18cbf20044bbe879ee321cf423e97987540eb91febadac2ea3821cc08cab07412e8ea3c075900600490b3e8c0419019a18d5d27dcda5a867adb6346577e313697f3257870c929a782c20c739bee16d3482ca0b6db524315ec0f8d2df33e34912265831c0abeb68ce04c71554d2ea74c09f562de2abdd8b12ab124fa65753be6753d7177387a69fdcdad4c8ce6351468bf2487e88afd9f860426f0451f6c12d47622941611e239a6986eef379a291535f60405d4bd7778fbfb4c5bc7d5ef79f618d9019d279345dad579db34e18d76c843d9360b3525d1dbe23e147f3ff3eba0854ebf0a6f693a09da58167edb909387c11c76c826d54966669aaf2d972a27428eb43c524a2889a8a9a0a5854efcb18180ff644bc07321c1a85b89915b93039c1f933db544ef7c43e7ea78b706597cb473a5d2818df0ef9ffb6c941b8f95b245e6b4180f2a6d979e69e3dcf5a3dce0052eee1b0a69ea6e276bc61e997b32faf379a35ac39aac14086cf8cb55976b874732e9c7ae0aaea37d74545d73559014b3fba07672f4578571407d618ca1174bf3cf31834342ad1b33820e8cd9e81e03a6318cc96c5edd1c2d969f95ebc3b8b440d8e957901e2dbe63cb2b591f2ec789ea96c294220e5802e624d396cc4818f959879d45f4796902de82130354eaf23faa7bcd3073e98f4944021e09abe61ebdedb3e93ed15f708f0029ec5c57a73a6ae0a519c2399c5d3250635f6e0c6ecc7c04e57b77c376a83cc77b1e063322d877ad96847e79562362b72dbaac01c7db490bb04be452a7023a45355608459ad7d91434934a0e5d3f5570b4c546229969307422033701fb85eecc05b04a246faec19d095fd82c34bd11ac19cd2b9dc7e941d755cc4896e0b51c317ae6468badd06a27a96efb7a417aa5f41059dbc6bcdb999d83164a796b79799934c60cfb9384323d8b6e379c9124f8a17f2668d1da28ee54c1a6f3abafe56d5c62956eed053336617c769d326454b9ab23ae1d362638ac317771ae526ae90f704c0390012842e8d3b81870b13a9c501d22ba718ffcade928ad75b89792667ea687918d96f734d349deae531cad89af4eb24fb7c476f814ddd4fa5e9bbdf6879f68fd1641e85a9645a0d3bbee8c787e7c6b2adea65a37f32c61bd72b799ad1f43d7c0e0cfee2ff05ea4fb71d6ea5250a3ac75e94e46b09d3adc8cc51282d2f7b85f40db1a74893935b60a059f68bed64fb86b1fc84d9c066872ef14913f51fb2fe6a51a18077aec3b2fd34258539d099224082637869d191c604c270b0fdf1248f6fc3001b24e9dda0b4b44bb39b1583b37b07d6c030fee32215b0a5d34264aab1eec02629f79906f81ebc52cd7de348eb96b0d58d8f2cc609e824be4a847c712b728521bf8698fe365b2b77c365d2db326e94260eeae3f6e6700390389bfd53ba0890cc0d5b055a6d6de0f8b52c057fa5a574c1922ae70ba9d7e47a7b768d4c1fbc2c10a204c85c8c2c0b8a4af0877c0e5e985f758977f64b203799b1957cea95f338ec9a94dc89cad58431b901df4879e8dac89e0a4ee81c26466414b22228efc6f161632be6d43f8ab32ecaecfb3ebc6664cadf95aaf9647423636f4fefad89ef9f3905f78f527ba9aa504e8e985aa68fd49d040a6be3c7f1ff15ce1ac6813e705c24ed34d73df8df2564828181ce69f52ebaaaab26dd9f9e1c300426c9d585ba341d4bd5770acbf044fcfbb943cf4e741e834ca71a75426d78b1348bad98b17266eb4cc6d200128bdd44e7573f018c38a2a48e25fab4d55f66c05901d00ea6499081a79a9d52b63573891b675753bfbb10b0eda7da46262e0586a9a57ce67b5507804f8ae420c167ee37bb20eaf350314c8bacf5a1f823b978aa47813720ebf51b110f15b018679246dffdb177ea2409127674c9951f9802a34f671d26b6f38d1e09b719da056f3e19b44d96f1c9174d52905504c68c95871f5c0565b41d480e46ac1b652cbdba16c05ac747424bab79de26ef11c585b52c6789a18b302e3a8cf06b807a8fa176e0b095d1fca1341e4be8ee96af60fb34ae8557e36239733d2710615c58efd114d17ff8d1cb4fdaf8fdca9f79ca6e1985f12fbee7bb0ad103da0a8f0cc7d93f635be7aee7ebfb5dd54c9d19f1af6780af01a61bae2758db27f0d40d919dca18cbef19fa8f5f90462170f8cb51b4e78e72f64fe5ec514434cb98a3974f4a5aaf482ddbd68e6f2d698fff5419e2893c92391e68f19cc98a465bef7b362e784894983937407866230348cca10171e854669a8c18f0e7b51278f03bbb388fa5f16b21ec3c61234987e9bf7a07754d68abbf09d72c6e112cb48349cd10b3ae680adc97e729801ec0caff249cf5315929299ca6b3a384fe1b405b01bbb58b1272af253886a076be6e2821f87531e5364b9cb1057f7ce355d0f3c10375d3e864d2d8e008cb0c5af0786e2ca0a7066e1f981a36d82bed9d19b9520bf1b01ea822e1c19290be215d601a0f8901eba7e56e08a70dc7a7289a009cd78a0e44654a28186602c38351c776a8fe43ab1563f6fe7daa264c3b4b0f2c28dd8af605cb062dfedeb57ad9fab731402ab038c6463ba7a2c29632ec2edcd07413d95ec218b85e9480436709c2e722c965aa2d4d87a112cbf4c3762ec560fd8166161f0d8a01d6dfaa8a4f9fd659fad4529fd3664340572dfb0946f5e5d7c3ef12bff588de692a798dd37a109743596dd375f90e757957d89c89ade7fc3edac16a1ed3552c64e4c337431b69a60a30715636aea7ff05e242220bc76bbe7f4238ddcd72328bfe926bd5bc35ff70b8c741f98fa0404209ce6900fc3e5ae496d9f2dae2ad94a15458d41d40332149676dc642442d912e34399734be962a2a7f9872f0a3a03058db7a0911e8de2ffc989d6469aa5a23cb95522240b5fa09de14599d3257c2b33cb7a506582b692a3059671a76ec166c9693a28d5b210aa252d95917353e3160161627c70a38c738e34d4f90ed13aeb03598f231b5138d93994b963006a0b4dfc3da4d531160581a3238624b6281a1397b4a1e8b0659af63cd1fba5a52fb6318620e052336e80d46de33f85ef5b67d144b986f987899c542a4bfd42c68cf6993ee180073f38184c955171a0b3097146d016ff27bde6d8fa3558d438f9c1b54f41445f24fc26f0902ca2092c7c2b36538363da10699cb3f0b02aa4fff9d03fa0e9afabbbf31013b16b6a2cf32873c02287a95b62a32f25492984c4436333dbeeb31562e375796cd70aafb911f4a996b1edbfba515514352d605722540ec9038efc6e884a17ff98806377d8f7e6e5250f507a911ac48d170223af6eaaed964ad3344ca7bcb6f5c1ad9a74fc18d145a9aeab2e80901cdcaa00c4570b9861c09795bff9661494c6631e47d799b7ae14435043d5df990d9a7ee9c7bb051d7a867e409084a4d813ac3fe0b0e307334759ded08a4e8e1f0e6d512bb6c6c94af97d166730dfa9e14d41185fa8b8d8453bd32fd20ebbfca2abe1edbe66fc4fd94cf29d1c44e44d83d647cb25748383c6a60cb156c29c2a0325d01d5ecc681c92a3c5425fe1baedea464a9a0372c5ca92179af16e18ba71b272092c38675f5dfb9a0f7c39e47cb30eb7a2fae187edf77f9e27f6501efc5afea86d9cfdd98002a356c13bca5b4cbe37a7bf99e0039a7558c5ec778b6c9fedbdf8ac71187e41fc6a08f9f3323827463f67ecc2020781cfdb3ffceaabe343c2d4548034e80644db5bf92e5015878d3df0aaa7c118e75bdd05eae0cd546cd16874757988c3051785cec3c0dbe7e628487cd82ab14793a7af664bb8bf73cbced08975c57cdfc3f16df670c9bc66426c6c627ac2850be01539ecf04c6534aeef22a4da8383bdebd7285cb36e3efad41fce9ab8ccc665b9e33f74612110129f9abf93f9b332b9396695d586f715a48190810f97405c655e3f0d10cb45e0de7e5375f15ae8a37bfc77b420bb1b91c53cffdbea5e02c489a37bf0d1327c43d765d138cd124b968106534c3c8ceba4d59fd3d3f6e71058248bc3becf75fca7d8dd10ed576830d0880fde9117a5947e21c17fa8aac196fd587ed5cde8b81e05cf72f530cf528da739fae116d749a007aa61b08b3d9d009fd4b087e49bc803c909cddae2838d8318f8b0b8c9256a0d7dfb35492f5adebb2524d6c1c51cf0ddc8663020c8d27a3e77e720346d746fd4f10f5330efa587748bac42bc9d6b23c06b3b6641c40a7eaafcfa4ef541700671f21900b5b24e3d1ea8d5d98c4684a6ec0659b7723d2f6cef88bf4c6d53c38745a51ec32b8774bc35a657c0d7fde0636b9cd805df38945d06a2f9d1310423c16fe665cd4e188e7a748823412690a500e5be1f5abd86756b69f5eb4a186d7f2199e351533da58fbb3874a687fdd762959cfb6b3974d60718f097b8077c329e7a06b3287c3f015fbd35c96a63c6402da85c8566a066fb0a4ca147fbf68b92cf5877a052f9a8117849ad5c2c35195998aad929fc414adc932ab689068690f34d092211d94793c13a33b21d80631b7d37f076781447bda4d6f3db057fcd5616f1b97457dbf3257fb617c5b54ca8a6e47a6c0420e558d6a7422c34acb04765ffbbadb44d405453e3e3170bebfb64dd32e2ed84e849ad62532d223aeebc2d738bdc024c82303cf04e9fa358190a954e1661661ca2471bc00b473f2ac26758dfeddc885067089b9e94df9146c9d01916e40fe488a7bba7979e2fa068cc5b46d4a2cbe60363be0dc4d2701187011d1ec16b6f2a61f5e41659692e655fac49c99c6f239d65082b3badbac01f3b1f8b8723a24f7ebd92d4de575771ceb29c8f04b6a4353b55c71e095e5017aa9bc9c5988c275925e59c531330db843b0e6941c285abedf883605723c92f08a1f8784422ad22b324c03a06b65603ff12c3cef3ab7655691a4fe5f9dfa556111cc63a681376f70ea8ecd8b0e9d720f728e12861986dd88dce722c2e18a3a5cc084be13ed8e8e0bd96cbc70c5f084bbb97dc6d0db46e78e8e2cd88e3244664574fe0fc0bc308855bafb900662b187d1c299a07c8d1f15d29678fe3c218f28e737a0e85b4db4ae60e109f1dd6983c767ef7cae6974e2afc25727697199a12b967ce02ddef764ceba6afdbdbae4442cc1f2bc2866c7054ffa4eb54c97368666626d33f481e6fede2164f930b7a2642e7e0e7bf025f8441a09b53d77291f7f78d05cb92d39f5844d65aa962621df4c3d43d525c705089e997d23866e3a6b148ac5dce1caa6231f797979c8013d3f7fe094583f601cddf250ab6c5ff64068bc2e6de185618ae1c8d8876d3a227bed49d183a223126346aebd220f7f2a47196968ea19bcc997f2eada434c4dcade8bb59b08e972e4e5e00c11a17a2318f654fdd0437e2bdad5a72ed6c0315154fccaee24592eac36ec00064e7830c3f26460f59683b397a56954105edf99024df67230ec5d71f62321255260c29da32cda77ac82ed30f8ae1b43b0133082019cd647a9dfa66463f01d8990bc9ef3f75efb0943de0b9e927f9c99913936435b6928ef67539d9eccdd5150f6bf9e3f88e604cda88735bd0394c79d6513cd2c54a2a1c0ed4ddfca732402d09f235a257e5d6dfb672eb5f1a278571ea7c0dd86d6d472f602a6e0e70fda5ad2ef8b25bd8accee30759f40d40c10396b6afb6b5705241e8a3aa7769595bec491e6c0b27beefe927a851c33ae5883a431783d7812764568e937e5eb0dbfd9eb5a235059be7041a97a2b4daaf9130283d818a833d154343e34b05362bf6ea1f70cd7ee5d9f24c7e1ba2fc8a61c115f9c4e2c2dc343541d7ad08091c881a7c9d74087215087a9b70c3cc0d54454e3275ae60edcb9351e5805ae58d1309e37297f8fe876efeed37747b71579fc8a4b9db4081f2943c952d960cf4eb4b64e79d02eacfcb9bcb5811bb442adf5068d6b97ffb0e2e128a18b676ae81b386e152ff06d17b8c2da4a185148111b67ee29fba7a5de5b37663129aa5520178ee44e0e7f0bc3b85420f944366293ef788c4e114dd9cb3f2e110de4c8f430469cae785b1d44ef36463b9e12088671579fbfa3fa949d6042e8da9bf76a8e31cedb3012d134cd94394a788da25cfbaea525c19a690ed30bc660219f0fb72aaf48b0530d673b2902d5bc078a00ee2b462901a0bf47cf84c7210ec87a1280eb49ee29a322ffab1bfed6d5db09905fb61cec0683ec413566cb8696d757491cece0b1526ea548a015eb4ce08183775cb1ee0375c63aedbb7c36fe380384ba3c5fbc4f02666ad6005039cb25243511288aa12f323a88eb6f255a11c0533858f0cd235d6d58e65025808315524bf80de526b79d9c5ac3f558d1ee18aedad19858a3cbf0b5d325f641d357131905d50899995ad4daed9d0ac98d072fbf944016ade9701531770dceadad495aebfc54657cc9e0ca62a118681b44aba4e0fa3721323cdc5ac39c29e2595b6d3e0ce35d537413f1a17f993cd6c869a93e50ff8efba75873516fa3a80450635b23d713d71ba79e11cb2e7d75b8cd76df12a45d98597f17c2a88fdeb1deff4a275ac37b1d77c8e3feb86b41458bd34b6ebb65371dd45e230b692cb2501e3af6e6b43eb797e6999496d4c005967b2348f283c1969cd44f56bf1242d9872db3a332443009a5da14f4f667c721edc199458ac23dba5f345245840b2363fe29d52fb179786cef0c8de7afa0003e682fae14e9c673e1657cfd321e90981c825c29a8fae186a9fdd422df78b4ecffbde3dc422425daf40e9fc358b8ca4fee9f7d1730b64214e0991087d3d0ed6541998d640447b3235500383a24321f18585a4dcde1486ad6023368fc01eca8970985805338795fabea441674f9c7e4f9c3f7ed413cbe295556dc90f349838fcc3e488669c85df6e43adbc710f0fa8be76f436021ef2693f331a27a3195ed319569eb3771630316b4d39fb783ea7c6c58e4d00fb2a086a047408fdce52e1ec8847493945d9dcf67c12fae4c9522d0b257bda6b723670118c7689838650fd9d03a4b225466cc6f349247f5a9ac93b4c0181242eaf7bb7fa1778b5d8537faff77995281d3c10bc533b5901de03043b066d276252329a77b2e4856f2055ce9129a96fe9ab6f19153dde50608d2c1e5a836822cd3c0b302256b6386b99b3ad17a17249c5db571024a7f8fd05363ea550c29514f2457f1f1849c982dca187c1415cb75d93811587603444e8ea85b62cd712bacccddb9b9edc45f705416e820c8ffef4ab84e179bf05c37023d2d6f64a4f1e032cb8b7a928222b99372cffb70a13024bfb0e5619c27f47c504b445ce040a0055f7121b8542038b5c7d0b0b305c1bc4f662249318615b05fd04538cff4e5afef4456dcd08ea8cc54661a82800bc5e4f3cdece30a3164e144fac557c866121136232495b7d4c7479a062e44077d7ebac11946f4bfdc5cbf2f8b1f7c883fe478bb2ee2c6792004a32838f7738542a38f653ee8bc9505967dc4416f80c527decf5ad75228a5c9b8d0642ff1b1ca8e3ab70d1523438a0e8adbb312a2aeef771805e9fe2158badece6abbef7c259762b8a7bfd7a05bffac6e54a0fea52900f43e8ba0f3381e5fa5a16210d7b3b36718a907e6e6ceb01a793ee46b2b5ae2de0023f7f2e65c85b8bbd6210a91ec92ad160ca9992be2a0332f2f422daa2bbca865a7445d97e74f0f6a48e0da7eb1291cf389c28f604a4f47fc02bf7ad6a0d862ace22d706962b89ad59058ba4d92c3e32ae21a2c1311b854870423996697f91fc3be5c2b8c4fbc7c77873c4dcb501918041ed7fc693aac766f0b9735cae88dfc69ed26bee89d2c6622270b1fa19deb1ef33eea4aef2918fef664b2510a48d8eb2c98fda2ec68a4508fe5dea4b3a9f69cf400d42b934ddeb361b2d1f99441fb3bbd8ca67574df68be0e50127e7ed7256302e500a0a0320fb67d2e691d048a99913455765576beeb63acffe87c622a85c9b5d1421080ead927518b4953d637f216c6c44f9e20b55f344223df293e08ce0f01afd32751f1e6fc994a4f3f860109a6491028dad8e9991f29c7c610a491dace032dd133b74b2fb6e231b58143a778f6656f5577cf92957b6011d7b9e77a46574f96355d7467f282e963c627a35088c78c2cd8caa95fc1ed3b8fbda2dc6f14933ac54ff4245714dfb50b444c694880bae26017ec82c724ca644d21371680d7497c315bc908a417ce552757c3aeb02ab0aaa7236eef63b0d044246e18679dbda1a1fb2d5194b08c0bc608bd1cc9591da1029cfdab70e67c3be2dd4bb290fe82b6105847ac5825705feacd40bb1ec71ee5e50bc4270375853f505db735666cbc3732a881e562dde4cf59afbbf113272d5711c1b7df2cb30eca1ad4adc993f3fe07ac44244ff21690c1e6d74e432a17c2314c13e682d3f5cd769e31bb0c162745d1e7e60e4479c0e682bc2fe31e8658c99e4a149a20bb9e89ab97fdd5d74fd9423aec590e45bd9c13849ed77147f5b56f3ff770048f945f9a9446d570c8284d695d7bca1afb068ad848f6670aa78fe3e21b658c0b66b12905fcf8a8a98c76a46dba520cc25b9db11cd7b1652183d967638fb9d10a867af282b29632f7df53fe1255fe2d84c55259f917332fbbd046b70abec0fcc6d46a0e866b3c7077cd651aa764ca26f29dadf7caa635efd13ea0d1c1393ecd7205febaa2d3b319b57f46d7d72f3066cf2f07d8b8719aa1e2276f07c468a4ab86da0f5ee0cfbb6a6804f078ba33ac5f9153eacd50f6e73a2f845570487749b8ad6c53d6ebbf676645fc83080679a3841a891bf49ea2283987081d696752d53092321948ca4ca89257d9d31318a9b75401e394fd8bb134290dcee6a4cc46f96120ee1005257fc316cd2494a5ff25d7b0351bf44baa6157fb6a03d7e25227edfa71ba71edb83b8b4969daf855f691a30e4f353b134c2326b0e097637e8164fc3bfac81b6218745d8921b037f738ff509cfcd206cd4869823860e1e9c19de415ae95dd7aa7fdd786f6c8d52e70d60e4b30380b7c368ef4d43f428bc89ecd118b4d263cf70072b9432c91cf91ea6a6b1fe2f9e42c3f9327381fba15c5b7e462e8f3b00dd700e7448d5c0dc4934b028f15f87a8ff9a76b367a44d09e0b1bf5f2fd8f4f98bc6aab42ab04afaf16875758c49e984562419f1ac269d540de8bc975a7166ccea69cb4478a786e3b6f32129f4ad5d6ed57cb260eefc3fcc8c6436b946c1baa5be795debe7004a4716daff4d60f4f798c791e50e8c5dd22e9e6f9f603d8478de6567b0663d23bfe93ee69089ea2a6a1061357dbd6445880d4ad71d68d36b15bbb6f731d5756ea95d307ceb3825bc0c0f86e098a3b33039e5a5771bd00bf36a340c564123ba3be59a137da44adad0bebb71111d2c20dee21384bc7e0062edc41ba1af43d2f6befb39deafa2d6db5e52a5b933baebb54d3e7a33c2e7a09b2d3c5758e8c943163a1a263542f1e7ee949656ae79690089866d851fbf36c4a25d9da0834055dc48ec13f6541bd7a57042352cf696e30de7f026b2cff68b1af9875cc7027584ea04b9df1e60f1874ea520417b928adbc45b7279acc08eebe95eda8c19e532a86781fc971cab72cd1e0e3d22af8fba8d4498fab7920ebdeecf972f80402f27f61fd6fd2d6ac358515dcebf0c7c210952ffd139957ff9b92dfe6e47e5375744236cd4cbb79588aa566e7d4e01cfc71143767e89e323bfb0a36765cb98e074fcc4fa3b31177f725fb77abb26d3c60172f08e2868c1f0cd0072498c045ad2f24d25b47291d0ee7fd314bfb641b00115e507395f284b1c5e10f9ac10f57cf14f8e96b6d9c30d4aef488f63c9f6313940b35a3c774f2a85b158b6754e2a817ee7563edc2096d5d1399cf6fcad42d538c9ce3ed666df86bf4a8edd35d35f09b71e1ec6ab774f48b4a8f97c8637528636b6caba18c959d3172dcf3fa1113378c8d94dfeb3165873ad85623955bc694e0e2d120b1955e72f5f62d2acb40404461fc0697e4df26f1ff1c46a035a50fd581459ffbd7a42400ee4d0a38e4778dd18bf80a8531e158193cc911298298b03ff261a8a19d6c15d72c4a18cecd7cebfec1e345d4971562590c597938bd279ad6b107f662d6e5d5b28d535198359951f030382fa07c1e7ff09a5a09df207db1dc37a5ec8b930b50eaff748d116a9a2d0d40fe91913d2bbdc21449622fdb4e7df45b9d7c662d5bfa5d5b0ee78369c38b29da9698e99df071f36066d4ee8c447ada4d8799cf60690e3740be48d8f900f62f20e783d40b7ef8443b2b44fb0d925f9238679592909586ac4142420009c3cf50da928e0c016124012333d841e0fb7ba1fb8aa0d2ff34e3ac8145e10b99ea36bf50f66e7ee64e26e89422a3f7b7754300a3f05cb3711f1c9ba83a190f6cfb9cfa489289d7943f83873fc4e2eb93ec605dd4245afadccd35ac5e2e797a9efeb76911f7789fda66a77b3629deb43c31ba76a175e6b78c43f0f9f1ca225068695616a7761b3e1167710fe19a5141c34f114d0d6aaa2361c383a6c291513c09759ca24b8010295e160fc97305daf25247d2d034c9ef37b34da4a0089cb25037bae7e693913860a79936e6663b9caca20611efccbdec8d7ecca5c831e7ebd7078aa1cf7aa1911d382ce04588713cd26774873ef7a1770871c671e868fab9cf64d6a4a47945af4f706172399f6f58f46d4324ad25b5543109007a88fec244d4c3c4bb74de8b4aaf5c3457d3acb2c1229d5704dc170ce434b44d8e3d1b6379136050a8ea676c1dafaa4df971434de508da3491200a97a12d2307f0f5ba060dcae39ee23d8719172d0c54b8d73a38d21ecd76b20bc24d2575ffca355361d60102ddcefbde0ef5d35005c54579982cbefe0ba2b681bf395528e45b4c39f1d6a384f84c1901a3c766426446f6bb0ab12c8e0c7742686f78f192c7d2266e8b748592d9f84fcd7181693403f5a0eff3eff56fd813b577eec3d9c0f567b8cac1627467d613c97e008459ffb9fda21eb9db8111d6e43b9d81e2a7df6523fcc179639e78b5c2b1ff1259fc5b31ba21502e6db1a2956f9a070714fb0e02539f403054345908dcf09ca7daa665161dcf4e81eea34c4063270bf8a601826f29ec4b00da12517765fe9ec9f73d570d421971470230fc5ad7da67712295393f3f6c9694d5057426da5ccd8915a7b9c0ff5d8ed70219d6345c2b8ab437953387025ea6f2d562c84c8eba4ae57ef22a00ba9268d09463d84e11fce2445d412a3204bf31713e9378261779ad0a617f35adbdbf56ebd37cd0382bdd777a698da9b10f654462d9defe58422188db877df2e955ca464ab149c3878622e5ea5e39b42d83703b2da489c1a11fe6dc081b35ba5fb9816f88085bc6427070dc2a1cec5325419992af2846ca9d16a6e14b343a709abb0f2739e692b661c36212ac4eea33929ba4401f060e7cdace6cfc2be2101f3bb73ebe317798600e4ebbb11e884a6ddca81f6f6cd34561f034d92beaf9b29480d082dac969a36eee63e114e6238fc314cae9de43737f00f1d8cfc765dba4fbcbe4a7b1f974c335b5886e98561bdd4b9c4bfd50aeb71fb6965444dbdbbbe66c064092881e5c30eb1d198dc59f0ec53615a5a122b6068f8926d6abb9bb53d0c6c4186f9910ca3f582b5615682c695bfff334394dda5e9a5e0eae3f26c2366b480b0aefe60e858f911e8130878944cef1458917cf27c7fa91c86c59a911eeb651664c366bb1ed9b9b2b3e33a9cc50370321922a95df452c69a553bb908be5e7e90f6801217b85180ee0981e8502739a1d97d29ddad5f4a4514b9d8596e43fd421329648ced02c64a61336f5bae64380d6148ab60fe7caa229704a87bf8d4a3f43d3efc444765db745000fca4c850cecf58942dbe42c28175a5ed95be8410d65a8a92b27bed754ad56db3e84b43bb13757c02c82a2adde0f511fa083c170240a530858296da220e9efb27ef34337c7f27294abf098eb8011fa7d887ad55cdf14bc690988607161634aae1121713895e94eee171095d15d6b2a26a4dcc8a54346d974295fc5eb928e42065a071121445fdd35483cca0741f48947e4615d8c53867e3da54cbf3b9763c6917b505d226c8fb32781b57bf277a51cc2a6b65da1c6ae3ca9e32069affceab5b60e57c1f7ab435807a63cd0660ae90f1b4a0436f3d52c8af58fc7f487c638e1fc45ad265f9e563e9168dcd646e59d86026c2ff38a4bb1d52e51b37d5b740320b22cd83eb156625b50bcad06bab155805e95054df15a88f1215b020db2b10f51dea6703d770eced2e34e342b1f96f3f5fb4c38e1b19550a487c0d08ef0ff9907530e4873a1277e5de23bf14908b96fc1b1f1034270b93fc3046fdd5310ac5a1eb69a21a58b4c8fe667f6d781dd4dc9629f1fb7ceba1b0e600b94b9c7d1ceb764db1506c8ff04cfca99e60fc459f36652d34f2e1f52f1665ab37d2297f01f7bf4ed73f7e0a6f863b3dfef6f41d25034fd56215eb05d3474136eec362d0558bb457cff072a10412b0d42ef5ed7d9f9f63eed3e9887319e62fc1262c33819fcd46969d2edb024d0358f723c73dc475676802c1535a321ede790a9159c68c650932773dc55c6ebefdb7bd3988c60d6cfa967764279bb0ee4f367492e57b157338e596b381c4a89c7dd0b892d3f8186c211bdf4c6956c6e06fc131663aa95586d2c1e928534e98a6afc862f3a650401a5407c9a1c4c846f2e380fda34fa1b6cf819c693d750e813a2c7b400e51a8179040483a0f390f34a50204b6902ecf43746e18603052514c0151013c064cfeabcb5e0fa754eb5fecaade34421d72d963bdbc9a0b495f499dd0b504b666225cac6869b627f7a5a2c40858b3d2d6cca82ebcc21d8edf9193833fdd0b6cbee3e93bee8bd147efc8a16b3c74a4193bdb03467bcef076328057d3ce715ffdaf32aa041f9eb217ed351ccf177518820b480567db3b789689aa2345bf9ead5f28e8fa422452f89ebcf64e22a00c8f1a7a1445d6f6ca37a49abf627e23f32dd08a4801e1e0e698889d65a9b86c2f92b04c7e98b9f8c4ae83a0e711ae0aa9cc0584e3ed8fae8e8c906c6ca5ee333b0254db39dbf2f74cab75bfca34110a8cc50cc8979d7291155e568710dda5490a1301a87b6a93ba72593d47ee25d398cc3641f96c4415f99aa959046cfc94e088b7c92f8fdd1ae316ba7b066bb1cbf469c6c0a912334f1d8aa8ee6e50d316c5fce17bb796f2328d1763bf46db9dfd3c8b2f66c69c5fb831bd5cf39a383a43ccb94dc081a6c8a9514ab59b3d1eda030c9710daf0677760094d588fa4f4ca84231e3e1cb1cfe1156ec3df3f0edcecab736c62b001f562290fd45587be2c3f40912eec416cd3bcfab9164dcff3ec200cfc0cdd8b0eda702d452c8639255a3728c579ad272faa00da4c7eed84f67d5e86b3ce63efa5837b36cc3d57d96e4c927f82b4864b35a65a877627babdd14ba2055f631fcb46e86e0ea38aaf928e9b503ca057edb14b31b73c30a841f22f31c09991aefcb437da2a2cd409d6adb3c43382406bea6afb3b7f25c42b4eae73d9e694ee1ea8ce3e71c229b5df41107d18982af9c2953a74eb2d48006e4a2475cb1dd9ab9579ebe7dbdf20756e1ee08ecc4b4426242b4c62ffb371fb4dd788a63974faa66e78dfce9d939409e23df60c637462428ecb595dfb058cc58c2d57ad917507d8fa0212808b4d6ffeab3cc37bde9db17e871699b21227afb282d285fe3b4a34cfe36872f43c6944e7c44106a2d8a63d970a497443b27d01ce7f0b54bef2177cf7fdc19d937b470f8193ee1a63de0100bcb4c7c7a2d0e6f6829653d2a5e0385133dd66edee5d54bc5c1fb8f507bbb579b0ee62967972c0e4046790c447898ffcefcfe1d08418dd2cf2f37c8c0afcab4bcb465736328990774499f5e4798fccb97ce3152e9299995398a44be2826a738744bd54085c1263135b0ae6a8a837614cb8226695e4cce3b36025c281cbb9a6f289100bc67b90f0703e9248b94519194189ff8425df06fa623943e27feaaa688464e72a41896aa93739389ed477ada4d6b24bfeabe371eaeab2ef191c299d6979cdb5f48eb3ff8a4496cb6ffac179e151eea8aac00d6d4789e4b4f9f9f2058064ff88c69faa62fde92343c3627acbe341112581c49ac52516a85d1c87a2044314fc23c6b5242030753ae5ed0c3a5c450a7086ec020cb11198cd35531a82bccc765e7db93b67becef45a3db3ebeb5b71fb927891e3688a6a21b2e02b1697c52a15cede5bbcebb5c1f002e5e0eb419f51063065d8fad5fc235cfd11188104c857df587d006fe1bbead397cec5aa8e1a5fddabc1efa0fb5a5070ba529e3045d1983fb764b866dd250e05d8c746ffe04534531263587ca11318d3e078fb2578c145dac8449f376236fbccbcb32784080fc71d4b43a48073e7a54559d548678d605acde017f0ffb3027bdd3a66aad4add9cc0f55e2365cccfe8faf3e0a5326f1d56a39ba8d6ec80cbd001bf033c0792c24365b7b8e381e197d463fec2789e0863614c8a20dcc06fc9bacb0a83948dfed9d0226a3dfe5f2ec93ad79e312a0b6d0ea52cbb8b74086cc3447651ddf362850f1d3c6940b89f92eb4342bf30a01b8a124c3704b6da06ef8fc37c325b385b266381548bd8b6ed301a07f2f5be86681209885cf6f1ed33ae925909f30935231f95ffe828b65b73e6d24536b919a6b6e11e37051cb7f0e244a12f8e6c028a07194461b2c47f851e9b7a3dac12e19a6839abb89b4b4477507b780c4ba7fb93f62083f81e673904c1baf4b1498c4e4d1c46f9be987f2dd151057741f015af2376fc5be8583c9c9fc02773281d971110bda04cf3c09c70d45d6bcc5d22330e219f8e311cc449a94d1d6e48c36d3e4af2c35e06d4452a75c87fde0496e1dab79c9e1ed1272b40b384d0bc528d0d35a3c6d41d35ffd645a6ed1aa157abeaf646313e50060438dc4445cc4f0a9628ef8235ab389bf458e13666135a7b219e272617aca7b159db1222bea58b67c377f57e1e096537003517849192b0925034cc7e4df4966c16a125db62fe565e8123365be73683c7df5887e85b2411d5ace752ebfb8e92da04d66572a378ab1c80e99aa46a84d38c790e23555fea9a3474bf561af57d516f42402d0b95a11935547a1ec373b9e9f84ef85724f7893c8749df6ffac140b6ea1be1fdaa1c4c44dd7b797cc1aac1d1906ed4f7300ffcc45abafd2d458342a296556d57e6cb4e556171d6d4ace235b79f7ea1decda3efa6f90726131af8a58a46e869cecd0380066181c1a29ce130e14bcdd53e90fb647e877cd59d2320ab6827aaa22a74d82378ac56d6fcb7c5aae678a8a76c086b3ab789eba84a5438d989175ab26276a47e7c403fff7fcdf13efad60fcda952cc70911e92c5eda2bdea2931d3915b1aa6e4efb954964147c768d0aba364e817f7ba5aa1e361c7ad9acf57d19b107aa840f578ea8f9c301bf8ffdd4b61f72a2245639a86e4b561d09d8727afa9fbabf6cc894bd9fb9a505362e9fa2353f933b54f617eb3942ab874f3caee1bf384ef27c0731507d4662302d62b709c484ea52e93186d68d5ec3dac68d9ba426a9270a66b17ea72f3ef7a7f01ff1efbc895323db04e8a8fc0d8337905031ef6b4a670f36fe458f1e76c7f7fdffa545c40e72f9268b4e6c47142259ff6fb3240afc1a111d89026ffe69e413fcac02d091a28eee5e551103e4d9269b6741723976a7a85ed0faf7e8e71e58d0eb715242412db070983fd6e132f3cde988abcfc81458b15bbac71bd857f18076352d0d81adeffcd47cc9555dcebadb2eb9ec1965a4e904d126cd7ae6d03f849197b40bddb25ad978b31e5f575c2d4c8990577274bfe7bd6f276cfff7ea626547c6a78567aa089a8b86372f8b68bded78588238bde66498b8459b0595e436032acd3a154aad6bba3be1949659ae52b8308e61022248363b837aae10db16900124f1572555ceb7a0e9fe243ea99077c199801f95047e1d6fc0bfe974a679e7ffdbf42554e832fa6fc3ee2d056648494f153a287c080552e0c54cd32ab4bd490fb5c49b27aa77f39376fa10c1497386332a2826b57c8d83b3b5c091a8788e385c754b57699df319ddef83fb445ef2a0ddcb5de25a05016da70878359e828fdd2d0a6a5dda910786fce698c70ee7cb8cfc9ff4690bd96737c8989db60d435264ea1688935504ae2c9da3b2d1c4274c613616eb29191b84db81699560f9a15ab35f6006da69dcc85620861424046963b26eaa17e407a06834f113e63047bf585ee7cb8bf644d0ebf57a462290600a5357e60764f8c5dead06222618f2f070fcb9ba7ee9f443d9d4559b200362fd57905a3c0ce25f4b0c204a31529d41c3653acf53f2b927311eb06a1d1740bc62160f33830f83b01522a362d162740f73f7f6d272cf9405abce8fbcfb8d8ab1436b171ddad0894f57d5de9f2637f2fcdbe68aa107d9339e0e6075bee93cd1ebbdfe90318142bc3a72932dcf08c9de89c7e483ada9dbd747453028c8f7c0b8e6865c4d1cc45bae887b1071c7fc7489415befbe1e525b5e01b775cc2d5696f946fde9c3a101a002132b97efe78fd9185dec1d1d8decd6992a8fd16958d5f290dd75c8e39b5f0b092b96090ebf364c0a21b4ded45795d8317edb21898113d29893d43b51823b4196bc7efde314c928503ee228f1595a5ba5bea499ff702dbe0d2dc2b7c0ad7082a29f12384703206d1f9e4d0d1cedc6fc4d0d6c85e9564cdd39c3758311041d6165f19854257e67e143fdd361da8a2fd6004b9a0620d902415c6e85ce90316c3c735d2db4850534eb18e89e043d319f7d93f0f45c34aabba34a8b2e25ccf08887b36aaaa86aed28c0242925006285a172dd52c699582903996c0610c4fa94e3efc65b668b6b9891f60179db9848686500cab866e88ef980f78d21d4aef003c0e0334a3943b027dc4d2b7bbb2a6feca97e0a6c1ea6f8c41c03e1631b65887c867b7faedf127049f6e95bdbb502217c6c1cf6c5e000bd2e818549f43f2c5603a158d50f2fe4e5480864d5233ed75f945d297b8c9307b944fd0d5078c9ccbdbb9d947508b28af064b9e2e0edf6dac7f1718c5026e828b231d839ee2d301f516a87d7ead73f9cc5ebcfb1ec7a7c90534ce3ce4cb4f63609e9a202fa8c720831967ca8c60f6cee3346fd951083cd2da30a211923a4c4c8ede53b1b33199bae3f024f2f0c97284d062d0a8d3b2414b4557b507845a0dba5d5deef1105203bcf28d2090591f0c472fd4abc6b77b9b36b1021bf4cc1e947021f2893146c25633cae460395c261e1cae6a01b98876921012b5db3112e19e44952733dc492a1b3d6bec472a3c358ae4dc0aacc8c401e25b0dd677e3416244f7f6c83696793262e452cabd1bbcadb6847d20d463061820e196e36b976da67aa560b34931fd2078e8995ff031fd7370736463e9bdcff4ceef84be0650abefc527e534a7a0f66ad6faf00e54618154c2fe7d3eea01265df2c226ac34ab7e3010b8f1f8daf699aa71d41a7e3a3160e1f71dc6a41e70f0f0cfd97f4f569b8241ef98dc2cc4c61cb3286e8b7caf79ad9d435172f1108007b4a1f2d2d98bc6902db3d17e24a5e00481bd3d7a15c4abfb50c5d68b9ca0429ab945d3403ed075c25b3e5011e0f89760ec0bfd7463c13ef8ac083f760d19791b15e7768a9c05edf8aa7436309cb0da07b5f57649b297fb5eb55e97c582fc2fd4c3e29fdebfe3f01a435bcd27be03e131c1af126ce608eca36c83c9e72815475c4d4f81882b0db4f4fa3de51d46fe64a42ff3733c55f2a515bb3ffbb159ca3b1def90bcb7c8fddda30e4632ee08717eddb728935c9b2becf09090045e6b7f1a6215748770adeb57fcd3651d088643c199215c8a4eb46b270fe54739ccf0804c5f9a224fe54a6025512b85e98a20a99db2f7b3a623bd82b359c9c38f7b32edc4088a06db716553f65176e1583cfb96dc05d684cce211c8d1343dc85dca0a1d4496f2231e65366c07fdae5ac0e65d86aa38bf0790db71e900193dba9288bdfea9f205b2122401ea6c556c09a2e0ddc9f04ae4a5f6d0d9d1cbff4405f0f484c557674ee5c337b8d6c045bcd11a6607acd919fec37a2d6ed31ac91bea68b17b78b30cc1d06426760b895c227b1de31a0bdfe29d2a4106af43ebe5f9792989bcba6c744298343b26e6d811a991dd821fb2fe7d55f7043a37637a1587efe444432efb33de725f41ecab5b99692ec83b2113cf4e6dfcc42023c3a85358b648a661a24b33399af1719643abd51930e19e4b537c30a46e65cd933382709de44b1c226b65d67f2ab82102f39a8e713a62ce3edb782848a19e60b452be3a9c9c8a7ec07aab44c0e20e30e893dbc6b3de8084413ed4094c6bb42225314a285f73985fc9948c9a6922ddd43ceb17da50e1dda2f374feb79ecb444fad874b1f6807450a13c136dc1d8b8a64413b7593831ee4cadc4742ff5d3bb0a051c3e7d0a84a8eb289c673f94b28e76d1bcd1675e35298cb83076b952c110923a7b92f3015e797fdf0a7db59cf1302e379e121461d307b9ae22610bc1cd1fbc6e7633135dcf4872e84dad0d791ec6af2028c7cac9bc24684961ade9f21ed3a14f45cb19b390c620cf09a16d706c8b394b37b0c6c39fa6b6e4d08e4523c95d35066f5122f3c1ba4e1f90b572a13745d1719dc0fa27b34a2352cd7c44c7ecc825116a655df34e453fa8288417b2ed3b148f9dfeeca14dba195e5566309361eab36b98dfa75d7c5a14ed4807af805318d76aeeb6ddaf558193f6e6c6a8eeb31012d49a6960c5b22b3e556999f597cca99f17977b54357431a1a3ee5338d2bf7ba273ce5a984a6deb8a04d450c45cc3c8a19138d582002b386131232d50e53fcf79a8ba1057d1555974c91b16b3a3c2c07969c4c9b39293ca0305afb393c371cdbaee870dd048982171c06be2b03108ce4c567db63338755ac8950be9616b3b5fa85eb9b7aaa1c85045373a667353a8a4f9dfeaebd820e45228624abf1fb80e381dfad18acc3c4ee10dc688007795f59968d79a5d0a70ac64965916e9b67953145b66a61de8637b442585186e3889d71da53823374bdc2e0da10e37b99f30d78cf92b67ebff5c835e7ac92cca972deb302410a00a63eac69a107fb05f45aab047873ec1250463c240b7723c973c8d280d244349bd68d4009f4e433e21aa14f558da9213323e5c7f68b988ff1368381c0eaab9f3e76d695291bcbc9aa4917b4e81166ab2b6b4c0075719b000d271b236bd289045812304eb05d6b87f99404204717ab25feb66ad1dec5a61c9ad50a1e9bad07fecf1205329f6362de715fce8b1a91e927d91ccc92e6a235fb9975491ec10c1ce03b1d5255d613e829973029ef7be886d8382843c3cc01354f8c75c30164206d64e0a98fa622067c7f3d3413874c35cd91117220cdd7523cc537b068b1bbf770b0f90dc5698bd6834caba0a40e97407dd9a269b3475d2346addde0f7c1c0c95665134e3db681e6fc323ade507b1a15c800bd708ebd481a3247e0048b122d9626bc553f4461aa71adb0a40c6c6f6133ec6dcc03e50e848db750eea14672dd08bef318d91dc3d186424eeceb6ffb6fe3541074334449e2478038abab402bb1177a57a8ae4a82a56343100758b32c9221a43c504c185b8071f3651783b6adfc93c9e51fb617f7f61d2c4165702b72baca6c4f11d59037059e17d7e0a29bc3fbd576ca28253cd03407407f4928f58a5286e036d7f624d3342af7b0b322d151663167df0385127756f7df96332529589704df3f3afc2833d102aa5b5810de543eff8b7b7b8a08a32468fd92eb4328fada1ff566f2a51a60bbd6349f51cd3d0e3899161515e7f5ae4c7777c167f46f4735f4f7526b1b8077d4382eb32f545a6a0940b191db7f078d59a51d38d921f9acc8699e6bdfc3ba897dd197bcbc59e14db302ab3f71c79839ff810a297ca277e7fea0d78b514f8a9ac3583242aa3298f54560d9df8480b5bf1ce6015ccc1905c69023f6ab9318b95a35701585e7b209959f789c709b9b09fb9d49467d817327bd277675dd72fee15418f9cfcb1d3438feccce6e472ee0ad8ce9b308012f74d44d96a6aa2a65ce425475312ab03f991aa2514c43b8773b83c88f8ef4fcfe4a272bef72fa4e42c41d9590f1b1cfdbe50ea26c7966d0e793100dcb12c639fcee370ff264d61fa752eaa1b245ac3c75cdce73a7a421b124d30ac9905cfe864880c321e8c55d59a4c022bacc418a73d054fccb34cf70d0faee70f3da9aeabd103c128c31fcda41ef6f018e60548743ef590cc058c9431f60faa7e5f5fffa7fbce2451c53454e3f80e0c5bc1a0b744249f2aaa3d29770fe169330b1e6aee758becf8cdbe804ac48341f8eff7804fefb8c09e756c2a7ab5719032d22b98d356f8d6282360103e883f253305dc7a23053625af0001b1004a2ecda372b8a98a1df02cde2dae592294e934694dd47aec0a5f6985a6b74b32ff817deca313f96a8cd89558576816fc115105ce9a1180e536f0a520767810d620e5222eddeb60bbde743f3b1359f7f28e83484776e33f0e339b46d479928d717bf2b7276c85304d068c77d9e74b25557b4ae847379269f36faa592cdf527b63e4a4fae23f956ac2e08c66205946041fde681b79aebfe1dd205fd5b7abd7fbcb9c235ec51ce8df9d1c0a328e5956dbd889b30fbd35331860f288b0efd17cc276f13d5765213a5b881a9b7645a7c0622918f3a4e94c7b8e95340721ef4f004e5018b86278454802bb61dff67d842341be7961cfff6cbfb6aab78fe412674a6273752fab4a40afe788c5ac3f946a4f061639f53190910fd10548622f204482472377ebf3a7875296be8460c99b4a7c21ddb71bf029da9680b07c3b53201d77504ce09621c16ed604df871d2998324627669dea5f9d7bd43705d1e852a7ad34dc85d588e663ca6179d420434715c65d8fe176570b5ecbd94009ef5f4e78f90629764bb3317ff05ceaf8ba13a9900a5bc63684f391193e51f04b8406dd7d6c9a0311598e854c617a451f3783b0d0878ceef14a332bf78a2998536a8a7f284c32963eb2bd1fb7e2aeb4dbe6fdfc138418b7b4f0d418df028f22f9d459563dba1b57b128f86d998c1b5394a2baacd64130ad3b2f2f7b4769e8a7a74b245d073be92e44e86c8cf8dff46e8784cc6f092f41c38a0561f011a8c90f3106533df3eb01c4e0fe75420c902d25461a42c62513c69873dcc0deb3cb2afadb042b3b406f854e5fc94d51ff96689cce700260a47a848a3dfde3506c1864e2290c4c872b0adaa1ed824ef085c0d520637cfca05c85b0c7f5a48c27eb075605132c7063cee80a510761ce8a8da658d81a12589f7cf1bcdd46b290968ac811fc2cc774fe7d5ee6c3329bb7b6f643c3762f4bf49c1f2dc07ac876be34f88d5b90bde9e97f74e8a6243e6ad729c9ec31e1dcaf407681336e1f4f6df886fde34df79d18af07f3d2e9fcdb6af25dc3938f80adf9c6f6aa8b36ad8fcf7f70d2dcd0778eac536b3b8c181707ebde0476577cde0e20da59ba63b3623c0e7e0669cc2cd3f4d0786ec30c212e354b96339d01a8fbccb8a5ea627192e00af947a8791435303c443fe7e471534c1525df652c91af79b86d2f4a8dc3e7da23460446a2dfd5fc01c18d1b8fdebb71bbf4d2985748b8bc772b0a8d6614ce4b53635c97c2aced4a941de5e9a3be4d42be5eb72ee17ae03ea84d6b27eac551249720b1a1ffd15207f83e1fdec4648b6775580cb532bc614566c56105768a95b5b2e56d8e8ca7a03fd2d991bcac01355d151fe889df41ac50fdcdb8d46caea690a5aaa1df60448ec93b1738b1ea2d5f8146e048b4955b1c2eed470d9610fae1d24ba79d7b8ba3946f10eb36d3dc59424665fa7c286f5bb61c9344dd8844578871b88ef6d553793e26a62b7b6df82fe44faccb0c1428baa6f1f1157d7c65d228bd9dd1c661592a404d801afbb5c90e57961ae6206ad8c5a7715a7b2918f9f5fdac94a3acec8657380f06c8508b5c6a55c0d8fa534b42d3021df2cb60e89d5d8a714f319f1d1028f5619cf566811e4f7cb68ae673caa927a0cc4b1d594e142365701a7a363ce73ec34282a0557f700d41a3aa7f50d4c28c3840f9a56f62a0ed999d7f0369a0b758c21768e1b613f323a8daf38c10ffcaa6fbd432ecc72f3e8e1e106c1c0dec3c82734668d81b2889009acb815597ed0c94d042133163d3f361d2225d63e0b38dccfeea3b36e0b8c64f4ac44cccd737f3f19278b33a6e3543127ac95df5649e1daac8ee8a21be1c42425ef220cae5dc34f7946561042346b3525538222c88087cb7eab07fb1e2c68c428e9582d28bc79d4df3224b932ed192a6f53d64d06704d9521a955b4d9ac55148bdd0c4d97ca18a8458508e355c24be68e3d13a756b2f51c46f9a9233a2b5ba8a9ef60833c0f1dd7c5e83d27ae7354697d1463828264554a0bb072c29bff7384a8c6502761e7a270b5562364e5e7219004c7fd50b4e957be2f43c9f18a95224df89b0e56d6b62ed6d8cb2f968c470dd48367a3c4cad0ef70da7befdad4ad5cae68e2784c4383dcfee3b54514e812901660fdf905b4fe08b31f04aa3cb7f2fe9bce36feca45a380cc40e7eec41c9978aa7d8bb7b83ad2597c253e3e3897136533199248e8f137b59dead25887e428dbab446949a47e869fa2522ea5208a49ca3eb9e27d6178e05ec19c308f1d3a14c2b98bf255a9e3e695032bad17967dff9f100f424a092d65e524770f6e24cabfd43977db5733ea92e87362c41d8153da8253e9e4170d57ea988ebad62fd8480e8b4d9237186c363cf756ad85b128e693f1bba24fc96e55d6331a2ce4f5e6faa6b742c2eb59d275d9d8fef07b2a56b8a6b25c8dca13e856dd6aa9e5bcfc1c153b51e97405db4db1097bfd0598d38df3ab969c72bb0e3fb034efa8393ee4e1ee7d4a4ee0ba4fa3ab2c9b45592675cb8683cb91eac708657064a8a3521332a060a2e6f7583086a13244cf2299931a50ae40fb5e3304b455c4c603450e59db2f84204a88626edc42a8032bd095d9a1a988e18abeefacef7bff1de2f28e0aeb0eec5b40dd64de56115f1a70be8a502673cc59793b39e4f68bb7868213edd3074a1b41c0f87a940d4e99acae1d60b1b82bf7ae17c08869d40533d1b3570ac1434ba4266734acc8bb31314bcee23aa11060cfaed7ba108cef2a182baf8a8e5b7ac7f6117023348bca50de7f56ae441bc06b731760e36442c6f1a2c357986c80b3f094269bc64f19ff8ba668b39ebf4077b440cd030626f07fbb092da46a64c2a9be9655ca182ea8b26b864efa36b5eeee64270d383c4e0d0460e002df6c7a46f2c042bf2b62dc011d69802d60e57bab4b1bdb59c4e164a56c3f13ac058d0d50bc44cc897e77160c34ad556851173ab0a57343c4059cea50434f0109810e23a2770ce54906348c14506ab04bae702af39425ff0b561f4f3b15abd4a4ab35f047da30f741b8745d02bb75830fc43fffe357aa08a149fa8b68ae18319ba6dd727d2637cda792e1fe1f1033fb1d0d853be59b1b587494eefbd3c7ce77ce00408d4d2b625ea471409588d732732d7f78f9bb4b211e7a5bd4751c4f213cfbe592a2230b20481100e1249ff3cedf10df50ebafb4b10f4eb15decda37fe8e9308b8174ac0f1e1bed16acd500994d34e18c4a18a166c08649c90a03af40eb672126930f6ebae3a3e216999d4cfa688774dd711c089b2890a5e4d989452cffa4af8310a059a2da180562ed841814d64fa4af1e665ae042f489d6e85ec3fb5276b9ce20f98777b6f36434dabe3ff2eb76870391e3204beaeae6e4cc5df76720b259e1570ee44f694bce449f3b1e11b1b4916f5873bd630b75539e5ccfdbb04da9cd1c3334e95cfe9bcfa512b32d3e75521779f724a31cf19e8981cd2991853714adeb644ebb3bafa8af83e5aebed9f4b50dbfc73ee82dda3d5cd2e00133340d7e572575c0afaaf706300baf6b81a7eceeacc1e212c3d8baa9860f070a64f66e2319839c371062fff8c65afb0ae639f93ea9eca6227acc9752bb554b0fd6a0d8e9e686672d0a58e3b87f2b4365985a27f9bdf50fe82fdd68f5ee12b7f64112e1bebe074473d39835101a5b7cc5210084af616f27dc58e74e31e7630da0d04dd082c811944dc7950f823fd3ee3bb8c10028af1bdab759384bf31f62df4cf8cea30a04cfada97270fb9278fda6824f913214281d912d9cdb1d46282054e5722df3d8641546e6123e89867298acb5d0e5e19582479befb24e770772657a36db1da062b1268709ba34d24bc2660d6d04fc377001b69724020e0e89ce3efdf88dc99143b9b1fdd3f3d3c74be20f1b9517cec32b5c8495eed2b189c7a5f14548d9456c6db38e68299de8ae9483b0b515d65634010d87fe823a44f020344b63c23c6bdcb2c7a3f034690cb6f1fed3776694cd5977f0108a5a0a72851a3c2fa9e8563f5c34f3ec5769c6e72d5d576ff9c0a5deeadf45f6ab86f1c24df722e5156f27128647f551130624a44d2fc9336dd4409f0f03a550ea2f238c2f8ae7bb6a157bcee9fa650844b705b43dd35595303e7854fc86d43041c6facf3767570dace282fc33cd7414a8e306a272a33ed44c7fc8d9b1902b5e837011c503bf982bcfd5a554f6b75c4c64dc571422b01ec9b565d59b11bb85920b78d5bcc1824aa3de7f36142dbd03e6645b928a52a2264aa1c8355d684a9c0e1e583a280a9e131449916f614ddaa3fd7e5737c3a41133a724dac9ae1f8485d49ba7e23dfee388ab7214f150c9420bcaec4d88bc4f972acbb63c01cdd74c548669106f3f21cb95384d873f64455a8acd995a9de892031aadbd731202b5d54c3635cb0eccd03795bd920126d4583dcc705ba63e5567a68d66257e41bf80c17b53b41e9d3172221dcd991a0d6be32833903cb2b4ba6830bf948651f8416e45220976f2b930af5039859bff68599c0ee5f84919ec058fd6b7254cd898f445ed042f9bbaadcfa0261c4fb8cff3a0ac2f1ba3027e884f8394ef4b4fb6b24a4dda6457879ddfe79e02fc374decce05c20332b896b38c7a94ea32f6812d9d250fc4f806d593abf34d23a9828a38234ec025835a610d4fd2fe22c1ab4efa5b8e87c081c76c71f43af76e564a0a7dd5617902a2a72a3f031134a1c75b0c03142d218a5889bf88a39f54efe6c7da10e1033f595912b27f1da2e8ff4e390eb4f18a0e49506f70849d3a0565a5013bb23ef17815fa34fb65c98661752a8a81e5fa46399f96de4d1932926df11a64e721f0b43f184e62b67306f9632c009efd30b7f454a929536d5b9965b576c41b1078d32c21bd72794b29fc3592e050c5d8759d4713b53beb84e6d5269df54583c92ca8a28e4ba8b32435f6109c0ddea0633a9091f2a5af00a2b32a4897c4a2f60a1613e2e51b4b7f4ccb228c70d375b08706ab4aa2d70ac155d797140bed661febf5560696b1635d8d1208f64759d9ac3f5dea5e28da8bd7a0e461f3a626fc1dce61c9b6f295b53fd39129e624a39b44c6840db6b5e99b7046b107597274a243e9b5a85147e163fd99741a8ccc2c3b2362b4fc899e1b55450ad9af772fa493cda912db19a34356643226cdef4061007024e789b2ce401e99d3cbc8338cb9a049fa2b4dbcf8a119dcd7255fa6b5aedca87bcdc0010831f5b4a6bb145a22fbf7d3c4a127d656509a3fcb6b2c3f1044dfee40af264b257309a245473484d147fc3939605fdf01c61ccf41279a0356cc9038fdb6caa6f1422d1ccd0afb372f958be19cec47b215ab3dbb83d10814831e2f591eb72e14960ccac44e791250c3d16a0273f355a6282cf86c8d7cddebd39c7489210f350914f7066eb5dfe1a5b29c6453c6fd8db978d33e33a33a48c287b9d5ad3ce375b044fa5fccb5b031c69276f895c5feec2e813398c728d19c5a4d6e3b2f0144a53a1e559171523eac07fe92ebeeb38d3c4a8ab88ad98ea80af95a14d981067f7a893ddb88d8b3520deb1cbbbda940c7bb3e05643a025c043312a784a7d8e9f26ac9bfad5a17b8c420033642ad76df6ab457d621238e320c6d4f1a0f5f1617442262b5c7467eccac63d97160efa1c17fa497b273ac0eb8006c4ca6c7cc480ef224f9931f757fe22f852d1042481b22347ffcac896607e535db9c4ce5383d8ba8d959941d940f1f8e3261c8172c402f0a3b78ed0557a0aafea7e96a7236ed1aefd77b3f74b966dd76cf85c64cf3d5e271bc1b76f53fb59186904b42d8b984801514949e97f099e8203338fdd46b46ec21f3a95d02e32058776edc6037ac8ff87ea3d3ce740b1cbb8c97d0a9f300a291e3b065cc8238b0c55605463c27b27f4dcf97b79753970714b88e616806da16224563b5f999aa3ab23535afd93b659d8b8ec2b6eeeffa717ca1fd5fdba1f35f1b5ce065a98b0beaf5f8de733ddb62653bd252ab3c13f7bfd4cf57d67875e69d8ae7162c8586849723120cbd8aefd093c2ec2a8cade3915b44d4798567040fc81d7dc8334a846ef27cc2516b2858355e064dfbc46794aa76c39a4e4162a3e2504f35d6d6f149e4ab90e27b771c74567dbc6c62a857415b940fb93c5e8dd7c39e44833200abd36d87e7d1fd1d7a1147d303a58997cf96d680c1b672d74a802eae69073fa9b379f045e19c054b665e13b0ff9f6072bae9acbf731adb992fa6dfdad045596752255866aabc6058a74a9de4e5ee536bb81a03fbcd2b19b372aa5c8a30051ac5b70fcc9dbee2b88dc21d89275e3924188a795ca116a8f76bd2702b9b15a3c48b36269588245600bccc2f23bae4b898fb051fe7defdd16aaaa057d9264c2509a2abf4426bc0d22abfffb96abb9da9c3034428c2832c84783669b28e17c8f6298a8c413a7e5f88", + "children": [ + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + } + ] + } + } + }, + "fieldTraversal_andChildEntitiesWithSubquery": { + "data": { + "Root": { + "predictablePayload": "4dcf8e0692a607eac1a57899572b31741387a715dace82cac4eb83748e1ed68058f927df649dcc7884961bd6d9d977922b70023fd57cf50bf2e9cae11f0e9639f74cbecbf0f487c954d989ba8d678f677e1ef775ae371f5a33ee5178385be8b35f01756abd685c97686261c13b7113f2bc6bc30195c390339a6978ecd9d4f3458f9e6c29d3d1f7e32a584e1c999e5e9167dd636177b53db216e4bdba486ccf86bea70496880c6d6c597e1136ef0a71e7d9288f29918afd4eea7b7bb2bdbc7b1af35199b8ece7f470807cd23eef40830de3feacd19bb20d6dc86fd428b5a385aba2d9067b95f1ae3337af20682e56933db9ba41385e1d4c35552627cee50288c75a5611b726c856ff22ca68d3eb342b563bec277162f5980226e5b46833c55b8fc8d89cb1394094bc74367287cd1eb68441284d4b9fa28c7a1316788fa7df04cb9dce281619c97debbfca0cb51b64ea54bf535c3283c6bb6193bbc73956c4374a63f358749e0ba7bae23599e52960cc8f2479542e1352a75f855bf14536093df3db61d4024b29c3eccf1e92fe5f22809fcfa55bed2f94ab15ff9e8038600e13741ead7e7bf0ecf437fd7aaad10e5545e34ec62f67ec17b38070a42b20c738ccf31ebefb54b5a5614f1dfd7b8843032bdb11ea1dc97cb2ed8ddd875e3f0c0ea575b56a77593e3a75facb3f8909c61aafa1f07ece5c34fbe357f9c2b32e09bd7b727e4cc524c5304060efb4f03ea95b479c1776a726a519c59f77e65c6e8e793f69530bd601919fe693ce178a712ca2f25a739fdc18c3cf9148a55b510e45ba1b75c838b9d341912465e07dd2a560702ffa75a1c8cbfa602db8c4a818618987cb6f712f08020c028c9ea955c152ebc70ce8f83af6f211b6a915560e7d1ea2124dd8a95ab67de2d0ceeeb1a3917293750211e99b973d9145ae9f18602be95029726986f72ff362d17447962bf85f0b0a036b60a74f60f50d2b0d1d018b1234e9df166e7d3fe010be5c718204dcda877da1e6e98b0bc20545699ce4998457753166fe7bfbf812018f93f6ba838feec3a153ca45e04ac0aee36fb59ee83394d80ba80a574b0c808dac322a79ed85c89aacc6df1f1fc7b87779eda22d0cace7c02ea3644ac239dbd0884747f23cb01d1d10f09c0f1119d2039a97967a484c3d705bca38e80ef390a96df0311507c42cd7f9067893f675e53047144be05b3f3fc585d8b1c99b4d083219469f12cbe92491a8e169755a64b171c00e3689d5b117d49fd1048812e1acc077cd50d595a85829d242e40143bd83a260190261ab70878593483bd3cf5d59e6dff5c39caaa53bb8008abdce0fd53e230f876b3a69efae7a4245e80ebe52a9b04e8a9900c7c56baaac9a0028af2365f0c41d8516793f5e81aa1cc96f9b6fe226ee2677d3df0e5141878c671718aa9fcbbc8d8a8c80ef0f84850bdcf5fcee5ed7ee0d238acb330eb22369d0c6c51dade2e645389123fb18c68e4f00ce5536838e8769eb7655e76b86d78be0284bc32b5dbff36415d33312e3262fe28a47ad27cf3e64d7054e8ac1cdd1bfbeee6cf82b1bdb8422c02cc6dd39a08d943a45d623057cd9472361689ad8a349a5948e24582ddbdbb96e9fe9b480080385140b50893aea94b76c9750adacabb15d00b26c3f2f0e37d99329b2b849094782b2e5ad5c04f928d36560033f8b9143af5eea839cbcb33e00e0ccbfa54daff28d297362e3c85182df2943f2eb95cc44da1fb15b9ebe0ea4ccca7f48286995aa85e6f349fab3e594c5266861e7695ac48820e0a32772cf22972e219e16d1fabdfddb3f9c19363b19bd06826c5a5269f740cb0cd4491cf65d3e38fb45de26df7b904b509be9d85a4e00bdf5ee9db626f19d2cfe41413b51552be794360df3dba17b84bed889d74131d55c5742fd21bcb1ee3697be15160eff9dfa04b63c4fdbcf7dd90ceedfa2a27f1aec7b6747874e4e030343192cf34fe7e6a191f98399d03a8d86082d8080a29a0730490322228088cb31e052db4f040c55fb6ca30024edf412c6672bf87135228dbe41cb65957e2e61150f7b93b56a0a3e00fc11296ce4bdb8b1150aefb5888d557266f515e41e93aee9660366ce91a390b42090da96c9c4fb1205c14423db51b5c0fabcd4def15b859e79e47a4ddac99e37ee8f3828ec232d2e73f0dbb9245a85de3d690871b8a838595fd594cf34808fb0969ce88782271a9f537b48fcb4d2e541a68309d5c9cd61158e34a296f44bb0f1a7db5f71baec67c81ecc85e4e6e6585fa93487d5f4f30538c2de07435201c6b65df5b9e2c4e5ba0e5c23971feb7fac26622e52874b49672d13a74477d3f19af61d438f308b585f97cce35e13abcae654fa23d7d23373154332cf252a17cc42e51a4945b7cc2072a0cf46f5bf23f790931515fad4d34a71d142fbdf2d964c7e255e1e64f96938d7b30c2217ecb5bd02f3a5279386a66abae3632820f0a2b41e1fe073b763589cfe135bcccd58d66acd7ec4b1c72aa4ac4d407b733a963452b0ec5260d9b5768f2357a643e17f535955040695d18ebca005ad606248cecc378c11fa635d5583586bcad7c6799e1df0cf33f963aabfa648398a7c864f36bf5cfb5f95ad3f649dfe625359d4721cd03127f3e27ca9bdac175e712fd0c232e3af5e1672719b8634f353fc91fee99ba5aa13b2858bd30b6678a37e91115df263e977f34ade7d107f257fd52594a030868903bb7f2b59b2b8d65ebf5e586f31b22fb734bded9766d9a961d07c4be53476ab20c3fcce40f76cc04224aa10dea7fa924ba254fb4c63f949f9812380764614d03b4aee717f78318f61862d7abd997515812629860454f1601e7a7750aea4ead43bc70c02f97e49ed9ba7b3facfcf2809ce0dbf9531289a2ee88084886835e8e897ce8e6c9a8e9975b39e868fdaf72c147ce7de6b58a894a489b9d1a5cc224fcf01592866e185de4b9054baa4d218ed679a2e6dc0fd9ba9d19d0b5fe4bc03ded9323949867775f70fbd5cbe817af785d8eac7873b7b1d0305a36ad6a534b3aca8ee9eb4ce937c19c20f4d4c778ea3e1eb2db2daed55f8df8474769f4fe1e1480e9a6ae438e153fa4927251b840ff989cfd29d49d2cf6d182f4ab492eb1f41d0123d34fbbad06de8c4afb072644101343dacb8b1fc19a326032777931a31effcac9f66f238f85a87e9af9ee1cb6e842b7b695d9fb264fd4cb96ca772f74d9bb9ae79c9b9fc0631e53c3d6b6140db8813d7723c6fc764733aa15a0e28666ae80d2a29d4cb2994dd79e760aa639480771a55f80a1c96b9e9d58e9c74a9f2b88cec9808e9ce2190adc31b055cd60f136b45e86329792e8294aa0ba323e97b03d08f38b91159961711f2872395aebde6f2dd176a41b24fb9c2c0953c1fdcca588d6bd2f68732f2e4a438c5fd0ef77d672defd32676e1951043ba507876676143f8fc1c3da2b0a985caca59cd5ee9eeb4bfd225e7228366b0a9267c204cc5a6e8118c031ef2696dc4c8fe513b3ad2c0b869f7d737dee3da393bc53fa90df8218489c4a68902b71a782df96724d848f5b3caeaa69e1e9bf4f988c2ee46129768611e70c8a9e4eaca5abd40b59e8d1ef215d800d7e2f4de3ba004a6e34c3bce64c63a83b83b2bc98986546452c1f3cb995772afdd22c441da3a4937b365e2c94b0ab1813c44f11a8fdf1e23c93412bb3e0fa5ac3efa07350f67f5f5cc608483201363b7b04c65a034b1c7ffb98ada1692f952dfcffd985f0a058f03d2085603656c004d270b70a39c2fe5f3ee133c81eb4cd6c1b1ddd5efcc40ca182575d02cc2d64c087ecac9302b3eaf5c9492279488da506c62a6c14f05551af3468536e15921747c80afa2c1845a89d89fe49ffc988a94954d02eaf281a651c6ae580233ef0e95697604519576ce4a95a5b64ebb682b80d4bfb59c674f679ae1812c0bd725f7d52dbfbf3667f55eb9f0d3975cdef3a200403d85078ea3fb3ce804f973b4fff32d60cb62b6ba30c4566436d93d1688b77221b12b94be1b857a8e4beb33029c854a8df1168afe1b4cb355e7875ed80e21a29fd8962f8db46aa86d7f2d2afb11cb64bb1739abe37a120abea91acbc2c7df61feda7a75637b880f544c26157f40c5f1be1acb3810a521b09e72aafde157ebb781c8cf00b0089493b676f9c9df65a2b2f1ea2385c9477f9dfe0aeca214b87ebf75ad583d77051421cfe6a9261282d26aec2bd68112e424b7b4b9d90df3a0030f6850387192a16d69484d4ab64ae40325e6e22a5405683b2dcec5cc6fec81712c267c73a882d55cad6218e9e2e5964d1c832328f0c7416120c0ee893def909051a2f18ee6e06e5117f36b8a39bb7d3ccac707de0fd8c63914f932a0f42506ae853425731baed4d794f235b10d0138ebcb25cbb90dcdd5c9785a10ac5e2f4f744ddbfb951878b1b1d8e18336ddb836405ea5e933c8ca8c46509427d9d3bdeb8a8b99f9a60ed5ae37f89346de14f9672dfa62ae2a41b9cc6ddc91b1881f0a70979cf6fa4c1a9059f7e2da42b543a79eb84d79118ab1518db68f412e810505bc147694798e65c92109d9fc3dd6fa7ccb9bd287f6dd5ebc3210f5bca1701284cf16d276ee6b4e01ae42752865e0c2174fba894b2cc8bd8cf74a8902b20d0674df9d32a841f4c9386eb400c64d19aab47354731ac568faaa79999061cafc2af8f6c5c80c7493889330d0003b91d5bc0b4a0a163af327d85dafc902c4b238419b5c42305e85499ebbfc31593c87fd7c6deefdc5b5e425784857d0a6bd3cda6d606c72c897471ca0e2410eaecb60d72236a9ad99538839d1a23d52ac558626316e2b71dcab2a93a6319aedb4e37ba0931c30cffa60141aec78ed8fff6d08125bab4fabd9f377f95263f84c8f1868296e0f99699073fb702bd7fe09dc6e552cb15acb513ccd0e9635efa8815e1f2a02d3de76efc9a553286d4e1735ba41eda59405a014e5723ae3877b360b1da6468c37e6559a82376d3a999479b6977c1d3b98b87129cda31e6b979a4f64626dac94d0461f825220c56170cbdf4c28d6134f21fc2e5884db28fca3e93882cbad14640ef8c31a0dba4e34cef205ffcf4b10c390133dca20ea8b86ef1e8d3b712f97b9e0d6fee79b1095885fccbb2fa5282703b148f63d97f1e9c9ec762b328bcc99884bf3647a209e1c979ca2a546eed63f9a32419530b6beebfaec1a09b133ad36bdd3003edba67f1b7e3298598f499402bfeee46bdccc8197f5b7c0dda27a319aba610b23ca7439e7da71024688b9a8433f71f3d14cbbe73e160e91b8a47f2f2e6a0c653af86ed5f4c5f160bc99f8b66d9feac5e9c1269ef6d2503eb94e8a793d930c8bc820874a1dd78217ef63e742a639efaaae5fc11f85a2c7d64632764122b9beb641304b625678644dafb5ea8a2b791dff2ab590c615170a690db95608fe306f4ef99c5c0f9d95bb6c89832ccc0ac3182873a447bdce9317902969ff2a8c896ceb5242d61b4b0485f764b86f94ba2cd9b10469d2ff362280b1942d4096bd13e48620bcc0a150e91c4bab64ca715ca2e881250d89b537cee642d2f520342ad81a3066987246c743d2a9d549a832a5f8a7f5906317a0f4f6029dcdc21a1bb48f96b40c40ad66e97a27d3b2a60933231d88fd36d82284a5d3cc6128458764f64e451af23456d15cef183b749f190ce71c8aa0802be6f0ff8818cd66f389229869cc2aa8381480c65a79dfc318b0bdd7d95f342e153ba1bdff3584bfba85739a2b432d7374ea5aca082a3184b39c5377b32ae9967f0ff41d59bc8821e029a54f37f894ac84472431f664ba341fff70662737f551b79412dd6a13d762caa81dd7d7d901db664cb0fe0dba2135312d50082d6bbfca13b2986ca267fc8f32134b58f60267e5441b827e3fa022eb076068ebdde0e36dd6b3f85826a8780fee2ea841227396aeb8be2491e52ce3ed9aedd71ce5991ed07ca83796343753ccf8d285da572468f97bebff4cfcf72423543d6bdcd23f934f82fe4ca1c6bf26105686b35fa3d6293d036b29404d18fe5e4c58a854e6598850bfa331d9b061fe2647cdb24d8a670acfa97397b5ceeda871b85d0ca179bfcb5ffdf524dbd08c19f05d303ece99e069bc465fedd4e2207c1273e2dfd10d1ffef2b307523c751480e8dd3560eded2ce0d631ee80ee15d6d74a3f3eb5c6f07fe8df9a9e003ef6b8011284245cf4d43f60c100cf4c79812767351348e4257b608fa11cdb5ccf6e2d4eb42b7328719eae29055568867dbd0f918876ce624c6147e9c8cfae3e3d3873c0084a0dae8553869b1eb4ee104b80332fb802889c84618edc1e83c1db5e8e654541c1754a187363be7fec74464589c8b3fa23a6342ca52433d0f0f3d7618362e3c29c543e6e92fab6d166deac88baf87da7032abcd2ac06f7d90b19e74e29c2ae8749a88f157326cf586ae52a98333eb0d1b47e1c929a506cee62157e6f1b6d56d97dd440561fffe25c2d585a59f195e3ed2a913c5a83a44e37f4c2d54c348e2499f9e836b91fdecd02415561d508919c379d27134fdfd71cac06d969152cc25078d10252e70def6ecc9d62e93f062d15ed20c6afc4fcad2327b14ea5bd1fab846cc8f317dfafb0926e3ed4e9595bc88b53acd5f7d564bd980e102f3767e8827b07dcb5e52fd639b97ba2c9a9a7c96c91c87c66f3572226421fd2f865cb6ab10414f9f76bc942c3f894c1792187e41a5472a82d005fab6377fff6226fe4ad08ce88a6b684ceed4b58f7b50b633ea7c70f4d2c14595314a39b3f69b0e2c4669391e1edd4cf27e05ed4ed1ce8f9b8e5cdd0a74da40c022b14e7a5b22129a0a056ab5655af451309d7d3914e15c66362efe694040e37eb8d4c24c75213eb87a2e221fdcef76d19374d2197b4ae279147ae358a8be68265dcb110ca49b0c50eeac50a230e202385169af9ae5c5b1e975e13e6a54e9873d838573ee9386f1c73a4d66ff7df1bdfa5c73cfed44f86f69127cfed22de91619dc4c5e6051ff399ec79d5e12ec5e6afff8c128cdcb936ea67319212d9f399bfe4d1e100f3f0a8f69c46dd0b69eb4f7ea0bab2e63b368629acccdde437ba5ff96c139bc9015a9627a4fa1686e59561d7e9581cef98fcc81a4552629dde76ad2cac657b3cf54c19413011395292afee564d398a2d080a552eed290263b8ba5bfbfe29007b96f881ad4dc5569595a6da5fec9bd0eea4972579f672ed8bd7ecd64771afeb49e526bb844553dae9ca0fbe6dba2f3c6ae7daabeb4d2d3b6885a217e24402d0c4571c2f9c9bb0cb17292a628d3633e59d453bcff228ce4a6613c78d76287b0b0622da00fe42498449285e1500086aa6ad70ae38c11d2a523b7bccb6b1ddd1a1153c35c5290c51c30007f6f50063ba6d927fcf6efae2eabe24cb297fbd6a632843ec2dfb84cb3c63ae1b4d9e6b50907e11929d2b207de4d0719fff598476859348d26bd8d38c6203f96e9f3ae2b9f09a34958456764d89f06673ead97544690907a49928621fe44fbd1b270d08a8a449eadd1d8eff4119d11a2d1d72626caac47d8f8a29593b38874dd8ad9b3e1e77e82092ce687b911d32f4193f8c0ae3809b6d5a861ba87f3e12e842a0481b7004b45ea85ec7b95e25f003a558e3142212c45bd7ee3e8c80818b1be698212ecdefc8b748a5847738bf1f21671d4cc221d8178f92ae8209d720d3e855da9df679902dbb453da533e5635c59bf5b17d9fdd22a9eac9be893eb740dcc0dca3e3aab3259411c22cbc586feee16722eb9fb45ac488b8901e14f99f6319a00c6a759fa4bdf47259328dab808be6d2e950a3c9a0e5154213e88cdab5e9810af2929d56fbb74d56f9a42c926e907ade37154c34a03aa3bc47836a3751838995f443973f59bfe0403fbb489bbc9faf2dbeddb9aefecda66ce72c7bfee511835b37804a505a043519664fe30ae91517f441f3216aaa738d9f4b2bd742f3c769ea2aed77df53cdb74dfd336163aac5d966b387da5b7882d51b089ce4fe4cd826118ca200e27e54c3dcfd2f2b057dc010cbea0de457caae5ee3f34ad6df987de16619c01bd2fa9cdc0ed683dc4d3beeacd8bc96d240ea27953d07d36e368de87d192da2a9d646c46ba41faa23a04c658525c7d3bfe1e16007fd73079809a51187ef033b17c48394e8372ce6dc64cdedcecb59de5f12ce5bebc5a55e76c81d30bd8a054b17e156e02d376451c3a6c4fdb79033150afbee91eb8b48dc85734cc85c86f0a4b0db3350f90ec8ccf87338973a1b02cd929115000e4472ea5829fc05566eac1de63d65224c30cdca04926e4ef3aaa70c530a964fdde4be429fa020ae26dcd22ab6962d96dd48b254865e0306c068b453c6dfef88cf63d99159b43fb894ba3a42afa4c7ab203868ff6d37eafce97ec6907f849f0ae7a73059aec6f634a0b81faac69525326bdb44d5c5cec3409ff08217e905c80e27f6d47c2efbd45f4f74af7801da83d81e53dfcdbb5e012b969f8ccbfc3981a6c2a2d45d33fc7a858bcb31222a08a907b1b99e98b8e7f45af80290b7d9c8e414d93f2c471922731106cbbf20e6b03364d3b5b9d8c841383b86912e2f2723bdc51cda749afbed0d5d32767e1ca7f728fc225ea4aa4c21892cf4d1407b3a919caaeb000af6c2e1696c4e112e35c27a075988e705f197344c719de0e0e9e522e7c84e42fc44a3e09ffa7f6730d118ebf1923511bcdb5825abd21e69bb385e30d24128c2272052523abef49ae9b6658af6b4d23af300d42fb3e4ce5b63d9b9fd5e21f8f0a03a2607ec00ddc29e65d979b51c1abaa952ebd825abc90856af10eee8c0010f81c91c68fcf1e4c3d8ace2814468dd7d7cde1a80599e85019ce8cdd66284fa15bd023cd80e30b04f0ad206554952e3430182c8162456a4933d38b8d8ba1e64d24be4e0f95a87631a8f2284dad6eee1b66da0374013af62d39d97057487073d2db568db8e14317efdf03735800599632a17f26cea6ef1dfedf5125b28bf9f125b47edb8ac72f5a30ef3ae661e7d898a45cc8900bef0c4a90ffd093eeec758295575121074c7395a21f790f9666c5a32db3ba3d1c5ac25c86ec6ce968481cbb8d7efc607b0a10b429e1c5c896cc0b9b9fd51df8db169ff283b1a7b5b9965c51032e0b855bae331a641d7f309fe6fd3700e07c972048e19a920f265dc77c04f6c9dc22e3c428ed9c876cde51be8df89c2ec793977759dc8c74ba6acca72fbdf06b289faf0bbffa42a5c623a7338ce18e8dbde12ed2eb9bdb45b10b23e3e47b4cc91429258d4e4df993558fb526c71b4072769eb6b30b91cc5e245c0f8af50223cc30ee449de38591963317b3c992f17b5c9905e24e05bf6800f269d7787cc34e912f9f995435a51e822abd83eac72f05eaec2fdc876a8dfe435cfe079a996bf468dd28cae8c49d0a83df82bde01759479ae551c8506eafb9cb99b66d3e9db75e4123fd648135adf13d8233153e24f8684094ee4cdf650d37e801fba7f062608c88fa59b7e5f8028c5855f6ce51cb23f936c5945c8593a53cdbecc8cea6dca14149f37767957fed4e08bf804c8bf480387bdcd1a859469f17ef8033c831dc59901a45cc5071e6347ec6e0813224c141737ee3ac94cda27824d96314101ac217880fdb4cf749f7f9481e7ba813d6ac8fdf460beb7b73d700ab3ea9aa45d679500462c8a4fbaf4240ae0bc3b1d7f732026efeb80b4b5263cf8e22e883a7545e7c9949f97666b4f0ae389a44a1d5a284455f676aacf56b9441fa5b3eb9a56ea28fb45bd30783a9b527f7b8e47caff6593cbe8c6b24b0fb3c485339f16706e2fa57567492af9fcd39b469eef82f632a0594717d4dcfd6967def7ef86c912ad0af92387fca36cda664036d820b028bb37a3e7a0f86aa2b33b8871485c003bde2274ddc9e762e7f767faa757318bd20dd03131fd6df8526e9e819f0ce6a5f6c16ee3a1833ccf3792915a8e92674a1eed499b20461d6143fdf0a0fdb1d3770dfcce98e34488b5d38a774d9f020cbebb7cb74f192944c0e095d9ea28f4590b7da8b5275a78178e8dd2cecd725235d5812dd02c55f9fa1bbdffcb9fddd84b86320ca4e454c42f751fe17a50a5b691c67fea43c1f95cd17e6ee0017f79a452265ef6b8dd38b45990d3c04409d28ad678fe4afa34c12414c767d73feec58497cec6de23b29eea0ce0992e5ef31428814a73322b4b5f113e0eff9b16bb2946c6b29d57427a668ab2e1d7a041f4759a9e5cc2e738d4d3cf23ccdf92bff2d8c0c71bdbee9e6b8efd5bff0da7a9a94e052d192b054be8023ca6786ce95aeca06a64c10095a9bbff0edac53c6843a74b5e1769550cac65a74e79a8203ad57e92b50659842b7a7965b1b17cb3cafa4128bda1a11463bbf5f63a311566711f77575fa0a3749eedad32066a54afed3152ec717c55d7595f6e6775ff70fc55ab623d3a3653bcfc3878f072601b4125b1299282886a6c0a2d74ad5587e0b86f92cc7c4e755c843d1c5719096c20dd4830afc554a4c15032577a72847245dcf02c92f2c9405100120cb8a13a24806c0fa04b54e45d55a048e9f5f6218e6a63c71e308949bbdef82079d26d18d5b1ccd30af888a977ad9695b5ddafc136ed752d53f3e85623d12ca017d6d1639e1551443408b703a9482ebf4c6daf02683e1acb3696780c3e6260ccc78f759cb0b4fa9591c6ed66760484f9909b7fbbcc4aa427133d678b199050a680deb95b7c031d5e23f617bd5b9993334d1f30a21d720a62c9bfac20e583f4a4ae965faee45df42eefe9dfa06cac54af76c2f78fd6d455d31f8790e73e3912a99eaf986dae602532a396688b7870954c220f6c18a0ece5640b7ec94f99399f6de1cb913849b58cd764ee703c21d3f1162a73ee7d25a98fd7fed9d7db616deab6bb957487c3d3c9fa3df182f333661ff79645a9224426b9246800ed3e91feff2a3a3c12109dcd14f274c20569317a857ab8cf3c1d98413106bea9c42897daabae5c8e0451658bec8bd40129cf6ec0f4dd6f0c9dff1a1286c6beedc841ad798190a7e99c0fcb2072e6e93eeee25922067a14127ac9da875b9f2e1a600dcfa4b1cc897127804abcab76318f02f27d34e23c866069ecaa0fac884bcca504fa873c02e952c7bb457d93103a415b305cf429a17fe3fce8b7933a082794c0d09386f3ec31d0d728cffd598b0beb8a8d07353de0154a39a5025ce2247d753816d6d29b1702b094511f747204292d80184fc6bd2035089f98080fa71ee82db62fe707ac475b981a0e021857ddf1d9e93a9990bd35aeddf43c4f89581d4d7514adef7fcbf2d16abd5ac2bcc06f886eca23d3f3a0154894dfc6579549908b388600742daa9b9775d3ac52a6ece7813efc05cbcf3de22221a4ce558261b104089047620f5a2b1844110d2d5fc3a0ebcd0afa1aabe3e8413ced9307541150ab427448454c873a03a076d716e24a896349b7d45d828511f19798b0222c5a04ae562339da6ca0a04d836eeef8ee62ebfdc42413ca90f4c6b09907dc6451da5504a001a0244bb3a1488c3a92e5ceae11d29a00dcfd29de8d3271a32807d9840f6a6dd19998c8829ffd82227478468b7a77f46419d1bcd4eed27971be9064f2bb41ff4c9ae5772fc6289fb6efd8c99baeeaba9c1830e235d1d87efd7304d971c96ae281e8052aa084c8420cd392b5786a05fcf638cbe588f1a7b275b9587b0b9cfc1513793ca7f78866710c2d2fae99c9aca8e1389dd0b2f96dc35ab940a2900f3648c104dddad31482ba6b8e1dba874a36d12a2d1c14077663505abd69933778bc43a9adef8d79df79225cf715c7405e5bcd6e43d7aebb282ca0f9eebe209510572c3e18e1fe7aaddaf3b5237e9d69b3fd8d4276858422b4bb189d6e1418ee53e19e658acc1b227ef99348059e013ce66097fbddb1db80931ef6e8374d5b4ce21742891fd02a067a9a60bd4bbeecf772b8484c3dc54b9a36419cbd72bb9d601951640aac1c6f6304467a49c2212d1bcdd8437b527526e72a08036cc7fffc2aeebd4dbb93cd680ddf3030d20d87298f4e7a66457f687af67bfb1f3eb04485b990b014c5a0d3a6dc649e21cdc997356c9f58412943f41c0d71307ff2790e6042be2097550f68256cc4711f19a13cc20ea6f994b0c7960628b762ab9314dea825045308a2adc167498168bc2961d39a43582c09535c6aedf9b2ff3bff93782611c71db7ab6b06ead99636410ceab8d9e8d02aa3c8de5924beb8273192615ea8c8d81f71e0ea3f352cbc18e8ceb143a1ec0d93859d45a6ec36482c4a6713bc73eb9451ba56bfd41b7be2c1fda95aea8a74e1416e9d50d5ee246a77003adf9e1cc20f06f69caf5ab3e52424f94d3c99026d158a6f44dbd0b6d216457752c4ae4b4673d7e515fce8f21c0359a125895ffda9519da74142c7c7dc3df78b650259be9d8ad1708cdab6ecc671cc0697b7a6fa003bd8fc12c0dc2937c6efc965d6518643df84f311cfc55044ca8766d0175002800139ce35b240abe1098848603bfc114025348544c57f53d401406f9c794446b750a2eb1497a5e3a12b2c4691b942a7342dffaa69cba57173bd49788634151295609607909d5c2100dc6f856d73c40dd2da0069272e2c7819dfd22f02d9b404f9e8fb80ddedaa29c0377ca003d30c816113980722f70728aa41ad9f78f21ed5bb6af8911575887a842e085dc2991beaadc1b97a993f0eceff212fa7c37ca2ad5f03cbc22393e82a70cdf5c7fc03ba9f77810ec0c519c07b77413f0a94d2e573b20ce1d39639ff4bf11490ad96715d2f0c7a372f1728ee82836bc638f26737aaaeb2a28029914e4ac1629f4f495878ff8b0c9688a2975d1efdd545d0e7ce11d9d4a6e28844941e9d81cfc3febf7c9b03b8790587fe7de8576264d0c310e5a4216da9bb5df9ad5db55dcd13b0b9102a0148fccc78dfd3d184f1967a99fe24097826882e85be18452c7dcab545731a3e5612d9df1bf6934faad774e307b09ecae6c885dcbb7f3f2cfe735c4dc4cde619c5c93c36fd7d49a7aee96c63513285a792164ec430f90df5fe18f4eb18b8c057076d1c3aff90ccc60aa00aafbf2fe355f014436e3321309673489f1427a9ee608f60f01a8b6cd063985c1de0af07b9988a0c6663667994dff7dc2f00aef81c435abdb3396d20e3483c4c330ea24ccaae008ff3e3048f67962d59b3732d7a28314b9928a9a8c50e3dddfe965ac5ee6c52f1dc8eff1e63c39c3aaf43f9d452fc09d36c1f00abb63bf58da4a64962d85401f495986f931bcced19905fe582704a9c771fcbf2c8b6664e600b251b0efa929c037ce07bd9ceef23e8e89d892b5a943f5a0b47db14bbcd89e5d155ebc819d7c03833c55331ba3d138346d109a2c9161e84e20f2e0524f41885cae243c6693430bbbb54211cb252eaa775e45b928b12340018e0b43d19fbbe9889ff2e461e8fc92089b805671a9524dcea3dab86263f50646e6eb64650404796c08589275103d0f13d376d97402380c6caafff948086abe6d2c7958bebabb6eced6f322d3a8fe3d0e1badbbfa98aef94690c2d268e00322c4dd20afc11b83b4af6f045dfddd86b71773def47430fd475142efc60172f95770f3690be1bc0f04672a5d221d41defe271dc5e1007dd46d06103a3705a5695209e36c838ecdec61f3a920e28ae6c73a46098a4945deb19184f433579b8843fe7a73c10d53746c7090601d0ecb4950816f70de1c40ccf5083875a2662decef156a40d2e5e4a4010acade4ba2d8cdb97d575fe80e0d9c393b3ab661fc342514fca0f0d1a57dbcef1206c09f8ce9e823eff3e3678969420623707c72e16591c142ba79141539a8df3b92076c83f2bc0fbb115e46712a9bd9833ca0d01e4320037fd4db13f57f0cbb8a381dfc6d08cba7ccdfb0a83114d93f9ac223dbbcf9914aa84e7461be90c7b2d537373bebf9d8975509591f907620fc1e93b0a1e5b6756880d51eb8fa407c1d2e55a25bfd3f69deb2ca95225cbbf8d34b0f430d9e6bb8c4af3a59ad0ea351f1be826dd252d7900fc6348bc42820e1ff60e3947d27833cc39ca8b1ab153bfe6af661cc5d013957451ed6d9e01bcf8c2eb1d671931e0c7590d22892ddea8f0a24afbd165b1495bd7a37bec7765fb72511b60623443a2a03f4d0a3430ca2c99c7108276c6133b00bf9d000e75060bfd35bcbe34e95a539789b34a458299bb7c58c59a649cdb49b4e7f86a153c44c17d07830761f759777a9fb8ee6ef6724e3e99846cdd86b13ab49c7726f85bcfca4d18d3b0ca46e2bbcee198ae903d8b5e73ccf88bebd0c3507a772f6cb9bfdbf95aa2735890a4f4fb3930a4a81fdb791d50e6a7a3c3a595cee78276cb3a360f13f51596b78832976c6b5cf449cbe875f71ecabef807cc6a6a3cedf91ef069f2387ed4fd042d0367d516f40a5bff343cf52dadb400036cda487cf2ba35746c0f47770128138a8444d3cbd0b949339822ebe900a78e84fd98d2b17f7a92ff1491e075393292d93d985ddbc1a54dcbe60b6dd812768c50f0ad2fc059c133b522719712518a45bb7b40e43e76bb16a29b1fee03a4fe1c9645b2ed9503e95453d977a6168f07e7849477be101d127cb261d5b2248340db846aaa51afc23c78e53cb9a9100e9bf8e3904c8d5826ba1524f4549838666432262cefcb1f8714a57620c103ac40329973cb95c44802b22a539921ab8c423af3781bce043bfe62c78834631d1cefcc808d01409bfde1f1229ef04e6bd498f06a2b8b6451dc5e34412e101278810864462b7edda068ab79d0b119c30fed017796746c6c42304936739b84eb1888bd674b7c1ce2990dfd8d6c81520eed3e7f73cfb8558b74affc945e64891811270881ebf0a5cedf312b6352ac6e8986e45c525be47240604df41320348481d1e5b9ced433de1f4623f4a8ee0c3b49ee7bdd5f314fbbd413f2b9e2d94ff4f174202a8391304aed8e667a36c8933a2eaa6f57bdcfc4efe1c094478056bea8b7668a8c0a7aabaadd045c3d22f7bff7018fce8c8541091dd159f0b766a4daaf0f46d07497d1ab18eda69eebe85a2fb94418adef946029d3ad9ee6a687c41a396bf757f2febe262cecf7d9f39d873f361f1fdb94c59d701adfa1e8602cc76242e779dfb5c96851bcc9c9480683c2ee5550519d79e4385422f48b5589be6774a29748d9bb92ab05a819d117a58c2dada8d94ae2390587a037f6334c572323771eb1d43892de1e3da2fd6329fd15e22e2e05ae7a0b49052bded8370409ab88806a875a38bfda55d84d254c1d9e4f297586e6b7e6d9e0f35db4c0c0ce8ad5bbea3c18c0948717e69365091125dec3fb1260c1a23cf921e5cfc8125171f54be1ce27bb6faa4e935fd72561a7ceb9be3f5b243cd0b866c5ab5e9988e7d357ccf9d9949a0b6229d340c0c5783d07d8f5c905920620f64afc05e15397f30509aad0b91a71e4bf54b3b5951575e70baee3c046f2e770e18b7f9e94877b7dee96ff766a0057ff3e3079410cd6a755701680a6af885d2d0af04c24c6292c926b29719a499e486aff8779bb899bd62b28f5355ece17ce27962be7533fbdd16baa81401ad132a729e02c5d1365a2642022a0b1b5c9e73934a18fe998d646886c85bc5c2004beb2399d1bfbb2bc51c7350b9b8042555efb6e08ab37af0997eb7e80d31b0e5be27f5e3af2f363b7df0ad3f6667e49f0c18d21636d6050e86d049dbac3bf0f13a5f6d7bff544d8754669d084df3034c2b4bdd3a239f920e97340cde944a52e9cdf03c55fa318fc016dce68b5064f179b05b05b3cda9566eb303886a2c5f9aacc67a39ef9c02cee76656946cd099e905f2addd9d59cb16cbd6510a5873bd6ecc6aff7984c60ef7d987aba467d39ffeefbc5ca4cc2bf6e82a508174fac5a16c27a45556d02bed99f108c1f382a19c3c114647b239319fc6ccefea0d3c5025cc654c3e19d9f87cd3fda7495e90687c7475f2cebbc294348499d4ddec668acab0cd1889563b2fbea86a9b72ab84cd73a2a9b40f8e926f4b5a23af92a06317c827e99bb08b2d77208295fa3320063e8db8f9d6f1705feeb71db653aabd75f8d34bf041a759d26fb3515a0963bea9bcb8b52d50b6273d64f4da2bf896bc1eaebbb9246ed9b3aabd25043dd743278e7ecf1efbabfc879f5f83909f8a7be12e1c2bb9e00dcaa9577eb1ec9c7d0d1c967913d975b41d544e05a9602b77290c146756095a54bad923d15359d34815d990500b70d529bdfd1af8fd05aa49793a4dfb9086d62067d5fcd5b9bb10357a1b808e5d6a7f6abd8cadac7a2ca1225abb7a792765696b91af7d3c06899432a8f5771ea1ad6e5b350914bc04fede83b15d3e85f6f79ef977fc89ed211efc931dba5263a1f944a3d8c8110d2b4073a0684a481f52a0ab1638a6a8a0fa5f2026f0dfd5b40ca7528a689576f3a55b71b31c0e5a091fa3a3d0a93465c9bc6d85794ee8ebfc901c159473fff0f3c7fe9d013a1020ced2e1c435aab7d79edb20c44c22f1059e6efc12d920a77e3e2b10da8f002eee5fd51fc63b1dae2de191008496d0b1a067bb3950c1e3c9a51720d49df4ff2d9e414b78828ebbfc9b52cddfcf9d8f8055ced05d155358d3eaa938bd594cd0c6eb6d2213ed8cd17371625bf596a32ed6772c2ce3e7dd6a2ca03810b95a5010529ae5572a4723efd1841a34c3a8f795f50ffc47e4e5623a551c1bc305a38b7d6e4c347b2178015dbedf41960130e1d4f541adb543eca13daed845e2a36002edfcac3474f77eb89964ba6eeef864f3ae0a4eb9811a38f3649ed54c2b1b0d9af9ea70bb8137e1846001280dd3a9425655e06760176d152d8b00baba85852b76bf6cb67387befa9109094c539d9d7653d4116b9948d049b26b690bf071a403377e9626f773ee9796273dc72d9acf0a4701b2330ca6d5bc55ad9ac98db480702a20ba2c6a5b29e87aafebc78674251b5d0a6fc15138550a2e23ad3757b9b3cfb3d0db82270a9769ae138e3961e9444b63013e9faf6600c874646cdb3d5ca8d130e2ee45e18fc39109c3b374d6ff69dcf7fae4abd206aa9757ad70bf40c2d6207bbc0417be9a97f81fadf200a888ba65bbf124b81050e1c34d05b10c3952ee6bb44d9e4d3a03a7798f6699788fd6698e4d7cfa6f7261a865e2778368d3ab615f4142291b91d089ac41e9ecb7693059a5a752aaac45d4bfd73f8c364a4e1b3fea5c36046f71c062ce929aaf84a8b2aa57c64af4ff46af7db7590356b12ada95dddb02443c6a13b8f06cd7f636d91c61dc53ca633dfd048dbc75bb775d9b4ab7ca69116950ddcd74813a0e91ceb20bb3946531c5e8d7d7dbed7c06d186841ef025c3f76cb1f89b61ab20d8e0800a659fb1f3ff833c12f9a5fb6c12d4d2a7237d47bff5fad456f7ab81189ead6be1fc70de8ad64a0b35b2b70bfa911143de3fad9bafdfc3fb22433abf19aa0603b08a8c478e13b70c943dcd0988dc38fb9bb60f5204e882dbd4da086f02f76645cc132acf433bb634d1af77b53329390d854a04935ecc0ff939037fa976b6197e963042093a95b1b8e1b93c1b654201f21fdcfac8a36fc6950b42193dc34874ed23104a5a08dafcc66865f7d4330b712c69be9a92f0addda01a8bfef527820552845115c8ff23330eed2875163ec0abfd365ebb85800bff030189378b5ad7632dfc65c971171c3f38fe1b68dac3f57d6246cb2091b4939ef6652dd3819e60b838997976e3eb59b491c376b8d525137f0a44f46f746d357fc7822298419ee9f10e085d4757b1249873251ad82a3464e41b3be65b215798ec460c3266b0addb76525e5926db6545f6c763173879e3f70f6b7c62f1125a10d672af5ba36403a8fb10c216334bf6fcaf5c859f82daa914b03fa01f327db0c1f3bcd9c53234ebf2c704acf7336cb1071911f32f0dc7338078a9746e70c794802870ee42c5a1ddec5b29ad8bf99f6016830627c1cb479de7b252abfdc264bc1511955b5d2c967467fd4c75011037a3a36c29dbc63675cc1b7a858f0662711a6924e4d7406adf27222b8bedbad042bdddb1df349fd3160da3a00b70015ecb058ec6b1fdcef0cb83d757d7c93c66ce1c64b2276f087f654934a366cf9c87beada538953428485f563169d159a77de0721e0116d67ae5372db0894b64bf0b44e650e2a6f51ef8325db0f06c3db0a84e0c540db5b481980313a47c1132858c9ae77a2ce74787d584afd16262e075dd0e326cc2b48e46fe239a70f9a72ee8cb9f0c346dc6ad0f876b366a0a99c6e2142e572cb6401b6a4b9d6f4864dd06117ca7ef9bc628adca655d05c80c431934233b6857dc6e2d8139c3233397e118e204a00919618c58f3a8a976ffc527a1c8a8b5247771f69d9e5b37cdaa3fe5f93572c0aea54b8fa01f1711b645af0b4cd89d9db5b315164cffa2d1aa6baccee201415647e91c3687b77eebd79f71ff932fe775e811db98ad0222c93c480636e460a16d6dc3ddff607a19a08aee1299b9b2bad1b6b640cf80f4736fc373ec1987db095f7f582912604588f0d33670fc62d2a2d5556ddd332a489f7e970c16f12cc540ee1ab98f8485ed9f0025f080c2c81fd50fadd0857c2211f2f485f8ba8abe0701e2a19ae3c530b4b5a5cd6559ed2a21dff5145dcf1871bcf8a8fd0b76305788f05230891154f17e54358646b1c4b2013357c342f919417ac8931a6afdf3097778ecbcccfcb222414c98f13d1aa59b297ee85400b9a7c596459a6bb2e30c42e265eda3221542c37026e511052b61c6e2366d8dbfddca9950582907e322f9439954928290c587b6b04e9148432748fec0fb0879fbcbf0b00c3995038a5247cb87aabaf2d05eca4fd07d322bda2bbd0de617a8dc280293182a21bdfd2cd574959d548384d2ee06de48e77d7bcb69631b25962ca90907926e336db8cade34c12585caef3005305714659947a3056abe178d0350ce62c6f484a6b35c724c87276ad46006cc397850faeb12187667fe82280d03ff1be83d2704e2527fe0af28da932743c13105da33a9966477c444504e9ec3ffa5a329604510662bdac85127e08bc871ea3a683ac7743d04d33c8c796ee9926c5470198854532b9a0cd3e245df0848c4fa4f1be0325806a19c71d524db9f0ca8d4fe2aab99d2e7abf2a6f44ea2b4b42e55273bce305bd9b2ce92747ff18f4d2ded83f382e51d5571ebfc103dd63cb902ce8e8e5f419de65cdebcc58f3dec7485f01d114ab928a8bd3779f9e55c1c1ce1c4e77ff38c271834874afb7278b6483bbbf90fb672bd66a7a5467c171cac3c1065f19bf634661e63f2a077dee45ace04220b0e4e6d95e816e8e6138bcbb6065a348c35611ed153c00ea7bedd9c35981b750070bd1624d6001da25a851dec89ba87325450202c985d13a3320c6c097e5fbb5a25a7355bbe5a7f6dfaa4a9714091c6631639aa6eab6d65b602206a6b57944cc46de2d2635db81174a61b98dd01bda5e1a943665f5acd0edc31ed129cbe9b6a72e47cf99ec66d5a9d45c7278f91670256c8e4252cc2bd70d31952424819b61d2742265d051bc3d71adc1daf3f29b8d5fc4644a564a22b163612791cddc60688bd723f19ff61da8d8bd9df8d5ec6a112e65d39f5fa92124817cd5d31c86a272ff6de5f71521da0d58325e56eea533fc7535a0584867fb2d648131abbd275a973b6bf546b0faa4c151c71cb9c60e73b93bc20b79ce9770f203e514924d760a0026acb7a5284c7df1e47b6e7314d623826d5433bd894f6d1c62f8222a93a200768d2d72013cb121309f8e128bd5282aa6d643c93c4ca0ec3d03d0da94d0f5b8366c2650ddd1fbe199b5d161c45f7db71a9081e1d316f891f8d1962d7ea2ee892ec9d51078f4e7ca093b2496afc07ad79ea9758ed563ebc399d9773b7552e0defada519f1e837cc70cc51fdf129e503c224d5146712d4826d5cc6fc960c3160090d741c68e05b0ace4daccc876db010964016f24254ba239e298bd11c3f45a6ce4ca9e16ef1114c07379311f6278481eed7d6b5de70951575252946ff2e5737d7e341a3eadaf8148f30fda15346eac3debd19e3c21ef3bdd2f992233a6eac449bdc27ca2a4abcee3e870b15ce015f5bae6eceeeb157d8658d2a64800145629962f34cc530538613cfd6032d5d6c7ec0e6d5d38545407d1b4f7b46653bdfdef0e0060ac8b383675e7a33ffeb77546ea0b842d90ffcaad16036a09b5c94d341991b4a9b42d06c829ad52099f759b19b256c237b8644794e373a74f3600cc02dd343c2a65488a1c5a02564a9cc17c1d03cc0f2cb33e146e1e49ac2b5c385275bd31f8aa5a0ecb2a1304776359de920f5641c131dfcd3d9fd498dd47e8c960f4114bab3bbd5d6ca6433fa91d6fb49a532c047587847adfc380e19030a2fb8f8d2d981cb1584d9cbf0db99f3a17dbb5a7ec26aa6da369491b0a3e4ac853e3fe9538536448057d83d7eeeb485417140f76473d78778dbfa2e5d31af42dc4bf765dc65902724c4a7d6f2d6a6659cf6b8335d838008aa20aa28047c01652842e0d3142c303f993c23ebeca7090f4fb263891023a4f81c1c9bd7724849679db44837e8d2e65fafabbffa0e9b0768d0433edef798baeac99221a420abfba5917b910154658edbd9e5e231d3e48be2af51d0630850b0287b9d2142eb11316a6973299680b13fbc9bedf138c1486223ad7bcecd714ecd14b273887ff6fe7f5890863ac13118b29c51c611a16b6f17c0e966726ddc82bd5381cbedc1bb0b834f9de9997466cced3f3f0b8950dba93ed8f59387d2b16560c2d8e163decfcdfab82e622ffdac1b8e16cd7315b585f9bc60cdf23fc5ccd3fe1d22bdb274c94fd1347a83db340c7b58a70c451abf0821dc243c9829b07c61cec01f3a998387472faf91bdc47032775ca22fc8bc5b916f4acb0b32974a1ab6276cc5c155d6657ec32983e36504e1a8a179a395212a949407f5d5f6055a9ac3b906f397a59118f00e0a93770f0308d872bc0803f7178c7662da9cfe65f6d9c986a3dc1e10f2dc69a203077644c63d80310f099147f363d9c4423166a6b927b2a1fa14dc0f53e19a933b98e4f1a563225ff608cc7fbdbc5d45b203079f77aaa9559fae191b18a985801c7fae62107c5433182cf3c146410b50e1c249f6623aac5a13a08ea7816ef0bb6a01878ff87c6c8aa34a5cdb8745ca7d42d8c261c6c2632a7ad49b9b4123b741148c3c75f9040789e8103e741cb5eadaefd21545070a10e2ab1ffe1be32da0ff3dc6638a3b3588eaf8a6412ca13e0cbd41de7ab2a22489f1a7d9327cfc2333fd671d9dfff9cbd3c91788f2bfff871c030de5d6e0cc4da50396a7533da4b6dfe53ed4b6883586f00e213d38945583511370af6c4780a01d47f80d94b8e145e8c4d608b7e795f13c695140463d6c8215db7c550aca7e2c5f74137004a3304e9f6b1e2dd306fb335739e0d386f03ceaebdaf57994d7eca5541ffef3df37fd546803cfd2ed537f6c7674cc70aefd9dfc1fbf358b13a8566c71922de77cad884755b579de5ce2c2ce5baee7ea3077a3eb1040ad605a472fd8a6e88d63a391f3ee4b0ab719f9b5b207837dff60585c30aa0d82f92bfe2b8eb2db5cafe0b04ae44703cc7c4ea79793c26ae409ebf190b51d73b546e122566eba365c64ae2e2244de00e1028dcfd9f2786b06fe9d8a59b9defaed99f41a3b0279dd3a5e18071c73c4ac8ffda57514d58407c590e20405766c919303d1ed2405e1f04ee77ee0901ca64d22aa826a458d4cd2ae817a14d6e1eded76dddebbbb9281b232a20ee8307de14b0d6198d6d515fa9afc0106b79956f955607fd2f4890648e75c13df1d184978ae12e9debbe1393157a879a58c4a932eb3db77f3753ec6bfaceb2b724c48954b1128f5e232c651e7660a50f395b06f55c6313d40cb0b4e9a09394fdf8180a60eef21de43fe854d092b34580682b956c969c1e24d01d925458f6e65ed9dc4104d7f5afa31efdef92b5afeddd397a219e28001d741aed9affb50324204878e81f92d6b37c7318c0d3e0852ae1fb959af8b054134b6786d0413ec758a3e3fb296136ff19a0598de3332d222f94ee32e51d27eb081ad4027a61694a7e93484e3dfcc8bc9bd4c715708aaddcf8615d165b496f1bd082fc59e0d19885c1666eda82e4b7303413a644fb2bb6c7d9b0d744695aae2a1eff7bd715578fa8329b3d9ab69f8ac4ce5831eaa11127c45b6fc0f2e24570d45383fd3171522c276f475dba1b2617cf90e197151036cdfa0a875296ec4cbeba4d92c4c2251f33697d2f5946577131d6c8eff04f68e1074ee305ad1877e533ccfb6fff05f4fa961265a932d370c4a00968de1dbbeb24c2b459f1480bf29205ac1a490a27cf59525bfbd5fb43eb79867d30705455447b76458d3a0bbebe918e65e207a27fb6c9f25ec6b41c8ee0c4b179ed3d36c46e51aa92b3566c10e3a4c33f3b85926e926f839ff89cc238f7774bb157bf52b692118881389dae365f8021f6ba431532fc441bc832a2f4ab5d3109423d9002b7939c9e86e259dfbafbeb4355155991d957e313f64f79dd35a564ec2420816521791a8cd74280a5d2a6474c47c9d41a0cd4825a3b3e2ed21a277133200729a4f9879eeae5b74d27fb9d25d0c466b34c38bcc14e58256b8d60153ce6861191bd892bfccffb10f21bdc701bb64d3394030eedc3db92a07ebc56fc0bdc139a89367a69bce358b3050265a4cec844e1002addb14fab7ba5e4314bf0815e99ff0745b04f57a016575b47941b286c89ac8a5a023a96e0da88a693900536dc304b84b34a5dca8f9367d9eba4e797d69175083c5cb56156f19d5d1060f81c3ff61010585d643a3602a8bc2e975da03e53d7d13a15c81e7814fa9a4e9c1236a389f3cf89c3d6c32b37d0db574551603557ab32932ea114357ddce9963d78c83b94117ef3f64561975be2b54ace57622e6160cae1c46ac8095c1efc91bc035bc73cb7887c7f858937d4b10392a747991eedfeb71be8d1767e19f82fcfb32ac1540a24d704be4917741211409ae5c3fea8ad4c5c048d971babc6c6c0231bd707c84e779de85cebe7b97d55607118e8e764c8cacc26300cad784df2a57915f4ab9987253b8759fe7f1672f205bb67838391f0bf094c0a58c50cda23fdd2c5d4067ed23296c6f59bb7e101850e41132a990889e9d9b8e9eebf6f7f089710a6daba5af1e0ecc18a35583ba0a75834738f2f38f23f79464760965282d35925c526293550765be90d6855a70c4744f34293071bf291055984ff8ccb6da4ca19e853692fd4e370c6ecd998e34916f8b158a8c7a579cea0b74b33e774d5f937e0040eec608db910232986c0ea42dab2706d35f2d11716765a42c9f1d1418b85b096aa4a139524c43b194d220125870ea7ba03c455c36f9648bcbbbd93ffff6352c5bf4f64f892c841337b96b54266ea539a2ace79932529259b678389d64096a7a77196054065c4ba3db3223ee8b798f813a4120d7e9610705526ce79a07e77060f3277b58b3d923e4f647733db8bdebe1ff9e2cc7b003bf7939e7151a136167242a223248eb8a6f9e1a623fd40c426402ee069d84ba6eeb060c900a6d146475a0568f37eff6d7e350798da28b359e8a370a79a7c93bf1b7a4c0ac28056bc0c3bc90c67ef918be71b49f98424acf193ccfd34cd882b4acc554fdc89c39f3bd1deb25ba7c32822a9ae5ff70d220a4cdbe3866071c691ec5f7dfddf9c5871bc5bd6410a31e227ba12dd84b17a2b16f7610846b783097ecc005e03ec62c6516239e02e6da6d210618a3a48eadc042f2ffe0579145679651ef370b96d500a95663d57c8e456c6bb49243f5d70d93edb3531a5cfe770f9ff93fbf6e41ff595532969d266b8eee251ad6a3f5998e5821756152ab4361856f4c79dee4838d0c5722185efc21d5cf6828a89c339af41bcaa26d9d3d0c136f7d89edd8e0a17bc3899d83e5ebc35a9bc7bd22f0fd7e24ea3893bc15bf67e4ebe71c791d2af72b44892cfef68a2febe21c69fa5b2eef41bd1a9e549998053d95baf1ef34464ad3b6f31a604f4d64279f509398246b76863100e53ef274f95ac2ea8dc530375f625decac37a39ba7095bdd2715f21cbeb74110e16f52dacfc440d098938b7458196363b992ce99faebcfd80756995c21d37fe06fbb198dde867b678ffb19428e8b3b974fa0cf20d433ec537c8b5f4ed7cdaf77e4ff2dfa9571df6c969809b7796a6ae4fae954da2f01c91135e62876f49370c70aacc3cbaae44f9bbfbca9a3f4102f41a328822c2d1acedfca7936f87b2af1a0533a9b7bc77bd955edb0b7aa9c7da46db5ae0379f4a83b5edc0e728d6e7068aaf332ca5de62ab95b1841326e1de6690570dc0681ad7610cc532468ae3d81092bf1cf6c9c8d33a82ff074e04ef1f41374a47ba23e937e7534f7410b875c53789d86df520e4d64667a59067d31bc71955cdd56a3c646eca8c99f9bb5bfd2633bdbd6fa90ddae3787bb5eed6d4c12bd7951624d743eb708d1129bf1a69a6f26216f4e35670f834615bc88b68a2b74a2a6c5148ede4a12a5f331c72707a55af23e61ab28773d7882985314d6a6fc65065fb9c142bf66bad9955344e5e96387b4ecdecb9cd99507f9b791051893b5af9cdf97c64f1978de315102a8a39ad1bd4a3a9cde949f63a2cbea93e2b236a4d6073be34de042790721a77079378f3fb7fe2adb20fd31ec9d14c0b8ad22b05ea7175a7d43a6a33391902c71f6997a8ae22cd1bdf664c92b035c2447d2ff16e4e533fdc33d110194202b40232419c6a5518524d6d4adabf3054676a919a5692291804a02b266eecd3e263e1b477f3e66d8fe4a88b0eee98151dcc800e98b40ffb1d301c4c9d1ffa1a5bb144acf22f0dc932021955d8efbf8b222c63f01e0548b7d25aefeabb217303918837538204ad574d1e4590931567fc19b0241290457e97f4f8b46650332cf5844de6b1f3cb9167dd3e0fd350dc779e44576159df513482fc9d9ee52ef6540bcb65b6484d5590af4c4a7f3c83274c73289730e82bacc365d8f7a3b63b69084237ef42661c9ca31430a4bbc7328ab25fb151b323f579aed6784092a5ee9be6607d64f574dd2fe7e815e5c951222bc8471ceaba85402df539d05fd55c7e944c741c35d333aa332aad2d6fa0556a171bdd1d5dfbb8c44cfc53a623e28a22338dc93c761221b3fadbd08ed08452ab0a8fc125238203f7caf95bce21d1d0a07da3b3e977232a940116e313d1ef9e978767bff9e158a1ee1afaa2b83a9f75757a3a2a011c79317cbaeda64f3d2415ebc4d4fb8df5595584d957560b8fedc9dadf078247d5df77b4192caee539d7e1907813afb49d42d27ac59f4ccf2c64fd001337385c217333c4c4437397d416a87aeb2b9fd8b3e1b9357355f619a2b8b8e447373c19681da6fcb2a0faa40b4b2a8417f97654a84ccc87169d16dc50162853a9644f19b8fb5e03f385c9bc4cac6bb573c8f5d4864a59c58dad0e6fa39ceac310fd22e763efe5c2aaea8e5b320bec5a8503970d9609a6f372862b598c08c59040a2f93b3fd7c98aae624c81fa0f8dde556544094e24de9cbfa17e22ad6873f08b5db8fb74e7c0b5585efcd24f3fd5c2d28b803725e8beec69815b654f8b69169c4b374028cf23fea277225a465598d11ff114ae46a64fb93792237589207c7d9174e33c9714892a67e100cdd472666d33ef6bc6c553089e29bb4303fee68997d014087499fbe5954e9ba49901d5b8ac0f73c179592928e7900b6030a258ebe37a83ad6485412e013543b9e7f082e1e2ac5d89bd524799b0df2609a8360f59f5934a269841007ba5712ea22df282e6bafa768ce05579a5b87843a157beb58fe201aab983b2eaa3b108a0de940394e36384c1486354ea9dfcb83d3dd835fa5e49ba273a295108c22825efa7a07b7587544292d5c619b95d162d3c52c7a6365ccc1085f646738ad9e4485cda269e408c1571f62d27158e2ac9618d5a156c1a9102b95f9179b91ef53ddb70bb355149478829c75297089e1d27c8e08ba0c86ec08452d915692f666a3e326a0691cb82f07b7fb4136271e601791e1ecc0c2aa4ed96c00edbd43a94e70335ec7e53ae01c68656b269f997d188d19cd0f3a42796a55b5d47d9b39ca493330810da38ed4a1468d5b5df10a37d67c27e8b185dbde4fd962fb765be14de432b6c75dc1dd984323e1ccacd734533b6199f199473854a0706e9faef62723af10f8178e665c2736031f4aec59566a5f21c1c0b72d896590d24c96b476a6a279973099646ef7ebe9f91c3b4f89e8fb249e7c9ab61828a7c0719bbac8375ee3180c78ef5e738646e9864b8826df70d13364c77df70bd1a8cc29d4dc7193b0747e8bea9fef35b930302ac8762ad42dcdc9ae48e7891a0295cebaed2241776289dcd58238cce6f1011a0dfcc64fdfbbbfc4d43cead7e75fcf4aa3b65630612cc1ec4c6b8cc3bd75d90e3930cc770107a07b7c6012a601a611214f73a8f2076a79968c4c1e0bf0962f508d34df2e7318492ef93bcc52805dde6fee08fb160bbf9629de9ae6450fb152aa784cc4118732216e85c0890cd5bb2ac7dcbe8c6b65de799bf9dea168d09357effe7bb8db483e52ea5f51f983542ceb399525b5cfb9099fe2c3fb19cd7efb3f97f800463d8b4825925f0236d5c56eb4619512c9d872357b8ec22ce8c4d26a9079ac4c6d3860b435f25a2dbb51d5e5fa34b5b5dbe99099cf2abff1f7cc8dfd66af908dbd680bff2732c7372ec1c3bc6504247153acd7d46c4f690c1e20d86851993bd47127af8cc6846bfdb0e6d2a1bb0b00d4449c757282a33c1135ee09afccd1d1928e67db8dabfc119ff3363442105370f21fb1fea96561f638123a6f42fa8aa46d467530182d5ecd0b7dae413e9bfe3fcc6f59bbc4adb2e65df37a18f220d0d1850548a77fb524037dbd163b7f4b32e1035ddce2970fb29008b24c19ac29e65b1e814ef643fed9d43b17764eaba93bf30fd1d3b1093375d3db0298c9ee3d9e82f78f4cbedecb772f90355e2d3ff1aa73824f370c52b80f31a7183c9789786fc7426d53343d49fa19b4af4fd425bcb7b33ea4ab8d8d1936b36de5bdbd5b21d13dcba5eb2c2c5cb4b80008a84695eb2e8316b09d0b2197ed9712a0004a751d438f0c5c2d5468511aba7596d5b1c14c365a795ef13f8965dc06f18260c200c52b2de1493992528a4414dee91d02ca757cd9632b8ffdadd63b62ad6907f9722654c36ee9146092c05617fbfe5a482da0aa412fe23e9fc9d6616e8ef4644e869d8ad2f9208beef5ec9a47e51ed4546f3723a41c3780f286c61413ebbb04c8b8b02db424f4fc29c53ff79a2f714ae99c2059aa990e66b9309b2707d3a025b66ced726ce16ac1668891168ecd4d5f44372ee5440adfc3dd6eb5432205ada13c5775504ca452639ef0f188fc7ecbc452444eec69464c36fd9af7b4e2dcd3a2cf7285d9fa769bd6db4d45592cd843b78a07fe4eb49de7bbcfb2f930a515b385923ecf1df24a1a77381f1ac510ee3ea1a6940bd1ed61674821e54c126f51f6ffb9a6d282a32ce3ce9236bf1fa5a533384e7c5fba64219df30b55801b0e2e6dfd1a6b7940b4ce606ab73b52bf24443ff8200e510cfb7187bc1b3c1196fe2d584872e0cf66bf80a6dc0da0b7917cc572c4eefc5a9292368a545e6496a53403c8fa0006e365bf6f4d41407c9ed94660afaae8835111d5cdf4f5fc025deb997a57666bd2291783935b0402230f6c56d2cd60985411c5640a1568e5d73461a6180fe2677a5f25daf47a1f7606cf059f0e7a64c35aaa816b1ce1bef4224adf1c2504539cb604ffac93fe13ae9f7858c79de5d2ed397da481dd979b47ed379ae97c5dccdac1274dbb86fbf2d4e8a87423ffc45cc8fb8e2bc441efaf7510d8573a77efc19f38417eb40e7faf733163085fc424e43a3d99c724dc1601e13c2b97632f7d4c7f206c30874ce4849c5591b23c19f9526394e0c741d4bb6f1aabca4613dc825885e0ff57dd66e442888e8d884dd1d9b1ec08b7d64afcd83718799847a4673fe8353c29255cf1d7638f2752bc4f76234384393a77f0c8335f50b25aa6d2676e648bf8180a66ee22a50e1ca5ca1516542e22dc2ecbc5e2a5a551937fefa8dcb36333d350f774c4265c2f8907a51303180d09cc6253e260b1c236d73d6ecffb4016a37208e56e6d80f9fa44eaddab859ff405bfddd18eef13dd3f373f44c6a55386db1788dcd9893df3b72c640210352bdc4437dc6a0bb341d55bc4402c287368238304831a2f180ec877aedcf82b19497ed98a388d1bff38f18b2eea4c5c3c9f4f87401518b3ebf240dc2560e21ce60c175ba386b953e28dcd029039afc1f6bca162f17004b9ba58ed4a4a71b025dd69e1084b5d25e06eff95057dafb9839e0810671758e55327f845c081e04a352a888794eafebbe28a9c8d73a5320ca09ea1db45c8f14423e7ccafcf2a1559e2008269b81dc997783d331080bf776e30ba290b22f9aeacf825e63863b00d1d1d660e20b34a1410a3eb2b6619be8c758d8d1a986144896877f6f987b89e2ea376ace81ac8075d049cb63bbd205022e2c79ed625e5bdda67f7b2a1dc728426ca8e1a349b0cd1d80a0fc4c1d84470f002d2e61939a0f0cd852d13e7547b283db6ac8be62cb40f70f4043b40c85d52dcf93f9a2331217e005a44a96b24ebcd231fd6888d29fd4f7969b0b4ad3cb6d1fb4a40845edfba61e4506436cbe8d91321891223676bb596a5fb7277e4394ecebf22a88f9cb64dc694b516489c71bb0a2bf0ad0e435521c306945f8dc3d6e9058ad2a653e75fba8101401492fca992dcb6678f659f859c4e0d470345d0a2686de793517191ca977c67bd177260f9cd632c14765951ca7cf067dd90bdec1fbfb02e439177666f016af3262d15448e1b05c1bf234b7d6b1c36d818b76dff0fed8697e040ef72e82c01416fd3c2006b76c2660a5a522c3418fcefff83c288698b3f97e787cf9b40ae134906821cfe81de669fcd7b6853058b2376d2c0ef83df4779f7b154ece5bc2dcc159c4b76c8a7edc74d932fda42b880da2113946da1934f8b5154c7fd0e089de151c388028a8efc8bc7ad59a2e692ca14d17ac68054c434b1554371f994ba19ea96d64b4a874588793ad153d9d31d5fd9b5879b0b3e5ea3f28d74d018c6275959d722a696a115a91bef9e3b669109b4148b108e7ea9cda8e19659a9e6c0d3057e199a80fd23135bd51597e78a51f7e68d985084820962d7ca9c423944a9ccf225bf731dcddb0be075c6eb9d0879cc664cc2c2c1ba83676e3dd6e268de36cb8dfa7b4be42e37e317e9a009cf3e1545326a6be0713fb09c1740b9cbe3800fa688f27f5d3b3e6c46bfcbd4e8b0b11ab120fd8faa89fcf307ec4fdca8f5446c5ce322527473c2061414cbbe8409a55b918b97163326ac5f33f3369dfd1077839889580c906ddb243c192512668591c81b9d5a89029d890af25a2644b6faa50cc9275cb96e8951683cb67a4d5972736f69457c6375095a3eb58b9ae1680564e8c7252dfc479170ad54e3159ef503e55de432264204a3f9c26d59cd627d6f7ba5a603b8670ee8fa9aa1ece22d8b536337d0d7c96fa92f22351a6c46982e48fd0e90328a5b2b07f9b6743ab5d85d49089bf75c3f9b0ac0115ef9d9f0776e2caa50518e92ca66767b5c884e602545fb1efeec6d8973f3e1e551549f38a696e55054fbdb6450e6a7bbb3fc77dcc4e5dad89af8e68a3274ee9616976c8c58b8be1f06ac68d4f048a897b3f6b486a3e4eec9ed5882403e42fbcdc9b3b130ecf0ab32e65f7dcb150a245d3ae3e1b85f54181f4ee049ebc15baf97602db1e1a044086af087cd4e003c8aa3af32d40e6c0ae69c993d82782691a7ee4f4a32198a40ebd68e385f1afa25514dffcd3df9df2cac3218a578c0c52f5845f0e101f063dd2fb377161ea85ece9512ef82d255673b8f97d00d884f1c60d407e308f5bd1e01ee532cbbbe49c892fccb8c9f4a1286fe5bf25b804ff0ba386a8569ad798be464cd9c14cc01ee5d09382826b275cb4e23b9dfe236b93606f5774d5831b7afde209636fd3c04c6af63245579cdf4ee5010adfeb8970452b32a0a562c271fd8a6846d5033bd75674bb36bc521eb2c133699f757db3fd47530a2387f374352b878e3e460bdb35afd685d752c09b7a33cc31f4a4237fc819f228d3cdbc2fc5d5e2cf33d739ad2a56cd675629d43106fd83614aef65edff3d9213bb5d8507e8fd45acba795984604616f84c190fea7ef1bdd38e39ebf5bf30e04abeda43d4f9e48252d7fe6bda7a9a12085f69d69dad5603a3a4a07f41975d9c4d4bf77915a364635e6a6468e7dbad2276a4e06e382f52547b3d8b62e856edcb9b28810d900bf7c9ee9374ab6886325313d1c22cca8e31c74f30816af80b8f0ac601e0c8269083697ab0d7d492ae8261ab54eb16aefcfb9cea91faa19138619c8912e59f40fe31f44bc027eb5e602c4c2ca85dff58cca5d6042b6ffaae085863dc149fb2cf058864e3180de17b582efcfdcbbb93da6cfb97b05601a25a348273010e4618375cfd8ec71cd025523c6c55a68e4724552a18a8da6712d99579bc98329867c6f59236a40749b60e91ad515e86b14052fab609a84acb2e51f9d89a4eab19543081a06b839585dccc9be0b97c4b4c50ac9fdf79559e7a76d254dfd5b127a38346043ea02967b54c09d0bc5c55cf9f9274704d599b7c9783c872fa0b6328d662c92412efd0c2d4a626f2580f1b5b99ebaf1c02b0562eee41c011247fe2c378c1f0cac3243a9fe0f07e27ce8653aa11fe167e20146601fb016fc091e7616ccf2e3ca6e1aa0c07ecd21f862f71641686fc95114d23c83bd5cb4c0bf9e81f1119d2d06033fe946860a9b48bfc2b9c5cf15691eedb8a6faf0c5ee9c9313c1fcae01d60984be6973bec7573a360f80b83b633cf6c900176fa0f5991af019304d993ba3e9e91a0638e56398307235dae08ce4cde5f8f1866255d7fb0a598274bb09c3fd580f90026ac8c2b25e9fe269bb1e4073fe8d79f3b3c6abedd20cefabdef1b7d7f077ce7cc6d6977a452624a578aef95810be812e3f004f8babe36fa8e918e000af2d4010590e4c29a983dcf2c800b1941d55babbc2b44ad9776d8a3d4766d85c60cd365db9586f331f978c95f53fdddb31aee6a55ac99b78591efa675cfde4e8cbf73003de126b6a22c10bec279a858fd7b77475c967bf28ff16a2cd698de0c132f02885e7a985b387e36c47fde6923f83550fd7dbc4ac048e740c6d91762d1d2b5940fb2665774115f013f6e5364fab574a649008a03032a608b0a3c65219c4fd62ab8848d2bd2eb11fd077cb2d3e393cb5acc4204887f341dede2b19252bb51340695debcc6b215075169e0716db6d9ccc9c0c8e427a20ca5bacd83ac2de9fd160ec4314a71c12a0a0a736bb638bc002c37e017a218245baf146869637d29aec51104d7ff548e81589a0c038326139edfbc209b3fea06f35907900dce371d0c5de8dd2e81ed51badb7ed1d5b1870927440e499504e1f94d42e6ae7dc0c9cc295cd5d16fc8d417ae1afb779d64dbcae87fe2f5efa9397bf5528ec62612781d4b9c4bdf944b3121acb2c4fb59d005bd6b1870edefc05af8338da656b0040812573668500d983da24fe6025b1a9589a70270fe23d29ec9c1e8248e07d7e93a8c994876d662d8b858ad24b4cfc042a06ea1183bb16b45f77de4f2b4b6e4fbf9829ea7241bafbbf02f777bf199de372aa388616cae9c3bc9494853e06656865ff2b200051bc2abf86aba67fc42ebd45db76cfbf4b1eec0db87a370c670377ccf016f5268df34c69c8a3b41f9395957e0fcda6f7bbc1f069ef755a0784a0fde268ce94a20ba6243141d54a1477bc368b2acabd44e171c71b3ea2adcfd26b5a0d30ee905bba0abf0218770b2cc54b254a1018bfb8e7f65b45deb947c025c6fd52fd5f15001a97b504bab52f761aa5fc34957fe26afbc615801fd8fc6ddcdc9455082259b5c9d048abb56280d9d6109cd183afdccbecd93bef2b5ccaeb11871e8735996a3b3ef631c257052d724b47179492db3c53098954a070ac03413d91cbe52f018b94a143d5a81a76d3051c16b2c1d5be44586179199428d7c7f4e446bee3fcfd5c5a710d24216eac9ffdfb1bdb56fd5012f59466964dea93c3c19b2999f43fde1fee714b62fed6e1eb061299e7eb37b52033115708dcfa3c37f975058b930aeaa03cbfcbea732059419d02c70c030ac4e41223a5641636512d4b154d9bef107de87ba471a9dc1705a9f10befc32b906d9969a6cf0d970df3a9219771e3c623a689a766ce5b7bac818a2d154d192b33fcdef2bdb9cb2abb907b5dd2053c6348dc588f677f6ae85df9c66bcb433a910f83f0329c6ea327b2017cd8eabbf9a0962cbe59b3b38cc375e1ce0679dbbc976f5ac24b3c0749bc950684c11e0669885a0401f60829ad3bad7569834ebf56658494565f261196fe52db3b9cc775519adf766581e3dda3d24ced37e70ed7085ad77aac674c4d4841a7e72ddf13beef126b7bbe260861b2e34fdba713e3cbf591d0ccd7dcc497181f6562e4e0eb1add1a6483a974daef8640e13e3eaee315f9e1811243a0efbd04dd4bc32a9baa8b0e8c7003e188c7d0e0b54b20433213afd019c95cb670a36b87f474e89157362b97d417fe412a23a10877cf512992862ebbe22b87a64dd95456972acda54caa94b2c9c0142bf748777803758e9130e59e7db8680d31e59be07df442fbed959fbd85fcf076f389974904587eade1ce8c7996f1dda1a056251275b0763372f6969ec3424382175f5a28f57dd1a4f4139c7e08b21f583d3bd795d794e07564b90ed63f67126359c7b0b81cdb317a8d43ed1e0cabac0544dd32057ebe6e7c514a0203a830bb43be40d19f9766c793fa247f25a6b61d6fd9b83c83bcb4addd4fd1ebdeaddb4a22b88bc78ba29c028c9fe7a7c39a8bd503c93074226c0c06ff032fd34dfa000eea5feea50035851ac7157409d2929c93593237f3fb19b1b8fb339c80dd9d657c57889281327b2efe68ad2df1de3fb3dce1b001c1e1029833bf49b5c3ce7f406ac0fbf2f72109a74e503311eaf875ee0326946d1e57036495e93553441973f975b0fae0c6ee0d1224150c340670e155246973d53c08d27f5cf6c7caafeff66eeaabac1cb0940780ae2225233a01b82c8e223f820de1d2d7973d215e8a3ebfd441f7d1ad661d2e9eed830f6521ac9cbb80ba9ad7f30d94fe0a78947d46f91502a04dbc9e65ceb27c0274af27722fd1bcbe058c2b3df57cff52f27a4e158a892774006a60a4aec3cb5cf8f8056648938f1e9b299c655bece1f00a2b63511d75e0ba2256dc201e9d7c093ebdc09dba982f76d0d4028baf7a7227128a302d8e331c7cfefcbb0c2a85ee95332210b547246a5aba8fcc457144724d17d77d47616582586e2ae5c149a5bc922ccc688ae52512a5259e1bb96de10af105e9172fb6d52de44c3b4cc78bb45986caeadad3df5fe0c9495a18754462a36be5cf5fa1957f10b907739e00d1610ed932cefaea2bd02f2af3a8a9cbe11c2c21d4d2ee2063a089a6ac530dff6f462f357a6a6983ef9fb10205ecc3487a44429e16f309abed48a8045de72482160887b13ff150bc43c452f71707ded0d14dda657b3cce0ccfa567cd9bf5a58327769beda44007158cdbc1acf5ac74024ec4002e7325d617f278b048239a97d1ba7eb43be140830a3eb8cebde7275e616a477497495e4324e8fa476252c0ba6396f2a744c130582aa979443389eb9506298d96d4859bfb989b69765546af7e9b3e997ec3ea99d6be5f0222d3e50f6971c08b7605197e5e69217f274dc0c69f17ed0dcdce1f26cd8e81db3b6bd6dbb0588bb46de992058ccd0babd2f7248ad6f1f07959c20e83ff6f1b1f96a4801bb1ed8361c156b0b14eb29b02d72da5bfa5c8cb3b3fa38cd1fa459e01390d6eedda6fcd6845228b3815b128c05491e27eac827b6eb6451c8791693c2a0753894fea2fd2f2a4df09a75ca58a03c12788b166a2bac07776e945e0a1ce2a55a402f99a01365b1ed5da62fd4985880dffd8cffa86d5de4281aceddae157ee73c96de1f2713a966d2b90f83b3e5c09414140b123dc2c3effb9d0f6e33f8ed0ccadc7b10422868bb39db11b4d63f1795ff81494aaf8e8527fcc4760f5f2bf451799d9519d7b7a2919e0bc76b1e1808cb67d1e964ba71a293f2970f7114f59c408c41cf0b2a3f56604270aa175f24dbbbdad2f263208f019609dd7a0e596c967e8b89befd8b2dd1c2cd5956ff7ab31256f08ee384d141dda1f68cd96c3aec475f0ccd795bfcde771bdb8e5b8719422129b71441fb7bd6c467d6536f9d6cc97915e44a8459e5998b29ca3c7d0ddbdcd24d1db82941f5b2fec3ccbeb109ce815daa204ece726846f53a38aeebaef11854b7d5d02c423247282a531139c44c196ee5e5ccbbbeede26b1f4126c04c0a9a9b55501f28b12bc9237613a04229b69367c0958696964d35bb93321374751870b449d2d70ec0020fc8487d7126221b2626d9df781538bed2899ca604206846bb275e9557ce57754f95a5b64c1e24976a2b3bf824ad8e063eaaf12d30c32c189c04f536cb091f4172552b0fd032646228b7446a00c79b94d7084cc9ca3b82ac3c0dd03849805f9c9b1738d467c90aeab499ad9931549a5e979181fc6eecbd20fe83bd07dc7b10014749a2039013f74555a4f27a935351f1055fb3afe8288b9658a4177f6d45c0a4a516fd10d7839d9621707289ecb706a0ddc2ce4a38829fb0b0c260dcbf554d139a5cf17e4f7eb1b624f2d794e3c378b43f04596f05bbcff2c7a8985ad8e18ce43b3f79cf5d64c93fc096dffd46e2d972785aaa8469a1acada51f23dcdaf4f9e2e6154760e55a4eecb6fcbdba734b358665ac8dec1f3dd34f1f0bd2311bc9a36e7c5d8086ee4c50b094b9f3f78cc6603e7b287df8deece8fe1e4329f4f37de93e6670b60c0ed3bfceff862630bcea1eb9ac5753d01e2783a5274895483d0a22ebe1f98549a90fa7dfe12a764454e22b71cc38e7819156bd46dacdf6c85b3c11c2684e1c033a22c5114c84b51b2a800060162125caa633fe3fc83bd0fbbc84235dc753c20e70dfab0a0499a2f0201996e70487ddbef862edfb5fdedfac53ec9bedc8e4785de095b75c446e4af234ed8f6ea5128696327da3f4e35de01d81a2ad0bde0606640746bd1f641c47041d4b0019a810144d3a5c611cd841dcd68c592a33447b758f6b1807c2d25905de143718a0f5b70a92ef3df0da0ddaa5b2e872b1724e3fbd5d2a47545b568ce7e909ae782c26ef73b0d97066f8c2fdaaef60c148b7248f020f17aeeb2bdbd6ede4f0b3dbb934de166c2c9776d7b742d17d2e0bb97ba06a5eabd4663866898be1546a4841fd2d1ca93fb6430b8b5df2f5ac1e9833613fb34594c55e79b319a14f8b274e02fe684385e1e0f66925e4a8f5fba50990eb33e4284e3fe13a6f3b280750aa35e644ac5ebbad1460ab5eea740fcb65509be215a5b9b3c3dd2d3d90e9a536ec2a696e4d8570f267f013408fc57c9dc347e9dde80321afcdae6b06f25e0140e73b9cb36277b39159ae3343d7bddfb5c8dbf2fc37369cd93e1e2fc276ea8ae4ed7712612a8996b65998b0d8b24c57edb5b2dd91dff11814453a20a8a68cd1dc7a78e1fa6e6d6f20a8f09580cdbe003e630cc951e07b890b4b8534c0ab168a445c374feb9da057dc5331811b7bfbdfa7a2787a0f598a8cf0ad50845668d42f829a8efd5208f6bf609396c271dbe62f7cb5249323cad773dc774c68ef3cb7a38d8d44435c1491c68f8ba6bb6ca41743813f5776a0f58f3ded0ea88df6e500229a9741e160bd944597871ba65acddad050fdd466a7f1921e080dd8c1fbb1bf769c2c3c7620ba53d36dc5bbb518d68d74de37821d0bc4a0c988c72c4fc8f11d38268562858892907e53b429f15f480a6e8a7c07ec8e2a0f62c551dfa1d24410a0f1b88d8244ed64f9067205f0bd43d8e01347f75d1f4b9234859249aeb022f27738053f00775d29319959de1d346d17f156e9a9bca6f2d5af91cb9dbe4a186179cfce834f92ca857e81c4213fff68a53517c9e39a0b53d90197c80a1bd8797e2b02cfb2f26b9fc88a8d8dcb583630423ee6acd926bd39746341359215d493b1f873aaf44704dfd0726ebb2c28adbc6347a7292a6763d8f4d8db3d9b78322ec1209fb6753d5146c2a370ac3f40b4dac984ed005a3f059d957573be66150644d77804c5ce4bdaab56e37e7bb082a9b22943064cf4e79d3166743433850ede64dbf2f4d06df2521fd7b15fbb66ab5f13a8945f5a909f64c2c54e80d5dd81d3943af60eb133a05f1f9141b0d6f8e30fcec6e4ab387e9fc4eef5c63c380be8182bf7680cdbbea7a4c62764913f34fef541f158b915fb0bda8aab101d05f62678d3fb538d3eabfb71eac6952b6039aee77881b52bc68939654d391ae5a4185a10aeaec0c9fbbb84872443549ce65fb08fc329ad74d900f6bfeebc13006bd15011ecf21a100b1c4779ebe96ed8424fde53d634facd218a49abb69952aa0e0cc285482e89407193903c330970566c2a973920a6e1de086f32a5fc8baf8b09360040ea0b97d153d8214ef31c80a08295491743dfb18d26e74b3086d1fa4b3dc623e1e89b814d08125073ac926f14c9945e6e8d285294ac4c622770d353a005f1d501d91bce514c4dce8fc4bb2f34eaeccb0f58bae39e112595520c9fcd70c7f8e645aa84c3f1dac16426f19b16047fcaad981514bfeac92d5af34bece109b87f3dae7a57465544569681578d39c8bc22d8dd759110f96b5161a4ea0ae6b560a1ddaf178ad7094f4989369b111a5ed78dfaffc75b78027a993a035c43c507fdf62b7261156c989ad0f8c9229800e9d837adec954f40d79dc9c66d91b768e2dd6561dcbb6afa4dcfa82d51a856bb3474872192a11559715e2c00b36d6abf918b32527231247fcfec3f92693998ed6be7f8f7e49120d854200af390ccf9d19d7054ddbd5f881117d33ecc95eae944b811f2db51a88e92f6a697871d161cb0370be46b5fe8b6d520ea9f5eadba87a9973b745ca26c5a6b5a4e39cae484f80a01e5f1dcb855557c93df9e2128fe24d445c58282b433f51334d33b9e6d6239eeb3d741377681ff6bdfc3e2460db8a2b0ab327b38c7d2be866e2f455c961d24905f02c4a84726b0e7691c3a75578054aa1099038fc89718fa3e3cd3815c9ef4358883cd9ea35c9e427d96983496c48267f3efc004b2372864d4928a6d7efa8eca8b4fff4386024e927bd01b94c01f208dfc246ec12d36456baadef29e4c68a76834829f408fafb5d8744ea2643c195d00a74cdba69dab0e25b6900a0cff1941b05505f189e078a0d0718033aca83ce02cd613c6b7bab09530e7590d3e08d66eabd3eaf41c8cbdb827c2b38267314d4819d3bc3531430f41df0ad53e6e2ea0cc1687e42c49bc5496d313383e2f906208ddbe0f8f8bae2f1d1c26b212a4a166a2d611bcbcb4a8a0516b38edf63ec4572dbb77f2f1131f60b931aff579793ff5e7b862dfc81656c65626386cec82e61e5ed143a6302c93c62c64961ac1a8c2b38749a82a1133d0070ae51f95fc8935547ce8496440d3e11445376dd9883263817edc4af7b66359c35bfbb6964da56d6d046c9d89e274d06c20470110804eb2e765318d5a55936ec4f457e3052e5b040283269dec59f86c319edae7f95b096863d47a7a8d1c8be95294145997a606f3be3d8cf9e5b1187dd463f2b0959b744914accd6e5b9242bcb60b11acd73d7d40ad9885d7a449803eef38db5b137615bbc42d63b4ff6e77b51adbf199188760dcf7a58efbeb46f3a0de128007dbc1707220d2f247333538f19c54f0ac5dedd0114c7f2805885c074056e3530070de7d6ca2f58a402bc36d95b333726423a9180fd506ce86fd69cff32763fec67af7e8974ad9c123ed4bf8307379428f45106896fad123a01e5e67a3eb804aa912d2da31ace5d6c2a50ff83236e01b5ffb562882431c53415d2c446f9b12f51de18bad6c633a35fbf3daca9922e8dad2d99fa4868b3cd08cdf4713a4d6e4aaf54ecaea3ad1ff9ff0f68fdc0d43478a3ad2dd4a7612286a28b3bc4b9825c66de941553ed56f770079b1e9721ce6bceb7ae32735565958abc049a9b865272f7880d54ab637dadec47bd0fa634631a0197d407ba33912f8f0c29be422971681b309fe7f321df52728713abe72ddb29820ba6193ac63e33f4bc55ac4a693630733edbea55adc435d92e9c7e7283cf01e41df97518df4cb7bfb843761d3df67bb3f978f3ad5eeb2c712994a834800f4f91f29751182f710ef4b3f375de8fd303ee87bd35bf2d0973055a9e60e12e8adfecd5c6c2e495996171ce633d2ee0a1301813e7dd6938e077c83fa2af24659942930ed301a12982af04f7f2c881e4d6b48a6744b9fec332d0b70d755cf6e90c40efe8616bdccac6ec5f71645823548e3f95a70ac199c2befdb43c60a9d678e116e4fc5a472c376a1ffab52a1b546644cbf82a3e3eb48e334eeba3cf1541a6c33be04225e949f8fbadb94031f32f2d260aedb386e008c1c7ddf39036109f99b334fb67f3a61349cd0669e4ed225ffb83162e4f141d0b10d2ded15bbcd1bad2ec2b5555604429b3ee97be18f93125d020401023baa040a25268b4e1c2e8ee2832984afb5dc0c8f617a23967b55e64575cc32576a482dc4f71c1986d9c015e3441feb7a5c8f3b8d0317cc4d6d2137ce3b9b4f61b63c612afb408040f930264e4300a0cd887181f1debac8a3f313edaa5546142afb7ce63d313ab0f66ef15d513f9a932343e4b06fe09b67106c9e0d77bf4c86560121e994f5fb4fad34f7a9982b69828daa4ea53de2e7dc654d8ec3d97946ad91cf8f19576dbb66425f73686940e7a2b1da5b69dd8d49c590d7002d9e129c2ed8e5780b5f9e889f86554fe1b22ac4d91ed3cb53395197fc19ae77402b74a17ba988581360f45dbc1aae8ca9ab3cc2948a7ac33cd3f50ba29298b697c257dd106168918c650d1668bd885ebd970dceeca88c55ebd8794d674418ef9fdbd0ed4e438a50d7c943da5b50e2b2c2037ca63170dd25eb5ae9ecb25ca6ea09f8d72c3873ae75c6c4451bc0955f914bde4c9e35ce9f746a12621747230f25487f81447f282b15ec830b9b0fd6da22e5f7cb144cb5f14080c741ac5b5d4ddef36a6780227606fa4edcebb281bfb5edd894cd0d47d3665dc5eaffd34f7aac111ae93f96c31e66762dc509203a920f8a8b595e1309f35803c67d26a02714e06c8f9e7e470db3856a9c80ae8323afe70305037fbb1ac7f558e5fcf3c6ae1ae3c23d284a889e7eb5401bcd4c9b6d8612f579c1e29de2fdc9683921100ab5abc6fb05dd2ec13527aa6124b0c92a5aad704885102808b3b1f4ef7787d78a9346ccae070a9cb6750e7aa83a1f88ba3e68983a0ac645ea20bce160c31be6a3e3672d3ac0b35e1a3bc76d6b462e3dce0281b5d86f3661e2e08a0865370f618318605a79664630dbd3d31f60fb893159f5c8e98df69ad654c13336fd79984176d330737386f9dcbc8363e0ba82eabab9f484ee3568edb25af8b7efa4cd9522cf5d07a9847cb32b366335d199e4e1ca706fc1922a22009a5d4c02b986185abc407d2bdc8002308183fbdbf7afacf6012ddd9efc7b27bf1ea2b4c986848bc0fc705762f6b4f8d4d467ed9bc11900e66001a4972dbcdb55d29811a068471afbfec7ab1e07c21a86a1b6741f72cde6afc5196c8c18e98b3d462582b1fc7eaffa31530868379cd2f98b1619fb98433e0ed7b433628075c722f62b67d5dc85acbf17fcba986fda264c7d8b81a28b34773913cae20671a13f0c0e188c8201701a89020d56716e2b19e5572f9b2894b73aa15c203c9e1f2e49ccca3a45242cb2866c87c2ba76e0b8a872f651129ab812038772922fb27d85d6fdd844459efe6b155d7137d913825942f877033e0f42e03ce8f73dff016e8317f1f0788e16108279c780eb10c9f08e10199918f77cec59f90ddca83ad3b3e2f4bbc9dd3f7af741e3f46f80ecaa45bc16a5376c6e83c93f05109cceb6382494792bb7917f2bcc8ef6e779ee3a35f24f1c48bc4968130992658e99447a613d2632fc090470858531b9180daf1460f7b4681fca8c7fb8ba0392359ed1871b6648343d0cb2007448c283c6f2e63e6572da51b66b0fec1135cb992fd343496884dd774b7b8ce3ac74f9bb254f240c5de78ee2106e0e57712e8d805a8557258f3ba32973a2b086a68d833a3ad9c2cf058e5e27dda38aabfe5d31dce1400644749b2fce63e598509b049548633a9c09a0f4b4dcc99c4ecd10624bda16f19e22aef10e15a3d4ae0893a276da40444f313835010da867408e2b2ff375d3573cbc4a1ebbcffcd6170ceb8c15521050c89a913805ebdca947e5d8adcd0aa607f271d901d8ca477bd22edf9931555dfd1af17b1d775d5305e5e66990d22f2f7d313d1af035a24a9218cf8890646c0f6e8f92f7c52b610c21f11bc260fe79b8ce4a71dcf61f5d4304b724f77c9aac216a3e13c3b1d44895f12ba7e263be17a395c50a958a603c6141f78b2575814dd2c0e94d7bbe5485c76bfd5ef42b286609f2b208b499b18b2dee1213407f789740cf759dbe9b92593ef4c3cadc29cdeb931302c7e83e27b77609474e959f990a5082c67155b54720ca641ee64d9d3cb027d440cd205409c8de51923be70781030a6a6b059398bddc1f96d8fe35ac8c4811b6df70d6edb59f49dc532154b46ca6e208da5ce4da7576e6e59ba3c32e4a32bde900b1f995230314c0c684e7a4a7b1f64e7a7a7443e32249d5b427b1b198e24af5a0495cc885682a1a75432d25a14e64149f92b6a18e1aa17f15fd94f9a029af83691774aa5589950852573d5586ec319e913f8931868476a68d5b3a172549df577a44563b915d34993198444a1ef79ceb960a944edaa7aa31c29935695dcd44430078c85df0082902a8b6b1aba9b923f9149e845cb98517e9123cb08698c5cc15d1cc678700deef1b29a34335400e14991f09e5a2581ba0554e6ce6a036ee48a4d4bc7b9d87ecefbce303c95abe9173ca777512d4853643af276a35830d31e7c9b3a8db4f334b223623e46841d4e6eda52b3956f5b5dcf58759ba75117f265594cdf8a4ecdc601e4cf1b90886352d69ed147ac0499710d6dad90c0b0c047f5560de326f5ef9d97a09fe5ccd1de08224a4492487b782b2098475e79ae57fe837a7958bc6ae769517d5aad97883252d251a8055c850c91792e708bc462e568468acaffe687d568fff50ad8b2f748ea0df02971847d648b7954ac24da2e7ac15a806e788728162d3fb3366c0582747e8a5b2a8c86e0aabed96d0fca3f956a4fe0dc48bdcaa697b6129c50262d288ec00cac54151669c1800017cce4a28513fa572c94f07b6d966ea80ee57b00af19c6bcb4f17c27eaff995399ea8541e9eef9dde46cf03a93821b9f2f3af5789662599aeca6c469ae8fc31903ba0d001b09c9d034c0a2a54ce0009cfc1d69c5550bb986037898603559219d20b55584ddf6c291d1729293a2dfe97e2e9794c283606e70718cc8cd1590fd97aa0c07e2ddc39f7ce9f6aebd019bea9a34d81ff2b4ba7a2f674cb11269f01307b9b8edd392346c90bc7999e516acf7cf0b0a6bb10bbbfbfac56fd1dbb2a93daefa137568008f044ec811160ed7149ed0628775f2f4c8f7bc54251d0358d1a32d7c87e321b282c97757e63d3517140939c89daf196781ead9c23c7689c2d0296b09984715196897b193815675dea0de0bfcc317ae387d9dfe0677b514a95a7b1d9c1642e4b38c50c04b88cd5ea5b46e40fb1b24366ebeb79c817ba1fa57247ef05578538039473176570e2700592f76c4f59cf75e97c3ca930f04b14a5387029a79e2bc5c5a586823eb33cb4547043d7195225e592bb6470ce3a1a87033daa1c33953400268e0df4fcc5bc35234ad601e2cf950712fd6e70c3b0fa7c30ef4b5e4e0f121cd0562a3425442dfad07fc967fe0d21f6529563535d0b3080ed0bade44715c67c93230d4a1faad8ced89e12f39409e61e32c60d3af61ebdd459cdd7427da26017d61fe9cc389cee6655c70688d8c6754dffb2aec905647d611c17bbe6085e6368200e3492f40c16e85ad8e867233c70170f392470d3c8faf806c6fe0d3ab0e9cb882835c78e837dc998bfd8df62f2eae64cdda646a22fe84aa78c2d4abf497fe4940364fe3977f49919100bb69b0b3278a56a4f46960de22540279b42f908d6090271cbcb4a14e8b5671076bb7536b19a9feff3f4a90bc73374f2c9e968e467f581f2da70e51050611469352f6a788d9213bf93b4498889816410a9c647c53a46dcbd84957b5a86b27553f3fbd01bbbfe08909938a83dac2990a47ec95a3e3bef6f8d4f68b9316078f0dd1cdc185faa70bf7f44063e93ebead32b54e783220a3d26bd20e757abcc84a1314c85db96c3aa4b06e5e7da13c1d9b43b9d99af98b8737c4c2bb8fd9bae746c6b3038aa23c2d71b222ce35f116ba0d8b1f699c62368a37ad901cea014f52867f5ebe71c34cc410e0729c795ad831f62084c362841d34ec272b0ccab53b62588377cf6acc8152a1530326cb49d51647fa25f947d93cc2e1c2aab001b2036b23c813553046bdc041e35815e9aee50efbe3b10b1530d4843e232f0ab6f40297b0273a4b1acd1063e49cbe8e41b94e717de6bb4072653ca48f3a2e3dc4bcea78435a2d1583d418befb3fed613f846963d67c1a81e4deeae5c6ccd38ba0fc4e34bc2636d9975481f23c09a391ed0939873b9444f3cb4770fee3d601c5135d30d598e60550855bf7c701b3d0682f84848b38e3735fb2a5fc91d313c7e994409fce9cfedbcf5fe02e9e98df80f250d13001c69b9e8736b74867ee63879cb41e4173bfcf77a6c903f841dd8f7afdd33dc3296d8fe8df4110288d9c904772db3b3e9300833a93fad14c8e6560eac0d1b0a14d3c1c499002a3b3af76cfc20a0a8b4f8ef2173039d3cbfc817286b8b234864d16a1e92cb6ab88401101d57a6b7afb47fe86e92ad9a043c0ab009e7bffff8011412bb6ee2f65fd037d374ef21bb67fa89a50d42782ec5c43824fc17a25f55d06cc2115cd619af51ab7c0a43ecb6c275ef040c1c8e159e12528cc9d09c1e7d57e21dc1225ef486d2e30fe7e84a22b31803a4eb2194abc5392a266fb8e527fb9b7b0fb6d4fc3e3205522a35a1f04bd0d26b714bbc87b6e8b7b80ba5f5c9b53b787bf254d325fcf3c21ce71020e90157d79bd08c4f4e4f0f8547c4e01149100b78370c223e3c54d073c8d61644ecc8bddaad280aae418a55788be20efaff1873819f1ef5602e03119723a6ce37d30247277bf052f914d0f78303b3e1f3f84bf55614c33040030e134aa3e89577ad350afa537d69d36cc33bc8725aa598cf22aa76c3d46f0f7b4804df8750d9d97f7cf7eac78ba6a486ce3d05307ab3a6b94629b101cc0e1307fae7ad8d9d78d0d7c9052692521f0fd14af7ae8e85b09d7524ea49f6b612e5db43e7dd3565b4f1974cb39e0468b14d7c8c595418cfe74357f18ddd2a78b4167083c654ee0fc494c4870bac34de3d3804c07d417e51a15d0eb5e8329e3a4266cf15af21cef5940029191d15a417922c6a674f0409707dd1a5e7893beaaff50834e924b7a7958de0474c69d7cf19f282c29e60a404bea762dbc21b7ede50895ca34dce787002e0fe5c24ed286d6d5fcf6962d237a47ace3fe6b0dd2e3c60fff477ca6e339ccfd589d565f62a39dbb0f14e60a2830d3f194ae758db564cced25af0cfb0291a84e9cf4929a1f49f466330ea6ea126bb4c4a1a62bf0ec16e274ec931ed61360a340a9463ce18cbf20044bbe879ee321cf423e97987540eb91febadac2ea3821cc08cab07412e8ea3c075900600490b3e8c0419019a18d5d27dcda5a867adb6346577e313697f3257870c929a782c20c739bee16d3482ca0b6db524315ec0f8d2df33e34912265831c0abeb68ce04c71554d2ea74c09f562de2abdd8b12ab124fa65753be6753d7177387a69fdcdad4c8ce6351468bf2487e88afd9f860426f0451f6c12d47622941611e239a6986eef379a291535f60405d4bd7778fbfb4c5bc7d5ef79f618d9019d279345dad579db34e18d76c843d9360b3525d1dbe23e147f3ff3eba0854ebf0a6f693a09da58167edb909387c11c76c826d54966669aaf2d972a27428eb43c524a2889a8a9a0a5854efcb18180ff644bc07321c1a85b89915b93039c1f933db544ef7c43e7ea78b706597cb473a5d2818df0ef9ffb6c941b8f95b245e6b4180f2a6d979e69e3dcf5a3dce0052eee1b0a69ea6e276bc61e997b32faf379a35ac39aac14086cf8cb55976b874732e9c7ae0aaea37d74545d73559014b3fba07672f4578571407d618ca1174bf3cf31834342ad1b33820e8cd9e81e03a6318cc96c5edd1c2d969f95ebc3b8b440d8e957901e2dbe63cb2b591f2ec789ea96c294220e5802e624d396cc4818f959879d45f4796902de82130354eaf23faa7bcd3073e98f4944021e09abe61ebdedb3e93ed15f708f0029ec5c57a73a6ae0a519c2399c5d3250635f6e0c6ecc7c04e57b77c376a83cc77b1e063322d877ad96847e79562362b72dbaac01c7db490bb04be452a7023a45355608459ad7d91434934a0e5d3f5570b4c546229969307422033701fb85eecc05b04a246faec19d095fd82c34bd11ac19cd2b9dc7e941d755cc4896e0b51c317ae6468badd06a27a96efb7a417aa5f41059dbc6bcdb999d83164a796b79799934c60cfb9384323d8b6e379c9124f8a17f2668d1da28ee54c1a6f3abafe56d5c62956eed053336617c769d326454b9ab23ae1d362638ac317771ae526ae90f704c0390012842e8d3b81870b13a9c501d22ba718ffcade928ad75b89792667ea687918d96f734d349deae531cad89af4eb24fb7c476f814ddd4fa5e9bbdf6879f68fd1641e85a9645a0d3bbee8c787e7c6b2adea65a37f32c61bd72b799ad1f43d7c0e0cfee2ff05ea4fb71d6ea5250a3ac75e94e46b09d3adc8cc51282d2f7b85f40db1a74893935b60a059f68bed64fb86b1fc84d9c066872ef14913f51fb2fe6a51a18077aec3b2fd34258539d099224082637869d191c604c270b0fdf1248f6fc3001b24e9dda0b4b44bb39b1583b37b07d6c030fee32215b0a5d34264aab1eec02629f79906f81ebc52cd7de348eb96b0d58d8f2cc609e824be4a847c712b728521bf8698fe365b2b77c365d2db326e94260eeae3f6e6700390389bfd53ba0890cc0d5b055a6d6de0f8b52c057fa5a574c1922ae70ba9d7e47a7b768d4c1fbc2c10a204c85c8c2c0b8a4af0877c0e5e985f758977f64b203799b1957cea95f338ec9a94dc89cad58431b901df4879e8dac89e0a4ee81c26466414b22228efc6f161632be6d43f8ab32ecaecfb3ebc6664cadf95aaf9647423636f4fefad89ef9f3905f78f527ba9aa504e8e985aa68fd49d040a6be3c7f1ff15ce1ac6813e705c24ed34d73df8df2564828181ce69f52ebaaaab26dd9f9e1c300426c9d585ba341d4bd5770acbf044fcfbb943cf4e741e834ca71a75426d78b1348bad98b17266eb4cc6d200128bdd44e7573f018c38a2a48e25fab4d55f66c05901d00ea6499081a79a9d52b63573891b675753bfbb10b0eda7da46262e0586a9a57ce67b5507804f8ae420c167ee37bb20eaf350314c8bacf5a1f823b978aa47813720ebf51b110f15b018679246dffdb177ea2409127674c9951f9802a34f671d26b6f38d1e09b719da056f3e19b44d96f1c9174d52905504c68c95871f5c0565b41d480e46ac1b652cbdba16c05ac747424bab79de26ef11c585b52c6789a18b302e3a8cf06b807a8fa176e0b095d1fca1341e4be8ee96af60fb34ae8557e36239733d2710615c58efd114d17ff8d1cb4fdaf8fdca9f79ca6e1985f12fbee7bb0ad103da0a8f0cc7d93f635be7aee7ebfb5dd54c9d19f1af6780af01a61bae2758db27f0d40d919dca18cbef19fa8f5f90462170f8cb51b4e78e72f64fe5ec514434cb98a3974f4a5aaf482ddbd68e6f2d698fff5419e2893c92391e68f19cc98a465bef7b362e784894983937407866230348cca10171e854669a8c18f0e7b51278f03bbb388fa5f16b21ec3c61234987e9bf7a07754d68abbf09d72c6e112cb48349cd10b3ae680adc97e729801ec0caff249cf5315929299ca6b3a384fe1b405b01bbb58b1272af253886a076be6e2821f87531e5364b9cb1057f7ce355d0f3c10375d3e864d2d8e008cb0c5af0786e2ca0a7066e1f981a36d82bed9d19b9520bf1b01ea822e1c19290be215d601a0f8901eba7e56e08a70dc7a7289a009cd78a0e44654a28186602c38351c776a8fe43ab1563f6fe7daa264c3b4b0f2c28dd8af605cb062dfedeb57ad9fab731402ab038c6463ba7a2c29632ec2edcd07413d95ec218b85e9480436709c2e722c965aa2d4d87a112cbf4c3762ec560fd8166161f0d8a01d6dfaa8a4f9fd659fad4529fd3664340572dfb0946f5e5d7c3ef12bff588de692a798dd37a109743596dd375f90e757957d89c89ade7fc3edac16a1ed3552c64e4c337431b69a60a30715636aea7ff05e242220bc76bbe7f4238ddcd72328bfe926bd5bc35ff70b8c741f98fa0404209ce6900fc3e5ae496d9f2dae2ad94a15458d41d40332149676dc642442d912e34399734be962a2a7f9872f0a3a03058db7a0911e8de2ffc989d6469aa5a23cb95522240b5fa09de14599d3257c2b33cb7a506582b692a3059671a76ec166c9693a28d5b210aa252d95917353e3160161627c70a38c738e34d4f90ed13aeb03598f231b5138d93994b963006a0b4dfc3da4d531160581a3238624b6281a1397b4a1e8b0659af63cd1fba5a52fb6318620e052336e80d46de33f85ef5b67d144b986f987899c542a4bfd42c68cf6993ee180073f38184c955171a0b3097146d016ff27bde6d8fa3558d438f9c1b54f41445f24fc26f0902ca2092c7c2b36538363da10699cb3f0b02aa4fff9d03fa0e9afabbbf31013b16b6a2cf32873c02287a95b62a32f25492984c4436333dbeeb31562e375796cd70aafb911f4a996b1edbfba515514352d605722540ec9038efc6e884a17ff98806377d8f7e6e5250f507a911ac48d170223af6eaaed964ad3344ca7bcb6f5c1ad9a74fc18d145a9aeab2e80901cdcaa00c4570b9861c09795bff9661494c6631e47d799b7ae14435043d5df990d9a7ee9c7bb051d7a867e409084a4d813ac3fe0b0e307334759ded08a4e8e1f0e6d512bb6c6c94af97d166730dfa9e14d41185fa8b8d8453bd32fd20ebbfca2abe1edbe66fc4fd94cf29d1c44e44d83d647cb25748383c6a60cb156c29c2a0325d01d5ecc681c92a3c5425fe1baedea464a9a0372c5ca92179af16e18ba71b272092c38675f5dfb9a0f7c39e47cb30eb7a2fae187edf77f9e27f6501efc5afea86d9cfdd98002a356c13bca5b4cbe37a7bf99e0039a7558c5ec778b6c9fedbdf8ac71187e41fc6a08f9f3323827463f67ecc2020781cfdb3ffceaabe343c2d4548034e80644db5bf92e5015878d3df0aaa7c118e75bdd05eae0cd546cd16874757988c3051785cec3c0dbe7e628487cd82ab14793a7af664bb8bf73cbced08975c57cdfc3f16df670c9bc66426c6c627ac2850be01539ecf04c6534aeef22a4da8383bdebd7285cb36e3efad41fce9ab8ccc665b9e33f74612110129f9abf93f9b332b9396695d586f715a48190810f97405c655e3f0d10cb45e0de7e5375f15ae8a37bfc77b420bb1b91c53cffdbea5e02c489a37bf0d1327c43d765d138cd124b968106534c3c8ceba4d59fd3d3f6e71058248bc3becf75fca7d8dd10ed576830d0880fde9117a5947e21c17fa8aac196fd587ed5cde8b81e05cf72f530cf528da739fae116d749a007aa61b08b3d9d009fd4b087e49bc803c909cddae2838d8318f8b0b8c9256a0d7dfb35492f5adebb2524d6c1c51cf0ddc8663020c8d27a3e77e720346d746fd4f10f5330efa587748bac42bc9d6b23c06b3b6641c40a7eaafcfa4ef541700671f21900b5b24e3d1ea8d5d98c4684a6ec0659b7723d2f6cef88bf4c6d53c38745a51ec32b8774bc35a657c0d7fde0636b9cd805df38945d06a2f9d1310423c16fe665cd4e188e7a748823412690a500e5be1f5abd86756b69f5eb4a186d7f2199e351533da58fbb3874a687fdd762959cfb6b3974d60718f097b8077c329e7a06b3287c3f015fbd35c96a63c6402da85c8566a066fb0a4ca147fbf68b92cf5877a052f9a8117849ad5c2c35195998aad929fc414adc932ab689068690f34d092211d94793c13a33b21d80631b7d37f076781447bda4d6f3db057fcd5616f1b97457dbf3257fb617c5b54ca8a6e47a6c0420e558d6a7422c34acb04765ffbbadb44d405453e3e3170bebfb64dd32e2ed84e849ad62532d223aeebc2d738bdc024c82303cf04e9fa358190a954e1661661ca2471bc00b473f2ac26758dfeddc885067089b9e94df9146c9d01916e40fe488a7bba7979e2fa068cc5b46d4a2cbe60363be0dc4d2701187011d1ec16b6f2a61f5e41659692e655fac49c99c6f239d65082b3badbac01f3b1f8b8723a24f7ebd92d4de575771ceb29c8f04b6a4353b55c71e095e5017aa9bc9c5988c275925e59c531330db843b0e6941c285abedf883605723c92f08a1f8784422ad22b324c03a06b65603ff12c3cef3ab7655691a4fe5f9dfa556111cc63a681376f70ea8ecd8b0e9d720f728e12861986dd88dce722c2e18a3a5cc084be13ed8e8e0bd96cbc70c5f084bbb97dc6d0db46e78e8e2cd88e3244664574fe0fc0bc308855bafb900662b187d1c299a07c8d1f15d29678fe3c218f28e737a0e85b4db4ae60e109f1dd6983c767ef7cae6974e2afc25727697199a12b967ce02ddef764ceba6afdbdbae4442cc1f2bc2866c7054ffa4eb54c97368666626d33f481e6fede2164f930b7a2642e7e0e7bf025f8441a09b53d77291f7f78d05cb92d39f5844d65aa962621df4c3d43d525c705089e997d23866e3a6b148ac5dce1caa6231f797979c8013d3f7fe094583f601cddf250ab6c5ff64068bc2e6de185618ae1c8d8876d3a227bed49d183a223126346aebd220f7f2a47196968ea19bcc997f2eada434c4dcade8bb59b08e972e4e5e00c11a17a2318f654fdd0437e2bdad5a72ed6c0315154fccaee24592eac36ec00064e7830c3f26460f59683b397a56954105edf99024df67230ec5d71f62321255260c29da32cda77ac82ed30f8ae1b43b0133082019cd647a9dfa66463f01d8990bc9ef3f75efb0943de0b9e927f9c99913936435b6928ef67539d9eccdd5150f6bf9e3f88e604cda88735bd0394c79d6513cd2c54a2a1c0ed4ddfca732402d09f235a257e5d6dfb672eb5f1a278571ea7c0dd86d6d472f602a6e0e70fda5ad2ef8b25bd8accee30759f40d40c10396b6afb6b5705241e8a3aa7769595bec491e6c0b27beefe927a851c33ae5883a431783d7812764568e937e5eb0dbfd9eb5a235059be7041a97a2b4daaf9130283d818a833d154343e34b05362bf6ea1f70cd7ee5d9f24c7e1ba2fc8a61c115f9c4e2c2dc343541d7ad08091c881a7c9d74087215087a9b70c3cc0d54454e3275ae60edcb9351e5805ae58d1309e37297f8fe876efeed37747b71579fc8a4b9db4081f2943c952d960cf4eb4b64e79d02eacfcb9bcb5811bb442adf5068d6b97ffb0e2e128a18b676ae81b386e152ff06d17b8c2da4a185148111b67ee29fba7a5de5b37663129aa5520178ee44e0e7f0bc3b85420f944366293ef788c4e114dd9cb3f2e110de4c8f430469cae785b1d44ef36463b9e12088671579fbfa3fa949d6042e8da9bf76a8e31cedb3012d134cd94394a788da25cfbaea525c19a690ed30bc660219f0fb72aaf48b0530d673b2902d5bc078a00ee2b462901a0bf47cf84c7210ec87a1280eb49ee29a322ffab1bfed6d5db09905fb61cec0683ec413566cb8696d757491cece0b1526ea548a015eb4ce08183775cb1ee0375c63aedbb7c36fe380384ba3c5fbc4f02666ad6005039cb25243511288aa12f323a88eb6f255a11c0533858f0cd235d6d58e65025808315524bf80de526b79d9c5ac3f558d1ee18aedad19858a3cbf0b5d325f641d357131905d50899995ad4daed9d0ac98d072fbf944016ade9701531770dceadad495aebfc54657cc9e0ca62a118681b44aba4e0fa3721323cdc5ac39c29e2595b6d3e0ce35d537413f1a17f993cd6c869a93e50ff8efba75873516fa3a80450635b23d713d71ba79e11cb2e7d75b8cd76df12a45d98597f17c2a88fdeb1deff4a275ac37b1d77c8e3feb86b41458bd34b6ebb65371dd45e230b692cb2501e3af6e6b43eb797e6999496d4c005967b2348f283c1969cd44f56bf1242d9872db3a332443009a5da14f4f667c721edc199458ac23dba5f345245840b2363fe29d52fb179786cef0c8de7afa0003e682fae14e9c673e1657cfd321e90981c825c29a8fae186a9fdd422df78b4ecffbde3dc422425daf40e9fc358b8ca4fee9f7d1730b64214e0991087d3d0ed6541998d640447b3235500383a24321f18585a4dcde1486ad6023368fc01eca8970985805338795fabea441674f9c7e4f9c3f7ed413cbe295556dc90f349838fcc3e488669c85df6e43adbc710f0fa8be76f436021ef2693f331a27a3195ed319569eb3771630316b4d39fb783ea7c6c58e4d00fb2a086a047408fdce52e1ec8847493945d9dcf67c12fae4c9522d0b257bda6b723670118c7689838650fd9d03a4b225466cc6f349247f5a9ac93b4c0181242eaf7bb7fa1778b5d8537faff77995281d3c10bc533b5901de03043b066d276252329a77b2e4856f2055ce9129a96fe9ab6f19153dde50608d2c1e5a836822cd3c0b302256b6386b99b3ad17a17249c5db571024a7f8fd05363ea550c29514f2457f1f1849c982dca187c1415cb75d93811587603444e8ea85b62cd712bacccddb9b9edc45f705416e820c8ffef4ab84e179bf05c37023d2d6f64a4f1e032cb8b7a928222b99372cffb70a13024bfb0e5619c27f47c504b445ce040a0055f7121b8542038b5c7d0b0b305c1bc4f662249318615b05fd04538cff4e5afef4456dcd08ea8cc54661a82800bc5e4f3cdece30a3164e144fac557c866121136232495b7d4c7479a062e44077d7ebac11946f4bfdc5cbf2f8b1f7c883fe478bb2ee2c6792004a32838f7738542a38f653ee8bc9505967dc4416f80c527decf5ad75228a5c9b8d0642ff1b1ca8e3ab70d1523438a0e8adbb312a2aeef771805e9fe2158badece6abbef7c259762b8a7bfd7a05bffac6e54a0fea52900f43e8ba0f3381e5fa5a16210d7b3b36718a907e6e6ceb01a793ee46b2b5ae2de0023f7f2e65c85b8bbd6210a91ec92ad160ca9992be2a0332f2f422daa2bbca865a7445d97e74f0f6a48e0da7eb1291cf389c28f604a4f47fc02bf7ad6a0d862ace22d706962b89ad59058ba4d92c3e32ae21a2c1311b854870423996697f91fc3be5c2b8c4fbc7c77873c4dcb501918041ed7fc693aac766f0b9735cae88dfc69ed26bee89d2c6622270b1fa19deb1ef33eea4aef2918fef664b2510a48d8eb2c98fda2ec68a4508fe5dea4b3a9f69cf400d42b934ddeb361b2d1f99441fb3bbd8ca67574df68be0e50127e7ed7256302e500a0a0320fb67d2e691d048a99913455765576beeb63acffe87c622a85c9b5d1421080ead927518b4953d637f216c6c44f9e20b55f344223df293e08ce0f01afd32751f1e6fc994a4f3f860109a6491028dad8e9991f29c7c610a491dace032dd133b74b2fb6e231b58143a778f6656f5577cf92957b6011d7b9e77a46574f96355d7467f282e963c627a35088c78c2cd8caa95fc1ed3b8fbda2dc6f14933ac54ff4245714dfb50b444c694880bae26017ec82c724ca644d21371680d7497c315bc908a417ce552757c3aeb02ab0aaa7236eef63b0d044246e18679dbda1a1fb2d5194b08c0bc608bd1cc9591da1029cfdab70e67c3be2dd4bb290fe82b6105847ac5825705feacd40bb1ec71ee5e50bc4270375853f505db735666cbc3732a881e562dde4cf59afbbf113272d5711c1b7df2cb30eca1ad4adc993f3fe07ac44244ff21690c1e6d74e432a17c2314c13e682d3f5cd769e31bb0c162745d1e7e60e4479c0e682bc2fe31e8658c99e4a149a20bb9e89ab97fdd5d74fd9423aec590e45bd9c13849ed77147f5b56f3ff770048f945f9a9446d570c8284d695d7bca1afb068ad848f6670aa78fe3e21b658c0b66b12905fcf8a8a98c76a46dba520cc25b9db11cd7b1652183d967638fb9d10a867af282b29632f7df53fe1255fe2d84c55259f917332fbbd046b70abec0fcc6d46a0e866b3c7077cd651aa764ca26f29dadf7caa635efd13ea0d1c1393ecd7205febaa2d3b319b57f46d7d72f3066cf2f07d8b8719aa1e2276f07c468a4ab86da0f5ee0cfbb6a6804f078ba33ac5f9153eacd50f6e73a2f845570487749b8ad6c53d6ebbf676645fc83080679a3841a891bf49ea2283987081d696752d53092321948ca4ca89257d9d31318a9b75401e394fd8bb134290dcee6a4cc46f96120ee1005257fc316cd2494a5ff25d7b0351bf44baa6157fb6a03d7e25227edfa71ba71edb83b8b4969daf855f691a30e4f353b134c2326b0e097637e8164fc3bfac81b6218745d8921b037f738ff509cfcd206cd4869823860e1e9c19de415ae95dd7aa7fdd786f6c8d52e70d60e4b30380b7c368ef4d43f428bc89ecd118b4d263cf70072b9432c91cf91ea6a6b1fe2f9e42c3f9327381fba15c5b7e462e8f3b00dd700e7448d5c0dc4934b028f15f87a8ff9a76b367a44d09e0b1bf5f2fd8f4f98bc6aab42ab04afaf16875758c49e984562419f1ac269d540de8bc975a7166ccea69cb4478a786e3b6f32129f4ad5d6ed57cb260eefc3fcc8c6436b946c1baa5be795debe7004a4716daff4d60f4f798c791e50e8c5dd22e9e6f9f603d8478de6567b0663d23bfe93ee69089ea2a6a1061357dbd6445880d4ad71d68d36b15bbb6f731d5756ea95d307ceb3825bc0c0f86e098a3b33039e5a5771bd00bf36a340c564123ba3be59a137da44adad0bebb71111d2c20dee21384bc7e0062edc41ba1af43d2f6befb39deafa2d6db5e52a5b933baebb54d3e7a33c2e7a09b2d3c5758e8c943163a1a263542f1e7ee949656ae79690089866d851fbf36c4a25d9da0834055dc48ec13f6541bd7a57042352cf696e30de7f026b2cff68b1af9875cc7027584ea04b9df1e60f1874ea520417b928adbc45b7279acc08eebe95eda8c19e532a86781fc971cab72cd1e0e3d22af8fba8d4498fab7920ebdeecf972f80402f27f61fd6fd2d6ac358515dcebf0c7c210952ffd139957ff9b92dfe6e47e5375744236cd4cbb79588aa566e7d4e01cfc71143767e89e323bfb0a36765cb98e074fcc4fa3b31177f725fb77abb26d3c60172f08e2868c1f0cd0072498c045ad2f24d25b47291d0ee7fd314bfb641b00115e507395f284b1c5e10f9ac10f57cf14f8e96b6d9c30d4aef488f63c9f6313940b35a3c774f2a85b158b6754e2a817ee7563edc2096d5d1399cf6fcad42d538c9ce3ed666df86bf4a8edd35d35f09b71e1ec6ab774f48b4a8f97c8637528636b6caba18c959d3172dcf3fa1113378c8d94dfeb3165873ad85623955bc694e0e2d120b1955e72f5f62d2acb40404461fc0697e4df26f1ff1c46a035a50fd581459ffbd7a42400ee4d0a38e4778dd18bf80a8531e158193cc911298298b03ff261a8a19d6c15d72c4a18cecd7cebfec1e345d4971562590c597938bd279ad6b107f662d6e5d5b28d535198359951f030382fa07c1e7ff09a5a09df207db1dc37a5ec8b930b50eaff748d116a9a2d0d40fe91913d2bbdc21449622fdb4e7df45b9d7c662d5bfa5d5b0ee78369c38b29da9698e99df071f36066d4ee8c447ada4d8799cf60690e3740be48d8f900f62f20e783d40b7ef8443b2b44fb0d925f9238679592909586ac4142420009c3cf50da928e0c016124012333d841e0fb7ba1fb8aa0d2ff34e3ac8145e10b99ea36bf50f66e7ee64e26e89422a3f7b7754300a3f05cb3711f1c9ba83a190f6cfb9cfa489289d7943f83873fc4e2eb93ec605dd4245afadccd35ac5e2e797a9efeb76911f7789fda66a77b3629deb43c31ba76a175e6b78c43f0f9f1ca225068695616a7761b3e1167710fe19a5141c34f114d0d6aaa2361c383a6c291513c09759ca24b8010295e160fc97305daf25247d2d034c9ef37b34da4a0089cb25037bae7e693913860a79936e6663b9caca20611efccbdec8d7ecca5c831e7ebd7078aa1cf7aa1911d382ce04588713cd26774873ef7a1770871c671e868fab9cf64d6a4a47945af4f706172399f6f58f46d4324ad25b5543109007a88fec244d4c3c4bb74de8b4aaf5c3457d3acb2c1229d5704dc170ce434b44d8e3d1b6379136050a8ea676c1dafaa4df971434de508da3491200a97a12d2307f0f5ba060dcae39ee23d8719172d0c54b8d73a38d21ecd76b20bc24d2575ffca355361d60102ddcefbde0ef5d35005c54579982cbefe0ba2b681bf395528e45b4c39f1d6a384f84c1901a3c766426446f6bb0ab12c8e0c7742686f78f192c7d2266e8b748592d9f84fcd7181693403f5a0eff3eff56fd813b577eec3d9c0f567b8cac1627467d613c97e008459ffb9fda21eb9db8111d6e43b9d81e2a7df6523fcc179639e78b5c2b1ff1259fc5b31ba21502e6db1a2956f9a070714fb0e02539f403054345908dcf09ca7daa665161dcf4e81eea34c4063270bf8a601826f29ec4b00da12517765fe9ec9f73d570d421971470230fc5ad7da67712295393f3f6c9694d5057426da5ccd8915a7b9c0ff5d8ed70219d6345c2b8ab437953387025ea6f2d562c84c8eba4ae57ef22a00ba9268d09463d84e11fce2445d412a3204bf31713e9378261779ad0a617f35adbdbf56ebd37cd0382bdd777a698da9b10f654462d9defe58422188db877df2e955ca464ab149c3878622e5ea5e39b42d83703b2da489c1a11fe6dc081b35ba5fb9816f88085bc6427070dc2a1cec5325419992af2846ca9d16a6e14b343a709abb0f2739e692b661c36212ac4eea33929ba4401f060e7cdace6cfc2be2101f3bb73ebe317798600e4ebbb11e884a6ddca81f6f6cd34561f034d92beaf9b29480d082dac969a36eee63e114e6238fc314cae9de43737f00f1d8cfc765dba4fbcbe4a7b1f974c335b5886e98561bdd4b9c4bfd50aeb71fb6965444dbdbbbe66c064092881e5c30eb1d198dc59f0ec53615a5a122b6068f8926d6abb9bb53d0c6c4186f9910ca3f582b5615682c695bfff334394dda5e9a5e0eae3f26c2366b480b0aefe60e858f911e8130878944cef1458917cf27c7fa91c86c59a911eeb651664c366bb1ed9b9b2b3e33a9cc50370321922a95df452c69a553bb908be5e7e90f6801217b85180ee0981e8502739a1d97d29ddad5f4a4514b9d8596e43fd421329648ced02c64a61336f5bae64380d6148ab60fe7caa229704a87bf8d4a3f43d3efc444765db745000fca4c850cecf58942dbe42c28175a5ed95be8410d65a8a92b27bed754ad56db3e84b43bb13757c02c82a2adde0f511fa083c170240a530858296da220e9efb27ef34337c7f27294abf098eb8011fa7d887ad55cdf14bc690988607161634aae1121713895e94eee171095d15d6b2a26a4dcc8a54346d974295fc5eb928e42065a071121445fdd35483cca0741f48947e4615d8c53867e3da54cbf3b9763c6917b505d226c8fb32781b57bf277a51cc2a6b65da1c6ae3ca9e32069affceab5b60e57c1f7ab435807a63cd0660ae90f1b4a0436f3d52c8af58fc7f487c638e1fc45ad265f9e563e9168dcd646e59d86026c2ff38a4bb1d52e51b37d5b740320b22cd83eb156625b50bcad06bab155805e95054df15a88f1215b020db2b10f51dea6703d770eced2e34e342b1f96f3f5fb4c38e1b19550a487c0d08ef0ff9907530e4873a1277e5de23bf14908b96fc1b1f1034270b93fc3046fdd5310ac5a1eb69a21a58b4c8fe667f6d781dd4dc9629f1fb7ceba1b0e600b94b9c7d1ceb764db1506c8ff04cfca99e60fc459f36652d34f2e1f52f1665ab37d2297f01f7bf4ed73f7e0a6f863b3dfef6f41d25034fd56215eb05d3474136eec362d0558bb457cff072a10412b0d42ef5ed7d9f9f63eed3e9887319e62fc1262c33819fcd46969d2edb024d0358f723c73dc475676802c1535a321ede790a9159c68c650932773dc55c6ebefdb7bd3988c60d6cfa967764279bb0ee4f367492e57b157338e596b381c4a89c7dd0b892d3f8186c211bdf4c6956c6e06fc131663aa95586d2c1e928534e98a6afc862f3a650401a5407c9a1c4c846f2e380fda34fa1b6cf819c693d750e813a2c7b400e51a8179040483a0f390f34a50204b6902ecf43746e18603052514c0151013c064cfeabcb5e0fa754eb5fecaade34421d72d963bdbc9a0b495f499dd0b504b666225cac6869b627f7a5a2c40858b3d2d6cca82ebcc21d8edf9193833fdd0b6cbee3e93bee8bd147efc8a16b3c74a4193bdb03467bcef076328057d3ce715ffdaf32aa041f9eb217ed351ccf177518820b480567db3b789689aa2345bf9ead5f28e8fa422452f89ebcf64e22a00c8f1a7a1445d6f6ca37a49abf627e23f32dd08a4801e1e0e698889d65a9b86c2f92b04c7e98b9f8c4ae83a0e711ae0aa9cc0584e3ed8fae8e8c906c6ca5ee333b0254db39dbf2f74cab75bfca34110a8cc50cc8979d7291155e568710dda5490a1301a87b6a93ba72593d47ee25d398cc3641f96c4415f99aa959046cfc94e088b7c92f8fdd1ae316ba7b066bb1cbf469c6c0a912334f1d8aa8ee6e50d316c5fce17bb796f2328d1763bf46db9dfd3c8b2f66c69c5fb831bd5cf39a383a43ccb94dc081a6c8a9514ab59b3d1eda030c9710daf0677760094d588fa4f4ca84231e3e1cb1cfe1156ec3df3f0edcecab736c62b001f562290fd45587be2c3f40912eec416cd3bcfab9164dcff3ec200cfc0cdd8b0eda702d452c8639255a3728c579ad272faa00da4c7eed84f67d5e86b3ce63efa5837b36cc3d57d96e4c927f82b4864b35a65a877627babdd14ba2055f631fcb46e86e0ea38aaf928e9b503ca057edb14b31b73c30a841f22f31c09991aefcb437da2a2cd409d6adb3c43382406bea6afb3b7f25c42b4eae73d9e694ee1ea8ce3e71c229b5df41107d18982af9c2953a74eb2d48006e4a2475cb1dd9ab9579ebe7dbdf20756e1ee08ecc4b4426242b4c62ffb371fb4dd788a63974faa66e78dfce9d939409e23df60c637462428ecb595dfb058cc58c2d57ad917507d8fa0212808b4d6ffeab3cc37bde9db17e871699b21227afb282d285fe3b4a34cfe36872f43c6944e7c44106a2d8a63d970a497443b27d01ce7f0b54bef2177cf7fdc19d937b470f8193ee1a63de0100bcb4c7c7a2d0e6f6829653d2a5e0385133dd66edee5d54bc5c1fb8f507bbb579b0ee62967972c0e4046790c447898ffcefcfe1d08418dd2cf2f37c8c0afcab4bcb465736328990774499f5e4798fccb97ce3152e9299995398a44be2826a738744bd54085c1263135b0ae6a8a837614cb8226695e4cce3b36025c281cbb9a6f289100bc67b90f0703e9248b94519194189ff8425df06fa623943e27feaaa688464e72a41896aa93739389ed477ada4d6b24bfeabe371eaeab2ef191c299d6979cdb5f48eb3ff8a4496cb6ffac179e151eea8aac00d6d4789e4b4f9f9f2058064ff88c69faa62fde92343c3627acbe341112581c49ac52516a85d1c87a2044314fc23c6b5242030753ae5ed0c3a5c450a7086ec020cb11198cd35531a82bccc765e7db93b67becef45a3db3ebeb5b71fb927891e3688a6a21b2e02b1697c52a15cede5bbcebb5c1f002e5e0eb419f51063065d8fad5fc235cfd11188104c857df587d006fe1bbead397cec5aa8e1a5fddabc1efa0fb5a5070ba529e3045d1983fb764b866dd250e05d8c746ffe04534531263587ca11318d3e078fb2578c145dac8449f376236fbccbcb32784080fc71d4b43a48073e7a54559d548678d605acde017f0ffb3027bdd3a66aad4add9cc0f55e2365cccfe8faf3e0a5326f1d56a39ba8d6ec80cbd001bf033c0792c24365b7b8e381e197d463fec2789e0863614c8a20dcc06fc9bacb0a83948dfed9d0226a3dfe5f2ec93ad79e312a0b6d0ea52cbb8b74086cc3447651ddf362850f1d3c6940b89f92eb4342bf30a01b8a124c3704b6da06ef8fc37c325b385b266381548bd8b6ed301a07f2f5be86681209885cf6f1ed33ae925909f30935231f95ffe828b65b73e6d24536b919a6b6e11e37051cb7f0e244a12f8e6c028a07194461b2c47f851e9b7a3dac12e19a6839abb89b4b4477507b780c4ba7fb93f62083f81e673904c1baf4b1498c4e4d1c46f9be987f2dd151057741f015af2376fc5be8583c9c9fc02773281d971110bda04cf3c09c70d45d6bcc5d22330e219f8e311cc449a94d1d6e48c36d3e4af2c35e06d4452a75c87fde0496e1dab79c9e1ed1272b40b384d0bc528d0d35a3c6d41d35ffd645a6ed1aa157abeaf646313e50060438dc4445cc4f0a9628ef8235ab389bf458e13666135a7b219e272617aca7b159db1222bea58b67c377f57e1e096537003517849192b0925034cc7e4df4966c16a125db62fe565e8123365be73683c7df5887e85b2411d5ace752ebfb8e92da04d66572a378ab1c80e99aa46a84d38c790e23555fea9a3474bf561af57d516f42402d0b95a11935547a1ec373b9e9f84ef85724f7893c8749df6ffac140b6ea1be1fdaa1c4c44dd7b797cc1aac1d1906ed4f7300ffcc45abafd2d458342a296556d57e6cb4e556171d6d4ace235b79f7ea1decda3efa6f90726131af8a58a46e869cecd0380066181c1a29ce130e14bcdd53e90fb647e877cd59d2320ab6827aaa22a74d82378ac56d6fcb7c5aae678a8a76c086b3ab789eba84a5438d989175ab26276a47e7c403fff7fcdf13efad60fcda952cc70911e92c5eda2bdea2931d3915b1aa6e4efb954964147c768d0aba364e817f7ba5aa1e361c7ad9acf57d19b107aa840f578ea8f9c301bf8ffdd4b61f72a2245639a86e4b561d09d8727afa9fbabf6cc894bd9fb9a505362e9fa2353f933b54f617eb3942ab874f3caee1bf384ef27c0731507d4662302d62b709c484ea52e93186d68d5ec3dac68d9ba426a9270a66b17ea72f3ef7a7f01ff1efbc895323db04e8a8fc0d8337905031ef6b4a670f36fe458f1e76c7f7fdffa545c40e72f9268b4e6c47142259ff6fb3240afc1a111d89026ffe69e413fcac02d091a28eee5e551103e4d9269b6741723976a7a85ed0faf7e8e71e58d0eb715242412db070983fd6e132f3cde988abcfc81458b15bbac71bd857f18076352d0d81adeffcd47cc9555dcebadb2eb9ec1965a4e904d126cd7ae6d03f849197b40bddb25ad978b31e5f575c2d4c8990577274bfe7bd6f276cfff7ea626547c6a78567aa089a8b86372f8b68bded78588238bde66498b8459b0595e436032acd3a154aad6bba3be1949659ae52b8308e61022248363b837aae10db16900124f1572555ceb7a0e9fe243ea99077c199801f95047e1d6fc0bfe974a679e7ffdbf42554e832fa6fc3ee2d056648494f153a287c080552e0c54cd32ab4bd490fb5c49b27aa77f39376fa10c1497386332a2826b57c8d83b3b5c091a8788e385c754b57699df319ddef83fb445ef2a0ddcb5de25a05016da70878359e828fdd2d0a6a5dda910786fce698c70ee7cb8cfc9ff4690bd96737c8989db60d435264ea1688935504ae2c9da3b2d1c4274c613616eb29191b84db81699560f9a15ab35f6006da69dcc85620861424046963b26eaa17e407a06834f113e63047bf585ee7cb8bf644d0ebf57a462290600a5357e60764f8c5dead06222618f2f070fcb9ba7ee9f443d9d4559b200362fd57905a3c0ce25f4b0c204a31529d41c3653acf53f2b927311eb06a1d1740bc62160f33830f83b01522a362d162740f73f7f6d272cf9405abce8fbcfb8d8ab1436b171ddad0894f57d5de9f2637f2fcdbe68aa107d9339e0e6075bee93cd1ebbdfe90318142bc3a72932dcf08c9de89c7e483ada9dbd747453028c8f7c0b8e6865c4d1cc45bae887b1071c7fc7489415befbe1e525b5e01b775cc2d5696f946fde9c3a101a002132b97efe78fd9185dec1d1d8decd6992a8fd16958d5f290dd75c8e39b5f0b092b96090ebf364c0a21b4ded45795d8317edb21898113d29893d43b51823b4196bc7efde314c928503ee228f1595a5ba5bea499ff702dbe0d2dc2b7c0ad7082a29f12384703206d1f9e4d0d1cedc6fc4d0d6c85e9564cdd39c3758311041d6165f19854257e67e143fdd361da8a2fd6004b9a0620d902415c6e85ce90316c3c735d2db4850534eb18e89e043d319f7d93f0f45c34aabba34a8b2e25ccf08887b36aaaa86aed28c0242925006285a172dd52c699582903996c0610c4fa94e3efc65b668b6b9891f60179db9848686500cab866e88ef980f78d21d4aef003c0e0334a3943b027dc4d2b7bbb2a6feca97e0a6c1ea6f8c41c03e1631b65887c867b7faedf127049f6e95bdbb502217c6c1cf6c5e000bd2e818549f43f2c5603a158d50f2fe4e5480864d5233ed75f945d297b8c9307b944fd0d5078c9ccbdbb9d947508b28af064b9e2e0edf6dac7f1718c5026e828b231d839ee2d301f516a87d7ead73f9cc5ebcfb1ec7a7c90534ce3ce4cb4f63609e9a202fa8c720831967ca8c60f6cee3346fd951083cd2da30a211923a4c4c8ede53b1b33199bae3f024f2f0c97284d062d0a8d3b2414b4557b507845a0dba5d5deef1105203bcf28d2090591f0c472fd4abc6b77b9b36b1021bf4cc1e947021f2893146c25633cae460395c261e1cae6a01b98876921012b5db3112e19e44952733dc492a1b3d6bec472a3c358ae4dc0aacc8c401e25b0dd677e3416244f7f6c83696793262e452cabd1bbcadb6847d20d463061820e196e36b976da67aa560b34931fd2078e8995ff031fd7370736463e9bdcff4ceef84be0650abefc527e534a7a0f66ad6faf00e54618154c2fe7d3eea01265df2c226ac34ab7e3010b8f1f8daf699aa71d41a7e3a3160e1f71dc6a41e70f0f0cfd97f4f569b8241ef98dc2cc4c61cb3286e8b7caf79ad9d435172f1108007b4a1f2d2d98bc6902db3d17e24a5e00481bd3d7a15c4abfb50c5d68b9ca0429ab945d3403ed075c25b3e5011e0f89760ec0bfd7463c13ef8ac083f760d19791b15e7768a9c05edf8aa7436309cb0da07b5f57649b297fb5eb55e97c582fc2fd4c3e29fdebfe3f01a435bcd27be03e131c1af126ce608eca36c83c9e72815475c4d4f81882b0db4f4fa3de51d46fe64a42ff3733c55f2a515bb3ffbb159ca3b1def90bcb7c8fddda30e4632ee08717eddb728935c9b2becf09090045e6b7f1a6215748770adeb57fcd3651d088643c199215c8a4eb46b270fe54739ccf0804c5f9a224fe54a6025512b85e98a20a99db2f7b3a623bd82b359c9c38f7b32edc4088a06db716553f65176e1583cfb96dc05d684cce211c8d1343dc85dca0a1d4496f2231e65366c07fdae5ac0e65d86aa38bf0790db71e900193dba9288bdfea9f205b2122401ea6c556c09a2e0ddc9f04ae4a5f6d0d9d1cbff4405f0f484c557674ee5c337b8d6c045bcd11a6607acd919fec37a2d6ed31ac91bea68b17b78b30cc1d06426760b895c227b1de31a0bdfe29d2a4106af43ebe5f9792989bcba6c744298343b26e6d811a991dd821fb2fe7d55f7043a37637a1587efe444432efb33de725f41ecab5b99692ec83b2113cf4e6dfcc42023c3a85358b648a661a24b33399af1719643abd51930e19e4b537c30a46e65cd933382709de44b1c226b65d67f2ab82102f39a8e713a62ce3edb782848a19e60b452be3a9c9c8a7ec07aab44c0e20e30e893dbc6b3de8084413ed4094c6bb42225314a285f73985fc9948c9a6922ddd43ceb17da50e1dda2f374feb79ecb444fad874b1f6807450a13c136dc1d8b8a64413b7593831ee4cadc4742ff5d3bb0a051c3e7d0a84a8eb289c673f94b28e76d1bcd1675e35298cb83076b952c110923a7b92f3015e797fdf0a7db59cf1302e379e121461d307b9ae22610bc1cd1fbc6e7633135dcf4872e84dad0d791ec6af2028c7cac9bc24684961ade9f21ed3a14f45cb19b390c620cf09a16d706c8b394b37b0c6c39fa6b6e4d08e4523c95d35066f5122f3c1ba4e1f90b572a13745d1719dc0fa27b34a2352cd7c44c7ecc825116a655df34e453fa8288417b2ed3b148f9dfeeca14dba195e5566309361eab36b98dfa75d7c5a14ed4807af805318d76aeeb6ddaf558193f6e6c6a8eeb31012d49a6960c5b22b3e556999f597cca99f17977b54357431a1a3ee5338d2bf7ba273ce5a984a6deb8a04d450c45cc3c8a19138d582002b386131232d50e53fcf79a8ba1057d1555974c91b16b3a3c2c07969c4c9b39293ca0305afb393c371cdbaee870dd048982171c06be2b03108ce4c567db63338755ac8950be9616b3b5fa85eb9b7aaa1c85045373a667353a8a4f9dfeaebd820e45228624abf1fb80e381dfad18acc3c4ee10dc688007795f59968d79a5d0a70ac64965916e9b67953145b66a61de8637b442585186e3889d71da53823374bdc2e0da10e37b99f30d78cf92b67ebff5c835e7ac92cca972deb302410a00a63eac69a107fb05f45aab047873ec1250463c240b7723c973c8d280d244349bd68d4009f4e433e21aa14f558da9213323e5c7f68b988ff1368381c0eaab9f3e76d695291bcbc9aa4917b4e81166ab2b6b4c0075719b000d271b236bd289045812304eb05d6b87f99404204717ab25feb66ad1dec5a61c9ad50a1e9bad07fecf1205329f6362de715fce8b1a91e927d91ccc92e6a235fb9975491ec10c1ce03b1d5255d613e829973029ef7be886d8382843c3cc01354f8c75c30164206d64e0a98fa622067c7f3d3413874c35cd91117220cdd7523cc537b068b1bbf770b0f90dc5698bd6834caba0a40e97407dd9a269b3475d2346addde0f7c1c0c95665134e3db681e6fc323ade507b1a15c800bd708ebd481a3247e0048b122d9626bc553f4461aa71adb0a40c6c6f6133ec6dcc03e50e848db750eea14672dd08bef318d91dc3d186424eeceb6ffb6fe3541074334449e2478038abab402bb1177a57a8ae4a82a56343100758b32c9221a43c504c185b8071f3651783b6adfc93c9e51fb617f7f61d2c4165702b72baca6c4f11d59037059e17d7e0a29bc3fbd576ca28253cd03407407f4928f58a5286e036d7f624d3342af7b0b322d151663167df0385127756f7df96332529589704df3f3afc2833d102aa5b5810de543eff8b7b7b8a08a32468fd92eb4328fada1ff566f2a51a60bbd6349f51cd3d0e3899161515e7f5ae4c7777c167f46f4735f4f7526b1b8077d4382eb32f545a6a0940b191db7f078d59a51d38d921f9acc8699e6bdfc3ba897dd197bcbc59e14db302ab3f71c79839ff810a297ca277e7fea0d78b514f8a9ac3583242aa3298f54560d9df8480b5bf1ce6015ccc1905c69023f6ab9318b95a35701585e7b209959f789c709b9b09fb9d49467d817327bd277675dd72fee15418f9cfcb1d3438feccce6e472ee0ad8ce9b308012f74d44d96a6aa2a65ce425475312ab03f991aa2514c43b8773b83c88f8ef4fcfe4a272bef72fa4e42c41d9590f1b1cfdbe50ea26c7966d0e793100dcb12c639fcee370ff264d61fa752eaa1b245ac3c75cdce73a7a421b124d30ac9905cfe864880c321e8c55d59a4c022bacc418a73d054fccb34cf70d0faee70f3da9aeabd103c128c31fcda41ef6f018e60548743ef590cc058c9431f60faa7e5f5fffa7fbce2451c53454e3f80e0c5bc1a0b744249f2aaa3d29770fe169330b1e6aee758becf8cdbe804ac48341f8eff7804fefb8c09e756c2a7ab5719032d22b98d356f8d6282360103e883f253305dc7a23053625af0001b1004a2ecda372b8a98a1df02cde2dae592294e934694dd47aec0a5f6985a6b74b32ff817deca313f96a8cd89558576816fc115105ce9a1180e536f0a520767810d620e5222eddeb60bbde743f3b1359f7f28e83484776e33f0e339b46d479928d717bf2b7276c85304d068c77d9e74b25557b4ae847379269f36faa592cdf527b63e4a4fae23f956ac2e08c66205946041fde681b79aebfe1dd205fd5b7abd7fbcb9c235ec51ce8df9d1c0a328e5956dbd889b30fbd35331860f288b0efd17cc276f13d5765213a5b881a9b7645a7c0622918f3a4e94c7b8e95340721ef4f004e5018b86278454802bb61dff67d842341be7961cfff6cbfb6aab78fe412674a6273752fab4a40afe788c5ac3f946a4f061639f53190910fd10548622f204482472377ebf3a7875296be8460c99b4a7c21ddb71bf029da9680b07c3b53201d77504ce09621c16ed604df871d2998324627669dea5f9d7bd43705d1e852a7ad34dc85d588e663ca6179d420434715c65d8fe176570b5ecbd94009ef5f4e78f90629764bb3317ff05ceaf8ba13a9900a5bc63684f391193e51f04b8406dd7d6c9a0311598e854c617a451f3783b0d0878ceef14a332bf78a2998536a8a7f284c32963eb2bd1fb7e2aeb4dbe6fdfc138418b7b4f0d418df028f22f9d459563dba1b57b128f86d998c1b5394a2baacd64130ad3b2f2f7b4769e8a7a74b245d073be92e44e86c8cf8dff46e8784cc6f092f41c38a0561f011a8c90f3106533df3eb01c4e0fe75420c902d25461a42c62513c69873dcc0deb3cb2afadb042b3b406f854e5fc94d51ff96689cce700260a47a848a3dfde3506c1864e2290c4c872b0adaa1ed824ef085c0d520637cfca05c85b0c7f5a48c27eb075605132c7063cee80a510761ce8a8da658d81a12589f7cf1bcdd46b290968ac811fc2cc774fe7d5ee6c3329bb7b6f643c3762f4bf49c1f2dc07ac876be34f88d5b90bde9e97f74e8a6243e6ad729c9ec31e1dcaf407681336e1f4f6df886fde34df79d18af07f3d2e9fcdb6af25dc3938f80adf9c6f6aa8b36ad8fcf7f70d2dcd0778eac536b3b8c181707ebde0476577cde0e20da59ba63b3623c0e7e0669cc2cd3f4d0786ec30c212e354b96339d01a8fbccb8a5ea627192e00af947a8791435303c443fe7e471534c1525df652c91af79b86d2f4a8dc3e7da23460446a2dfd5fc01c18d1b8fdebb71bbf4d2985748b8bc772b0a8d6614ce4b53635c97c2aced4a941de5e9a3be4d42be5eb72ee17ae03ea84d6b27eac551249720b1a1ffd15207f83e1fdec4648b6775580cb532bc614566c56105768a95b5b2e56d8e8ca7a03fd2d991bcac01355d151fe889df41ac50fdcdb8d46caea690a5aaa1df60448ec93b1738b1ea2d5f8146e048b4955b1c2eed470d9610fae1d24ba79d7b8ba3946f10eb36d3dc59424665fa7c286f5bb61c9344dd8844578871b88ef6d553793e26a62b7b6df82fe44faccb0c1428baa6f1f1157d7c65d228bd9dd1c661592a404d801afbb5c90e57961ae6206ad8c5a7715a7b2918f9f5fdac94a3acec8657380f06c8508b5c6a55c0d8fa534b42d3021df2cb60e89d5d8a714f319f1d1028f5619cf566811e4f7cb68ae673caa927a0cc4b1d594e142365701a7a363ce73ec34282a0557f700d41a3aa7f50d4c28c3840f9a56f62a0ed999d7f0369a0b758c21768e1b613f323a8daf38c10ffcaa6fbd432ecc72f3e8e1e106c1c0dec3c82734668d81b2889009acb815597ed0c94d042133163d3f361d2225d63e0b38dccfeea3b36e0b8c64f4ac44cccd737f3f19278b33a6e3543127ac95df5649e1daac8ee8a21be1c42425ef220cae5dc34f7946561042346b3525538222c88087cb7eab07fb1e2c68c428e9582d28bc79d4df3224b932ed192a6f53d64d06704d9521a955b4d9ac55148bdd0c4d97ca18a8458508e355c24be68e3d13a756b2f51c46f9a9233a2b5ba8a9ef60833c0f1dd7c5e83d27ae7354697d1463828264554a0bb072c29bff7384a8c6502761e7a270b5562364e5e7219004c7fd50b4e957be2f43c9f18a95224df89b0e56d6b62ed6d8cb2f968c470dd48367a3c4cad0ef70da7befdad4ad5cae68e2784c4383dcfee3b54514e812901660fdf905b4fe08b31f04aa3cb7f2fe9bce36feca45a380cc40e7eec41c9978aa7d8bb7b83ad2597c253e3e3897136533199248e8f137b59dead25887e428dbab446949a47e869fa2522ea5208a49ca3eb9e27d6178e05ec19c308f1d3a14c2b98bf255a9e3e695032bad17967dff9f100f424a092d65e524770f6e24cabfd43977db5733ea92e87362c41d8153da8253e9e4170d57ea988ebad62fd8480e8b4d9237186c363cf756ad85b128e693f1bba24fc96e55d6331a2ce4f5e6faa6b742c2eb59d275d9d8fef07b2a56b8a6b25c8dca13e856dd6aa9e5bcfc1c153b51e97405db4db1097bfd0598d38df3ab969c72bb0e3fb034efa8393ee4e1ee7d4a4ee0ba4fa3ab2c9b45592675cb8683cb91eac708657064a8a3521332a060a2e6f7583086a13244cf2299931a50ae40fb5e3304b455c4c603450e59db2f84204a88626edc42a8032bd095d9a1a988e18abeefacef7bff1de2f28e0aeb0eec5b40dd64de56115f1a70be8a502673cc59793b39e4f68bb7868213edd3074a1b41c0f87a940d4e99acae1d60b1b82bf7ae17c08869d40533d1b3570ac1434ba4266734acc8bb31314bcee23aa11060cfaed7ba108cef2a182baf8a8e5b7ac7f6117023348bca50de7f56ae441bc06b731760e36442c6f1a2c357986c80b3f094269bc64f19ff8ba668b39ebf4077b440cd030626f07fbb092da46a64c2a9be9655ca182ea8b26b864efa36b5eeee64270d383c4e0d0460e002df6c7a46f2c042bf2b62dc011d69802d60e57bab4b1bdb59c4e164a56c3f13ac058d0d50bc44cc897e77160c34ad556851173ab0a57343c4059cea50434f0109810e23a2770ce54906348c14506ab04bae702af39425ff0b561f4f3b15abd4a4ab35f047da30f741b8745d02bb75830fc43fffe357aa08a149fa8b68ae18319ba6dd727d2637cda792e1fe1f1033fb1d0d853be59b1b587494eefbd3c7ce77ce00408d4d2b625ea471409588d732732d7f78f9bb4b211e7a5bd4751c4f213cfbe592a2230b20481100e1249ff3cedf10df50ebafb4b10f4eb15decda37fe8e9308b8174ac0f1e1bed16acd500994d34e18c4a18a166c08649c90a03af40eb672126930f6ebae3a3e216999d4cfa688774dd711c089b2890a5e4d989452cffa4af8310a059a2da180562ed841814d64fa4af1e665ae042f489d6e85ec3fb5276b9ce20f98777b6f36434dabe3ff2eb76870391e3204beaeae6e4cc5df76720b259e1570ee44f694bce449f3b1e11b1b4916f5873bd630b75539e5ccfdbb04da9cd1c3334e95cfe9bcfa512b32d3e75521779f724a31cf19e8981cd2991853714adeb644ebb3bafa8af83e5aebed9f4b50dbfc73ee82dda3d5cd2e00133340d7e572575c0afaaf706300baf6b81a7eceeacc1e212c3d8baa9860f070a64f66e2319839c371062fff8c65afb0ae639f93ea9eca6227acc9752bb554b0fd6a0d8e9e686672d0a58e3b87f2b4365985a27f9bdf50fe82fdd68f5ee12b7f64112e1bebe074473d39835101a5b7cc5210084af616f27dc58e74e31e7630da0d04dd082c811944dc7950f823fd3ee3bb8c10028af1bdab759384bf31f62df4cf8cea30a04cfada97270fb9278fda6824f913214281d912d9cdb1d46282054e5722df3d8641546e6123e89867298acb5d0e5e19582479befb24e770772657a36db1da062b1268709ba34d24bc2660d6d04fc377001b69724020e0e89ce3efdf88dc99143b9b1fdd3f3d3c74be20f1b9517cec32b5c8495eed2b189c7a5f14548d9456c6db38e68299de8ae9483b0b515d65634010d87fe823a44f020344b63c23c6bdcb2c7a3f034690cb6f1fed3776694cd5977f0108a5a0a72851a3c2fa9e8563f5c34f3ec5769c6e72d5d576ff9c0a5deeadf45f6ab86f1c24df722e5156f27128647f551130624a44d2fc9336dd4409f0f03a550ea2f238c2f8ae7bb6a157bcee9fa650844b705b43dd35595303e7854fc86d43041c6facf3767570dace282fc33cd7414a8e306a272a33ed44c7fc8d9b1902b5e837011c503bf982bcfd5a554f6b75c4c64dc571422b01ec9b565d59b11bb85920b78d5bcc1824aa3de7f36142dbd03e6645b928a52a2264aa1c8355d684a9c0e1e583a280a9e131449916f614ddaa3fd7e5737c3a41133a724dac9ae1f8485d49ba7e23dfee388ab7214f150c9420bcaec4d88bc4f972acbb63c01cdd74c548669106f3f21cb95384d873f64455a8acd995a9de892031aadbd731202b5d54c3635cb0eccd03795bd920126d4583dcc705ba63e5567a68d66257e41bf80c17b53b41e9d3172221dcd991a0d6be32833903cb2b4ba6830bf948651f8416e45220976f2b930af5039859bff68599c0ee5f84919ec058fd6b7254cd898f445ed042f9bbaadcfa0261c4fb8cff3a0ac2f1ba3027e884f8394ef4b4fb6b24a4dda6457879ddfe79e02fc374decce05c20332b896b38c7a94ea32f6812d9d250fc4f806d593abf34d23a9828a38234ec025835a610d4fd2fe22c1ab4efa5b8e87c081c76c71f43af76e564a0a7dd5617902a2a72a3f031134a1c75b0c03142d218a5889bf88a39f54efe6c7da10e1033f595912b27f1da2e8ff4e390eb4f18a0e49506f70849d3a0565a5013bb23ef17815fa34fb65c98661752a8a81e5fa46399f96de4d1932926df11a64e721f0b43f184e62b67306f9632c009efd30b7f454a929536d5b9965b576c41b1078d32c21bd72794b29fc3592e050c5d8759d4713b53beb84e6d5269df54583c92ca8a28e4ba8b32435f6109c0ddea0633a9091f2a5af00a2b32a4897c4a2f60a1613e2e51b4b7f4ccb228c70d375b08706ab4aa2d70ac155d797140bed661febf5560696b1635d8d1208f64759d9ac3f5dea5e28da8bd7a0e461f3a626fc1dce61c9b6f295b53fd39129e624a39b44c6840db6b5e99b7046b107597274a243e9b5a85147e163fd99741a8ccc2c3b2362b4fc899e1b55450ad9af772fa493cda912db19a34356643226cdef4061007024e789b2ce401e99d3cbc8338cb9a049fa2b4dbcf8a119dcd7255fa6b5aedca87bcdc0010831f5b4a6bb145a22fbf7d3c4a127d656509a3fcb6b2c3f1044dfee40af264b257309a245473484d147fc3939605fdf01c61ccf41279a0356cc9038fdb6caa6f1422d1ccd0afb372f958be19cec47b215ab3dbb83d10814831e2f591eb72e14960ccac44e791250c3d16a0273f355a6282cf86c8d7cddebd39c7489210f350914f7066eb5dfe1a5b29c6453c6fd8db978d33e33a33a48c287b9d5ad3ce375b044fa5fccb5b031c69276f895c5feec2e813398c728d19c5a4d6e3b2f0144a53a1e559171523eac07fe92ebeeb38d3c4a8ab88ad98ea80af95a14d981067f7a893ddb88d8b3520deb1cbbbda940c7bb3e05643a025c043312a784a7d8e9f26ac9bfad5a17b8c420033642ad76df6ab457d621238e320c6d4f1a0f5f1617442262b5c7467eccac63d97160efa1c17fa497b273ac0eb8006c4ca6c7cc480ef224f9931f757fe22f852d1042481b22347ffcac896607e535db9c4ce5383d8ba8d959941d940f1f8e3261c8172c402f0a3b78ed0557a0aafea7e96a7236ed1aefd77b3f74b966dd76cf85c64cf3d5e271bc1b76f53fb59186904b42d8b984801514949e97f099e8203338fdd46b46ec21f3a95d02e32058776edc6037ac8ff87ea3d3ce740b1cbb8c97d0a9f300a291e3b065cc8238b0c55605463c27b27f4dcf97b79753970714b88e616806da16224563b5f999aa3ab23535afd93b659d8b8ec2b6eeeffa717ca1fd5fdba1f35f1b5ce065a98b0beaf5f8de733ddb62653bd252ab3c13f7bfd4cf57d67875e69d8ae7162c8586849723120cbd8aefd093c2ec2a8cade3915b44d4798567040fc81d7dc8334a846ef27cc2516b2858355e064dfbc46794aa76c39a4e4162a3e2504f35d6d6f149e4ab90e27b771c74567dbc6c62a857415b940fb93c5e8dd7c39e44833200abd36d87e7d1fd1d7a1147d303a58997cf96d680c1b672d74a802eae69073fa9b379f045e19c054b665e13b0ff9f6072bae9acbf731adb992fa6dfdad045596752255866aabc6058a74a9de4e5ee536bb81a03fbcd2b19b372aa5c8a30051ac5b70fcc9dbee2b88dc21d89275e3924188a795ca116a8f76bd2702b9b15a3c48b36269588245600bccc2f23bae4b898fb051fe7defdd16aaaa057d9264c2509a2abf4426bc0d22abfffb96abb9da9c3034428c2832c84783669b28e17c8f6298a8c413a7e5f88", + "children": [ + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + } + ] + } + } + } +} diff --git a/spec/regression/traversal-performance/tests/root-and-sub-children/test.graphql b/spec/regression/traversal-performance/tests/root-and-sub-children/test.graphql new file mode 100644 index 000000000..79fdddb8a --- /dev/null +++ b/spec/regression/traversal-performance/tests/root-and-sub-children/test.graphql @@ -0,0 +1,36 @@ +query fieldTraversal_andChildEntitiesWithArrayExpansion { + Root(key: "root1") { + # this is a big field. query it so we're sure it is loaded from disk + predictablePayload + + children { + # accessing root in a child entity subquery can lead to the root being copied into a + # register for each child. This happens if there is another subquery, that's why we're + # querying the children's children. + root { + key + } + children { + key + } + } + } +} + +query fieldTraversal_andChildEntitiesWithSubquery { + Root(key: "root1") { + predictablePayload + + children { + root { + key + } + # without order, the children can be fetched via an array expansion expression, which + # avoids the problem outlined above - but this no longer works if there is sorting + # because SORT is not supported in array expansion expressions + children(orderBy: key_ASC) { + key + } + } + } +} diff --git a/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/fewRootFields.aql b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/fewRootFields.aql new file mode 100644 index 000000000..5fb4e7259 --- /dev/null +++ b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/fewRootFields.aql @@ -0,0 +1,33 @@ +WITH @@roots +LET v_super1 = FIRST(( + FOR v_super2 + IN @@supers + FILTER (v_super2.`key` == @var1) + LIMIT @var2 + RETURN v_super2 +)) +RETURN { + "Super": (IS_NULL(v_super1) ? null : { + "rootChildren": ( + FOR v_root1, v_edge1, v_path1 IN @var3..@var4 OUTBOUND v_super1 @@supers_roots + FILTER v_root1._key != null + LET v_root2 = NOEVAL({ + "key": v_root1.`key` + }) + FOR v_item1 IN v_root1.`children`[*] + RETURN { + "root": v_root2, + "children": ( + FOR v_grandchild1 + IN v_item1.`children`[*] + SORT (v_grandchild1.`key`) + RETURN { + "key": v_grandchild1.`key` + } + ) + } + ) + }) +} + +// Peak memory usage: 98304 bytes diff --git a/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/manyRootFields_innerWithArrayExpansion.aql b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/manyRootFields_innerWithArrayExpansion.aql new file mode 100644 index 000000000..3301885df --- /dev/null +++ b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/manyRootFields_innerWithArrayExpansion.aql @@ -0,0 +1,33 @@ +WITH @@roots +LET v_super1 = FIRST(( + FOR v_super2 + IN @@supers + FILTER (v_super2.`key` == @var1) + LIMIT @var2 + RETURN v_super2 +)) +RETURN { + "Super": (IS_NULL(v_super1) ? null : { + "rootChildren": ( + FOR v_root1, v_edge1, v_path1 IN @var3..@var4 OUTBOUND v_super1 @@supers_roots + FILTER v_root1._key != null + LET v_root2 = NOEVAL({ + "key": v_root1.`key`, + "fieldA": v_root1.`fieldA`, + "fieldB": v_root1.`fieldB`, + "fieldC": v_root1.`fieldC`, + "fieldD": v_root1.`fieldD`, + "fieldE": v_root1.`fieldE` + }) + FOR v_item1 IN v_root1.`children`[* RETURN { + "root": v_root2, + "children": CURRENT.`children`[* RETURN { + "key": CURRENT.`key` + }] + }] + RETURN v_item1 + ) + }) +} + +// Peak memory usage: 51085312 bytes diff --git a/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/manyRootFields_innerWithSubquery.aql b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/manyRootFields_innerWithSubquery.aql new file mode 100644 index 000000000..db2c6e95e --- /dev/null +++ b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/aql/manyRootFields_innerWithSubquery.aql @@ -0,0 +1,38 @@ +WITH @@roots +LET v_super1 = FIRST(( + FOR v_super2 + IN @@supers + FILTER (v_super2.`key` == @var1) + LIMIT @var2 + RETURN v_super2 +)) +RETURN { + "Super": (IS_NULL(v_super1) ? null : { + "rootChildren": ( + FOR v_root1, v_edge1, v_path1 IN @var3..@var4 OUTBOUND v_super1 @@supers_roots + FILTER v_root1._key != null + LET v_root2 = NOEVAL({ + "key": v_root1.`key`, + "fieldA": v_root1.`fieldA`, + "fieldB": v_root1.`fieldB`, + "fieldC": v_root1.`fieldC`, + "fieldD": v_root1.`fieldD`, + "fieldE": v_root1.`fieldE` + }) + FOR v_item1 IN v_root1.`children`[*] + RETURN { + "root": v_root2, + "children": ( + FOR v_grandchild1 + IN v_item1.`children`[*] + SORT (v_grandchild1.`key`) + RETURN { + "key": v_grandchild1.`key` + } + ) + } + ) + }) +} + +// Peak memory usage: 51118080 bytes diff --git a/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/context.json b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/context.json new file mode 100644 index 000000000..fb12a4966 --- /dev/null +++ b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/context.json @@ -0,0 +1,5 @@ +{ + "authRoles": ["user"], + // we request the payload here. Pay close attention to actual memory usage in the .aql files + "queryMemoryLimit": "100000000" +} diff --git a/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/result.json b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/result.json new file mode 100644 index 000000000..1a16c36e4 --- /dev/null +++ b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/result.json @@ -0,0 +1,2826 @@ +{ + "fewRootFields": { + "data": { + "Super": { + "rootChildren": [ + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root9" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root8" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root7" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root6" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root5" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root4" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root3" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root2" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root1" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + }, + { + "root": { + "key": "root0" + }, + "children": [] + } + ] + } + } + }, + "manyRootFields_innerWithSubquery": { + "data": { + "Super": { + "rootChildren": [ + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + } + ] + } + } + }, + "manyRootFields_innerWithArrayExpansion": { + "data": { + "Super": { + "rootChildren": [ + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root9", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root8", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root7", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root6", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root5", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root4", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root3", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root2", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root1", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + }, + { + "root": { + "key": "root0", + "fieldA": null, + "fieldB": null, + "fieldC": null, + "fieldD": null, + "fieldE": null + }, + "children": [] + } + ] + } + } + } +} diff --git a/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/test.graphql b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/test.graphql new file mode 100644 index 000000000..f2ba96818 --- /dev/null +++ b/spec/regression/traversal-performance/tests/traversal-then-root-and-sub-children/test.graphql @@ -0,0 +1,63 @@ +# this will probably use the reduce-extraction-to-projection optimization so only the root key +# will be kept in memory +query fewRootFields { + Super(key: "super1") { + rootChildren { + root { + key + } + + children(orderBy: key_ASC) { + key + } + } + } +} + +# this requests more fields so the reduce-extraction-to-projection optimization will not be used +# hence, the root objects will be big. +# There are 10 root entities with 5 MB payload each, so it should take 50 MB +# If it duplicates the root object (pre-mapping) into each child, it will take 500 MB +# (because there are 10 children per root) +query manyRootFields_innerWithSubquery { + Super(key: "super1") { + rootChildren { + root { + key + fieldA + fieldB + fieldC + fieldD + fieldE + } + + children(orderBy: key_ASC) { + key + } + } + } +} + +# this is a variant where we are able to use an array expansion expression instead of a subquery +# for the children node, which should make it easier to avoid the performance pitfall +# again: +# There are 10 root entities with 5 MB payload each, so it should take 50 MB +# If it duplicates the root object (pre-mapping) into each child, it will take 500 MB +query manyRootFields_innerWithArrayExpansion { + Super(key: "super1") { + rootChildren { + root { + key + fieldA + fieldB + fieldC + fieldD + fieldE + } + + children { + key + } + } + } +} diff --git a/src/database/arangodb/aql-generator.ts b/src/database/arangodb/aql-generator.ts index 4021c2101..8d29d2bf9 100644 --- a/src/database/arangodb/aql-generator.ts +++ b/src/database/arangodb/aql-generator.ts @@ -1,5 +1,6 @@ +import { Clock, DefaultClock, IDGenerator, UUIDGenerator } from '../../execution/execution-options'; import { AggregationOperator, Field, Relation, RootEntityType } from '../../model'; -import { FieldSegment, RelationSegment } from '../../model/implementation/collect-path'; +import { FieldSegment } from '../../model/implementation/collect-path'; import { IDENTITY_ANALYZER } from '../../model/implementation/flex-search'; import { AddEdgesQueryNode, @@ -28,6 +29,7 @@ import { FieldQueryNode, FirstOfListQueryNode, FollowEdgeQueryNode, + HoistableQueryNode, ListItemQueryNode, ListQueryNode, LiteralQueryNode, @@ -69,7 +71,11 @@ import { FlexSearchStartsWithQueryNode, } from '../../query-tree/flex-search'; import { Quantifier, QuantifierFilterNode } from '../../query-tree/quantifiers'; -import { extractVariableAssignments, simplifyBooleans } from '../../query-tree/utils'; +import { + extractVariableAssignments, + getReferencedVariables, + simplifyBooleans, +} from '../../query-tree/utils'; import { not } from '../../schema-generation/utils/input-types'; import { Constructor, decapitalize, isReadonlyArray } from '../../utils/utils'; import { FlexSearchTokenizable } from '../database-adapter'; @@ -88,10 +94,7 @@ import { getCollectionNameForRootEntity, } from './arango-basics'; import { getFlexSearchViewNameForRootEntity } from './schema-migration/arango-search-helpers'; -import { Clock, DefaultClock, IDGenerator, UUIDGenerator } from '../../execution/execution-options'; -import { visitQueryNode } from '../../query-tree/visitor'; -import { VisitResult } from '../../utils/visitor'; -import { mightGenerateSubquery } from './traversal-helpers'; +import { supportedAsArrayExpansion } from './traversal-helpers'; enum AccessType { /** @@ -464,6 +467,11 @@ register(VariableQueryNode, (node, context) => { return context.getVariable(node); }); +register(HoistableQueryNode, (node, context) => { + // if we process a HoistableQueryNode here, the node did not get hoisted, but that's fine too + return processNode(node.node, context); +}); + register(VariableAssignmentQueryNode, (node, context) => { const newContext = context.bindVariable(node.variableNode); const tmpVar = newContext.getVariable(node.variableNode); @@ -558,21 +566,57 @@ register(FlexSearchQueryNode, (node, context) => { }); register(TransformListQueryNode, (node, context) => { - let itemContext = context.bindVariable(node.itemVariable); - const itemVar = itemContext.getVariable(node.itemVariable); - let itemProjectionContext = itemContext; - // move LET statements up // they often occur for value objects / entity extensions // this avoids the FIRST() and the subquery which reduces load on the AQL query optimizer - let variableAssignments: AQLFragment[] = []; + const hoistedAssignments: AQLFragment[] = []; + const loopScopedAssignmentNodes: VariableAssignmentQueryNode[] = []; + const loopScopedVariables = new Set(); + + let currentContext = context; let innerNode = node.innerNode; const variableAssignmentNodes: VariableAssignmentQueryNode[] = []; innerNode = extractVariableAssignments(innerNode, variableAssignmentNodes); + for (const assignmentNode of variableAssignmentNodes) { + const referencedVariables = getReferencedVariables(assignmentNode.variableValueNode); + const referencesItemVariable = referencedVariables.has(node.itemVariable); + let referencesLoopScopedVariable = false; + for (const variableNode of loopScopedVariables) { + if (referencedVariables.has(variableNode)) { + referencesLoopScopedVariable = true; + break; + } + } + + if (!referencesItemVariable && !referencesLoopScopedVariable) { + currentContext = currentContext.bindVariable(assignmentNode.variableNode); + const tmpVar = currentContext.getVariable(assignmentNode.variableNode); + // ArangoDB will try to move the hoisted variable down to their usages again, even + // though that increases memory usage because it requires the subquery to hold the whole + // source (root) variable. NOEVAL() forces the optimizer to keep the variable where it's + // declared + hoistedAssignments.push( + aql`LET ${tmpVar} = NOEVAL(${processNode( + assignmentNode.variableValueNode, + currentContext, + )})`, + ); + } else { + loopScopedAssignmentNodes.push(assignmentNode); + loopScopedVariables.add(assignmentNode.variableNode); + } + } + + let itemContext = currentContext.bindVariable(node.itemVariable); + const itemVar = itemContext.getVariable(node.itemVariable); + let itemProjectionContext = itemContext; + const loopScopedAssignments: AQLFragment[] = []; + + for (const assignmentNode of loopScopedAssignmentNodes) { itemProjectionContext = itemProjectionContext.bindVariable(assignmentNode.variableNode); const tmpVar = itemProjectionContext.getVariable(assignmentNode.variableNode); - variableAssignments.push( + loopScopedAssignments.push( aql`LET ${tmpVar} = ${processNode( assignmentNode.variableValueNode, itemProjectionContext, @@ -586,9 +630,15 @@ register(TransformListQueryNode, (node, context) => { // it if 5 or less fields are selected. We probably want to increase this limit // (also applies to FollowEdgeQueryNode and TraversalQueryNode) return aqlExt.subquery( + ...hoistedAssignments, aql`FOR ${itemVar}`, - generateInClauseWithFilterAndOrderAndLimit({ node, context, itemContext, itemVar }), - ...variableAssignments, + generateInClauseWithFilterAndOrderAndLimit({ + node, + context: currentContext, + itemContext, + itemVar, + }), + ...loopScopedAssignments, aql`RETURN ${processNode(innerNode, itemProjectionContext)}`, ); }); @@ -1445,7 +1495,7 @@ register(TraversalQueryNode, (node, context) => { } } - if (node.innerNode && mightGenerateSubquery(node.innerNode)) { + if (!supportedAsArrayExpansion(node, { skipTopLevelChecks: true })) { // cannot have subqueries within array expansions, so we need to use a subquery here return processTraversalWithRelationAndListFieldSegmentsUsingSubquery(node, context); } @@ -1475,10 +1525,7 @@ register(TraversalQueryNode, (node, context) => { // In the simple case, we can use an array expansion expression instead of a subquery // - SORT is not supported by array expressions (documented) // - subqueries in array expressions currently cause an internal error in arangodb (3.12.6) - if ( - node.orderBy.isUnordered() && - (!node.innerNode || !mightGenerateSubquery(node.innerNode)) - ) { + if (supportedAsArrayExpansion(node)) { return processTraversalWithOnlyFieldSegmentsUsingArrayExpansion(node, context); } else { return processTraversalWithOnlyFieldSegmentsUsingSubquery(node, context); @@ -1489,14 +1536,264 @@ register(TraversalQueryNode, (node, context) => { } }); +interface ExtractTraversalAssignmentsResult { + /** + * The inner node with extracted variable assignments removed + */ + readonly innerNode: QueryNode | undefined; + + /** + * Variables that do not depend on rootEntityVariable or itemVariable + */ + readonly traversalIndependentAssignments: ReadonlyArray; + + /** + * Variables that depend on rootEntityVariable but not on itemVariable + */ + readonly rootScopedAssignments: ReadonlyArray; + + /** + * Variables that depend on itemVariable + */ + readonly itemScopedAssignments: ReadonlyArray; +} + +/** + * Extracts three kinds of VariableAssignmentQueryNode from the traversal's innerNode + * + * Variables that depend on nested traversals etc. are not extracted. + */ +function extractTraversalAssignments(node: TraversalQueryNode): ExtractTraversalAssignmentsResult { + if (!node.innerNode) { + return { + innerNode: undefined, + traversalIndependentAssignments: [], + rootScopedAssignments: [], + itemScopedAssignments: [], + }; + } + + const extractedAssignments: VariableAssignmentQueryNode[] = []; + const processedInnerNode = extractVariableAssignments(node.innerNode, extractedAssignments); + + const traversalIndependentAssignments: VariableAssignmentQueryNode[] = []; + const rootScopedAssignments: VariableAssignmentQueryNode[] = []; + const itemScopedAssignments: VariableAssignmentQueryNode[] = []; + + const rootScopedVariables = [node.rootEntityVariable]; + const itemScopedVariables = [node.itemVariable]; + + for (const assignmentNode of extractedAssignments) { + const referencedVariables = getReferencedVariables(assignmentNode.variableValueNode); + + if (itemScopedVariables.some((v) => referencedVariables.has(v))) { + itemScopedAssignments.push(assignmentNode); + itemScopedVariables.push(assignmentNode.variableNode); + } else if (rootScopedVariables.some((v) => referencedVariables.has(v))) { + rootScopedAssignments.push(assignmentNode); + rootScopedVariables.push(assignmentNode.variableNode); + } else { + traversalIndependentAssignments.push(assignmentNode); + } + } + + return { + innerNode: processedInnerNode, + traversalIndependentAssignments, + rootScopedAssignments, + itemScopedAssignments, + }; +} + +interface ExtractTraversalAssignmentsAsAqlArgs { + /** + * The traversal node + */ + readonly node: TraversalQueryNode; + + /** + * The base context, without any traversal-specific bindings + */ + readonly context: QueryContext; + + /** + * A fragment holding the value of rootEntityVariable + * + * If not specified, variable assignments that depend on rootEntityVariable throw + */ + readonly rootVar?: AQLFragment; + + /** + * A fragment holding the value of itemVariable + * + * If not specified, variable assignments that depend on rootEntityVariable throw + */ + readonly itemVar?: AQLVariable; + + /** + * Whether to wrap root-based variable assignments in NOEVAL() + * + * NOEVAL() is used when a variable is pulled out of a loop to prevent ArangoDB from pushing it + * down into the loop again (which would increase memory usage). This is always done for + * independentAssignmentFrags. By default, it is also done for rootAssignmentFrags. + * + * Set this to false if there is no subquery around item traversal within the context of a root + * variable (e.g. when there are no list field segments) + * + * @default true + */ + readonly wrapRootVarsInNoEval?: boolean; +} + +interface ExtractTraversalAssignmentsAsAqlResult { + /** + * LET statements for variable assignments that do not depend on the traversal + */ + readonly independentAssignmentFrags: ReadonlyArray; + + /** + * LET statements for variable assignments that depend on the root variable + * + * Always empty if rootVar is not provided + */ + readonly rootAssignmentFrags: ReadonlyArray; + + /** + * LET statements for variable assignments that depend on the item variable + * + * Always empty if supportsLoopVariables is false + */ + readonly itemAssignmentFrags: ReadonlyArray; + + /** + * The node's innerNode with hoisted variable assignments removed + */ + readonly processedInnerNode: QueryNode | undefined; + + /** + * A context where rootVar and all root-based variables have been bound + */ + readonly rootContext: QueryContext; + + /** + * A context where rootVar, itemVar and all root-based variables have been bound + * + * Can be used to e.g. process filterNode + */ + readonly itemBaseContext: QueryContext; + + /** + * A context where rootVar, itemVar and all item- and root-based variables have been bound + */ + readonly itemContext: QueryContext; + + /** + * A fragment for innerNode processed in itemContext (or just itemVar if innerNode is undefined) + * + * If itemVar is not provided, this is aql`NULL` + */ + readonly innerFrag: AQLFragment; +} + +/** + * Extracts variable assignments from the traversal's innerNode and produces LET statements + */ +function extractTraversalAssignmentsAsAql({ + node, + context, + rootVar, + itemVar, + wrapRootVarsInNoEval = true, +}: ExtractTraversalAssignmentsAsAqlArgs): ExtractTraversalAssignmentsAsAqlResult { + // TODO aql-perf: can there also be VariableAssignments in filterNode? If yes, should we hoist them? + const { + innerNode: processedInnerNode, + traversalIndependentAssignments, + rootScopedAssignments, + itemScopedAssignments, + } = extractTraversalAssignments(node); + + if (rootScopedAssignments.length > 0 && !rootVar) { + throw new Error( + 'Found variable assignments that depend on the root variable, but the current traversal variant does not support them.', + ); + } + if (itemScopedAssignments.length > 0 && !itemVar) { + throw new Error( + 'Found variable assignments that depend on the loop variable, but the current traversal variant does not support them.', + ); + } + + const { fragments: independentAssignmentFrags, context: baseContext } = + buildAssignmentFragments(traversalIndependentAssignments, context, { + wrapWithNoEval: true, + }); + + const rootBaseContext = rootVar + ? baseContext.bindVariable(node.rootEntityVariable, rootVar) + : baseContext; + const { fragments: rootAssignmentFrags, context: rootContext } = buildAssignmentFragments( + rootScopedAssignments, + rootBaseContext, + { + wrapWithNoEval: wrapRootVarsInNoEval, + }, + ); + + const itemBaseContext = itemVar + ? rootContext.bindVariable(node.itemVariable, itemVar) + : rootContext; + const { fragments: itemAssignmentFrags, context: itemContext } = buildAssignmentFragments( + itemScopedAssignments, + itemBaseContext, + ); + + const innerFrag = + itemVar && processedInnerNode + ? processNode(processedInnerNode, itemContext) + : (itemVar ?? aql`NULL`); + + return { + processedInnerNode, + innerFrag, + independentAssignmentFrags, + rootAssignmentFrags, + itemAssignmentFrags, + rootContext, + itemBaseContext, + itemContext, + }; +} + +function buildAssignmentFragments( + assignments: ReadonlyArray, + startContext: QueryContext, + { wrapWithNoEval = false }: { wrapWithNoEval?: boolean } = {}, +): { fragments: AQLFragment[]; context: QueryContext } { + let currentContext = startContext; + const fragments: AQLFragment[] = []; + for (const assignmentNode of assignments) { + currentContext = currentContext.bindVariable(assignmentNode.variableNode); + const tmpVar = currentContext.getVariable(assignmentNode.variableNode); + const valueFrag = processNode(assignmentNode.variableValueNode, currentContext); + fragments.push( + wrapWithNoEval + ? aql`LET ${tmpVar} = NOEVAL(${valueFrag})` + : aql`LET ${tmpVar} = ${valueFrag}`, + ); + } + return { fragments, context: currentContext }; +} + /** * Produces: * * FIRST( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 - * FOR result IN OUTBOUND hop2_target - * RETURN innerNode(result) + * FOR item IN OUTBOUND hop2_target + * LET extractedVar = variableValueExpr(item) + * RETURN innerNode(item) * ) * * or, if preserveNullValues is true and hop2_target is a to-1 relation: @@ -1504,8 +1801,9 @@ register(TraversalQueryNode, (node, context) => { * FIRST( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 - * LET result = FIRST(FOR node3 IN OUTBOUND hop2_target RETURNN node3) - * RETURN innerNode(result) + * LET item = FIRST(FOR node3 IN OUTBOUND hop2_target RETURNN node3) + * LET extractedVar = variableValueExpr(item) + * RETURN innerNode(item) * ) */ function processTraversalWithOnlyRelationSegmentsNoList( @@ -1526,8 +1824,8 @@ function processTraversalWithOnlyRelationSegmentsNoList( ); } - const innerContext = context.bindVariable(node.itemVariable); - const itemVar = innerContext.getVariable(node.itemVariable); + const itemVar = aql.variable(node.itemVariable.label ?? 'item'); + const forStatementsFrag = getRelationTraversalForStatements({ node, innermostItemVar: itemVar, @@ -1535,9 +1833,14 @@ function processTraversalWithOnlyRelationSegmentsNoList( context, }); + const { independentAssignmentFrags, itemAssignmentFrags, innerFrag } = + extractTraversalAssignmentsAsAql({ node, context, itemVar }); + return aqlExt.firstOfSubquery( + ...independentAssignmentFrags, forStatementsFrag, - aql`RETURN ${node.innerNode ? processNode(node.innerNode, innerContext) : itemVar}`, + ...itemAssignmentFrags, + aql`RETURN ${innerFrag}`, ); } @@ -1547,6 +1850,7 @@ function processTraversalWithOnlyRelationSegmentsNoList( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * FOR item IN OUTBOUND hop2_target + * LET extractedVar = variableValueExpr(item) * FILTER filterExpr(item) * SORT item.field1 ASC * LIMIT skip, maxCount @@ -1557,6 +1861,7 @@ function processTraversalWithOnlyRelationSegmentsNoList( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * LET item = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) + * LET extractedVar = variableValueExpr(item) * FILTER filterExpr(item) * SORT item.field1 ASC * LIMIT skip, maxCount @@ -1575,9 +1880,7 @@ function processTraversalWithOnlyRelationSegmentsAsList( // - sourceIsList is handled in getRelationTraversalForStatements() // - alwaysProduceList is automatically handled because we always RETURN a list here // we could refactor the single usage so it does not use a TraversalQueryNode in the first place - const itemVar = aql.variable(`node`); - const innerContext = context.bindVariable(node.itemVariable, itemVar); const forStatementsFrag = getRelationTraversalForStatements({ node, @@ -1586,16 +1889,21 @@ function processTraversalWithOnlyRelationSegmentsAsList( preserveNullValues: node.preserveNullValues, }); + const { independentAssignmentFrags, itemAssignmentFrags, itemBaseContext, innerFrag } = + extractTraversalAssignmentsAsAql({ node, context, itemVar }); + return aqlExt.subquery( + ...independentAssignmentFrags, forStatementsFrag, - node.filterNode ? aql`FILTER ${processNode(node.filterNode, context)}` : aql``, + node.filterNode ? aql`FILTER ${processNode(node.filterNode, itemBaseContext)}` : aql``, // yes, we can SORT and LIMIT like this even if there are multiple FOR statements // because there is one result set for the cross product of all FOR statements // see https://docs.arangodb.com/3.12/aql/high-level-operations/for/#usage - generateSortAQL(node.orderBy, innerContext), + generateSortAQL(node.orderBy, itemBaseContext), generateLimitClause(node) ?? aql``, - aql`RETURN ${node.innerNode ? processNode(node.innerNode, innerContext) : itemVar}`, + ...itemAssignmentFrags, + aql`RETURN ${innerFrag}`, ); } @@ -1604,21 +1912,25 @@ function processTraversalWithOnlyRelationSegmentsAsList( * * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 - * FOR item IN OUTBOUND hop2_target - * FILTER filterExpr(item.fieldSegment1.fieldSegment2) - * SORT item.fieldSegment1.fieldSegment2.sortField ASC + * FOR root IN OUTBOUND hop2_target + * LET extractedVar1 = variable1ValueExpr(root)) + * LET extractedVar2 = variable2ValueExpr(root.fieldSegment1.fieldSegment2) + * FILTER filterExpr(root.fieldSegment1.fieldSegment2) + * SORT root.fieldSegment1.fieldSegment2.sortField ASC * LIMIT skip, maxCount - * RETURN innerNode(item.fieldSegment1.fieldSegment2, { root: node2 }) + * RETURN innerNode(root.fieldSegment1.fieldSegment2, { root: node2 }) * * or, if preserveNullValues is true and hop2_target is a to-1 relation: * * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 - * LET item = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) - * FILTER filterExpr(item.fieldSegment1.fieldSegment2) - * SORT item.fieldSegment1.fieldSegment2.sortField ASC + * LET root = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) + * LET extractedVar1 = variable1ValueExpr(root) + * LET extractedVar2 = variable2ValueExpr(root.fieldSegment1.fieldSegment2) + * FILTER filterExpr(root.fieldSegment1.fieldSegment2) + * SORT root.fieldSegment1.fieldSegment2.sortField ASC * LIMIT skip, maxCount - * RETURN innerNode(item.fieldSegment1.fieldSegment2, { root: node2 }) + * RETURN innerNode(root.fieldSegment1.fieldSegment2, { root: node2 }) */ function processTraversalWithListRelationSegmentsAndNonListFieldSegments( node: TraversalQueryNode, @@ -1645,17 +1957,35 @@ function processTraversalWithListRelationSegmentsAndNonListFieldSegments( segments: node.fieldSegments, sourceFrag: rootVar, }); - const innerContext = context.bindVariable(node.itemVariable, fieldTraversalFrag); + const { + independentAssignmentFrags, + itemBaseContext, + itemAssignmentFrags, + rootAssignmentFrags, + innerFrag, + } = extractTraversalAssignmentsAsAql({ + node, + context, + rootVar, + itemVar: fieldTraversalFrag, + + // there is no loop within the context of a root item where the root var assignment could + // be pushed down into, so we don't need to guard against that + wrapRootVarsInNoEval: false, + }); // note: we don't filter out NULL values even if preserveNullValues is false because that's currently // only a flag for performance - actually filtering out NULLs is done by a surrounding AggregationQueryNode // TODO aql-perf remove this note once the NULL filtering / preserving has moved out of AggregationQueryNode return aqlExt.subquery( - forStatementsFrag, - node.filterNode ? aql`FILTER ${processNode(node.filterNode, innerContext)}` : aql``, - generateSortAQL(node.orderBy, innerContext), + ...independentAssignmentFrags, + aql`${forStatementsFrag}`, + node.filterNode ? aql`FILTER ${processNode(node.filterNode, itemBaseContext)}` : aql``, + generateSortAQL(node.orderBy, itemBaseContext), generateLimitClause(node) ?? aql``, - aql`RETURN ${node.innerNode ? processNode(node.innerNode, innerContext) : fieldTraversalFrag}`, + ...rootAssignmentFrags, + ...itemAssignmentFrags, + aql`RETURN ${innerFrag}`, ); } @@ -1665,8 +1995,10 @@ function processTraversalWithListRelationSegmentsAndNonListFieldSegments( * FIRST( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 - * FOR item IN OUTBOUND hop2_target - * RETURN innerNode(item.fieldSegment1.fieldSegment2, { root: node2 }) + * FOR root IN OUTBOUND hop2_target + * LET extractedVar1 = variable1ValueExpr(root) + * LET extractedVar2 = variable2ValueExpr(root.fieldSegment1.fieldSegment2) + * RETURN innerNode(root.fieldSegment1.fieldSegment2, { root: node2 }) * ) * * or, if preserveNullValues is true and hop2_target is a to-1 relation: @@ -1674,8 +2006,10 @@ function processTraversalWithListRelationSegmentsAndNonListFieldSegments( * FIRST( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 - * LET item = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) - * RETURN innerNode(item.fieldSegment1.fieldSegment2, { root: node2 }) + * LET root = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) + * LET extractedVar1 = variable1ValueExpr(root) + * LET extractedVar2 = variable2ValueExpr(root.fieldSegment1.fieldSegment2) + * RETURN innerNode(root.fieldSegment1.fieldSegment2, { root: node2 }) * ) */ function processTraversalWithNonListRelationSegmentsAndNonListFieldSegments( @@ -1700,23 +2034,35 @@ function processTraversalWithNonListRelationSegmentsAndNonListFieldSegments( // this is very similar to processTraversalWithOnlyRelationSegmentsNoList(), // but instead of using the rootVar in mapping, we use the field traversal result - const rootVar = aql.variable(`root`); + const rootVar = aql.variable('root'); const forStatementsFrag = getRelationTraversalForStatements({ node, innermostItemVar: rootVar, preserveNullValues: node.preserveNullValues, context, }); - const fieldTraversalFrag = getFieldTraversalFragment({ segments: node.fieldSegments, sourceFrag: rootVar, }); - const innerContext = context.bindVariable(node.itemVariable, fieldTraversalFrag); + const { independentAssignmentFrags, itemAssignmentFrags, rootAssignmentFrags, innerFrag } = + extractTraversalAssignmentsAsAql({ + node, + context, + rootVar, + itemVar: fieldTraversalFrag, + + // there is no loop within the context of a root item where the root var assignment could + // be pushed down into, so we don't need to guard against that + wrapRootVarsInNoEval: false, + }); return aqlExt.firstOfSubquery( - forStatementsFrag, - aql`RETURN ${node.innerNode ? processNode(node.innerNode, innerContext) : fieldTraversalFrag}`, + ...independentAssignmentFrags, + aql`${forStatementsFrag}`, + ...rootAssignmentFrags, + ...itemAssignmentFrags, + aql`RETURN ${innerFrag}`, ); } @@ -1726,7 +2072,9 @@ function processTraversalWithNonListRelationSegmentsAndNonListFieldSegments( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * FOR root IN OUTBOUND hop2_target + * LET extractedVar1 = NOEVAL(variable1ValueExpr(root)) * FOR item IN root.fieldSegment1[*].fieldSegment2[** FILTER filterExpr(CURRENT)][*] + * LET extractedVar2 = variable1ValueExpr(item) * SORT item.sortValues[0] * LIMIT skip, maxCount * RETURN innerNode(item, { root }) @@ -1736,7 +2084,9 @@ function processTraversalWithNonListRelationSegmentsAndNonListFieldSegments( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * LET root = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) + * LET extractedVar1 = NOEVAL(variable1ValueExpr(root)) * FOR item IN root.fieldSegment1[*].fieldSegment2[** FILTER filterExpr(CURRENT)][*] + * LET extractedVar2 = variable1ValueExpr(item) * SORT item.sortValues[0] * LIMIT skip, maxCount * RETURN innerNode(item, { root }) @@ -1781,19 +2131,26 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery( filterFrag: innerFilterFrag, }); - const itemVar = aql.variable(`item`); - const innerContext = context - .bindVariable(node.itemVariable, itemVar) - .bindVariable(node.rootEntityVariable, rootVar); + const itemVar = aql.variable(node.itemVariable.label ?? 'item'); + const { + independentAssignmentFrags, + rootAssignmentFrags, + itemAssignmentFrags, + itemBaseContext, + innerFrag, + } = extractTraversalAssignmentsAsAql({ node, context, rootVar, itemVar }); // The fieldTraversalFrag will produce a list, so a simple RETURN mapFrag would result in nested lists // -> we iterate over the items again to flatten the lists (the FOR ${itemVar} ...) return aqlExt.subquery( + ...independentAssignmentFrags, aql`${forStatementsFrag}`, + ...rootAssignmentFrags, aql`FOR ${itemVar} IN ${fieldTraversalFrag}`, - generateSortAQL(node.orderBy, innerContext), + generateSortAQL(node.orderBy, itemBaseContext), generateLimitClause(node) ?? aql``, - aql`RETURN ${node.innerNode ? processNode(node.innerNode, innerContext) : itemVar}`, + ...itemAssignmentFrags, + aql`RETURN ${innerFrag}`, ); } @@ -1803,6 +2160,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * FOR root IN OUTBOUND hop2_target + * LET extractedVar = NOEVAL(variableValueExpr(root)) * FOR item IN root.fieldSegment1[*].fieldSegment2[**][* * FILTER filterExpr(CURRENT) * LIMIT skip, maxCount @@ -1829,6 +2187,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery( * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * LET root = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) + * LET extractedVar = NOEVAL(variableValueExpr(root)) * FOR item IN root.fieldSegment1[*].fieldSegment2[**][* * FILTER filterExpr(CURRENT) * LIMIT skip, maxCount @@ -1872,16 +2231,6 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith context, }); - const innerNode = node.innerNode; - const innerMapFrag = innerNode - ? (itemFrag: AQLFragment) => { - const innerContext = context - .bindVariable(node.itemVariable, itemFrag) - .bindVariable(node.rootEntityVariable, rootVar); - return processNode(innerNode, innerContext); - } - : undefined; - // We can do the LIMIT within the field traversal's mapping function using an array expansion, // but only if the relation traversal yields at most one result (i.e. if it only follows 1:1 relations) const lastRelationSegment = node.relationSegments[node.relationSegments.length - 1]; @@ -1901,8 +2250,12 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith }; } - let innerFilterFrag: ((item: AQLFragment) => AQLFragment) | undefined; + // There is no place to put item-dependent LET statements in this variant, so we don't pass an itemVar + const { independentAssignmentFrags, rootAssignmentFrags, rootContext, processedInnerNode } = + extractTraversalAssignmentsAsAql({ node, context, rootVar }); + const filterNode = node.filterNode; + let innerFilterFrag: ((item: AQLFragment) => AQLFragment) | undefined; if (filterNode) { innerFilterFrag = (itemFrag: AQLFragment) => { // don't map rootEntityVariable @@ -1912,6 +2265,11 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith }; } + const innerMapFrag = processedInnerNode + ? (itemFrag: AQLFragment) => + processNode(processedInnerNode, rootContext.bindVariable(node.itemVariable, itemFrag)) + : undefined; + const fieldTraversalFrag = getFieldTraversalFragment({ segments: node.fieldSegments, sourceFrag: rootVar, @@ -1932,9 +2290,11 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith // FOR item IN root.children // RETURN item // (could also use FLATTEN(), but since we're already using nested FORs, this is probably cleaner) - const itemVar = aql.variable(`item`); + const itemVar = aql.variable('item'); return aqlExt.subquery( + ...independentAssignmentFrags, aql`${forStatementsFrag}`, + ...rootAssignmentFrags, aql`FOR ${itemVar} IN ${fieldTraversalFrag}`, generateLimitClause(limitArgs) ?? aql``, aql`RETURN ${itemVar}`, @@ -1947,6 +2307,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * FOR root IN OUTBOUND hop2_target + * LET extractedVar = NOEVAL(variableValueExpr(root)) * FOR item IN root.fieldSegment1[*].fieldSegment2[**][* * FILTER filterExpr(CURRENT) * RETURN { @@ -1966,6 +2327,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith * FOR node1 IN OUTBOUND source_hop1 * FOR node2 in OUTBOUND hop1_hop2 * LET root = FIRST(FOR node3 IN OUTBOUND hop2_target RETURN node3) + * LET extractedVar = NOEVAL(variableValueExpr(root)) * FOR item IN root.fieldSegment1[*].fieldSegment2[**][* * FILTER filterExpr(CURRENT) * RETURN { @@ -2038,13 +2400,20 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith (because sorting probably copies the whole item into some temporary structure) */ + // There is no place to put item-dependent LET statements in this variant, so we don't pass an itemVar + const { processedInnerNode, independentAssignmentFrags, rootAssignmentFrags, rootContext } = + extractTraversalAssignmentsAsAql({ node, context, rootVar }); + // we sort after mapping roots to items, so we need to preserve the sort values that are based on the item // -> we produce items like this: { value: ..., sortValues: [...] } const innerMapFrag = (itemFrag: AQLFragment) => { - const innerContext = context - .bindVariable(node.itemVariable, itemFrag) - .bindVariable(node.rootEntityVariable, rootVar); - const valueFrag = node.innerNode ? processNode(node.innerNode, innerContext) : itemFrag; + const innerContext = rootContext.bindVariable(node.itemVariable, itemFrag); + const valueFrag = processedInnerNode + ? processNode(processedInnerNode, innerContext) + : itemFrag; + const sortValueFrags = node.orderBy.clauses.map((c) => + processNode(c.valueNode, innerContext), + ); return aql.lines( aql`{`, @@ -2052,12 +2421,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith aql.lines( aql`value: ${valueFrag},`, aql`sortValues: [`, - aql.indent( - aql.join( - node.orderBy.clauses.map((c) => processNode(c.valueNode, innerContext)), - aql`,\n`, - ), - ), + aql.indent(aql.join(sortValueFrags, aql`,\n`)), aql`]`, ), ), @@ -2093,7 +2457,9 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith // The fieldTraversalFrag will produce a list, so a simple RETURN mapFrag would result in nested lists // -> we iterate over the items again to flatten the lists (the FOR ${itemVar} ...) return aqlExt.subquery( + ...independentAssignmentFrags, aql`${forStatementsFrag}`, + ...rootAssignmentFrags, aql`FOR ${itemVar} IN ${fieldTraversalFrag}`, aql`SORT ${aql.join(clauseFrags, aql`, `)}`, generateLimitClause(node) ?? aql``, @@ -2163,6 +2529,7 @@ function processTraversalWithOnlyFieldSegmentsUsingArrayExpansion( * FILTER filterExpr(item) * SORT item.sortField1 ASC, item.sortField1 DESC * LIMIT skip, maxCount + * LET extractedVar = variableValueExpr(item) * RETURN innerNode(item) */ function processTraversalWithOnlyFieldSegmentsUsingSubquery( @@ -2199,24 +2566,25 @@ function processTraversalWithOnlyFieldSegmentsUsingSubquery( sourceFrag, }); - const itemVar = aql.variable('item'); - - const innerContext = context.bindVariable(node.itemVariable, itemVar); - const returnValueFrag = node.innerNode ? processNode(node.innerNode, innerContext) : itemVar; + const itemVar = aql.variable(node.itemVariable.label ?? 'item'); + const { independentAssignmentFrags, itemAssignmentFrags, itemBaseContext, innerFrag } = + extractTraversalAssignmentsAsAql({ node, context, itemVar }); // filter in the subquery instead of in getFieldTraversalFragment() because the filter // expression might use subqueries const filterFrag = node.filterNode - ? aql`FILTER ${processNode(node.filterNode, innerContext)}` + ? aql`FILTER ${processNode(node.filterNode, itemBaseContext)}` : aql``; return aqlExt.subquery( + ...independentAssignmentFrags, aql`FOR ${itemVar}`, aql`IN ${fieldTraversalFrag}`, filterFrag, - generateSortAQL(node.orderBy, innerContext), + generateSortAQL(node.orderBy, itemBaseContext), generateLimitClause(node) ?? aql``, - aql`RETURN ${returnValueFrag}`, + ...itemAssignmentFrags, + aql`RETURN ${innerFrag}`, ); } diff --git a/src/database/arangodb/traversal-helpers.ts b/src/database/arangodb/traversal-helpers.ts index 2b523f2fb..c486f457e 100644 --- a/src/database/arangodb/traversal-helpers.ts +++ b/src/database/arangodb/traversal-helpers.ts @@ -9,33 +9,90 @@ import { TransformListQueryNode, TraversalQueryNode, VariableAssignmentQueryNode, + VariableQueryNode, } from '../../query-tree'; import { visitQueryNode } from '../../query-tree/visitor'; import { VisitResult } from '../../utils/visitor'; import { FlexSearchQueryNode } from '../../query-tree/flex-search'; +interface SupportedAsArrayExpansionOptions { + /** + * Set to true if you're only interested whether the field traversal (filter + map) can be implemented as array expansion + */ + skipTopLevelChecks?: boolean; +} + /** - * Determines whether the AQL for a given node might produce a subquery somewhere - * - * If in doubt, this will return true. - * - * Used to determine whether an array expansion expression can be used, because they don't support - * nested subqueries. + * Determines whether the given traversal can (and will) be implemented using an + * array expansion expression (as opposed to a subquery) */ -export function mightGenerateSubquery(node: QueryNode) { - let foundPotentialSubquery = false; - visitQueryNode(node, { +export function supportedAsArrayExpansion( + rootNode: TraversalQueryNode, + { skipTopLevelChecks }: SupportedAsArrayExpansionOptions = {}, +) { + // relation traversals always include subqueries + // SORT clauses are only supported by subqueries. + if (!skipTopLevelChecks) { + if (rootNode.relationSegments.length > 0 || !rootNode.orderBy.isUnordered()) { + return false; + } + } + + // technically we should exclude orderBy if skipTopLevelChecks is true, but we shouldn't have + // variables etc. in order by hopefully... + + let supported = true; + visitQueryNode(rootNode, { enter(currentNode): VisitResult { - if (mightGenerateSubqueryShallow(currentNode)) { - foundPotentialSubquery = true; + if (currentNode === rootNode) { + // don't actually want to check the root node, we did that above + return { recurse: true, newValue: currentNode }; } - return { recurse: !foundPotentialSubquery, newValue: currentNode }; + + // don't do potential expensive checks if we already know it's unsupported from a sibling + if (!supported) { + return { recurse: false, newValue: currentNode }; + } + + // traversals can be nested, but only if they use array expansions, too + if (currentNode instanceof TraversalQueryNode) { + if (!supportedAsArrayExpansion(currentNode)) { + supported = false; + } + + // the inner traversal cannot access the outer traversal's item variable because there only + // is the CURRENT keyword which is always the innermost array expansion's item + // (this is relevant for @parent fields) + // specify the three properties explicitly to ignore references in sourceEntityNode + if ( + referencesVariable( + [currentNode.innerNode, currentNode.filterNode, currentNode.orderBy], + rootNode.itemVariable, + ) + ) { + supported = false; + } + + // in all other cases, the nested traversal is fine + // we never recurse because we checked it recursively in supportedAsArrayExpansion() + return { recurse: false, newValue: currentNode }; + } + + // subqueries aren't supported in array expansions + if (mightGenerateSubquery(currentNode)) { + supported = false; + return { recurse: false, newValue: currentNode }; + } + + // regular node, no issues found so far + return { recurse: true, newValue: currentNode }; }, }); - return foundPotentialSubquery; + + return supported; } -function mightGenerateSubqueryShallow(node: QueryNode) { +function mightGenerateSubquery(node: QueryNode) { // we assume this is not called for mutations, so we don't include those if ( node instanceof FollowEdgeQueryNode || @@ -43,7 +100,8 @@ function mightGenerateSubqueryShallow(node: QueryNode) { node instanceof AggregationQueryNode || node instanceof FlexSearchQueryNode || node instanceof ObjectEntriesQueryNode || // TODO aql-perf: remove once refactored to not use subqueries - node instanceof VariableAssignmentQueryNode + node instanceof VariableAssignmentQueryNode || + node instanceof TraversalQueryNode // shouldn't occur because we handle that above ) { return true; } @@ -55,16 +113,28 @@ function mightGenerateSubqueryShallow(node: QueryNode) { ); } - if (node instanceof TraversalQueryNode) { - // relation traversals always include subqueries - if (node.relationSegments.length > 0) { - return true; + return false; +} + +function referencesVariable( + nodes: ReadonlyArray, + variable: VariableQueryNode, +): boolean { + let found = false; + for (const node of nodes) { + if (!node) { + continue; } - // SORT clauses are only supported by subqueries. - // Without ordering, we always generate expressions - return !node.orderBy.isUnordered(); + visitQueryNode(node, { + enter(currentNode): VisitResult { + if (currentNode === variable) { + found = true; + return { recurse: false, newValue: currentNode }; + } + return { recurse: !found, newValue: currentNode }; + }, + }); } - - return false; + return found; } diff --git a/src/database/inmemory/js-generator.ts b/src/database/inmemory/js-generator.ts index 95d6ab358..1a9537db6 100644 --- a/src/database/inmemory/js-generator.ts +++ b/src/database/inmemory/js-generator.ts @@ -27,6 +27,7 @@ import { FirstOfListQueryNode, FlexSearchStartsWithQueryNode, FollowEdgeQueryNode, + HoistableQueryNode, ListItemQueryNode, ListQueryNode, LiteralQueryNode, @@ -316,6 +317,11 @@ register(VariableQueryNode, (node, context) => { return context.getVariable(node); }); +register(HoistableQueryNode, (node, context) => { + // if we process a HoistableQueryNode here, the node did not get hoisted, but that's fine too + return processNode(node.node, context); +}); + register(VariableAssignmentQueryNode, (node, context) => { const newContext = context.bindVariable(node.variableNode); const tmpVar = newContext.getVariable(node.variableNode); @@ -909,6 +915,8 @@ register(TraversalQueryNode, (node, context): JSFragment => { if (relationFrag && rootVar) { if (relationTraversalReturnsList) { + relationFrag = js`(${relationFrag} || [])`; + if (node.fieldSegments.some((f) => f.isListSegment)) { currentFrag = js`${relationFrag}.flatMap(${rootVar} => (${currentFrag}).map(obj => ({ obj: obj, root: ${rootVar} })))`; } else { @@ -920,7 +928,7 @@ register(TraversalQueryNode, (node, context): JSFragment => { const mapper = js`${objVar} => ({ obj: ${objVar}, root: ${rootVar} })`; currentFrag = jsExt.evaluatingLambda( rootVar, - js`(${currentFrag}).map(${mapper})`, + js`(${currentFrag} || []).map(${mapper})`, relationFrag, ); } else { diff --git a/src/query-tree/queries.ts b/src/query-tree/queries.ts index 307b18e5f..0f72e8e11 100644 --- a/src/query-tree/queries.ts +++ b/src/query-tree/queries.ts @@ -328,8 +328,8 @@ export class TraversalQueryNode extends QueryNode { this.innerNode = params.innerNode; this.filterNode = params.filterNode; this.orderBy = params.orderBy ?? OrderSpecification.UNORDERED; - this.itemVariable = params.itemVariable ?? new VariableQueryNode(`collectItem`); - this.rootEntityVariable = params.rootEntityVariable ?? new VariableQueryNode(`collectRoot`); + this.itemVariable = params.itemVariable ?? new VariableQueryNode(`item`); + this.rootEntityVariable = params.rootEntityVariable ?? new VariableQueryNode(`root`); this.skip = params.skip ?? 0; this.maxCount = params.maxCount; diff --git a/src/query-tree/utils/extract-variable-assignments.ts b/src/query-tree/utils/extract-variable-assignments.ts index 500d08de6..e6c98517f 100644 --- a/src/query-tree/utils/extract-variable-assignments.ts +++ b/src/query-tree/utils/extract-variable-assignments.ts @@ -3,6 +3,7 @@ import { ConditionalQueryNode, FieldQueryNode, FirstOfListQueryNode, + HoistableQueryNode, ObjectQueryNode, OrderClause, OrderSpecification, @@ -11,24 +12,70 @@ import { RootEntityIDQueryNode, UnaryOperationQueryNode, VariableAssignmentQueryNode, + VariableQueryNode, } from '..'; /** - * Traverses recursively through Unary/Binary operations, extracts all variable definitions and replaces them by their - * variable nodes - * @param {QueryNode} node - * @param variableAssignmentsList: (will be modified) list to which to add the variable assignment nodes + * Traverses recursively through Unary/Binary operations, extracts all variable definitions and + * replaces them by their variable nodes + * + * The variableAssignmentsList variable will be modified to contain all extracted variable + * assignments. */ export function extractVariableAssignments( node: QueryNode, variableAssignmentsList: VariableAssignmentQueryNode[], ): QueryNode { + // TODO aql-perf: figure out if there are real cases where we should extract variables but we don't + // We don't traverse into loops or other more complex nodes at the moment + // If we decide to do that in the future, we would need to ensure that we don't extract + // variables assignments that depend on loop variables, because they can't be extracted out of + // their loop. One way to do this would be to maintain a set of known variables (with a starter + // set and newly found assignments), and skip variable assignments that depend on unknown + // variables. + + if (node instanceof VariableAssignmentQueryNode) { + // traverse into the variable value node + const newVariableValueNode = extractVariableAssignments( + node.variableValueNode, + variableAssignmentsList, + ); + if (newVariableValueNode === node.variableValueNode) { + variableAssignmentsList.push(node); + } else { + variableAssignmentsList.push( + new VariableAssignmentQueryNode({ + variableNode: node.variableNode, + resultNode: node.resultNode, + variableValueNode: newVariableValueNode, + }), + ); + } + return extractVariableAssignments(node.resultNode, variableAssignmentsList); + } + + if (node instanceof HoistableQueryNode) { + // this is basically an "optional" variable assignment - it should be extracted / hoisted + // if possible, but otherwise the value will be inline (without variable) + const variableNode = new VariableQueryNode(node.variableLabel); + const newInnerNode = extractVariableAssignments(node.node, variableAssignmentsList); + variableAssignmentsList.push( + new VariableAssignmentQueryNode({ + variableNode, + resultNode: variableNode, + variableValueNode: newInnerNode, + }), + ); + return variableNode; + } + if (node instanceof UnaryOperationQueryNode) { return new UnaryOperationQueryNode( extractVariableAssignments(node.valueNode, variableAssignmentsList), node.operator, ); } + if (node instanceof BinaryOperationQueryNode) { return new BinaryOperationQueryNode( extractVariableAssignments(node.lhs, variableAssignmentsList), @@ -36,6 +83,7 @@ export function extractVariableAssignments( extractVariableAssignments(node.rhs, variableAssignmentsList), ); } + if (node instanceof ConditionalQueryNode) { return new ConditionalQueryNode( extractVariableAssignments(node.condition, variableAssignmentsList), @@ -43,41 +91,26 @@ export function extractVariableAssignments( extractVariableAssignments(node.expr2, variableAssignmentsList), ); } - if (node instanceof VariableAssignmentQueryNode) { - // traverse into the variable value node - const newVariableValueNode = extractVariableAssignments( - node.variableValueNode, - variableAssignmentsList, - ); - if (newVariableValueNode === node.variableValueNode) { - variableAssignmentsList.push(node); - } else { - variableAssignmentsList.push( - new VariableAssignmentQueryNode({ - variableNode: node.variableNode, - resultNode: node.resultNode, - variableValueNode: newVariableValueNode, - }), - ); - } - return extractVariableAssignments(node.resultNode, variableAssignmentsList); - } + if (node instanceof FirstOfListQueryNode) { return new FirstOfListQueryNode( extractVariableAssignments(node.listNode, variableAssignmentsList), ); } + if (node instanceof FieldQueryNode) { return new FieldQueryNode( extractVariableAssignments(node.objectNode, variableAssignmentsList), node.field, ); } + if (node instanceof RootEntityIDQueryNode) { return new RootEntityIDQueryNode( extractVariableAssignments(node.objectNode, variableAssignmentsList), ); } + if (node instanceof ObjectQueryNode) { return new ObjectQueryNode( node.properties.map( @@ -89,38 +122,6 @@ export function extractVariableAssignments( ), ); } - return node; -} -/** - * Wraps a queryNode in a list of variable assignments (the logical counterpart to extractVariableAssignments) - */ -export function prependVariableAssignments( - node: QueryNode, - variableAssignmentsList: ReadonlyArray, -) { - return variableAssignmentsList.reduce( - (currentNode, assignmentNode) => - new VariableAssignmentQueryNode({ - resultNode: currentNode, - variableNode: assignmentNode.variableNode, - variableValueNode: assignmentNode.variableValueNode, - }), - node, - ); -} - -export function extractVariableAssignmentsInOrderSpecification( - orderSpecification: OrderSpecification, - variableAssignmentsList: VariableAssignmentQueryNode[], -): OrderSpecification { - return new OrderSpecification( - orderSpecification.clauses.map( - (clause) => - new OrderClause( - extractVariableAssignments(clause.valueNode, variableAssignmentsList), - clause.direction, - ), - ), - ); + return node; } diff --git a/src/query-tree/utils/index.ts b/src/query-tree/utils/index.ts index 8670d8de5..2242d3a0a 100644 --- a/src/query-tree/utils/index.ts +++ b/src/query-tree/utils/index.ts @@ -1,3 +1,4 @@ export * from './extract-variable-assignments'; +export * from './referenced-variables'; export * from './simplify-booleans'; export * from './static-evaluation'; diff --git a/src/query-tree/utils/referenced-variables.ts b/src/query-tree/utils/referenced-variables.ts new file mode 100644 index 000000000..67cabfae5 --- /dev/null +++ b/src/query-tree/utils/referenced-variables.ts @@ -0,0 +1,16 @@ +import { QueryNode } from '../base'; +import { VariableQueryNode } from '../variables'; +import { visitQueryNode } from '../visitor'; + +export function getReferencedVariables(node: QueryNode): ReadonlySet { + const referenced = new Set(); + visitQueryNode(node, { + enter(current) { + if (current instanceof VariableQueryNode) { + referenced.add(current); + } + return { newValue: current }; + }, + }); + return referenced; +} diff --git a/src/query-tree/variables.ts b/src/query-tree/variables.ts index b12021e50..ebebc5615 100644 --- a/src/query-tree/variables.ts +++ b/src/query-tree/variables.ts @@ -84,3 +84,25 @@ export class VariableAssignmentQueryNode extends QueryNode { )}\n) in (\n${indent(this.resultNode.describe())}\n)`; } } + +/** + * A wrapper around an expression that should be hoisted out of certain contexts + * + * This is a simpler version of a variable assignment (which is also hoistable) but does not require + * a variable. For this reason, it cannot be used if the expression is used multiple times. + */ +export class HoistableQueryNode extends QueryNode { + constructor( + public readonly node: QueryNode, + /** + * The name of the variable this node would be assigned to when hoisted + */ + public readonly variableLabel: string, + ) { + super(); + } + + public describe() { + return `hoistable as ${this.variableLabel} (\n${indent(this.node.describe())}\n)`; + } +} diff --git a/src/schema-generation/field-nodes.ts b/src/schema-generation/field-nodes.ts index 5e25d0cec..5559212b0 100644 --- a/src/schema-generation/field-nodes.ts +++ b/src/schema-generation/field-nodes.ts @@ -26,11 +26,25 @@ import { ID_FIELD } from '../schema/constants'; import { GraphQLOffsetDateTime } from '../schema/scalars/offset-date-time'; import { getScalarFilterValueNode } from './filter-input-types/filter-fields'; import { and } from './utils/input-types'; +import { decapitalize } from '../utils/utils'; export interface CreateFieldNodeOptions { readonly skipNullFallbackForEntityExtensions?: boolean; readonly rootEntityVar?: VariableQueryNode; + /** + * If true, child entity fields use a TraversalQueryNode instead of a FieldQueryNode + * + * This is useful if it is expected that filtering, mapping, sorting etc. will be added because + * TraversalQueryNode has native support for those and will be optimized better in the AQL generation. + * + * We do not always set this, because sometimes, a FieldQueryNode (with SafeListQueryNode) + * can be recognized more easily by other optimizations like those of QuantifierFilterNode + * + * @default false + */ + readonly preferTraversals?: boolean; + /** * Call this on collect fields that traverse root entities to store a reference to the root entity in the stack */ @@ -73,7 +87,6 @@ export function createFieldNode( if (field.collectPath) { const { relationSegments, fieldSegments } = getEffectiveCollectSegments(field.collectPath); - const itemVariable = new VariableQueryNode('collectItem'); const rootEntityVariable = options.registerRootNode ? new VariableQueryNode('collectRoot') : undefined; @@ -85,7 +98,6 @@ export function createFieldNode( relationSegments, fieldSegments, rootEntityVariable, - itemVariable, preserveNullValues, }); if (options.registerRootNode && rootEntityVariable) { @@ -138,7 +150,27 @@ export function createFieldNode( return createToNRelationNode(field, sourceNode); } - // there are no lists of references + // note: there are no lists of references + + if (options.preferTraversals) { + return new TraversalQueryNode({ + sourceEntityNode: sourceNode, + itemVariable: new VariableQueryNode(decapitalize(field.type.name)), + fieldSegments: [ + { + field, + isListSegment: true, + resultingType: field.type, + isNullableSegment: false, + resultIsList: true, + kind: 'field', + resultIsNullable: false, + resultMayContainDuplicateEntities: false, + }, + ], + relationSegments: [], + }); + } return createSafeListQueryNode(new FieldQueryNode(sourceNode, field)); } diff --git a/src/schema-generation/output-type-generator.ts b/src/schema-generation/output-type-generator.ts index b81a3158c..568f6211c 100644 --- a/src/schema-generation/output-type-generator.ts +++ b/src/schema-generation/output-type-generator.ts @@ -7,7 +7,6 @@ import { Field, ObjectType, Type, TypeKind } from '../model'; import { NullQueryNode, ObjectQueryNode, - OrderDirection, PropertySpecification, QueryNode, RevisionQueryNode, @@ -232,6 +231,7 @@ export class OutputTypeGenerator { skipNullCheck: field.type.isEntityExtensionType || field.isParentField || field.isRootField, isPure: true, + hoist: field.isRootField, resolve: (sourceNode, args, info) => this.resolveField(field, sourceNode, info), }; @@ -259,6 +259,11 @@ export class OutputTypeGenerator { return createFieldNode(field, sourceNode, { skipNullFallbackForEntityExtensions: true, + + // we expect that filtering, mapping etc. will happen, + // and traversals are better optimized in that case + preferTraversals: true, + registerRootNode: (rootNode) => rootHelperResult.registerRootNode(rootNode), }); } diff --git a/src/schema-generation/query-node-object-type/definition.ts b/src/schema-generation/query-node-object-type/definition.ts index ca5a4b03d..cb5085962 100644 --- a/src/schema-generation/query-node-object-type/definition.ts +++ b/src/schema-generation/query-node-object-type/definition.ts @@ -65,6 +65,12 @@ export interface QueryNodeField { * Pure fields are assumed to be pure all the way down - the purity of nested fields is not checked. */ isPure?: boolean; + + /** + * If set to `true`, the whole field (including mapping logic) is put into a HoistableQueryNode + * so it can be hoisted out of loops. + */ + hoist?: boolean; } export interface QueryNodeObjectType { diff --git a/src/schema-generation/query-node-object-type/query-node-generator.ts b/src/schema-generation/query-node-object-type/query-node-generator.ts index 975b2e6e4..a8bfc9364 100644 --- a/src/schema-generation/query-node-object-type/query-node-generator.ts +++ b/src/schema-generation/query-node-object-type/query-node-generator.ts @@ -1,10 +1,11 @@ import { resolveReadonlyArrayThunk } from 'graphql'; +import { DefaultClock, UUIDGenerator } from '../../execution/execution-options'; import { FieldRequest, FieldSelection } from '../../graphql/query-distiller'; import { BasicType, ConditionalQueryNode, - EntitiesIdentifierKind, FieldQueryNode, + HoistableQueryNode, LiteralQueryNode, NullQueryNode, ObjectQueryNode, @@ -21,13 +22,11 @@ import { WithPreExecutionQueryNode, } from '../../query-tree'; import { groupByEquivalence } from '../../utils/group-by-equivalence'; +import { RequireAllProperties } from '../../utils/util-types'; import { decapitalize, flatMap } from '../../utils/utils'; import { FieldContext, SelectionToken } from './context'; import { QueryNodeField, QueryNodeObjectType } from './definition'; import { extractQueryTreeObjectType, isListTypeIgnoringNonNull } from './utils'; -import { DefaultClock, UUIDGenerator } from '../../execution/execution-options'; -import { FieldSegment, RelationSegment } from '../../model/implementation/collect-path'; -import { RequireAllProperties } from '../../utils/util-types'; export function createRootFieldContext( options: Partial< @@ -137,14 +136,21 @@ function buildObjectQueryNode( selectionToken, }; const fieldQueryNode = buildFieldQueryNode(sourceNode, field, fieldRequest, newContext); - if (selections.length === 1) { - return [new PropertySpecification(selections[0].propertyName, fieldQueryNode)]; - } else { + if (selections.length > 1) { const variableNode = new VariableQueryNode(field.name); variableAssignments.push([variableNode, fieldQueryNode]); return selections.map( (s) => new PropertySpecification(s.propertyName, variableNode), ); + } else if (field.hoist) { + return [ + new PropertySpecification( + selections[0].propertyName, + new HoistableQueryNode(fieldQueryNode, selections[0].propertyName), + ), + ]; + } else { + return [new PropertySpecification(selections[0].propertyName, fieldQueryNode)]; } }), ); @@ -278,7 +284,7 @@ function applyListTransformations( // this is actually functionally required because otherwise we would not have access to the rootEntityNode // (needed for @root fields) if (listNode instanceof TraversalQueryNode) { - const itemVariable = listNode.itemVariable ?? new VariableQueryNode(`collectItem`); + const itemVariable = listNode.itemVariable; const rootEntityVariable = listNode.rootEntityVariable ?? new VariableQueryNode(`collectRoot`); const oldInnerNode = listNode.innerNode ?? itemVariable; diff --git a/src/utils/visitor.ts b/src/utils/visitor.ts index f2f4c4037..e019fc601 100644 --- a/src/utils/visitor.ts +++ b/src/utils/visitor.ts @@ -1,7 +1,18 @@ import { isReadonlyArray } from './utils'; export type VisitResult = { + /** + * Whether to recurse into the object's properties. + * + * @default true + */ recurse?: boolean; + + /** + * The value to assign to the property + * + * Use the value of the `object` parameter to keep the same value. + */ newValue: T; };