diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-08-12 11:20:49 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-08-24 13:06:23 -0700 |
commit | e706ed4b2ee8d73e17146b33b2c91463b7186777 (patch) | |
tree | 76375e15c031d169474a864b2dfa13c7485727be | |
parent | 3d3648387bd3cfc8e330a0a729decd68ae37f96e (diff) | |
download | qtlocation-mapboxgl-e706ed4b2ee8d73e17146b33b2c91463b7186777.tar.gz |
[core] Avoid RenderStyle dependency in query code
21 files changed, 78 insertions, 96 deletions
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index c2e6191d1d..34fb576727 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -60,9 +60,9 @@ std::vector<std::reference_wrapper<RenderTile>> RenderAnnotationSource::getRende std::unordered_map<std::string, std::vector<Feature>> RenderAnnotationSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const { - return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options); + return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options); } std::vector<Feature> RenderAnnotationSource::querySourceFeatures(const SourceQueryOptions&) const { diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp index 4000c4b04a..9536b2e101 100644 --- a/src/mbgl/annotation/render_annotation_source.hpp +++ b/src/mbgl/annotation/render_annotation_source.hpp @@ -26,7 +26,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const final; std::vector<Feature> diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 4c4e985369..d846fb1700 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -1,5 +1,4 @@ #include <mbgl/geometry/feature_index.hpp> -#include <mbgl/renderer/render_style.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/renderer/query.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> @@ -32,19 +31,6 @@ void FeatureIndex::insert(const GeometryCollection& geometries, } } -static bool vectorContains(const std::vector<std::string>& vector, const std::string& s) { - return std::find(vector.begin(), vector.end(), s) != vector.end(); -} - -static bool vectorsIntersect(const std::vector<std::string>& vectorA, const std::vector<std::string>& vectorB) { - for (const auto& a : vectorA) { - if (vectorContains(vectorB, a)) { - return true; - } - } - return false; -} - static bool topDown(const IndexedSubfeature& a, const IndexedSubfeature& b) { return a.sortIndex > b.sortIndex; } @@ -53,30 +39,17 @@ static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature& return a.sortIndex < b.sortIndex; } -static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions, - const RenderStyle& style, +static int16_t getAdditionalQueryRadius(const std::vector<const RenderLayer*>& layers, const GeometryTile& tile, const float pixelsToTileUnits) { // Determine the additional radius needed factoring in property functions float additionalRadius = 0; - auto getQueryRadius = [&](const RenderLayer& layer) { - auto bucket = tile.getBucket(*layer.baseImpl); - if (bucket) { - additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(layer) * pixelsToTileUnits); - } - }; - if (queryOptions.layerIDs) { - for (const auto& layerID : *queryOptions.layerIDs) { - const RenderLayer* layer = style.getRenderLayer(layerID); - if (layer) { - getQueryRadius(*layer); - } - } - } else { - for (const RenderLayer* layer : style.getRenderLayers()) { - getQueryRadius(*layer); + for (const auto& layer : layers) { + auto bucket = tile.getBucket(*layer->baseImpl); + if (bucket) { + additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(*layer) * pixelsToTileUnits); } } @@ -92,13 +65,13 @@ void FeatureIndex::query( const RenderedQueryOptions& queryOptions, const GeometryTileData& geometryTileData, const CanonicalTileID& tileID, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const CollisionTile* collisionTile, const GeometryTile& tile) const { // Determine query radius const float pixelsToTileUnits = util::EXTENT / tileSize / scale; - const int16_t additionalRadius = getAdditionalQueryRadius(queryOptions, style, tile, pixelsToTileUnits); + const int16_t additionalRadius = getAdditionalQueryRadius(layers, tile, pixelsToTileUnits); // Query the grid index mapbox::geometry::box<int16_t> box = mapbox::geometry::envelope(queryGeometry); @@ -113,7 +86,7 @@ void FeatureIndex::query( if (indexedFeature.sortIndex == previousSortIndex) continue; previousSortIndex = indexedFeature.sortIndex; - addFeature(result, indexedFeature, queryGeometry, queryOptions, geometryTileData, tileID, style, bearing, pixelsToTileUnits); + addFeature(result, indexedFeature, queryGeometry, queryOptions, geometryTileData, tileID, layers, bearing, pixelsToTileUnits); } // Query symbol features, if they've been placed. @@ -124,7 +97,7 @@ void FeatureIndex::query( std::vector<IndexedSubfeature> symbolFeatures = collisionTile->queryRenderedSymbols(queryGeometry, scale); std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols); for (const auto& symbolFeature : symbolFeatures) { - addFeature(result, symbolFeature, queryGeometry, queryOptions, geometryTileData, tileID, style, bearing, pixelsToTileUnits); + addFeature(result, symbolFeature, queryGeometry, queryOptions, geometryTileData, tileID, layers, bearing, pixelsToTileUnits); } } @@ -135,30 +108,39 @@ void FeatureIndex::addFeature( const RenderedQueryOptions& options, const GeometryTileData& geometryTileData, const CanonicalTileID& tileID, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const float bearing, const float pixelsToTileUnits) const { - auto& layerIDs = bucketLayerIDs.at(indexedFeature.bucketName); - if (options.layerIDs && !vectorsIntersect(layerIDs, *options.layerIDs)) { - return; - } - - auto sourceLayer = geometryTileData.getLayer(indexedFeature.sourceLayerName); - assert(sourceLayer); + auto getRenderLayer = [&] (const std::string& layerID) -> const RenderLayer* { + for (const auto& layer : layers) { + if (layer->getID() == layerID) { + return layer; + } + } + return nullptr; + }; - auto geometryTileFeature = sourceLayer->getFeature(indexedFeature.index); - assert(geometryTileFeature); + // Lazily calculated. + std::unique_ptr<GeometryTileLayer> sourceLayer; + std::unique_ptr<GeometryTileFeature> geometryTileFeature; - for (const auto& layerID : layerIDs) { - if (options.layerIDs && !vectorContains(*options.layerIDs, layerID)) { + for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketName)) { + const RenderLayer* renderLayer = getRenderLayer(layerID); + if (!renderLayer) { continue; } - auto renderLayer = style.getRenderLayer(layerID); - if (!renderLayer || - (!renderLayer->is<RenderSymbolLayer>() && - !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits))) { + if (!geometryTileFeature) { + sourceLayer = geometryTileData.getLayer(indexedFeature.sourceLayerName); + assert(sourceLayer); + + geometryTileFeature = sourceLayer->getFeature(indexedFeature.index); + assert(geometryTileFeature); + } + + if (!renderLayer->is<RenderSymbolLayer>() && + !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits)) { continue; } diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp index 83f339a9de..380546c794 100644 --- a/src/mbgl/geometry/feature_index.hpp +++ b/src/mbgl/geometry/feature_index.hpp @@ -13,7 +13,7 @@ namespace mbgl { class GeometryTile; class RenderedQueryOptions; -class RenderStyle; +class RenderLayer; class CollisionTile; class CanonicalTileID; @@ -42,7 +42,7 @@ public: const RenderedQueryOptions& options, const GeometryTileData&, const CanonicalTileID&, - const RenderStyle&, + const std::vector<const RenderLayer*>&, const CollisionTile*, const GeometryTile& tile) const; @@ -63,7 +63,7 @@ private: const RenderedQueryOptions& options, const GeometryTileData&, const CanonicalTileID&, - const RenderStyle&, + const std::vector<const RenderLayer*>&, const float bearing, const float pixelsToTileUnits) const; diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index b565439588..8293923ff6 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -18,7 +18,6 @@ namespace mbgl { class PaintParameters; class TransformState; class RenderTile; -class RenderStyle; class RenderLayer; class RenderedQueryOptions; class SourceQueryOptions; @@ -63,7 +62,7 @@ public: virtual std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const = 0; virtual std::vector<Feature> diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index 3d95b12bc4..77516586d6 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -373,24 +373,28 @@ RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) std::vector<Feature> RenderStyle::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const RenderedQueryOptions& options) const { - std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; - + std::vector<const RenderLayer*> layers; if (options.layerIDs) { - std::unordered_set<std::string> sourceIDs; for (const auto& layerID : *options.layerIDs) { if (const RenderLayer* layer = getRenderLayer(layerID)) { - sourceIDs.emplace(layer->baseImpl->source); - } - } - for (const auto& sourceID : sourceIDs) { - if (RenderSource* renderSource = getRenderSource(sourceID)) { - auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, *this, options); - std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); + layers.emplace_back(layer); } } } else { - for (const auto& entry : renderSources) { - auto sourceResults = entry.second->queryRenderedFeatures(geometry, transformState, *this, options); + for (const auto& entry : renderLayers) { + layers.emplace_back(entry.second.get()); + } + } + + std::unordered_set<std::string> sourceIDs; + for (const RenderLayer* layer : layers) { + sourceIDs.emplace(layer->baseImpl->source); + } + + std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; + for (const auto& sourceID : sourceIDs) { + if (RenderSource* renderSource = getRenderSource(sourceID)) { + auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options); std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); } } diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index df8bcc0ae7..d6a81e13ca 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -75,9 +75,9 @@ std::vector<std::reference_wrapper<RenderTile>> RenderGeoJSONSource::getRenderTi std::unordered_map<std::string, std::vector<Feature>> RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const { - return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options); + return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options); } std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const { diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index b84156ab95..72ab4879ef 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -30,7 +30,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const final; std::vector<Feature> diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 50d5b17ec2..9140e01711 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -83,7 +83,7 @@ void RenderImageSource::finishRender(PaintParameters& parameters) { std::unordered_map<std::string, std::vector<Feature>> RenderImageSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, - const RenderStyle&, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions&) const { return std::unordered_map<std::string, std::vector<Feature>> {}; } diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index fc1a462090..7b69d09fa7 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -31,7 +31,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const final; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index cbd874f647..bcd719365d 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -73,7 +73,7 @@ std::vector<std::reference_wrapper<RenderTile>> RenderRasterSource::getRenderTil std::unordered_map<std::string, std::vector<Feature>> RenderRasterSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, - const RenderStyle&, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions&) const { return std::unordered_map<std::string, std::vector<Feature>> {}; } diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp index 1f4678da9f..01de812309 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -26,7 +26,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const final; std::vector<Feature> diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index 47bccdaca8..ca3071c6b0 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -76,9 +76,9 @@ std::vector<std::reference_wrapper<RenderTile>> RenderVectorSource::getRenderTil std::unordered_map<std::string, std::vector<Feature>> RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const { - return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options); + return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options); } std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const { diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp index 256ad4e800..5e5c6d1108 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -26,7 +26,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const final; std::vector<Feature> diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 219f154675..4944de2ba9 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -206,7 +206,7 @@ void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) { std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) const { std::unordered_map<std::string, std::vector<Feature>> result; if (renderTiles.empty() || geometry.empty()) { @@ -249,7 +249,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered renderTile.tile.queryRenderedFeatures(result, tileSpaceQueryGeometry, transformState, - style, + layers, options); } diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index d940f378fa..3bf9dc75d4 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -21,7 +21,7 @@ namespace mbgl { class PaintParameters; class TransformState; class RenderTile; -class RenderStyle; +class RenderLayer; class RenderedQueryOptions; class SourceQueryOptions; class TileParameters; @@ -50,7 +50,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions& options) const; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const; diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 20056e355d..0d01eba894 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -214,7 +214,7 @@ void GeometryTile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState& transformState, - const RenderStyle& style, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) { if (!featureIndex || !data) return; @@ -227,7 +227,7 @@ void GeometryTile::queryRenderedFeatures( options, *data, id.canonical, - style, + layers, collisionTile.get(), *this); } diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index c45762742b..5aac3a63a6 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -19,7 +19,6 @@ namespace mbgl { class GeometryTileData; -class RenderStyle; class RenderLayer; class SourceQueryOptions; class TileParameters; @@ -56,7 +55,7 @@ public: std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, - const RenderStyle&, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) override; void querySourceFeatures( diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index 35fc31dae1..7d7eb0b3fc 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -33,7 +33,7 @@ void Tile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>&, const GeometryCoordinates&, const TransformState&, - const RenderStyle&, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions&) {} void Tile::querySourceFeatures( diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index a1ab6a84b7..39cc0de8bd 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -23,7 +23,7 @@ class DebugBucket; class TransformState; class TileObserver; class PlacementConfig; -class RenderStyle; +class RenderLayer; class RenderedQueryOptions; class SourceQueryOptions; @@ -61,7 +61,7 @@ public: std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, - const RenderStyle&, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions& options); virtual void querySourceFeatures( diff --git a/test/tile/annotation_tile.test.cpp b/test/tile/annotation_tile.test.cpp index c58b980ecd..86ede07089 100644 --- a/test/tile/annotation_tile.test.cpp +++ b/test/tile/annotation_tile.test.cpp @@ -4,7 +4,6 @@ #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/util/run_loop.hpp> #include <mbgl/map/transform.hpp> -#include <mbgl/renderer/render_style.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/renderer/query.hpp> #include <mbgl/text/collision_tile.hpp> @@ -31,7 +30,6 @@ public: AnnotationManager annotationManager { style }; HeadlessBackend backend; BackendScope scope { backend }; - RenderStyle renderStyle { threadPool, fileSource }; ImageManager imageManager; GlyphManager glyphManager { fileSource }; @@ -93,7 +91,7 @@ TEST(AnnotationTile, Issue8289) { TransformState transformState; RenderedQueryOptions options; - tile.queryRenderedFeatures(result, queryGeometry, transformState, test.renderStyle, options); + tile.queryRenderedFeatures(result, queryGeometry, transformState, {}, options); EXPECT_TRUE(result.empty()); } |