From da81211feaffd89319330774b61b261b939dde33 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 19 May 2015 01:13:46 +0300 Subject: [PATCH 1/7] Add callback for error notifications on renderStill() The callback will be called when any of the resources requested from the network failed to load. There is not recovery implemented yet, so the closest thing to reseting the Map object and reloading all the resources would be setting a new style. --- bin/render.cpp | 11 ++++++++++- include/mbgl/map/map.hpp | 2 +- include/mbgl/platform/event.hpp | 2 ++ src/mbgl/map/map_context.cpp | 11 ++++++++++- src/mbgl/map/map_context.hpp | 3 ++- src/mbgl/map/resource_loader.cpp | 16 ++++++++++++++++ src/mbgl/map/resource_loader.hpp | 2 ++ test/api/repeated_render.cpp | 4 ++-- test/headless/headless.cpp | 2 +- 9 files changed, 46 insertions(+), 7 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index 33e216f52..740d3dffe 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -111,7 +111,16 @@ int main(int argc, char *argv[]) { util::write_file(output, png); }); - map.renderStill([async](std::unique_ptr image) { + map.renderStill([async](std::exception_ptr error, std::unique_ptr image) { + try { + if (error) { + std::rethrow_exception(error); + } + } catch(std::exception& e) { + std::cout << "Error: " << e.what() << std::endl; + exit(1); + } + async->data = const_cast(image.release()); uv_async_send(async); }); diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index e71c5f5b4..a6aac08b3 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -42,7 +42,7 @@ public: // Register a callback that will get called (on the render thread) when all resources have // been loaded and a complete render occurs. - using StillImageCallback = std::function)>; + using StillImageCallback = std::function)>; void renderStill(StillImageCallback callback); // Triggers a synchronous or asynchronous render. diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp index 5fd64119c..8cdd1d50a 100644 --- a/include/mbgl/platform/event.hpp +++ b/include/mbgl/platform/event.hpp @@ -29,6 +29,7 @@ enum class Event : uint8_t { ParseStyle, ParseTile, Render, + ResourceLoader, Database, HttpRequest, Sprite, @@ -46,6 +47,7 @@ MBGL_DEFINE_ENUM_CLASS(EventClass, Event, { { Event::ParseStyle, "ParseStyle" }, { Event::ParseTile, "ParseTile" }, { Event::Render, "Render" }, + { Event::ResourceLoader, "ResourceLoader" }, { Event::Database, "Database" }, { Event::HttpRequest, "HttpRequest" }, { Event::Sprite, "Sprite" }, diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index f373274eb..28bd8903e 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -232,7 +232,7 @@ void MapContext::render() { painter->render(*style, transformState, data.getAnimationTime()); if (data.mode == MapMode::Still) { - callback(view.readStillImage()); + callback(nullptr, view.readStillImage()); callback = nullptr; } @@ -274,4 +274,13 @@ void MapContext::onTileDataChanged() { triggerUpdate(); } +void MapContext::onResourceLoadingFailed(std::exception_ptr error) { + assert(Environment::currentlyOn(ThreadType::Map)); + + if (data.mode == MapMode::Still && callback) { + callback(error, nullptr); + callback = nullptr; + } +} + } diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index c84245484..fb9fdb4d4 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -43,7 +43,7 @@ public: void resize(uint16_t width, uint16_t height, float ratio); - using StillImageCallback = std::function)>; + using StillImageCallback = std::function)>; void renderStill(StillImageCallback callback); void triggerUpdate(Update = Update::Nothing); @@ -61,6 +61,7 @@ public: // ResourceLoader::Observer implementation. void onTileDataChanged() override; + void onResourceLoadingFailed(std::exception_ptr error) override; private: void updateTiles(); diff --git a/src/mbgl/map/resource_loader.cpp b/src/mbgl/map/resource_loader.cpp index 2be86dc5e..620b1b137 100644 --- a/src/mbgl/map/resource_loader.cpp +++ b/src/mbgl/map/resource_loader.cpp @@ -130,4 +130,20 @@ void ResourceLoader::emitTileDataChanged() { } } +void ResourceLoader::emitResourceLoadingFailed(std::exception_ptr error) { + assert(Environment::currentlyOn(ThreadType::Map)); + + try { + if (error) { + std::rethrow_exception(error); + } + } catch(const std::exception& e) { + Log::Error(Event::ResourceLoader, e.what()); + } + + if (observer_) { + observer_->onResourceLoadingFailed(error); + } +} + } diff --git a/src/mbgl/map/resource_loader.hpp b/src/mbgl/map/resource_loader.hpp index 379444135..fb05e67e1 100644 --- a/src/mbgl/map/resource_loader.hpp +++ b/src/mbgl/map/resource_loader.hpp @@ -32,6 +32,7 @@ public: virtual ~Observer() = default; virtual void onTileDataChanged() = 0; + virtual void onResourceLoadingFailed(std::exception_ptr error) = 0; }; ResourceLoader(); @@ -72,6 +73,7 @@ public: private: void emitTileDataChanged(); + void emitResourceLoadingFailed(std::exception_ptr error); bool shouldReparsePartialTiles_ = false; diff --git a/test/api/repeated_render.cpp b/test/api/repeated_render.cpp index ce7e6cbb0..f563b0007 100644 --- a/test/api/repeated_render.cpp +++ b/test/api/repeated_render.cpp @@ -28,7 +28,7 @@ TEST(API, RepeatedRender) { map.resize(128, 512, 1); map.setStyleJSON(style, "test/suite"); std::promise> promise; - map.renderStill([&promise](std::unique_ptr image) { + map.renderStill([&promise](std::exception_ptr, std::unique_ptr image) { promise.set_value(std::move(image)); }); auto result = promise.get_future().get(); @@ -42,7 +42,7 @@ TEST(API, RepeatedRender) { map.resize(512, 512, 2); map.setStyleJSON(style, "TEST_DATA/suite"); std::promise> promise; - map.renderStill([&promise](std::unique_ptr image) { + map.renderStill([&promise](std::exception_ptr, std::unique_ptr image) { promise.set_value(std::move(image)); }); auto result = promise.get_future().get(); diff --git a/test/headless/headless.cpp b/test/headless/headless.cpp index a02062dbd..8dfed0383 100644 --- a/test/headless/headless.cpp +++ b/test/headless/headless.cpp @@ -152,7 +152,7 @@ TEST_P(HeadlessTest, render) { map.setLatLngZoom(mbgl::LatLng(latitude, longitude), zoom); map.setBearing(bearing); - map.renderStill([&](std::unique_ptr image) { + map.renderStill([&](std::exception_ptr, std::unique_ptr image) { const std::string png = util::compress_png(image->width, image->height, image->pixels.get()); util::write_file("test/suite/tests/" + base + "/" + name + "/actual.png", png); promise.set_value(); From 90fd06762c17eeb71eed69632045ae3db9f6e322 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 19 May 2015 01:42:13 +0300 Subject: [PATCH 2/7] Notify failures when loading the source JSON --- include/mbgl/util/exception.hpp | 5 +++++ src/mbgl/map/resource_loader.cpp | 4 ++++ src/mbgl/map/resource_loader.hpp | 1 + src/mbgl/map/source.cpp | 18 ++++++++++++++++-- src/mbgl/map/source.hpp | 3 +++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/mbgl/util/exception.hpp b/include/mbgl/util/exception.hpp index 0b4403270..050e56da3 100644 --- a/include/mbgl/util/exception.hpp +++ b/include/mbgl/util/exception.hpp @@ -21,6 +21,11 @@ struct ShaderException : Exception { inline ShaderException(const std::string &msg) : Exception(msg) {} }; +struct SourceLoadingException : Exception { + inline SourceLoadingException(const char *msg) : Exception(msg) {} + inline SourceLoadingException(const std::string &msg) : Exception(msg) {} +}; + } } diff --git a/src/mbgl/map/resource_loader.cpp b/src/mbgl/map/resource_loader.cpp index 620b1b137..a7dbc67d8 100644 --- a/src/mbgl/map/resource_loader.cpp +++ b/src/mbgl/map/resource_loader.cpp @@ -108,6 +108,10 @@ void ResourceLoader::onSourceLoaded() { emitTileDataChanged(); } +void ResourceLoader::onSourceLoadingFailed(std::exception_ptr error) { + emitResourceLoadingFailed(error); +} + void ResourceLoader::onTileLoaded(bool isNewTile) { if (isNewTile) { shouldReparsePartialTiles_ = true; diff --git a/src/mbgl/map/resource_loader.hpp b/src/mbgl/map/resource_loader.hpp index fb05e67e1..70b79d8fe 100644 --- a/src/mbgl/map/resource_loader.hpp +++ b/src/mbgl/map/resource_loader.hpp @@ -66,6 +66,7 @@ public: // Source::Observer implementation. void onSourceLoaded() override; + void onSourceLoadingFailed(std::exception_ptr error) override; void onTileLoaded(bool isNewTile) override; // Sprite::Observer implementation. diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index e8dc3468d..37bc40830 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -150,7 +151,9 @@ void Source::load(const std::string& accessToken) { req = nullptr; if (res.status != Response::Successful) { - Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str()); + std::stringstream message; + message << "Failed to load [" << info.url << "]: " << res.message; + emitSourceLoadingFailed(message.str()); return; } @@ -158,7 +161,9 @@ void Source::load(const std::string& accessToken) { d.Parse<0>(res.data.c_str()); if (d.HasParseError()) { - Log::Error(Event::General, "Invalid source TileJSON; Parse Error at %d: %s", d.GetErrorOffset(), d.GetParseError()); + std::stringstream message; + message << "Failed to parse [" << info.url << "]: " << d.GetErrorOffset() << " - " << d.GetParseError(); + emitSourceLoadingFailed(message.str()); return; } @@ -536,6 +541,15 @@ void Source::emitSourceLoaded() { } } +void Source::emitSourceLoadingFailed(const std::string& message) { + if (!observer_) { + return; + } + + auto error = std::make_exception_ptr(util::SourceLoadingException(message)); + observer_->onSourceLoadingFailed(error); +} + void Source::emitTileLoaded(bool isNewTile) { if (observer_) { observer_->onTileLoaded(isNewTile); diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 9d3de81b7..781e8621a 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -58,6 +58,8 @@ public: virtual ~Observer() = default; virtual void onSourceLoaded() = 0; + virtual void onSourceLoadingFailed(std::exception_ptr error) = 0; + virtual void onTileLoaded(bool isNewTile) = 0; }; @@ -102,6 +104,7 @@ public: private: void emitSourceLoaded(); + void emitSourceLoadingFailed(const std::string& message); void emitTileLoaded(bool isNewTile); bool handlePartialTile(const TileID &id, Worker &worker); From 7274d2e195b419babbc8c10e99af4f6d7803195f Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 19 May 2015 00:12:34 +0300 Subject: [PATCH 3/7] Notify failures when loading the sprite JSON and image --- include/mbgl/util/exception.hpp | 5 +++++ src/mbgl/map/resource_loader.cpp | 4 ++++ src/mbgl/map/resource_loader.hpp | 1 + src/mbgl/map/sprite.cpp | 36 ++++++++++++++++++++++++-------- src/mbgl/map/sprite.hpp | 2 ++ 5 files changed, 39 insertions(+), 9 deletions(-) diff --git a/include/mbgl/util/exception.hpp b/include/mbgl/util/exception.hpp index 050e56da3..dd0199d4e 100644 --- a/include/mbgl/util/exception.hpp +++ b/include/mbgl/util/exception.hpp @@ -26,6 +26,11 @@ struct SourceLoadingException : Exception { inline SourceLoadingException(const std::string &msg) : Exception(msg) {} }; +struct SpriteLoadingException : Exception { + inline SpriteLoadingException(const char *msg) : Exception(msg) {} + inline SpriteLoadingException(const std::string &msg) : Exception(msg) {} +}; + } } diff --git a/src/mbgl/map/resource_loader.cpp b/src/mbgl/map/resource_loader.cpp index a7dbc67d8..90c87c142 100644 --- a/src/mbgl/map/resource_loader.cpp +++ b/src/mbgl/map/resource_loader.cpp @@ -126,6 +126,10 @@ void ResourceLoader::onSpriteLoaded() { emitTileDataChanged(); } +void ResourceLoader::onSpriteLoadingFailed(std::exception_ptr error) { + emitResourceLoadingFailed(error); +} + void ResourceLoader::emitTileDataChanged() { assert(Environment::currentlyOn(ThreadType::Map)); diff --git a/src/mbgl/map/resource_loader.hpp b/src/mbgl/map/resource_loader.hpp index 70b79d8fe..5b7863a6d 100644 --- a/src/mbgl/map/resource_loader.hpp +++ b/src/mbgl/map/resource_loader.hpp @@ -71,6 +71,7 @@ public: // Sprite::Observer implementation. void onSpriteLoaded() override; + void onSpriteLoadingFailed(std::exception_ptr error) override; private: void emitTileDataChanged(); diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index cfc097457..d8cadbeb3 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -1,17 +1,20 @@ #include -#include -#include -#include -#include #include +#include +#include #include #include -#include +#include +#include #include +#include #include +#include +#include + using namespace mbgl; SpritePosition::SpritePosition(uint16_t x_, uint16_t y_, uint16_t width_, uint16_t height_, float pixelRatio_, bool sdf_) @@ -39,25 +42,31 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) std::string spriteURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".png"); std::string jsonURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".json"); - jsonRequest = env.request({ Resource::Kind::JSON, jsonURL }, [this](const Response &res) { + jsonRequest = env.request({ Resource::Kind::JSON, jsonURL }, [this, jsonURL](const Response &res) { jsonRequest = nullptr; if (res.status == Response::Successful) { body = res.data; parseJSON(); } else { - Log::Warning(Event::Sprite, "Failed to load sprite info: %s", res.message.c_str()); + std::stringstream message; + message << "Failed to load [" << jsonURL << "]: " << res.message; + emitSpriteLoadingFailed(message.str()); + return; } loadedJSON = true; emitSpriteLoadedIfComplete(); }); - spriteRequest = env.request({ Resource::Kind::Image, spriteURL }, [this](const Response &res) { + spriteRequest = env.request({ Resource::Kind::Image, spriteURL }, [this, spriteURL](const Response &res) { spriteRequest = nullptr; if (res.status == Response::Successful) { image = res.data; parseImage(); } else { - Log::Warning(Event::Sprite, "Failed to load sprite image: %s", res.message.c_str()); + std::stringstream message; + message << "Failed to load [" << spriteURL << "]: " << res.message; + emitSpriteLoadingFailed(message.str()); + return; } loadedImage = true; emitSpriteLoadedIfComplete(); @@ -80,6 +89,15 @@ void Sprite::emitSpriteLoadedIfComplete() { } } +void Sprite::emitSpriteLoadingFailed(const std::string& message) { + if (!observer) { + return; + } + + auto error = std::make_exception_ptr(util::SpriteLoadingException(message)); + observer->onSpriteLoadingFailed(error); +} + bool Sprite::isLoaded() const { return loadedImage && loadedJSON; } diff --git a/src/mbgl/map/sprite.hpp b/src/mbgl/map/sprite.hpp index ccf256161..13cfbe2d8 100644 --- a/src/mbgl/map/sprite.hpp +++ b/src/mbgl/map/sprite.hpp @@ -39,6 +39,7 @@ public: virtual ~Observer() = default; virtual void onSpriteLoaded() = 0; + virtual void onSpriteLoadingFailed(std::exception_ptr error) = 0; }; Sprite(const std::string& baseUrl, float pixelRatio); @@ -56,6 +57,7 @@ public: void setObserver(Observer* observer); private: void emitSpriteLoadedIfComplete(); + void emitSpriteLoadingFailed(const std::string& message); void parseJSON(); void parseImage(); From ac64bef87f5c0b3d23be59de984fd93eb7f2378f Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 19 May 2015 00:28:55 +0300 Subject: [PATCH 4/7] Notify failures when loading tiles --- include/mbgl/util/exception.hpp | 5 +++++ src/mbgl/map/resource_loader.cpp | 4 ++++ src/mbgl/map/resource_loader.hpp | 1 + src/mbgl/map/source.cpp | 21 +++++++++++++++++---- src/mbgl/map/source.hpp | 2 ++ src/mbgl/map/tile_data.cpp | 23 +++++++++++++++-------- src/mbgl/map/tile_data.hpp | 5 ++++- 7 files changed, 48 insertions(+), 13 deletions(-) diff --git a/include/mbgl/util/exception.hpp b/include/mbgl/util/exception.hpp index dd0199d4e..7ef8ea976 100644 --- a/include/mbgl/util/exception.hpp +++ b/include/mbgl/util/exception.hpp @@ -31,6 +31,11 @@ struct SpriteLoadingException : Exception { inline SpriteLoadingException(const std::string &msg) : Exception(msg) {} }; +struct TileLoadingException : Exception { + inline TileLoadingException(const char *msg) : Exception(msg) {} + inline TileLoadingException(const std::string &msg) : Exception(msg) {} +}; + } } diff --git a/src/mbgl/map/resource_loader.cpp b/src/mbgl/map/resource_loader.cpp index 90c87c142..ddef11293 100644 --- a/src/mbgl/map/resource_loader.cpp +++ b/src/mbgl/map/resource_loader.cpp @@ -120,6 +120,10 @@ void ResourceLoader::onTileLoaded(bool isNewTile) { emitTileDataChanged(); } +void ResourceLoader::onTileLoadingFailed(std::exception_ptr error) { + emitResourceLoadingFailed(error); +} + void ResourceLoader::onSpriteLoaded() { shouldReparsePartialTiles_ = true; diff --git a/src/mbgl/map/resource_loader.hpp b/src/mbgl/map/resource_loader.hpp index 5b7863a6d..9d94cb649 100644 --- a/src/mbgl/map/resource_loader.hpp +++ b/src/mbgl/map/resource_loader.hpp @@ -68,6 +68,7 @@ public: void onSourceLoaded() override; void onSourceLoadingFailed(std::exception_ptr error) override; void onTileLoaded(bool isNewTile) override; + void onTileLoadingFailed(std::exception_ptr error) override; // Sprite::Observer implementation. void onSpriteLoaded() override; diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 37bc40830..b0c4e22f5 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -287,22 +287,26 @@ TileData::State Source::addTile(MapData& data, new_tile.data = cache.get(normalized_id.to_uint64()); } - auto callback = std::bind(&Source::emitTileLoaded, this, true); + auto successCallback = std::bind(&Source::emitTileLoaded, this, true); + auto failureCallback = std::bind(&Source::emitTileLoadingFailed, this, std::placeholders::_1); + if (!new_tile.data) { // If we don't find working tile data, we're just going to load it. if (info.type == SourceType::Vector) { new_tile.data = std::make_shared(normalized_id, data.transform.getMaxZoom(), style, glyphAtlas, glyphStore, spriteAtlas, sprite, info); - new_tile.data->request(style.workers, transformState.getPixelRatio(), callback); + new_tile.data->request( + style.workers, transformState.getPixelRatio(), successCallback, failureCallback); } else if (info.type == SourceType::Raster) { new_tile.data = std::make_shared(normalized_id, texturePool, info); - new_tile.data->request(style.workers, transformState.getPixelRatio(), callback); + new_tile.data->request( + style.workers, transformState.getPixelRatio(), successCallback, failureCallback); } else if (info.type == SourceType::Annotations) { new_tile.data = std::make_shared(normalized_id, data.annotationManager, data.transform.getMaxZoom(), style, glyphAtlas, glyphStore, spriteAtlas, sprite, info); - new_tile.data->reparse(style.workers, callback); + new_tile.data->reparse(style.workers, successCallback); } else { throw std::runtime_error("source type not implemented"); } @@ -556,4 +560,13 @@ void Source::emitTileLoaded(bool isNewTile) { } } +void Source::emitTileLoadingFailed(const std::string& message) { + if (!observer_) { + return; + } + + auto error = std::make_exception_ptr(util::TileLoadingException(message)); + observer_->onTileLoadingFailed(error); +} + } diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 781e8621a..303d4d024 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -61,6 +61,7 @@ public: virtual void onSourceLoadingFailed(std::exception_ptr error) = 0; virtual void onTileLoaded(bool isNewTile) = 0; + virtual void onTileLoadingFailed(std::exception_ptr error) = 0; }; Source(); @@ -106,6 +107,7 @@ private: void emitSourceLoaded(); void emitSourceLoadingFailed(const std::string& message); void emitTileLoaded(bool isNewTile); + void emitTileLoadingFailed(const std::string& message); bool handlePartialTile(const TileID &id, Worker &worker); bool findLoadedChildren(const TileID& id, int32_t maxCoveringZoom, std::forward_list& retain); diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index e9084bdff..be0d7d32f 100644 --- a/src/mbgl/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp @@ -1,11 +1,13 @@ #include + #include #include - -#include -#include -#include #include +#include +#include +#include + +#include using namespace mbgl; @@ -34,15 +36,20 @@ void TileData::setState(const State& state_) { state = state_; } -void TileData::request(Worker& worker, float pixelRatio, std::function callback) { +void TileData::request(Worker& worker, + float pixelRatio, + const std::function& successCallback, + const std::function& failureCallback) { std::string url = source.tileURL(id, pixelRatio); state = State::loading; - req = env.request({ Resource::Kind::Tile, url }, [url, callback, &worker, this](const Response &res) { + req = env.request({ Resource::Kind::Tile, url }, [url, successCallback, failureCallback, &worker, this](const Response &res) { req = nullptr; if (res.status != Response::Successful) { - Log::Error(Event::HttpRequest, "[%s] tile loading failed: %s", url.c_str(), res.message.c_str()); + std::stringstream message; + message << "Failed to load [" << url << "]: " << res.message; + failureCallback(message.str()); return; } @@ -50,7 +57,7 @@ void TileData::request(Worker& worker, float pixelRatio, std::function c data = res.data; // Schedule tile parsing in another thread - reparse(worker, callback); + reparse(worker, successCallback); }); } diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 3945a3214..0d34b2df7 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -44,7 +44,10 @@ public: TileData(const TileID&, const SourceInfo&); ~TileData(); - void request(Worker&, float pixelRatio, std::function callback); + void request(Worker&, + float pixelRatio, + const std::function& successCallback, + const std::function& failureCallback); // Schedule a tile reparse on a worker thread and call the callback on // completion. It will return true if the work was schedule or false it was From ee9b172152c7e462f2c204ea7b85c3cc4bd04582 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 19 May 2015 00:38:10 +0300 Subject: [PATCH 5/7] Notify failures when loading glyphs --- include/mbgl/util/exception.hpp | 5 +++ src/mbgl/map/resource_loader.cpp | 4 +++ src/mbgl/map/resource_loader.hpp | 1 + src/mbgl/text/glyph_store.cpp | 59 ++++++++++++++++++++++---------- src/mbgl/text/glyph_store.hpp | 10 +++++- 5 files changed, 60 insertions(+), 19 deletions(-) diff --git a/include/mbgl/util/exception.hpp b/include/mbgl/util/exception.hpp index 7ef8ea976..da61aa482 100644 --- a/include/mbgl/util/exception.hpp +++ b/include/mbgl/util/exception.hpp @@ -11,6 +11,11 @@ struct Exception : std::runtime_error { inline Exception(const std::string &msg) : std::runtime_error(msg) {} }; +struct GlyphRangeLoadingException : Exception { + inline GlyphRangeLoadingException(const char *msg) : Exception(msg) {} + inline GlyphRangeLoadingException(const std::string &msg) : Exception(msg) {} +}; + struct MisuseException : Exception { inline MisuseException(const char *msg) : Exception(msg) {} inline MisuseException(const std::string &msg) : Exception(msg) {} diff --git a/src/mbgl/map/resource_loader.cpp b/src/mbgl/map/resource_loader.cpp index ddef11293..5aa714595 100644 --- a/src/mbgl/map/resource_loader.cpp +++ b/src/mbgl/map/resource_loader.cpp @@ -104,6 +104,10 @@ void ResourceLoader::onGlyphRangeLoaded() { emitTileDataChanged(); } +void ResourceLoader::onGlyphRangeLoadingFailed(std::exception_ptr error) { + emitResourceLoadingFailed(error); +} + void ResourceLoader::onSourceLoaded() { emitTileDataChanged(); } diff --git a/src/mbgl/map/resource_loader.hpp b/src/mbgl/map/resource_loader.hpp index 9d94cb649..33949aa48 100644 --- a/src/mbgl/map/resource_loader.hpp +++ b/src/mbgl/map/resource_loader.hpp @@ -63,6 +63,7 @@ public: // GlyphStore::Observer implementation. void onGlyphRangeLoaded() override; + void onGlyphRangeLoadingFailed(std::exception_ptr error) override; // Source::Observer implementation. void onSourceLoaded() override; diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 4ee853b1e..72c7b16a8 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -1,20 +1,23 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include + #include +#include namespace mbgl { @@ -139,7 +142,8 @@ GlyphPBF::GlyphPBF(const std::string& glyphURL, const std::string& fontStack, GlyphRange glyphRange, Environment& env_, - const GlyphLoadedCallback& callback) + const GlyphLoadedCallback& successCallback, + const GlyphLoadingFailedCallback& failureCallback) : parsed(false), env(env_) { // Load the glyph set URL std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string { @@ -149,20 +153,20 @@ GlyphPBF::GlyphPBF(const std::string& glyphURL, }); // The prepare call jumps back to the main thread. - req = env.request({ Resource::Kind::Glyphs, url }, [&, url, callback](const Response &res) { + req = env.request({ Resource::Kind::Glyphs, url }, [&, url, successCallback, failureCallback](const Response &res) { req = nullptr; if (res.status != Response::Successful) { - // Something went wrong with loading the glyph pbf. - const std::string msg = std::string { "[ERROR] failed to load glyphs: " } + url + " message: " + res.message; - Log::Error(Event::HttpRequest, msg); + std::stringstream message; + message << "Failed to load [" << url << "]: " << res.message; + failureCallback(message.str()); } else { // Transfer the data to the GlyphSet and signal its availability. // Once it is available, the caller will need to call parse() to actually // parse the data we received. We are not doing this here since this callback is being // called from another (unknown) thread. data = res.data; - callback(this); + successCallback(this); } }); } @@ -234,8 +238,10 @@ bool GlyphPBF::isParsed() const { GlyphStore::GlyphStore(uv_loop_t* loop, Environment& env_) : env(env_), asyncEmitGlyphRangeLoaded(util::make_unique(loop, [this] { emitGlyphRangeLoaded(); })), + asyncEmitGlyphRangeLoadedingFailed(util::make_unique(loop, [this] { emitGlyphRangeLoadingFailed(); })), observer(nullptr) { asyncEmitGlyphRangeLoaded->unref(); + asyncEmitGlyphRangeLoadedingFailed->unref(); } GlyphStore::~GlyphStore() { @@ -254,19 +260,26 @@ bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStackName, return requestIsNeeded; } - auto callback = [this, fontStackName](GlyphPBF* glyph) { + auto successCallback = [this, fontStackName](GlyphPBF* glyph) { auto fontStack = createFontStack(fontStackName); glyph->parse(**fontStack); asyncEmitGlyphRangeLoaded->send(); }; + auto failureCallback = [this](const std::string& message) { + std::lock_guard lock(errorMessageMutex); + errorMessage = message; + asyncEmitGlyphRangeLoadedingFailed->send(); + }; + std::lock_guard lock(rangesMutex); auto& rangeSets = ranges[fontStackName]; for (const auto& range : glyphRanges) { const auto& rangeSets_it = rangeSets.find(range); if (rangeSets_it == rangeSets.end()) { - auto glyph = util::make_unique(glyphURL, fontStackName, range, env, callback); + auto glyph = util::make_unique(glyphURL, fontStackName, range, env, + successCallback, failureCallback); rangeSets.emplace(range, std::move(glyph)); requestIsNeeded = true; continue; @@ -312,4 +325,14 @@ void GlyphStore::emitGlyphRangeLoaded() { } } +void GlyphStore::emitGlyphRangeLoadingFailed() { + if (!observer) { + return; + } + + std::lock_guard lock(errorMessageMutex); + auto error = std::make_exception_ptr(util::GlyphRangeLoadingException(errorMessage)); + observer->onGlyphRangeLoadingFailed(error); +} + } diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index e13ed1f1d..77452a305 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -59,12 +59,14 @@ private: class GlyphPBF { public: using GlyphLoadedCallback = std::function; + using GlyphLoadingFailedCallback = std::function; GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, Environment &env, - const GlyphLoadedCallback& callback); + const GlyphLoadedCallback& successCallback, + const GlyphLoadingFailedCallback& failureCallback); ~GlyphPBF(); void parse(FontStack &stack); @@ -91,6 +93,7 @@ public: virtual ~Observer() = default; virtual void onGlyphRangeLoaded() = 0; + virtual void onGlyphRangeLoadingFailed(std::exception_ptr error) = 0; }; GlyphStore(uv_loop_t* loop, Environment &); @@ -110,6 +113,7 @@ public: private: void emitGlyphRangeLoaded(); + void emitGlyphRangeLoadingFailed(); util::exclusive createFontStack(const std::string &fontStack); @@ -122,7 +126,11 @@ private: std::unordered_map> stacks; std::mutex stacksMutex; + std::string errorMessage; + std::mutex errorMessageMutex; + std::unique_ptr asyncEmitGlyphRangeLoaded; + std::unique_ptr asyncEmitGlyphRangeLoadedingFailed; Observer* observer; }; From 6ef6591a526fd23e95f0ee854e8d57ee273ccf7e Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Mon, 18 May 2015 13:32:56 +0300 Subject: [PATCH 6/7] Add MockFileSource and MockView for testing the ResourceLoader - MockFileSource Will load pre-defined resources from the filesystem. It supports passing a string, that when it matches an URL, will simulate a failure. - MockView It is just a no-op to not get in the way when testing resource loading. Few more additions: - style.json Specially crafted style that will look always for the same tile, glyph range, etc at the "test/fixtures/resources/" path. No matter where you look (or at what zoom), you always get the same stuff. - vector.pbf This taken from a part of Taipei that will request several glyph ranges. --- test/fixtures/resources/glyphs.pbf | Bin 0 -> 74722 bytes test/fixtures/resources/source.json | 1 + test/fixtures/resources/sprite.json | 1 + test/fixtures/resources/sprite.png | Bin 0 -> 39041 bytes test/fixtures/resources/style.json | 31 ++++++++++++++++++ test/fixtures/resources/vector.pbf | Bin 0 -> 103021 bytes test/resources/mock_file_source.cpp | 47 ++++++++++++++++++++++++++++ test/resources/mock_file_source.hpp | 33 +++++++++++++++++++ test/resources/mock_view.hpp | 21 +++++++++++++ test/test.gypi | 4 +++ 10 files changed, 138 insertions(+) create mode 100644 test/fixtures/resources/glyphs.pbf create mode 100644 test/fixtures/resources/source.json create mode 100644 test/fixtures/resources/sprite.json create mode 100644 test/fixtures/resources/sprite.png create mode 100644 test/fixtures/resources/style.json create mode 100644 test/fixtures/resources/vector.pbf create mode 100644 test/resources/mock_file_source.cpp create mode 100644 test/resources/mock_file_source.hpp create mode 100644 test/resources/mock_view.hpp diff --git a/test/fixtures/resources/glyphs.pbf b/test/fixtures/resources/glyphs.pbf new file mode 100644 index 0000000000000000000000000000000000000000..0d160f78989795546bd6e27824a99194ab9a7f63 GIT binary patch literal 74722 zcmeFaWpGGFG4eoT(={Ozeq|;$$a2z|1A%>WlnQd9NY?+yvEt5<#Gs(8h%xoEC zPV(OO-di4XXXe>Ql9Rr7puVd2&i$rpc2(rFmyQnXz1P}nJqvR3%lvmI z9~t<$F|V6AF$1m}yLkk8JNZApuHsL3^1g1yq`UaKx?R^Zk$fZl{qrX;Wn?a&lDdA0 zcAa*g_Wae`A1;46CUrwvaLmZvKQJ)R+eXzjCa<8NAl1**H@l6`=a)s=`sQ>Bgd^pV zwmwoxY-AbB~n9c_F_b(9|udes-%T zKfuH_v2JFgE01O59A7iF&dc>Pbc(BN~_#j<2?7`RLh4bH|ojGZ;Fyk>vve z&FNm+ZqY@J&6VlCrvACD(~JFOQTD+_ecS&$RTJ+LSkSY+H(nL%_a zQCyN2W`>BRN3_rH677B5(NOzNg|?lBu5yq{k{U|@iUiC-#SF`Hdb zz>al~D#u&ab@KV`xva?Y5#ek@*9LjY@Y2Ek>Do@gYI`;_q_}@~vbuehJYrBGUpU5X zSz2gHqx-YFH%H2w7Umj~-TiVq1%oB^v(vSSu0EN~U7dwhU0s#2PR^0pdAadvd3mY+ z7Wyu}ES9G?i{)*re(8tnKTuEj)8)exQn#d6PS9wyt8&I<9(+8E4_}JQ7Utej<^agDVZI^s(jpG9}>ySJy zmpdlpbGd{2gE%aScXthqi%Y7XS?$QdEqV&#Vj_LagY&AZt6P`mo2nb;R@$qpxv302 z%)sR2+b<={* z+{&>neqnZYW~7UTxd$`7WpS}Now~O#)5lr=je-%GtLeH-a_>~SzMi_w4OxreqF%u$ zm)#|p#1d0|a_{m_pcQs>b{6Ngb#|6U+P(i%ibi{`M~}+XgA-R zy8HV2dbr|)ZmDwbXV5PFg7tSC>+j6v$`ewzrE@X6S7eRc1A~KEPTJ2d{c`-r%MaCE zqS-}7*}>LIZysO0{#wJ-JF}&)uO{BZ-b_pOjh>@_bY|PibZusGRDi3#j!Sq}d1L3w zG_S3`EHA>rCN!^ca8|IhwZ1Yv)R^K)Pp%ykZqBYwPcLkaS0}gy=JQt9`|g6AGjC5{?*C5e zj&##^*Wc>f`-Db>v0O})70taMDtzqJADyAS)^iU}D=sU^j`1-wU?k=j6r}l^zr9RT za}3X~=MN9IlqPuDhZlA6`4!O)O4n${z8Q@Z>l@p1yuvVMdc)LaA6AdzpET<*PT$s4 z*RXK1E-9*{cVns{ooS2}P_y1VCBI&)dZhCb;HW9yqc^IemheZ9g_ZpH9UUva3_2Zyk{x}M>|R`NS6PHwkE1#9siWowet>*rCzCG6uX9)e)8H26^nqJ*7+44 zC7d`A_#+ij_Ox@)bUYHMS4zz9-W;#08pC4;ThOk(w+?1^EG@R@1!cC(tqcyXEVkwN z8vbxs-7T?ZOfXmx=N41OpWohI=)<9=h~C-Rob7MUOet&a?QN|{^D~zt*9l6?$;paz z*0A=C$u2C)iDlWUKBS#{s%hu#>&t}9P&IX7fpuNY)Sh0rBrWFcbC=V;le#PYzn!3+ zeV}CQ>=PUj8P4*s)OhhbBmj-}(``j_@92!evhtFgM1OmYC(?v^;gumHp`@i}cx0fX zG9$q1{k3DD-c+&+=kR7X_jh+z2C5R>wH}=Y^|1~;rEco;{NTXU?s7-2zp2axP@fz6 z<#etIy305%^SfjhmLvCjVZ_So+Q9rL)y*6Xl}6aSyLLtT#4`hCR@?GcZz+ejve{c0 zY_6pA?%CD*n(i2&gSigg?7?(n2Gha8!Ae`^#(V3K{Py|7>E)f7_M(Wen3$MgXDu0h zw@7wf-|82^NJ~*{L_uX`Wlo@lnqx$M%lP`{(!or7aa>Z}`1mmN0%K-I)5Pv_f6vn4 zYzHU1Z5g6I$igWQ&d$!Vs5|e?Ji`*R3X2Qb>G6SHv5@yUNxr|{d#7jX z<{K0e)oObT9h8>gW zZq`5DQL+k1hia4Jd+D{IcXB14-%}cKU(GR+)3dVLT^uHB0?{XukL^%?qu(}$Z-_!f8i zIbqiFS0HRxC{6G6dEe}gwN1!$W#5*o6EiKxU zcKWW8sSBM>cQ(58{q^(Imi!|bx(66KO9qC`*Fp2yd75_;#Ck@M?T7oPLW{fk{F+o> z6WJ@l`JGFG-m(~%j}JW(xP!vE7Kjdc3;(R9*&Rq17Yz-k=<>nc#nvoeBUxyw?aM+U z5FdfPL?h;SO$nM5HIAN_WX*#M`CCNaJu6~XL1&KN8E~k0oK8Q{lZ+{-MC;z@V*8(a zY3vWi#<{+i8B!u(_J6+&@G6X6Sgwr5;LGAE%v=ex~Kf3JD1baM68v;d|P-8xIw%gR_c@ zi*v*5lpfu>@I+Bd*Ez1bzrVje$z4}R<%OEHr?-1-)%fmoU81YEmz|b{e{yCb7~>N* zg@lZ>U^|z1Zd+|BXJBu%qNJv!E|u*!!lFuyswwtKjN z701kO9~d5;nBJS87#kkwE(mms&F7R=4sMO^jMkQM3KP9dJcD9Nx>weCOY8j=iNOpD z3=+F-?#pD|$o^7SaioK?0*sE~~K59$C^%o z3GAw(sNAZe6M_U7HM_YZR=huF|^z-$f zvD%1wfgyWDhKzRXPkB>%aA;_ti|z|(AT-*^2b%72g&a;URFvy9+KDq4p6Zh~8o&st z-9CTn&nIu*g3z%xLkMqQKX|KcW@#xQSX!EB7`O$7hK7pHzyZs_F_O(eBR?U3GXp(S z8wW^Ro1y-2V~CothxTcoe2!NV!Vqa|Gt{5T7^kR$QZ#Z6@;5uk&?6)~JX~}a90WMY z>sne{OP<5p+D!Atb2<61Pbx3__oM@fTvrXt~E1mzH8gm9CRb@A$QM zW{lAA@F0vRHa78)UBr-uOFfqMex+^aNvC_->#8}1rlh5%hB@o|WYje`H)Q*p2IO}y zE)H-)t-?41yK9|!{$Pi(&olKYbPs4dyMwS7$;P+bp5t!{uG<`|PIT7{DdKf^7KB(U zFcR5pc0670xjEh6-`~^h{Y}`5KVZ6^y#4;Nv(yu5Q*-iMqy@VhcqZVXNz0FPfPAI~ zX{aH^gNV8VwE0Hr7{(78j_FBdFnZ96qMa;#BcrJnPB((ZcMSKq^Y+Kf4pL90jTDWX zJiS~k)SsI&qEpin{OwfT;y8`XT*~NepZUKwdiw|4{+-bqAToMSK&5>GqxZiYmwG0> zk2Qy3zxTn~8-k8$|B-Yr${72mV2{WMv_$W_o66Wmd-!}vcXZD@fyPlkEgUM3c0l(s zIDySuTkXsXFr(3ayrb$AQ!%_hRhR6kO{1NAVc?VAG`HPf5@DxAqy4F19a_ZSTx!eq zGk#6``N2oGgzE86V^#648uw`zUSnHsTiSpjV)gFoi5p6G5hc(AAf5D|OaJm%+cUXt zYJa#Q#!2nMch|oo-Ag}V->1R8le*k~Lh89R_r!O9ywZS@7#0~3 z;%%p|`0yO<(hEq)m~2jYX;EsJm!kE^7Oy#e=HDhJe4$N;K z9IQ`vm&SQ$Kh=QYHL$)tGc>$-FyFxrvQmHw*E+vD(p*~6F|$8fmEfw5ZJNKe)Rr3+ z&*|M-Y)NP6+D5|8pQ=f4V?si%cjft;xWrdaej2TawkJY#mu%S{DGhVG1Dr4`05Owa z#<=)Og4z(%{%;Tk4%nR+sg0VV5N#duW1d2G9Am2{sB>VK%2xjZFgBUF$0y`Eki*{oB+t>v^X&Oz)4kS5|k= zi{9&leFUd_d4FMiV)bCIogHMU05v9w+da9yv%NCbSrY56{p604B`dkGuDh?7SItiF zHj%$3{RpT=SZaPzAv-D9!(8d^Y1)M+O8R!*0l`83o>n>v52R_APKouj)0b--q7zatrBhB^d#Pq@PY(=>2oGd987n{j?X9l8Ut|iqq^vYQE!x}a!$Uo{ z(2SCL-r(?HS7S-CuZ4nLIJ>@odTnoie|@f}Ji$W?%Vd0Wb7o|4bn$SpBQL<*A+nga z*w?Rz5+T8HjMY?eo2|}evVj1gZne}Np256SbBK7n`ybm zRgQh0sETts|LDDz?niaI;M}%_tv*hKE$!^}hfmaO{4;7tcW0Y3nMN?Ro~T*-r&SHC zuXJ;wozy_0Ii;RF)>=cPq)8?A^U1i?`Qfu35A zSvYC{2SPK5jUj1COl=1r%*RoKnep?{^2Nlw!o=K@)3J1824iA^yj{#xpZ~6G>K+`Q zRfvfx$cXc^(|BgijAd7~@dt;8x|_?>18h}XlJ1t5X^JWa;j&O$`r@ zF6^!K6ouM2$8fqQd3EI_6|FO$Cu$SjjKO{Ng~?H2v84lh3r(q>N>;4+gyYtyC=36yCCl`y|oPG49w0gY%EXm$`ifxMFfFh zeP?B+zaclo_L8hc2tnGq`o}l6Mr)Hj@5}0Y#Q|Z<flH)Hvh0JSP$6u zEqtS6gXqro4qm{Ufn$bwB$idOQ{$qelZz7MK?TLb(wVRKBP)Kl~kE^YL;^T|oObqsc*VqTh?m#>9K+TpZQH}}W$D0b~eraOu z_y(a|ey#7BP|-)J#~OD*kbbP;6j9i@xJ%GvLOFRG=3G|elt3t^9KR}S#7L?d5{_?* zDd(SQxkPiiSC)IWM3mF_RBVHDTV}Qf_~Kt(lQ(6i){O2>G)O2fVJMaL3KlvFBosCK zFc|*pePt5LOAA&;{rKK!ZJL;3r$8&It}%?0oX-8 z&57Ff;@n(+aR?|I;&!;Tu>neSMVGkYS6zU~gIOtgqDEagFE7E%hQXp*py*yKPcvmb zBhpMk5s)|4R=EB21=?$DD}ZOK6W!GB{BY(h+GA~Z0?wudS--zV#+i2Fn!GWw*1hdM zK9&AvANb#oOUX$8Psdd$Zn$e>1*Up{2=^-MA8z19o5O63wKC#RH(0;tBuwxMn=ohT1N%9 zqBtut&{mdwnCfw959zLA+7;Yd}y zn^Rb31-GQQxT1Mr{jU0s}!5EGM9+_SOT$qtOF809zDR8}_dWu>?z%x|^aXx169sFZba|(-!AcaCa%#`nIm^ssZgMz^^ zE>?Q)?wff2x%fm$*UHU5Bplm}mxa=8+C@lidT>HcacNmeK_Wx{`LB=E zY*@+pRqg#l!-L)MGs#|8uwbQfyGECG_jZ9fhFHkH(Dh7!FyCDsALt*ZC<->A1)WR6 zvG!_Cad~B?pYba-s6`WpQ;m6vVIh$*fez{qbQ$T*3tRl6_@sm=mb<0q%im3jrn1yp zQd3`BmXqLXt#aR%pc9i#eN(g3gYD%hOj9{B>z_wwHdj|RcNY0&ajxpbyLC9T(BIL< zpW0t&&14#qmGCc1yt3@fqPE4Y-r_K8a?Y2r$^<{}`0DX5MBl=7#yn1=iXHbFrf62=jd_X0)CH#0M{pT>5-D(ET*v9e;t zQJj;QST%YuS(oCar)J^oN?Jf}`_d-AINVP8k-Vy!n%YO#IPUNs5%h*H&-`)g_H9{H zR(9)xupg3M^$x_q$$M(fG3A3h^DS9^CNh^G87{#T%50w79jb_RQNIs+LFY{8r zrS{wa^S8td09xyl-Z*mrwcB0u5scU$ZYkS^7xOn(dHKOs@BV}td+xbDBei}C`(-k) zva>YWcQ+JmLJPYE>pcX+x&eFP>{A`jq?!r%InuoKU;KvaUVUd336XQoDDOQ1GjORHzBbzNWI534wO@iH0o$!i{dF`hXzD zc&V?NE>wlLP!&$!me;lOWIddZyZc*9!}VD#Q(d^1Cia&{`UfXBwg$?golFAqyVlnDRh*Lg zkzE*aUgq%6?!ccG8V>FuAQy1F9vCOtVbMk8Z#u)k7xS?_)KJ7}ojMqW$cCv?(Z9Ae z(aoRPn{Ha>g`&&REsT|l?8Ezk% z+h6YG#=F}`0o+;USLT+tjqfgXumfGebqB+hDS@%JR)#m(gfSN!BvD!}A&EI9Wt@W42)fDpd$07|quAAe zxCVOai{coja;oq-wTv(C?(eNnb#UU`v|tW5PVBBs42~=w&bH+RSy>W;c%`SNgxfK* zH&T`8M&!t+iR$FAI8KiME+!`YL9@glw80jDt*J1W`0R<%XHE=5;@2lA{QgjRlwU|j z!^|hR{vD&shxTWhIk|A!t$%!Cw7X?tqdPzFk(#YvLUw6oRRu8S#g+{3TM9;wZhjFlvGEln2a`1kuCEN} zQAsh8(dnGdrHuhV#P4mxi|Q-OxlR1p-O;)XmWdKEOUFha{6k!{v{!D*M zQIxCp3nlyLavlKv?uL@A7`mbCRasNtDXg68$3PJQTvs$6)TlpkQw6m(ZD;I+uc*26=*?%1eQ04xX}(oE8qJ&*>cPR z3wVpG1LaY6y7Z)qw)W~wKT}03zxd4T)1kK4D zVRIT^!MP)J&hiMJGd;rRw2uHfa!nG}HVT+}T_cYSlFpBoK7V0bFk-I(reEX@e82_oI8b-^URfs+yCYwwX1k=%2jfkCtv98+U^k{!KD_!MR08)k*wpSdw+wSA9X4td_ZpUsPIAEe~oAd9bUGjFpXCN{NVfCni;1tVk z|JvFLL(EypS>Lo+x>IaL>(|y&5KOMIeAL7joj+C86{(TCrfRGr`OMlj5V66cT{YUht*e-OI%46I}s!uoF$F3 zFqxyBAO%ZEWOkR2NbjFsC$qb_15&lF_BK_Ob6chk$ExC-wLKDwIT^8$F@X08Af#aK z9Tw)}>=sorut)qy50nh8t&KdQ*e%oh#PcP6`=z{rM|5G!#O{21UZ4d4Xm!Vk!q%zX z`L5D9cWv7FSH^y@rT6D}rHKGuX;&3&!b|#va~+%n9}A^>$3%eJR&Plh!%X?1^od)l zWHpi~HB-g==V(;FW?-N-(_8m3bi7j!HC>|$5uujhXDSQ#yYx#VR!+;*;sAhioOm$Jc6Q=vhwotvXZ0yT}@OT;Tx%IZ}gl464@2?ZCyQGZS@s7F-*%3 zkAC~^PZ?d8@a(G2k(uRx(^Qv2L2LjC@k-Muju&<=KU06=lWj+M)INHfYoE-*Wit zvmM374c)_|!+pHE+OgdsZj7Tg;IOHU-V#pd%=+f~*3L>B6ifJ>JxP?-+H7N1>&*5f zpVzap)Pf+cmG*33%TPE$N4cCn;dE0`ZpRvMsVW4tZ;h3oy zB`#_baJbpcZkWRdJnb8^^+||^!7(w&s4wvI2n0w?*QPeil6w$61HY^u-yNyRgUfuj zfzu@*-d4LPctA!f5XmFx>l)b_-5l(m#nVSRP@a;xri_L$!S=?+c-N9}Q!reY&NPBY zrD0~hrzEewdw7`NSOEu8Pi=OHy{fW9R2h8Aon<+NWo1R_83ko!g()FUS})$1`e#F_ zTNvo5tthXoY3UxWj6sCY>pvcTbb|UfCfHe-9338?TG)V$a8Q1J^~cMIQHsi|>l&Hg z*xD8f7N`2K!7E++j`kx|O4rcTd~Q=$PcOf-xt5aw%ZAtvr*6sW*n0)VrsowD7UZTU zhWpxUAlM1*quHRPQH3?Q9~lM>O6A<8DSsJpL^czGy?3+ShbtGs4>heU)JQ0pGV zOL%{{(up5C%tjO*L;K-230N519owC#kwnMPq~Q!ADs1m60?zy?J|uo9$|bbeIt?8^ z+VKN1u1-Cac%%BaXB%OIJx3_cB^eV|PTSIYccI8JMSMg*+){A>vblqk;Jl*zNDoh) zeWu4qZJ5~`DlY~`LNFG@{SgDMpnH7<{_Xz$xt)R1NC%Z$4?YtA)8WA`X?y=X(*Q~L zOon)&7Pk=0NSZ(Zac3z{yl(y5^Ua8WtgddDJ{+xtpG?;)wI1S(8%G+R0&xX?#*|B+ zIK!NroQMyN^0&FfRgNA`5to<>-V81;att@oqJZ+o-K5-N#FPnSW;G+?3Ddy`#;}C^cK)(IJ)$mnIzW9;LR1<#aB9x1c7!lxpYP>cg_$$*9Tbt zS`NM<)8F6M)7eVr-92gR;7pO-&(2Pb3-&Nox`)6Hk@er*(OAWf^EQ3T+=a#k)=Gt=n%?RaSsHUd2p>060GguzuD58|cCnRUrP5zB2+hR&M z-5a>nXCht2l(e+WeAwymMmdNmfaBYEBO8ky>|jem`9u);<+Y`W&hmJ79YXoMg0{A? zI@1TV-&*vmwzjs8?$OnaA*?bHr8F}$C%g-5IS)#Wg z&;YTEpuM3YKaOdkWJ%fn#7mHs5*_4Wrt(l^`(vVfedvznI`Tl*i1kn6p3hvKIU%Jg z-3uoD_3m43OE+)g#0h0FoXs_9XYMMRxCJF-l|PV30x#{S{Kj$nScBI=2jTTD^M?B4G31a^bfRUkC)EQ4~}W)4?|+N&$7 z>N*B%lIb7a;;TmX1ih8H2~n}hxg|LvHi&U)Tlzd!lj`qo=jh=d7U--)`7nXIh1h5+ zDr=cqnQ6+{!ijmX2n*HV#kCucWaQpF{)2Ku5(kjRy`PSszVQ3SUyc#z?Vre6P`xGA z-)IDr{Q{v*&N^}O?D^kL(+Hk+u+*A`Yu&i@;JM7}M}Ods-5b;$byQR}4a`h5-{>*Y zo8~{^xdJ_%Ts)XT{w{i|&asuF2Y7mRa$G`6c41Dqy}Tufi~HN^2(PZXwxJyn*B;LZ zhTc8DyT3X!IX$~VTqD;3v?rCe56-M_?+Q1UXFviPZ{ZV{Q`Xqs+t2TAt1pRlq5bwy z$<*CHDh+OhLUvYCl(#9ghkNpxrVb1^7J~e-ksB*rI*n-*g%2Y*Tn)kDU)j!&?qI6* z{?Ww~w6Bbpn;PZsVX5}~%89S6$7?9dO=8(;KEFs7mx%cUGlL!6^k6%+N7ND|>^Hl* zi-^72be6?CLZcY4zGHB9f4!dz7*RwcESOu?Hg!mO+QqbR7f=6~!p>DnB1vf0TBdO3 zPyf?YU6RKUOIogCISN}7nFqN=^K_@#^0c#4#c$N)U4v_o`o+|=z)mV(9qP@H@@;^sjCD# z6QL2-Tv!qwZp?O7B*ITfXcTj<%#U<8aT5J3l#QlRIvB}0w_7uHoDP_$i#<8r#{ctbRTrJeZ{dB6uF^ok07Eyz9 zmGnO^i5hYEQ+*;n(IowYAqY>>N<`-gWN3%ghCQ=oSW`an|%rM8JS)gR4lkPW82+V-S zf8q>KHn;Q941^;d$=~1Gnp%e#LBuJcrTCeOMyy-ZfYgxw-#0}~G6RRRq9*Ad4AqNT zVVHP(D@~$Wq^G`Q2HZ$THVx%?nnGU!G2y& z=9;f*r*6s_II^NsbKwdqEzC)a33Sprc~j2NJtDKLsk3hg7G`Ht1%SCLZw%d|@|y-` z*R~H14}@!T!&s+}KRQPhv`h*Q)~3hCCT9sGA8IXU5s=+Hxhojq)pNPkjl3a(%4@)V zFtokiU&Bs`iH=WYm*qz|sObA-wJv-auT2l4JJ>sW1xAK=7`z5r*0TwBPNUzPM_j#-~Etug+C$JtNesDyv z)~=whx*#n+E?!K0YaW!>I`e65w7apUx~4&N<`Zq#Xin#}@Nj)@YGP_`(s{h(F&}G^0mnagZ<7-`CsK*1$zf9PR8q1tS;Vh~&J2;-bR5tdy7# zcLVsqZ_8>J*?Ia0h9C@w>FH>xD@SRQWLrB+v=dEeCnCYeuu{4ARFhIHy{$#EFPUll zTERMqXqG8VO8oVdV6nkTQjMtQl5n#Agw*<@40RHr^L2?*B!Wu+-;uPniG}~|SwtBA zl_U~~-<~Cwi7iJzl!(QprDe&rz8v9TYZB7IkOT`m`XRVm1c!Zl`O49UCX_U;JWWpq~B$YJI?nxu0?85yM zVEG>i%jKWm|S@okrWOO8cRW&kdhc{RF6-mq^Z6mFEaDA<>GR4nQ<$-u1R`#z62CC9n)*l|7 z6Ok%NG+0eWfUVk-^VBAHFw_HwPhDmZP))dHMQ1Ji(`+j{)Isz4?{EMU(&60Z%HCLg z2FpV6He9uY^sj=U!L5w}Zlafw?9~(EAJ#OC?=N>1!&CMAf|yjAk7)FnmfR3K)d#+&kFa?#N`%wMUgIA5|Tq0g4;h$H|GS~ z5E8}m?j!(SFjAA`F5v?!V`PVb<3W!%k|I<%D9hXc7_Lv6`9^Ak2 z+tKrAp=l~Tlk^b=NT++)YKr?*7+_j*kXU7p2pTZo-e*TYCSx;TA`c6tu zI`2EN(co?U;oi^Zkc~m%G7KxR?T~_*xNz;gjR>4c7VV+fIU^7^{YVR_8&pSM9A9`_A83KIekC{P3tiT_BJUY3kjT+;bRE&t$Tfb zT0-9LT_T|`HUtN!r$zBfi=Hi#=0JwvU;j4Kk`rk47ux#D&Tv%{<1e($;hmN4;z*}&f4kK) z^JTgzJK$T|c5lz>_E2TwUuo4Ny9jxT_~yRYxmspFPc>%#l~%$RYz=b%N<+Nk-co1b z*JmcXUS8Y$r^$xD(qc+`*EjpSHzn^z&SR$4jqNXXZG20!LkiWx!36OrP-8&OGk1?G z??Y_kUudSj>Gczb|DA+JX4+g8(Ul#G)Nd*Ii)l8K(e;S0_*MYNdg?xXXHLarA4y=6 zZSVlG?NGXi2qr1zMC+0!X{QDx?UZ)mk&>RJt6yk%WO#^=6C6Odfx%yVs%q&K9G}f8 zMdktVJ{u|A{pHt(YBqjJ1y!y6LnA}{rt;iqy2-m6Bq}wvqI-04`{2|5=G;(gQJkm# zs~7qR_Uv6c+?*R58DHGqo$e?IcT|689a_jkVrOp?x4g1-VEJ&e5kYS1c%|`AiyfSd zn8>(nZZB+;;!tbE0<WdnpZtN?VVF0YlrIMv3B)2&yL0BL9tnyh8p@IJ^x@{I$GRk>jD-FjSx@SB ze|<(0sHk&A<`W#(`Ly0Um zC(l3xy&R5mW1T1{5Zg8U^>NAU>i*639)jH?e++2g;$T}%Rc+_U8WPQ5KR(lOk40|k z&d$;lkkS3kvF6-hTa{~arp&|=F($Y&!Eelq#LiD(L2n5x*jZDQ9`0%&dzE$$$ecfiN=xk+uZ$;~ixwObVqTko?Tj=HUV#I|Vs|0D^U` zy$k;|T`$_yAgkjOGt2sg0t~0<3`CXsX0@$+3y8Z=1WcLujF|W|xLa3{sU;$CE32D& z=0A;N51CqYTm*HSVBLtC&B+^i5N7|BD zg`pkkN@7ss-=P|!SR%rtzg+(NcTz^uo4C>c&!qoVOxnf%KVed&2LF2|{Tm4y`*%!= zM9v7?f6Ju1WA$l1hX001H%437q4poXWzxf41k2_{x#_(4mPu#7%=1d(y-XDDe8Z$1 z-s0!EPEMSc@w;!BG@+co@(FHk$a5^IU;cdf=7XLI$_-TZ3pQtvU1m;J+OboYZa;mc zV(p(^13-^gh*}1s_QRRq9;@30WdQR-7`(oiia(d0Yuft|XwcJK5zH@2WR@mAIpc49 zasmF{aMvn7{r&h6_p>t+BD`&2x*V~8cS{W?1@;YP15y0Hu{haNmF8zc*%gP=)6+8x zg3oKHx#LL5h=ZZp+PdbhnJ=@A$k!9IO+sRNF@JNTCqGaOO+v5pft^V0j1tyj1muW{ ze@M*3L=CluKWpJ|qCSmsH&F7x4HC-(~x)+P|vzur^OwoVzB4M^08Juv}b`oZ@9FZyQlE zu(QM~&x#B3w6WBGe-9qXRl1Fej0>6&@YLaCLGfxedhG;~ZVg%}-B^i%%t$B9P~eh}4m;=DO;d`tDim5lJ2-M0I^( zdU9%3aJT@sBa#^#Czs)AL-Ni%d{v1cDe=?)_6l{Kz*wmPmhb)$$wQR6F!v;|yA3iJh-@UzQW6_QO`{p6 zQO^a_7(ho}_j7G0V0nQIO9xUuD?fp*`&7|3BnvZ{zwo@~wyG=Fc& zO0VKikh&^@nW3fv08x+B>;h6aHSPTVUS30ac7%t)n~TpitbM`~a|+<`PK^q1)|b0+ z;`b*ihBoeg@OTH%9n3z;+&FavF`XsWt2wM!swQ24r|G-vzsu-TSRuobDo@9bLt6G7 zRmTW2r%B#ar8=Z8naNVw;nYkL14KAX0)XVHcp%vP!9clD5~DGVp{MQ=hoBj9Xi1`Y z$d?v|qyiSA-lH8UWP=QmvvpW;@75X*>F)qR%7^#K$RMwM0532s1Tz}>BG_lAzjIBTQje&u`$>9{)T! zxF^o52WucoiAu_!Iv62gS9cH#MUzI}en#{B=8~Wb>IfAJMw7a$<{Zl%Is8mQmUKlK z@3bp&7BH3s0st?FZ4&9ozdqGvq#=E^74cSYNDd9!_qSE-Nd{|nw411G5g}fDDGDKS zHIgGqG9sThVbWhN=YKC{A)WZWwj<$8R2-Bu_5d;gQ7bR1x&{BYh(%F^P*nR4^R2B< zRo=>tbV4;6NZztYJ7d3`c0RuYx$Y>`hU#0*84P%bCWKQ+T(t@3^b3V3Gh^ovT`?k@ zYfSY*yyw8~QY%6bFoB1MQ?*I%Bov)0Y-8e|hlzw$=#$y9xVF07p6%z0#Pw}b%|!=t zV(wtLJSw=bXLEiIv@nFLVyi+Ta5yoFh_QIw?vMluYRRLHR^Rq= zTNZx4)6d_8txGtMM5`*lBspCx$i2wp306B=7r}(M9m&P8c#Az(bRKffX6maaK8w_}D&C0H8Y`mtXH{Ko$oEO7Ys+ z=cEqQlCZZ|2umCB8T&&Wt2isr?9IiW?tdf&ehx=Q0glDND&L##6;k^4(=)Vdil_rL zv_Cy7gjtWgIKeXBld9PB1MMQQ*1I)_1*v#e*zDfmz_krB%m~&P z-JK^@I!p*S{Nr7K2GtXPLlvM%J4-UEf5-gLwI7oNCMqr$+7?O%nCg?+5Kx7OZjpG` z^RF>a@TAtK(sk4UD0X&s6op#JlRPa%5^A|eBkwaK)LuoLB^A#Q)p?*D|5MJ06zB7C z)Ojh+m+~-Eyai^sbV0mzTp%*X5;8|rOUchs`?<&s6bOXdf-0(%6=JIbC1|oFw2w35CYkzq!mS47D_2qU6s0ED$pSAqfX76Y2U0p2aai z%*c1sO0=IL&24+Z%qJi zjUSK_Pz*yEV(0$$OxrCM&%Lyc-;%rjN;`Q+*@nPn!ol%_ndU5i3xyj$TzO;UodQ^G zx~XH4pmlV;mluh5ozt_1-&G6>@wVX(Y7gF9!nr;}uAkL34ZJPG&rIIHE3tBDdmgo> zB2mL>v%fsfUB@w^sB2}TuQbM$fy?eMw6jBO8R)%#Oz2hu!3SB+EM7{?{B`) zp%eoj8)`$zPw>)vp==vU6oXW-K5A>Cc%QAZfp;nt1AcjwPe#*>aH1}iVL<9o3D)_X zaK}j0@I$e_aC_9noBBLipXP1klh!cxWvU^~hkUozRfxw%WxyVkv*JYJ3I}5~$zJ+Y z{VJqyHfEIeZ!LG`huA3H!o3T4tEd#%JV%nYJanG@_CgQF$>_ms^T76ETW+AG!u9WO zC{hLQgeVw7irZ;DIZKm%Dyoe)ze^RTlDm2g3D55=17XDc^HzUZw6n%T5|;bxV@IAqA3>tBwKc@oLgs%+5fc3o2B9t{ zNx#tdipLaw&DW;=c|JZvySmie9qH-tAlgxUNh#>$0~x3g zqDKlk4p0b%*brY;bP_rZiX>=iW^IpTpt{7BiKC|K#}DS)@`A0z3VLE9z~1%V(pWcb zk$&zP3Lf4^%mvd#j#AG}eF| zI2cl6Z=oYU)DE7hkMAFAy8^}*Y=EsO-;}$R8sXl#18|baJC(??WDrPvu|w>hYOYLh zCAQZW;+vux0jvq-YaU0AvtWXs;bQPr>N~&v9Uo;;zJ)tD=o>P zp8V6J!zX9I9-jV39$q=Rn7XXwkl{jAT|~NTMn<%!h}znUR3>t`0pLRP7Ss^qkeOLe z%|KIr5LMEOOiz@%4k>d*nv)?_XpO*!KavVgwy5AliKzf0u_y)1E|i2LKw3RR93hS7 zo(%ECBcL>881NdNDbTqg$A|G9-8Nip|In-#Dxo@R{hz@D^C3k{6;@ zDIPtnNF*j|(-`y^v41<*&e&PBNIh(|{#p*uo~mtk>b{z-Z)j+cyWtxVdj9(x6TdVL zCqK$b{Q=orkbdtJUDh{%Tm(~U148ya%7xAfN!?EkB(IB;@3&UwTC!MXZ~u_w-mi{q z50=NG1miE_)cc8!<@wfZe>1tOFR0A>^`5E`QjXD8^AYmavD;2Juu-BcW<^Z@4nvJ&4^&>d3Mz$tg>y zEerqD3Wk zqhpOD8(lz6q#Pi@D2k6sIY_4-({-Secr$VHwE5^1mL>`}qdt=Ztx@Si5^aXR)yW=ORef(Me=!|s!c$8Rqq&_o=-Jw15(Sl6&b#lo@vXTAz!j)lO zTT|mC`5wT}{QgK4J2SO*n)Iof7W~43dP%*Ogbbj&GAbZ0h0N^~sU3MZxd^ z`sRUoE#s)jv9;LG7oe~0iqg6reSQ4a3T(6`5wZqup-DMKC^r<3Z8p*8rkt*=2MZMh zm?YE`Nb}O1IbrM(6cQ3dH+^>v5}h>HnEc}6f;e}rholTSnom|+ ze?M$h!{@(>0(FQlm4L2>FP=WQ`YW8sM+77NkMd8ipE)A@no;rvh=LfBjDZ^7Km zA55T99U*)fugOeEE$!PP<}D$>fDCgXrZ=&L34xSAHSquzM`{WX0`=$w&?ljlqBHVX z#yEotA|V7)pO#dATtSuS5JCVNlNy!4;cvkh_oWCc{Q8Qjj+xKIIwgdqdBODP*z&<* zS5defAxw2o3$}OGCVR>g=?2~zut7>2yL$V&>WYyV`JTf1lhRPUJwGMf8!40&)KB*c z2!{XB)G0;=w;w;LmfED)0F_<0lwm+E@v=6VYEBtvNP?&+I1 z&+ncm;iRMzjlJ?mLsNqfPYJT|3CM;!3U47sPt7W%2m{!WpBS5%U695yHDG48A|#@t zx~jGf29lk+E5adG_m(Fnrk7D5!cN}IH?697Y7MKM>OWA0MBvo%P<^JomK|bs0dj#E zk<2bE%Fjs*bJIP3>FEa}J9s?^g(Sce`g)h z3a9<{%7~d-R9u`BYC};@oPr$_%IWRzM}8P6KmK;((KE`jp>l~~^WJ`;sBK_OnLi}P z;Mm2d%KEl+Uw=QU-W(|BpQ_m)%|3^nn?WkjfpYJIjelxUZD%*H3I8($p%6{HvS(s- zLonMvutzBBE-0+Ea@361t3k&=1ON_Vq#wF!oLy< z;;P#b0^@-l{AiKQriu)eW4io8J&-4BkD#a#>gD^pXXMr3}dl`bQVAPpTgwVksE2s3e| zVn_f-BqjlY1?t9hKndo3k;kQDbqo2x6fcM^zZK%KB*XhPY8wPHx}QfSG25;Aff&=# zPt*0Hi0!P*Xb-B+%4%m(N=$r8UTI#q9V)RjBl410S6NfvIfzk1xuH^2LSLI2pPHpA z_`WsqNv`M~2U@8tiFh2mE+f%_X*^Yhi0|AMkJB6#~-%a+n?*nrck*lKDvG$St>*l-6>h z9d(@jBdGd|>FFs^3}f5S?9$rd!zm~uH7TBO*VYb9Eq_^tE<*n27BYmhv!CXmijb~T zOlf^RPKGwZP4dt*@s3HtQl6?wN{VM$y;m}EA}f2UCf?1(LhbQAk=F`cXI1$}7sMVb z(*1Dr4DB!7BfG>N|n#)8U?V~`_aV}WHZ2Z-dWv7km0qhT;eLs2?|lCS^$ z2`LZh!xOY$?#k&}xp+gQQ)-;Mh04j>3MTF$aT!Fala|0Vz5K?Aj!KNpM6i=q7UKxC zJ-VoE46=QVD0Jj;UK#?FpWa^_8=2VMotYQ`=^ZhmHkUfM<;@ejGmRB_p*E!4&DfWT zs`$wKP61Nqf?ai~qM;D%(E-@DusO1fWT7UNkL*u1<>yuRZ@~Uz>OXyJ5yCM)3nH;_x3G2yh1%Z~zKHJCWqvbKVVig;!31Z!Lo|03m1EPAlao_XJPu!5S`zqQ!g(%9VEJGnd8oW(LR@y%?S+}c{2UtHeWp6f1+c2-wI-Rh?P zvAKo$nbE$MQvCNUvNDDq5t*FIhNi}PZc$c@4{93RlGAte4U0`qO-YIl@pCr8W_{|0 zjGD2Ple?#fn}em1hU`7m?mdlUcbY`g^8ByXw1~^&NRKjn@$A9%3(&rZW!L=H_3~N zja!=%E>2Icep>Fv|F=NS*bxl0*4A~-A0kxOi4dS^WhEq+69h2DgE|9Rk}JuqB!&bb z5T7-bk|`mOC;g8n2*h_0klRw4R&y2;I6ta7)}?q-niewEMMWLcL+mI`3t8$SMBm#% z`x{M5a7>CWJ#kD9HkY%F-a7*@B0}GcoFds()dkV6%*>|oiPjtz`M(yn@gIo51+%b( z{A~C5^0qc^5}lD&*V0m->4U*oTEbJ2K_O%CAMuyGwd7?b?89kRXqROq?*$x1@@gn2B6&M${C@%B7bFma_#LU*>!R00;H2bDPd_26hk9Aj zA@#oh?;hS1MR$^cR@60-jJ1VVfUkJ?@n19KpqK|q6b>!!>S!O@A^%SV6t&eA;npx} z#o%yuVP+83xvc!NxD8G9WjUcvT8@D+$*IXv&=Oy3S~$9Ux;vPDl=&0T#ijelAjE&T zoO42oAss8Wpgc|FDL19WfI=yg2NH7$_7f_C7(6?3^5n_yD3&G9V({!C+N}%ZiK)K2 zwzjsG$_q)~*adq6-CkSLr^jGBNDXz6^ka&!7u08Xi~CW9ZPQEBZP}C+gzM$EPVM7= zVTo}Sea~*5+#^wCbff>Hy|<2!>sqr!OO}%;=vYpi*w=~UfMaH623eM5i^*bUW@ct) zW@ct8G260}3w^t19`&2|`pxw8gXvk{K2<8P=iR3CP4~~|54+B;Qo%WUfBS>=t;L;J z4y;cQ_Dod}d4Y-r2sInEt3S~5b3Myb&DkNg>eu#fqw|@$+2{S>Pt&^g!-sUfG1fkh z&Xh2lrx(8F-mj#0ZMrGb-|W#T?mVGtxbH@kg|xy*5hjbN55DHGj<13>E^2xj|7yRm+4v3`Xy ztuT}oMzHirztnpC$G-1BaQ&{!%Gt?J%0ARbuE!iaJ&ty!>e^;@@PEy8l`jAI%p)>7 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© Mapbox © OpenStreetMap Improve this map","bounds":[-180,-85.0511,180,85.0511],"center":[0,0,0],"format":"pbf","maxzoom":15,"minzoom":0,"name":"Mapbox Streets V6 + Vector Terrain V2","scheme":"xyz","tilejson":"2.0.0","tiles":["test/fixtures/resources/vector.pbf"],"vector_layers":[{"description":"Generalized landcover classification","fields":{"class":"One of: wood, scrub, grass, crop, snow"},"id":"landcover","maxzoom":22,"minzoom":0},{"description":"","fields":{"class":"One of: shadow, highlight","level":"Brightness %. One of: 94, 90, 89, 78, 67, 56"},"id":"hillshade","maxzoom":22,"minzoom":0},{"description":"Elevation contour polygons","fields":{"ele":"Integer. The elevation of the contour in meters.","index":"Indicator for every 2nd, 5th, or 10th contour. Coastlines are given -1. One of: 2, 5, 10, -1, null"},"id":"contour","maxzoom":22,"minzoom":0},{"description":"","fields":{"class":"One of: cemetery, hospital, industrial, park, parking, pitch, sand, school, wood","osm_id":"Unique OSM ID number","type":"OSM tag, more specific than class"},"id":"landuse"},{"description":"","fields":{"class":"One of: river, canal, stream, stream_intermittent, ditch, drain","osm_id":"Unique OSM ID number","type":"One of: river, canal, stream, ditch, drain"},"id":"waterway"},{"description":"","fields":{"osm_id":"Unique OSM ID number"},"id":"water"},{"description":"","fields":{"osm_id":"Unique OSM ID number","type":"One of: runway, taxiway, apron"},"id":"aeroway"},{"description":"","fields":{"class":"One of: fence, hedge, cliff, gate","osm_id":"Unique OSM ID number"},"id":"barrier_line"},{"description":"","fields":{"osm_id":"Unique OSM ID number"},"id":"building"},{"description":"","fields":{"class":"One of: wetland, wetland_noveg","osm_id":"Unique OSM ID number"},"id":"landuse_overlay"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path, major_rail, minor_rail, aerialway","layer":"Number used for ordering overlapping tunnels","oneway":"Number. Oneway roads are 1, all others are 0.","osm_id":"Unique OSM ID number","type":"The value of the tunnel's highway tag"},"id":"tunnel"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path, major_rail, minor_rail, aerialway","oneway":"Number. Oneway roads are 1, all others are 0.","osm_id":"Unique OSM ID number","type":"The value of the road's highway tag"},"id":"road"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path, major_rail, minor_rail, aerialway","layer":"Number used for ordering overlapping bridges","oneway":"Number. Oneway bridges are 1, all others are 0.","osm_id":"Unique OSM ID number","type":"The value of the bridge's highway tag"},"id":"bridge"},{"description":"","fields":{"admin_level":"The OSM administrative level of the boundary","disputed":"Number. Disputed boundaries are 1, all others are 0.","maritime":"Number. Maritime boundaries are 1, all others are 0."},"id":"admin"},{"description":"","fields":{"code":"ISO 3166-1 Alpha-2 code","name":"Local name of the country","name_de":"German name of the country","name_en":"English name of the country","name_es":"Spanish name of the country","name_fr":"French name of the country","name_ru":"Russian name of the country","name_zh":"Chinese name of the country","osm_id":"Unique OSM ID number","parent":"ISO 3166-1 Alpha-2 code of the administering/parent state, if any","scalerank":"Number, 1-6. Useful for styling text sizes.","type":"One of: country, territory, disputed territory, sar"},"id":"country_label"},{"description":"","fields":{"labelrank":"Number, 1-6. Useful for styling text sizes.","name":"Local or international name of the water body","name_de":"German name of the water body","name_en":"English name of the water body","name_es":"Spanish name of the water body","name_fr":"French name of the water body","name_ru":"Russian name of the water body","name_zh":"Chinese name of the water body","placement":"One of: point, line"},"id":"marine_label"},{"description":"","fields":{"abbr":"Abbreviated state name","area":"The area of the state in kilometers²","name":"Local name of the state","name_de":"German name of the state","name_en":"English name of the state","name_es":"Spanish name of the state","name_fr":"French name of the state","name_ru":"Russian name of the state","name_zh":"Chinese name of the state","osm_id":"Unique OSM ID number"},"id":"state_label"},{"description":"","fields":{"capital":"Admin level the city is a capital of, if any. One of: 2, 3, 4, null","ldir":"A hint for label placement at low zoom levels. One of: N, E, S, W, NE, SE, SW, NW, null","localrank":"Number. Priority relative to nearby places. Useful for limiting label density.","name":"Local name of the place","name_de":"German name of the place","name_en":"English name of the place","name_es":"Spanish name of the place","name_fr":"French name of the place","name_ru":"Russian name of the place","name_zh":"Chinese name of the place","osm_id":"Unique OSM ID number","scalerank":"Number, 0-9 or null. Useful for styling text & marker sizes.","type":"One of: city, town, village, hamlet, suburb, neighbourhood"},"id":"place_label"},{"description":"","fields":{"area":"The area of the water polygon in Mercator meters²","name":"Local name of the water body","name_de":"German name of the water body","name_en":"English name of the water body","name_es":"Spanish name of the water body","name_fr":"French name of the water body","name_ru":"Russian name of the water body","name_zh":"Chinese name of the water body","osm_id":"Unique OSM ID number"},"id":"water_label"},{"description":"","fields":{"address":"Street address of the POI","localrank":"Number. Priority relative to nearby POIs. Useful for limiting label density.","maki":"The name of the Maki icon that should be used for the POI","name":"Local name of the POI","name_de":"German name of the POI","name_en":"English name of the POI","name_es":"Spanish name of the POI","name_fr":"French name of the POI","name_ru":"Russian name of the POI","name_zh":"Chinese name of the POI","network":"For rail stations, the network(s) that the station serves. Useful for icon styling.","osm_id":"Unique OSM ID number","ref":"Short reference code, if any","scalerank":"Number. 1-4. Useful for styling icon sizes and minimum zoom levels.","type":"The original OSM tag value","website":"URL of the POI"},"id":"poi_label"},{"description":"","fields":{"class":"One of: motorway, motorway_link, main, street, street_limited, service, driveway, path","len":"Number. Length of the road segment in Mercator meters.","localrank":"Number. Used for shield points only. Priority relative to nearby shields. Useful for limiting shield density.","name":"Local name of the road","name_de":"German name of the road","name_en":"English name of the road","name_es":"Spanish name of the road","name_fr":"French name of the road","name_ru":"Russian name of the road","name_zh":"Chinese name of the road","osm_id":"Unique OSM ID number","ref":"Route number of the road","reflen":"Number. How many characters long the ref tag is. Useful for shield styling.","shield":"The shield style to use. One of: default, mx-federal, mx-state, us-highway, us-highway-alternate, us-highway-business, us-highway-duplex, us-interstate, us-interstate-business, us-interstate-duplex, us-interstate-truck, us-state"},"id":"road_label"},{"description":"","fields":{"class":"One of: river, canal, stream, stream_intermittent","name":"Local name of the waterway","name_de":"German name of the waterway","name_en":"English name of the waterway","name_es":"Spanish name of the waterway","name_fr":"French name of the waterway","name_ru":"Russian name of the waterway","name_zh":"Chinese name of the waterway","osm_id":"Unique OSM ID number","type":"One of: river, canal, stream"},"id":"waterway_label"},{"description":"","fields":{"house_num":"House number","osm_id":"Unique OSM ID number"},"id":"housenum_label"}]} diff --git a/test/fixtures/resources/sprite.json b/test/fixtures/resources/sprite.json new file mode 100644 index 000000000..dcc2b4808 --- /dev/null +++ b/test/fixtures/resources/sprite.json @@ -0,0 +1 @@ +{"background":{"x":0,"y":20,"width":50,"height":50,"pixelRatio":1,"sdf":false},"grass_pattern":{"x":100,"y":80,"width":50,"height":50,"pixelRatio":1,"sdf":false},"interstate_1":{"x":0,"y":100,"width":41,"height":40,"pixelRatio":1,"sdf":false},"interstate_2":{"x":0,"y":100,"width":41,"height":40,"pixelRatio":1,"sdf":false},"interstate_3":{"x":41,"y":100,"width":48,"height":39,"pixelRatio":1,"sdf":false},"us_state_1":{"x":0,"y":73,"width":29,"height":24,"pixelRatio":1,"sdf":false},"us_state_2":{"x":0,"y":73,"width":29,"height":24,"pixelRatio":1,"sdf":false},"us_state_3":{"x":30,"y":73,"width":32,"height":24,"pixelRatio":1,"sdf":false},"us_highway_1":{"x":0,"y":142,"width":29,"height":29,"pixelRatio":1,"sdf":false},"us_highway_2":{"x":30,"y":142,"width":33,"height":29,"pixelRatio":1,"sdf":false},"us_highway_3":{"x":64,"y":142,"width":36,"height":29,"pixelRatio":1,"sdf":false},"default_1":{"x":0,"y":0,"width":17,"height":16,"pixelRatio":1,"sdf":false},"default_2":{"x":17,"y":0,"width":22,"height":16,"pixelRatio":1,"sdf":false},"default_3":{"x":39,"y":0,"width":27,"height":16,"pixelRatio":1,"sdf":false},"default_4":{"x":66,"y":0,"width":32,"height":16,"pixelRatio":1,"sdf":false},"default_5":{"x":98,"y":0,"width":37,"height":16,"pixelRatio":1,"sdf":false},"default_6":{"x":135,"y":0,"width":42,"height":16,"pixelRatio":1,"sdf":false},"london-overground":{"x":70,"y":25,"width":18,"height":18,"pixelRatio":1,"sdf":false},"london-underground":{"x":88,"y":25,"width":18,"height":18,"pixelRatio":1,"sdf":false},"national-rail":{"x":106,"y":25,"width":18,"height":18,"pixelRatio":1,"sdf":false},"dlr":{"x":106,"y":25,"width":18,"height":18,"pixelRatio":1,"sdf":false},"dlr.london-overground.london-underground.national-rail":{"x":70,"y":25,"width":72,"height":18,"pixelRatio":1,"sdf":false},"dlr.london-underground":{"x":88,"y":25,"width":36,"height":18,"pixelRatio":1,"sdf":false},"dlr.london-underground.national-rail":{"x":88,"y":25,"width":54,"height":18,"pixelRatio":1,"sdf":false},"dlr.national-rail":{"x":106,"y":25,"width":36,"height":18,"pixelRatio":1,"sdf":false},"london-overground.london-underground":{"x":70,"y":25,"width":36,"height":18,"pixelRatio":1,"sdf":false},"london-overground.london-underground.national-rail":{"x":124,"y":25,"width":54,"height":18,"pixelRatio":1,"sdf":false},"london-overground.national-rail":{"x":124,"y":25,"width":36,"height":18,"pixelRatio":1,"sdf":false},"london-underground.national-rail":{"x":124,"y":43,"width":36,"height":18,"pixelRatio":1,"sdf":false},"metro":{"x":71,"y":43,"width":18,"height":18,"pixelRatio":1,"sdf":false},"rer":{"x":87,"y":43,"width":18,"height":18,"pixelRatio":1,"sdf":false},"metro.rer":{"x":71,"y":43,"width":34,"height":18,"pixelRatio":1,"sdf":false},"rer.transilien":{"x":87,"y":43,"width":36,"height":18,"pixelRatio":1,"sdf":false},"u-bahn":{"x":70,"y":62,"width":18,"height":18,"pixelRatio":1,"sdf":false},"s-bahn":{"x":88,"y":62,"width":18,"height":18,"pixelRatio":1,"sdf":false},"s-bahn.u-bahn":{"x":70,"y":62,"width":36,"height":18,"pixelRatio":1,"sdf":false},"washington-metro":{"x":106,"y":62,"width":18,"height":18,"pixelRatio":1,"sdf":false},"wiener-linien":{"x":124,"y":62,"width":18,"height":18,"pixelRatio":1,"sdf":false},"moscow-metro":{"x":142,"y":61,"width":21,"height":18,"pixelRatio":1,"sdf":false},"generic-metro":{"x":160,"y":43,"width":18,"height":18,"pixelRatio":1,"sdf":false},"generic-rail":{"x":178,"y":43,"width":18,"height":18,"pixelRatio":1,"sdf":false},"dot":{"x":166,"y":63,"width":13,"height":13,"pixelRatio":1,"sdf":false},"default_marker":{"x":0,"y":175,"width":33,"height":86,"pixelRatio":1,"sdf":false},"secondary_marker":{"x":33,"y":175,"width":33,"height":86,"pixelRatio":1,"sdf":false},"oneway_motorway":{"x":178,"y":24,"width":21,"height":19,"pixelRatio":1,"sdf":false},"oneway_road":{"x":178,"y":62,"width":21,"height":19,"pixelRatio":1,"sdf":false},"hospital_icon":{"x":157,"y":259,"width":18,"height":18,"pixelRatio":1,"sdf":false},"fire-station_icon":{"x":157,"y":241,"width":18,"height":18,"pixelRatio":1,"sdf":false},"cemetery_icon":{"x":157,"y":79,"width":18,"height":18,"pixelRatio":1,"sdf":false},"zoo_icon":{"x":177,"y":79,"width":18,"height":18,"pixelRatio":1,"sdf":false},"park_icon":{"x":177,"y":97,"width":18,"height":18,"pixelRatio":1,"sdf":false},"golf_icon":{"x":177,"y":115,"width":18,"height":18,"pixelRatio":1,"sdf":false},"school_icon":{"x":177,"y":133,"width":18,"height":18,"pixelRatio":1,"sdf":false},"monument_icon":{"x":177,"y":151,"width":18,"height":18,"pixelRatio":1,"sdf":false},"library_icon":{"x":177,"y":169,"width":18,"height":18,"pixelRatio":1,"sdf":false},"museum_icon":{"x":177,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false},"college_icon":{"x":177,"y":205,"width":18,"height":18,"pixelRatio":1,"sdf":false},"religious-christian_icon":{"x":157,"y":115,"width":18,"height":18,"pixelRatio":1,"sdf":false},"religious-jewish_icon":{"x":157,"y":133,"width":18,"height":18,"pixelRatio":1,"sdf":false},"religious-muslim_icon":{"x":157,"y":151,"width":18,"height":18,"pixelRatio":1,"sdf":false},"government_icon":{"x":157,"y":169,"width":18,"height":18,"pixelRatio":1,"sdf":false},"post_icon":{"x":157,"y":205,"width":18,"height":18,"pixelRatio":1,"sdf":false},"embassy_icon":{"x":157,"y":223,"width":18,"height":18,"pixelRatio":1,"sdf":false},"police_icon":{"x":157,"y":169,"width":18,"height":18,"pixelRatio":1,"sdf":false},"marker_icon":{"x":157,"y":169,"width":18,"height":18,"pixelRatio":1,"sdf":false},"prison_icon":{"x":157,"y":169,"width":18,"height":18,"pixelRatio":1,"sdf":false},"airfield_icon":{"x":157,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false},"airport_icon":{"x":157,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false},"harbor_icon":{"x":139,"y":169,"width":18,"height":18,"pixelRatio":1,"sdf":false},"generic_icon":{"x":139,"y":187,"width":18,"height":18,"pixelRatio":1,"sdf":false},"hospital_striped":{"x":117,"y":135,"width":3,"height":3,"pixelRatio":1,"sdf":false},"school_striped":{"x":114,"y":135,"width":3,"height":3,"pixelRatio":1,"sdf":false},"sand_noise":{"x":75,"y":174,"width":50,"height":50,"pixelRatio":1,"sdf":false}} \ No newline at end of file diff --git a/test/fixtures/resources/sprite.png b/test/fixtures/resources/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..967f2e76a6857fd2ab3ab4c491e220345345aaab GIT binary patch literal 39041 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

;=Ye*^3A1%eA1+{YTvW32CE)eC}cG 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 d2w|kxNOBFTEDoTn`Xt0p`=S1WQVrXP{{gly$6 literal 0 HcmV?d00001 diff --git a/test/fixtures/resources/style.json b/test/fixtures/resources/style.json new file mode 100644 index 000000000..698f3fb1e --- /dev/null +++ b/test/fixtures/resources/style.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "name": "Test", + "sources": { + "compositedsource": { + "url": "test/fixtures/resources/source.json", + "type": "vector" + } + }, + "sprite": "test/fixtures/resources/sprite", + "glyphs": "test/fixtures/resources/glyphs.pbf", + "layers": [{ + "id": "road", + "type": "symbol", + "source": "compositedsource", + "source-layer": "road_label", + "layout": { + "text-font": "Open Sans Regular, Arial Unicode MS Regular", + "text-field": "{name_en}" + } + }, { + "id": "poi", + "type": "symbol", + "source": "compositedsource", + "source-layer": "poi_label", + "layout": { + "text-font": "Open Sans Regular, Arial Unicode MS Regular", + "icon-image": "{maki}_icon" + } + }] +} diff --git a/test/fixtures/resources/vector.pbf b/test/fixtures/resources/vector.pbf new file mode 100644 index 0000000000000000000000000000000000000000..cea355eeffa4e37a03894d26b7e91040b36bda00 GIT binary patch literal 103021 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 +#include +#include + +namespace mbgl { + +class MockFileSource::Impl { +public: + Impl(uv_loop_t*, const std::string& matchFail) : matchFail_(matchFail) {} + + void handleRequest(Request* req) const; + +private: + std::string matchFail_; +}; + +void MockFileSource::Impl::handleRequest(Request* req) const { + const Resource& resource = req->resource; + + std::shared_ptr response = std::make_shared(); + if (matchFail_.empty() || resource.url.find(matchFail_) == std::string::npos) { + response->status = Response::Status::Successful; + response->data = util::read_file(resource.url.c_str()); + } else { + response->message = "Failed by the test case"; + } + + req->notify(response); +} + +MockFileSource::MockFileSource(const std::string& matchFail) + : thread_(util::make_unique>("FileSource", util::ThreadPriority::Low, matchFail)) { +} + +Request* MockFileSource::request(const Resource& resource, uv_loop_t* loop, Callback callback) { + Request* req = new Request(resource, loop, std::move(callback)); + thread_->invoke(&Impl::handleRequest, req); + + return req; +} + +void MockFileSource::cancel(Request*) { +} + +} diff --git a/test/resources/mock_file_source.hpp b/test/resources/mock_file_source.hpp new file mode 100644 index 000000000..8c76bd539 --- /dev/null +++ b/test/resources/mock_file_source.hpp @@ -0,0 +1,33 @@ +#ifndef TEST_RESOURCES_MOCK_FILE_SOURCE +#define TEST_RESOURCES_MOCK_FILE_SOURCE + +#include + +#include + +namespace mbgl { + +namespace util { +template class Thread; +} + +// This mock FileSource will read data from the disk and will fail +// the request if the URL matches the 'matchFail' string. +class MockFileSource : public FileSource { +public: + class Impl; + + MockFileSource(const std::string& matchFail); + ~MockFileSource() override = default; + + // FileSource implementation. + Request* request(const Resource&, uv_loop_t*, Callback) override; + void cancel(Request*) override; + +private: + const std::unique_ptr> thread_; +}; + +} + +#endif diff --git a/test/resources/mock_view.hpp b/test/resources/mock_view.hpp new file mode 100644 index 000000000..865cd2da5 --- /dev/null +++ b/test/resources/mock_view.hpp @@ -0,0 +1,21 @@ +#ifndef TEST_RESOURCES_MOCK_VIEW +#define TEST_RESOURCES_MOCK_VIEW + +#include + +namespace mbgl { + +class MockView : public View { +public: + MockView() = default; + + // View implementation. + void activate() override {}; + void deactivate() override {}; + void notify() override {}; + void invalidate(std::function) override {}; +}; + +} + +#endif diff --git a/test/test.gypi b/test/test.gypi index 926a899cf..4a733b457 100644 --- a/test/test.gypi +++ b/test/test.gypi @@ -59,6 +59,10 @@ 'miscellaneous/variant.cpp', 'miscellaneous/worker.cpp', + 'resources/mock_file_source.cpp', + 'resources/mock_file_source.hpp', + 'resources/mock_view.hpp', + 'storage/storage.hpp', 'storage/storage.cpp', 'storage/cache_response.cpp', From 6624dbb225817988b1f70489b3328fcb854a7210 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Mon, 18 May 2015 13:33:53 +0300 Subject: [PATCH 7/7] Add ResourceLoader unit tests This first test will simulate a request failure on every resource directly or indirectly loaded by the ResourceLoader. The idea is to verify whenever we are failing gracefully or not. --- test/resources/resource_loader.cpp | 154 +++++++++++++++++++++++++++++ test/test.gypi | 1 + 2 files changed, 155 insertions(+) create mode 100644 test/resources/resource_loader.cpp diff --git a/test/resources/resource_loader.cpp b/test/resources/resource_loader.cpp new file mode 100644 index 000000000..4203755f8 --- /dev/null +++ b/test/resources/resource_loader.cpp @@ -0,0 +1,154 @@ +#include "../fixtures/util.hpp" +#include "mock_file_source.hpp" +#include "mock_view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mbgl; + +namespace { + +class MockMapContext : public ResourceLoader::Observer { +public: + MockMapContext(uv_loop_t* loop, + View& view, + FileSource& fileSource, + const std::function& callback) + : env_(fileSource), + envScope_(env_, ThreadType::Map, "Map"), + data_(view, MapMode::Still), + glyphStore_(util::make_unique(loop, env_)), + glyphAtlas_(util::make_unique(1024, 1024)), + spriteAtlas_(util::make_unique(512, 512)), + texturePool_(util::make_unique()), + style_(util::make_unique