diff --git a/.travis.yml b/.travis.yml index bc50d38..025a1d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js node_js: - '0.10' -- '0.12' +- '4.2.3' addons: apt: sources: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a7fe3a..192bdc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog +## 3.9.2 + +- Add `EMAPNIK` error code to errors returned from `source.profile()` + ## 3.9.1 - Updated to use tilelieve `~5.12.0` diff --git a/appveyor.yml b/appveyor.yml index a3eb9d6..e0cb132 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,6 @@ os: Visual Studio 2015 environment: matrix: - nodejs_version: 0.10.40 - - nodejs_version: 0.12.7 MapboxAccessToken: secure: 01rO70zKIKzh2l8htHugNS3cCk9u3LfTu2SXojFaYkveumhZRDgRrH/BroS+fIv8T6YB5l0P2nvKAjqhdDW2yuaLWGIB5KdBmhywp4dXa0g= AWS_ACCESS_KEY_ID: diff --git a/backend.js b/backend.js index 86348f8..6c93aad 100644 --- a/backend.js +++ b/backend.js @@ -3,6 +3,7 @@ var crypto = require('crypto'); var mapnik = require('mapnik'); var util = require('util'); var sm = new (require('sphericalmercator'))(); +var queue = require('d3-queue'); module.exports = Backend; @@ -75,7 +76,7 @@ Backend.prototype.getTile = function(z, x, y, callback) { var size = 0; var headers = {}; - var lookbacks = 0; + var lookbacks = true; // Overzooming support. if (bz > backend._maxzoom) { @@ -85,6 +86,20 @@ Backend.prototype.getTile = function(z, x, y, callback) { headers['x-vector-backend-object'] = 'overzoom'; } + function loadAsync(lz, lx, ly, callback) { + source.getTile(lz, lx, ly, function (err, body, head) { + if (err && err.message !== 'Tile does not exist') return callback(err); + return callback(null, { + err: err, + body: body, + head: head, + z: lz, + x: lx, + y: ly + }); + }); + } + source.getTile(bz, bx, by, function sourceGet(err, body, head) { if (typeof backend._fillzoom === 'number' && err && err.message === 'Tile does not exist' && @@ -96,13 +111,23 @@ Backend.prototype.getTile = function(z, x, y, callback) { return source.getTile(bz, bx, by, sourceGet); } else if (typeof backend._lookback === 'number' && err && err.message === 'Tile does not exist' && - lookbacks <= backend._lookback) { - lookbacks += 1 - bz = bz - 1; - bx = Math.floor(x / Math.pow(2, z - bz)); - by = Math.floor(y / Math.pow(2, z - bz)); - headers['x-vector-backend-object'] = 'fillzoom'; - return source.getTile(bz, bx, by, sourceGet); + lookbacks === true) { + lookbacks = false; + var q = new queue.queue(); + for (var lb = 1; lb <= Math.min(backend._lookback, z); lb++) { + q.defer(loadAsync, bz - lb, Math.floor(x / Math.pow(2, lb)), Math.floor(y / Math.pow(2, lb))); + } + return q.awaitAll(function(err, data) { + if (err) return callback(err); + data = data.filter(function(d, i) { + return d === null || i === data.length - 1; + }); + headers['x-vector-backend-object'] = 'fillzoom'; + bz = data[0].z; + bx = data[0].x; + by = data[0].y; + sourceGet(data[0].err, data[0].body, data[0].head); + }); } if (err && err.message !== 'Tile does not exist') return callback(err); diff --git a/index.js b/index.js index 08aa03c..5b1be93 100644 --- a/index.js +++ b/index.js @@ -341,7 +341,10 @@ Vector.prototype.profile = function(callback) { if (queue.length) { var t = queue.shift(); s.getTile(t.z, t.x, t.y, function(err, run1, headers) { - if (err) return callback(err); + if (err) { + err.code = 'EMAPNIK'; + return callback(err); + } s.getTile(t.z, t.x, t.y, function(err, run2, headers) { if (err) return callback(err); t.drawtime = Math.min(run1._drawtime, run2._drawtime); diff --git a/package.json b/package.json index 2c0c65f..9cfb841 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tilelive-vector", - "version": "3.9.1", + "version": "3.9.2", "main": "./index.js", "description": "Vector tile => raster tile backend for tilelive", "repository": { @@ -14,14 +14,15 @@ ], "dependencies": { "aws-sdk": "^2.2.30", + "d3-queue": "^2.0.3", "s3urls": "^1.3.0", - "mapnik": "~3.5.0", + "mapnik": "~3.5.8", "tilelive": "~5.12.0", "tiletype": "0.3.x", "tar": "~2.2.1", "request": "~2.65.0", "numeral": "~1.5.3", - "sphericalmercator": "~1.0.2", + "sphericalmercator": "~1.0.5", "spherical": "~0.1.0", "underscore": "~1.8.0" }, diff --git a/test/expected/backend-l.2.0.0.json b/test/expected/backend-l.2.0.0.json index 848a73e..b87b0f6 100644 --- a/test/expected/backend-l.2.0.0.json +++ b/test/expected/backend-l.2.0.0.json @@ -5,7 +5,7 @@ "extent": 4096, "features": [ { - "raster": "ffd8ffe000104a46494600010100000100010000ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828ffc00011080100010003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f99c519a4cd2e78ae93103452529c628108681451da90c28cd1450004d1484d19a005069d4c069c0d30168a3345020c52529a4a0029451450028a5cd369714c033485a971498cd201a4e68a7eda4db4582e36956976d382d160b89494f229a7814c043c0a849e69ee738a654b290940a5a5000eb4863e90f1452127bd31067279a526994b9a403b3e9467f3a6834ab400bf5a3348d4940051451400b9e69734da2801c0e6941a677a7d310a39a5a4029c0531094e02940c5761e0bf01ea1e28b59ef849159e950388e4bb9bee87232140ea49a7b6e238f0296bdff00c3fa5782b41d3f4fb7baf0f8d6eee65cdc4f33ba329f65e80633dfb545e2ef863a4dde9bfdb1a4e997fa5d9cee24472e244546036f071d79efdbdeb3f6f04ec572b3c171462ba2d6bc2979a6d9cb781e39ad11b696070c0670091ffebae76b44d3d5121451d4e2bd37e1af83f4eba68eef5b437a5d4490d9c2ff00794673b8f183c7033f5a1bb01e7fa4e957dabdec769a6dacb737121c2a46b926bd5b4af80dae5c5aa4b7975124a705e080091d013819e4753fcabbc8b43bbd5f50bb87c32b059c714664f2d1443248067036939ce00e01c7be4d765e21b6f12c1a1c12d95d41776ad6b23bcc54465e318720e0020f27e5f5ac6556cae8695d9e1175f05f538e56b689ee85ea9198e4b7c2ae471960c7f4af3df17786751f0bead269fabc3e5cebe9d0d7d670e817975a7ff6a6a7ac94d626950db35b380aa0907cc3952e71ce78e3f3af32f187807fb79268b4d925b9d4448656b99a4f3495009ea3b67dbdeb158a4a494dee5723dd1f3d3fa5308eb5b3af68975a1ea32596a1185990f553953f4359320c1aeadd5d093e83568ce4fb521e283c1e290c79a6d38f4a6d0c10868a0d14000a507149466801c69b4668a0029474a4a05002d14a3ad2e2801169ea33480669ea2a9213628152c10c93cc91411b492b9daa8a3258fa0151815d5f86e5bbf0c3db6bb0476b705ff77192039b773d0943df00e33c1a6dd893acf869e07b24d74a78f2136d6d2c256159091873c65b1f771d79fa57a9782acb4dd0525f086a2a66b65977c7228df0dc0671924601edb41f634dd37c450b41629e2496dbec258cc969f31cb39cf9785e7183939e06075c0af5ab78fc1d63a65c4f19b692d12244b978c89942a0e0bb283d3824fae2b963579f565b858b8de16b76d520bb8e1b64816cfecc4633ea01f7e0f5273c0ae4fe20b6836d6969a6cb7525c2d82a85d36027f7ac48cb391d30b938279cf3555bc63a9ea369347a6cc52de71e5dab18c2c8f1118de5792ae7a83d08e71d2b84d66d0594b22d9db4f35ecec72eea6595db192072303039c600ee6b9ab6212f760aecd230befb167c551687a83de6a7736df60d300cbdbf054201dc74c9fe600af16f0dfc3ed43c56f797fa722dbe96923152dcb05cf4c67ae08ea6a2f195feab7f3ad9b5e3ddf920c935bc0acc90053c6e3df1dfb0cd7d3ba5f84efe3b2b2d46d6c63486ead61134568554630086e99efe878fa5387b5a30e6ddbfb909f2cddb64785f873c05a6697e31806a738bcb086511ce8d16ec074f95b1dce4f4c7515df59470e956971696908b569258dec8db8119b7b918e0e78d87af3e9835e82be18c4536a074c9a4d4279d25dd32ef5e300e41e8b81d3009ddd6afbf81efee755593cd48ed1661956c302832ca403dc13e99e4f6ad15593b2fbc970d19a375a43eb2f61ab1b55835ab2f2c90c998cba939dac3ef29dcc3fef9ce08a6f8cb539a6b6bab77d3678e15b71e6b49b46d5638c839c76edf88e2bbab78fca8238f8f9540e0607159fe21d1e2d62c24824da24da446ec81b612319c1ee32714ab45ce364cd29da2eecf0bf14ea3ff0008fdec09335c9bd98030d9c318925c1fbb855391c7d2b9e97c506277b8b6d335537cbca4725bf9441f76e87f1af5b97c071e8f34ba8dacb235fe1a66bc924f9cbe001920676a8dc42807a81ef5e5d1e20bab9b6beb9990de49b5a7955da4752c37601e0123279391d4f18ae1787a707692375cf2574cf1ff008849afeb9aa497fa8dbedd8a156304165183d7df835c3dcdb4b0b6d9e2922623203a953fad7d4be15f06c9a8ebda86aba3c1e6c4d2ff00a224ec76e23c04918f4209c9c0ec3e95d8fc7ef0f68179f0ee797c473db5aea96d0192dee91026f9547dc1ea189fbbfe15eb529c79545238da6db67c3ac3b50bcafd2a5957bd44bc1ad5ab30b8f229952114c6143121290d3b14d3486145145001451450014b8a414e1400014f029053d4552426c502968ad8b8f0ceb16fa143accd6132e9929012e31f292699252b1b479ef2de120a094820b7031ebcd7b8788fc2da96a1f0e44b2fd84c31dc044920fbcd8518738e307383dc1ea3a57917fc24534cfa57da228dbec4a62071f790f63f857d3bf0ebe217842d7495f0e5cc96f2c13026448e3778c066202331fbc471f300073d38ae7ae9b69f634a67806837d3e97ac5b0bcd31aeded033ee822129701b6ee656ea01cf07a9c66bb8b0d67c69f106d7ec50c72ad94ade537cc91a85527e558c003773d48c66b47c65a33785fc4d7179b2d9ad2d9097f2d88f320918104371b8af5c1eb9aecfe12c377a4f8b3ced39631657d0ef9c4ceca91904e6418e18b01d3dab89574e56b1b3a76573d1fe1df83d740b14b9d4a59a7be553b84cdb842dd0ed200c8c018e3e9d6bcbbf683f1ae99a369b73a768e211abdcca184d01e029ceecfbe704fa923d315d47c4cf8b5a7e8905d5ac5757505f5b9cacb0daf98aed8f947ce3182783c8f6af91bc61e207f12eb2f7ef6e96e5970510e72dd598f03924935d94e9a7b2d0c6523e9ef83de0f3e0df0dc97578b149ad5e949a633a83f2156063dddc7cdc8f5e7b57b3f853eca9a2dbdbd846b0dbdba089615e91e00e07b7a73debc1bf64fd3750d5749d62ff5cfb45d69c5a3b7b43712b30ca64b0507b0ca8cfe15f46db411db42b14281507402b2e5a919be67745ae56ae913514515a0c28a28a004232083d2bc43c67e1592cbc405e4959ede6cb44f924c7d8827d4e7d6bdc2b27c49a67f6ae952dba6df37864ddd322b0c452f691d3734a73e5670b6da83d90926d1adec91847f64b41757422fba067e5208c64f20741d3bd7cb3f1a3c7faaf8cfc42f0df18e1b6b26312c16f3b490b3a920b8ec7be0e3a57aa7c6e923f0868c2182dedb52bbd46292de4674252d4e325e31d37727271c71d2be66aeac346d04dee734dfbcec079155c8f9aac1e950b75ada44a1d4d232714e34d1d6818f0b814d7e9c53f34da1888cae0669b5239f96a3a96520a28a280014e519a4a923142063956afe8f62b7f7d1452ce96d0160249dc12a83d78ea7d055bf0be8736bfa9ada4322c2806e926704ac63a64e39249c0007526badd5ad1fc0da9c36fa6cd73730b44b35e128006c670548ce072719a1ce29f22dc5caed7e86478eb44d23488ec7fb1a5be943261e6b98bcb133739641d80e3afad755f0f75cd3d7428ad75ed737c3b8c71594a1b6c273f7c9e98c76e39c5729f103c4a3c537b15c5a593db59db208c0ebc9ee48ee4826b2afa5b484da5d69be5ef6882cb132e42be3938350e0ea43965a31df96574759ff0008ae9b7badeafa6c65e1bac24b65b4160e0f5c01d477fa5741f05b5fd0bc3fa86a565e29b6b06fb345379724d9f99b18c018e4f18cf079af39d1b50d6ae75eb56b192f2e2fc8102470bb091d3a6c18e718e38a66b02dff00b5a38aef4c9b4bd80acf192c5cb64fcd86e47618f6f7a9706fdd93b8d492d51ea3aceb5a778d7c657b2dcea19d336c69145bf697c28c741c90001f5af6ff00823a341126b41ae26bc489840ad7037285e4900f7fc315f3dfc30f07dfeb1a59b8b0d2a4fed4b7996ead6e0a12b2460e082076cf1f8d7baf806e753f05e89a92cfa2cb78cb1bdd5d0865552ac3270031c9f941f7fcf8e3692ac9266eafc976701fb4fe9fa168765696f616d243a9dd30323a4e5048a0924bc78c1e71839e31c7be7fc3cf823ab4f6b61a9dc5ba3b5e44b2c4f36d30c48cb9cb0e4938231c75fcebc6fc61aaddeafe21bfb9bb59e2dd3c852da676636e0b13b067a6338af60f811aafc40fb0edf0c5c477ba742fe4adbdddcae223c31c459dc5707b63f435db521ee593b18425adda3eaff0e68b67e1fd16db4dd3a158ade1180ab9e4939279f524d6a572df0daf35ebef0a5bcbe2b8e38f54deeae51360600f076f6fc3d2ba9a8340a28a2800a28a2800a8e67291b3280481c0271cfd6a4a82e668e20825380ec1467d7b5007c9ff00b46788352babed4ada7b6b68ad2d2e4c50c912e2472e98258f7e011f8d7cf75edbf1a52e6db50d63eccd61359c370ed2090e66dce4a8c8e84f3907b578956f4649c74319269ea1daa1638353678a81fad5c84879a402a4c0a5c5160b8d23029a3ad3d8530f0334302390f38a6d04e4d15050514528a00551935328c5449d6ad410bcf32450aee91c85551dcfa552133b9b3d7b4787c3f6f65a5412c1a918f63bbe023bb70cc4f5e07afe15d17873c35378dac27b99ee8095f0a9b0e36a64800004e1782718cd79dddf85b58b582295ecde449300795f3e09e80e2b4b4af12eaba7cf0e9da85f5c595bdb3e4aac237ab0040047e3d79c571d48369ca84b5fbcd62ecd2a8b43a4d03c2b7b77a46aba084113aca5bcd2a76c9b7a1cf723d3b73eb58d6b636b697d3681a898bcfb6b80f1cdc2071c6e058f438e4678f5a9a6f88f7f6eab6fa7a45240ae5cc9711e5e43effad721aa6ab75aa48ef78eaecd234a4ed00e5b19e7d381574e35657e7d13264e0b6d4f43f155aff64e93a4eafa532ff69c174025c5b2f0fb4365b2383f7573f535d17853544f889e20d5adbc45a2db7f6e4768b25a489ba229b48254eedc17ef020907bf5cd7977fc257a93c1a44372b0cd67a64ab245094c2b118c862392085e6bd022f8a66cbc747c4e7409edad2fac96da48c1c0765607cc56239c74c7eb594a95451b6ef5d7f4294e37b946cfe24f8ef43ba974ab342a4efb758560cb1f70500c91c1c8e3bd6ca78bfe28f82ac67d4b58d3ae2dad6f616b749a7b608b1b123f78428ceee70377073df15d568df1dfc330c51cda8e9f7af711cae6344854ed5e80e777523ae3e9cd65fc4ff008f563e2df87d79a25a585dc17d74e11e460a13cb0d9f5272401c76f5ad69734be2858995ba33c0afaea7bebc9eeeee5696e677692491bab313924fe35b9f0fbc4517863c5167a95ddbcb756b1b7ef618a66899d7d320fe87835cdd2138aea7a991f45ddfed3dab04816c745b24daf972ecd864cf000cf071debdafe11fc58d23e225b3c50afd8b5785774b66edb8ede3e753fc439fa8af828364576bf083c6337823c7167aa4682481b305c4678dd1b63383d88c023e950e09ad0a52699fa114536360e8aca72a4020fad3ab0360a28a2800accd56c3ed52c52b3b048be6d8bdc8e7ea7e95a759fa96a36b6d1949e5d9bc1507a0cfa67a6693b5b503e19f8cfa3c5a4788bccb6927962bd4f30b4a002086e9c139c0c726bceabd1fe2e5ddb7fc2433cfa75ec5730dc29cc580701bf8b038078f624f3815e6b236056f49fb9766325ad8477a8b393cd079a4aa6ee348b5455ed5edad2d6eb658dd8ba8b1cb85239fc6a8d5a77572029ae9ba9d52430cb312228d9c8eb81d2876ea0526183495b93e8776aaaca824c8c9d87907d2b25e120f2307deb34d4be165dfb90e29c06697611d69c169d82e228ad6f0f5b1bad62d62c3637ee6dbd7039359a16aee95a84da5deadcdbedde0608619041ea28927cad477126afa9ec715d8b2885cccc63862f9cb004e0f03fa8ac8f10f842fbc4e45edbc4a97cecb1ac601c91939691ba02003d3a62b9ef12f8c6df51fecf86ceccf936f20964599fe5988ec40e71d7bd7a8f8725bcb8b7197b1b433ae22ff004856209eea7232dec33c578ae1530a9544b5676f346ade3d0f27d07c157775afdad96a84da4125d1b3926003f9726d257be08246383eb5a5e36d1adef3c776da3e956b6563325bac6c158a45348149c8cf20b70003ce4d7a76b11c496f671349249e44f1dc46c176c8aea49e847d7391debcb7e294467d521d46d619823a65a4c7039e3e95d586c54abcf5d3430ab4941686ff00c44d2dd7c19a6ddc5a64364cebfe928a9f748c631d7f135b9e34f889676ff0e1344b6c7f6a3dbc70a8f28ed48ce4330cf1f740e9ebed5c443e2fd4b5bf0ed8f84258a36b99e616ed7370c7214b2ece73c1ea093db1deb0fc73622d3508a412b3ee5f2cab1cedd985033e98c53850f7946aee9b681cfdd6e27a7eb5e12b0f0cfc31f0fda0d2a29359d75d3ed3773c219e2057795466fb876ed031fed1eb552f74bf05e8a9a6de5fe86f36981becd72be792e770cf98194e7782a78c01ce2baef1cf886cfc67e01d2cc7a6de5adcc32c5340b3ec092009824306c118271d08207bd50d7f5bf0e5fe836914b6935bdddb304408814950b8249e84e33ee4f23ad60ebcd495df577358c138bd0f25f893a2e9b61a9417de1bb5d4e0d06fa312db7db61284724101b2430c827aff002ae31abe95d4a587c53e0cb7f0d810fd8c3e219e50239227e769233b49e719c038cf1c9af13f1e7842efc2babc96d20926b6c068ee0a615c7e048eb919cf38c8af46955551799cd3838339653835346c564561d8e6a0c73522f4ad910cfd03f835e2787c4de05d3e55706eed635b7b84ee195400c393c11820fd6bbaaf8b3e07fc459fc3dafe9d6d22adbe93314b699cc7904923e624606476ce71935f698ae669adcd53ec140a5c514144538631304fbd8e2be67f8a1aceb7fda10432cef6d7003ba6176a49824847e9bb1db60fcf9afa33c405c68f78d148d13ac65848a70531ce7f0ebf857cd9e3df105aead3e9fa36aa905c4faa5badca6a42dd9081c91f2b72a41e72bc75ace7b6a0b73e76d73519b53d4a6bab9118918e0ec181596dc9abdac5ab586a97966ec59a099e22c7bed2467f4aa4466bb5249591875b91e293152ede339a692052b0ee587468dca3a9560704118229b5e97e27f0dbea16526a060f2a50a5fcc5000600771d87a7f8579fdee9f756210dd40d1ac9ca31e8df435146bc6aaf31ce0e232d2cee2edc0b785dc670580e07d4f6aefed34a8ad61091a228c0dc477fad71da16af369d218c1cdb48c0c8b8ce3b66bac5d4918a342ed27cbdb0067dbd7f1ae2c6ba8ddba1b50e55abdc7c96e41e090073f4a3ec29763c992dc4a4f52c39c0e49cf6a7cfaac413e466ddd36b20247e22a3975276850aa2c6c7aede3757245496b735728156ff00c2769e4036efb59b2c0eec91ec41ede958b1786a5fb798a59556dd5779940e4fb007bfb56a1ba95b219db0dc900f53eb52c371232b4721ddf2b72dc91c5742af522b4662d41991fd956d0ce4297718ff009683ee9fa77fad4b269115cb47e532e56264009ea71f29cfd4fe953a9380bdbaf4f6f5a0c8f1caae9c3678f6a3db54bdee4a8a1d7fe079e3d352e6ce75965507ce89fe5edd54f7fc715d078793424d2acacf54f0f5c5bdf4e0c5f6896dcbac8e39dcac5860918e0715506b8ed10b672bbd9bccc28c9ce3ff00ae7ad54d4c3ea168b6ff006a911236dc1548233ffd6feb42ab39ae5a9f79ab8c56b13aad675a82cad95c5c08bca652898f9b38e3683dc6073d6b2a6f12c52d8c8e5a267c1df0cff2b1e7278f5209ae71349fb1b24f04d29914e1c93d41e0e0f635726d26cefd419032480eddca403fad44614a9b4db7ea29394909e14d14dcdc36a6d791437b04e935bc7c4b923e6c328391db19ab9e24986b7a78b8789a046dd214382c08cfa7f5c1e69fa669b6fa7d95c794dbc4840264009e9ea06719abb0aa430a46ab198d060a11904f73eff8d693afcd3e68eb61420edcace3b4e7d52c352b7d367965891c0da9c380adce541e39ad8f1049a868f716f14b243345749c2ed0bcfa30edd473e9dead4f0abeb02ede4428b1ec8d4e418f04f03d4735cff8c255fb7dbbc536e91472bd718e87fcfa56f16aacd5d74d49778459dafc37f16ff62dddbcf711437d6e11e392097e65951b2ac08e7071839c7a7bd75babdf691e22f096b70132db5ada27da2de39d83950303cb2c304a8ec3fad78e41ab59c3a35a5ad9da31d44b93349d3712df28047e15e8de15d4adf4eb8537f0472c3b54b2a36e5009ced3f502b3ac9d27ccb61539737bb23c5240031c1c8f5a16bd7be287c37b4866b5d4bc172fdbecafd5a65862520a7cd82a1792307b1e9c735e4382ac558608e08aee84d4d5d19c935a33abd0b5f8ac3488ed6d22956fda6c316daf0c88d9cee4618c8f9707b63e95fa07a1c92cba3d8bdc0c4cd0465f391f36d19fd6bf3dbc24a17cd9a395167475d8a5371ce090476ea2bf40bc2976fa878734cbc9a48e5967b68a4778feeb3141923f1cd6326b99c5171bee6bd14551d5754b3d2ec2eaeefae238a0b589a69598fdd503249a4591eb56d6ba8e9d35a5e31104ca558a9e40e86be58f8e87c07e16b73a5695a741aaeb92aee6bb92e6432db91c7cc5480381c2631ed5e75e37f8a5e22f11ea7a8187509ecb4c9e76923b5b7628141e39239c9ea79c649ae01b2cc49249f535b469db73272b88ec5d8924927924d369d8a42315a12349f96a3eb52374a8aa58d1dff873c66d6db2d3514cdb33317b8c969067a67b115078db59134874fb49219ad0057122a8cf4e83d2b91a9237540c1a3470c3a9ce47d2b3587829f3a43f68dab33a8d06ef495d2cc734314571cac8cee49907b0c7f5ab45e016ac2c510468768651df3d8d62786f4e82ede492ec6615c20192393d4e47a0adb960822711da47e5c18dc493924f4fc38ed5c3888c54da4ddcd232762ab3aefcb65db3fe79a566dcdb883b7d3d3d8568e8da44daa4efe5911c1191e63852e541ce3e51c9e86b6924b14927baf0fe9e27b2b7db1f95a8059249c91f36517f3e3a7ae6b3485a1cab0050374078c679ad348219763a4c11c80037503b73572e349bcd4b476d6f4fd32286c23f9266866dea1c60648249427838fc4573cebf2eec9009ed4dab0cde874559e22c9709f2e49c10781f4acdbeb2303a47214657018143d47f4351594ef6b2a9604c6f8f607dc7e35b5ab2457168650eab32287f2c7539ea71e98c7eb49c6db0ee9a38f6b36170e4fca3040119c6476ff26b46003185238edda9176bf38ce3b52ed448e328fb9c9231b79e3fc9a6e6e5a312d352e2c8de6156e431fcaa5898e7a0e0e3dbf0acfb77577d8ebb5339cf73f855c94ba5b6d85943907048048352d74358cba9335c796c00919d40dccbd87d7b559fb5a1fbb8c360f07358993952460f3d6ab6a3a82db425506257521769c6df7aa8439a5640e492b9b9a7da45aa6aa2c2e6e1b11dbcd70258d32c182fc9c03ea7fc8ae335ab1b8b1bc2b74065c6e561d187b54ba06bb7ba16a0b7b62ebe70cfdf1b8138207e59cfd40a7de5e5c5dc02d12f9aea371f6a97cd50bb640a4b00c793c7d327b74af46109539791cf2929235742b0d3ed5ad6e6e6f3f7ae3242904283c1e3a9c035d66b36867b999e15536c316f0dca20457550070b9c8c67b8f5ae022f0f6a372b0c96d14722caa0aec71c6467073deb5749d7d60b73a7eabe742ea4af9ca32c8474e3ebdbd2b9eb53737cd177b154da8e8d178788b59f0b6857ba2dca3837b166091f91e531392be9923afb57046ba4f186b52ea9f64b794c320b4de893459db20273919e40e7eef6ae618f35d54d5a376b53396aec771f0b7c4b3683aa5d4515bc170b7b0988a4d089541eb92a78238c62beeef06dcdadef85749b9b08a386d65b68de38e35c2a02bd00f41cd7e7069d79258dfc1750edf32170ea08c8241cf35fa0df093c4361e23f0269975a7cd1bf97108a544409e5b8eabb4741e9ed51523af31707d0b5f12bc569e0bf075feb6f099cc0bf247b80cb1e17a919192338e719af877c6ff123c41e30f3d7539d22b79a7f3de0801542d8c0ce4938006319c7e35eebfb60f8a6faced34ef0e40152cef90cf3302097dac30b8c71c806be5366f5ab82495c993bb1fbb35734d9d2def229648e39029ced933b73ef8e6a82d3c1c55ee893d4348f0d58df092761632cf7ac7c98fcd54dac586001c2a8e7a9206338e95ccf8fb4a5d1f541673c4b05fc636cf0abab05e0633b4900f5e335849ab5e476ed0acedb1883cf247d0f5154cb9762cc4924e493deb0a74a519734a572e524d59218fd2a302a7dbbb3d29bb706b76894c7a9c8cd2d565622ac2b03de9a771346d685a8c360c37b4a43e778c70be8473c9eb5d8c0d6d269c675666966019001ce0920e7f0cfe55e6b5aba3d8dc5c133c92b5bd8c58f3276242a8f41ea4e3a0ae6af878cdf35f5294da563bfd235b3e148af2fe38a690980c51100ec594fdd24f1f77248eb838acb8fc6afe1bd3045e18d42ea0d4a62924d730aaa045c366204f2dd5493c7208e700d616abe214bab79ed98c9f63562d0a00aa5db18dee79ce07419e3f5ae4e4937f03a52a549457bdb8b767b47843e2f693a76a56d79aa786c35da121ee6c6e0c45815c1ca636b64e4e38ea6baed6f4af0dfc4244d7bc1e069d6a030bf81b68f224c9da4a83c06033c7a67b1c7cd02b4f46d4ee2c25748e6912098049903101c0391903ae0e08f71553a5192b243bb475da8d86a1a7df5d69d788f05cc04a3c2c71b483d31d3a60823d4566b493870f212768c1c8e80e4577d673d9f8cf46816e26964f115a1937ba8526ee2c82a49272cca030c7b0ae552f160c6f1e65bcca51f7a8cb2938c8f7070723f1ae29269d8a4ee66c7d73939fcea64d9e687008908dbd7b1a8ede096542631bf048c0eb4eb82e92f96c3050e3a608ef58df5b215c1d5da666546f720640f62698acc5b2a7047afeb52fda0a9f9c97edc9c60d5699cb15dbf4ff1ad56a5dd58bd115933bc00c0e063a74ae56fd99af26ddd4311f857451b67046720f349aa5b26a291b6fd92a64640c823deb4a1555396a4cbde472d4559bcb396d1f128c83d1874350c486470abd4fbe2bd2524d5d191dbe9733c1a6da875c61002a3b552f19456f2431dd4308f30b00ee382463bfe95168b705ed14cc4b18db683dc8ad2b93be325412bc1231d41f5af3399d3a97376ef1b1caff654e7423a98e6159bca23b8e3afd33c564c9c1af4886e217d1a7b4750636c82b9c0ede9f87e55e797516c91d7fba71d2bb2955f697b99b56b15eba8f0b78e35ff000d5a5c59e93a94f6d6772ca67890f0f83c73d47e15cb9a01c568076df157c713f8f3c430ea77286331dac76e14fa8c96381eac4d715d4d275a728a0070f5a09a4269a79e05310e1cf4a7018a451814ac703de988703e94e518e48a9b4e08d3aac8321fe5cfa67bd6c78a2d6081a3787386e1428014281fcea5d44a4a3dc76d2e72f8e7152471b13d29a2ea50b85dabee1467f3a8de491ce5dc934ae8ab1a3e6dbda9524adc3f39539da3fc6a3bdd56e2f08f39cb28fbabd02f18e00e074159f4b45ee1ca8733963c9a3b74c53680690ec3c5381a68345508ddd12fcda5cdacc656088ff305254e3ea39e6b6f57b61e65bce9fea274de9b47dde791f51eb5c5a360d76fe12d72c60b1fb0ea96a2e6c9dc33153b6588f42c87a74ae7ad0d39913b31ba65b4b234df6775578c0396202907381f5cf00ff2e2a4b583ed370cb725c4807423a71c53ae8410dfbcb652b14525a225792993d7df18cd6a5aea0351d523927c34ac9b598e327032327f888ec7d315e7d4d22da1b57467dc6952ae761dc3ebc83f4aa72e9f2dba6f930a091d0e7f4af401660c07f76d93c9c8c0fceb36fadc385c80dcf4c038ed915c91c43bd872a7289c7ec52981927d48e3f0a8d5d957920f38eb5b73d818e095b70000c9ebd7fc6b9d20e78eb5d9092992997d1d268f6ba86f50466b2f56b211cf0cc2202d8b7964af1cf5c7e46addb3e18920fb923f955891a29800f18600e707a67b5690a8e9bd362ee9a1c84427ca58d5625185e6a65965504a1240e0f5e87b55291c93f29008e01c714c9e660bf7f685c1c9e292d42e8b514fb25611e0a720641e3f0ef546eed63bc46c20f380f95b38fd2a117ea72bb5bd72475fa7345bddbcf3ac76ea4aae4b12074ada309c5dd6826d330654c64771c541d2afdd452472132a152c4919aa4ebcf15dfbaba250dcd3d48c5459c52e695cab0e269334a3a534f1408915b0b4e55ddce6a06a9627c803d284c1a3acd1ec2d97497ba7512b146382b8da467a1ab5a75b4baae8ad15cf1c8f298738007f8d732f7d7325ba40d3379483014703ff00af5bba66b52c56e20b4b769dd5739e9f901dab9ab539daeb7bfdc66715466928ad4dc7514829698051451400034ea68a75310f5ab366fb2e6339fe219aaa2a7b3c1ba8c31c02c3354f6259e9fe17b18a48aedaed4b5b44a1083918ddc920f638c55268521d5d8e9e18a315785867729c838c7a9e98adef0658a6a705c5bca1a5791b7a8420fa641039e463b7e55d247a119753f36ceddde523e68947cbb402724f6e3a91d2be76552d3773ba3439a9a6ba15ad2edeede569da35119c32ab648fa8e9c1cd41a92a85cc0d80d8c1c7bd6af82b47dd0ea975706016b729244e3cd00aa8c1ce0fbf43c6319a8efade09a749e3c98ca91b84b9523b37f87e39ae69594b429c5ca3738b986d2c18927b023815ce5ddbb8078f9bb13c8c5761a9461252a1831ec579e7deb1e78b23072b839cd75d29f2ea79f5236673060749d0f9c096e304727d4015324bb646092608c8c7209ad87b366bc86455dd1989864119ceec734496d05acd2930b3b3804b1195538f5ee79ce0576ba919ad77b19ec66c56f2cec0aaeec90062a57891582c84310793e953941b46d72549cfdd03a562eb375244ea90c8b823e62a7907d2a69c25525ca89bb62ea368f7241858304eaa0e79aa315c3d848e91f96d9c6e38cfe15564bc7f2847b8851d40efee6aa34c4f4e95e8c21cb1e593b9a24cd5bebd176abb936ba9e0fb567b95079a8639483cf4a495b2722b4568ab21f2ea36460cdc522d25381a92c72d2b52a8a43544919eb48091d29cdd6907279a9287accc3af35d8783f51f3eea3b3982e186d46c0041f73547c31a02eb2a5515d9c3ed38ec3d6bb4b0f87335aea205b5c2c9346bb82f40c7b007d7eb8ae4c4e22924e9cdea354a52578a3c931453b8c74a6d75000a334945201734514530168cd14500193524321491581e41c8a8e814c47b97c39bf486e74ebf8006b674f2274038539c0cfe2707d78cd7a7b1b8d1aecddaf9932323c6c2152a76b2f1fcc8e9e95f33783bc4afa1c92249109ed64237c6c718f71ef5f52e8d796de31f0bc77b611341e682c40f98260f19e7d71d7d6bc1c5d095297325a74677e1e7192e56713aee932597857ceb7b7b859ae017b968e356d85b240c8f9b6e3191c51e1ad3a19fc3b22b5ca99958b84c762aadc9fc7d3f956f2b6af05cdbd83daf9f1c3fb96b88581dd11fe16523a6de323a62ae1d223b2b1952084a7efd89461c707861ec46315c12a8d46cceb549396879d6b360910dc236560392463b57337016362ac09538f435db788c96475461b800c4938f7c7ff5ab838e4617677e0e07def4ae8a0dc91e5e2e2a33b2250029c8c607526a94f3492ca028e338e9c62a5f3bcc0c48e0919c5437372b671b492b118e013d4ff8575422dbb2dce377667f882f4dbd888e3055a4e3777f7fe95c73ca7279ad1d73536be901da1517ee815906bd7a30f6504ba9a4501249c9a28c719ed456858519a28a4000669eabcd0a29d9c55244b648303ad3240319078a4ce7eb51b139a6d89210f5a5c1c671428c91d29cd9ce2a4a3d2be174ba70b578e79152eda4d8a8d2005f7631b471e9fad77be20d4b4ed374295ef6e6dd268d1c46d148a656623e5521739eff004e335e59f0fbc1d7dae4c97fb0a69b6f28f364f5239da3f4fcebdcf41f839e1c96282f6ee397cedc5cc4643221cf4057fa66bc4c6fd5e35b9aa49fa23be87b570b457ccf957145253837b0af68e01b8a0d3ce0f238f6a4da7190323d453b00d1452d25218b45252d0006941a4a502988729c1af47f86da8eaf7568fa768f2dc25dd83b6a70f96ff2b045cbc6c33d187d79e08e78f37a9ada792da749a091e3950e55d0e083ec694e3ceac09d9dcfa317c6314ba9c1a8e8d2936b29cb0742a636ee8464e08e3bfe75df4bac4b3d9497389651e503246b80324f38f7e4d7cc4de23b68b50fb6d9a32c578a05ddab7255c019756e0609c91e9c83ea7d9bc01afb5c698967bd248a45caef19cfa30ef9ebf9578389c27b1d7a1e8d0aeea5e2f7317c6b37f65c534d7a4793bbe5207507a01ef5e5a3c41007941b6728df7497f9bfc2badf8abaa48d633d983e6c5f6af96565c1c727181d3d2bca57713c735df81c341d3bc95ee70577cd366e8d7a55b826348f664e011cfe756f58125f68d6d7c33f7b6b8ce707a5735e5b0c63935d2d85aea1159089ed1da091c3919c9201190a07d2bbfd8c62d492b3461276396b8cac8548208ea0d455d6f8d74db55bf964d3ee3cd50e428763bcae32320f4c0e0e79c8ae49815382306aea45c58e9545522a482933452541a8b4e5eb4d14f4a1098e2714c2d431a6d36c121c0e0d25252d218a837301d2b7fc31e18d53c4ba97d8343b56bcbbda5ca4647ca83ab12780391d6b0e2192057dabf007c0d1f84bc151c97d146356d5409e67d9878a3651b22e79e3a9e9c9f6acabd65421cdd4708f3cac56f871f0fae74af0ad8e9f7b74b3793976f2c8f2f731c9db9ebd8648eddabd26c2c951d546d7445c727240ab73ac56b032c312608c9c8c007d6934731796de548aff00ecaf6af95a8954abef3d5eacf539da869b23f37703d68e3b5368afafb9e48b4aac548c1231494945c64d712249b0aa6d7030e7b13eb8ed515252d0ddc4145145030a075a28a603a9c29a3a52d32476715d9f84fc51169f6c96d3130b29caca327ffd55c553aa2a538d58f2c8136b63d4b584b4d6b4f942b8f31fe62e9ca939fbd8fe78ae66c7c332dbdc6eba9206442708adb8be2b9786e67b7cf912bc79ebb5b15a7a5ebf71680acfba78c9c80cc720fa835846954a5171a6c8926cb1e2c251eda24c01b4b10a31b79c63f4ac68e69d190a3c80a1cae5ba5767637963ab993088b2e3a48a33f9f7ae6b5c963fb748b12aaaa7ca02fb56d46575caf46898bfb24b7ba835d794b75f662c304ccaa77fd09ef51eac34c9114db5ddc3c81001e6ae40007ddcfb565aabc8d85058fa0abb73a35fc1179935bb2a60124f419e99f4e9d2b47d916924526b700e2395243fec83fd6a0208382306ac471bae7e53c5174b9766ee4f3438e855f520a7ad329cadeb490d88dd69b4e61cd34d2602d395091900914ca92294c79c0049efe94d01240e62951d7ef290457e82f85f583ab785747bfba2cb2dc5a43349191862cc80b038f7e7b57e7d5a3017319750ea186549e08f4afab97c7eb1470ada442389515445d542ed18c7b6071ed5e466fcee315046d87946327cccf7a02de50b92bb48c019c8fa52bac50aed80221f615e25a7f8ce6b994195cc680f181d79e7f4c574765e234965db24c58927696c01c9e07e02bc3759c16b1d4ec8a52d9e87c318e334034b495f6479c28a52b8a4a729ec7f3a684368a08c1c518a56185145290298098a294f0292801c38a29053a988514b4da514c404514b4e44dc7e519340896cee25b59d6681b6baf7ad392eb4c9c3dc4f0c9f69ee8a708c7b9f6ac73c0c54b656d25e5c2410a9676a1a5b89aea777e1ab4b286d5a6b70e5ae3a17c1d8be9fd6b7a3559610b20dcacb8d87900771cf6e3a564e9e8ba6d82c44ab18c739ea79ed4db9d4a599888db646063038e2bc6af79d46d33356bdd96271a22ac8b14203b0193b78cff9f6ae4356d21a692496d109eec80e7ea47f856b94323671c0fc80ab7a949148d19810a1db86f7c77ad69d49537bdc39ba9c15d594d6e079b13a13fde522aaed35dd18fcd9042ffbc563b080339cf19fad73fe23d1a5d1efdada52181512238180ea4641fe9f506bba9d58d476ea691936b53141c75a319e94a47b7340e2b42c42a6900a938348453b05c4076104574be16f107d8e430de4aff6761f2f7d87fa5732493d693915328a92e57b09c6fb9ecfa56a9978ca49c67230c0822b6935a7139dcff74e47b9af088351bb82231c33ba21ec0d21bfba28c9f68976b751b8f35c12cbe127b9294e3a267fffd9", + "raster": "ffd8ffe000104a46494600010100000100010000ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828ffc00011080100010003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f99e8a6938a6eeae8b98d87d14d073413400b9a506994038a2e3b12d25341a70a7b9228a5157f46d26f358bc16ba7c0669b69723200551c9624f000f535db49f0baf8e9af7165a9595ddc428249ede2593312e0725b6edc738ce7143928eec373ce4e69369abfa8e9f73a74e22bc88c6e5770e41047a822aef85f41b9f10ea6b696cf1c4bd5e590fca83d78e4fd053d37031029cd2918afa07c1df0b34682d6f2e359b0d4f5248b9134400461bb076a86cf071c9e3f4cd0f1efc2f863d2d24d174a9a0bb91b7c4ad3a92e8464294049df8e7e983df159bab08bb363b36784487269a0558bcb596d67921b8468e58d8ab230c1523b557ce05363418a434bd69082290c052d20a5c1a601453821346c228b0ae368a795a6e2801292971450312929692900f41cd4869b1f4a5aa5b12c652af5a08a00e690c1bad369ec29a450020341a28a0005380cd20a7a2d0903154568e91691dcdd2fda9a48ed10833491aee2ab9ea077a86d6cae6e9666b682495615df21452762fa9f6af50f849a6f873539755d3353d552ce2bb80c51cb3b6c064206d047a673cfd29ca5caae24aecf57f86de13d322b4dda3dd69d6df641ba57bb51e73c4e32cb27518ca8c1edc92315d578bbc4d6034b95b46d3a2759c932cd3afcbd410a8a3ef64aa9e78e9c1cd78ff0084bc317f1f884787af754d423b337263ba82050aeca7e5562dfc43822ba7f8e1f10747f0ff0085c7847c24f0b4f8d92ca06e64078621bb371827f2ae252955568b34b726ace6b46d3a0f89be26bb7974c736ba79df3246b8695e4272e76f000207ca3dfe95de683f0f6e74db57874bb258cc92923ca88e555c6012c707803f339f4aee7e05c0b2f81f45bfb3b25b0b07b529140e77480073f316c0cee396cf7c8af4caa8a6b45a20b27b9ce5ee832ae9f77f619992eae00698055fdeb05c64f18dc4753debc5fc51a46afa65ec62e66364b33131a00184400183bcff0011279206d03a66be8cae77c6da043af695b5e3df3db9f322193f31eea7eb59d6a4a5ef257669076d0f94f55f83f73a978675af12c97cf04d02bdc0fb410639d413d2438c1206471dc7ad78532e1ebdcbf681f16ea0f709e19f39e28226f32e6147fddb375518031c7a0e9c0ed5e2328ce2bb69ddc13673bd188aa00cd2302dd29f083232a0c649c0c9c57a5693f0c27b79e5ff0084b6e86936826fb20986d709315dc858921421c1f9b3dbdc55e823cc84673cd3c28aeafe20e83a4f86bc512699a56ae357b78914c93c4a1407239504120e38e6b97a690360a32c154649e00ab5796325bcb2c6fcc917de0067ebc8e383c55bfed485459b41671c52c077964032cfc61b38e800fbbebcf3935735bf14dd5fc734102ac104c5bcd3b419650cc1b0ee00cf2a3a0038e9408e7319a368a728c9edf8d069804b6b2c71ef78dd53714c95c0dc3a8fad5622bdd459dbf88be01c76da6c505b9d15deea7ba9464dc49b773a06c7076b0e3bede38071e1f2a152720823b1acd3e62b6213d69314e3498a0a2451f2d14a80914ed9c55589b91f5a5a08c502900a6958718a5d9cd0dc1f6aa110b800f149413924d15050e41935d1e89a2492431ea3788574c59023bf1963e807523d6b02152c4000924e0015db695ac35b5fc71789ac65fb288c44b0aa0854f1804f6e0739a526e2b404aef505d5e1d2fc477f7da525bb5a61556328caaebea14119c11dff009d1a6f88ce93a959eb7a658c31dc5bdc3ae278b745229e406e319193f8629dad6b9a324569fd951ccf7312f9721907c8c9fdc073d07ae3b569e85afe94fac473dd5ecd6ba63cf6e2eac5edfcc475f2995a6c723729c00719e73ed59b7a5ecc69799e99f062e2e46b50f88bc41a7318a659ae1aed6191b3956f948f63ce30401835c4e83adf87fc5ff172f2f754f0e5ecb6b3e3ecd6ba6805a3d9d58a606ec8073d08ce6acbdce8b63a0ddde45f14b579f5282067d3ed234900071f71b24819c91c631d7dabc7ecafa7b1bf86f6da4db730c825472036181c8241e0fe3452a7a37dc252d51fa4ba0cd05c68d6335a5b496b6ef023470491f96d1ae0614af620718ad0af8abe1b7c73f145978c6c4f88f5792f748b89522b94990111a9e37ae00208ebefe86bed45390082083e944a3ca54657169ae70a7240f7a7554d4cdb7d91c5e322c5d7e76da320e47eb8a928f81be30dc4b75e38be96e1e5790b104c8437424704751c63f0ae1253c5745e3df213c59aa7d995122f3df0a8c19473d8f707afe35ccbb126ba13f7518db51c87041af67b9f1edf5cf80215d5aeeda5b7d5ee21b3b8852352d1c16e9b5b0392a4ee43ce0e7918af165a9d1895032703b5095c1935d2451dccc96f2f9d0ab90926ddbbd41e0e3b67d2a2a28ab2428c12401c93da9f0c6f34a9144a5a4760aaa3a927802bd235cbdd13e1fdcc1a77876d60d47c4b678375ac5c12e904f8e5608feefc87a3b0272323b50d81e698209041047041a51c9c53a695e69a496676795d8b3331c9627924d59d32c24d42e3ca8d9540196663d07f5a52928abb1a4dbb2174ad4aeb4e9f7db4b2aa37cb2468e40917bab7a83d2b4fc6d7779aa6b0da95fd959d9c972a1bcbb48f620fc3d7d6b7ac3c3967691c52dc866e4b067fe21ea0569dfdcda98417850228fbcc32c7d87e75c32c6479d72a37f60d2d59e56c9e948b1fad4f310d33945da0b1c2fa73d29a012703ad7759185c403141e2ba0822d11fc38ed29b95d455c60a212b8e7393d3fbb8fa1ac8be8228255105c2ce84677018c7b1a98cf99dac0d58aa4034c2306a4a42335761124a86291918a92a7076b023f314d085c8500927a015a9ae68975a4dc324a8ed0e372c9b48054f427d2b53c26b60b0bc8edbae4e0307c0da3fd9f5ac6a5651873ad4b8c2f2b3394b9b39adce258d933d3231510535e984d8ef6577de98f98050723f1acab8b2d2ee670c96ad1e0fdd53f29c7638f5ae78e2d3f891a3a76d99c9d818e3bb81a7cf942452f8193b73cd7abe9b3e97e28bab8d3279249ec9361531fcb9723ae5b0060fca3fa8ae312dad40c3c0a632c0900608fa56ac5158584f25d691023b98423433a248a4e4138dfca9c0ea3d6b3ab52156cd5d3e83a7745df11f872d341d02686188dc3fda22959b39729b4e50119c60e791d7f411ea9e26786d755bdf0def4b6bfb486ceecca80146da7705c6067a723b9351cbaaeb176d26d58e162b81117c83ee0fafb6314b65605348166e8918910b4aa0ef0ef9f958fe19e9ede99a51a9eeaf68eeee0d6bee9da5f69da2a4f7674d974616f1585a3583dcdb8604aa8dea432f52d9241e5b7579d7c42f0a49a74edaa69cab36973ed667862d890c8c32c817270b9ce0f4c545768da66937204d31613010fef7909d30477c8aeabc21e2196e34cfec79eea092c0c6cae5d3210c89820b63240c0247232bc7ad69072a7795ee85269d95b53c950d7df5f03fc6f078cfc1b0317dda858a24173c6371dbc301ee07e60d7c37e25d02ff00c39ab4b63a946a244381246dba39060105587046083f8d7d27fb1eceee35c59e762c6183cb88001422b38cf0739cfb574d4b349911d19f4ae2bc8bf682bc44d1a0b517525accf8d8fbb0aec5b010e390490003d0679af57bcba86ced65b8b9916286252eeee70000324fe55f1e7c62f8db65e2eb596c748d06dd4e0c4350bb55924099e7cb523e5cfa9e476c1acd45cb445b958f0dba69249e46998b48589624e493df35015c548735139e6ba199214119a957915104cd755a169915be9c750bc8b76e60b0a48386ff00687b0a894d415d85ae73ed148a81d91c29e848e2995d65d4e2e632b315f200fb9dab1751d3d2178de09018a421704f2a7fad453c4467a3d01c6c4fe139160d5c5c6e513c31bc902b7f14a07cbf91e7f0aca6324f392db9e691b9cf25989fe79ad4b3d18cd1ee99fca1c81c72dcf5c76ad6b6d12d8a2a6f26453b967e9b31ebd88a996261193d46a0da1fff0008dc0c614deb1b0b70642dddb3dbf51f9568d8c1059c02258621220c175032ddc1f5e94c123b1c860eeb1fcd81c71fcbbd24b2223a3e0658e1813c138e09af3a75273d1b3a528c75259af0eff9dd9cf4eb9c54fe46e8927999411cac78c9fc7b67ebdaa45bb4554952351327cd9ea38f6e9ef5496e2697cccf0ac493c64f3ffebacb96c6bce88e5b0d3ee9922f2a30cad9564c29273dce39ac9f12693235ec2b6b1abbc9b892806323b1c715af8d80ece4e339ab10391012092dc609fcff00cfe1574eb4e0f9afb133845ab3464e8161f67b4905ccaebe61e5170411ef59da8e8127db02698ad2c6c33862063f13d4575177bbecb1b2282589c90b8e9d79f5e9545aea64545182aa3038e47e35ac3135149cbb984a115a1c5dcc12db4ad14e851c7506988a5d82af527032715da259dadf4f9bb88193030c18ff002ad38fc31a63db882e7cbf3046489233824ff0fb67d78ed5d6b1d0ea895464f54718faf5f4ba59b09662d164618fde0b8fbbf4ad6d29ae24d3a291e3b658f6796a5171237bf4e95c82386ebd6b7f41d5a783fd196059d083b474d9ea73fe35a56a5cd0b4110a4d3d4e86cb4b9ae2212c922c51312506c2ef2019dccaa3960bdf91d462993c2fa7ba99a02f14c82589cab20913b3ae79c76acad63c5171088a1d36e8ac488c10a8dad1b31f98a91d3381cf5c7a66b4f43f89178d6dfd99e25b68354d25db795f2d22955fb30902e7b739ce466b9d619dae5731604705e5948d0c22396300ba97383f9fafa5644312c459a30304e4e4f2726b5356d36080c1716f74cd613a992da4fbc76ff7580e8ca4e0f3efdc5664619620e5485e0838e0fd0d73cbddd07cc5f866dcacf962a3b6727e94d9355fb3c2eee404c7dde6a84ac8bf32b127392bd0d41a9dbb5ddaaf96c37a7214ff0017ff005eaa118b92bec5b9b48ada85edadfd82feea44bd12312c0820a9c6d5ebce307e95afa3ea31db5afd8efac85a4127cd1ca410246dbd093eb9ce7fa5725246e9218dd4ab83820d75a08bdd1bc8cfcac8a5410095c77fd0d76d6e58a49ec6517777ea61788ef7ed1769045753dc595aaf956de77544ea471ee4f35f437ec75af892e754d1ae2e9774717996f0328c91bb2db4f5ea7247d0f6af9e35fd3e2b35b66b77deaf18ddece3afe159b617d75a75d2dc58dc4d6d3ae40922728c01183c8f6ad34947412d1dcf70fda97c757ba8f8eae741b1bdb98f4cb08d619a0076a4929e589c751ca8e7d0d787c12b4722c8bf7948238ef4fd5350bad5b52b8bebf99a6bbb890cb2c8dd5989c9355c9ed56b4427a9d06a9acd8dd69896d6da72c3364169770e7b9e319ce4f5cf4e31deb0194939a00c0cd5c86d1a4b296e432ed8c80c3bf349251560bb64ba3e9575a93badac4ceb18dd230e8a3eb5afabdcec31c2bc32a886319e171c66a868fa84f6d6d776b6e9b8dc05279c602e49a2f9fcc92dd631ba6620827a8f418ac2aa729a4f6045b8c08d511cf9847527bd36ced638dbcc56de5b903d3ffaf52fd959406b9dfbc8076b71820f6c5583090a70bc8e82b8a53b5d27b8730df39c9cb703a5588a60cbb38e8738eac79c5442d1d955ce79cf6cd16d13e4e14100e38acb40e62ec73a2a900053ebebf5aaf70e1b27b8e453dd672470ff004a468c8cfca727b7a5256357252422cc48e0f18c6054c93b21c8c9f6aa6b1b22f5e3a6714e8cc8ff00220cb673f4aa6ae67ccfa170cb962081cf5c54f0384411b61d339eb826ab35b3aa024e1870727bd3763edf94838a8e57d0ae76b7372d2392e21592281a58d0e5948cedea064f5c7154eea1592e8b45f2ab0c9c8c0e9ce6b0753d6a4b42b05b101d7efe7b7b7d6b3e5d6afaf62fb2657f7a40ca8c1fa67d2ba61859c95c1cd33b32f046823b77594904a903391d38fc6a9ea974d630b335c2c57182c818f5f4c62b99d4de5d1adededede5c4d226e95c751c9c28f403f99ac3b8b896794bcb233b7a935a430a9bbb7a0d54696843bd14f1b8fe94f6ba94a9456d887aaaf43f5aaf45765c561d9f5a78351d2ad09833a7f0edd41730cb617b2a44ac3cc8a57c90ae303071d88efdbad6f5a5bc2cc9048fb655970417cab839191e8471eb5c0db92258f1c1dc39af5fd3b4092fb46d3e4b78d47cfbb70525ce49c8181db8e2b871ad42cfb8e9d373ba450bcf0fc6b197e412bc0c9233fceb06fe17b37456182c0e3078eb5ea2d6973268f6f34f80d36586e3f311bb00fd08c1ae1f58b4f30946ce5723835e751aaef690ea53e4d51813c71dddaed6da24eaa71df3df8a985c088363214671838c5034e742c5582287c12c49e31c63eb515d3c7676e59c16638efd7f0aeebded15a98f395e7bb82e116266de1b80a17a67fc2b9b9d0ab1e0823b1ab7757a9e779b0868e43c921bf95569ae4cd9918e5cf526bbe94395587abd480362827bd3072727ad498f96ad142a3e5b06ba5d36f2cddd22923648443b1940ff58c7d71cd72a7afbd75be13d135992582fac6032db970ad8239f6e7af4359d594547de62716f62fe97a12db1134db8bbe4c6390421f5f7ab7169b631c8f298c6fdd956273cfaf26997badda4376609cbc8c8f82aa080a3b9fc39ab161783cf78644dcee4b447390ca070ca4f07dc579d375a4b9d8ac2490b16395ca9cfcdd7e952c3665fcb4452ce381c739aababdfcba7436d1dac2d2b48fb89d840c0eaa3f1cfd2ac786b5b693512b7303c6e1cb0046001d874e6a3d8d474fda25a02e54d731b96fe1ebb745c8249ec47e3f4fc2af69fe139e3b305c7cdd5beb5d7fc39d5edf57f14dee8b7d22401504967134601981eb863d082738fad7a63e93651e9d728df3057c36405c803ef03e8723afa1ae1a8eac15e5a1dd4e14a5b23c2a3d1521db0cea9e713c30e95ce6ada6cff6d1696d1486524601c1c739e3d7f0af5fd46e34e8ee1d618de620150aabb8e4e00c1f4cfe7468ba638ba992ff0049bab98e4f95484da809e548ef9fc41a985597c4554a507eea3c7eefc2fa85adc06bab775126e61b57ee91f53dfdff000ac910345323b7c80b10aa324b1fa7602be929f413a85a4769a8db4ad0a9254efcb0c8c673d73f5cd5397c11a41b71e78680a70b24e141f7ff003c557d6dc7e2427854fe13c12f6c2e6dedd67911846c01dc7dfa551990c681892371c119af46f11d8da25d9b49efe3923b621888db25b39c003d47bd79dea1a95a5acf2cac366e0c23c7273dbffd75d14272a9b238eb4395d9181ac5adbc41f62b09b1b8f3ee2b2eca6f22ea2949e11831fc2a6925fb5acf34b2aa0e8bbb926b2e47cf0bf77f9d7b904e30b4884ae4d7d78f7774f2b13cf0a3d07a544aebc673515142d0bb01a29460d1b7d28b0c4a5a4a5a0055621811dabe88f83dad43ace93259417063d4edd4cf1c18fe2c61997b1190a707a64d7cec3ad69e83a89d33518e7fdef97f764589f6332fb1ec7201fc2b1c45055e36ea5d3a9ece573e978f458e4bf37705bb8821b736ef14d114da7192571c1c9ebfe71c078a123875011a0da18f5c71ef5d07c38f1cbea97b7565757a03cc4be507c81fb155278073d3b72315e69f1175a953c4924368d88e31d0a82771ea33dc578f430951d5707d0e8c4ce12a6b97a972e254f2c9326c8872c7a7f9ff00ebd70daedf7daaf9da372d18f9578c71572c2e2e2ed6e209ccb223af18c9dad9e0d65eab66f637b2c2e55b6b10194e41fc6bd8a386f64aef73cf8db9ac543ef452669cbc9ad8d472a8ea69cedc74a8d9a933557b0ac2819af69f86fa6f89f56f0cfd9b4ad32ce35642ab7172e50321fe2c63939e878e95ca7c1bf0149e3ef13fd89de4874eb74f3aee74032abd154678dcc7819f73dabecdf0e78774fd061b4d3ec630a218963c9624e1470327ad79798d7508a8257674e1e176e4d9f3ab7ecefaac5a6cd7835649a5489d9a18a03b890a4851cf24f4af1e44d534ed5ad6d56caee2bb8d862d591b7b13fec919e7e95f7e992e50f96b11724939240c01d481ff00d7a88e93a7dc6a967a8deda594b776d9f22e1e30658db1d15fae305b3f5ae7c3e653578d6572aa61d6f13e23f0f78c468772566d322b8c4bbc8989ca64fcc39c9fea0d7d11e07f0945e24f0a596b970b6f6571731998429186006e3b771ebd31f81af50d6fc3fa2ea91497375a569cf748095967b58dce7b6491cf6e3bd733f0cfc593eb505c58ea10c76fac69d235bde42830885781b571c291c8ed8e2a7135215a3cf4e3eba8528b8bb3392d3fc113db78decb59b4befb37d8e3689ace48cb2e181ced20f439079e3815daea4f70d6c21ba06547dcac50e4e00ee318cfe154bc5b61e29d3bc5716a5a1daff6b6937a82396cda610fd91c0fbeac78dadc120827238ae224f8d7a469170fa66b5a7eaf657c9b5268a684651b1c93f3648c1cf4aca585a955249dec5c6a4217d2c6958c96d61ae456f736f2a9772229a4dad9c1ceccfbe3f4aee24d74ada8fb346884019f976807d00fd2b95d73fb0f56d2a0943ace67412096363b707a60671eff00fd7ae6a69afacece622f16f2dd72ca67255faff7875fc7df9ac54afee6cd0dbe5f79ad0dcf1778d235b4220927b4bc419578f0c1883c820f1cfbd727abfc401ab58436c36acec9b2425303703d55403c938f6ae4afa69eefcc89ede18e267da642a49461c9da7af20f43db151dc5b889618f7aca910560768e071f9d747d5e2edcceece59e29ef02a78dadcae8bf6b88cef751312cf1be38e859b239f6ef5e7fa808efc5bcab2a232441666627683d8fd7d6ba9f14ebad145750c53279b221491436783c1c8e99e83d6bcea59770da0f1dfdebd8c2c3961a9cf773772dea4f6e96d1416ae64e4b3be3009f6ef59b4e3ca7d2995bb2d2b0e3c1c5000f5a4a0503173ed46483c5253860f068108496393d68a28c5030a7034da70a684cbda56a571a65d0b8b460af8c723a8ad9935bb0d46fa29f50b42930182e8dc1fa8ef5cd0a50b938149d35277ea4bd558dad66d901fb743721e395b08173daa8996e2e2298f91e70382cec092bf8d36d6695710c6a24dc78465ddcfb0af43b2921b1b0822955436ce6241dcf5cfe3eb5156afb18aea46c798bc7f26e0bb4fa5317ad77fa8c516a36ede74504410e1446bb49cd72fa9e8ef6f0b5c4219a0560ac4ff0939c7f23f952a75a33f26529a7a18edc1a54c67e6e94bec7a505456b62cf70fd997c436de1fb9d7a5bcb8d914c90a08b04ee2198eefc0647fc0abe8fd3fc77a6de8062440c780e4e2be08d3efa6b0ba59eddb0ca7a763ec6bb2b4f88535b42a8b0312393f3e066bc9c6e06a55a8ea537b9ac2b3868d5d1f6bc1af5a48f084ba8ca8cb36c6049ff00668bbd73426612ace8278c98d78c11ebf8735f1d787fe20dd4b73e5bc656466fdded3900fa9cf7ad9b8f11decf932ccc08cfcc1793f8d70cf055e9ae5959dcb78a8a7b58fabae75db48ac04a24017195ddd5f8ec0f735e437daa47a578edbc55a4ccf1e9d322c7ab42e7850b909281d38c63db3f5af34d37c433cecb15c4b230196e5b245779a398746b337b7d788fa6842649382093d9b3c719e8783584154c3cbded6fd0de8ce388764ad6ea58f1dfed1565696be5784ac9af65278b9b94290af1d875620fd057cbdac6a977ac6a973a86a3334f7770e649246ee4ff0021ed5d7fc5ff001b0f176b56f1d9b1fecbd3e3f2adc6c09bc9fbcf80063381dba015c1f0df5afa4c35350826959b38eabbc9eb73d4be0c6b0a2eee34bbc98ac5328688b1fba572481e99ac4f1f78c2f757d467b48dda1b18646408af9df83d49efed5c8d8dd4d632a5c5b48d1cc87e565ea2997571f69b8694a8567e4e3b9ee7f1a161e0aababd589d46e2a1d0eefc21e211f614d32f9df6a3995646236a8db83bbbf4a5f1d011c51dd595cbbdbb47b70dd0eeea57f2c5729a0aacd73b032ee236956e8c0f079ec6ad5f5a5ec9702c373c890ffab52780a79cd57b18fb4e78bb1cef7d4cbb1845cc92abe73b0eced96ed5464429232302194e0835bb776cfa7adbbc5be49b25b2bc0c8c7e3c5665fee96e5e7318457390074adb492ba2e2caaa71d7a536a4078e4520018f4c52b16340a3760629c41069ad40060d291c66a49b03a77a8bb50d5816a14a0719a542a3a8cd38e0fdd18a2c1723c1a70a5a514ec2b874a031072090690d1401a1a05dc569ac5b4d725c46adc95c120e383cf5c1ed5d7dc23453946196f5f5f71ec7a8af3ec126bd23e1f6a307886e2dbc3d7f6abf6978cc76d76a4e46dcb61867d33cfb0c835cb898b6b9bb07b3e7765b9588930b88f3bb38f7ad0d3ad1ee77acbc64edd98fbdf855cbcb4363a94b6cfb6531b9438185071c11efed57d22486318014e7820e064f5cd7933aafa0a14d735a4737e26f0be9f6da235e92b0c8177029c027b2907fa579c66bb3f1fde1905adb072026e6283a7a027df835c657af86e7f669cddd9a4b96feeec39052375a54a4635d04f526b3b992dae12588e194e457a82cd05e6996ce136ee8c1041efc93f875f7af29419615eed16836779a669f3e96ecd6d2401e25098c0000393dce4303ee0d716366a314df70f64ea3d3a187691c11cc14012c720dae1f80c3d3db278accf89faa492da5ada5a964b22c59947019801f981daba9fec6360f992374603cc19f4c1c633c579e7887518f54be834f86375449b6ee192dcf04015cd845ed2aa96f61da54e3cbdce4c0c1058714edb8c11d2b6bc5f6b6da7ea49616809f2102bb37566ea7358dd80f4af5a2d495d09a6b718fda9a3ad2b0e685eff4a0058a468a40e84860739adf1aca5c9864924fb3dca0dacdb370615ce9a500922814a29ee74125ef9af23192294edd80af1f88aa90cb240db728ca38381906b43c2de14d4359bc87cab7956d5d807b82b84519e4e4f5af5cd3fc1fa6e945c4118f31a30aef23121bf0ae6af8ea387f765bf637a381ab595e0b43caa3b7d3ae34d33c823478d46fd99cae4e071deb12e62489f03054938901073f957a9de7819211aa4af234cb72859142fdc39c8391db38af2abeb29ac6e1a1b8468e453820d6987af4eadfd9bb984a8ce93b4caf2a6d6ec78ce4542724f4a9d14eece3701d47b5226dddf39207b56ed5c572194e5cd36948c1a2a0a4029c31da9b45301e0d385301ed4e0698828a0d0298086bbaf82bfbbf1dc1700e0c104ae0633bb2bb71ff008f75ae16bbef83b6eb278899c921bcb6008edc66b9f152e5a527e46b47e34753ac069757ba91a404c9293b73d724f5fa715c978ab52b9b48d625b82b21ec9c605741e2cbb8744ba904b26e9d836c8f1939ec4fa738af2cd46f66bdb969677dee7a9af3f0541c9aa92d88a89a9b4472bbcce59d8b31ea58e6a2231499a7039af5b716c2a8e29a4734fed48781c53b08693818af7cf81dae5a5d68474db9da2eb4f2f246adc078dce783ea1b3f98af02abda4eab79a4ced358ccf0c8ca50b2f5c1ae5c5e1feb149d337a157d94d4cf67f885af1b481e7326d95b844c86f9bb578b25e4e9a92dda36275904a1b1fc59ce714ba8ea379a84c25beb99277ec5db38aa8b92d9a30986587872eec55aafb59b913ea3752dedf4d7370dba6958b31c639355c714f6e39ef51f535d36b6c65b8fea280b926851cd29a621bb38a4538233c8a520d34714867d07e16be8aefc33a5dcc6bb5562113301c02bc107d3a56a960d3476ef246c491f2161b88cfa6726be7db5f10ea96960b676b76f0c018b6d4e324fafad67add4eb3097cc6f301ddbb3ce7d735e2cf28e79ca4e56b9ee52ce654e0a1c97b1f5a789a3b5b6d26386ca557555cbb9e08271c0fcebc0be25c51c6d6cfbb74e4e0b7723aff5ab9a07c416362f6fab87965049571ce7d88ae37c4faabeada934ce0280301474a30182ab87abef6cbf138f1988a75d26b7287606a323e614e89b2307ad5a5815ad249490ac8475fe206bddf33ccd8a4ef9e000299451517b96b40a29c16976e45160b8c039a916900c53a9a1311a9b9a5634c3431a1e0d7a87c1eb07324f7c40310cc5b4f193807afa1e9d6bcb075aedfc27af5c45a0dd6931dcf92afbdd72c1304ae09049f6031d4e6b0c445ce9b8a2e9c9424a4cc5f13df4ba8eb57f773471c72cb2b1291905579e808e0fd7bd60f43cd5e2caa594e09e9d7a540c467b56fca924974324db776419a51d6a529bf90471f8546719c52b58ab8f1d2908c1a453520c1155b888f19c9ef4da95b1ebc53720d2b05c60e4d4aa540c544dd78a72631cd086c73608e29a8a58d21c75cd08483c5004ac850f34dcd4a5cc832e496f535031c1a6f4250eeb484500d2e690c611460d293429a062a128eac0f2296e1da4959dce598e49f5a319a691eb45844968a8d3a79a488f3f31039c55dd4278e59b16f1ecb74e2353d71ea7dcd518880df4a25933c29a6acb513d591ed34a01a7800504d2b0ee1da909a42691ba50004d37268a290c3345145030a721c5340cd491a6e6000a10986327d69429af41d6bc0b37863c01a56bfab5a4c6e755919208d9b6a451edcabb01c966192070063273d2bcfe53f371d6aac48631d78a6be3691de985893cd252b8ec2f028dc6928a4302734539971d29a462800a28032714b8e714ac312807078aded0bc23adebb617d7ba569f2cf6964864b89b215235032492c40e00cd65de58dcd85d496d7b6f2dbdc4670f1ca85594fb834ec2b91237f7a9245e7229769adef0ef83fc43e25dff00d87a45ddeaa0cb3c69f28e71f78f155d09ea73b923ad1c9af4df087c18f1678912f98597f67fd959548be578f7924e76f0738c73f8564df7c31f155af889347fec9b97b892431c720899637209190ec00c7ca793c11ce7041a561dce1f068aea23f0378925f100d11347bbfed4259440531b8a824e09e0f03ae79ad3b9f851e3287519ac9742bb9e689d636685772ee2bbb83dfaf27a0345877386069fd6b4759d0753d16ea4b6d52c6e2da58dcc6448840dc3b03d0f51d3d6b3f691da9937237539a6e2a6c9a438a4d0ee34f5a29f28e6a3a6c10734638a29c149ce074a431a05295ae93c11e0dd5bc65ac0d37448564b831b4a4bb6d50abd793f515abe22f865e2cf0fced1de68b772aaf064b7432a838ce32b9edcfd39a7625b3852b4043e95d2783ec2d2f7c5fa4586ac937d926bb8e29d23c2b952c01032460f6afac75dfd9ebc1ba8c20582dc6992e492d0b961db8c3138e9fad2765b8d36cf8b8464d7a97c2cf84dabf8cec1b55b1be86ce0866088e49f33702092076c0c907b918ec71b1ae7c01f1269de28d3f4d827b49ec6fa731457664098c2b39054f25b62336173c03e95ef1f07be1dea7f0fae757b192eed6ef47b9db2c1288b64c1c12087fef0da78e78f419343925b0926f7386fdae035a783fc2d6485da149d86ee80ed8828cfb9c9fa735f2abf535f5e7ed7a211e06d237b66717ea139ede5beeffd97f3af924a834e3aa07a32b114da999314eb7b69ae66586da292595b384452c4e064f0293434c86289e691638919e46380aa324fe15d6e87f0dbc5dad4b6e963e1fd476ce40596581a38c03cee2cc00c7bd7d2df01be10697a6f852c758d7ed1a5d62f156e76b964302ee0c8bc608e00241ebb88391c57b7dadbc56d6d15b5ac51c3044a1238e340aa8a0600007000e381f4a9e648ab1f0f587c09f1f5cea1f666d212000f334b71184c7ae4124fe02ba193f66af17fd8e0963bad31a67277c7e6901076e71cfe55f619538da59ff038a746a2340899000fad2e70b1f1d781ff00676f10ead75707c4320d22d607d8bf289249baf2a32303dcf5cf4af5bd0ff672f07e9b7c25bd6bdd49000424f2855cfd14027d7ad7b4a29524ee6249e84f03e9488a1176839c127f339a4e4c122be99a75969702c3a75a436d081811c4815471e82b0fc51e03f0bf89a5336bba3db5ccc13679a548703d88e6ba614c9dd96362a99c293d7149319f3df8a7f66fb1bfd7e0b9f0fea4b63a5c8ea66b6742c63400676364e49c67e6f5fc2bdcfc31a069de19d0edb4ad1adc41676e36a28e4f2492493c9249249ad088158d4118240c83daa5a6e4d82490a02807fa50bc7e3476a4a91885177eedabbba6714e239ed494b4015ee6cedae828b9822940391bd41c578c78aff675f0dead2de5ce957375a75d4ee5d5410d1213db6e338fc6bdbbbd14d36b613499f0e7c43f82be27f079927487fb4f4d45de6e6d97ee8c64ee4ea31ebc8af2d22bf49f516b754985cb449198cf98d2b00aa9c924e7a01cf3d2bf3dfc673d85ef8b357b9d1a15874e96ea468117a04dc718f407ae3b66b58b6c86ac6332e6a33131385e49ed5f4278ebf674d4b4eb989bc292ddeab6d20398cac2af09007de679101079c60718e7b13adf0b3e00ded97882def7c651a35b245e7451412826395594812107af5fbbb87ca724719bd1ab93669d8e27e0e7c0fbef174b35df88c5de97a6c2c9843115927c827e5247006067bf22beaed1bc1fe1bd2ac16df4cd174f821d8108102ee603a6e6c65bf1279cd6f93d430ebfa5290074ac1cae6a915ecac6cec2354b4b682dd40da0451aa0c7a600a96ee086eeda5b6b98a39a0990a49148a19645230411d0839ef52633452b81cadcfc3cf08dc6e32787f4f0ccb1a868e2f2ca08f1b3615c14c6d1f771d2ba8550a001d29d9cd078c628bb616178c8cd31d4ee20103f95314c9e7c818031f0579fcf8f623f5a97f5a0670df16be1ce9ff1174786daea692d6f2d8b3dadc2f3b19800432f707033df8e0d7c5fe37f05eb5e0dd5a7b2d66d24458df6a5caa1f2a51d8ab639c8edd477afd091cd60f8dbc29a678cb446d275a8cc96eee2405490518670411d0f26aa33b6e44a373f3bcd7d09fb317c37d49bc470f8af57b492dac2da36369bdb6b4b230db9db8e57696eb8e71d6bbdf0d7ecebe1bd1b5482f6f6eeef51681c3ac329558c90723700391d38cd7b600000aa30076f4aa94eeb414616dc318ce09e78a503d2814a062b2340a4a3e941a003f9d1c51ce68fad002f6e290d039a0d00140340e7ad18fca800038a281d28a0031474a33477a0028a28240193c0a00f16fda58de5d78512d749178d7723bc4f1c1bc2c89852c8c3a3123900f3d71debe3f9e192de79219d1a39a3628e8c3054838208afd0f6d21bfb65ef6de4458e67479d181632151b46d3fc3800608f7ac2f1cfc32f0d78b74d9adeeb4fb7b6ba650a977044ab2478e9838e7fc335aa9a4ac66e373b61ce7239e942e33c76a4de3269370193eb591a126320d339ce3a502400f7a378273400eed8a31eb4ddc280e01e050039b819a17e6c126982419c6324d2a8e73e94c7614c6acea4e7238fa8f4a7bf0d8279a4eb43b80d9348420ce79a38dc09ebe94d6900e7f1a6452895dc0040519ce38a007c8e55b27383da98158bb1e76f6e7ad47136e7766e57240fa0a9c3a8229ec20030783934ea6f9800cf6e99a4de290c9292901cd2e450160ce68ef499140a760b0a7fd9a09cd20619a0b01d68b0ec2819ebd28cf38148ad9a70c520b01c7e3498a3f9d2d1615829b9a71eb498a0000cd57d42332d94a8aee848e193af1cf1f9559a6b8c2e48e942022b4431dac6ac72428fc3daa6eb8aa567361e443b880e4658e707a800fd31c55bf300fc69b120c71cd35978acc8354796f27850094a36c08bd43038604f4e39eb57ac2f21beb613db3878892323daaac03f6d38631d29c718e6a3738048e942421739ce281c1e6913934d72db8055079e72718a2c31c3ad4e838a6a2738f4a94e225cb1c01de958ab91e48e94de4d3c8e69ad9c516132aea0fe540ec49c2a963819e00c9e3f0a2d95bc8576c06750703a0ef4bb1d998b03b4fa9efdc7d2a65e80516122351c8f7a738c73438c74a553b873d68b0c0282bf5a8f904015274048a68ce68b012af5ea29d4d0b93c53c0a2c3b8dc5380e28c734f51cd21dc6eda0a715305a4931b69dc0836e38a314a69b482e28a29075a5f7ed4c04279c53b14c1c9a97da86891b4cb9845c5b490b1215d4a920e0e0d4ddba5369580c39e08ed98ce4bb4a8e4c5167ef923038eb9ea73e95a4ae19d9320b2f5c0aa5aac71c37514c06c6c1662bc64f0013ebc0c73db3505948eb1c97304525c87505020c000edc753cf001cfd6aad7449ffd9", "properties": {} } ] diff --git a/test/expected/l.2.0.0.png b/test/expected/l.2.0.0.png index bfbc6b3..87e1414 100644 Binary files a/test/expected/l.2.0.0.png and b/test/expected/l.2.0.0.png differ diff --git a/test/expected/l.2.3.3.png b/test/expected/l.2.3.3.png index e7bd907..1f2a55c 100644 Binary files a/test/expected/l.2.3.3.png and b/test/expected/l.2.3.3.png differ diff --git a/test/expected/l.3.1.1.png b/test/expected/l.3.1.1.png new file mode 100644 index 0000000..8e4b8c0 Binary files /dev/null and b/test/expected/l.3.1.1.png differ diff --git a/test/fixtures/tm2z/invalid.tm2z b/test/fixtures/tm2z/invalid.tm2z new file mode 100644 index 0000000..d3c3d5b Binary files /dev/null and b/test/fixtures/tm2z/invalid.tm2z differ diff --git a/test/test.js b/test/test.js index f13eceb..907705c 100644 --- a/test/test.js +++ b/test/test.js @@ -144,7 +144,7 @@ var tests = { // Image sources. 'i@2x': ['0.0.0', '1.0.0'], // Image sources for multiple lookback - l: ['0.0.0', '1.0.0', '1.1.1', '2.0.0', '2.3.3'], + l: ['0.0.0', '1.0.0', '1.1.1', '2.0.0', '2.3.3', '3.1.1'], // Invalid tiles that are empty invalid: ['1.1.0', '1.1.1'], diff --git a/test/tm2z.js b/test/tm2z.js index f79b190..f7511ce 100644 --- a/test/tm2z.js +++ b/test/tm2z.js @@ -57,10 +57,14 @@ Vector.mapnik.register_fonts(path.join(__dirname, 'fonts', 'source-sans-pro')); }); }); -test('tm2z+http ENOTFOUND', function(assert) { +test('tm2z+http ENOTFOUND or Z_DATA_ERROR', function(assert) { tilelive.load('tm2z+http://not-a-valid-domain/patternstyle.tm2z', function(err, source) { assert.ok(err, 'has error'); - assert.equal(err.code, 'ENOTFOUND', 'code: ENOTFOUND'); + if (err.code && err.code === 'Z_DATA_ERROR') { + assert.equal(err.code, 'Z_DATA_ERROR', 'code: Z_DATA_ERROR'); + } else { + assert.equal(err.code, 'ENOTFOUND', 'code: ENOTFOUND'); + } assert.end(); }); }); @@ -175,7 +179,7 @@ test('errors out if unzipped project.xml size exceeds custom max size', function }); test('errors out if not a directory', function(t) { tilelive.load('tm2z://' + path.join(fixtureDir, 'nodirectory.tm2z'), function(err, source) { - t.equal(err.message.split(',')[0], 'EISDIR'); + t.ok(err.message.indexOf('EISDIR') !== -1); t.end(); }); }); @@ -240,12 +244,29 @@ test('profiles a tm2z file', function(t) { t.deepEqual(['avg','min','max'], Object.keys(profile.loadtime)); t.deepEqual(['avg','min','max'], Object.keys(profile.srcbytes)); t.deepEqual(['avg','min','max'], Object.keys(profile.imgbytes)); - var expected_tiles = [ '0/0/0', '1/1/0', '2/2/1', '3/4/3', '4/9/6', '5/19/12', '6/39/24', '7/79/48', '8/159/96', '9/319/193', '10/638/387', '11/1276/774', '12/2553/1548', '13/5107/3096', '14/10214/6193', '15/20428/12386', '16/40856/24772', '17/81713/49544', '18/163427/99088', '19/326855/198177', '20/653710/396354', '21/1307421/792709', '22/2614842/1585418' ]; + var expected_tiles = [ '0/0/0', '1/1/0', '2/2/1', '3/4/3', '4/9/6', '5/19/12', '6/39/24', '7/79/48', '8/159/96', '9/319/193', '10/638/387', '11/1276/774', '12/2553/1548', '13/5107/3096', '14/10214/6192', '15/20429/12384', '16/40859/24769', '17/81719/49538', '18/163439/99076', '19/326879/198152', '20/653759/396305', '21/1307519/792610', '22/2615038/1585221' ]; t.deepEqual(profile.tiles.map(function(t) { return t.z + '/' + t.x + '/' + t.y }),expected_tiles); t.end(); }); }); }); +test('profiles tm2z with very southern data', function(t) { + tilelive.load('tm2z://' + path.join(fixtureDir, 'invalid.tm2z'), function(err, source) { + t.ifError(err); + source.profile(function(err, profile) { + t.ifError(err); + t.deepEqual([ + 'tiles', + 'xmltime', + 'drawtime', + 'loadtime', + 'srcbytes', + 'imgbytes' + ], Object.keys(profile), 'produced correct fields of profile'); + t.end(); + }); + }); +}); test('loads a tm2z+http url', function(t) { tilelive.load('tm2z+' + remotePath, function(err, source) {