diff options
author | Sudarsana Babu Nagineni <sudarsana.babu@mapbox.com> | 2018-07-30 15:30:57 +0300 |
---|---|---|
committer | Sudarsana Babu Nagineni <sudarsana.babu@mapbox.com> | 2018-08-06 16:55:30 +0300 |
commit | 0130c58fdd74edbbfe668f3125a9377554d7d605 (patch) | |
tree | 6be1c1d25d146e9273f04f40f2283e18048c17ac | |
parent | 7373abef92ed4911b91f9fca3d97784ed0d9e02e (diff) | |
download | qtlocation-mapboxgl-0130c58fdd74edbbfe668f3125a9377554d7d605.tar.gz |
Bump Mapbox GL Native
Bump version.
mapbox-gl-native @ 377a6e42d687c419e6ae1012b8626336f5dfc1b6
315 files changed, 20751 insertions, 7093 deletions
diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt.hpp index ee1bbbca8d..af5bbc3129 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt.hpp @@ -51,9 +51,6 @@ struct Options : TileOptions { // max number of points per tile in the tile index uint32_t indexMaxPoints = 100000; - - // whether to tile solid square tiles further - bool solidChildren = false; }; const Tile empty_tile{}; @@ -63,12 +60,12 @@ inline uint64_t toID(uint8_t z, uint32_t x, uint32_t y) { } inline const Tile geoJSONToTile(const geojson& geojson_, - uint8_t z, - uint32_t x, - uint32_t y, - const TileOptions& options = TileOptions(), - bool wrap = false, - bool clip = false) { + uint8_t z, + uint32_t x, + uint32_t y, + const TileOptions& options = TileOptions(), + bool wrap = false, + bool clip = false) { const auto features_ = geojson::visit(geojson_, ToFeatureCollection{}); auto z2 = 1u << z; @@ -83,8 +80,7 @@ inline const Tile geoJSONToTile(const geojson& geojson_, const auto left = detail::clip<0>(features, (x - p) / z2, (x + 1 + p) / z2, -1, 2); features = detail::clip<1>(left, (y - p) / z2, (y + 1 + p) / z2, -1, 2); } - return detail::InternalTile({ features, z, x, y, options.extent, options.buffer, tolerance }) - .tile; + return detail::InternalTile({ features, z, x, y, options.extent, tolerance }).tile; } class GeoJSONVT { @@ -131,10 +127,6 @@ public: // if we found a parent tile containing the original geometry, we can drill down from it const auto& parent = it->second; - // parent tile is a solid clipped square, return it instead since it's identical - if (parent.is_solid) - return parent.tile; - // drill down parent tile up to the requested one splitTile(parent.source_features, parent.z, parent.x, parent.y, z, x, y); @@ -146,11 +138,6 @@ public: if (it == tiles.end()) throw std::runtime_error("Parent tile not found"); - // drilling stopped because parent was a solid square; return it instead - if (it->second.is_solid) - return it->second.tile; - - // otherwise it was an empty tile return empty_tile; } @@ -198,8 +185,8 @@ private: (z == options.maxZoom ? 0 : options.tolerance / (z2 * options.extent)); it = tiles - .emplace(id, detail::InternalTile{ features, z, x, y, options.extent, - options.buffer, tolerance }) + .emplace(id, + detail::InternalTile{ features, z, x, y, options.extent, tolerance }) .first; stats[z] = (stats.count(z) ? stats[z] + 1 : 1); total++; @@ -211,10 +198,6 @@ private: if (features.empty()) return; - // stop tiling if the tile is solid clipped square - if (!options.solidChildren && tile.is_solid) - return; - // if it's the first-pass tiling if (cz == 0u) { // stop tiling if we reached max zoom, or if the tile is too simple diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/clip.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/clip.hpp index 212e2979d0..e6f305921f 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/clip.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/clip.hpp @@ -116,13 +116,13 @@ private: if (i == len - 2) slice.push_back(b); // last point } - } else if (ak > k2) { + } else if (ak >= k2) { if (bk < k1) { // <--|-----|--- slice.push_back(intersect<I>(a, b, k2)); slice.push_back(intersect<I>(a, b, k1)); slice = newSlice(slices, slice, dist); - } else if (bk <= k2) { // | <--|--- + } else if (bk < k2) { // | <--|--- slice.push_back(intersect<I>(a, b, k2)); if (i == len - 2) slice.push_back(b); // last point @@ -171,8 +171,8 @@ private: else if (i == len - 2) slice.push_back(b); // last point } - } else if (ak > k2) { - if (bk <= k2) { // | <--|--- + } else if (ak >= k2) { + if (bk < k2) { // | <--|--- slice.push_back(intersect<I>(a, b, k2)); if (bk < k1) // <--|-----|--- slice.push_back(intersect<I>(a, b, k1)); @@ -216,10 +216,10 @@ inline vt_features clip(const vt_features& features, const double minAll, const double maxAll) { - if (minAll >= k1 && maxAll <= k2) // trivial accept + if (minAll >= k1 && maxAll < k2) // trivial accept return features; - if (minAll > k2 || maxAll < k1) // trivial reject + if (maxAll < k1 || minAll >= k2) // trivial reject return {}; vt_features clipped; @@ -232,10 +232,10 @@ inline vt_features clip(const vt_features& features, const double min = get<I>(feature.bbox.min); const double max = get<I>(feature.bbox.max); - if (min >= k1 && max <= k2) { // trivial accept + if (min >= k1 && max < k2) { // trivial accept clipped.push_back(feature); - } else if (min > k2 || max < k1) { // trivial reject + } else if (max < k1 || min >= k2) { // trivial reject continue; } else { diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/convert.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/convert.hpp index ba28f449b3..88c036f02c 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/convert.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/convert.hpp @@ -99,8 +99,7 @@ inline vt_features convert(const geometry::feature_collection<double>& features, for (const auto& feature : features) { projected.emplace_back( geometry::geometry<double>::visit(feature.geometry, project{ tolerance }), - feature.properties, - feature.id); + feature.properties, feature.id); } return projected; } diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/simplify.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/simplify.hpp index be0165b0f1..784f085e7f 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/simplify.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/simplify.hpp @@ -37,6 +37,8 @@ inline double getSqSegDist(const vt_point& p, const vt_point& a, const vt_point& inline void simplify(std::vector<vt_point>& points, size_t first, size_t last, double sqTolerance) { double maxSqDist = sqTolerance; size_t index = 0; + const int64_t mid = (last - first) >> 1; + int64_t minPosToMid = last - first; for (auto i = first + 1; i < last; i++) { const double sqDist = getSqSegDist(points[i], points[first], points[last]); @@ -44,6 +46,16 @@ inline void simplify(std::vector<vt_point>& points, size_t first, size_t last, d if (sqDist > maxSqDist) { index = i; maxSqDist = sqDist; + + } else if (sqDist == maxSqDist) { + // a workaround to ensure we choose a pivot close to the middle of the list, + // reducing recursion depth, for certain degenerate inputs + // https://github.com/mapbox/geojson-vt/issues/104 + auto posToMid = std::abs(static_cast<int64_t>(i) - mid); + if (posToMid < minPosToMid) { + index = i; + minPosToMid = posToMid; + } } } diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/tile.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/tile.hpp index ccb230bb9c..e382346779 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/tile.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/tile.hpp @@ -17,12 +17,16 @@ namespace detail { class InternalTile { public: + const uint16_t extent; const uint8_t z; const uint32_t x; const uint32_t y; + const double z2; + const double tolerance; + const double sq_tolerance; + vt_features source_features; - bool is_solid = false; mapbox::geometry::box<double> bbox = { { 2, 1 }, { -1, 0 } }; Tile tile; @@ -32,13 +36,12 @@ public: const uint32_t x_, const uint32_t y_, const uint16_t extent_, - const uint16_t buffer, const double tolerance_) - : z(z_), + : extent(extent_), + z(z_), x(x_), y(y_), z2(std::pow(2, z)), - extent(extent_), tolerance(tolerance_), sq_tolerance(tolerance_ * tolerance_) { @@ -59,59 +62,33 @@ public: bbox.max.x = std::max(feature.bbox.max.x, bbox.max.x); bbox.max.y = std::max(feature.bbox.max.y, bbox.max.y); } - - is_solid = isSolid(buffer); } private: - const double z2; - const uint16_t extent; - const double tolerance; - const double sq_tolerance; - - bool isSolid(const uint16_t buffer) { - if (tile.features.size() != 1) - return false; - - const auto& geom = tile.features.front().geometry; - if (!geom.is<mapbox::geometry::polygon<int16_t>>()) - return false; - - const auto& rings = geom.get<mapbox::geometry::polygon<int16_t>>(); - if (rings.size() > 1) - return false; - - const auto& ring = rings.front(); - if (ring.size() != 5) - return false; - - const int16_t min = -static_cast<int16_t>(buffer); - const int16_t max = static_cast<int16_t>(extent + buffer); - for (const auto& p : ring) { - if ((p.x != min && p.x != max) || (p.y != min && p.y != max)) - return false; - } - - return true; - } - - void addFeature(const vt_point& point, const property_map& props, const optional<identifier>& id) { + void + addFeature(const vt_point& point, const property_map& props, const optional<identifier>& id) { tile.features.push_back({ transform(point), props, id }); } - void addFeature(const vt_line_string& line, const property_map& props, const optional<identifier>& id) { + void addFeature(const vt_line_string& line, + const property_map& props, + const optional<identifier>& id) { const auto new_line = transform(line); if (!new_line.empty()) tile.features.push_back({ std::move(new_line), props, id }); } - void addFeature(const vt_polygon& polygon, const property_map& props, const optional<identifier>& id) { + void addFeature(const vt_polygon& polygon, + const property_map& props, + const optional<identifier>& id) { const auto new_polygon = transform(polygon); if (!new_polygon.empty()) tile.features.push_back({ std::move(new_polygon), props, id }); } - void addFeature(const vt_geometry_collection& collection, const property_map& props, const optional<identifier>& id) { + void addFeature(const vt_geometry_collection& collection, + const property_map& props, + const optional<identifier>& id) { for (const auto& geom : collection) { vt_geometry::visit(geom, [&](const auto& g) { // `this->` is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636 diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/types.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/types.hpp index b54357a7b9..b65844f432 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/types.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/types.hpp @@ -60,13 +60,19 @@ using vt_multi_point = std::vector<vt_point>; struct vt_line_string : std::vector<vt_point> { using container_type = std::vector<vt_point>; - using container_type::container_type; + vt_line_string() = default; + vt_line_string(std::initializer_list<vt_point> args) + : container_type(std::move(args)) {} + double dist = 0.0; // line length }; struct vt_linear_ring : std::vector<vt_point> { using container_type = std::vector<vt_point>; - using container_type::container_type; + vt_linear_ring() = default; + vt_linear_ring(std::initializer_list<vt_point> args) + : container_type(std::move(args)) {} + double area = 0.0; // polygon ring area }; diff --git a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/wrap.hpp b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/wrap.hpp index 495ccc5800..495ccc5800 100644 --- a/deps/geojsonvt/6.3.0/include/mapbox/geojsonvt/wrap.hpp +++ b/deps/geojsonvt/6.5.1/include/mapbox/geojsonvt/wrap.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry.hpp b/deps/geometry/0.9.3/include/mapbox/geometry.hpp index e232453179..e232453179 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/box.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/box.hpp index bf81b703ec..bf81b703ec 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/box.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/box.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/envelope.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/envelope.hpp index 8603583985..8603583985 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/envelope.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/envelope.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/feature.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/feature.hpp index 20d2ddf6b8..685c01229f 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/feature.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/feature.hpp @@ -84,7 +84,12 @@ struct feature_collection : Cont<feature<T>> using coordinate_type = T; using feature_type = feature<T>; using container_type = Cont<feature_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + feature_collection(Args&&... args) : container_type(std::forward<Args>(args)...) {} + feature_collection(std::initializer_list<feature_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/for_each_point.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/for_each_point.hpp index 44d6e77bd0..44d6e77bd0 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/for_each_point.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/for_each_point.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/geometry.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/geometry.hpp index a9d072be7e..3b86117220 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/geometry.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/geometry.hpp @@ -46,12 +46,12 @@ struct geometry_collection : Cont<geometry<T>> using coordinate_type = T; using geometry_type = geometry<T>; using container_type = Cont<geometry_type>; + using size_type = typename container_type::size_type; - geometry_collection() = default; - geometry_collection(geometry_collection const&) = default; - geometry_collection(geometry_collection &&) = default; - geometry_collection(std::initializer_list<geometry_type> && args) - : container_type(std::forward<std::initializer_list<geometry_type>>(args)) {}; + template <class... Args> + geometry_collection(Args&&... args) : container_type(std::forward<Args>(args)...) {} + geometry_collection(std::initializer_list<geometry_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/line_string.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/line_string.hpp index 6d811ce221..d11d06bd84 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/line_string.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/line_string.hpp @@ -14,7 +14,12 @@ struct line_string : Cont<point<T> > using coordinate_type = T; using point_type = point<T>; using container_type = Cont<point_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + line_string(Args&&... args) : container_type(std::forward<Args>(args)...) {} + line_string(std::initializer_list<point_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/multi_line_string.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/multi_line_string.hpp index 07a7a1d609..7dfefd8ffa 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/multi_line_string.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/multi_line_string.hpp @@ -14,7 +14,12 @@ struct multi_line_string : Cont<line_string<T>> using coordinate_type = T; using line_string_type = line_string<T>; using container_type = Cont<line_string_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + multi_line_string(Args&&... args) : container_type(std::forward<Args>(args)...) {} + multi_line_string(std::initializer_list<line_string_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/multi_point.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/multi_point.hpp index a3c73cff91..d2d7a6768a 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/multi_point.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/multi_point.hpp @@ -14,7 +14,12 @@ struct multi_point : Cont<point<T>> using coordinate_type = T; using point_type = point<T>; using container_type = Cont<point_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + multi_point(Args&&... args) : container_type(std::forward<Args>(args)...) {} + multi_point(std::initializer_list<point_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/multi_polygon.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/multi_polygon.hpp index ad230a04c8..0e3cb321a4 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/multi_polygon.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/multi_polygon.hpp @@ -14,7 +14,12 @@ struct multi_polygon : Cont<polygon<T>> using coordinate_type = T; using polygon_type = polygon<T>; using container_type = Cont<polygon_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + multi_polygon(Args&&... args) : container_type(std::forward<Args>(args)...) {} + multi_polygon(std::initializer_list<polygon_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/point.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/point.hpp index 0cba4996e7..0cba4996e7 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/point.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/point.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/point_arithmetic.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/point_arithmetic.hpp index 0c4c63278a..0c4c63278a 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/point_arithmetic.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/point_arithmetic.hpp diff --git a/deps/geometry/0.9.2/include/mapbox/geometry/polygon.hpp b/deps/geometry/0.9.3/include/mapbox/geometry/polygon.hpp index 99a66aa125..0c7e1161cb 100644 --- a/deps/geometry/0.9.2/include/mapbox/geometry/polygon.hpp +++ b/deps/geometry/0.9.3/include/mapbox/geometry/polygon.hpp @@ -15,7 +15,12 @@ struct linear_ring : Cont<point<T>> using coordinate_type = T; using point_type = point<T>; using container_type = Cont<point_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + linear_ring(Args&&... args) : container_type(std::forward<Args>(args)...) {} + linear_ring(std::initializer_list<point_type> args) + : container_type(std::move(args)) {} }; template <typename T, template <typename...> class Cont = std::vector> @@ -24,7 +29,12 @@ struct polygon : Cont<linear_ring<T>> using coordinate_type = T; using linear_ring_type = linear_ring<T>; using container_type = Cont<linear_ring_type>; - using container_type::container_type; + using size_type = typename container_type::size_type; + + template <class... Args> + polygon(Args&&... args) : container_type(std::forward<Args>(args)...) {} + polygon(std::initializer_list<linear_ring_type> args) + : container_type(std::move(args)) {} }; } // namespace geometry diff --git a/deps/optional/f27e7908/include/experimental/optional b/deps/optional/f27e7908/include/experimental/optional new file mode 100644 index 0000000000..7b9148f3a7 --- /dev/null +++ b/deps/optional/f27e7908/include/experimental/optional @@ -0,0 +1,1052 @@ +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# ifndef ___OPTIONAL_HPP___ +# define ___OPTIONAL_HPP___ + +# include <utility> +# include <type_traits> +# include <initializer_list> +# include <cassert> +# include <functional> +# include <string> +# include <stdexcept> + +# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if (defined __cplusplus) && (__cplusplus == 201103L) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +namespace std{ + +namespace experimental{ + +// BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template <typename T> + using is_trivially_destructible = std::has_trivial_destructor<T>; +# endif +// END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + +// workaround for missing traits in GCC and CLANG +template <class T> +struct is_nothrow_move_constructible +{ + constexpr static bool value = std::is_nothrow_constructible<T, T&&>::value; +}; + + +template <class T, class U> +struct is_assignable +{ + template <class X, class Y> + constexpr static bool has_assign(...) { return false; } + + template <class X, class Y, size_t S = sizeof((std::declval<X>() = std::declval<Y>(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign<T, U>(true); +}; + + +template <class T> +struct is_nothrow_move_assignable +{ + template <class X, bool has_any_move_assign> + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template <class X> + struct has_nothrow_move_assign<X, true> { + constexpr static bool value = noexcept( std::declval<X&>() = std::declval<X&&>() ); + }; + + constexpr static bool value = has_nothrow_move_assign<T, is_assignable<T&, T&&>::value>::value; +}; +// end workaround + + +# endif + + + +// 20.5.4, optional for object types +template <class T> class optional; + +// 20.5.5, optional for lvalue reference types +template <class T> class optional<T&>; + + +// workaround: std utility functions aren't constexpr yet +template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type& t) noexcept +{ + return static_cast<T&&>(t); +} + +template <class T> inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type&& t) noexcept +{ + static_assert(!std::is_lvalue_reference<T>::value, "!!"); + return static_cast<T&&>(t); +} + +template <class T> inline constexpr typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept +{ + return static_cast<typename std::remove_reference<T>::type&&>(t); +} + + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + +namespace detail_ +{ + +// static_addressof: a constexpr version of addressof +template <typename T> +struct has_overloaded_addressof +{ + template <class X> + constexpr static bool has_overload(...) { return false; } + + template <class X, size_t S = sizeof(std::declval<X&>().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload<T>(true); +}; + +template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)> +constexpr T* static_addressof(T& ref) +{ + return &ref; +} + +template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)> +T* static_addressof(T& ref) +{ + return std::addressof(ref); +} + + +// the call to convert<A>(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +template <class U> +constexpr U convert(U v) { return v; } + +} // namespace detail + + +constexpr struct trivial_init_t{} trivial_init{}; + + +// 20.5.6, In-place construction +constexpr struct in_place_t{} in_place{}; + + +// 20.5.7, Disengaged state indicator +struct nullopt_t +{ + struct init{}; + constexpr explicit nullopt_t(init){} +}; +constexpr nullopt_t nullopt{nullopt_t::init()}; + + +// 20.5.8, class bad_optional_access +class bad_optional_access : public logic_error { +public: + explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} + explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} +}; + + +template <class T> +union storage_t +{ + unsigned char dummy_; + T value_; + + constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template <class... Args> + constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {} + + ~storage_t(){} +}; + + +template <class T> +union constexpr_storage_t +{ + unsigned char dummy_; + T value_; + + constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; + + template <class... Args> + constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {} + + ~constexpr_storage_t() = default; +}; + + +template <class T> +struct optional_base +{ + bool init_; + storage_t<T> storage_; + + constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template <class... Args> explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward<Args>(args)...) {} + + template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> + explicit optional_base(in_place_t, std::initializer_list<U> il, Args&&... args) + : init_(true), storage_(il, std::forward<Args>(args)...) {} + + ~optional_base() { if (init_) storage_.value_.T::~T(); } +}; + + +template <class T> +struct constexpr_optional_base +{ + bool init_; + constexpr_storage_t<T> storage_; + + constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} + + template <class... Args> explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_(constexpr_forward<Args>(args)...) {} + + template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list<U> il, Args&&... args) + : init_(true), storage_(il, std::forward<Args>(args)...) {} + + ~constexpr_optional_base() = default; +}; + +template <class T> +using OptionalBase = typename std::conditional< + is_trivially_destructible<T>::value, // if possible + constexpr_optional_base<typename std::remove_const<T>::type>, // use base with trivial destructor + optional_base<typename std::remove_const<T>::type> +>::type; + + + +template <class T> +class optional : private OptionalBase<T> +{ + static_assert( !std::is_same<typename std::decay<T>::type, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same<typename std::decay<T>::type, in_place_t>::value, "bad T" ); + + + constexpr bool initialized() const noexcept { return OptionalBase<T>::init_; } + typename std::remove_const<T>::type* dataptr() { return std::addressof(OptionalBase<T>::storage_.value_); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase<T>::storage_.value_); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase<T>::storage_.value_; } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase<T>::storage_.value_; } +# else + T& contained_val() & { return OptionalBase<T>::storage_.value_; } + T&& contained_val() && { return std::move(OptionalBase<T>::storage_.value_); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase<T>::storage_.value_; } + T& contained_val() { return OptionalBase<T>::storage_.value_; } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase<T>::init_ = false; + } + + template <class... Args> + void initialize(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) + { + assert(!OptionalBase<T>::init_); + ::new (static_cast<void*>(dataptr())) T(std::forward<Args>(args)...); + OptionalBase<T>::init_ = true; + } + + template <class U, class... Args> + void initialize(std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, std::forward<Args>(args)...))) + { + assert(!OptionalBase<T>::init_); + ::new (static_cast<void*>(dataptr())) T(il, std::forward<Args>(args)...); + OptionalBase<T>::init_ = true; + } + +public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase<T>() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {}; + + optional(const optional& rhs) + : OptionalBase<T>() + { + if (rhs.initialized()) { + ::new (static_cast<void*>(dataptr())) T(*rhs); + OptionalBase<T>::init_ = true; + } + } + + optional(optional&& rhs) noexcept(is_nothrow_move_constructible<T>::value) + : OptionalBase<T>() + { + if (rhs.initialized()) { + ::new (static_cast<void*>(dataptr())) T(std::move(*rhs)); + OptionalBase<T>::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase<T>(v) {} + + constexpr optional(T&& v) : OptionalBase<T>(constexpr_move(v)) {} + + template <class... Args> + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {} + + template <class U, class... Args, TR2_OPTIONAL_REQUIRES(is_constructible<T, std::initializer_list<U>>)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args) + : OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(is_nothrow_move_assignable<T>::value && is_nothrow_move_constructible<T>::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); + return *this; + } + + template <class U> + auto operator=(U&& v) + -> typename enable_if + < + is_same<typename decay<U>::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = std::forward<U>(v); } + else { initialize(std::forward<U>(v)); } + return *this; + } + + + template <class... Args> + void emplace(Args&&... args) + { + clear(); + initialize(std::forward<Args>(args)...); + } + + template <class U, class... Args> + void emplace(initializer_list<U> il, Args&&... args) + { + clear(); + initialize<U, Args...>(il, std::forward<Args>(args)...); + } + + // 20.5.4.4, Swap + void swap(optional<T>& rhs) noexcept(is_nothrow_move_constructible<T>::value && noexcept(swap(declval<T&>(), declval<T&>()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + constexpr bool has_value() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert (initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert (initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + if (!initialized()) throw bad_optional_access("bad optional access"); + return std::move(contained_val()); + } + +# else + + T* operator ->() { + assert (initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert (initialized()); + return contained_val(); + } + + constexpr T const& value() const { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + + T& value() { + return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template <class V> + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template <class V> + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# else + + template <class V> + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# endif + +# else + + template <class V> + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); + } + +# endif + + // 20.6.3.6, modifiers + void reset() noexcept { clear(); } +}; + + +template <class T> +class optional<T&> +{ + static_assert( !std::is_same<T, nullopt_t>::value, "bad T" ); + static_assert( !std::is_same<T, in_place_t>::value, "bad T" ); + T* ref; + +public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template <typename U> + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + is_same<typename decay<U>::type, optional<T&>>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template <typename U> + auto operator=(U&& rhs) noexcept + -> typename enable_if + < + !is_same<typename decay<U>::type, optional<T&>>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + + void swap(optional<T&>& rhs) noexcept + { + std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + constexpr bool has_value() const noexcept { + return ref != nullptr; + } + + template <class V> + constexpr typename decay<T>::type value_or(V&& v) const + { + return *this ? **this : detail_::convert<typename decay<T>::type>(constexpr_forward<V>(v)); + } + + // x.x.x.x, modifiers + void reset() noexcept { ref = nullptr; } +}; + + +template <class T> +class optional<T&&> +{ + static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); +}; + + +// 20.5.8, Relational operators +template <class T> constexpr bool operator==(const optional<T>& x, const optional<T>& y) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template <class T> constexpr bool operator!=(const optional<T>& x, const optional<T>& y) +{ + return !(x == y); +} + +template <class T> constexpr bool operator<(const optional<T>& x, const optional<T>& y) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template <class T> constexpr bool operator>(const optional<T>& x, const optional<T>& y) +{ + return (y < x); +} + +template <class T> constexpr bool operator<=(const optional<T>& x, const optional<T>& y) +{ + return !(y < x); +} + +template <class T> constexpr bool operator>=(const optional<T>& x, const optional<T>& y) +{ + return !(x < y); +} + + +// 20.5.9, Comparison with nullopt +template <class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept +{ + return (!x); +} + +template <class T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept +{ + return (!x); +} + +template <class T> constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept +{ + return false; +} + +template <class T> constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept +{ + return (!x); +} + +template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept +{ + return true; +} + +template <class T> constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept +{ + return bool(x); +} + +template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept +{ + return false; +} + +template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept +{ + return true; +} + +template <class T> constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept +{ + return (!x); +} + + + +// 20.5.10, Comparison with T +template <class T> constexpr bool operator==(const optional<T>& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template <class T> constexpr bool operator==(const T& v, const optional<T>& x) +{ + return bool(x) ? v == *x : false; +} + +template <class T> constexpr bool operator!=(const optional<T>& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template <class T> constexpr bool operator!=(const T& v, const optional<T>& x) +{ + return bool(x) ? v != *x : true; +} + +template <class T> constexpr bool operator<(const optional<T>& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template <class T> constexpr bool operator>(const T& v, const optional<T>& x) +{ + return bool(x) ? v > *x : true; +} + +template <class T> constexpr bool operator>(const optional<T>& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template <class T> constexpr bool operator<(const T& v, const optional<T>& x) +{ + return bool(x) ? v < *x : false; +} + +template <class T> constexpr bool operator>=(const optional<T>& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template <class T> constexpr bool operator<=(const T& v, const optional<T>& x) +{ + return bool(x) ? v <= *x : false; +} + +template <class T> constexpr bool operator<=(const optional<T>& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template <class T> constexpr bool operator>=(const T& v, const optional<T>& x) +{ + return bool(x) ? v >= *x : true; +} + + +// Comparison of optional<T&> with T +template <class T> constexpr bool operator==(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template <class T> constexpr bool operator==(const T& v, const optional<T&>& x) +{ + return bool(x) ? v == *x : false; +} + +template <class T> constexpr bool operator!=(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template <class T> constexpr bool operator!=(const T& v, const optional<T&>& x) +{ + return bool(x) ? v != *x : true; +} + +template <class T> constexpr bool operator<(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template <class T> constexpr bool operator>(const T& v, const optional<T&>& x) +{ + return bool(x) ? v > *x : true; +} + +template <class T> constexpr bool operator>(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template <class T> constexpr bool operator<(const T& v, const optional<T&>& x) +{ + return bool(x) ? v < *x : false; +} + +template <class T> constexpr bool operator>=(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template <class T> constexpr bool operator<=(const T& v, const optional<T&>& x) +{ + return bool(x) ? v <= *x : false; +} + +template <class T> constexpr bool operator<=(const optional<T&>& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template <class T> constexpr bool operator>=(const T& v, const optional<T&>& x) +{ + return bool(x) ? v >= *x : true; +} + +// Comparison of optional<T const&> with T +template <class T> constexpr bool operator==(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x == v : false; +} + +template <class T> constexpr bool operator==(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v == *x : false; +} + +template <class T> constexpr bool operator!=(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x != v : true; +} + +template <class T> constexpr bool operator!=(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v != *x : true; +} + +template <class T> constexpr bool operator<(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x < v : true; +} + +template <class T> constexpr bool operator>(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v > *x : true; +} + +template <class T> constexpr bool operator>(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x > v : false; +} + +template <class T> constexpr bool operator<(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v < *x : false; +} + +template <class T> constexpr bool operator>=(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x >= v : false; +} + +template <class T> constexpr bool operator<=(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v <= *x : false; +} + +template <class T> constexpr bool operator<=(const optional<const T&>& x, const T& v) +{ + return bool(x) ? *x <= v : true; +} + +template <class T> constexpr bool operator>=(const T& v, const optional<const T&>& x) +{ + return bool(x) ? v >= *x : true; +} + + +// 20.5.12, Specialized algorithms +template <class T> +void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) +{ + x.swap(y); +} + + +template <class T> +constexpr optional<typename decay<T>::type> make_optional(T&& v) +{ + return optional<typename decay<T>::type>(constexpr_forward<T>(v)); +} + +template <class X> +constexpr optional<X&> make_optional(reference_wrapper<X> v) +{ + return optional<X&>(v.get()); +} + + +} // namespace experimental +} // namespace std + +namespace std +{ + template <typename T> + struct hash<std::experimental::optional<T>> + { + typedef typename hash<T>::result_type result_type; + typedef std::experimental::optional<T> argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash<T>{}(*arg) : result_type{}; + } + }; + + template <typename T> + struct hash<std::experimental::optional<T&>> + { + typedef typename hash<T>::result_type result_type; + typedef std::experimental::optional<T&> argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? std::hash<T>{}(*arg) : result_type{}; + } + }; +} + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif //___OPTIONAL_HPP___ diff --git a/deps/vector-tile/1.0.1/include/mapbox/vector_tile.hpp b/deps/vector-tile/1.0.2/include/mapbox/vector_tile.hpp index 2308462c68..5ddae485f0 100644 --- a/deps/vector-tile/1.0.1/include/mapbox/vector_tile.hpp +++ b/deps/vector-tile/1.0.2/include/mapbox/vector_tile.hpp @@ -23,13 +23,15 @@ using point_type = mapbox::geometry::point<std::int16_t>; class points_array_type : public std::vector<point_type> { public: using coordinate_type = point_type::coordinate_type; - using std::vector<point_type>::vector; + template <class... Args> + points_array_type(Args&&... args) : std::vector<point_type>(std::forward<Args>(args)...) {} }; class points_arrays_type : public std::vector<points_array_type> { public: using coordinate_type = points_array_type::coordinate_type; - using std::vector<points_array_type>::vector; + template <class... Args> + points_arrays_type(Args&&... args) : std::vector<points_array_type>(std::forward<Args>(args)...) {} }; class layer; @@ -137,7 +139,7 @@ inline feature::feature(protozero::data_view const& feature_view, layer const& l while (feature_pbf.next()) { switch (feature_pbf.tag()) { case FeatureType::ID: - id = { feature_pbf.get_uint64() }; + id = optional<mapbox::geometry::identifier>{ feature_pbf.get_uint64() }; break; case FeatureType::TAGS: tags_iter = feature_pbf.get_packed_uint32(); diff --git a/deps/vector-tile/1.0.1/include/mapbox/vector_tile/vector_tile_config.hpp b/deps/vector-tile/1.0.2/include/mapbox/vector_tile/vector_tile_config.hpp index acf1185673..acf1185673 100644 --- a/deps/vector-tile/1.0.1/include/mapbox/vector_tile/vector_tile_config.hpp +++ b/deps/vector-tile/1.0.2/include/mapbox/vector_tile/vector_tile_config.hpp diff --git a/deps/vector-tile/1.0.1/include/mapbox/vector_tile/version.hpp b/deps/vector-tile/1.0.2/include/mapbox/vector_tile/version.hpp index 13b8755d3c..cc1974d63c 100644 --- a/deps/vector-tile/1.0.1/include/mapbox/vector_tile/version.hpp +++ b/deps/vector-tile/1.0.2/include/mapbox/vector_tile/version.hpp @@ -7,10 +7,10 @@ #define VECTOR_TILE_VERSION_MINOR 0 /// The patch number -#define VECTOR_TILE_VERSION_PATCH 1 +#define VECTOR_TILE_VERSION_PATCH 2 /// The complete version number #define VECTOR_TILE_VERSION_CODE (VECTOR_TILE_VERSION_MAJOR * 10000 + VECTOR_TILE_VERSION_MINOR * 100 + VECTOR_TILE_VERSION_PATCH) /// Version number as string -#define VECTOR_TILE_VERSION_STRING "1.0.1" +#define VECTOR_TILE_VERSION_STRING "1.0.2" diff --git a/include/mbgl/actor/actor.hpp b/include/mbgl/actor/actor.hpp index a0df19208e..0052fad242 100644 --- a/include/mbgl/actor/actor.hpp +++ b/include/mbgl/actor/actor.hpp @@ -1,5 +1,7 @@ #pragma once +#include <mbgl/actor/aspiring_actor.hpp> +#include <mbgl/actor/established_actor.hpp> #include <mbgl/actor/mailbox.hpp> #include <mbgl/actor/message.hpp> #include <mbgl/actor/actor_ref.hpp> @@ -8,6 +10,7 @@ #include <memory> #include <future> #include <type_traits> +#include <cassert> namespace mbgl { @@ -34,65 +37,33 @@ namespace mbgl { the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is a no-op. (In the future, a dead-letters queue or log may be implemented.) - Construction and destruction of an actor is currently synchronous: the corresponding `O` + Construction and destruction of an Actor is synchronous: the corresponding `O` object is constructed synchronously by the `Actor` constructor, and destructed synchronously by the `~Actor` destructor, after ensuring that the `O` is not currently receiving an - asynchronous message. (Construction and destruction may change to be asynchronous in the - future.) The constructor of `O` is passed an `ActorRef<O>` referring to itself (which it - can use to self-send messages), followed by the forwarded arguments passed to `Actor<O>`. + asynchronous message. The constructor of `O` is passed an `ActorRef<O>` referring to itself + (which it can use to self-send messages), followed by the forwarded arguments passed to + `Actor<O>`. Asynchronous object construction can be accomplished by directly using the + lower-level types, `AspiringActor<O>` and `EstablishedActor<O>`. Please don't send messages that contain shared pointers or references. That subverts the purpose of the actor model: prohibiting direct concurrent access to shared state. */ - template <class Object> -class Actor : public util::noncopyable { +class Actor { public: + template <class... Args> + Actor(Scheduler& scheduler, Args&&... args) + : target(scheduler, parent, std::forward<Args>(args)...) {} - // Enabled for Objects with a constructor taking ActorRef<Object> as the first parameter - template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, ActorRef<U>, Args...>::value>::type * = nullptr> - Actor(Scheduler& scheduler, Args&&... args_) - : mailbox(std::make_shared<Mailbox>(scheduler)), - object(self(), std::forward<Args>(args_)...) { - } - - // Enabled for plain Objects - template<typename U = Object, class... Args, typename std::enable_if<!std::is_constructible<U, ActorRef<U>, Args...>::value>::type * = nullptr> - Actor(Scheduler& scheduler, Args&& ... args_) - : mailbox(std::make_shared<Mailbox>(scheduler)), object(std::forward<Args>(args_)...) { - } - - ~Actor() { - mailbox->close(); - } - - template <typename Fn, class... Args> - void invoke(Fn fn, Args&&... args) { - mailbox->push(actor::makeMessage(object, fn, std::forward<Args>(args)...)); - } - - template <typename Fn, class... Args> - auto ask(Fn fn, Args&&... args) { - // Result type is deduced from the function's return type - using ResultType = typename std::result_of<decltype(fn)(Object, Args...)>::type; - - std::promise<ResultType> promise; - auto future = promise.get_future(); - mailbox->push(actor::makeMessage(std::move(promise), object, fn, std::forward<Args>(args)...)); - return future; - } + Actor(const Actor&) = delete; ActorRef<std::decay_t<Object>> self() { - return ActorRef<std::decay_t<Object>>(object, mailbox); - } - - operator ActorRef<std::decay_t<Object>>() { - return self(); + return parent.self(); } private: - std::shared_ptr<Mailbox> mailbox; - Object object; + AspiringActor<Object> parent; + EstablishedActor<Object> target; }; } // namespace mbgl diff --git a/include/mbgl/actor/aspiring_actor.hpp b/include/mbgl/actor/aspiring_actor.hpp new file mode 100644 index 0000000000..6c410cdfca --- /dev/null +++ b/include/mbgl/actor/aspiring_actor.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include <mbgl/actor/mailbox.hpp> +#include <mbgl/actor/message.hpp> +#include <mbgl/actor/actor_ref.hpp> + +#include <memory> +#include <future> +#include <type_traits> +#include <cassert> + +namespace mbgl { + +template <class Object> +class EstablishedActor; + +template <class Object> +class Actor; + +/* + An `AspiringActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`), + the other half being `EstablishedActor<O>`. It is responsible for: + - ownership of the actor's `Mailbox` + - allocating the memory for (but *not* constructing) the target object `O` + + Using these two pieces--the mailbox and a stable address for `O`--an `AspiringActor<O>` can + accept messages for the target object, or provide `ActorRef<O>`s that do so, before the object + has actually been constructed by the corresponding `EstablishedActor<O>`. (Such messages are + queued in the mailbox until after the object is constructed.) + + This allows for an `AspiringActor<O>` to be created and safely used by a thread other than the + one on which the target object will (eventually) live. +*/ +template <class Object> +class AspiringActor { +public: + AspiringActor() : mailbox(std::make_shared<Mailbox>()) { + // mailbox starts closed because the `Object` hasn't yet been constructed + assert(!mailbox->isOpen()); + } + + AspiringActor(const AspiringActor&) = delete; + + ActorRef<std::decay_t<Object>> self() { + return ActorRef<std::decay_t<Object>>(object(), mailbox); + } + +private: + std::shared_ptr<Mailbox> mailbox; + std::aligned_storage_t<sizeof(Object)> objectStorage; + + Object& object() { + return *reinterpret_cast<Object *>(&objectStorage); + } + + friend class EstablishedActor<Object>; + friend class Actor<Object>; +}; + +} // namespace mbgl diff --git a/include/mbgl/actor/established_actor.hpp b/include/mbgl/actor/established_actor.hpp new file mode 100644 index 0000000000..da0d8ac705 --- /dev/null +++ b/include/mbgl/actor/established_actor.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include <mbgl/actor/aspiring_actor.hpp> +#include <mbgl/actor/mailbox.hpp> +#include <mbgl/actor/message.hpp> +#include <mbgl/actor/actor_ref.hpp> + +#include <memory> +#include <future> +#include <type_traits> +#include <cassert> + +namespace mbgl { + +/* + An `EstablishedActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`), + the other half being `AspiringActor<O>`. It is responsible for managing the lifetime of the + target object `O` and the open/closed state of the parent's `mailbox`. + + The `O` object's lifetime is contained by that of its owning `EstablishedActor<O>`: the + `EstablishedActor` constructor executes the `O` constructor via "placement new", constructing + it at the address provided by the parent `AspiringActor`, and the `~EstablishedActor` destructor + similarly executes the `~O` destructor (after closing the mailbox). `EstablishedActor` should + therefore live entirely on the thread intended to own `O`. +*/ + +template <class Object> +class EstablishedActor { +public: + // Construct the Object from a parameter pack `args` (i.e. `Object(args...)`) + template <typename U = Object, class... Args, typename std::enable_if< + std::is_constructible<U, Args...>::value || + std::is_constructible<U, ActorRef<U>, Args...>::value + >::type * = nullptr> + EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, Args&& ... args) + : parent(parent_) { + emplaceObject(std::forward<Args>(args)...); + parent.mailbox->open(scheduler); + } + + // Construct the `Object` from a tuple containing the constructor arguments (i.e. + // `Object(std::get<0>(args), std::get<1>(args), ...)`) + template <class ArgsTuple, std::size_t ArgCount = std::tuple_size<std::decay_t<ArgsTuple>>::value> + EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, ArgsTuple&& args) + : parent(parent_) { + emplaceObject(std::forward<ArgsTuple>(args), std::make_index_sequence<ArgCount>{}); + parent.mailbox->open(scheduler); + } + + EstablishedActor(const EstablishedActor&) = delete; + + ~EstablishedActor() { + parent.mailbox->close(); + parent.object().~Object(); + } + +private: + // Enabled for Objects with a constructor taking ActorRef<Object> as the first parameter + template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, ActorRef<U>, Args...>::value>::type * = nullptr> + void emplaceObject(Args&&... args_) { + new (&parent.objectStorage) Object(parent.self(), std::forward<Args>(args_)...); + } + + // Enabled for plain Objects + template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, Args...>::value>::type * = nullptr> + void emplaceObject(Args&&... args_) { + new (&parent.objectStorage) Object(std::forward<Args>(args_)...); + } + + // Used to expand a tuple holding the constructor arguments + template <class ArgsTuple, std::size_t... I> + void emplaceObject(ArgsTuple&& args, std::index_sequence<I...>) { + emplaceObject(std::move(std::get<I>(std::forward<ArgsTuple>(args)))...); + (void) args; // mark args as used: if it's empty tuple, it's not actually used above. + } + + AspiringActor<Object>& parent; +}; + +} // namespace mbgl diff --git a/include/mbgl/actor/mailbox.hpp b/include/mbgl/actor/mailbox.hpp index 8ecf91701a..23c579917a 100644 --- a/include/mbgl/actor/mailbox.hpp +++ b/include/mbgl/actor/mailbox.hpp @@ -1,5 +1,7 @@ #pragma once +#include <mbgl/util/optional.hpp> + #include <memory> #include <mutex> #include <queue> @@ -11,17 +13,30 @@ class Message; class Mailbox : public std::enable_shared_from_this<Mailbox> { public: + + // Create a "holding" mailbox, messages to which will remain queued, + // unconsumed, until the mailbox is associated with a Scheduler using + // start(). This allows a Mailbox object to be created on one thread and + // later transferred to a different target thread that may not yet exist. + Mailbox(); + Mailbox(Scheduler&); - void push(std::unique_ptr<Message>); - + // Attach the given scheduler to this mailbox and begin processing messages + // sent to it. The mailbox must be a "holding" mailbox, as created by the + // default constructor Mailbox(). + void open(Scheduler& scheduler_); void close(); + + bool isOpen() const; + + void push(std::unique_ptr<Message>); void receive(); static void maybeReceive(std::weak_ptr<Mailbox>); private: - Scheduler& scheduler; + optional<Scheduler*> scheduler; std::recursive_mutex receivingMutex; std::mutex pushingMutex; diff --git a/include/mbgl/actor/scheduler.hpp b/include/mbgl/actor/scheduler.hpp index d8a26ebeab..75ead29f0a 100644 --- a/include/mbgl/actor/scheduler.hpp +++ b/include/mbgl/actor/scheduler.hpp @@ -31,6 +31,11 @@ class Mailbox; class Scheduler { public: virtual ~Scheduler() = default; + + // Used by a Mailbox when it has a message in its queue to request that it + // be scheduled. Specifically, the scheduler is expected to asynchronously + // call `receive() on the given mailbox, provided it still exists at that + // time. virtual void schedule(std::weak_ptr<Mailbox>) = 0; // Set/Get the current Scheduler for this thread diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 5ba23a76dd..3aee932070 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -67,9 +67,9 @@ public: void jumpTo(const CameraOptions&); void easeTo(const CameraOptions&, const AnimationOptions&); void flyTo(const CameraOptions&, const AnimationOptions&); - CameraOptions cameraForLatLngBounds(const LatLngBounds&, const EdgeInsets&, optional<double> bearing = {}) const; - CameraOptions cameraForLatLngs(const std::vector<LatLng>&, const EdgeInsets&, optional<double> bearing = {}) const; - CameraOptions cameraForGeometry(const Geometry<double>&, const EdgeInsets&, optional<double> bearing = {}) const; + CameraOptions cameraForLatLngBounds(const LatLngBounds&, const EdgeInsets&, optional<double> bearing = {}, optional<double> pitch = {}) const; + CameraOptions cameraForLatLngs(const std::vector<LatLng>&, const EdgeInsets&, optional<double> bearing = {}, optional<double> pitch = {}) const; + CameraOptions cameraForGeometry(const Geometry<double>&, const EdgeInsets&, optional<double> bearing = {}, optional<double> pitch = {}) const; LatLngBounds latLngBoundsForCamera(const CameraOptions&) const; // Position diff --git a/include/mbgl/math/log2.hpp b/include/mbgl/math/log2.hpp index 53d5e45545..6a1ba23ed9 100644 --- a/include/mbgl/math/log2.hpp +++ b/include/mbgl/math/log2.hpp @@ -2,7 +2,6 @@ #include <cmath> #include <cstdint> -#include <type_traits> namespace mbgl { namespace util { @@ -11,17 +10,5 @@ namespace util { // (== number of bits required to store x) uint32_t ceil_log2(uint64_t x); -template <typename T> -typename std::enable_if_t<std::is_floating_point<T>::value, T> log2(T x) -{ -// log2() is producing wrong results on ARMv5 binaries -// running on ARMv7+ CPUs. -#if defined(__ANDROID__) - return ::log(x) / M_LN2; -#else - return ::log2(x); -#endif -} - } // namespace util } // namespace mbgl diff --git a/include/mbgl/style/heatmap_color_property_value.hpp b/include/mbgl/style/color_ramp_property_value.hpp index 130639c6e2..bc5639c899 100644 --- a/include/mbgl/style/heatmap_color_property_value.hpp +++ b/include/mbgl/style/color_ramp_property_value.hpp @@ -2,7 +2,7 @@ #include <mbgl/util/variant.hpp> #include <mbgl/style/undefined.hpp> -#include <mbgl/style/function/camera_function.hpp> +#include <mbgl/style/expression/expression.hpp> namespace mbgl { namespace style { @@ -11,21 +11,21 @@ namespace style { * Special-case implementation of (a subset of) the PropertyValue<T> interface * used for building the HeatmapColor paint property traits class. */ -class HeatmapColorPropertyValue { +class ColorRampPropertyValue { private: std::shared_ptr<expression::Expression> value; - friend bool operator==(const HeatmapColorPropertyValue& lhs, const HeatmapColorPropertyValue& rhs) { + friend bool operator==(const ColorRampPropertyValue& lhs, const ColorRampPropertyValue& rhs) { return (lhs.isUndefined() && rhs.isUndefined()) || (lhs.value && rhs.value && *(lhs.value) == *(rhs.value)); } - friend bool operator!=(const HeatmapColorPropertyValue& lhs, const HeatmapColorPropertyValue& rhs) { + friend bool operator!=(const ColorRampPropertyValue& lhs, const ColorRampPropertyValue& rhs) { return !(lhs == rhs); } public: - HeatmapColorPropertyValue() : value(nullptr) {} - HeatmapColorPropertyValue(std::shared_ptr<expression::Expression> value_) : value(std::move(value_)) {} + ColorRampPropertyValue() : value(nullptr) {} + ColorRampPropertyValue(std::shared_ptr<expression::Expression> value_) : value(std::move(value_)) {} bool isUndefined() const { return value.get() == nullptr; } @@ -33,14 +33,14 @@ public: template <typename Evaluator> Color evaluate(const Evaluator&, TimePoint = {}) const { return {}; } - Color evaluate(double heatmapDensity) const { - const auto result = value->evaluate(expression::EvaluationContext({}, nullptr, {heatmapDensity})); + Color evaluate(double rampEvaluationParameter) const { + const auto result = value->evaluate(expression::EvaluationContext({}, nullptr, {rampEvaluationParameter})); return *expression::fromExpressionValue<Color>(*result); } - bool isDataDriven() const { return false; } - bool hasDataDrivenPropertyDifference(const HeatmapColorPropertyValue&) const { return false; } - + bool isDataDriven() const { return false; } + bool hasDataDrivenPropertyDifference(const ColorRampPropertyValue&) const { return false; } + const expression::Expression& getExpression() const { return *value; } }; diff --git a/include/mbgl/style/conversion/heatmap_color_property_value.hpp b/include/mbgl/style/conversion/color_ramp_property_value.hpp index a4710792d2..290ee6a56c 100644 --- a/include/mbgl/style/conversion/heatmap_color_property_value.hpp +++ b/include/mbgl/style/conversion/color_ramp_property_value.hpp @@ -1,13 +1,11 @@ #pragma once -#include <mbgl/style/heatmap_color_property_value.hpp> +#include <mbgl/style/color_ramp_property_value.hpp> #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/constant.hpp> -#include <mbgl/style/conversion/function.hpp> #include <mbgl/style/expression/value.hpp> #include <mbgl/style/expression/is_constant.hpp> #include <mbgl/style/expression/is_expression.hpp> -#include <mbgl/style/expression/find_zoom_curve.hpp> #include <mbgl/style/expression/parsing_context.hpp> namespace mbgl { @@ -15,11 +13,11 @@ namespace style { namespace conversion { template <> -struct Converter<HeatmapColorPropertyValue> { - optional<HeatmapColorPropertyValue> operator()(const Convertible& value, Error& error) const { +struct Converter<ColorRampPropertyValue> { + optional<ColorRampPropertyValue> operator()(const Convertible& value, Error& error, bool /* convertTokens */ = false) const { using namespace mbgl::style::expression; if (isUndefined(value)) { - return HeatmapColorPropertyValue(); + return ColorRampPropertyValue(); } else if (isExpression(value)) { ParsingContext ctx(type::Color); ParseResult expression = ctx.parseLayerPropertyExpression(value); @@ -36,9 +34,9 @@ struct Converter<HeatmapColorPropertyValue> { error = { "zoom expressions not supported" }; return {}; } - return {HeatmapColorPropertyValue(std::move(*expression))}; + return {ColorRampPropertyValue(std::move(*expression))}; } else { - error = { "heatmap-color must be an expression" }; + error = { "color ramp must be an expression" }; return {}; } } diff --git a/include/mbgl/style/conversion/data_driven_property_value.hpp b/include/mbgl/style/conversion/data_driven_property_value.hpp index 07ed201c99..59d197b216 100644 --- a/include/mbgl/style/conversion/data_driven_property_value.hpp +++ b/include/mbgl/style/conversion/data_driven_property_value.hpp @@ -6,76 +6,71 @@ #include <mbgl/style/conversion/function.hpp> #include <mbgl/style/expression/is_expression.hpp> #include <mbgl/style/expression/is_constant.hpp> -#include <mbgl/style/expression/find_zoom_curve.hpp> #include <mbgl/style/expression/literal.hpp> #include <mbgl/style/expression/value.hpp> #include <mbgl/style/expression/parsing_context.hpp> -#include <unordered_set> - - namespace mbgl { namespace style { namespace conversion { template <class T> struct Converter<DataDrivenPropertyValue<T>> { - - optional<DataDrivenPropertyValue<T>> operator()(const Convertible& value, Error& error) const { + optional<DataDrivenPropertyValue<T>> operator()(const Convertible& value, Error& error, bool convertTokens) const { using namespace mbgl::style::expression; - + if (isUndefined(value)) { return DataDrivenPropertyValue<T>(); - } else if (isExpression(value)) { + } + + optional<PropertyExpression<T>> expression; + + if (isExpression(value)) { ParsingContext ctx(valueTypeToExpressionType<T>()); - ParseResult expression = ctx.parseLayerPropertyExpression(value); - if (!expression) { + ParseResult parsed = ctx.parseLayerPropertyExpression(value); + if (!parsed) { error = { ctx.getCombinedErrors() }; return {}; } - - bool featureConstant = isFeatureConstant(**expression); - bool zoomConstant = isZoomConstant(**expression); - - if (featureConstant && !zoomConstant) { - return DataDrivenPropertyValue<T>(CameraFunction<T>(std::move(*expression))); - } else if (!featureConstant && zoomConstant) { - return DataDrivenPropertyValue<T>(SourceFunction<T>(std::move(*expression))); - } else if (!featureConstant && !zoomConstant) { - return DataDrivenPropertyValue<T>(CompositeFunction<T>(std::move(*expression))); - } else { - auto literal = dynamic_cast<Literal*>(expression->get()); - assert(literal); - optional<T> constant = fromExpressionValue<T>(literal->getValue()); - if (!constant) { - return {}; - } - return DataDrivenPropertyValue<T>(*constant); - } - } else if (!isObject(value)) { + expression = PropertyExpression<T>(std::move(*parsed)); + } else if (isObject(value)) { + expression = convertFunctionToExpression<T>(value, error, convertTokens); + } else { optional<T> constant = convert<T>(value, error); if (!constant) { return {}; } - return DataDrivenPropertyValue<T>(*constant); - } else if (!objectMember(value, "property")) { - optional<CameraFunction<T>> function = convert<CameraFunction<T>>(value, error); - if (!function) { + return convertTokens ? maybeConvertTokens(*constant) : DataDrivenPropertyValue<T>(*constant); + } + + if (!expression) { + return {}; + } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) { + return { std::move(*expression) }; + } else if ((*expression).getExpression().getKind() == Kind::Literal) { + optional<T> constant = fromExpressionValue<T>( + static_cast<const Literal&>((*expression).getExpression()).getValue()); + if (!constant) { return {}; } - return DataDrivenPropertyValue<T>(*function); + return DataDrivenPropertyValue<T>(*constant); } else { - optional<CompositeFunction<T>> composite = convert<CompositeFunction<T>>(value, error); - if (composite) { - return DataDrivenPropertyValue<T>(*composite); - } - optional<SourceFunction<T>> source = convert<SourceFunction<T>>(value, error); - if (!source) { - return {}; - } - return DataDrivenPropertyValue<T>(*source); + assert(false); + error = { "expected a literal expression" }; + return {}; } } + + template <class S> + DataDrivenPropertyValue<T> maybeConvertTokens(const S& t) const { + return DataDrivenPropertyValue<T>(t); + }; + + DataDrivenPropertyValue<T> maybeConvertTokens(const std::string& t) const { + return hasTokens(t) + ? DataDrivenPropertyValue<T>(PropertyExpression<T>(convertTokenStringToExpression(t))) + : DataDrivenPropertyValue<T>(t); + } }; } // namespace conversion diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index e230884944..8799e9faa4 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -1,392 +1,40 @@ #pragma once -#include <mbgl/style/function/camera_function.hpp> -#include <mbgl/style/function/source_function.hpp> -#include <mbgl/style/function/composite_function.hpp> +#include <mbgl/style/property_expression.hpp> #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/constant.hpp> -#include <mbgl/util/ignore.hpp> +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/style/expression/value.hpp> namespace mbgl { namespace style { namespace conversion { -template <class D, class R> -optional<std::map<D, R>> convertStops(const Convertible& value, Error& error) { - auto stopsValue = objectMember(value, "stops"); - if (!stopsValue) { - error = { "function value must specify stops" }; - return {}; - } - - if (!isArray(*stopsValue)) { - error = { "function stops must be an array" }; - return {}; - } - - if (arrayLength(*stopsValue) == 0) { - error = { "function must have at least one stop" }; - return {}; - } - - std::map<D, R> stops; - for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { - const auto& stopValue = arrayMember(*stopsValue, i); - - if (!isArray(stopValue)) { - error = { "function stop must be an array" }; - return {}; - } - - if (arrayLength(stopValue) != 2) { - error = { "function stop must have two elements" }; - return {}; - } - - optional<D> d = convert<D>(arrayMember(stopValue, 0), error); - if (!d) { - return {}; - } - - optional<R> r = convert<R>(arrayMember(stopValue, 1), error); - if (!r) { - return {}; - } +bool hasTokens(const std::string&); +std::unique_ptr<expression::Expression> convertTokenStringToExpression(const std::string&); - stops.emplace(*d, *r); - } - - return stops; -} +optional<std::unique_ptr<expression::Expression>> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens); template <class T> -struct Converter<ExponentialStops<T>> { - static constexpr const char * type = "exponential"; - - optional<ExponentialStops<T>> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops<float, T>(value, error); - if (!stops) { - return {}; - } - - auto baseValue = objectMember(value, "base"); - if (!baseValue) { - return ExponentialStops<T>(*stops); - } - - optional<float> base = toNumber(*baseValue); - if (!base) { - error = { "function base must be a number"}; - return {}; - } - - return ExponentialStops<T>(*stops, *base); - } -}; - -template <class T> -struct Converter<IntervalStops<T>> { - static constexpr const char * type = "interval"; - - optional<IntervalStops<T>> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops<float, T>(value, error); - if (!stops) { - return {}; - } - return IntervalStops<T>(*stops); - } -}; - -template <> -struct Converter<CategoricalValue> { - optional<CategoricalValue> operator()(const Convertible& value, Error& error) const { - auto b = toBool(value); - if (b) { - return { *b }; - } - - auto n = toNumber(value); - if (n) { - return { int64_t(*n) }; - } - - auto s = toString(value); - if (s) { - return { *s }; - } - - error = { "stop domain value must be a number, string, or boolean" }; +optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) { + auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error, convertTokens); + if (!expression) { return {}; } -}; - -template <class T> -struct Converter<CategoricalStops<T>> { - static constexpr const char * type = "categorical"; - - optional<CategoricalStops<T>> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops<CategoricalValue, T>(value, error); - if (!stops) { - return {}; - } - return CategoricalStops<T>( - std::map<CategoricalValue, T>((*stops).begin(), (*stops).end())); - } -}; - -template <class T> -struct Converter<IdentityStops<T>> { - static constexpr const char * type = "identity"; - - optional<IdentityStops<T>> operator()(const Convertible&, Error&) const { - return IdentityStops<T>(); - } -}; - -template <class, class> -struct StopsConverter; - -template <class T, class... Ts> -struct StopsConverter<T, variant<Ts...>> { -public: - optional<variant<Ts...>> operator()(const Convertible& value, Error& error) const { - std::string type = util::Interpolatable<T>::value ? "exponential" : "interval"; - - auto typeValue = objectMember(value, "type"); - if (typeValue && toString(*typeValue)) { - type = *toString(*typeValue); - } - - bool matched = false; - optional<variant<Ts...>> result; - - // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 - auto tryConvert = [&] (auto* tp) { - using Stops = std::decay_t<decltype(*tp)>; - if (type == Converter<Stops>::type) { - matched = true; - optional<Stops> stops = convert<Stops>(value, error); - if (stops) { - result = variant<Ts...>(*stops); - } - } - }; - util::ignore({ - (tryConvert((Ts*)nullptr), 0)... - }); + optional<T> defaultValue; - if (!matched) { - error = { "unsupported function type" }; - return {}; - } - - return result; - } -}; - -template <class T> -struct Converter<CameraFunction<T>> { - optional<CameraFunction<T>> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "function must be an object" }; - return {}; - } - - auto stops = StopsConverter<T, typename CameraFunction<T>::Stops>()(value, error); - if (!stops) { - return {}; - } - - return CameraFunction<T>(*stops); - } -}; - -template <class T> -optional<optional<T>> convertDefaultValue(const Convertible& value, Error& error) { auto defaultValueValue = objectMember(value, "default"); - if (!defaultValueValue) { - return optional<T>(); - } - - auto defaultValue = convert<T>(*defaultValueValue, error); - if (!defaultValue) { - error = { R"(wrong type for "default": )" + error.message }; - return {}; - } - - return { *defaultValue }; -} - -template <class T> -struct Converter<SourceFunction<T>> { - optional<SourceFunction<T>> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "function must be an object" }; - return {}; - } - - auto propertyValue = objectMember(value, "property"); - if (!propertyValue) { - error = { "function must specify property" }; - return {}; - } - - auto propertyString = toString(*propertyValue); - if (!propertyString) { - error = { "function property must be a string" }; - return {}; - } - - auto stops = StopsConverter<T, typename SourceFunction<T>::Stops>()(value, error); - if (!stops) { - return {}; - } - - auto defaultValue = convertDefaultValue<T>(value, error); + if (defaultValueValue) { + defaultValue = convert<T>(*defaultValueValue, error); if (!defaultValue) { + error = { R"(wrong type for "default": )" + error.message }; return {}; } - - return SourceFunction<T>(*propertyString, *stops, *defaultValue); - } -}; - -template <class S> -struct CompositeValue : std::pair<float, S> { - using std::pair<float, S>::pair; -}; - -template <class S> -struct Converter<CompositeValue<S>> { - optional<CompositeValue<S>> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "stop must be an object" }; - return {}; - } - - auto zoomValue = objectMember(value, "zoom"); - if (!zoomValue) { - error = { "stop must specify zoom" }; - return {}; - } - - auto propertyValue = objectMember(value, "value"); - if (!propertyValue) { - error = { "stop must specify value" }; - return {}; - } - - optional<float> z = convert<float>(*zoomValue, error); - if (!z) { - return {}; - } - - optional<S> s = convert<S>(*propertyValue, error); - if (!s) { - return {}; - } - - return CompositeValue<S> { *z, *s }; - } -}; - -template <class T> -struct Converter<CompositeExponentialStops<T>> { - static constexpr const char * type = "exponential"; - - optional<CompositeExponentialStops<T>> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops<CompositeValue<float>, T>(value, error); - if (!stops) { - return {}; - } - - auto base = 1.0f; - auto baseValue = objectMember(value, "base"); - if (baseValue && toNumber(*baseValue)) { - base = *toNumber(*baseValue); - } - - std::map<float, std::map<float, T>> convertedStops; - for (const auto& stop : *stops) { - convertedStops[stop.first.first].emplace(stop.first.second, stop.second); - } - - return CompositeExponentialStops<T>(convertedStops, base); - } -}; - -template <class T> -struct Converter<CompositeIntervalStops<T>> { - static constexpr const char * type = "interval"; - - optional<CompositeIntervalStops<T>> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops<CompositeValue<float>, T>(value, error); - if (!stops) { - return {}; - } - - std::map<float, std::map<float, T>> convertedStops; - for (const auto& stop : *stops) { - convertedStops[stop.first.first].emplace(stop.first.second, stop.second); - } - - return CompositeIntervalStops<T>(convertedStops); } -}; - -template <class T> -struct Converter<CompositeCategoricalStops<T>> { - static constexpr const char * type = "categorical"; - - optional<CompositeCategoricalStops<T>> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value, error); - if (!stops) { - return {}; - } - std::map<float, std::map<CategoricalValue, T>> convertedStops; - for (const auto& stop : *stops) { - convertedStops[stop.first.first].emplace(stop.first.second, stop.second); - } - - return CompositeCategoricalStops<T>(convertedStops); - } -}; - -template <class T> -struct Converter<CompositeFunction<T>> { - optional<CompositeFunction<T>> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "function must be an object" }; - return {}; - } - - auto propertyValue = objectMember(value, "property"); - if (!propertyValue) { - error = { "function must specify property" }; - return {}; - } - - auto propertyString = toString(*propertyValue); - if (!propertyString) { - error = { "function property must be a string" }; - return {}; - } - - auto stops = StopsConverter<T, typename CompositeFunction<T>::Stops>()(value, error); - if (!stops) { - return {}; - } - - auto defaultValue = convertDefaultValue<T>(value, error); - if (!defaultValue) { - return {}; - } - - return CompositeFunction<T>(*propertyString, *stops, *defaultValue); - } -}; + return PropertyExpression<T>(std::move(*expression), defaultValue); +} } // namespace conversion } // namespace style diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index 3130661f61..b03655a848 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -7,8 +7,8 @@ #include <mbgl/style/expression/value.hpp> #include <mbgl/style/expression/is_constant.hpp> #include <mbgl/style/expression/is_expression.hpp> -#include <mbgl/style/expression/find_zoom_curve.hpp> #include <mbgl/style/expression/parsing_context.hpp> +#include <mbgl/style/expression/literal.hpp> namespace mbgl { namespace style { @@ -16,31 +16,29 @@ namespace conversion { template <class T> struct Converter<PropertyValue<T>> { - optional<PropertyValue<T>> operator()(const Convertible& value, Error& error) const { + optional<PropertyValue<T>> operator()(const Convertible& value, Error& error, bool convertTokens = false) const { using namespace mbgl::style::expression; + // Only icon-image and text-field support tokens, and they are both data-driven. + assert(!convertTokens); + (void)convertTokens; + if (isUndefined(value)) { return PropertyValue<T>(); - } else if (isExpression(value)) { + } + + optional<PropertyExpression<T>> expression; + + if (isExpression(value)) { ParsingContext ctx(valueTypeToExpressionType<T>()); - ParseResult expression = ctx.parseLayerPropertyExpression(value); - if (!expression) { + ParseResult parsed = ctx.parseLayerPropertyExpression(value); + if (!parsed) { error = { ctx.getCombinedErrors() }; return {}; } - - if (isFeatureConstant(**expression)) { - return { CameraFunction<T>(std::move(*expression)) }; - } else { - error = { "property expressions not supported" }; - return {}; - } + expression = PropertyExpression<T>(std::move(*parsed)); } else if (isObject(value)) { - optional<CameraFunction<T>> function = convert<CameraFunction<T>>(value, error); - if (!function) { - return {}; - } - return { *function }; + expression = convertFunctionToExpression<T>(value, error, false); } else { optional<T> constant = convert<T>(value, error); if (!constant) { @@ -48,6 +46,26 @@ struct Converter<PropertyValue<T>> { } return { *constant }; } + + if (!expression) { + return {}; + } else if (!(*expression).isFeatureConstant()) { + error = { "data expressions not supported" }; + return {}; + } else if (!(*expression).isZoomConstant()) { + return { std::move(*expression) }; + } else if ((*expression).getExpression().getKind() == Kind::Literal) { + optional<T> constant = fromExpressionValue<T>( + static_cast<const Literal&>((*expression).getExpression()).getValue()); + if (!constant) { + return {}; + } + return PropertyValue<T>(*constant); + } else { + assert(false); + error = { "expected a literal expression" }; + return {}; + } } }; diff --git a/include/mbgl/style/data_driven_property_value.hpp b/include/mbgl/style/data_driven_property_value.hpp index 0a1fce29c7..baea861f62 100644 --- a/include/mbgl/style/data_driven_property_value.hpp +++ b/include/mbgl/style/data_driven_property_value.hpp @@ -2,9 +2,7 @@ #include <mbgl/util/variant.hpp> #include <mbgl/style/undefined.hpp> -#include <mbgl/style/function/camera_function.hpp> -#include <mbgl/style/function/source_function.hpp> -#include <mbgl/style/function/composite_function.hpp> +#include <mbgl/style/property_expression.hpp> namespace mbgl { namespace style { @@ -15,9 +13,7 @@ private: using Value = variant< Undefined, T, - CameraFunction<T>, - SourceFunction<T>, - CompositeFunction<T>>; + PropertyExpression<T>>; Value value; @@ -33,32 +29,32 @@ private: public: DataDrivenPropertyValue() = default; - DataDrivenPropertyValue( T v) : value(std::move(v)) {} - DataDrivenPropertyValue( CameraFunction<T> v) : value(std::move(v)) {} - DataDrivenPropertyValue( SourceFunction<T> v) : value(std::move(v)) {} - DataDrivenPropertyValue(CompositeFunction<T> v) : value(std::move(v)) {} + DataDrivenPropertyValue( T v) : value(std::move(v)) {} + DataDrivenPropertyValue(PropertyExpression<T> v) : value(std::move(v)) {} bool isUndefined() const { return value.template is<Undefined>(); } bool isDataDriven() const { - return value.template is<SourceFunction<T>>() || value.template is<CompositeFunction<T>>(); - } - - bool isZoomConstant() const { - return !value.template is<CameraFunction<T>>() && !value.template is<CompositeFunction<T>>(); + return value.match( + [] (const Undefined&) { return false; }, + [] (const T&) { return false; }, + [] (const PropertyExpression<T>& fn) { return !fn.isFeatureConstant(); } + ); } - bool isExpression() const { + bool isZoomConstant() const { return value.match( - [] (const Undefined&) { return false; }, - [] (const T&) { return false; }, - [] (const CameraFunction<T>& fn) { return fn.isExpression; }, - [] (const SourceFunction<T>& fn) { return fn.isExpression; }, - [] (const CompositeFunction<T>& fn) { return fn.isExpression; }); + [] (const Undefined&) { return true; }, + [] (const T&) { return true; }, + [] (const PropertyExpression<T>& fn) { return fn.isZoomConstant(); } + ); } + const T & asConstant() const { return value.template get< T >(); } + const PropertyExpression<T>& asExpression() const { return value.template get<PropertyExpression<T>>(); } + template <class... Ts> auto match(Ts&&... ts) const { return value.match(std::forward<Ts>(ts)...); diff --git a/include/mbgl/style/expression/array_assertion.hpp b/include/mbgl/style/expression/array_assertion.hpp index af153611ff..0c0912b73e 100644 --- a/include/mbgl/style/expression/array_assertion.hpp +++ b/include/mbgl/style/expression/array_assertion.hpp @@ -14,7 +14,7 @@ namespace expression { class ArrayAssertion : public Expression { public: ArrayAssertion(type::Array type_, std::unique_ptr<Expression> input_) : - Expression(type_), + Expression(Kind::ArrayAssertion, type_), input(std::move(input_)) {} @@ -24,7 +24,8 @@ public: void eachChild(const std::function<void(const Expression&)>& visit) const override; bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const ArrayAssertion*>(&e)) { + if (e.getKind() == Kind::ArrayAssertion) { + auto rhs = static_cast<const ArrayAssertion*>(&e); return getType() == rhs->getType() && *input == *(rhs->input); } return false; diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index d1e919b10f..90da16b068 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -13,10 +13,7 @@ namespace expression { class Assertion : public Expression { public: - Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_) : - Expression(type_), - inputs(std::move(inputs_)) - {} + Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_); static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); diff --git a/include/mbgl/style/expression/at.hpp b/include/mbgl/style/expression/at.hpp index 1e6f1c7dd2..f0dbccb794 100644 --- a/include/mbgl/style/expression/at.hpp +++ b/include/mbgl/style/expression/at.hpp @@ -11,7 +11,7 @@ namespace expression { class At : public Expression { public: At(std::unique_ptr<Expression> index_, std::unique_ptr<Expression> input_) : - Expression(input_->getType().get<type::Array>().itemType), + Expression(Kind::At, input_->getType().get<type::Array>().itemType), index(std::move(index_)), input(std::move(input_)) {} @@ -22,7 +22,8 @@ public: void eachChild(const std::function<void(const Expression&)>&) const override; bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const At*>(&e)) { + if (e.getKind() == Kind::At) { + auto rhs = static_cast<const At*>(&e); return *index == *(rhs->index) && *input == *(rhs->input); } return false; diff --git a/include/mbgl/style/expression/boolean_operator.hpp b/include/mbgl/style/expression/boolean_operator.hpp index 6d0f85756a..d254747513 100644 --- a/include/mbgl/style/expression/boolean_operator.hpp +++ b/include/mbgl/style/expression/boolean_operator.hpp @@ -12,7 +12,7 @@ namespace expression { class Any : public Expression { public: Any(std::vector<std::unique_ptr<Expression>> inputs_) : - Expression(type::Boolean), + Expression(Kind::Any, type::Boolean), inputs(std::move(inputs_)) {} @@ -31,7 +31,7 @@ private: class All : public Expression { public: All(std::vector<std::unique_ptr<Expression>> inputs_) : - Expression(type::Boolean), + Expression(Kind::All, type::Boolean), inputs(std::move(inputs_)) {} diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp index 667ca53712..02dc3bc4c2 100644 --- a/include/mbgl/style/expression/case.hpp +++ b/include/mbgl/style/expression/case.hpp @@ -16,7 +16,7 @@ public: using Branch = std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>; Case(type::Type type_, std::vector<Branch> branches_, std::unique_ptr<Expression> otherwise_) - : Expression(type_), branches(std::move(branches_)), otherwise(std::move(otherwise_)) { + : Expression(Kind::Case, type_), branches(std::move(branches_)), otherwise(std::move(otherwise_)) { } static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp index a858bef695..cd60cee02e 100644 --- a/include/mbgl/style/expression/coalesce.hpp +++ b/include/mbgl/style/expression/coalesce.hpp @@ -15,7 +15,7 @@ class Coalesce : public Expression { public: using Args = std::vector<std::unique_ptr<Expression>>; Coalesce(const type::Type& type_, Args args_) : - Expression(type_), + Expression(Kind::Coalesce, type_), args(std::move(args_)) {} diff --git a/include/mbgl/style/expression/collator.hpp b/include/mbgl/style/expression/collator.hpp new file mode 100644 index 0000000000..2a79e55556 --- /dev/null +++ b/include/mbgl/style/expression/collator.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include <mbgl/util/feature.hpp> +#include <mbgl/util/optional.hpp> + +#include <string> +#include <memory> + +namespace mbgl { +namespace style { +namespace expression { + +class Collator { +public: + Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale = {}); + + bool operator==(const Collator& other) const; + + int compare(const std::string& lhs, const std::string& rhs) const; + + std::string resolvedLocale() const; +private: + class Impl; + std::shared_ptr<Impl> impl; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/collator_expression.hpp b/include/mbgl/style/expression/collator_expression.hpp new file mode 100644 index 0000000000..2551cd19c8 --- /dev/null +++ b/include/mbgl/style/expression/collator_expression.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/style/expression/parsing_context.hpp> +#include <mbgl/style/conversion.hpp> + +#include <memory> + +namespace mbgl { +namespace style { +namespace expression { + +class CollatorExpression : public Expression { +public: + CollatorExpression(std::unique_ptr<Expression> caseSensitive, + std::unique_ptr<Expression> diacriticSensitive, + optional<std::unique_ptr<Expression>> locale); + + EvaluationResult evaluate(const EvaluationContext&) const override; + static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); + + void eachChild(const std::function<void(const Expression&)>&) const override; + + bool operator==(const Expression& e) const override; + + std::vector<optional<Value>> possibleOutputs() const override { + // Technically the set of possible outputs is the combinatoric set of Collators produced + // by all possibleOutputs of locale/caseSensitive/diacriticSensitive + // But for the primary use of Collators in comparison operators, we ignore the Collator's + // possibleOutputs anyway, so we can get away with leaving this undefined for now. + return { nullopt }; + } + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "collator"; } +private: + std::unique_ptr<Expression> caseSensitive; + std::unique_ptr<Expression> diacriticSensitive; + optional<std::unique_ptr<Expression>> locale; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index 6baaae862f..c618f2f206 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -33,10 +33,13 @@ namespace expression { */ struct VarargsType { type::Type type; }; template <typename T> -struct Varargs : std::vector<T> { using std::vector<T>::vector; }; +struct Varargs : std::vector<T> { + template <class... Args> + Varargs(Args&&... args) : std::vector<T>(std::forward<Args>(args)...) {} +}; namespace detail { -// Base class for the Signature<Fn> structs that are used to determine the +// Base class for the Signature<Fn> structs that are used to determine // each CompoundExpression definition's type::Type data from the type of its // "evaluate" function. struct SignatureBase { @@ -62,7 +65,7 @@ struct SignatureBase { class CompoundExpressionBase : public Expression { public: CompoundExpressionBase(std::string name_, const detail::SignatureBase& signature) : - Expression(signature.result), + Expression(Kind::CompoundExpression, signature.result), name(std::move(name_)), params(signature.params) {} @@ -108,7 +111,8 @@ public: } bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const CompoundExpression*>(&e)) { + if (e.getKind() == Kind::CompoundExpression) { + auto rhs = static_cast<const CompoundExpression*>(&e); return getName() == rhs->getName() && Expression::childrenEqual(args, rhs->args); } return false; @@ -134,10 +138,6 @@ struct CompoundExpressionRegistry { ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); -ParseResult createCompoundExpression(const CompoundExpressionRegistry::Definition& definition, - std::vector<std::unique_ptr<Expression>> args, - ParsingContext& ctx); - ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx); diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp new file mode 100644 index 0000000000..e9de20de18 --- /dev/null +++ b/include/mbgl/style/expression/dsl.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include <mbgl/style/expression/value.hpp> +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/style/expression/interpolator.hpp> +#include <mbgl/util/ignore.hpp> + +#include <memory> +#include <string> +#include <initializer_list> + +namespace mbgl { +namespace style { +namespace expression { +namespace dsl { + +// This convenience API does little to no expression validation or type-checking, and is intended for +// use only by test and other non-production code. + +template <class... Args> +std::vector<std::unique_ptr<Expression>> vec(Args... args) { + std::vector<std::unique_ptr<Expression>> result; + util::ignore({ (result.push_back(std::move(args)), 0)... }); + return result; +} + +std::unique_ptr<Expression> error(std::string); + +std::unique_ptr<Expression> literal(const char* value); +std::unique_ptr<Expression> literal(Value value); +std::unique_ptr<Expression> literal(std::initializer_list<double> value); +std::unique_ptr<Expression> literal(std::initializer_list<const char *> value); + +std::unique_ptr<Expression> number(std::unique_ptr<Expression>); +std::unique_ptr<Expression> string(std::unique_ptr<Expression>); +std::unique_ptr<Expression> boolean(std::unique_ptr<Expression>); + +std::unique_ptr<Expression> toColor(std::unique_ptr<Expression>); +std::unique_ptr<Expression> toString(std::unique_ptr<Expression>); + +std::unique_ptr<Expression> get(const char* value); +std::unique_ptr<Expression> get(std::unique_ptr<Expression>); + +std::unique_ptr<Expression> id(); +std::unique_ptr<Expression> zoom(); + +std::unique_ptr<Expression> eq(std::unique_ptr<Expression>, + std::unique_ptr<Expression>); +std::unique_ptr<Expression> ne(std::unique_ptr<Expression>, + std::unique_ptr<Expression>); +std::unique_ptr<Expression> gt(std::unique_ptr<Expression>, + std::unique_ptr<Expression>); +std::unique_ptr<Expression> lt(std::unique_ptr<Expression>, + std::unique_ptr<Expression>); + +std::unique_ptr<Expression> step(std::unique_ptr<Expression> input, + std::unique_ptr<Expression> output0, + double input1, std::unique_ptr<Expression> output1); + +Interpolator linear(); +Interpolator exponential(double base); +Interpolator cubicBezier(double x1, double y1, double x2, double y2); + +std::unique_ptr<Expression> interpolate(Interpolator interpolator, + std::unique_ptr<Expression> input, + double input1, std::unique_ptr<Expression> output1); + +std::unique_ptr<Expression> interpolate(Interpolator interpolator, + std::unique_ptr<Expression> input, + double input1, std::unique_ptr<Expression> output1, + double input2, std::unique_ptr<Expression> output2); + +std::unique_ptr<Expression> interpolate(Interpolator interpolator, + std::unique_ptr<Expression> input, + double input1, std::unique_ptr<Expression> output1, + double input2, std::unique_ptr<Expression> output2, + double input3, std::unique_ptr<Expression> output3); + +std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inputs); + +} // namespace dsl +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/equals.hpp b/include/mbgl/style/expression/equals.hpp index 54df890a68..1e8bf7acef 100644 --- a/include/mbgl/style/expression/equals.hpp +++ b/include/mbgl/style/expression/equals.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mbgl/style/expression/collator_expression.hpp> #include <mbgl/style/expression/expression.hpp> #include <mbgl/style/expression/parsing_context.hpp> #include <mbgl/style/conversion.hpp> @@ -12,7 +13,7 @@ namespace expression { class Equals : public Expression { public: - Equals(std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs, bool negate); + Equals(std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs, optional<std::unique_ptr<Expression>> collator, bool negate); static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); @@ -25,6 +26,7 @@ public: private: std::unique_ptr<Expression> lhs; std::unique_ptr<Expression> rhs; + optional<std::unique_ptr<Expression>> collator; bool negate; }; diff --git a/include/mbgl/style/expression/error.hpp b/include/mbgl/style/expression/error.hpp new file mode 100644 index 0000000000..9e1da2f0f0 --- /dev/null +++ b/include/mbgl/style/expression/error.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <mbgl/style/expression/expression.hpp> + +#include <string> + +namespace mbgl { +namespace style { +namespace expression { + +class Error : public Expression { +public: + Error(std::string message_) + : Expression(Kind::Error, type::Error), + message(std::move(message_)) {} + + void eachChild(const std::function<void(const Expression&)>&) const override {} + + bool operator==(const Expression& e) const override { + return e.getKind() == Kind::Error; + } + + EvaluationResult evaluate(const EvaluationContext&) const override { + return EvaluationError{message}; + } + + std::vector<optional<Value>> possibleOutputs() const override { + return {}; + } + + std::string getOperator() const override { return "error"; } + +private: + std::string message; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index c41ac0b5f1..8301f1572c 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -113,9 +113,32 @@ public: ParseResult ExpressionClass::parse(const V&, ParsingContext), which handles parsing a style-spec JSON representation of the expression. */ + +enum class Kind : int32_t { + Coalesce, + CompoundExpression, + Literal, + ArrayAssertion, + At, + Interpolate, + Assertion, + Length, + Step, + Let, + Var, + CollatorExpression, + Coercion, + Match, + Error, + Case, + Any, + All, + Equals, +}; + class Expression { public: - Expression(type::Type type_) : type(std::move(type_)) {} + Expression(Kind kind_, type::Type type_) : kind(kind_), type(std::move(type_)) {} virtual ~Expression() = default; virtual EvaluationResult evaluate(const EvaluationContext& params) const = 0; @@ -125,6 +148,7 @@ public: return !operator==(rhs); } + Kind getKind() const { return kind; }; type::Type getType() const { return type; }; EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> heatmapDensity) const; @@ -182,6 +206,7 @@ protected: } private: + Kind kind; type::Type type; }; diff --git a/include/mbgl/style/expression/find_zoom_curve.hpp b/include/mbgl/style/expression/find_zoom_curve.hpp index 6301938033..6f1419a69f 100644 --- a/include/mbgl/style/expression/find_zoom_curve.hpp +++ b/include/mbgl/style/expression/find_zoom_curve.hpp @@ -11,9 +11,9 @@ namespace mbgl { namespace style { namespace expression { -optional<variant<const InterpolateBase*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e); +optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e); -variant<const InterpolateBase*, const Step*> findZoomCurveChecked(const expression::Expression* e); +variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression* e); } // namespace expression } // namespace style diff --git a/include/mbgl/style/expression/interpolate.hpp b/include/mbgl/style/expression/interpolate.hpp index cc744ac7b7..0e78504719 100644 --- a/include/mbgl/style/expression/interpolate.hpp +++ b/include/mbgl/style/expression/interpolate.hpp @@ -3,12 +3,9 @@ #include <mbgl/style/expression/expression.hpp> #include <mbgl/style/expression/parsing_context.hpp> #include <mbgl/style/expression/get_covering_stops.hpp> +#include <mbgl/style/expression/interpolator.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/interpolate.hpp> -#include <mbgl/util/range.hpp> -#include <mbgl/util/unitbezier.hpp> - #include <memory> #include <map> #include <cmath> @@ -17,57 +14,14 @@ namespace mbgl { namespace style { namespace expression { -class ExponentialInterpolator { -public: - ExponentialInterpolator(double base_) : base(base_) {} - - double base; - - double interpolationFactor(const Range<double>& inputLevels, const double input) const { - return util::interpolationFactor(base, - Range<float> { - static_cast<float>(inputLevels.min), - static_cast<float>(inputLevels.max) - }, - input); - } - - bool operator==(const ExponentialInterpolator& rhs) const { - return base == rhs.base; - } -}; - -class CubicBezierInterpolator { -public: - CubicBezierInterpolator(double x1_, double y1_, double x2_, double y2_) : ub(x1_, y1_, x2_, y2_) {} - - double interpolationFactor(const Range<double>& inputLevels, const double input) const { - return ub.solve(input / (inputLevels.max - inputLevels.min), 1e-6); - } - - bool operator==(const CubicBezierInterpolator& rhs) const { - return ub == rhs.ub; - } - - util::UnitBezier ub; -}; - - ParseResult parseInterpolate(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); -class InterpolateBase : public Expression { +class Interpolate : public Expression { public: - using Interpolator = variant<ExponentialInterpolator, CubicBezierInterpolator>; - - InterpolateBase(const type::Type& type_, - Interpolator interpolator_, - std::unique_ptr<Expression> input_, - std::map<double, std::unique_ptr<Expression>> stops_ - ) : Expression(type_), - interpolator(std::move(interpolator_)), - input(std::move(input_)), - stops(std::move(stops_)) - {} + Interpolate(const type::Type& type_, + Interpolator interpolator_, + std::unique_ptr<Expression> input_, + std::map<double, std::unique_ptr<Expression>> stops_); const std::unique_ptr<Expression>& getInput() const { return input; } const Interpolator& getInterpolator() const { return interpolator; } @@ -96,100 +50,37 @@ public: ); } - std::vector<optional<Value>> possibleOutputs() const override; - -protected: - const Interpolator interpolator; - const std::unique_ptr<Expression> input; - const std::map<double, std::unique_ptr<Expression>> stops; -}; - -template <typename T> -class Interpolate : public InterpolateBase { -public: - Interpolate(type::Type type_, - Interpolator interpolator_, - std::unique_ptr<Expression> input_, - std::map<double, std::unique_ptr<Expression>> stops_ - ) : InterpolateBase(std::move(type_), std::move(interpolator_), std::move(input_), std::move(stops_)) - { - static_assert(util::Interpolatable<T>::value, "Interpolate expression requires an interpolatable value type."); - } - - EvaluationResult evaluate(const EvaluationContext& params) const override { - const EvaluationResult evaluatedInput = input->evaluate(params); - if (!evaluatedInput) { - return evaluatedInput.error(); - } - - float x = *fromExpressionValue<float>(*evaluatedInput); - if (std::isnan(x)) { - return EvaluationError { "Input is not a number." }; - } - - if (stops.empty()) { - return EvaluationError { "No stops in exponential curve." }; - } - - auto it = stops.upper_bound(x); - if (it == stops.end()) { - return stops.rbegin()->second->evaluate(params); - } else if (it == stops.begin()) { - return stops.begin()->second->evaluate(params); - } else { - float t = interpolationFactor({ std::prev(it)->first, it->first }, x); - - if (t == 0.0f) { - return std::prev(it)->second->evaluate(params); - } - if (t == 1.0f) { - return it->second->evaluate(params); - } - - EvaluationResult lower = std::prev(it)->second->evaluate(params); - if (!lower) { - return lower.error(); - } - EvaluationResult upper = it->second->evaluate(params); - if (!upper) { - return upper.error(); - } - - if (!lower->is<T>()) { - return EvaluationError { - "Expected value to be of type " + toString(valueTypeToExpressionType<T>()) + - ", but found " + toString(typeOf(*lower)) + " instead." - }; - } - - if (!upper->is<T>()) { - return EvaluationError { - "Expected value to be of type " + toString(valueTypeToExpressionType<T>()) + - ", but found " + toString(typeOf(*upper)) + " instead." - }; - } - return util::interpolate(lower->get<T>(), upper->get<T>(), t); - } - } - bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const Interpolate*>(&e)) { + if (e.getKind() == Kind::Interpolate) { + auto rhs = static_cast<const Interpolate*>(&e); if (interpolator != rhs->interpolator || *input != *(rhs->input) || stops.size() != rhs->stops.size()) { return false; } - + return Expression::childrenEqual(stops, rhs->stops); } return false; } - + + std::vector<optional<Value>> possibleOutputs() const override; mbgl::Value serialize() const override; std::string getOperator() const override { return "interpolate"; } + +protected: + const Interpolator interpolator; + const std::unique_ptr<Expression> input; + const std::map<double, std::unique_ptr<Expression>> stops; }; +ParseResult createInterpolate(type::Type type, + Interpolator interpolator, + std::unique_ptr<Expression> input, + std::map<double, std::unique_ptr<Expression>> stops, + ParsingContext& ctx); + } // namespace expression } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/expression/interpolator.hpp b/include/mbgl/style/expression/interpolator.hpp new file mode 100644 index 0000000000..f37fb2c9cd --- /dev/null +++ b/include/mbgl/style/expression/interpolator.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include <mbgl/util/interpolate.hpp> +#include <mbgl/util/range.hpp> +#include <mbgl/util/unitbezier.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +class ExponentialInterpolator { +public: + ExponentialInterpolator(double base_) : base(base_) {} + + double base; + + double interpolationFactor(const Range<double>& inputLevels, const double input) const { + return util::interpolationFactor(base, + Range<float> { + static_cast<float>(inputLevels.min), + static_cast<float>(inputLevels.max) + }, + input); + } + + bool operator==(const ExponentialInterpolator& rhs) const { + return base == rhs.base; + } +}; + +class CubicBezierInterpolator { +public: + CubicBezierInterpolator(double x1_, double y1_, double x2_, double y2_) : ub(x1_, y1_, x2_, y2_) {} + + double interpolationFactor(const Range<double>& inputLevels, const double input) const { + return ub.solve(input / (inputLevels.max - inputLevels.min), 1e-6); + } + + bool operator==(const CubicBezierInterpolator& rhs) const { + return ub == rhs.ub; + } + + util::UnitBezier ub; +}; + +using Interpolator = variant<ExponentialInterpolator, CubicBezierInterpolator>; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/is_constant.hpp b/include/mbgl/style/expression/is_constant.hpp index 29e03ccbc0..065fa30db1 100644 --- a/include/mbgl/style/expression/is_constant.hpp +++ b/include/mbgl/style/expression/is_constant.hpp @@ -9,7 +9,8 @@ namespace expression { template <typename T> bool isGlobalPropertyConstant(const Expression& expression, const T& properties) { - if (auto e = dynamic_cast<const CompoundExpressionBase*>(&expression)) { + if (expression.getKind() == Kind::CompoundExpression) { + auto e = static_cast<const CompoundExpressionBase*>(&expression); for (const std::string& property : properties) { if (e->getName() == property) { return false; diff --git a/include/mbgl/style/expression/let.hpp b/include/mbgl/style/expression/let.hpp index d0210d8bba..d11ba1b976 100644 --- a/include/mbgl/style/expression/let.hpp +++ b/include/mbgl/style/expression/let.hpp @@ -16,7 +16,7 @@ public: using Bindings = std::map<std::string, std::shared_ptr<Expression>>; Let(Bindings bindings_, std::unique_ptr<Expression> result_) : - Expression(result_->getType()), + Expression(Kind::Let, result_->getType()), bindings(std::move(bindings_)), result(std::move(result_)) {} @@ -27,7 +27,8 @@ public: void eachChild(const std::function<void(const Expression&)>&) const override; bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const Let*>(&e)) { + if (e.getKind() == Kind::Let) { + auto rhs = static_cast<const Let*>(&e); return *result == *(rhs->result); } return false; @@ -49,7 +50,7 @@ private: class Var : public Expression { public: Var(std::string name_, std::shared_ptr<Expression> value_) : - Expression(value_->getType()), + Expression(Kind::Var, value_->getType()), name(std::move(name_)), value(value_) {} @@ -60,7 +61,8 @@ public: void eachChild(const std::function<void(const Expression&)>&) const override; bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const Var*>(&e)) { + if (e.getKind() == Kind::Var) { + auto rhs = static_cast<const Var*>(&e); return *value == *(rhs->value); } return false; diff --git a/include/mbgl/style/expression/literal.hpp b/include/mbgl/style/expression/literal.hpp index a00c468efc..bcae23b1fa 100644 --- a/include/mbgl/style/expression/literal.hpp +++ b/include/mbgl/style/expression/literal.hpp @@ -13,12 +13,12 @@ namespace expression { class Literal : public Expression { public: Literal(Value value_) - : Expression(typeOf(value_)) + : Expression(Kind::Literal, typeOf(value_)) , value(value_) {} Literal(type::Array type_, std::vector<Value> value_) - : Expression(type_) + : Expression(Kind::Literal, type_) , value(value_) {} @@ -31,7 +31,8 @@ public: void eachChild(const std::function<void(const Expression&)>&) const override {} bool operator==(const Expression& e) const override { - if (auto rhs = dynamic_cast<const Literal*>(&e)) { + if (e.getKind() == Kind::Literal) { + auto rhs = static_cast<const Literal*>(&e); return value == rhs->value; } return false; @@ -47,6 +48,7 @@ public: mbgl::Value serialize() const override; std::string getOperator() const override { return "literal"; } + private: Value value; }; diff --git a/include/mbgl/style/expression/match.hpp b/include/mbgl/style/expression/match.hpp index 3775e38067..2ce4b7a533 100644 --- a/include/mbgl/style/expression/match.hpp +++ b/include/mbgl/style/expression/match.hpp @@ -19,7 +19,7 @@ public: std::unique_ptr<Expression> input_, Branches branches_, std::unique_ptr<Expression> otherwise_ - ) : Expression(type_), + ) : Expression(Kind::Match, type_), input(std::move(input_)), branches(std::move(branches_)), otherwise(std::move(otherwise_)) diff --git a/include/mbgl/style/expression/step.hpp b/include/mbgl/style/expression/step.hpp index 2f9524a53c..24e29b1a4e 100644 --- a/include/mbgl/style/expression/step.hpp +++ b/include/mbgl/style/expression/step.hpp @@ -1,4 +1,3 @@ - #pragma once #include <mbgl/style/expression/expression.hpp> @@ -10,7 +9,6 @@ #include <memory> #include <map> - namespace mbgl { namespace style { namespace expression { @@ -18,12 +16,8 @@ namespace expression { class Step : public Expression { public: Step(const type::Type& type_, - std::unique_ptr<Expression> input_, - std::map<double, std::unique_ptr<Expression>> stops_ - ) : Expression(type_), - input(std::move(input_)), - stops(std::move(stops_)) - {} + std::unique_ptr<Expression> input_, + std::map<double, std::unique_ptr<Expression>> stops_); EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function<void(const Expression&)>& visit) const override; @@ -40,6 +34,7 @@ public: mbgl::Value serialize() const override; std::string getOperator() const override { return "step"; } + private: const std::unique_ptr<Expression> input; const std::map<double, std::unique_ptr<Expression>> stops; diff --git a/include/mbgl/style/expression/type.hpp b/include/mbgl/style/expression/type.hpp index 513c4bdc17..316496839b 100644 --- a/include/mbgl/style/expression/type.hpp +++ b/include/mbgl/style/expression/type.hpp @@ -60,6 +60,12 @@ struct ValueType { std::string getName() const { return "value"; } bool operator==(const ValueType&) const { return true; } }; + +struct CollatorType { + constexpr CollatorType() {}; // NOLINT + std::string getName() const { return "collator"; } + bool operator==(const CollatorType&) const { return true; } +}; constexpr NullType Null; constexpr NumberType Number; @@ -68,6 +74,7 @@ constexpr BooleanType Boolean; constexpr ColorType Color; constexpr ValueType Value; constexpr ObjectType Object; +constexpr CollatorType Collator; constexpr ErrorType Error; struct Array; @@ -81,6 +88,7 @@ using Type = variant< ObjectType, ValueType, mapbox::util::recursive_wrapper<Array>, + CollatorType, ErrorType>; struct Array { diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index 7839ff2ca7..b1126118a9 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mbgl/style/expression/collator.hpp> #include <mbgl/style/expression/type.hpp> #include <mbgl/style/position.hpp> #include <mbgl/style/types.hpp> @@ -23,6 +24,7 @@ using ValueBase = variant< double, std::string, Color, + Collator, mapbox::util::recursive_wrapper<std::vector<Value>>, mapbox::util::recursive_wrapper<std::unordered_map<std::string, Value>>>; struct Value : ValueBase { @@ -58,64 +60,39 @@ type::Type valueTypeToExpressionType(); Conversions between style value types and expression::Value */ -// no-op overloads -Value toExpressionValue(const Value&); - -// T = Value (just wrap in optional) -template <typename T> -std::enable_if_t<std::is_same<T, Value>::value, -optional<T>> fromExpressionValue(const Value& v) -{ - return optional<T>(v); -} - -// T = member type of Value -template <typename T> -std::enable_if_t< std::is_convertible<T, Value>::value && !std::is_same<T, Value>::value, -optional<T>> fromExpressionValue(const Value& v) -{ - return v.template is<T>() ? v.template get<T>() : optional<T>(); -} - -// real conversions -template <typename T, typename Enable = std::enable_if_t< !std::is_convertible<T, Value>::value >> -Value toExpressionValue(const T& value); - -template <typename T> -std::enable_if_t< !std::is_convertible<T, Value>::value, -optional<T>> fromExpressionValue(const Value& v); - - - template <class T, class Enable = void> struct ValueConverter { - using ExpressionType = T; - static Value toExpressionValue(const T& value) { return Value(value); } + static optional<T> fromExpressionValue(const Value& value) { return value.template is<T>() ? value.template get<T>() : optional<T>(); } }; template <> -struct ValueConverter<float> { - using ExpressionType = double; - static type::Type expressionType() { return type::Number; } - static Value toExpressionValue(const float value); - static optional<float> fromExpressionValue(const Value& value); +struct ValueConverter<Value> { + static type::Type expressionType() { return type::Value; } + static Value toExpressionValue(const Value& value) { return value; } + static optional<Value> fromExpressionValue(const Value& value) { return value; } }; -template<> +template <> struct ValueConverter<mbgl::Value> { static Value toExpressionValue(const mbgl::Value& value); static mbgl::Value fromExpressionValue(const Value& value); }; +template <> +struct ValueConverter<float> { + static type::Type expressionType() { return type::Number; } + static Value toExpressionValue(const float value); + static optional<float> fromExpressionValue(const Value& value); +}; + template <typename T, std::size_t N> struct ValueConverter<std::array<T, N>> { - using ExpressionType = std::vector<Value>; static type::Type expressionType() { return type::Array(valueTypeToExpressionType<T>(), N); } @@ -125,7 +102,6 @@ struct ValueConverter<std::array<T, N>> { template <typename T> struct ValueConverter<std::vector<T>> { - using ExpressionType = std::vector<Value>; static type::Type expressionType() { return type::Array(valueTypeToExpressionType<T>()); } @@ -135,7 +111,6 @@ struct ValueConverter<std::vector<T>> { template <> struct ValueConverter<Position> { - using ExpressionType = std::vector<Value>; static type::Type expressionType() { return type::Array(type::Number, 3); } static Value toExpressionValue(const mbgl::style::Position& value); static optional<Position> fromExpressionValue(const Value& v); @@ -143,13 +118,22 @@ struct ValueConverter<Position> { template <typename T> struct ValueConverter<T, std::enable_if_t< std::is_enum<T>::value >> { - using ExpressionType = std::string; static type::Type expressionType() { return type::String; } static Value toExpressionValue(const T& value); static optional<T> fromExpressionValue(const Value& value); }; template <typename T> +Value toExpressionValue(const T& value) { + return ValueConverter<T>::toExpressionValue(value); +} + +template <typename T> +optional<T> fromExpressionValue(const Value& value) { + return ValueConverter<T>::fromExpressionValue(value); +} + +template <typename T> std::vector<optional<T>> fromExpressionValues(const std::vector<optional<Value>>& values) { std::vector<optional<T>> result; for (const auto& value : values) { diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp index ccf8dce188..c9dc9fb1ec 100644 --- a/include/mbgl/style/filter.hpp +++ b/include/mbgl/style/filter.hpp @@ -12,270 +12,44 @@ namespace mbgl { namespace style { -class Filter; - -class NullFilter { -public: - friend bool operator==(const NullFilter&, const NullFilter&) { - return true; - } -}; - -class EqualsFilter { -public: - std::string key; - Value value; - - friend bool operator==(const EqualsFilter& lhs, const EqualsFilter& rhs) { - return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value); - } -}; - -class NotEqualsFilter { -public: - std::string key; - Value value; - - friend bool operator==(const NotEqualsFilter& lhs, const NotEqualsFilter& rhs) { - return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value); - } -}; - -class LessThanFilter { -public: - std::string key; - Value value; - - friend bool operator==(const LessThanFilter& lhs, const LessThanFilter& rhs) { - return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value); - } -}; - -class LessThanEqualsFilter { -public: - std::string key; - Value value; - - friend bool operator==(const LessThanEqualsFilter& lhs, const LessThanEqualsFilter& rhs) { - return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value); - } -}; - -class GreaterThanFilter { +class Filter { public: - std::string key; - Value value; - - friend bool operator==(const GreaterThanFilter& lhs, const GreaterThanFilter& rhs) { - return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value); - } -}; - -class GreaterThanEqualsFilter { + optional<std::shared_ptr<const expression::Expression>> expression; +private: + optional<mbgl::Value> legacyFilter; public: - std::string key; - Value value; - - friend bool operator==(const GreaterThanEqualsFilter& lhs, const GreaterThanEqualsFilter& rhs) { - return std::tie(lhs.key, lhs.value) == std::tie(rhs.key, rhs.value); - } -}; - -class InFilter { -public: - std::string key; - std::vector<Value> values; - - friend bool operator==(const InFilter& lhs, const InFilter& rhs) { - return std::tie(lhs.key, lhs.values) == std::tie(rhs.key, rhs.values); - } -}; - -class NotInFilter { -public: - std::string key; - std::vector<Value> values; - - friend bool operator==(const NotInFilter& lhs, const NotInFilter& rhs) { - return std::tie(lhs.key, lhs.values) == std::tie(rhs.key, rhs.values); - } -}; - -class AnyFilter { -public: - std::vector<Filter> filters; - - friend bool operator==(const AnyFilter& lhs, const AnyFilter& rhs) { - return lhs.filters == rhs.filters; - } -}; - -class AllFilter { -public: - std::vector<Filter> filters; - - friend bool operator==(const AllFilter& lhs, const AllFilter& rhs) { - return lhs.filters == rhs.filters; - } -}; - -class NoneFilter { -public: - std::vector<Filter> filters; - - friend bool operator==(const NoneFilter& lhs, const NoneFilter& rhs) { - return lhs.filters == rhs.filters; - } -}; - -class HasFilter { -public: - std::string key; - - friend bool operator==(const HasFilter& lhs, const HasFilter& rhs) { - return lhs.key == rhs.key; - } -}; - -class NotHasFilter { -public: - std::string key; - - friend bool operator==(const NotHasFilter& lhs, const NotHasFilter& rhs) { - return lhs.key == rhs.key; - } -}; - - -class TypeEqualsFilter { -public: - FeatureType value; - - friend bool operator==(const TypeEqualsFilter& lhs, const TypeEqualsFilter& rhs) { - return lhs.value == rhs.value; - } -}; - -class TypeNotEqualsFilter { -public: - FeatureType value; - - friend bool operator==(const TypeNotEqualsFilter& lhs, const TypeNotEqualsFilter& rhs) { - return lhs.value == rhs.value; - } -}; - -class TypeInFilter { -public: - std::vector<FeatureType> values; - - friend bool operator==(const TypeInFilter& lhs, const TypeInFilter& rhs) { - return lhs.values == rhs.values; - } -}; - -class TypeNotInFilter { -public: - std::vector<FeatureType> values; - - friend bool operator==(const TypeNotInFilter& lhs, const TypeNotInFilter& rhs) { - return lhs.values == rhs.values; - } -}; - - -class IdentifierEqualsFilter { -public: - FeatureIdentifier value; - - friend bool operator==(const IdentifierEqualsFilter& lhs, const IdentifierEqualsFilter& rhs) { - return lhs.value == rhs.value; - } -}; - -class IdentifierNotEqualsFilter { -public: - FeatureIdentifier value; - - friend bool operator==(const IdentifierNotEqualsFilter& lhs, const IdentifierNotEqualsFilter& rhs) { - return lhs.value == rhs.value; - } -}; - -class IdentifierInFilter { -public: - std::vector<FeatureIdentifier> values; - - friend bool operator==(const IdentifierInFilter& lhs, const IdentifierInFilter& rhs) { - return lhs.values == rhs.values; - } -}; - -class IdentifierNotInFilter { -public: - std::vector<FeatureIdentifier> values; - - friend bool operator==(const IdentifierNotInFilter& lhs, const IdentifierNotInFilter& rhs) { - return lhs.values == rhs.values; - } -}; - -class HasIdentifierFilter { -public: - friend bool operator==(const HasIdentifierFilter&, const HasIdentifierFilter&) { - return true; + Filter() : expression() {} + + Filter(expression::ParseResult _expression, optional<mbgl::Value> _filter = {}) + : expression(std::move(*_expression)), + legacyFilter(std::move(_filter)){ + assert(!expression || *expression != nullptr); } -}; + + bool operator()(const expression::EvaluationContext& context) const; -class NotHasIdentifierFilter { -public: - friend bool operator==(const NotHasIdentifierFilter&, const NotHasIdentifierFilter&) { - return true; + friend bool operator==(const Filter& lhs, const Filter& rhs) { + if (!lhs.expression || !rhs.expression) { + return lhs.expression == rhs.expression; + } else { + return *(lhs.expression) == *(rhs.expression); + } } -}; -class ExpressionFilter { -public: - std::shared_ptr<const expression::Expression> expression; + friend bool operator!=(const Filter& lhs, const Filter& rhs) { + return !(lhs == rhs); + } - friend bool operator==(const ExpressionFilter& lhs, const ExpressionFilter& rhs) { - return *(lhs.expression) == *(rhs.expression); + mbgl::Value serialize() const { + if (legacyFilter) { + return *legacyFilter; + } + else if (expression) { + return (**expression).serialize(); + } + return NullValue(); } }; - -using FilterBase = variant< - class NullFilter, - class EqualsFilter, - class NotEqualsFilter, - class LessThanFilter, - class LessThanEqualsFilter, - class GreaterThanFilter, - class GreaterThanEqualsFilter, - class InFilter, - class NotInFilter, - class AnyFilter, - class AllFilter, - class NoneFilter, - class HasFilter, - class NotHasFilter, - class TypeEqualsFilter, - class TypeNotEqualsFilter, - class TypeInFilter, - class TypeNotInFilter, - class IdentifierEqualsFilter, - class IdentifierNotEqualsFilter, - class IdentifierInFilter, - class IdentifierNotInFilter, - class HasIdentifierFilter, - class NotHasIdentifierFilter, - class ExpressionFilter>; - -class Filter : public FilterBase { -public: - using FilterBase::FilterBase; - bool operator()(const expression::EvaluationContext& context) const; -}; - } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp deleted file mode 100644 index a4a4098b3f..0000000000 --- a/include/mbgl/style/filter_evaluator.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include <mbgl/style/filter.hpp> -#include <mbgl/util/geometry.hpp> - -#include <type_traits> - -namespace mbgl { -namespace style { - -/* - A visitor that evaluates a `Filter` for a given feature. - - Use via `Filter::operator()`. For example: - - if (filter(feature)) { - // matches the filter - } else { - // does not match - } -*/ -class FilterEvaluator { -public: - const expression::EvaluationContext context; - - bool operator()(const NullFilter&) const; - bool operator()(const EqualsFilter& filter) const; - bool operator()(const NotEqualsFilter& filter) const; - bool operator()(const LessThanFilter& filter) const; - bool operator()(const LessThanEqualsFilter& filter) const; - bool operator()(const GreaterThanFilter& filter) const; - bool operator()(const GreaterThanEqualsFilter& filter) const; - bool operator()(const InFilter& filter) const; - bool operator()(const NotInFilter& filter) const; - bool operator()(const AnyFilter& filter) const; - bool operator()(const AllFilter& filter) const; - bool operator()(const NoneFilter& filter) const; - bool operator()(const HasFilter& filter) const; - bool operator()(const NotHasFilter& filter) const; - bool operator()(const TypeEqualsFilter& filter) const; - bool operator()(const TypeNotEqualsFilter& filter) const; - bool operator()(const TypeInFilter& filter) const; - bool operator()(const TypeNotInFilter& filter) const; - bool operator()(const IdentifierEqualsFilter& filter) const; - bool operator()(const IdentifierNotEqualsFilter& filter) const; - bool operator()(const IdentifierInFilter& filter) const; - bool operator()(const IdentifierNotInFilter& filter) const; - bool operator()(const HasIdentifierFilter&) const; - bool operator()(const NotHasIdentifierFilter&) const; - bool operator()(const ExpressionFilter&) const; - -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp deleted file mode 100644 index 97ba633e44..0000000000 --- a/include/mbgl/style/function/camera_function.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include <mbgl/style/expression/expression.hpp> -#include <mbgl/style/expression/interpolate.hpp> -#include <mbgl/style/expression/step.hpp> -#include <mbgl/style/expression/find_zoom_curve.hpp> -#include <mbgl/style/expression/value.hpp> -#include <mbgl/style/expression/is_constant.hpp> -#include <mbgl/style/function/convert.hpp> -#include <mbgl/style/function/exponential_stops.hpp> -#include <mbgl/style/function/interval_stops.hpp> -#include <mbgl/util/interpolate.hpp> -#include <mbgl/util/variant.hpp> - -namespace mbgl { -namespace style { - -template <class T> -class CameraFunction { -public: - using Stops = std::conditional_t< - util::Interpolatable<T>::value, - variant< - ExponentialStops<T>, - IntervalStops<T>>, - variant< - IntervalStops<T>>>; - - CameraFunction(std::unique_ptr<expression::Expression> expression_) - : isExpression(true), - expression(std::move(expression_)), - zoomCurve(expression::findZoomCurveChecked(expression.get())) - { - assert(!expression::isZoomConstant(*expression)); - assert(expression::isFeatureConstant(*expression)); - } - - CameraFunction(const Stops& stops) - : isExpression(false), - expression(stops.match([&] (const auto& s) { - return expression::Convert::toExpression(s); - })), - zoomCurve(expression::findZoomCurveChecked(expression.get())) - {} - - T evaluate(float zoom) const { - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(zoom, nullptr)); - if (result) { - const optional<T> typed = expression::fromExpressionValue<T>(*result); - return typed ? *typed : T(); - } - return T(); - } - - float interpolationFactor(const Range<float>& inputLevels, const float inputValue) const { - return zoomCurve.match( - [&](const expression::InterpolateBase* z) { - return z->interpolationFactor(Range<double> { inputLevels.min, inputLevels.max }, inputValue); - }, - [&](const expression::Step*) { return 0.0f; } - ); - } - - Range<float> getCoveringStops(const float lower, const float upper) const { - return zoomCurve.match( - [&](auto z) { return z->getCoveringStops(lower, upper); } - ); - } - - std::vector<optional<T>> possibleOutputs() const { - return expression::fromExpressionValues<T>(expression->possibleOutputs()); - } - - friend bool operator==(const CameraFunction& lhs, - const CameraFunction& rhs) { - return *lhs.expression == *rhs.expression; - } - - bool useIntegerZoom = false; - bool isExpression; - - const expression::Expression& getExpression() const { return *expression; } - -private: - std::shared_ptr<expression::Expression> expression; - const variant<const expression::InterpolateBase*, const expression::Step*> zoomCurve; -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/categorical_stops.hpp b/include/mbgl/style/function/categorical_stops.hpp deleted file mode 100644 index c8505115ab..0000000000 --- a/include/mbgl/style/function/categorical_stops.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <mbgl/util/feature.hpp> -#include <mbgl/util/variant.hpp> - -#include <cassert> -#include <utility> -#include <map> - -namespace mbgl { -namespace style { - -class CategoricalValue : public variant<bool, int64_t, std::string> { -public: - using variant<bool, int64_t, std::string>::variant; -}; - -template <class T> -class CategoricalStops { -public: - using Stops = std::map<CategoricalValue, T>; - - Stops stops; - - CategoricalStops() = default; - CategoricalStops(Stops stops_) - : stops(std::move(stops_)) { - assert(stops.size() > 0); - } - - optional<T> evaluate(const Value&) const; - - friend bool operator==(const CategoricalStops& lhs, - const CategoricalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_categorical_stops.hpp b/include/mbgl/style/function/composite_categorical_stops.hpp deleted file mode 100644 index b796621d1a..0000000000 --- a/include/mbgl/style/function/composite_categorical_stops.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <mbgl/style/function/categorical_stops.hpp> - -namespace mbgl { -namespace style { - -template <class T> -class CompositeCategoricalStops { -public: - using Stops = std::map<float, std::map<CategoricalValue, T>>; - Stops stops; - - CompositeCategoricalStops() = default; - CompositeCategoricalStops(Stops stops_) - : stops(std::move(stops_)) { - } - - CategoricalStops<T> innerStops(const std::map<CategoricalValue, T>& stops_) const { - return CategoricalStops<T>(stops_); - } - - friend bool operator==(const CompositeCategoricalStops& lhs, - const CompositeCategoricalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_exponential_stops.hpp b/include/mbgl/style/function/composite_exponential_stops.hpp deleted file mode 100644 index f1ad32a04d..0000000000 --- a/include/mbgl/style/function/composite_exponential_stops.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include <mbgl/style/function/exponential_stops.hpp> - -#include <map> - -namespace mbgl { -namespace style { - -template <class T> -class CompositeExponentialStops { -public: - using Stops = std::map<float, std::map<float, T>>; - - Stops stops; - float base = 1.0f; - - CompositeExponentialStops() = default; - CompositeExponentialStops(Stops stops_, float base_ = 1.0f) - : stops(std::move(stops_)), - base(base_) { - } - - ExponentialStops<T> innerStops(const std::map<float, T>& stops_) const { - return ExponentialStops<T>(stops_, base); - } - - friend bool operator==(const CompositeExponentialStops& lhs, - const CompositeExponentialStops& rhs) { - return lhs.stops == rhs.stops && lhs.base == rhs.base; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp deleted file mode 100644 index 614c345c25..0000000000 --- a/include/mbgl/style/function/composite_function.hpp +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include <mbgl/style/expression/expression.hpp> -#include <mbgl/style/expression/interpolate.hpp> -#include <mbgl/style/expression/step.hpp> -#include <mbgl/style/expression/find_zoom_curve.hpp> -#include <mbgl/style/expression/value.hpp> -#include <mbgl/style/expression/is_constant.hpp> -#include <mbgl/style/function/convert.hpp> -#include <mbgl/style/function/composite_exponential_stops.hpp> -#include <mbgl/style/function/composite_interval_stops.hpp> -#include <mbgl/style/function/composite_categorical_stops.hpp> -#include <mbgl/util/interpolate.hpp> -#include <mbgl/util/range.hpp> -#include <mbgl/util/variant.hpp> - -#include <string> -#include <tuple> - -namespace mbgl { - -class GeometryTileFeature; - -namespace style { - -// A CompositeFunction consists of an outer zoom function whose stop range values are -// "inner" source functions. It provides the GL Native implementation of -// "zoom-and-property" functions from the style spec. - -template <class T> -class CompositeFunction { -public: - using InnerStops = std::conditional_t< - util::Interpolatable<T>::value, - variant< - ExponentialStops<T>, - IntervalStops<T>, - CategoricalStops<T>>, - variant< - IntervalStops<T>, - CategoricalStops<T>>>; - - using Stops = std::conditional_t< - util::Interpolatable<T>::value, - variant< - CompositeExponentialStops<T>, - CompositeIntervalStops<T>, - CompositeCategoricalStops<T>>, - variant< - CompositeIntervalStops<T>, - CompositeCategoricalStops<T>>>; - - CompositeFunction(std::unique_ptr<expression::Expression> expression_) - : isExpression(true), - expression(std::move(expression_)), - zoomCurve(expression::findZoomCurveChecked(expression.get())) - { - assert(!expression::isZoomConstant(*expression)); - assert(!expression::isFeatureConstant(*expression)); - } - - CompositeFunction(const std::string& property, const Stops& stops, optional<T> defaultValue_ = {}) - : isExpression(false), - defaultValue(std::move(defaultValue_)), - expression(stops.match([&] (const auto& s) { - return expression::Convert::toExpression(property, s); - })), - zoomCurve(expression::findZoomCurveChecked(expression.get())) - {} - - // Return the range obtained by evaluating the function at each of the zoom levels in zoomRange - template <class Feature> - Range<T> evaluate(const Range<float>& zoomRange, const Feature& feature, T finalDefaultValue) { - return Range<T> { - evaluate(zoomRange.min, feature, finalDefaultValue), - evaluate(zoomRange.max, feature, finalDefaultValue) - }; - } - - template <class Feature> - T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const { - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext({zoom}, &feature)); - if (result) { - const optional<T> typed = expression::fromExpressionValue<T>(*result); - return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; - } - return defaultValue ? *defaultValue : finalDefaultValue; - } - - float interpolationFactor(const Range<float>& inputLevels, const float inputValue) const { - return zoomCurve.match( - [&](const expression::InterpolateBase* z) { - return z->interpolationFactor(Range<double> { inputLevels.min, inputLevels.max }, inputValue); - }, - [&](const expression::Step*) { return 0.0f; } - ); - } - - Range<float> getCoveringStops(const float lower, const float upper) const { - return zoomCurve.match( - [&](auto z) { return z->getCoveringStops(lower, upper); } - ); - } - - std::vector<optional<T>> possibleOutputs() const { - return expression::fromExpressionValues<T>(expression->possibleOutputs()); - } - - friend bool operator==(const CompositeFunction& lhs, - const CompositeFunction& rhs) { - return *lhs.expression == *rhs.expression; - } - - const expression::Expression& getExpression() const { return *expression; } - - bool useIntegerZoom = false; - bool isExpression; - -private: - optional<T> defaultValue; - std::shared_ptr<expression::Expression> expression; - const variant<const expression::InterpolateBase*, const expression::Step*> zoomCurve; -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_interval_stops.hpp b/include/mbgl/style/function/composite_interval_stops.hpp deleted file mode 100644 index 3c495f2a7f..0000000000 --- a/include/mbgl/style/function/composite_interval_stops.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include <mbgl/style/function/interval_stops.hpp> - -#include <map> - -namespace mbgl { -namespace style { - -template <class T> -class CompositeIntervalStops { -public: - using Stops = std::map<float, std::map<float, T>>; - Stops stops; - - CompositeIntervalStops() = default; - CompositeIntervalStops(Stops stops_) - : stops(std::move(stops_)) { - } - - IntervalStops<T> innerStops(const std::map<float, T>& stops_) const { - return IntervalStops<T>(stops_); - } - - friend bool operator==(const CompositeIntervalStops& lhs, - const CompositeIntervalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/convert.hpp b/include/mbgl/style/function/convert.hpp deleted file mode 100644 index 401a81d52e..0000000000 --- a/include/mbgl/style/function/convert.hpp +++ /dev/null @@ -1,356 +0,0 @@ -#pragma once - -#include <mbgl/style/expression/array_assertion.hpp> -#include <mbgl/style/expression/assertion.hpp> -#include <mbgl/style/expression/case.hpp> -#include <mbgl/style/expression/coalesce.hpp> -#include <mbgl/style/expression/compound_expression.hpp> -#include <mbgl/style/expression/coercion.hpp> -#include <mbgl/style/expression/interpolate.hpp> -#include <mbgl/style/expression/expression.hpp> -#include <mbgl/style/expression/literal.hpp> -#include <mbgl/style/expression/match.hpp> -#include <mbgl/style/expression/step.hpp> - -#include <mbgl/style/function/exponential_stops.hpp> -#include <mbgl/style/function/interval_stops.hpp> -#include <mbgl/style/function/categorical_stops.hpp> -#include <mbgl/style/function/composite_exponential_stops.hpp> -#include <mbgl/style/function/composite_interval_stops.hpp> -#include <mbgl/style/function/composite_categorical_stops.hpp> -#include <mbgl/style/function/identity_stops.hpp> - -#include <mbgl/util/enum.hpp> -#include <mbgl/style/types.hpp> - -#include <string> - - -namespace mbgl { -namespace style { -namespace expression { - -namespace detail { - -class ErrorExpression : public Expression { -public: - ErrorExpression(std::string message_) : Expression(type::Error), message(std::move(message_)) {} - void eachChild(const std::function<void(const Expression&)>&) const override {} - - bool operator==(const Expression& e) const override { - return dynamic_cast<const ErrorExpression*>(&e); - } - - EvaluationResult evaluate(const EvaluationContext&) const override { - return EvaluationError{message}; - } - - std::vector<optional<Value>> possibleOutputs() const override { - return {}; - } - - std::string getOperator() const override { return "error"; } -private: - std::string message; -}; - -} // namespace detail - - -// Create expressions representing 'classic' (i.e. stop-based) style functions - -struct Convert { - template <typename T> - static std::unique_ptr<Literal> makeLiteral(const T& value) { - return std::make_unique<Literal>(Value(toExpressionValue(value))); - } - - static std::unique_ptr<Expression> makeGet(type::Type type, const std::string& property) { - ParsingContext ctx; - std::vector<std::unique_ptr<Expression>> getArgs; - getArgs.push_back(makeLiteral(property)); - ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx); - assert(get); - assert(ctx.getErrors().size() == 0); - - std::vector<std::unique_ptr<Expression>> assertionArgs; - assertionArgs.push_back(std::move(*get)); - - return std::make_unique<Assertion>(type, std::move(assertionArgs)); - } - - static std::unique_ptr<Expression> makeZoom() { - ParsingContext ctx; - ParseResult zoom = createCompoundExpression("zoom", std::vector<std::unique_ptr<Expression>>(), ctx); - assert(zoom); - assert(ctx.getErrors().size() == 0); - return std::move(*zoom); - } - - static std::unique_ptr<Expression> makeError(std::string message) { - return std::make_unique<detail::ErrorExpression>(message); - } - - template <typename OutputType> - static ParseResult makeInterpolate(type::Type type, - std::unique_ptr<Expression> input, - std::map<double, std::unique_ptr<Expression>> convertedStops, - typename Interpolate<OutputType>::Interpolator interpolator) - { - ParseResult curve = ParseResult(std::make_unique<Interpolate<OutputType>>( - std::move(type), - std::move(interpolator), - std::move(input), - std::move(convertedStops) - )); - assert(curve); - return std::move(*curve); - } - - template <typename Key> - static ParseResult makeMatch(type::Type type, - std::unique_ptr<Expression> input, - std::map<CategoricalValue, std::unique_ptr<Expression>> stops) { - // match expression - typename Match<Key>::Branches branches; - for(auto it = stops.begin(); it != stops.end(); it++) { - assert(it->first.template is<Key>()); - Key key = it->first.template get<Key>(); - branches.emplace( - std::move(key), - std::move(it->second) - ); - } - - return ParseResult(std::make_unique<Match<Key>>(std::move(type), - std::move(input), - std::move(branches), - makeError("No matching label"))); - } - - static ParseResult makeCase(type::Type type, - std::unique_ptr<Expression> input, - std::map<CategoricalValue, std::unique_ptr<Expression>> stops) { - // case expression - std::vector<typename Case::Branch> branches; - - auto it = stops.find(true); - std::unique_ptr<Expression> true_case = it == stops.end() ? - makeError("No matching label") : - std::move(it->second); - - it = stops.find(false); - std::unique_ptr<Expression> false_case = it == stops.end() ? - makeError("No matching label") : - std::move(it->second); - - branches.push_back(std::make_pair(std::move(input), std::move(true_case))); - return ParseResult(std::make_unique<Case>(std::move(type), std::move(branches), std::move(false_case))); - } - - template <typename T> - static ParseResult fromCategoricalStops(std::map<CategoricalValue, T> stops, const std::string& property) { - assert(stops.size() > 0); - - std::map<CategoricalValue, std::unique_ptr<Expression>> convertedStops; - for(const std::pair<CategoricalValue, T>& stop : stops) { - convertedStops.emplace( - stop.first, - makeLiteral(stop.second) - ); - } - - type::Type type = valueTypeToExpressionType<T>(); - - const CategoricalValue& firstKey = stops.begin()->first; - return firstKey.match( - [&](bool) { - return makeCase(type, makeGet(type::Boolean, property), std::move(convertedStops)); - }, - [&](const std::string&) { - return makeMatch<std::string>(type, makeGet(type::String, property), std::move(convertedStops)); - }, - [&](int64_t) { - return makeMatch<int64_t>(type, makeGet(type::Number, property), std::move(convertedStops)); - } - ); - } - - template <typename T> - static std::map<double, std::unique_ptr<Expression>> convertStops(const std::map<float, T>& stops) { - std::map<double, std::unique_ptr<Expression>> convertedStops; - for(const auto& stop : stops) { - convertedStops.emplace( - stop.first, - makeLiteral(stop.second) - ); - } - return convertedStops; - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const ExponentialStops<T>& stops) - { - ParseResult e = makeInterpolate<typename ValueConverter<T>::ExpressionType>( - valueTypeToExpressionType<T>(), - makeZoom(), - convertStops(stops.stops), - ExponentialInterpolator(stops.base)); - assert(e); - return std::move(*e); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const IntervalStops<T>& stops) - { - ParseResult e(std::make_unique<Step>(valueTypeToExpressionType<T>(), - makeZoom(), - convertStops(stops.stops))); - assert(e); - return std::move(*e); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const std::string& property, - const ExponentialStops<T>& stops) - { - ParseResult e = makeInterpolate<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeGet(type::Number, property), - convertStops(stops.stops), - ExponentialInterpolator(stops.base)); - assert(e); - return std::move(*e); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const std::string& property, - const IntervalStops<T>& stops) - { - std::unique_ptr<Expression> get = makeGet(type::Number, property); - ParseResult e(std::make_unique<Step>(valueTypeToExpressionType<T>(), - std::move(get), - convertStops(stops.stops))); - assert(e); - return std::move(*e); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const std::string& property, - const CategoricalStops<T>& stops) - { - ParseResult expr = fromCategoricalStops(stops.stops, property); - assert(expr); - return std::move(*expr); - } - - // interpolatable zoom curve - template <typename T> - static typename std::enable_if_t<util::Interpolatable<T>::value, - ParseResult> makeZoomCurve(std::map<double, std::unique_ptr<Expression>> stops) { - return makeInterpolate<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - makeZoom(), - std::move(stops), - ExponentialInterpolator(1.0)); - } - - // non-interpolatable zoom curve - template <typename T> - static typename std::enable_if_t<!util::Interpolatable<T>::value, - ParseResult> makeZoomCurve(std::map<double, std::unique_ptr<Expression>> stops) { - return ParseResult(std::make_unique<Step>(valueTypeToExpressionType<T>(), makeZoom(), std::move(stops))); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const std::string& property, - const CompositeExponentialStops<T>& stops) - { - std::map<double, std::unique_ptr<Expression>> outerStops; - for (const std::pair<float, std::map<float, T>>& stop : stops.stops) { - std::unique_ptr<Expression> get = makeGet(type::Number, property); - ParseResult innerInterpolate = makeInterpolate<typename ValueConverter<T>::ExpressionType>(valueTypeToExpressionType<T>(), - std::move(get), - convertStops(stop.second), - ExponentialInterpolator(stops.base)); - assert(innerInterpolate); - outerStops.emplace(stop.first, std::move(*innerInterpolate)); - } - - ParseResult zoomCurve = makeZoomCurve<T>(std::move(outerStops)); - assert(zoomCurve); - return std::move(*zoomCurve); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const std::string& property, - const CompositeIntervalStops<T>& stops) - { - std::map<double, std::unique_ptr<Expression>> outerStops; - for (const std::pair<float, std::map<float, T>>& stop : stops.stops) { - std::unique_ptr<Expression> get = makeGet(type::Number, property); - ParseResult innerInterpolate(std::make_unique<Step>(valueTypeToExpressionType<T>(), - std::move(get), - convertStops(stop.second))); - assert(innerInterpolate); - outerStops.emplace(stop.first, std::move(*innerInterpolate)); - } - - ParseResult zoomCurve = makeZoomCurve<T>(std::move(outerStops)); - assert(zoomCurve); - return std::move(*zoomCurve); - } - - template <typename T> - static std::unique_ptr<Expression> toExpression(const std::string& property, - const CompositeCategoricalStops<T>& stops) - { - std::map<double, std::unique_ptr<Expression>> outerStops; - for (const std::pair<float, std::map<CategoricalValue, T>>& stop : stops.stops) { - ParseResult innerInterpolate = fromCategoricalStops(stop.second, property); - assert(innerInterpolate); - outerStops.emplace(stop.first, std::move(*innerInterpolate)); - } - - ParseResult zoomCurve = makeZoomCurve<T>(std::move(outerStops)); - assert(zoomCurve); - return std::move(*zoomCurve); - } - - - static std::unique_ptr<Expression> fromIdentityFunction(type::Type type, const std::string& property) - { - std::unique_ptr<Expression> input = type.match( - [&] (const type::StringType&) { - return makeGet(type::String, property); - }, - [&] (const type::NumberType&) { - return makeGet(type::Number, property); - }, - [&] (const type::BooleanType&) { - return makeGet(type::Boolean, property); - }, - [&] (const type::ColorType&) { - std::vector<std::unique_ptr<Expression>> args; - args.push_back(makeGet(type::String, property)); - return std::make_unique<Coercion>(type::Color, std::move(args)); - }, - [&] (const type::Array& arr) { - std::vector<std::unique_ptr<Expression>> getArgs; - getArgs.push_back(makeLiteral(property)); - ParsingContext ctx; - ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx); - assert(get); - assert(ctx.getErrors().size() == 0); - return std::make_unique<ArrayAssertion>(arr, std::move(*get)); - }, - [&] (const auto&) -> std::unique_ptr<Expression> { - return makeLiteral(Null); - } - ); - - return input; - } -}; - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/exponential_stops.hpp b/include/mbgl/style/function/exponential_stops.hpp deleted file mode 100644 index b3866c4059..0000000000 --- a/include/mbgl/style/function/exponential_stops.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include <mbgl/util/feature.hpp> -#include <mbgl/util/interpolate.hpp> - -#include <map> - -namespace mbgl { -namespace style { - -template <class T> -class ExponentialStops { -public: - using Stops = std::map<float, T>; - - Stops stops; - float base = 1.0f; - - ExponentialStops() = default; - ExponentialStops(Stops stops_, float base_ = 1.0f) - : stops(std::move(stops_)), - base(base_) { - } - - optional<T> evaluate(float z) const { - if (stops.empty()) { - return {}; - } - - auto it = stops.upper_bound(z); - if (it == stops.end()) { - return stops.rbegin()->second; - } else if (it == stops.begin()) { - return stops.begin()->second; - } else { - return util::interpolate(std::prev(it)->second, it->second, - util::interpolationFactor(base, { std::prev(it)->first, it->first }, z)); - } - } - - optional<T> evaluate(const Value& value) const { - optional<float> z = numericValue<float>(value); - if (!z) { - return {}; - } - return evaluate(*z); - } - - friend bool operator==(const ExponentialStops& lhs, - const ExponentialStops& rhs) { - return lhs.stops == rhs.stops && lhs.base == rhs.base; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/identity_stops.hpp b/include/mbgl/style/function/identity_stops.hpp deleted file mode 100644 index 741ebbbe0c..0000000000 --- a/include/mbgl/style/function/identity_stops.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include <mbgl/util/feature.hpp> - -namespace mbgl { -namespace style { - -template <class T> -class IdentityStops { -public: - optional<T> evaluate(const Value&) const; - - friend bool operator==(const IdentityStops&, - const IdentityStops&) { - return true; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/interval_stops.hpp b/include/mbgl/style/function/interval_stops.hpp deleted file mode 100644 index 45e2dc6f2e..0000000000 --- a/include/mbgl/style/function/interval_stops.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include <mbgl/util/feature.hpp> - -#include <map> - -namespace mbgl { -namespace style { - -template <class T> -class IntervalStops { -public: - using Stops = std::map<float, T>; - Stops stops; - - IntervalStops() = default; - IntervalStops(Stops stops_) - : stops(std::move(stops_)) { - } - - optional<T> evaluate(float z) const { - if (stops.empty()) { - return {}; - } - - auto it = stops.upper_bound(z); - if (it == stops.end()) { - return stops.rbegin()->second; - } else if (it == stops.begin()) { - return stops.begin()->second; - } else { - return std::prev(it)->second; - } - } - - optional<T> evaluate(const Value& value) const { - optional<float> z = numericValue<float>(value); - if (!z) { - return {}; - } - return evaluate(*z); - } - - friend bool operator==(const IntervalStops& lhs, - const IntervalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/source_function.hpp b/include/mbgl/style/function/source_function.hpp deleted file mode 100644 index 5b51d0bf81..0000000000 --- a/include/mbgl/style/function/source_function.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include <mbgl/style/expression/is_constant.hpp> -#include <mbgl/style/function/convert.hpp> -#include <mbgl/style/function/exponential_stops.hpp> -#include <mbgl/style/function/interval_stops.hpp> -#include <mbgl/style/function/categorical_stops.hpp> -#include <mbgl/style/function/identity_stops.hpp> -#include <mbgl/util/interpolate.hpp> -#include <mbgl/util/variant.hpp> - -#include <string> - -namespace mbgl { -namespace style { - -template <class T> -class SourceFunction { -public: - using Stops = std::conditional_t< - util::Interpolatable<T>::value, - variant< - ExponentialStops<T>, - IntervalStops<T>, - CategoricalStops<T>, - IdentityStops<T>>, - variant< - IntervalStops<T>, - CategoricalStops<T>, - IdentityStops<T>>>; - - SourceFunction(std::unique_ptr<expression::Expression> expression_) - : isExpression(true), - expression(std::move(expression_)) - { - assert(expression::isZoomConstant(*expression)); - assert(!expression::isFeatureConstant(*expression)); - } - - SourceFunction(const std::string& property, const Stops& stops, optional<T> defaultValue_ = {}) - : isExpression(false), - defaultValue(std::move(defaultValue_)), - expression(stops.match([&] (const IdentityStops<T>&) { - return expression::Convert::fromIdentityFunction(expression::valueTypeToExpressionType<T>(), property); - }, [&] (const auto& s) { - return expression::Convert::toExpression(property, s); - })) - {} - - template <class Feature> - T evaluate(const Feature& feature, T finalDefaultValue) const { - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(&feature)); - if (result) { - const optional<T> typed = expression::fromExpressionValue<T>(*result); - return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; - } - return defaultValue ? *defaultValue : finalDefaultValue; - } - - std::vector<optional<T>> possibleOutputs() const { - return expression::fromExpressionValues<T>(expression->possibleOutputs()); - } - - friend bool operator==(const SourceFunction& lhs, - const SourceFunction& rhs) { - return *lhs.expression == *rhs.expression; - } - - bool useIntegerZoom = false; - bool isExpression; - - const expression::Expression& getExpression() const { return *expression; } - -private: - optional<T> defaultValue; - std::shared_ptr<expression::Expression> expression; -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/layers/heatmap_layer.hpp b/include/mbgl/style/layers/heatmap_layer.hpp index 33d927ad38..4c434b2aff 100644 --- a/include/mbgl/style/layers/heatmap_layer.hpp +++ b/include/mbgl/style/layers/heatmap_layer.hpp @@ -2,11 +2,11 @@ #pragma once +#include <mbgl/style/color_ramp_property_value.hpp> #include <mbgl/style/layer.hpp> #include <mbgl/style/filter.hpp> #include <mbgl/style/property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> -#include <mbgl/style/heatmap_color_property_value.hpp> #include <mbgl/util/color.hpp> @@ -55,9 +55,9 @@ public: void setHeatmapIntensityTransition(const TransitionOptions&); TransitionOptions getHeatmapIntensityTransition() const; - static HeatmapColorPropertyValue getDefaultHeatmapColor(); - HeatmapColorPropertyValue getHeatmapColor() const; - void setHeatmapColor(HeatmapColorPropertyValue); + static ColorRampPropertyValue getDefaultHeatmapColor(); + ColorRampPropertyValue getHeatmapColor() const; + void setHeatmapColor(ColorRampPropertyValue); void setHeatmapColorTransition(const TransitionOptions&); TransitionOptions getHeatmapColorTransition() const; diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs new file mode 100644 index 0000000000..e15ff74f17 --- /dev/null +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -0,0 +1,93 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Do not edit. + +#pragma once + +<% if (type === 'heatmap') { -%> +#include <mbgl/style/color_ramp_property_value.hpp> +<% } -%> +#include <mbgl/style/layer.hpp> +#include <mbgl/style/filter.hpp> +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/data_driven_property_value.hpp> + +#include <mbgl/util/color.hpp> + +<% if (type === 'line' || type === 'symbol') { -%> +#include <vector> + +<% } -%> +namespace mbgl { +namespace style { + +class TransitionOptions; + +class <%- camelize(type) %>Layer : public Layer { +public: +<% if (type === 'background') { -%> + <%- camelize(type) %>Layer(const std::string& layerID); +<% } else { -%> + <%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID); +<% } -%> + ~<%- camelize(type) %>Layer() final; + +<% if (type !== 'background') { -%> + // Source + const std::string& getSourceID() const; +<% if (type !== 'raster' && type !== 'hillshade') { -%> + const std::string& getSourceLayer() const; + void setSourceLayer(const std::string& sourceLayer); + + void setFilter(const Filter&); + const Filter& getFilter() const; +<% } -%> + +<% } -%> + // Visibility + void setVisibility(VisibilityType) final; + + // Zoom range + void setMinZoom(float) final; + void setMaxZoom(float) final; + +<% if (layoutProperties.length) { -%> + // Layout properties + +<% for (const property of layoutProperties) { -%> + static <%- propertyValueType(property) %> getDefault<%- camelize(property.name) %>(); + <%- propertyValueType(property) %> get<%- camelize(property.name) %>() const; + void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>); + +<% } -%> +<% } -%> + // Paint properties + +<% for (const property of paintProperties) { -%> + static <%- propertyValueType(property) %> getDefault<%- camelize(property.name) %>(); + <%- propertyValueType(property) %> get<%- camelize(property.name) %>() const; + void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>); + void set<%- camelize(property.name) %>Transition(const TransitionOptions&); + TransitionOptions get<%- camelize(property.name) %>Transition() const; + +<% } -%> + // Private implementation + + class Impl; + const Impl& impl() const; + + Mutable<Impl> mutableImpl() const; + <%- camelize(type) %>Layer(Immutable<Impl>); + std::unique_ptr<Layer> cloneRef(const std::string& id) const final; +}; + +template <> +inline bool Layer::is<<%- camelize(type) %>Layer>() const { + return getType() == LayerType::<%- camelize(type) %>; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp index 8111364709..8e7849c27d 100644 --- a/include/mbgl/style/layers/raster_layer.hpp +++ b/include/mbgl/style/layers/raster_layer.hpp @@ -67,6 +67,12 @@ public: void setRasterContrastTransition(const TransitionOptions&); TransitionOptions getRasterContrastTransition() const; + static PropertyValue<RasterResamplingType> getDefaultRasterResampling(); + PropertyValue<RasterResamplingType> getRasterResampling() const; + void setRasterResampling(PropertyValue<RasterResamplingType>); + void setRasterResamplingTransition(const TransitionOptions&); + TransitionOptions getRasterResamplingTransition() const; + static PropertyValue<float> getDefaultRasterFadeDuration(); PropertyValue<float> getRasterFadeDuration() const; void setRasterFadeDuration(PropertyValue<float>); diff --git a/include/mbgl/style/light.hpp.ejs b/include/mbgl/style/light.hpp.ejs new file mode 100644 index 0000000000..adc5b651e3 --- /dev/null +++ b/include/mbgl/style/light.hpp.ejs @@ -0,0 +1,40 @@ +<% + const properties = locals.properties; +-%> +// This file is generated. Do not edit. + +#pragma once + +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/style/types.hpp> +#include <mbgl/util/immutable.hpp> + +namespace mbgl { +namespace style { + +class LightObserver; + +class Light { +public: + Light(); + ~Light(); + +<% for (const property of properties) { -%> + static <%- evaluatedType(property) %> getDefault<%- camelize(property.name) %>(); + <%- propertyValueType(property) %> get<%- camelize(property.name) %>() const; + void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>); + void set<%- camelize(property.name) %>Transition(const TransitionOptions&); + TransitionOptions get<%- camelize(property.name) %>Transition() const; + +<% } -%> + class Impl; + Immutable<Impl> impl; + Mutable<Impl> mutableImpl() const; + + LightObserver* observer = nullptr; + void setObserver(LightObserver*); +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp new file mode 100644 index 0000000000..b198de02b2 --- /dev/null +++ b/include/mbgl/style/property_expression.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/style/expression/value.hpp> +#include <mbgl/style/expression/is_constant.hpp> +#include <mbgl/style/expression/interpolate.hpp> +#include <mbgl/style/expression/step.hpp> +#include <mbgl/style/expression/find_zoom_curve.hpp> +#include <mbgl/util/range.hpp> + +namespace mbgl { +namespace style { + +template <class T> +class PropertyExpression { +public: + // Second parameter to be used only for conversions from legacy functions. + PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = {}) + : expression(std::move(expression_)), + defaultValue(std::move(defaultValue_)), + zoomCurve(expression::findZoomCurveChecked(expression.get())) { + } + + bool isZoomConstant() const { return expression::isZoomConstant(*expression); } + bool isFeatureConstant() const { return expression::isFeatureConstant(*expression); } + + T evaluate(float zoom) const { + assert(!expression::isZoomConstant(*expression)); + assert(expression::isFeatureConstant(*expression)); + const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(zoom, nullptr)); + if (result) { + const optional<T> typed = expression::fromExpressionValue<T>(*result); + return typed ? *typed : defaultValue ? *defaultValue : T(); + } + return defaultValue ? *defaultValue : T(); + } + + template <class Feature> + T evaluate(const Feature& feature, T finalDefaultValue) const { + assert(expression::isZoomConstant(*expression)); + assert(!expression::isFeatureConstant(*expression)); + const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(&feature)); + if (result) { + const optional<T> typed = expression::fromExpressionValue<T>(*result); + return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; + } + return defaultValue ? *defaultValue : finalDefaultValue; + } + + template <class Feature> + T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const { + assert(!expression::isFeatureConstant(*expression)); + const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext({zoom}, &feature)); + if (result) { + const optional<T> typed = expression::fromExpressionValue<T>(*result); + return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; + } + return defaultValue ? *defaultValue : finalDefaultValue; + } + + float interpolationFactor(const Range<float>& inputLevels, const float inputValue) const { + return zoomCurve.match( + [](std::nullptr_t) { + assert(false); + return 0.0f; + }, + [&](const expression::Interpolate* z) { + return z->interpolationFactor(Range<double> { inputLevels.min, inputLevels.max }, inputValue); + }, + [&](const expression::Step*) { + return 0.0f; + } + ); + } + + Range<float> getCoveringStops(const float lower, const float upper) const { + return zoomCurve.match( + [](std::nullptr_t) { + assert(false); + return Range<float>(0.0f, 0.0f); + }, + [&](auto z) { + return z->getCoveringStops(lower, upper); + } + ); + } + + // Return the range obtained by evaluating the function at each of the zoom levels in zoomRange + template <class Feature> + Range<T> evaluate(const Range<float>& zoomRange, const Feature& feature, T finalDefaultValue) { + return Range<T> { + evaluate(zoomRange.min, feature, finalDefaultValue), + evaluate(zoomRange.max, feature, finalDefaultValue) + }; + } + + std::vector<optional<T>> possibleOutputs() const { + return expression::fromExpressionValues<T>(expression->possibleOutputs()); + } + + const expression::Expression& getExpression() const { return *expression; } + + bool useIntegerZoom = false; + + friend bool operator==(const PropertyExpression& lhs, + const PropertyExpression& rhs) { + return *lhs.expression == *rhs.expression; + } + +private: + std::shared_ptr<const expression::Expression> expression; + optional<T> defaultValue; + variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve; +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp index 02d3a31148..1b0f3d2ab0 100644 --- a/include/mbgl/style/property_value.hpp +++ b/include/mbgl/style/property_value.hpp @@ -2,7 +2,7 @@ #include <mbgl/util/variant.hpp> #include <mbgl/style/undefined.hpp> -#include <mbgl/style/function/camera_function.hpp> +#include <mbgl/style/property_expression.hpp> namespace mbgl { namespace style { @@ -10,7 +10,7 @@ namespace style { template <class T> class PropertyValue { private: - using Value = variant<Undefined, T, CameraFunction<T>>; + using Value = variant<Undefined, T, PropertyExpression<T>>; Value value; friend bool operator==(const PropertyValue& lhs, const PropertyValue& rhs) { @@ -22,17 +22,24 @@ private: } public: - PropertyValue() : value() {} - PropertyValue( T constant) : value(constant) {} - PropertyValue(CameraFunction<T> function) : value(function) {} + PropertyValue() + : value() {} + + PropertyValue(T constant) + : value(constant) {} + + PropertyValue(PropertyExpression<T> expression) + : value(expression) { + assert(expression.isFeatureConstant()); + } bool isUndefined() const { return value.which() == 0; } bool isConstant() const { return value.which() == 1; } - bool isCameraFunction() const { return value.which() == 2; } + bool isExpression() const { return value.which() == 2; } bool isDataDriven() const { return false; } - const T & asConstant() const { return value.template get< T >(); } - const CameraFunction<T>& asCameraFunction() const { return value.template get<CameraFunction<T>>(); } + const T & asConstant() const { return value.template get< T >(); } + const PropertyExpression<T>& asExpression() const { return value.template get<PropertyExpression<T>>(); } template <typename Evaluator> auto evaluate(const Evaluator& evaluator, TimePoint = {}) const { diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp index 693972a72f..805cff118c 100644 --- a/include/mbgl/style/types.hpp +++ b/include/mbgl/style/types.hpp @@ -38,6 +38,11 @@ enum class LineJoinType : uint8_t { FlipBevel }; +enum class RasterResamplingType : bool { + Linear, + Nearest +}; + enum class HillshadeIlluminationAnchorType : bool { Map, Viewport @@ -58,9 +63,10 @@ enum class CirclePitchScaleType : bool { Viewport, }; -enum class SymbolPlacementType : bool { +enum class SymbolPlacementType : uint8_t { Point, Line, + LineCenter }; enum class AlignmentType : uint8_t { diff --git a/include/mbgl/tile/tile_id.hpp b/include/mbgl/tile/tile_id.hpp index 11fb5ce537..dd2fba573d 100644 --- a/include/mbgl/tile/tile_id.hpp +++ b/include/mbgl/tile/tile_id.hpp @@ -58,10 +58,11 @@ public: uint32_t overscaleFactor() const; OverscaledTileID scaledTo(uint8_t z) const; UnwrappedTileID toUnwrapped() const; + OverscaledTileID unwrapTo(int16_t wrap); - const uint8_t overscaledZ; - const int16_t wrap; - const CanonicalTileID canonical; + uint8_t overscaledZ; + int16_t wrap; + CanonicalTileID canonical; }; ::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs); @@ -84,9 +85,10 @@ public: std::array<UnwrappedTileID, 4> children() const; OverscaledTileID overscaleTo(uint8_t z) const; float pixelsToTileUnits(float pixelValue, float zoom) const; + UnwrappedTileID unwrapTo(int16_t wrap); - const int16_t wrap; - const CanonicalTileID canonical; + int16_t wrap; + CanonicalTileID canonical; }; ::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs); @@ -191,6 +193,10 @@ inline UnwrappedTileID OverscaledTileID::toUnwrapped() const { return { wrap, canonical }; } +inline OverscaledTileID OverscaledTileID::unwrapTo(int16_t newWrap) { + return { overscaledZ, newWrap, canonical }; +} + inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_) : wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)), canonical( @@ -215,6 +221,10 @@ inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const { return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical); } +inline UnwrappedTileID UnwrappedTileID::unwrapTo(int16_t newWrap) { + return { newWrap, canonical }; +} + inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const { return wrap == parent.wrap && canonical.isChildOf(parent.canonical); } diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp index d5e55065c4..7110d9e26b 100644 --- a/include/mbgl/util/constants.hpp +++ b/include/mbgl/util/constants.hpp @@ -11,7 +11,7 @@ namespace mbgl { namespace util { -constexpr float tileSize = 512; +constexpr double tileSize = 512; /* * The maximum extent of a feature that can be safely stored in the buffer. diff --git a/include/mbgl/util/event.hpp b/include/mbgl/util/event.hpp index 5fe0baae3c..15583e956d 100644 --- a/include/mbgl/util/event.hpp +++ b/include/mbgl/util/event.hpp @@ -28,6 +28,7 @@ enum class Event : uint8_t { Android, Crash, Glyph, + Timing }; struct EventPermutation { diff --git a/include/mbgl/util/logging.hpp b/include/mbgl/util/logging.hpp index d072673e76..03db2d7462 100644 --- a/include/mbgl/util/logging.hpp +++ b/include/mbgl/util/logging.hpp @@ -67,8 +67,8 @@ public: private: static void record(EventSeverity severity, Event event, const std::string &msg); - static void record(EventSeverity severity, Event event, const char* format, ...); - static void record(EventSeverity severity, Event event, int64_t code); + static void record(EventSeverity severity, Event event, const char* format = "", ...); + static void record(EventSeverity severity, Event event, int64_t code, const char* format = "", ...); static void record(EventSeverity severity, Event event, int64_t code, const std::string &msg); // This method is the data sink that must be implemented by each platform we diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp index 65a84d8dc2..9619a380b4 100644 --- a/include/mbgl/util/projection.hpp +++ b/include/mbgl/util/projection.hpp @@ -94,9 +94,10 @@ public: private: static Point<double> project_(const LatLng& latLng, double worldSize) { + const double latitude = util::clamp(latLng.latitude(), -util::LATITUDE_MAX, util::LATITUDE_MAX); return Point<double> { util::LONGITUDE_MAX + latLng.longitude(), - util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + latLng.latitude() * M_PI / util::DEGREES_MAX)) + util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + latitude * M_PI / util::DEGREES_MAX)) } * worldSize / util::DEGREES_MAX; } }; diff --git a/include/mbgl/util/thread.hpp b/include/mbgl/util/thread.hpp index 74e722b02d..bc58427349 100644 --- a/include/mbgl/util/thread.hpp +++ b/include/mbgl/util/thread.hpp @@ -37,45 +37,55 @@ namespace util { // - `Object` can use `Timer` and do asynchronous I/O, like wait for sockets events. // template<class Object> -class Thread : public Scheduler { +class Thread { public: template <class... Args> Thread(const std::string& name, Args&&... args) { - std::promise<void> running; - thread = std::thread([&] { + std::promise<void> running_; + running = running_.get_future(); + + auto capturedArgs = std::make_tuple(std::forward<Args>(args)...); + + thread = std::thread([ + this, + name, + capturedArgs = std::move(capturedArgs), + runningPromise = std::move(running_) + ] () mutable { platform::setCurrentThreadName(name); platform::makeThreadLowPriority(); util::RunLoop loop_(util::RunLoop::Type::New); loop = &loop_; + EstablishedActor<Object> establishedActor(loop_, object, std::move(capturedArgs)); - object = std::make_unique<Actor<Object>>(*this, std::forward<Args>(args)...); - running.set_value(); - + runningPromise.set_value(); + loop->run(); + + (void) establishedActor; + loop = nullptr; }); - - running.get_future().get(); } - ~Thread() override { + ~Thread() { if (paused) { resume(); } - std::promise<void> joinable; + std::promise<void> stoppable; + + running.wait(); - // Kill the actor, so we don't get more - // messages posted on this scheduler after - // we delete the RunLoop. + // Invoke a noop task on the run loop to ensure that we're executing + // run() before we call stop() loop->invoke([&] { - object.reset(); - joinable.set_value(); + stoppable.set_value(); }); - joinable.get_future().get(); + stoppable.get_future().get(); loop->stop(); thread.join(); @@ -85,8 +95,8 @@ public: // can be used to send messages to `Object`. It is safe // to the non-owning reference to outlive this object // and be used after the `Thread<>` gets destroyed. - ActorRef<std::decay_t<Object>> actor() const { - return object->self(); + ActorRef<std::decay_t<Object>> actor() { + return object.self(); } // Pauses the `Object` thread. It will prevent the object to wake @@ -103,6 +113,8 @@ public: auto pausing = paused->get_future(); + running.wait(); + loop->invoke(RunLoop::Priority::High, [this] { auto resuming = resumed->get_future(); paused->set_value(); @@ -127,13 +139,12 @@ public: private: MBGL_STORE_THREAD(tid); - void schedule(std::weak_ptr<Mailbox> mailbox) override { - loop->schedule(mailbox); - } + AspiringActor<Object> object; std::thread thread; - std::unique_ptr<Actor<Object>> object; + std::future<void> running; + std::unique_ptr<std::promise<void>> paused; std::unique_ptr<std::promise<void>> resumed; diff --git a/include/mbgl/util/unique_any.hpp b/include/mbgl/util/unique_any.hpp index d488930a03..c7dc8b38ea 100644 --- a/include/mbgl/util/unique_any.hpp +++ b/include/mbgl/util/unique_any.hpp @@ -135,15 +135,12 @@ private: template <typename ValueType> struct VTableHeap : public VTable { void move(Storage&& src, Storage& dest) override { - destroy(dest); dest.dynamic = src.dynamic; + src.dynamic = nullptr; } void destroy(Storage& s) override { - if (s.dynamic) { - delete reinterpret_cast<ValueType*>(s.dynamic); - } - s.dynamic = nullptr; + delete reinterpret_cast<ValueType*>(s.dynamic); } const std::type_info& type() override { @@ -154,9 +151,8 @@ private: template <typename ValueType> struct VTableStack : public VTable { void move(Storage&& src, Storage& dest) override { - auto srcValue = reinterpret_cast<ValueType&&>(src.stack); - new (static_cast<void*>(&dest.stack)) ValueType(std::move(srcValue)); - srcValue.~ValueType(); + new (&dest.stack) ValueType(std::move(reinterpret_cast<ValueType&>(src.stack))); + destroy(src); } void destroy(Storage& s) override { @@ -178,13 +174,13 @@ private: template <typename ValueType, typename _Vt> std::enable_if_t<AllocateOnStack<_Vt>::value> createStorage(ValueType&& value) { - new (static_cast<void*>(&storage.stack)) _Vt(std::forward<ValueType>(value)); + new (&storage.stack) _Vt(std::forward<ValueType>(value)); } template <typename ValueType, typename _Vt> std::enable_if_t<!AllocateOnStack<_Vt>::value> createStorage(ValueType&& value) { - storage.dynamic = static_cast<void*>(new _Vt(std::forward<ValueType>(value))); + storage.dynamic = new _Vt(std::forward<ValueType>(value)); } template <typename ValueType> diff --git a/mapbox-gl-native.pro b/mapbox-gl-native.pro index a05699f4a3..2f499b6ec5 100644 --- a/mapbox-gl-native.pro +++ b/mapbox-gl-native.pro @@ -70,6 +70,7 @@ SOURCES += \ platform/qt/src/qmapboxgl_map_observer.cpp \ platform/qt/src/qmapboxgl_map_renderer.cpp \ platform/qt/src/qmapboxgl_renderer_backend.cpp \ + platform/qt/src/qmapboxgl_scheduler.cpp \ platform/qt/src/qt_geojson.cpp \ platform/qt/src/qt_image.cpp \ platform/qt/src/qt_logging.cpp \ @@ -196,6 +197,7 @@ SOURCES += \ src/mbgl/shaders/preludes.cpp \ src/mbgl/shaders/raster.cpp \ src/mbgl/shaders/shaders.cpp \ + src/mbgl/shaders/source.cpp \ src/mbgl/shaders/symbol_icon.cpp \ src/mbgl/shaders/symbol_sdf.cpp \ src/mbgl/sprite/sprite_loader.cpp \ @@ -208,6 +210,7 @@ SOURCES += \ src/mbgl/style/conversion/constant.cpp \ src/mbgl/style/conversion/coordinate.cpp \ src/mbgl/style/conversion/filter.cpp \ + src/mbgl/style/conversion/function.cpp \ src/mbgl/style/conversion/geojson.cpp \ src/mbgl/style/conversion/geojson_options.cpp \ src/mbgl/style/conversion/get_json_type.cpp \ @@ -226,8 +229,11 @@ SOURCES += \ src/mbgl/style/expression/check_subtype.cpp \ src/mbgl/style/expression/coalesce.cpp \ src/mbgl/style/expression/coercion.cpp \ + src/mbgl/style/expression/collator_expression.cpp \ src/mbgl/style/expression/compound_expression.cpp \ + src/mbgl/style/expression/dsl.cpp \ src/mbgl/style/expression/equals.cpp \ + src/mbgl/style/expression/expression.cpp \ src/mbgl/style/expression/find_zoom_curve.cpp \ src/mbgl/style/expression/get_covering_stops.cpp \ src/mbgl/style/expression/interpolate.cpp \ @@ -242,10 +248,6 @@ SOURCES += \ src/mbgl/style/expression/util.cpp \ src/mbgl/style/expression/value.cpp \ src/mbgl/style/filter.cpp \ - src/mbgl/style/filter_evaluator.cpp \ - src/mbgl/style/function/categorical_stops.cpp \ - src/mbgl/style/function/expression.cpp \ - src/mbgl/style/function/identity_stops.cpp \ src/mbgl/style/image.cpp \ src/mbgl/style/image_impl.cpp \ src/mbgl/style/layer.cpp \ @@ -307,6 +309,7 @@ SOURCES += \ src/mbgl/text/glyph_atlas.cpp \ src/mbgl/text/glyph_manager.cpp \ src/mbgl/text/glyph_pbf.cpp \ + src/mbgl/text/language_tag.cpp \ src/mbgl/text/placement.cpp \ src/mbgl/text/quads.cpp \ src/mbgl/text/shaping.cpp \ @@ -358,8 +361,9 @@ SOURCES += \ src/mbgl/util/url.cpp \ src/mbgl/util/version.cpp \ src/mbgl/util/work_request.cpp \ - src/parsedate/parsedate.c \ + src/parsedate/parsedate.cpp \ platform/default/asset_file_source.cpp \ + platform/default/collator.cpp \ platform/default/default_file_source.cpp \ platform/default/file_source_request.cpp \ platform/default/local_file_source.cpp \ @@ -369,7 +373,16 @@ SOURCES += \ platform/default/mbgl/storage/offline_download.cpp \ platform/default/mbgl/util/default_thread_pool.cpp \ platform/default/mbgl/util/shared_thread_pool.cpp \ - platform/default/online_file_source.cpp + platform/default/online_file_source.cpp \ + platform/default/unaccent.cpp \ + vendor/nunicode/src/libnu/ducet.c \ + vendor/nunicode/src/libnu/strcoll.c \ + vendor/nunicode/src/libnu/strings.c \ + vendor/nunicode/src/libnu/tolower.c \ + vendor/nunicode/src/libnu/tounaccent.c \ + vendor/nunicode/src/libnu/toupper.c \ + vendor/nunicode/src/libnu/utf8.c + HEADERS += \ platform/qt/include/qmapbox.hpp \ @@ -382,6 +395,7 @@ HEADERS += \ platform/qt/src/qmapboxgl_p.hpp \ platform/qt/src/qmapboxgl_renderer_backend.hpp \ platform/qt/src/qmapboxgl_renderer_observer.hpp \ + platform/qt/src/qmapboxgl_scheduler.hpp \ platform/qt/src/qt_conversion.hpp \ platform/qt/src/qt_geojson.hpp \ platform/qt/src/run_loop_impl.hpp \ @@ -390,22 +404,18 @@ HEADERS += \ INCLUDEPATH += \ deps/boost/1.65.1 \ deps/boost/1.65.1/include \ - deps/cheap-ruler/2.5.3 \ - deps/cheap-ruler/2.5.3/include \ deps/earcut/0.12.4 \ deps/earcut/0.12.4/include \ deps/geojson/0.4.2 \ deps/geojson/0.4.2/include \ - deps/geojsonvt/6.3.0 \ - deps/geojsonvt/6.3.0/include \ - deps/geometry/0.9.2 \ - deps/geometry/0.9.2/include \ + deps/geojsonvt/6.5.1 \ + deps/geojsonvt/6.5.1/include \ + deps/geometry/0.9.3 \ + deps/geometry/0.9.3/include \ deps/kdbush/0.1.1-1 \ deps/kdbush/0.1.1-1/include \ deps/optional/f27e7908 \ deps/optional/f27e7908/include \ - deps/pixelmatch/0.10.0 \ - deps/pixelmatch/0.10.0/include \ deps/polylabel/1.0.3 \ deps/polylabel/1.0.3/include \ deps/protozero/1.5.2 \ @@ -422,15 +432,16 @@ INCLUDEPATH += \ deps/unique_resource/cba309e/include \ deps/variant/1.1.4 \ deps/variant/1.1.4/include \ - deps/vector-tile/1.0.1 \ - deps/vector-tile/1.0.1/include \ + deps/vector-tile/1.0.2 \ + deps/vector-tile/1.0.2/include \ deps/wagyu/0.4.3 \ deps/wagyu/0.4.3/include \ include \ platform/default \ platform/qt \ platform/qt/include \ - src + src \ + vendor/nunicode/include QMAKE_CXXFLAGS += \ - -DMBGL_VERSION_REV=\\\"qt-v1.4.0\\\" + -DMBGL_VERSION_REV=\\\"qt-v1.5.0\\\" diff --git a/platform/default/collator.cpp b/platform/default/collator.cpp new file mode 100644 index 0000000000..b7f256756e --- /dev/null +++ b/platform/default/collator.cpp @@ -0,0 +1,79 @@ +#include <mbgl/style/expression/collator.hpp> +#include <mbgl/util/platform.hpp> +#include <libnu/strcoll.h> +#include <unaccent.hpp> + +/* + The default implementation of Collator ignores locale. + Case sensitivity and collation order are based on + Default Unicode Collation Element Table (DUCET). + + Diacritic-insensitivity is implemented with nunicode's + non-standard "unaccent" functionality, which is tailored + to European languages. + + It would be possible to implement locale awareness using ICU, + but would require bundling locale data. +*/ + +namespace mbgl { +namespace style { +namespace expression { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional<std::string>) + : caseSensitive(caseSensitive_) + , diacriticSensitive(diacriticSensitive_) + {} + + bool operator==(const Impl& other) const { + return caseSensitive == other.caseSensitive && + diacriticSensitive == other.diacriticSensitive; + } + + int compare(const std::string& lhs, const std::string& rhs) const { + if (caseSensitive && diacriticSensitive) { + return nu_strcoll(lhs.c_str(), rhs.c_str(), + nu_utf8_read, nu_utf8_read); + } else if (!caseSensitive && diacriticSensitive) { + return nu_strcasecoll(lhs.c_str(), rhs.c_str(), + nu_utf8_read, nu_utf8_read); + } else if (caseSensitive && !diacriticSensitive) { + return nu_strcoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(), + nu_utf8_read, nu_utf8_read); + } else { + return nu_strcasecoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(), + nu_utf8_read, nu_utf8_read); + } + } + + std::string resolvedLocale() const { + return ""; + } +private: + bool caseSensitive; + bool diacriticSensitive; +}; + + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale_) + : impl(std::make_shared<Impl>(caseSensitive, diacriticSensitive, std::move(locale_))) +{} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index cb602995a4..f070121497 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -11,6 +11,7 @@ #include <mbgl/util/url.hpp> #include <mbgl/util/thread.hpp> #include <mbgl/util/work_request.hpp> +#include <mbgl/util/stopwatch.hpp> #include <cassert> @@ -18,15 +19,10 @@ namespace mbgl { class DefaultFileSource::Impl { public: - Impl(ActorRef<Impl> self, std::shared_ptr<FileSource> assetFileSource_, const std::string& cachePath, uint64_t maximumCacheSize) + Impl(std::shared_ptr<FileSource> assetFileSource_, std::string cachePath, uint64_t maximumCacheSize) : assetFileSource(assetFileSource_) - , localFileSource(std::make_unique<LocalFileSource>()) { - // Initialize the Database asynchronously so as to not block Actor creation. - self.invoke(&Impl::initializeOfflineDatabase, cachePath, maximumCacheSize); - } - - void initializeOfflineDatabase(std::string cachePath, uint64_t maximumCacheSize) { - offlineDatabase = std::make_unique<OfflineDatabase>(cachePath, maximumCacheSize); + , localFileSource(std::make_unique<LocalFileSource>()) + , offlineDatabase(std::make_unique<OfflineDatabase>(cachePath, maximumCacheSize)) { } void setAPIBaseURL(const std::string& url) { @@ -151,8 +147,17 @@ public: // Get from the online file source if (resource.hasLoadingMethod(Resource::LoadingMethod::Network)) { + MBGL_TIMING_START(watch); tasks[req] = onlineFileSource.request(resource, [=] (Response onlineResponse) mutable { this->offlineDatabase->put(resource, onlineResponse); + if (resource.kind == Resource::Kind::Tile) { + // onlineResponse.data will be null if data not modified + MBGL_TIMING_FINISH(watch, + " Action: " << "Requesting," << + " URL: " << resource.url.c_str() << + " Size: " << (onlineResponse.data != nullptr ? onlineResponse.data->size() : 0) << "B," << + " Time") + } callback(onlineResponse); }); } diff --git a/platform/default/http_file_source.cpp b/platform/default/http_file_source.cpp index a9c442c2de..9166d92fb7 100644 --- a/platform/default/http_file_source.cpp +++ b/platform/default/http_file_source.cpp @@ -13,6 +13,85 @@ #include <curl/curl.h> +// Dynamically load all cURL functions. Debian-derived systems upgraded the OpenSSL version linked +// to in https://salsa.debian.org/debian/curl/commit/95c94957bb7e89e36e78b995fed468c42f64d18d +// They state: +// Rename libcurl3 to libcurl4, because libcurl exposes an SSL_CTX via +// CURLOPT_SSL_CTX_FUNCTION, and this object changes incompatibly between +// openssl 1.0 and openssl 1.1. +// Since we are not accessing the underlying OpenSSL context, we don't care whether we're linking +// against libcurl3 or libcurl4; both use the ABI version 4 which hasn't changed since 2006 +// (see https://curl.haxx.se/libcurl/abi.html). In fact, cURL's ABI compatibility is very good as +// shown on https://abi-laboratory.pro/tracker/timeline/curl/ +// Therefore, we're dynamically loading the cURL symbols we need to avoid linking against versioned +// symbols. +#include <dlfcn.h> + +namespace curl { + +#define CURL_FUNCTIONS \ + X(global_init) \ + X(getdate) \ + X(easy_strerror) \ + X(easy_init) \ + X(easy_setopt) \ + X(easy_cleanup) \ + X(easy_getinfo) \ + X(easy_reset) \ + X(multi_init) \ + X(multi_add_handle) \ + X(multi_remove_handle) \ + X(multi_cleanup) \ + X(multi_info_read) \ + X(multi_strerror) \ + X(multi_socket_action) \ + X(multi_setopt) \ + X(share_init) \ + X(share_cleanup) \ + X(slist_append) \ + X(slist_free_all) + +#define X(name) static decltype(&curl_ ## name) name = nullptr; +CURL_FUNCTIONS +#undef X + +static void* handle = nullptr; + +static void* load(const char* name) { + void* symbol = dlsym(handle, name); + if (const char* error = dlerror()) { + fprintf(stderr, "Cannot load symbol '%s': %s\n", name, error); + dlclose(handle); + handle = nullptr; + abort(); + } + return symbol; +} + +__attribute__((constructor)) +static void load() { + assert(!handle); + handle = dlopen("libcurl.so.4", RTLD_LAZY | RTLD_LOCAL); + if (!handle) { + fprintf(stderr, "Could not open shared library '%s'\n", "libcurl.so.4"); + abort(); + } + + #define X(name) name = (decltype(&curl_ ## name))load("curl_" #name); + CURL_FUNCTIONS + #undef X +} + +__attribute__((constructor)) +static void unload() { + if (handle) { + dlclose(handle); + } +} + +} // namespace curl + + #include <queue> #include <map> #include <cassert> @@ -21,13 +100,13 @@ static void handleError(CURLMcode code) { if (code != CURLM_OK) { - throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(code)); + throw std::runtime_error(std::string("CURL multi error: ") + curl::multi_strerror(code)); } } static void handleError(CURLcode code) { if (code != CURLE_OK) { - throw std::runtime_error(std::string("CURL easy error: ") + curl_easy_strerror(code)); + throw std::runtime_error(std::string("CURL easy error: ") + curl::easy_strerror(code)); } } @@ -91,29 +170,29 @@ private: }; HTTPFileSource::Impl::Impl() { - if (curl_global_init(CURL_GLOBAL_ALL)) { + if (curl::global_init(CURL_GLOBAL_ALL)) { throw std::runtime_error("Could not init cURL"); } - share = curl_share_init(); + share = curl::share_init(); - multi = curl_multi_init(); - handleError(curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, handleSocket)); - handleError(curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, this)); - handleError(curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, startTimeout)); - handleError(curl_multi_setopt(multi, CURLMOPT_TIMERDATA, this)); + multi = curl::multi_init(); + handleError(curl::multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, handleSocket)); + handleError(curl::multi_setopt(multi, CURLMOPT_SOCKETDATA, this)); + handleError(curl::multi_setopt(multi, CURLMOPT_TIMERFUNCTION, startTimeout)); + handleError(curl::multi_setopt(multi, CURLMOPT_TIMERDATA, this)); } HTTPFileSource::Impl::~Impl() { while (!handles.empty()) { - curl_easy_cleanup(handles.front()); + curl::easy_cleanup(handles.front()); handles.pop(); } - curl_multi_cleanup(multi); + curl::multi_cleanup(multi); multi = nullptr; - curl_share_cleanup(share); + curl::share_cleanup(share); share = nullptr; timeout.stop(); @@ -125,12 +204,12 @@ CURL *HTTPFileSource::Impl::getHandle() { handles.pop(); return handle; } else { - return curl_easy_init(); + return curl::easy_init(); } } void HTTPFileSource::Impl::returnHandle(CURL *handle) { - curl_easy_reset(handle); + curl::easy_reset(handle); handles.push(handle); } @@ -138,11 +217,11 @@ void HTTPFileSource::Impl::checkMultiInfo() { CURLMsg *message = nullptr; int pending = 0; - while ((message = curl_multi_info_read(multi, &pending))) { + while ((message = curl::multi_info_read(multi, &pending))) { switch (message->msg) { case CURLMSG_DONE: { HTTPRequest *baton = nullptr; - curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&baton); + curl::easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&baton); assert(baton); baton->handleResult(message->data.result); } break; @@ -166,7 +245,7 @@ void HTTPFileSource::Impl::perform(curl_socket_t s, util::RunLoop::Event events) int running_handles = 0; - curl_multi_socket_action(multi, s, flags, &running_handles); + curl::multi_socket_action(multi, s, flags, &running_handles); checkMultiInfo(); } @@ -200,9 +279,9 @@ int HTTPFileSource::Impl::handleSocket(CURL * /* handle */, curl_socket_t s, int void HTTPFileSource::Impl::onTimeout(Impl *context) { int running_handles; - CURLMcode error = curl_multi_socket_action(context->multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); + CURLMcode error = curl::multi_socket_action(context->multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); if (error != CURLM_OK) { - throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(error)); + throw std::runtime_error(std::string("CURL multi error: ") + curl::multi_strerror(error)); } context->checkMultiInfo(); } @@ -233,45 +312,45 @@ HTTPRequest::HTTPRequest(HTTPFileSource::Impl* context_, Resource resource_, Fil // getting a 304 response if possible. This avoids redownloading unchanged data. if (resource.priorEtag) { const std::string header = std::string("If-None-Match: ") + *resource.priorEtag; - headers = curl_slist_append(headers, header.c_str()); + headers = curl::slist_append(headers, header.c_str()); } else if (resource.priorModified) { const std::string time = std::string("If-Modified-Since: ") + util::rfc1123(*resource.priorModified); - headers = curl_slist_append(headers, time.c_str()); + headers = curl::slist_append(headers, time.c_str()); } if (headers) { - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + curl::easy_setopt(handle, CURLOPT_HTTPHEADER, headers); } - handleError(curl_easy_setopt(handle, CURLOPT_PRIVATE, this)); - handleError(curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error)); - handleError(curl_easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt")); - handleError(curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1)); - handleError(curl_easy_setopt(handle, CURLOPT_URL, resource.url.c_str())); - handleError(curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback)); - handleError(curl_easy_setopt(handle, CURLOPT_WRITEDATA, this)); - handleError(curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerCallback)); - handleError(curl_easy_setopt(handle, CURLOPT_HEADERDATA, this)); + handleError(curl::easy_setopt(handle, CURLOPT_PRIVATE, this)); + handleError(curl::easy_setopt(handle, CURLOPT_ERRORBUFFER, error)); + handleError(curl::easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt")); + handleError(curl::easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1)); + handleError(curl::easy_setopt(handle, CURLOPT_URL, resource.url.c_str())); + handleError(curl::easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback)); + handleError(curl::easy_setopt(handle, CURLOPT_WRITEDATA, this)); + handleError(curl::easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerCallback)); + handleError(curl::easy_setopt(handle, CURLOPT_HEADERDATA, this)); #if LIBCURL_VERSION_NUM >= ((7) << 16 | (21) << 8 | 6) // Renamed in 7.21.6 - handleError(curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate")); + handleError(curl::easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate")); #else - handleError(curl_easy_setopt(handle, CURLOPT_ENCODING, "gzip, deflate")); + handleError(curl::easy_setopt(handle, CURLOPT_ENCODING, "gzip, deflate")); #endif - handleError(curl_easy_setopt(handle, CURLOPT_USERAGENT, "MapboxGL/1.0")); - handleError(curl_easy_setopt(handle, CURLOPT_SHARE, context->share)); + handleError(curl::easy_setopt(handle, CURLOPT_USERAGENT, "MapboxGL/1.0")); + handleError(curl::easy_setopt(handle, CURLOPT_SHARE, context->share)); // Start requesting the information. - handleError(curl_multi_add_handle(context->multi, handle)); + handleError(curl::multi_add_handle(context->multi, handle)); } HTTPRequest::~HTTPRequest() { - handleError(curl_multi_remove_handle(context->multi, handle)); + handleError(curl::multi_remove_handle(context->multi, handle)); context->returnHandle(handle); handle = nullptr; if (headers) { - curl_slist_free_all(headers); + curl::slist_free_all(headers); headers = nullptr; } } @@ -320,7 +399,7 @@ size_t HTTPRequest::headerCallback(char *const buffer, const size_t size, const // Always overwrite the modification date; We might already have a value here from the // Date header, but this one is more accurate. const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n - baton->response->modified = Timestamp{ Seconds(curl_getdate(value.c_str(), nullptr)) }; + baton->response->modified = Timestamp{ Seconds(curl::getdate(value.c_str(), nullptr)) }; } else if ((begin = headerMatches("etag: ", buffer, length)) != std::string::npos) { baton->response->etag = std::string(buffer + begin, length - begin - 2); // remove \r\n } else if ((begin = headerMatches("cache-control: ", buffer, length)) != std::string::npos) { @@ -330,7 +409,7 @@ size_t HTTPRequest::headerCallback(char *const buffer, const size_t size, const baton->response->mustRevalidate = cc.mustRevalidate; } else if ((begin = headerMatches("expires: ", buffer, length)) != std::string::npos) { const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n - baton->response->expires = Timestamp{ Seconds(curl_getdate(value.c_str(), nullptr)) }; + baton->response->expires = Timestamp{ Seconds(curl::getdate(value.c_str(), nullptr)) }; } else if ((begin = headerMatches("retry-after: ", buffer, length)) != std::string::npos) { baton->retryAfter = std::string(buffer + begin, length - begin - 2); // remove \r\n } else if ((begin = headerMatches("x-rate-limit-reset: ", buffer, length)) != std::string::npos) { @@ -357,17 +436,17 @@ void HTTPRequest::handleResult(CURLcode code) { case CURLE_OPERATION_TIMEDOUT: response->error = std::make_unique<Error>( - Error::Reason::Connection, std::string{ curl_easy_strerror(code) } + ": " + error); + Error::Reason::Connection, std::string{ curl::easy_strerror(code) } + ": " + error); break; default: response->error = std::make_unique<Error>( - Error::Reason::Other, std::string{ curl_easy_strerror(code) } + ": " + error); + Error::Reason::Other, std::string{ curl::easy_strerror(code) } + ": " + error); break; } } else { long responseCode = 0; - curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode); + curl::easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode); if (responseCode == 200) { if (data) { diff --git a/platform/default/mbgl/map/map_snapshotter.cpp b/platform/default/mbgl/map/map_snapshotter.cpp index 9341c23cfd..565f72930d 100644 --- a/platform/default/mbgl/map/map_snapshotter.cpp +++ b/platform/default/mbgl/map/map_snapshotter.cpp @@ -13,18 +13,21 @@ namespace mbgl { class MapSnapshotter::Impl { public: - Impl(FileSource&, - Scheduler&, - const std::string& styleURL, + Impl(FileSource*, + std::shared_ptr<Scheduler>, + const std::pair<bool, std::string> style, const Size&, const float pixelRatio, - const CameraOptions&, + const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, const optional<std::string> programCacheDir); void setStyleURL(std::string styleURL); std::string getStyleURL() const; + void setStyleJSON(std::string styleJSON); + std::string getStyleJSON() const; + void setSize(Size); Size getSize() const; @@ -37,24 +40,32 @@ public: void snapshot(ActorRef<MapSnapshotter::Callback>); private: + std::shared_ptr<Scheduler> scheduler; HeadlessFrontend frontend; Map map; }; -MapSnapshotter::Impl::Impl(FileSource& fileSource, - Scheduler& scheduler, - const std::string& styleURL, +MapSnapshotter::Impl::Impl(FileSource* fileSource, + std::shared_ptr<Scheduler> scheduler_, + const std::pair<bool, std::string> style, const Size& size, const float pixelRatio, - const CameraOptions& cameraOptions, + const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, const optional<std::string> programCacheDir) - : frontend(size, pixelRatio, fileSource, scheduler, programCacheDir) - , map(frontend, MapObserver::nullObserver(), size, pixelRatio, fileSource, scheduler, MapMode::Static) { - - map.getStyle().loadURL(styleURL); + : scheduler(std::move(scheduler_)) + , frontend(size, pixelRatio, *fileSource, *scheduler, programCacheDir) + , map(frontend, MapObserver::nullObserver(), size, pixelRatio, *fileSource, *scheduler, MapMode::Static) { + + if (style.first) { + map.getStyle().loadJSON(style.second); + } else{ + map.getStyle().loadURL(style.second); + } - map.jumpTo(cameraOptions); + if (cameraOptions) { + map.jumpTo(*cameraOptions); + } // Set region, if specified if (region) { @@ -76,6 +87,15 @@ void MapSnapshotter::Impl::snapshot(ActorRef<MapSnapshotter::Callback> callback) return transform.latLngToScreenCoordinate(unwrappedLatLng); }}; + // Create lambda that captures the current transform state + // and can be used to translate for geographic to screen + // coordinates + assert (frontend.getTransformState()); + LatLngForFn latLngForFn { [=, transformState = *frontend.getTransformState()] (const ScreenCoordinate& screenCoordinate) { + Transform transform { transformState }; + return transform.screenCoordinateToLatLng(screenCoordinate); + }}; + // Collect all source attributions std::vector<std::string> attributions; for (auto source : map.getStyle().getSources()) { @@ -91,7 +111,8 @@ void MapSnapshotter::Impl::snapshot(ActorRef<MapSnapshotter::Callback> callback) error, error ? PremultipliedImage() : frontend.readStillImage(), std::move(attributions), - std::move(pointForFn) + std::move(pointForFn), + std::move(latLngForFn) ); }); } @@ -104,6 +125,14 @@ std::string MapSnapshotter::Impl::getStyleURL() const { return map.getStyle().getURL(); } +void MapSnapshotter::Impl::setStyleJSON(std::string styleJSON) { + map.getStyle().loadJSON(styleJSON); +} + +std::string MapSnapshotter::Impl::getStyleJSON() const { + return map.getStyle().getJSON(); +} + void MapSnapshotter::Impl::setSize(Size size) { map.setSize(size); frontend.setSize(size); @@ -132,15 +161,15 @@ LatLngBounds MapSnapshotter::Impl::getRegion() const { return map.latLngBoundsForCamera(getCameraOptions()); } -MapSnapshotter::MapSnapshotter(FileSource& fileSource, - Scheduler& scheduler, - const std::string& styleURL, +MapSnapshotter::MapSnapshotter(FileSource* fileSource, + std::shared_ptr<Scheduler> scheduler, + const std::pair<bool, std::string> style, const Size& size, const float pixelRatio, - const CameraOptions& cameraOptions, + const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, const optional<std::string> programCacheDir) - : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>("Map Snapshotter", fileSource, scheduler, styleURL, size, pixelRatio, cameraOptions, region, programCacheDir)) { + : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>("Map Snapshotter", fileSource, std::move(scheduler), style, size, pixelRatio, cameraOptions, region, programCacheDir)) { } MapSnapshotter::~MapSnapshotter() = default; @@ -157,6 +186,14 @@ std::string MapSnapshotter::getStyleURL() const { return impl->actor().ask(&Impl::getStyleURL).get(); } +void MapSnapshotter::setStyleJSON(const std::string& styleJSON) { + impl->actor().invoke(&Impl::setStyleJSON, styleJSON); +} + +std::string MapSnapshotter::getStyleJSON() const { + return impl->actor().ask(&Impl::getStyleJSON).get(); +} + void MapSnapshotter::setSize(const Size& size) { impl->actor().invoke(&Impl::setSize, size); } diff --git a/platform/default/mbgl/map/map_snapshotter.hpp b/platform/default/mbgl/map/map_snapshotter.hpp index 985396e5a3..264f74541d 100644 --- a/platform/default/mbgl/map/map_snapshotter.hpp +++ b/platform/default/mbgl/map/map_snapshotter.hpp @@ -25,12 +25,12 @@ class Style; class MapSnapshotter { public: - MapSnapshotter(FileSource& fileSource, - Scheduler& scheduler, - const std::string& styleURL, + MapSnapshotter(FileSource* fileSource, + std::shared_ptr<Scheduler> scheduler, + const std::pair<bool, std::string> style, const Size&, const float pixelRatio, - const CameraOptions&, + const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, const optional<std::string> cacheDir = {}); @@ -39,6 +39,9 @@ public: void setStyleURL(const std::string& styleURL); std::string getStyleURL() const; + void setStyleJSON(const std::string& styleJSON); + std::string getStyleJSON() const; + void setSize(const Size&); Size getSize() const; @@ -49,8 +52,9 @@ public: LatLngBounds getRegion() const; using PointForFn = std::function<ScreenCoordinate (const LatLng&)>; + using LatLngForFn = std::function<LatLng (const ScreenCoordinate&)>; using Attributions = std::vector<std::string>; - using Callback = std::function<void (std::exception_ptr, PremultipliedImage, Attributions, PointForFn)>; + using Callback = std::function<void (std::exception_ptr, PremultipliedImage, Attributions, PointForFn, LatLngForFn)>; void snapshot(ActorRef<Callback>); private: diff --git a/platform/default/mbgl/storage/.clang-tidy b/platform/default/mbgl/storage/.clang-tidy new file mode 100644 index 0000000000..b4ecd26b95 --- /dev/null +++ b/platform/default/mbgl/storage/.clang-tidy @@ -0,0 +1,2 @@ +Checks: 'modernize-*,misc-static-assert,llvm-namespace-comment,-clang-analyzer-security.insecureAPI.rand,-clang-analyzer-core.uninitialized.UndefReturn,-clang-analyzer-core.StackAddressEscape,-clang-analyzer-core.CallAndMessage,-clang-diagnostic-unused-command-line-argument,-clang-analyzer-core.uninitialized.*,-clang-analyzer-core.NullDereference,-clang-analyzer-cplusplus.NewDelete,-clang-analyzer-unix.MismatchedDeallocator,-clang-analyzer-unix.cstring.NullArg,-clang-analyzer-cplusplus.NewDeleteLeaks,-clang-analyzer-unix.Malloc,-clang-analyzer-core.NonNullParamChecker' +HeaderFilterRegex: '\/mbgl\/' diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp index 4611e69f43..8f7f0965f4 100644 --- a/platform/default/mbgl/storage/offline_database.cpp +++ b/platform/default/mbgl/storage/offline_database.cpp @@ -6,6 +6,8 @@ #include <mbgl/util/chrono.hpp> #include <mbgl/util/logging.hpp> +#include "offline_schema.hpp" + #include "sqlite3.hpp" namespace mbgl { @@ -27,58 +29,73 @@ OfflineDatabase::~OfflineDatabase() { } } -void OfflineDatabase::connect(int flags) { - db = std::make_unique<mapbox::sqlite::Database>(path.c_str(), flags); - db->setBusyTimeout(Milliseconds::max()); - db->exec("PRAGMA foreign_keys = ON"); -} - void OfflineDatabase::ensureSchema() { - if (path != ":memory:") { - try { - connect(mapbox::sqlite::ReadWrite); - - switch (userVersion()) { - case 0: break; // cache-only database; ok to delete - case 1: break; // cache-only database; ok to delete - case 2: migrateToVersion3(); // fall through - case 3: // no-op and fall through - case 4: migrateToVersion5(); // fall through - case 5: migrateToVersion6(); // fall through - case 6: return; - default: break; // downgrade, delete the database - } - + auto result = mapbox::sqlite::Database::tryOpen(path, mapbox::sqlite::ReadWriteCreate); + if (result.is<mapbox::sqlite::Exception>()) { + const auto& ex = result.get<mapbox::sqlite::Exception>(); + if (ex.code == mapbox::sqlite::ResultCode::NotADB) { + // Corrupted; blow it away. removeExisting(); - connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create); - } catch (mapbox::sqlite::Exception& ex) { - if (ex.code != mapbox::sqlite::ResultCode::CantOpen && ex.code != mapbox::sqlite::ResultCode::NotADB) { - Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what()); - throw; - } - - try { - if (ex.code == mapbox::sqlite::ResultCode::NotADB) { - removeExisting(); - } - connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create); - } catch (...) { - Log::Error(Event::Database, "Unexpected error creating database: %s", util::toString(std::current_exception()).c_str()); - throw; - } + result = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate); + } else { + Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what()); + throw ex; } } try { - #include "offline_schema.cpp.include" + assert(result.is<mapbox::sqlite::Database>()); + db = std::make_unique<mapbox::sqlite::Database>(std::move(result.get<mapbox::sqlite::Database>())); + db->setBusyTimeout(Milliseconds::max()); + db->exec("PRAGMA foreign_keys = ON"); + + switch (userVersion()) { + case 0: + case 1: + // Newly created database, or old cache-only database; remove old table if it exists. + removeOldCacheTable(); + break; + case 2: + migrateToVersion3(); + // fall through + case 3: + case 4: + migrateToVersion5(); + // fall through + case 5: + migrateToVersion6(); + // fall through + case 6: + // happy path; we're done + return; + default: + // downgrade, delete the database + removeExisting(); + break; + } + } catch (const mapbox::sqlite::Exception& ex) { + // Unfortunately, SQLITE_NOTADB is not always reported upon opening the database. + // Apparently sometimes it is delayed until the first read operation. + if (ex.code == mapbox::sqlite::ResultCode::NotADB) { + removeExisting(); + } else { + throw; + } + } - connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create); + try { + // When downgrading the database, or when the database is corrupt, we've deleted the old database handle, + // so we need to reopen it. + if (!db) { + db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate)); + db->setBusyTimeout(Milliseconds::max()); + db->exec("PRAGMA foreign_keys = ON"); + } - // If you change the schema you must write a migration from the previous version. db->exec("PRAGMA auto_vacuum = INCREMENTAL"); db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); - db->exec(schema); + db->exec(offlineDatabaseSchema); db->exec("PRAGMA user_version = 6"); } catch (...) { Log::Error(Event::Database, "Unexpected error creating database schema: %s", util::toString(std::current_exception()).c_str()); @@ -93,6 +110,7 @@ int OfflineDatabase::userVersion() { void OfflineDatabase::removeExisting() { Log::Warning(Event::Database, "Removing existing incompatible offline database"); + statements.clear(); db.reset(); try { @@ -102,6 +120,11 @@ void OfflineDatabase::removeExisting() { } } +void OfflineDatabase::removeOldCacheTable() { + db->exec("DROP TABLE IF EXISTS http_cache"); + db->exec("VACUUM"); +} + void OfflineDatabase::migrateToVersion3() { db->exec("PRAGMA auto_vacuum = INCREMENTAL"); db->exec("VACUUM"); @@ -160,7 +183,10 @@ optional<int64_t> OfflineDatabase::hasInternal(const Resource& resource) { } std::pair<bool, uint64_t> OfflineDatabase::put(const Resource& resource, const Response& response) { - return putInternal(resource, response, true); + mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate); + auto result = putInternal(resource, response, true); + transaction.commit(); + return result; } std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource, const Response& response, bool evict_) { @@ -179,7 +205,7 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource, } if (evict_ && !evict(size)) { - Log::Debug(Event::Database, "Unable to make space for entry"); + Log::Info(Event::Database, "Unable to make space for entry"); return { false, 0 }; } @@ -277,11 +303,6 @@ bool OfflineDatabase::putResource(const Resource& resource, } // We can't use REPLACE because it would change the id value. - - // Begin an immediate-mode transaction to ensure that two writers do not attempt - // to INSERT a resource at the same moment. - mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate); - // clang-format off mapbox::sqlite::Query updateQuery{ getStatement( "UPDATE resources " @@ -314,7 +335,6 @@ bool OfflineDatabase::putResource(const Resource& resource, updateQuery.run(); if (updateQuery.changes() != 0) { - transaction.commit(); return false; } @@ -341,7 +361,6 @@ bool OfflineDatabase::putResource(const Resource& resource, } insertQuery.run(); - transaction.commit(); return true; } @@ -469,10 +488,6 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, // We can't use REPLACE because it would change the id value. - // Begin an immediate-mode transaction to ensure that two writers do not attempt - // to INSERT a resource at the same moment. - mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate); - // clang-format off mapbox::sqlite::Query updateQuery{ getStatement( "UPDATE tiles " @@ -511,7 +526,6 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, updateQuery.run(); if (updateQuery.changes() != 0) { - transaction.commit(); return false; } @@ -541,7 +555,6 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, } insertQuery.run(); - transaction.commit(); return true; } @@ -624,6 +637,43 @@ optional<int64_t> OfflineDatabase::hasRegionResource(int64_t regionID, const Res } uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& resource, const Response& response) { + mapbox::sqlite::Transaction transaction(*db); + auto size = putRegionResourceInternal(regionID, resource, response); + transaction.commit(); + return size; +} + +void OfflineDatabase::putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>& resources, OfflineRegionStatus& status) { + mapbox::sqlite::Transaction transaction(*db); + + for (const auto& elem : resources) { + const auto& resource = std::get<0>(elem); + const auto& response = std::get<1>(elem); + + try { + uint64_t resourceSize = putRegionResourceInternal(regionID, resource, response); + status.completedResourceCount++; + status.completedResourceSize += resourceSize; + if (resource.kind == Resource::Kind::Tile) { + status.completedTileCount += 1; + status.completedTileSize += resourceSize; + } + } catch (const MapboxTileLimitExceededException&) { + // Commit the rest of the batch and retrow + transaction.commit(); + throw; + } + } + + // Commit the completed batch + transaction.commit(); +} + +uint64_t OfflineDatabase::putRegionResourceInternal(int64_t regionID, const Resource& resource, const Response& response) { + if (exceedsOfflineMapboxTileCountLimit(resource)) { + throw MapboxTileLimitExceededException(); + } + uint64_t size = putInternal(resource, response, false).second; bool previouslyUnused = markUsed(regionID, resource); @@ -894,4 +944,10 @@ uint64_t OfflineDatabase::getOfflineMapboxTileCount() { return *offlineMapboxTileCount; } +bool OfflineDatabase::exceedsOfflineMapboxTileCountLimit(const Resource& resource) { + return resource.kind == Resource::Kind::Tile + && util::mapbox::isMapboxURL(resource.url) + && offlineMapboxTileCountLimitExceeded(); +} + } // namespace mbgl diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp index 9673ad8212..38eb3783ba 100644 --- a/platform/default/mbgl/storage/offline_database.hpp +++ b/platform/default/mbgl/storage/offline_database.hpp @@ -2,6 +2,7 @@ #include <mbgl/storage/resource.hpp> #include <mbgl/storage/offline.hpp> +#include <mbgl/util/exception.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/optional.hpp> #include <mbgl/util/constants.hpp> @@ -10,6 +11,7 @@ #include <unordered_map> #include <memory> #include <string> +#include <list> namespace mapbox { namespace sqlite { @@ -24,6 +26,10 @@ namespace mbgl { class Response; class TileID; +struct MapboxTileLimitExceededException : util::Exception { + MapboxTileLimitExceededException() : util::Exception("Mapbox tile limit exceeded") {} +}; + class OfflineDatabase : private util::noncopyable { public: // Limits affect ambient caching (put) only; resources required by offline @@ -49,6 +55,7 @@ public: optional<std::pair<Response, uint64_t>> getRegionResource(int64_t regionID, const Resource&); optional<int64_t> hasRegionResource(int64_t regionID, const Resource&); uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&); + void putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>&, OfflineRegionStatus&); OfflineRegionDefinition getRegionDefinition(int64_t regionID); OfflineRegionStatus getRegionCompletedStatus(int64_t regionID); @@ -57,12 +64,13 @@ public: uint64_t getOfflineMapboxTileCountLimit(); bool offlineMapboxTileCountLimitExceeded(); uint64_t getOfflineMapboxTileCount(); + bool exceedsOfflineMapboxTileCountLimit(const Resource&); private: - void connect(int flags); int userVersion(); void ensureSchema(); void removeExisting(); + void removeOldCacheTable(); void migrateToVersion3(); void migrateToVersion5(); void migrateToVersion6(); @@ -79,6 +87,8 @@ private: bool putResource(const Resource&, const Response&, const std::string&, bool compressed); + uint64_t putRegionResourceInternal(int64_t regionID, const Resource&, const Response&); + optional<std::pair<Response, uint64_t>> getInternal(const Resource&); optional<int64_t> hasInternal(const Resource&); std::pair<bool, uint64_t> putInternal(const Resource&, const Response&, bool evict); diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index ba504c1f9b..4da51db655 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -330,7 +330,8 @@ void OfflineDownload::ensureResource(const Resource& resource, return; } - if (checkTileCountLimit(resource)) { + if (offlineDatabase.exceedsOfflineMapboxTileCountLimit(resource)) { + onMapboxTileCountLimitExceeded(); return; } @@ -347,17 +348,24 @@ void OfflineDownload::ensureResource(const Resource& resource, callback(onlineResponse); } - status.completedResourceCount++; - uint64_t resourceSize = offlineDatabase.putRegionResource(id, resource, onlineResponse); - status.completedResourceSize += resourceSize; - if (resource.kind == Resource::Kind::Tile) { - status.completedTileCount += 1; - status.completedTileSize += resourceSize; - } + // Queue up for batched insertion + buffer.emplace_back(resource, onlineResponse); - observer->statusChanged(status); + // Flush buffer periodically + if (buffer.size() == 64 || resourcesRemaining.size() == 0) { + try { + offlineDatabase.putRegionResources(id, buffer, status); + } catch (const MapboxTileLimitExceededException&) { + onMapboxTileCountLimitExceeded(); + return; + } - if (checkTileCountLimit(resource)) { + buffer.clear(); + observer->statusChanged(status); + } + + if (offlineDatabase.exceedsOfflineMapboxTileCountLimit(resource)) { + onMapboxTileCountLimitExceeded(); return; } @@ -366,15 +374,9 @@ void OfflineDownload::ensureResource(const Resource& resource, }); } -bool OfflineDownload::checkTileCountLimit(const Resource& resource) { - if (resource.kind == Resource::Kind::Tile && util::mapbox::isMapboxURL(resource.url) && - offlineDatabase.offlineMapboxTileCountLimitExceeded()) { - observer->mapboxTileCountLimitExceeded(offlineDatabase.getOfflineMapboxTileCountLimit()); - setState(OfflineRegionDownloadState::Inactive); - return true; - } - - return false; +void OfflineDownload::onMapboxTileCountLimitExceeded() { + observer->mapboxTileCountLimitExceeded(offlineDatabase.getOfflineMapboxTileCountLimit()); + setState(OfflineRegionDownloadState::Inactive); } } // namespace mbgl diff --git a/platform/default/mbgl/storage/offline_download.hpp b/platform/default/mbgl/storage/offline_download.hpp index 437f221c11..cffac1665b 100644 --- a/platform/default/mbgl/storage/offline_download.hpp +++ b/platform/default/mbgl/storage/offline_download.hpp @@ -46,7 +46,8 @@ private: * is deactivated, all in progress requests are cancelled. */ void ensureResource(const Resource&, std::function<void (Response)> = {}); - bool checkTileCountLimit(const Resource& resource); + + void onMapboxTileCountLimitExceeded(); int64_t id; OfflineRegionDefinition definition; @@ -58,6 +59,7 @@ private: std::list<std::unique_ptr<AsyncRequest>> requests; std::unordered_set<std::string> requiredSourceURLs; std::deque<Resource> resourcesRemaining; + std::list<std::tuple<Resource, Response>> buffer; void queueResource(Resource); void queueTiles(style::SourceType, uint16_t tileSize, const Tileset&); diff --git a/platform/default/mbgl/storage/offline_schema.cpp.include b/platform/default/mbgl/storage/offline_schema.hpp index 41af81e55b..e177d0dbd3 100644 --- a/platform/default/mbgl/storage/offline_schema.cpp.include +++ b/platform/default/mbgl/storage/offline_schema.hpp @@ -1,5 +1,11 @@ -/* THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD */ -static const char * schema = +#pragma once + +// THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD +// To regenerate, run `node platform/default/mbgl/storage/offline_schema.js` + +namespace mbgl { + +static constexpr const char* offlineDatabaseSchema = "CREATE TABLE resources (\n" " id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n" " url TEXT NOT NULL,\n" @@ -53,3 +59,5 @@ static const char * schema = "CREATE INDEX region_tiles_tile_id\n" "ON region_tiles (tile_id);\n" ; + +} // namespace mbgl diff --git a/platform/default/mbgl/storage/offline_schema.js b/platform/default/mbgl/storage/offline_schema.js new file mode 100644 index 0000000000..fdb7dc6405 --- /dev/null +++ b/platform/default/mbgl/storage/offline_schema.js @@ -0,0 +1,21 @@ +var fs = require('fs'); +fs.writeFileSync('platform/default/mbgl/storage/offline_schema.hpp', `#pragma once + +// THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD +// To regenerate, run \`node platform/default/mbgl/storage/offline_schema.js\` + +namespace mbgl { + +static constexpr const char* offlineDatabaseSchema = +${fs.readFileSync('platform/default/mbgl/storage/offline_schema.sql', 'utf8') + .replace(/ *--.*/g, '') + .split('\n') + .filter(a => a) + .map(line => '"' + line + '\\n"') + .join('\n') +} +; + +} // namespace mbgl +`); + diff --git a/platform/default/mbgl/storage/offline_schema.sql b/platform/default/mbgl/storage/offline_schema.sql new file mode 100644 index 0000000000..722b0e0451 --- /dev/null +++ b/platform/default/mbgl/storage/offline_schema.sql @@ -0,0 +1,64 @@ +CREATE TABLE resources ( -- Generic table for style, source, sprite, and glyph resources. + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + url TEXT NOT NULL, + kind INTEGER NOT NULL, + expires INTEGER, + modified INTEGER, + etag TEXT, + data BLOB, + compressed INTEGER NOT NULL DEFAULT 0, + accessed INTEGER NOT NULL, + must_revalidate INTEGER NOT NULL DEFAULT 0, + UNIQUE (url) +); + +CREATE TABLE tiles ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + url_template TEXT NOT NULL, + pixel_ratio INTEGER NOT NULL, + z INTEGER NOT NULL, + x INTEGER NOT NULL, + y INTEGER NOT NULL, + expires INTEGER, + modified INTEGER, + etag TEXT, + data BLOB, + compressed INTEGER NOT NULL DEFAULT 0, + accessed INTEGER NOT NULL, + must_revalidate INTEGER NOT NULL DEFAULT 0, + UNIQUE (url_template, pixel_ratio, z, x, y) +); + +CREATE TABLE regions ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + definition TEXT NOT NULL, -- JSON formatted definition of region. Regions may be of variant types: + -- e.g. bbox and zoom range, route path, flyTo parameters, etc. Note that + -- the set of tiles required for a region may span multiple sources. + description BLOB -- User provided data in user-defined format +); + +CREATE TABLE region_resources ( + region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE, + resource_id INTEGER NOT NULL REFERENCES resources(id), + UNIQUE (region_id, resource_id) +); + +CREATE TABLE region_tiles ( + region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE, + tile_id INTEGER NOT NULL REFERENCES tiles(id), + UNIQUE (region_id, tile_id) +); + +-- Indexes for efficient eviction queries + +CREATE INDEX resources_accessed +ON resources (accessed); + +CREATE INDEX tiles_accessed +ON tiles (accessed); + +CREATE INDEX region_resources_resource_id +ON region_resources (resource_id); + +CREATE INDEX region_tiles_tile_id +ON region_tiles (tile_id); diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp index 8f9c34191f..2e76f6eec4 100644 --- a/platform/default/sqlite3.cpp +++ b/platform/default/sqlite3.cpp @@ -14,27 +14,23 @@ namespace sqlite { class DatabaseImpl { public: - DatabaseImpl(const char* filename, int flags) + DatabaseImpl(sqlite3* db_) + : db(db_) { - const int error = sqlite3_open_v2(filename, &db, flags, nullptr); - if (error != SQLITE_OK) { - const auto message = sqlite3_errmsg(db); - db = nullptr; - throw Exception { error, message }; - } } ~DatabaseImpl() { - if (!db) return; - const int error = sqlite3_close(db); if (error != SQLITE_OK) { mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", sqlite3_errmsg(db), error); } } - sqlite3* db = nullptr; + void setBusyTimeout(std::chrono::milliseconds timeout); + void exec(const std::string& sql); + + sqlite3* db; }; class StatementImpl { @@ -69,84 +65,8 @@ public: template <typename T> using optional = std::experimental::optional<T>; -static const char* codeToString(const int err) { - switch (err) { - case SQLITE_OK: return "SQLITE_OK"; - case SQLITE_ERROR: return "SQLITE_ERROR"; - case SQLITE_INTERNAL: return "SQLITE_INTERNAL"; - case SQLITE_PERM: return "SQLITE_PERM"; - case SQLITE_ABORT: return "SQLITE_ABORT"; - case SQLITE_BUSY: return "SQLITE_BUSY"; - case SQLITE_LOCKED: return "SQLITE_LOCKED"; - case SQLITE_NOMEM: return "SQLITE_NOMEM"; - case SQLITE_READONLY: return "SQLITE_READONLY"; - case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT"; - case SQLITE_IOERR: return "SQLITE_IOERR"; - case SQLITE_CORRUPT: return "SQLITE_CORRUPT"; - case SQLITE_NOTFOUND: return "SQLITE_NOTFOUND"; - case SQLITE_FULL: return "SQLITE_FULL"; - case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN"; - case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL"; - case SQLITE_EMPTY: return "SQLITE_EMPTY"; - case SQLITE_SCHEMA: return "SQLITE_SCHEMA"; - case SQLITE_TOOBIG: return "SQLITE_TOOBIG"; - case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT"; - case SQLITE_MISMATCH: return "SQLITE_MISMATCH"; - case SQLITE_MISUSE: return "SQLITE_MISUSE"; - case SQLITE_NOLFS: return "SQLITE_NOLFS"; - case SQLITE_AUTH: return "SQLITE_AUTH"; - case SQLITE_FORMAT: return "SQLITE_FORMAT"; - case SQLITE_RANGE: return "SQLITE_RANGE"; - case SQLITE_NOTADB: return "SQLITE_NOTADB"; - case SQLITE_NOTICE: return "SQLITE_NOTICE"; - case SQLITE_WARNING: return "SQLITE_WARNING"; - case SQLITE_ROW: return "SQLITE_ROW"; - case SQLITE_DONE: return "SQLITE_DONE"; - default: return "<unknown>"; - } -} - static void errorLogCallback(void *, const int err, const char *msg) { - auto severity = mbgl::EventSeverity::Info; - - switch (err) { - case SQLITE_ERROR: // Generic error - case SQLITE_INTERNAL: // Internal logic error in SQLite - case SQLITE_PERM: // Access permission denied - case SQLITE_ABORT: // Callback routine requested an abort - case SQLITE_BUSY: // The database file is locked - case SQLITE_LOCKED: // A table in the database is locked - case SQLITE_NOMEM: // A malloc() failed - case SQLITE_READONLY: // Attempt to write a readonly database - case SQLITE_INTERRUPT: // Operation terminated by sqlite3_interrupt( - case SQLITE_IOERR: // Some kind of disk I/O error occurred - case SQLITE_CORRUPT: // The database disk image is malformed - case SQLITE_NOTFOUND: // Unknown opcode in sqlite3_file_control() - case SQLITE_FULL: // Insertion failed because database is full - case SQLITE_CANTOPEN: // Unable to open the database file - case SQLITE_PROTOCOL: // Database lock protocol error - case SQLITE_EMPTY: // Internal use only - case SQLITE_SCHEMA: // The database schema changed - case SQLITE_TOOBIG: // String or BLOB exceeds size limit - case SQLITE_CONSTRAINT: // Abort due to constraint violation - case SQLITE_MISMATCH: // Data type mismatch - case SQLITE_MISUSE: // Library used incorrectly - case SQLITE_NOLFS: // Uses OS features not supported on host - case SQLITE_AUTH: // Authorization denied - case SQLITE_FORMAT: // Not used - case SQLITE_RANGE: // 2nd parameter to sqlite3_bind out of range - case SQLITE_NOTADB: // File opened that is not a database file - severity = mbgl::EventSeverity::Error; - break; - case SQLITE_WARNING: // Warnings from sqlite3_log() - severity = mbgl::EventSeverity::Warning; - break; - case SQLITE_NOTICE: // Notifications from sqlite3_log() - default: - break; - } - - mbgl::Log::Record(severity, mbgl::Event::Database, "%s (%s)", msg, codeToString(err)); + mbgl::Log::Record(mbgl::EventSeverity::Info, mbgl::Event::Database, err, "%s", msg); } const static bool sqliteVersionCheck __attribute__((unused)) = []() { @@ -164,11 +84,29 @@ const static bool sqliteVersionCheck __attribute__((unused)) = []() { return true; }(); -Database::Database(const std::string &filename, int flags) - : impl(std::make_unique<DatabaseImpl>(filename.c_str(), flags)) -{ +mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) { + sqlite3* db = nullptr; + const int error = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr); + if (error != SQLITE_OK) { + const auto message = sqlite3_errmsg(db); + return Exception { error, message }; + } + return Database(std::make_unique<DatabaseImpl>(db)); +} + +Database Database::open(const std::string &filename, int flags) { + auto result = tryOpen(filename, flags); + if (result.is<Exception>()) { + throw result.get<Exception>(); + } else { + return std::move(result.get<Database>()); + } } +Database::Database(std::unique_ptr<DatabaseImpl> impl_) + : impl(std::move(impl_)) +{} + Database::Database(Database &&other) : impl(std::move(other.impl)) {} @@ -181,23 +119,31 @@ Database::~Database() = default; void Database::setBusyTimeout(std::chrono::milliseconds timeout) { assert(impl); - const int err = sqlite3_busy_timeout(impl->db, + impl->setBusyTimeout(timeout); +} + +void DatabaseImpl::setBusyTimeout(std::chrono::milliseconds timeout) { + const int err = sqlite3_busy_timeout(db, int(std::min<std::chrono::milliseconds::rep>(timeout.count(), std::numeric_limits<int>::max()))); if (err != SQLITE_OK) { - throw Exception { err, sqlite3_errmsg(impl->db) }; + throw Exception { err, sqlite3_errmsg(db) }; } } void Database::exec(const std::string &sql) { assert(impl); + impl->exec(sql); +} + +void DatabaseImpl::exec(const std::string& sql) { char *msg = nullptr; - const int err = sqlite3_exec(impl->db, sql.c_str(), nullptr, nullptr, &msg); + const int err = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &msg); if (msg) { const std::string message = msg; sqlite3_free(msg); throw Exception { err, message }; } else if (err != SQLITE_OK) { - throw Exception { err, sqlite3_errmsg(impl->db) }; + throw Exception { err, sqlite3_errmsg(db) }; } } @@ -470,16 +416,16 @@ uint64_t Query::changes() const { } Transaction::Transaction(Database& db_, Mode mode) - : db(db_) { + : dbImpl(*db_.impl) { switch (mode) { case Deferred: - db.exec("BEGIN DEFERRED TRANSACTION"); + dbImpl.exec("BEGIN DEFERRED TRANSACTION"); break; case Immediate: - db.exec("BEGIN IMMEDIATE TRANSACTION"); + dbImpl.exec("BEGIN IMMEDIATE TRANSACTION"); break; case Exclusive: - db.exec("BEGIN EXCLUSIVE TRANSACTION"); + dbImpl.exec("BEGIN EXCLUSIVE TRANSACTION"); break; } } @@ -496,12 +442,12 @@ Transaction::~Transaction() { void Transaction::commit() { needRollback = false; - db.exec("COMMIT TRANSACTION"); + dbImpl.exec("COMMIT TRANSACTION"); } void Transaction::rollback() { needRollback = false; - db.exec("ROLLBACK TRANSACTION"); + dbImpl.exec("ROLLBACK TRANSACTION"); } } // namespace sqlite diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp index 20d09b550c..612e92acc6 100644 --- a/platform/default/sqlite3.hpp +++ b/platform/default/sqlite3.hpp @@ -5,18 +5,14 @@ #include <stdexcept> #include <chrono> #include <memory> +#include <mapbox/variant.hpp> namespace mapbox { namespace sqlite { enum OpenFlag : int { - ReadOnly = 0x00000001, - ReadWrite = 0x00000002, - Create = 0x00000004, - NoMutex = 0x00008000, - FullMutex = 0x00010000, - SharedCache = 0x00020000, - PrivateCache = 0x00040000, + ReadOnly = 0b001, + ReadWriteCreate = 0b110, }; enum class ResultCode : int { @@ -68,14 +64,18 @@ class DatabaseImpl; class Statement; class StatementImpl; class Query; +class Transaction; class Database { private: + Database(std::unique_ptr<DatabaseImpl>); Database(const Database &) = delete; Database &operator=(const Database &) = delete; public: - Database(const std::string &filename, int flags = 0); + static mapbox::util::variant<Database, Exception> tryOpen(const std::string &filename, int flags = 0); + static Database open(const std::string &filename, int flags = 0); + Database(Database &&); ~Database(); Database &operator=(Database &&); @@ -87,6 +87,7 @@ private: std::unique_ptr<DatabaseImpl> impl; friend class Statement; + friend class Transaction; }; // A Statement object represents a prepared statement that can be run repeatedly run with a Query object. @@ -169,7 +170,7 @@ public: void rollback(); private: - Database& db; + DatabaseImpl& dbImpl; bool needRollback = true; }; diff --git a/platform/default/string_stdlib.cpp b/platform/default/string_stdlib.cpp index 2642e88aff..103444df1c 100644 --- a/platform/default/string_stdlib.cpp +++ b/platform/default/string_stdlib.cpp @@ -1,8 +1,5 @@ #include <mbgl/util/platform.hpp> -#define NU_WITH_TOUPPER -#define NU_WITH_TOLOWER -#define NU_WITH_UTF8_WRITER -#include <libnu/libnu.h> +#include <libnu/casemap.h> #include <cstring> #include <sstream> diff --git a/platform/default/unaccent.cpp b/platform/default/unaccent.cpp new file mode 100644 index 0000000000..faefb4b4cd --- /dev/null +++ b/platform/default/unaccent.cpp @@ -0,0 +1,43 @@ +#include <mbgl/util/platform.hpp> +#include <libnu/unaccent.h> +#include <unaccent.hpp> + +#include <cstring> +#include <sstream> + +namespace mbgl { namespace platform { + +std::string unaccent(const std::string& str) +{ + std::stringstream output; + char const *itr = str.c_str(), *nitr; + char const *end = itr + str.length(); + char lo[5] = { 0 }; + + for (; itr < end; itr = nitr) + { + uint32_t code_point = 0; + char const* buf = nullptr; + + nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr); + if (buf != nullptr) + { + do + { + buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); + if (code_point == 0) break; + output.write(lo, nu_utf8_write(code_point, lo) - lo); + } + while (code_point != 0); + } + else + { + output.write(itr, nitr - itr); + } + } + + return output.str(); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/default/unaccent.hpp b/platform/default/unaccent.hpp new file mode 100644 index 0000000000..85ac37a7de --- /dev/null +++ b/platform/default/unaccent.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include <string> + +namespace mbgl { +namespace platform { + +// Non-locale-aware diacritic folding based on nunicode +// Used as a fallback when locale-aware comparisons aren't available +std::string unaccent(const std::string &string); + +} // namespace platform +} // namespace mbgl diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp index 79eb672d1f..a699b77cec 100644 --- a/platform/qt/include/qmapboxgl.hpp +++ b/platform/qt/include/qmapboxgl.hpp @@ -236,8 +236,10 @@ public: bool layerExists(const QString &id); void removeLayer(const QString &id); - void setFilter(const QString &layer, const QVariant &filter); + QList<QString> layerIds() const; + void setFilter(const QString &layer, const QVariant &filter); + QVariant getFilter(const QString &layer) const; // When rendering on a different thread, // should be called on the render thread. void createRenderer(); diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 8c3355dc09..09479581bb 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -55,6 +55,10 @@ #include <QString> #include <QStringList> #include <QThreadStorage> +#include <QVariant> +#include <QVariantList> +#include <QVariantMap> +#include <QColor> #include <memory> @@ -703,7 +707,7 @@ double QMapboxGL::scale() const void QMapboxGL::setScale(double scale_, const QPointF ¢er) { - d_ptr->mapObj->setZoom(mbgl::util::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); + d_ptr->mapObj->setZoom(::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); } /*! @@ -1111,7 +1115,7 @@ void QMapboxGL::moveBy(const QPointF &offset) can be used for implementing a pinch gesture. */ void QMapboxGL::scaleBy(double scale_, const QPointF ¢er) { - d_ptr->mapObj->setZoom(d_ptr->mapObj->getZoom() + mbgl::util::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); + d_ptr->mapObj->setZoom(d_ptr->mapObj->getZoom() + ::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); } /*! @@ -1466,6 +1470,23 @@ void QMapboxGL::removeLayer(const QString& id) } /*! + List of all existing layer ids from the current style. +*/ +QList<QString> QMapboxGL::layerIds() const +{ + const auto &layers = d_ptr->mapObj->getStyle().getLayers(); + + QList<QString> layerIds; + layerIds.reserve(layers.size()); + + for (const mbgl::style::Layer *layer : layers) { + layerIds.append(QString::fromStdString(layer->getID())); + } + + return layerIds; +} + +/*! Adds the \a image with the identifier \a id that can be used later by a symbol layer. @@ -1492,7 +1513,7 @@ void QMapboxGL::removeImage(const QString &id) /*! Adds a \a filter to a style \a layer using the format described in the \l - {https://www.mapbox.com/mapbox-gl-style-spec/#types-filter}{Mapbox style specification}. + {https://www.mapbox.com/mapbox-gl-js/style-spec/#other-filter}{Mapbox style specification}. Given a layer \c marker from an arbitrary GeoJSON source containing features of type \b "Point" and \b "LineString", this example shows how to make sure the layer will only tag @@ -1500,14 +1521,14 @@ void QMapboxGL::removeImage(const QString &id) \code QVariantList filterExpression; - filterExpression.append("=="); - filterExpression.append("$type"); - filterExpression.append("Point"); + filterExpression.push_back(QLatin1String("==")); + filterExpression.push_back(QLatin1String("$type")); + filterExpression.push_back(QLatin1String("Point")); QVariantList filter; - filter.append(filterExpression); + filter.push_back(filterExpression); - map->setFilter("marker", filter); + map->setFilter(QLatin1String("marker"), filter); \endcode */ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter) @@ -1555,6 +1576,77 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter) qWarning() << "Layer doesn't support filters"; } +QVariant QVariantFromValue(const mbgl::Value &value) { + return value.match( + [](const mbgl::NullValue) { + return QVariant(); + }, [](const bool value_) { + return QVariant(value_); + }, [](const float value_) { + return QVariant(value_); + }, [](const int64_t value_) { + return QVariant(static_cast<qlonglong>(value_)); + }, [](const double value_) { + return QVariant(value_); + }, [](const std::string &value_) { + return QVariant(value_.c_str()); + }, [](const mbgl::Color &value_) { + return QColor(value_.r, value_.g, value_.b, value_.a); + }, [&](const std::vector<mbgl::Value> &vector) { + QVariantList list; + list.reserve(vector.size()); + for (const auto &value_ : vector) { + list.push_back(QVariantFromValue(value_)); + } + return list; + }, [&](const std::unordered_map<std::string, mbgl::Value> &map) { + QVariantMap varMap; + for (auto &item : map) { + varMap.insert(item.first.c_str(), QVariantFromValue(item.second)); + } + return varMap; + }, [](const auto &) { + return QVariant(); + }); +} + +/*! + Returns the current \a expression-based filter value applied to a style + \layer, if any. + + Filter value types are described in the {https://www.mapbox.com/mapbox-gl-js/style-spec/#types}{Mapbox style specification}. +*/ +QVariant QMapboxGL::getFilter(const QString &layer) const { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Layer* layer_ = d_ptr->mapObj->getStyle().getLayer(layer.toStdString()); + if (!layer_) { + qWarning() << "Layer not found:" << layer; + return QVariant(); + } + + Filter filter_; + + if (layer_->is<FillLayer>()) { + filter_ = layer_->as<FillLayer>()->getFilter(); + } else if (layer_->is<LineLayer>()) { + filter_ = layer_->as<LineLayer>()->getFilter(); + } else if (layer_->is<SymbolLayer>()) { + filter_ = layer_->as<SymbolLayer>()->getFilter(); + } else if (layer_->is<CircleLayer>()) { + filter_ = layer_->as<CircleLayer>()->getFilter(); + } else if (layer_->is<FillExtrusionLayer>()) { + filter_ = layer_->as<FillExtrusionLayer>()->getFilter(); + } else { + qWarning() << "Layer doesn't support filters"; + return QVariant(); + } + + auto serialized = filter_.serialize(); + return QVariantFromValue(serialized); +} + /*! Creates the infrastructure needed for rendering the map. It should be called before any call to render(). diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp index 7a9d1f6f78..acc4194498 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.cpp +++ b/platform/qt/src/qmapboxgl_map_renderer.cpp @@ -1,12 +1,47 @@ #include "qmapboxgl_map_renderer.hpp" +#include "qmapboxgl_scheduler.hpp" +#include <QThreadStorage> #include <QtGlobal> +static bool needsToForceScheduler() { + static QThreadStorage<bool> force; + + if (!force.hasLocalData()) { + force.setLocalData(mbgl::Scheduler::GetCurrent() == nullptr); + } + + return force.localData(); +}; + +static auto *getScheduler() { + static QThreadStorage<std::shared_ptr<QMapboxGLScheduler>> scheduler; + + if (!scheduler.hasLocalData()) { + scheduler.setLocalData(std::make_shared<QMapboxGLScheduler>()); + } + + return scheduler.localData().get(); +}; + QMapboxGLMapRenderer::QMapboxGLMapRenderer(qreal pixelRatio, mbgl::DefaultFileSource &fs, mbgl::ThreadPool &tp, QMapboxGLSettings::GLContextMode mode) : m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio, fs, tp, static_cast<mbgl::GLContextMode>(mode))) - , m_threadWithScheduler(Scheduler::GetCurrent() != nullptr) + , m_forceScheduler(needsToForceScheduler()) { + // If we don't have a Scheduler on this thread, which + // is usually the case for render threads, use a shared + // dummy scheduler that needs to be explicitly forced to + // process events. + if (m_forceScheduler) { + auto scheduler = getScheduler(); + + if (mbgl::Scheduler::GetCurrent() == nullptr) { + mbgl::Scheduler::SetCurrent(scheduler); + } + + connect(scheduler, SIGNAL(needsProcessing()), this, SIGNAL(needsRendering())); + } } QMapboxGLMapRenderer::~QMapboxGLMapRenderer() @@ -14,16 +49,6 @@ QMapboxGLMapRenderer::~QMapboxGLMapRenderer() MBGL_VERIFY_THREAD(tid); } -void QMapboxGLMapRenderer::schedule(std::weak_ptr<mbgl::Mailbox> mailbox) -{ - std::lock_guard<std::mutex> lock(m_taskQueueMutex); - m_taskQueue.push(mailbox); - - // Need to force the main thread to wake - // up this thread and process the events. - emit needsRendering(); -} - void QMapboxGLMapRenderer::updateParameters(std::shared_ptr<mbgl::UpdateParameters> newParameters) { std::lock_guard<std::mutex> lock(m_updateMutex); @@ -57,26 +82,10 @@ void QMapboxGLMapRenderer::render() // The OpenGL implementation automatically enables the OpenGL context for us. mbgl::BackendScope scope(m_backend, mbgl::BackendScope::ScopeType::Implicit); - // If we don't have a Scheduler on this thread, which - // is usually the case for render threads, use this - // object as scheduler. - if (!m_threadWithScheduler) { - Scheduler::SetCurrent(this); - } - m_renderer->render(*params); - if (!m_threadWithScheduler) { - std::queue<std::weak_ptr<mbgl::Mailbox>> taskQueue; - { - std::unique_lock<std::mutex> lock(m_taskQueueMutex); - std::swap(taskQueue, m_taskQueue); - } - - while (!taskQueue.empty()) { - mbgl::Mailbox::maybeReceive(taskQueue.front()); - taskQueue.pop(); - } + if (m_forceScheduler) { + getScheduler()->processEvents(); } } diff --git a/platform/qt/src/qmapboxgl_map_renderer.hpp b/platform/qt/src/qmapboxgl_map_renderer.hpp index adba11de51..0b17542e2f 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.hpp +++ b/platform/qt/src/qmapboxgl_map_renderer.hpp @@ -14,7 +14,6 @@ #include <memory> #include <mutex> -#include <queue> namespace mbgl { class Renderer; @@ -23,7 +22,7 @@ class UpdateParameters; class QMapboxGLRendererBackend; -class QMapboxGLMapRenderer : public QObject, public mbgl::Scheduler +class QMapboxGLMapRenderer : public QObject { Q_OBJECT @@ -32,9 +31,6 @@ public: mbgl::ThreadPool &, QMapboxGLSettings::GLContextMode); virtual ~QMapboxGLMapRenderer(); - // mbgl::Scheduler implementation. - void schedule(std::weak_ptr<mbgl::Mailbox> scheduled) final; - void render(); void updateFramebuffer(quint32 fbo, const mbgl::Size &size); void setObserver(std::shared_ptr<mbgl::RendererObserver>); @@ -56,8 +52,5 @@ private: QMapboxGLRendererBackend m_backend; std::unique_ptr<mbgl::Renderer> m_renderer; - std::mutex m_taskQueueMutex; - std::queue<std::weak_ptr<mbgl::Mailbox>> m_taskQueue; - - bool m_threadWithScheduler; + bool m_forceScheduler; }; diff --git a/platform/qt/src/qmapboxgl_scheduler.cpp b/platform/qt/src/qmapboxgl_scheduler.cpp new file mode 100644 index 0000000000..e2d39703ee --- /dev/null +++ b/platform/qt/src/qmapboxgl_scheduler.cpp @@ -0,0 +1,38 @@ +#include "qmapboxgl_scheduler.hpp" + +#include <mbgl/util/util.hpp> + +#include <cassert> + +QMapboxGLScheduler::QMapboxGLScheduler() +{ +} + +QMapboxGLScheduler::~QMapboxGLScheduler() +{ + MBGL_VERIFY_THREAD(tid); +} + +void QMapboxGLScheduler::schedule(std::weak_ptr<mbgl::Mailbox> mailbox) +{ + std::lock_guard<std::mutex> lock(m_taskQueueMutex); + m_taskQueue.push(mailbox); + + // Need to force the main thread to wake + // up this thread and process the events. + emit needsProcessing(); +} + +void QMapboxGLScheduler::processEvents() +{ + std::queue<std::weak_ptr<mbgl::Mailbox>> taskQueue; + { + std::unique_lock<std::mutex> lock(m_taskQueueMutex); + std::swap(taskQueue, m_taskQueue); + } + + while (!taskQueue.empty()) { + mbgl::Mailbox::maybeReceive(taskQueue.front()); + taskQueue.pop(); + } +} diff --git a/platform/qt/src/qmapboxgl_scheduler.hpp b/platform/qt/src/qmapboxgl_scheduler.hpp new file mode 100644 index 0000000000..68636d0d11 --- /dev/null +++ b/platform/qt/src/qmapboxgl_scheduler.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <mbgl/actor/mailbox.hpp> +#include <mbgl/actor/scheduler.hpp> +#include <mbgl/util/util.hpp> + +#include <QObject> + +#include <memory> +#include <mutex> +#include <queue> + +class QMapboxGLScheduler : public QObject, public mbgl::Scheduler +{ + Q_OBJECT + +public: + QMapboxGLScheduler(); + virtual ~QMapboxGLScheduler(); + + // mbgl::Scheduler implementation. + void schedule(std::weak_ptr<mbgl::Mailbox> scheduled) final; + + void processEvents(); + +signals: + void needsProcessing(); + +private: + MBGL_STORE_THREAD(tid); + + std::mutex m_taskQueueMutex; + std::queue<std::weak_ptr<mbgl::Mailbox>> m_taskQueue; +}; diff --git a/platform/qt/src/qt_geojson.cpp b/platform/qt/src/qt_geojson.cpp index 80377de64d..9d0a3e96eb 100644 --- a/platform/qt/src/qt_geojson.cpp +++ b/platform/qt/src/qt_geojson.cpp @@ -72,10 +72,8 @@ mbgl::Value asMapboxGLPropertyValue(const QVariant &value) { auto valueMap = [](const QVariantMap &map) { std::unordered_map<std::string, mbgl::Value> mbglMap; mbglMap.reserve(map.size()); - auto it = map.constBegin(); - while (it != map.constEnd()) { + for (auto it = map.constBegin(); it != map.constEnd(); ++it) { mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); - ++it; } return mbglMap; }; @@ -132,8 +130,7 @@ mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) { mbgl::PropertyMap properties; properties.reserve(feature.properties.size()); - auto it = feature.properties.constBegin(); - while (it != feature.properties.constEnd()) { + for (auto it = feature.properties.constBegin(); it != feature.properties.constEnd(); ++it) { properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); } diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp index 4bcaea0e31..2ca09fd3ad 100644 --- a/platform/qt/src/sqlite3.cpp +++ b/platform/qt/src/sqlite3.cpp @@ -52,15 +52,6 @@ void checkDatabaseError(const QSqlDatabase &db) { } } -void checkDatabaseOpenError(const QSqlDatabase &db) { - // Assume every error when opening the data as CANTOPEN. Qt - // always returns -1 for `nativeErrorCode()` on database errors. - QSqlError lastError = db.lastError(); - if (lastError.type() != QSqlError::NoError) { - throw Exception { ResultCode::CantOpen, "Error opening the database." }; - } -} - namespace { QString incrementCounter() { static QAtomicInt count = 0; @@ -70,32 +61,9 @@ namespace { class DatabaseImpl { public: - DatabaseImpl(const char* filename, int flags) - : connectionName(QString::number(uint64_t(QThread::currentThread())) + incrementCounter()) + DatabaseImpl(QString connectionName_) + : connectionName(std::move(connectionName_)) { - if (!QSqlDatabase::drivers().contains("QSQLITE")) { - throw Exception { ResultCode::CantOpen, "SQLite driver not found." }; - } - - assert(!QSqlDatabase::contains(connectionName)); - auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName); - - QString connectOptions = db.connectOptions(); - if (flags & OpenFlag::ReadOnly) { - if (!connectOptions.isEmpty()) connectOptions.append(';'); - connectOptions.append("QSQLITE_OPEN_READONLY"); - } - if (flags & OpenFlag::SharedCache) { - if (!connectOptions.isEmpty()) connectOptions.append(';'); - connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE"); - } - - db.setConnectOptions(connectOptions); - db.setDatabaseName(QString(filename)); - - if (!db.open()) { - checkDatabaseOpenError(db); - } } ~DatabaseImpl() { @@ -104,6 +72,9 @@ public: checkDatabaseError(db); } + void setBusyTimeout(std::chrono::milliseconds timeout); + void exec(const std::string& sql); + QString connectionName; }; @@ -127,12 +98,47 @@ public: template <typename T> using optional = std::experimental::optional<T>; +mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) { + if (!QSqlDatabase::drivers().contains("QSQLITE")) { + return Exception { ResultCode::CantOpen, "SQLite driver not found." }; + } -Database::Database(const std::string& file, int flags) - : impl(std::make_unique<DatabaseImpl>(file.c_str(), flags)) { - assert(impl); + QString connectionName = QString::number(uint64_t(QThread::currentThread())) + incrementCounter(); + + assert(!QSqlDatabase::contains(connectionName)); + auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName); + + QString connectOptions = db.connectOptions(); + if (flags & OpenFlag::ReadOnly) { + if (!connectOptions.isEmpty()) connectOptions.append(';'); + connectOptions.append("QSQLITE_OPEN_READONLY"); + } + + db.setConnectOptions(connectOptions); + db.setDatabaseName(QString(filename.c_str())); + + if (!db.open()) { + // Assume every error when opening the data as CANTOPEN. Qt + // always returns -1 for `nativeErrorCode()` on database errors. + return Exception { ResultCode::CantOpen, "Error opening the database." }; + } + + return Database(std::make_unique<DatabaseImpl>(connectionName)); } +Database Database::open(const std::string &filename, int flags) { + auto result = tryOpen(filename, flags); + if (result.is<Exception>()) { + throw result.get<Exception>(); + } else { + return std::move(result.get<Database>()); + } +} + +Database::Database(std::unique_ptr<DatabaseImpl> impl_) + : impl(std::move(impl_)) +{} + Database::Database(Database &&other) : impl(std::move(other.impl)) { assert(impl); @@ -149,12 +155,15 @@ Database::~Database() { void Database::setBusyTimeout(std::chrono::milliseconds timeout) { assert(impl); + impl->setBusyTimeout(timeout); +} +void DatabaseImpl::setBusyTimeout(std::chrono::milliseconds timeout) { // std::chrono::milliseconds.count() is a long and Qt will cast // internally to int, so we need to make sure the limits apply. std::string timeoutStr = mbgl::util::toString(timeout.count() & INT_MAX); - auto db = QSqlDatabase::database(impl->connectionName); + auto db = QSqlDatabase::database(connectionName); QString connectOptions = db.connectOptions(); if (connectOptions.isEmpty()) { if (!connectOptions.isEmpty()) connectOptions.append(';'); @@ -165,19 +174,25 @@ void Database::setBusyTimeout(std::chrono::milliseconds timeout) { } db.setConnectOptions(connectOptions); if (!db.open()) { - checkDatabaseOpenError(db); + // Assume every error when opening the data as CANTOPEN. Qt + // always returns -1 for `nativeErrorCode()` on database errors. + throw Exception { ResultCode::CantOpen, "Error opening the database." }; } } void Database::exec(const std::string &sql) { assert(impl); + impl->exec(sql); +} + +void DatabaseImpl::exec(const std::string& sql) { QStringList statements = QString::fromStdString(sql).split(';', QString::SkipEmptyParts); statements.removeAll("\n"); for (QString statement : statements) { if (!statement.endsWith(';')) { statement.append(';'); } - QSqlQuery query(QSqlDatabase::database(impl->connectionName)); + QSqlQuery query(QSqlDatabase::database(connectionName)); query.prepare(statement); if (!query.exec()) { @@ -424,16 +439,16 @@ uint64_t Query::changes() const { } Transaction::Transaction(Database& db_, Mode mode) - : db(db_) { + : dbImpl(*db_.impl) { switch (mode) { case Deferred: - db.exec("BEGIN DEFERRED TRANSACTION"); + dbImpl.exec("BEGIN DEFERRED TRANSACTION"); break; case Immediate: - db.exec("BEGIN IMMEDIATE TRANSACTION"); + dbImpl.exec("BEGIN IMMEDIATE TRANSACTION"); break; case Exclusive: - db.exec("BEGIN EXCLUSIVE TRANSACTION"); + dbImpl.exec("BEGIN EXCLUSIVE TRANSACTION"); break; } } @@ -450,12 +465,12 @@ Transaction::~Transaction() { void Transaction::commit() { needRollback = false; - db.exec("COMMIT TRANSACTION"); + dbImpl.exec("COMMIT TRANSACTION"); } void Transaction::rollback() { needRollback = false; - db.exec("ROLLBACK TRANSACTION"); + dbImpl.exec("ROLLBACK TRANSACTION"); } } // namespace sqlite diff --git a/qt_attribution.json b/qt_attribution.json index 7ca84ae92b..d56b716a33 100644 --- a/qt_attribution.json +++ b/qt_attribution.json @@ -256,5 +256,18 @@ "LicenseId": "MIT", "License": "MIT License", "Copyright": "Copyright (c) 2010-2015, Angus Johnson, 2016 Mapbox" + }, + { + "Id": "mapboxgl-nunicode", + "Name": "nunicode", + "QDocModule": "qtlocation", + "QtUsage": "Used in the Mapbox GL plugin of Qt Location.", + + "Path": "vendor/nunicode", + "Description": "nunicode is i18n library implementing Unicode 11.0.", + "Homepage": "https://bitbucket.org/alekseyt/nunicode.git", + "LicenseId": "MIT", + "License": "MIT License", + "Copyright": "Copyright (c) 2013 Aleksey Tulinov <aleksey.tulinov@gmail.com>" } ] diff --git a/src/csscolorparser/csscolorparser.cpp b/src/csscolorparser/csscolorparser.cpp index 4d1c6a3d65..106dae6cef 100644 --- a/src/csscolorparser/csscolorparser.cpp +++ b/src/csscolorparser/csscolorparser.cpp @@ -185,7 +185,6 @@ optional<Color> parse(const std::string& css_str) { // Convert to lowercase. std::transform(str.begin(), str.end(), str.begin(), ::tolower); - for (const auto& namedColor : namedColors) { if (str == namedColor.name) { return { namedColor.color }; @@ -262,8 +261,9 @@ optional<Color> parse(const std::string& css_str) { } float h = parseFloat(params[0]) / 360.0f; - while (h < 0.0f) h++; - while (h > 1.0f) h--; + float i; + // Normalize the hue to [0..1[ + h = std::modf(h, &i); // NOTE(deanm): According to the CSS spec s/l should only be // percentages, but we don't bother and let float or percentage. diff --git a/src/mbgl/actor/mailbox.cpp b/src/mbgl/actor/mailbox.cpp index 373c24275f..8ee8dca114 100644 --- a/src/mbgl/actor/mailbox.cpp +++ b/src/mbgl/actor/mailbox.cpp @@ -6,8 +6,30 @@ namespace mbgl { +Mailbox::Mailbox() { +} + Mailbox::Mailbox(Scheduler& scheduler_) - : scheduler(scheduler_) { + : scheduler(&scheduler_) { +} + +void Mailbox::open(Scheduler& scheduler_) { + assert(!scheduler); + + // As with close(), block until neither receive() nor push() are in progress, and acquire the two + // mutexes in the same order. + std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex); + std::lock_guard<std::mutex> pushingLock(pushingMutex); + + scheduler = &scheduler_; + + if (closed) { + return; + } + + if (!queue.empty()) { + (*scheduler)->schedule(shared_from_this()); + } } void Mailbox::close() { @@ -22,6 +44,9 @@ void Mailbox::close() { closed = true; } +bool Mailbox::isOpen() const { return bool(scheduler); } + + void Mailbox::push(std::unique_ptr<Message> message) { std::lock_guard<std::mutex> pushingLock(pushingMutex); @@ -32,13 +57,15 @@ void Mailbox::push(std::unique_ptr<Message> message) { std::lock_guard<std::mutex> queueLock(queueMutex); bool wasEmpty = queue.empty(); queue.push(std::move(message)); - if (wasEmpty) { - scheduler.schedule(shared_from_this()); + if (wasEmpty && scheduler) { + (*scheduler)->schedule(shared_from_this()); } } void Mailbox::receive() { std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex); + + assert(scheduler); if (closed) { return; @@ -58,7 +85,7 @@ void Mailbox::receive() { (*message)(); if (!wasEmpty) { - scheduler.schedule(shared_from_this()); + (*scheduler)->schedule(shared_from_this()); } } diff --git a/src/mbgl/algorithm/covered_by_children.hpp b/src/mbgl/algorithm/covered_by_children.hpp index ad2f1dd5dd..fe5af3f3db 100644 --- a/src/mbgl/algorithm/covered_by_children.hpp +++ b/src/mbgl/algorithm/covered_by_children.hpp @@ -8,15 +8,23 @@ namespace algorithm { template <typename Iterator> bool coveredByChildren(const UnwrappedTileID& id, Iterator it, const Iterator& end) { for (const auto& child : id.children()) { - it = std::lower_bound(it, end, child, [](auto& a, auto& b) { return std::get<0>(a) < b; }); + it = std::lower_bound(it, end, child, [](const auto& a, const auto& b) { return std::get<0>(a) < b; }); + + // Child is not present, neither its grandchildren. if (it == end) { return false; - } else if (std::get<0>(*it) != child) { - return coveredByChildren(child, it, end); + } + + // Child is not present, but its grandchildren are. + if (std::get<0>(*it) != child) { + // This child is not covered by its grandchildren. + if (!coveredByChildren(child, it, end)) { + return false; + } } } - // We looked at all four immediate children and verified that they're covered. + // We looked at all four children (recursively) and verified that they're covered. return true; } diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index b94b0a1bce..41eedf17dc 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -8,6 +8,7 @@ #include <mbgl/style/style_impl.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> +#include <mbgl/style/expression/dsl.hpp> #include <mbgl/storage/file_source.hpp> #include <boost/function_output_iterator.hpp> @@ -160,8 +161,9 @@ void AnnotationManager::updateStyle() { std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID); + using namespace expression::dsl; layer->setSourceLayer(PointLayerID); - layer->setIconImage({SourceID + ".{sprite}"}); + layer->setIconImage(PropertyExpression<std::string>(concat(vec(literal(SourceID + "."), toString(get("sprite")))))); layer->setIconAllowOverlap(true); layer->setIconIgnorePlacement(true); diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index fdd9558d0b..651e3b9c56 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -7,7 +7,6 @@ #include <mbgl/util/math.hpp> #include <mbgl/math/minmax.hpp> #include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/tile/tile_id.hpp> #include <mapbox/geometry/envelope.hpp> @@ -78,11 +77,12 @@ void FeatureIndex::query( } } -std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbolFeatures(const std::vector<IndexedSubfeature>& symbolFeatures, - const RenderedQueryOptions& queryOptions, - const std::vector<const RenderLayer*>& layers, - const OverscaledTileID& tileID, - const std::shared_ptr<std::vector<size_t>>& featureSortOrder) const { +std::unordered_map<std::string, std::vector<Feature>> +FeatureIndex::lookupSymbolFeatures(const std::vector<IndexedSubfeature>& symbolFeatures, + const RenderedQueryOptions& queryOptions, + const std::vector<const RenderLayer*>& layers, + const OverscaledTileID& tileID, + const std::shared_ptr<std::vector<size_t>>& featureSortOrder) const { std::unordered_map<std::string, std::vector<Feature>> result; if (!tileData) { return result; diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 71a855b943..1129bd0b20 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -41,6 +41,10 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte const uint8_t dashheight = 2 * n + 1; const uint8_t offset = 128; + if (dasharray.size() < 2) { + return LinePatternPos(); + } + if (nextRow + dashheight > image.size.height) { Log::Warning(Event::OpenGL, "line atlas bitmap overflow"); return LinePatternPos(); @@ -73,6 +77,9 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte while (right < x / stretch) { left = right; + if (partIndex >= dasharray.size()) { + return LinePatternPos(); + } right = right + dasharray[partIndex]; if (oddLength && partIndex == dasharray.size() - 1) { diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index bb5b2ddc34..b2d05fe665 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -1,14 +1,20 @@ #include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/gl/gl.hpp> namespace mbgl { namespace gl { -void bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { - if (location >= MAX_ATTRIBUTES) { - throw gl::Error("too many vertex attributes"); +void bindAttributeLocation(Context& context, ProgramID id, AttributeLocation location, const char* name) { + // We're using sequentially numberered attribute locations starting with 0. Therefore we can use + // the location as a proxy for the number of attributes. + if (location >= context.maximumVertexBindingCount) { + // Don't bind the location on this hardware since it exceeds the limit (otherwise we'd get + // an OpenGL error). This means we'll see rendering errors, and possibly slow rendering due + // to unbound attributes. + } else { + MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); } - MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); } std::set<std::string> getActiveAttributes(ProgramID id) { diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index fa6c2ddeab..3763f0a583 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -17,8 +17,6 @@ namespace mbgl { namespace gl { -static constexpr std::size_t MAX_ATTRIBUTES = 8; - template <class> struct DataTypeOf; template <> struct DataTypeOf< int8_t> : std::integral_constant<DataType, DataType::Byte> {}; template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {}; @@ -45,7 +43,7 @@ public: } }; -using AttributeBindingArray = std::array<optional<AttributeBinding>, MAX_ATTRIBUTES>; +using AttributeBindingArray = std::vector<optional<AttributeBinding>>; /* gl::Attribute<T,N> manages the binding of a vertex buffer to a GL program attribute. @@ -214,7 +212,8 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { } // namespace detail -void bindAttributeLocation(ProgramID, AttributeLocation, const char * name); +class Context; +void bindAttributeLocation(Context&, ProgramID, AttributeLocation, const char * name); std::set<std::string> getActiveAttributes(ProgramID); template <class... As> @@ -231,13 +230,13 @@ public: using Vertex = detail::Vertex<typename As::Type...>; - static Locations bindLocations(const ProgramID& id) { + static Locations bindLocations(Context& context, const ProgramID& id) { std::set<std::string> activeAttributes = getActiveAttributes(id); AttributeLocation location = 0; auto maybeBindLocation = [&](const char* name) -> optional<AttributeLocation> { if (activeAttributes.count(name)) { - bindAttributeLocation(id, location, name); + bindAttributeLocation(context, id, location, name); return location++; } else { return {}; @@ -277,6 +276,7 @@ public: static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) { AttributeBindingArray result; + result.resize(sizeof...(As)); auto maybeAddBinding = [&] (const optional<AttributeLocation>& location, const optional<AttributeBinding>& binding) { @@ -289,6 +289,12 @@ public: return result; } + + static uint32_t activeBindingCount(const Bindings& bindings) { + uint32_t result = 0; + util::ignore({ ((result += bool(bindings.template get<As>())), 0)... }); + return result; + } }; namespace detail { diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index ba44adb42b..4afbe5af1e 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -94,7 +94,13 @@ static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "Ope static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch"); -Context::Context() = default; +Context::Context() + : maximumVertexBindingCount([] { + GLint value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); + return value; + }()) { +} Context::~Context() { if (cleanupOnDestruction) { @@ -281,7 +287,7 @@ UniqueTexture Context::createTexture() { bool Context::supportsVertexArrays() const { static bool blacklisted = []() { - const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER))); Log::Info(Event::General, "GPU Identifier: %s", renderer.c_str()); @@ -312,7 +318,7 @@ bool Context::supportsProgramBinaries() const { // https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_driver_bug_list.json#2316 // Blacklist Vivante GC4000 due to bugs when linking loaded programs: // https://github.com/mapbox/mapbox-gl-native/issues/10704 - const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER))); if (renderer.find("Adreno (TM) 3") != std::string::npos || renderer.find("Adreno (TM) 4") != std::string::npos || renderer.find("Adreno (TM) 5") != std::string::npos @@ -351,7 +357,7 @@ VertexArray Context::createVertexArray() { VertexArrayID id = 0; MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); UniqueVertexArray vao(std::move(id), { this }); - return { UniqueVertexArrayState(new VertexArrayState(std::move(vao), *this), VertexArrayStateDeleter { true })}; + return { UniqueVertexArrayState(new VertexArrayState(std::move(vao)), VertexArrayStateDeleter { true })}; } else { // On GL implementations which do not support vertex arrays, attribute bindings are global state. // So return a VertexArray which shares our global state tracking and whose deleter is a no-op. diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 67624288e2..c8181d7e80 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -36,10 +36,12 @@ class Debugging; class ProgramBinary; } // namespace extension -class Context : private util::noncopyable { +class Context { public: Context(); ~Context(); + Context(const Context&) = delete; + Context& operator=(const Context& other) = delete; void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&); @@ -226,7 +228,7 @@ public: State<value::BindVertexBuffer> vertexBuffer; State<value::BindVertexArray, const Context&> bindVertexArray { *this }; - VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }), *this }; + VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }) }; State<value::PixelStorePack> pixelStorePack; State<value::PixelStoreUnpack> pixelStoreUnpack; @@ -239,6 +241,8 @@ public: #endif // MBGL_USE_GLES2 bool supportsHalfFloatTextures = false; + const uint32_t maximumVertexBindingCount; + static constexpr const uint32_t minimumRequiredVertexBindingCount = 8; private: State<value::StencilFunc> stencilFunc; diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index af02ad3d54..f33501cd11 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -35,7 +35,7 @@ public: context.createProgram(context.createShader(ShaderType::Vertex, vertexSource), context.createShader(ShaderType::Fragment, fragmentSource))), uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))), - attributeLocations(Attributes::bindLocations(program)) { + attributeLocations(Attributes::bindLocations(context, program)) { // Re-link program after manually binding only active attributes in Attributes::bindLocations context.linkProgram(program); diff --git a/src/mbgl/gl/vertex_array.cpp b/src/mbgl/gl/vertex_array.cpp index 68a500ac45..d552a8292e 100644 --- a/src/mbgl/gl/vertex_array.cpp +++ b/src/mbgl/gl/vertex_array.cpp @@ -9,7 +9,11 @@ void VertexArray::bind(Context& context, BufferID indexBuffer, const AttributeBi context.bindVertexArray = state->vertexArray; state->indexBuffer = indexBuffer; - for (AttributeLocation location = 0; location < MAX_ATTRIBUTES; ++location) { + state->bindings.reserve(bindings.size()); + for (AttributeLocation location = 0; location < bindings.size(); ++location) { + if (state->bindings.size() <= location) { + state->bindings.emplace_back(context, AttributeLocation(location)); + } state->bindings[location] = bindings[location]; } } diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp index 46c67017bb..604754f672 100644 --- a/src/mbgl/gl/vertex_array.hpp +++ b/src/mbgl/gl/vertex_array.hpp @@ -15,9 +15,8 @@ class Context; class VertexArrayState { public: - VertexArrayState(UniqueVertexArray vertexArray_, Context& context) - : vertexArray(std::move(vertexArray_)), - bindings(makeBindings(context, std::make_index_sequence<MAX_ATTRIBUTES>())) { + VertexArrayState(UniqueVertexArray vertexArray_) + : vertexArray(std::move(vertexArray_)) { } void setDirty() { @@ -31,13 +30,7 @@ public: State<value::BindElementBuffer> indexBuffer; using AttributeState = State<value::VertexAttribute, Context&, AttributeLocation>; - std::array<AttributeState, MAX_ATTRIBUTES> bindings; - -private: - template <std::size_t... I> - std::array<AttributeState, MAX_ATTRIBUTES> makeBindings(Context& context, std::index_sequence<I...>) { - return {{ AttributeState { context, I }... }}; - } + std::vector<AttributeState> bindings; }; class VertexArrayStateDeleter { diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 7dfa8edf43..a9b4b929ec 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -11,7 +11,6 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, optional<PositionedIcon> shapedIcon, const SymbolLayoutProperties::Evaluated& layout, const float layoutTextSize, - const uint32_t index_, const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement, @@ -21,19 +20,20 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, const std::array<float, 2> iconOffset_, const GlyphPositionMap& positions, const IndexedSubfeature& indexedFeature, - const std::size_t featureIndex_, + const std::size_t layoutFeatureIndex_, + const std::size_t dataFeatureIndex_, const std::u16string& key_, const float overscaling) : anchor(anchor_), line(line_), - index(index_), hasText(false), hasIcon(shapedIcon), // Create the collision features that will be used to check whether this symbol instance can be placed textCollisionFeature(line_, anchor, shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature, overscaling), iconCollisionFeature(line_, anchor, shapedIcon, iconBoxScale, iconPadding, indexedFeature), - featureIndex(featureIndex_), + layoutFeatureIndex(layoutFeatureIndex_), + dataFeatureIndex(dataFeatureIndex_), textOffset(textOffset_), iconOffset(iconOffset_), key(key_) { diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 827a5dbbdb..ae79311790 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -19,7 +19,6 @@ public: optional<PositionedIcon> shapedIcon, const style::SymbolLayoutProperties::Evaluated&, const float layoutTextSize, - const uint32_t index, const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement, @@ -29,13 +28,13 @@ public: const std::array<float, 2> iconOffset, const GlyphPositionMap&, const IndexedSubfeature&, - const std::size_t featureIndex, + const std::size_t layoutFeatureIndex, + const std::size_t dataFeatureIndex, const std::u16string& key, const float overscaling); Anchor anchor; GeometryCoordinates line; - uint32_t index; bool hasText; bool hasIcon; SymbolQuads horizontalGlyphQuads; @@ -44,7 +43,8 @@ public: CollisionFeature textCollisionFeature; CollisionFeature iconCollisionFeature; WritingModeType writingModes; - std::size_t featureIndex; + std::size_t layoutFeatureIndex; // Index into the set of features included at layout time + std::size_t dataFeatureIndex; // Index into the underlying tile data feature set std::array<float, 2> textOffset; std::array<float, 2> iconOffset; std::u16string key; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index b2f6fd450f..41469f293d 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -2,7 +2,6 @@ #include <mbgl/layout/merge_lines.hpp> #include <mbgl/layout/clip_lines.hpp> #include <mbgl/renderer/buckets/symbol_bucket.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/renderer/bucket_parameters.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/renderer/image_atlas.hpp> @@ -11,7 +10,6 @@ #include <mbgl/text/shaping.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/utf.hpp> -#include <mbgl/util/token.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> @@ -59,7 +57,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, layout = leader.layout.evaluate(PropertyEvaluationParameters(zoom)); if (layout.get<IconRotationAlignment>() == AlignmentType::Auto) { - if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) { + if (layout.get<SymbolPlacement>() != SymbolPlacementType::Point) { layout.get<IconRotationAlignment>() = AlignmentType::Map; } else { layout.get<IconRotationAlignment>() = AlignmentType::Viewport; @@ -67,7 +65,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, } if (layout.get<TextRotationAlignment>() == AlignmentType::Auto) { - if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) { + if (layout.get<SymbolPlacement>() != SymbolPlacementType::Point) { layout.get<TextRotationAlignment>() = AlignmentType::Map; } else { layout.get<TextRotationAlignment>() = AlignmentType::Viewport; @@ -107,31 +105,10 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, ft.index = i; - auto getValue = [&ft](const std::string& key) -> std::string { - auto value = ft.getValue(key); - if (!value) - return std::string(); - if (value->is<std::string>()) - return value->get<std::string>(); - if (value->is<bool>()) - return value->get<bool>() ? "true" : "false"; - if (value->is<int64_t>()) - return util::toString(value->get<int64_t>()); - if (value->is<uint64_t>()) - return util::toString(value->get<uint64_t>()); - if (value->is<double>()) - return util::toString(value->get<double>()); - return "null"; - }; - if (hasText) { std::string u8string = layout.evaluate<TextField>(zoom, ft); - if (layout.get<TextField>().isConstant() && !leader.layout.get<TextField>().isExpression()) { - u8string = util::replaceTokens(u8string, getValue); - } - - auto textTransform = layout.evaluate<TextTransform>(zoom, ft); + auto textTransform = layout.evaluate<TextTransform>(zoom, ft); if (textTransform == TextTransformType::Uppercase) { u8string = platform::uppercase(u8string); } else if (textTransform == TextTransformType::Lowercase) { @@ -140,7 +117,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, ft.text = applyArabicShaping(util::utf8_to_utf16::convert(u8string)); const bool canVerticalizeText = layout.get<TextRotationAlignment>() == AlignmentType::Map - && layout.get<SymbolPlacement>() == SymbolPlacementType::Line + && layout.get<SymbolPlacement>() != SymbolPlacementType::Point && util::i18n::allowsVerticalWritingMode(*ft.text); FontStack fontStack = layout.evaluate<TextFont>(zoom, ft); @@ -158,11 +135,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, } if (hasIcon) { - std::string icon = layout.evaluate<IconImage>(zoom, ft); - if (layout.get<IconImage>().isConstant() && !leader.layout.get<IconImage>().isExpression()) { - icon = util::replaceTokens(icon, getValue); - } - ft.icon = icon; + ft.icon = layout.evaluate<IconImage>(zoom, ft); imageDependencies.insert(*ft.icon); } @@ -183,7 +156,7 @@ bool SymbolLayout::hasSymbolInstances() const { void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, const ImagePositions& imagePositions) { const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && - layout.get<SymbolPlacement>() == SymbolPlacementType::Line; + layout.get<SymbolPlacement>() != SymbolPlacementType::Point; for (auto it = features.begin(); it != features.end(); ++it) { auto& feature = *it; @@ -208,7 +181,7 @@ void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyph const float oneEm = 24.0f; const Shaping result = getShaping( /* string */ text, - /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ? + /* maxWidth: ems */ layout.get<SymbolPlacement>() == SymbolPlacementType::Point ? layout.evaluate<TextMaxWidth>(zoom, feature) * oneEm : 0, /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm, /* anchor */ layout.evaluate<TextAnchor>(zoom, feature), @@ -261,7 +234,7 @@ void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyph compareText.clear(); } -void SymbolLayout::addFeature(const std::size_t index, +void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const SymbolFeature& feature, const std::pair<Shaping, Shaping>& shapedTextOrientations, optional<PositionedIcon> shapedIcon, @@ -285,6 +258,10 @@ void SymbolLayout::addFeature(const std::size_t index, const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize; const float iconBoxScale = tilePixelRatio * layoutIconSize; const float symbolSpacing = tilePixelRatio * layout.get<SymbolSpacing>(); + // CJL: I'm not sure why SymbolPlacementType::Line -> avoidEdges = false. It seems redundant since + // getAnchors will already avoid generating anchors outside the tile bounds. + // However, SymbolPlacementType::LineCenter allows anchors outside tile boundaries, so its behavior + // here should match SymbolPlacement::Point const bool avoidEdges = layout.get<SymbolAvoidEdges>() && layout.get<SymbolPlacement>() != SymbolPlacementType::Line; const float textPadding = layout.get<TextPadding>() * tilePixelRatio; const float iconPadding = layout.get<IconPadding>() * tilePixelRatio; @@ -318,10 +295,9 @@ void SymbolLayout::addFeature(const std::size_t index, if (mode == MapMode::Tile || withinPlus0) { symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout.evaluate(zoom, feature), layoutTextSize, - symbolInstances.size(), textBoxScale, textPadding, textPlacement, textOffset, iconBoxScale, iconPadding, iconOffset, - glyphPositionMap, indexedFeature, index, feature.text.value_or(std::u16string()), overscaling); + glyphPositionMap, indexedFeature, layoutFeatureIndex, feature.index, feature.text.value_or(std::u16string()), overscaling); } }; @@ -347,6 +323,24 @@ void SymbolLayout::addFeature(const std::size_t index, } } } + } else if (layout.get<SymbolPlacement>() == SymbolPlacementType::LineCenter) { + // No clipping, multiple lines per feature are allowed + // "lines" with only one point are ignored as in clipLines + for (const auto& line : feature.geometry) { + if (line.size() > 1) { + optional<Anchor> anchor = getCenterAnchor(line, + textMaxAngle, + (shapedTextOrientations.second ?: shapedTextOrientations.first).left, + (shapedTextOrientations.second ?: shapedTextOrientations.first).right, + (shapedIcon ? shapedIcon->left() : 0), + (shapedIcon ? shapedIcon->right() : 0), + glyphSize, + textMaxBoxScale); + if (anchor) { + addSymbolInstance(line, *anchor); + } + } + } } else if (type == FeatureType::Polygon) { for (const auto& polygon : classifyRings(feature.geometry)) { Polygon<double> poly; @@ -427,7 +421,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(const bool showCollisionBoxes) const bool hasText = symbolInstance.hasText; const bool hasIcon = symbolInstance.hasIcon; - const auto& feature = features.at(symbolInstance.featureIndex); + const auto& feature = features.at(symbolInstance.layoutFeatureIndex); // Insert final placement into collision tree and add glyphs/icons to buffers diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index d81544eed5..c177299485 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -364,13 +364,13 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const EdgeInsets& pad impl->onUpdate(); } -CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding, optional<double> bearing) const { +CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding, optional<double> bearing, optional<double> pitch) const { return cameraForLatLngs({ bounds.northwest(), bounds.southwest(), bounds.southeast(), bounds.northeast(), - }, padding, bearing); + }, padding, bearing, pitch); } CameraOptions cameraForLatLngs(const std::vector<LatLng>& latLngs, const Transform& transform, const EdgeInsets& padding) { @@ -402,7 +402,7 @@ CameraOptions cameraForLatLngs(const std::vector<LatLng>& latLngs, const Transfo scaleY -= (padding.top() + padding.bottom()) / height; minScale = util::min(scaleX, scaleY); } - double zoom = transform.getZoom() + util::log2(minScale); + double zoom = transform.getZoom() + ::log2(minScale); zoom = util::clamp(zoom, transform.getState().getMinZoom(), transform.getState().getMaxZoom()); // Calculate the center point of a virtual bounds that is extended in all directions by padding. @@ -426,26 +426,37 @@ CameraOptions cameraForLatLngs(const std::vector<LatLng>& latLngs, const Transfo return options; } -CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const EdgeInsets& padding, optional<double> bearing) const { - if(bearing) { - double angle = -*bearing * util::DEG2RAD; // Convert to radians - Transform transform(impl->transform.getState()); - transform.setAngle(angle); - CameraOptions options = mbgl::cameraForLatLngs(latLngs, transform, padding); - options.angle = angle; - return options; - } else { +CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const EdgeInsets& padding, optional<double> bearing, optional<double> pitch) const { + + if (!bearing && !pitch) { return mbgl::cameraForLatLngs(latLngs, impl->transform, padding); } + + Transform transform(impl->transform.getState()); + + if (bearing) { + double angle = -*bearing * util::DEG2RAD; // Convert to radians + transform.setAngle(angle); + } + if (pitch) { + double pitchAsRadian = *pitch * util::DEG2RAD; // Convert to radians + transform.setPitch(pitchAsRadian); + } + + CameraOptions options = mbgl::cameraForLatLngs(latLngs, transform, padding); + options.angle = transform.getAngle(); + options.pitch = transform.getPitch(); + + return options; } -CameraOptions Map::cameraForGeometry(const Geometry<double>& geometry, const EdgeInsets& padding, optional<double> bearing) const { +CameraOptions Map::cameraForGeometry(const Geometry<double>& geometry, const EdgeInsets& padding, optional<double> bearing, optional<double> pitch) const { std::vector<LatLng> latLngs; forEachPoint(geometry, [&](const Point<double>& pt) { latLngs.push_back({ pt.y, pt.x }); }); - return cameraForLatLngs(latLngs, padding, bearing); + return cameraForLatLngs(latLngs, padding, bearing, pitch); } LatLngBounds Map::latLngBoundsForCamera(const CameraOptions& camera) const { diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 105adf0400..da8e243d91 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -594,13 +594,10 @@ void Transform::startTransition(const CameraOptions& camera, animation.transitionFrameFn(t); } observer.onCameraIsChanging(); + return false; } else { - transitionFinishFn(); - transitionFinishFn = nullptr; - - // This callback gets destroyed here, - // we can only return after this point. - transitionFrameFn = nullptr; + // Indicate that we need to terminate this transition + return true; } }; @@ -615,7 +612,14 @@ void Transform::startTransition(const CameraOptions& camera, }; if (!isAnimated) { - transitionFrameFn(Clock::now()); + auto update = std::move(transitionFrameFn); + auto finish = std::move(transitionFinishFn); + + transitionFrameFn = nullptr; + transitionFinishFn = nullptr; + + update(Clock::now()); + finish(); } } @@ -624,8 +628,43 @@ bool Transform::inTransition() const { } void Transform::updateTransitions(const TimePoint& now) { - if (transitionFrameFn) { - transitionFrameFn(now); + + // Use a temporary function to ensure that the transitionFrameFn lambda is + // called only once per update. + + // This addresses the symptoms of https://github.com/mapbox/mapbox-gl-native/issues/11180 + // where setting a shape source to nil (or similar) in the `onCameraIsChanging` + // observer function causes `Map::Impl::onUpdate()` to be called which + // in turn calls this function (before the current iteration has completed), + // leading to an infinite loop. See https://github.com/mapbox/mapbox-gl-native/issues/5833 + // for a similar, related, issue. + // + // By temporarily nulling the `transitionFrameFn` (and then restoring it + // after the temporary has been called) we stop this recursion. + // + // It's important to note that the scope of this change is stop the above + // crashes. It doesn't address any potential deeper issue (for example + // user error, how often and when transition callbacks are called). + + auto transition = std::move(transitionFrameFn); + transitionFrameFn = nullptr; + + if (transition && transition(now)) { + // If the transition indicates that it is complete, then we should call + // the finish lambda (going via a temporary as above) + auto finish = std::move(transitionFinishFn); + + transitionFinishFn = nullptr; + transitionFrameFn = nullptr; + + if (finish) { + finish(); + } + } else if (!transitionFrameFn) { + // We have to check `transitionFrameFn` is nil here, since a new transition + // may have been triggered in a user callback (from the transition call + // above) + transitionFrameFn = std::move(transition); } } diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index d429c57661..bff44a2dcd 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -165,7 +165,7 @@ private: TimePoint transitionStart; Duration transitionDuration; - std::function<void(const TimePoint)> transitionFrameFn; + std::function<bool(const TimePoint)> transitionFrameFn; std::function<void()> transitionFinishFn; }; diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index a85b251fb4..948954570f 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -270,7 +270,7 @@ double TransformState::zoomScale(double zoom) const { } double TransformState::scaleZoom(double s) const { - return util::log2(s); + return ::log2(s); } ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const { @@ -280,7 +280,7 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) mat4 mat = coordinatePointMatrix(getZoom()); vec4 p; - Point<double> pt = Projection::project(latLng, scale) / double(util::tileSize); + Point<double> pt = Projection::project(latLng, scale) / util::tileSize; vec4 c = {{ pt.x, pt.y, 0, 1 }}; matrix::transformMat4(p, c, mat); return { p[0] / p[3], size.height - p[1] / p[3] }; @@ -427,7 +427,7 @@ float TransformState::maxPitchScaleFactor() const { } auto latLng = screenCoordinateToLatLng({ 0, static_cast<float>(getSize().height) }); mat4 mat = coordinatePointMatrix(getZoom()); - Point<double> pt = Projection::project(latLng, scale) / double(util::tileSize); + Point<double> pt = Projection::project(latLng, scale) / util::tileSize; vec4 p = {{ pt.x, pt.y, 0, 1 }}; vec4 topPoint; matrix::transformMat4(topPoint, p, mat); diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index bcdb270b9c..4d5de05337 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -46,26 +46,38 @@ public: Shaders::fragmentSource)) { } + static typename AllUniforms::Values computeAllUniformValues( + const UniformValues& uniformValues, + const PaintPropertyBinders& paintPropertyBinders, + const typename PaintProperties::PossiblyEvaluated& currentProperties, + float currentZoom) { + return uniformValues + .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); + } + + static typename Attributes::Bindings computeAllAttributeBindings( + const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer, + const PaintPropertyBinders& paintPropertyBinders, + const typename PaintProperties::PossiblyEvaluated& currentProperties) { + return LayoutAttributes::bindings(layoutVertexBuffer) + .concat(paintPropertyBinders.attributeBindings(currentProperties)); + } + + static uint32_t activeBindingCount(const typename Attributes::Bindings& allAttributeBindings) { + return Attributes::activeBindingCount(allAttributeBindings); + } + template <class DrawMode> void draw(gl::Context& context, DrawMode drawMode, gl::DepthMode depthMode, gl::StencilMode stencilMode, gl::ColorMode colorMode, - const UniformValues& uniformValues, - const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer, const gl::IndexBuffer<DrawMode>& indexBuffer, const SegmentVector<Attributes>& segments, - const PaintPropertyBinders& paintPropertyBinders, - const typename PaintProperties::PossiblyEvaluated& currentProperties, - float currentZoom, + const typename AllUniforms::Values& allUniformValues, + const typename Attributes::Bindings& allAttributeBindings, const std::string& layerID) { - typename AllUniforms::Values allUniformValues = uniformValues - .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); - - typename Attributes::Bindings allAttributeBindings = LayoutAttributes::bindings(layoutVertexBuffer) - .concat(paintPropertyBinders.attributeBindings(currentProperties)); - for (auto& segment : segments) { auto vertexArrayIt = segment.vertexArrays.find(layerID); diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 84a7a53f1d..07d07ff0dd 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -17,14 +17,20 @@ std::unique_ptr<SymbolSizeBinder> SymbolSizeBinder::create(const float tileZoom, const style::DataDrivenPropertyValue<float>& sizeProperty, const float defaultValue) { return sizeProperty.match( - [&] (const style::CompositeFunction<float>& function) -> std::unique_ptr<SymbolSizeBinder> { - return std::make_unique<CompositeFunctionSymbolSizeBinder>(tileZoom, function, defaultValue); - }, - [&] (const style::SourceFunction<float>& function) { - return std::make_unique<SourceFunctionSymbolSizeBinder>(tileZoom, function, defaultValue); + [&] (const Undefined& value) -> std::unique_ptr<SymbolSizeBinder> { + return std::make_unique<ConstantSymbolSizeBinder>(tileZoom, value, defaultValue); }, - [&] (const auto& value) -> std::unique_ptr<SymbolSizeBinder> { + [&] (float value) -> std::unique_ptr<SymbolSizeBinder> { return std::make_unique<ConstantSymbolSizeBinder>(tileZoom, value, defaultValue); + }, + [&] (const style::PropertyExpression<float>& expression) -> std::unique_ptr<SymbolSizeBinder> { + if (expression.isFeatureConstant()) { + return std::make_unique<ConstantSymbolSizeBinder>(tileZoom, expression, defaultValue); + } else if (expression.isZoomConstant()) { + return std::make_unique<SourceFunctionSymbolSizeBinder>(tileZoom, expression, defaultValue); + } else { + return std::make_unique<CompositeFunctionSymbolSizeBinder>(tileZoom, expression, defaultValue); + } } ); } @@ -88,7 +94,6 @@ Values makeValues(const bool isText, uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() }, uniforms::u_pitch::Value{ state.getPitch() }, uniforms::u_pitch_with_map::Value{ pitchWithMap }, - uniforms::u_max_camera_distance::Value{ values.maxCameraDistance }, uniforms::u_rotate_symbol::Value{ rotateInShader }, uniforms::u_aspect_ratio::Value{ state.getSize().aspectRatio() }, std::forward<Args>(args)... diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 9b5037ed9f..653fce9d4c 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -41,7 +41,6 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_max_camera_distance); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_symbol); MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); } // namespace uniforms @@ -143,13 +142,13 @@ public: ConstantSymbolSizeBinder(const float /*tileZoom*/, const style::Undefined&, const float defaultValue) : layoutSize(defaultValue) {} - ConstantSymbolSizeBinder(const float tileZoom, const style::CameraFunction<float>& function_, const float /*defaultValue*/) - : layoutSize(function_.evaluate(tileZoom + 1)), - function(function_) { - const Range<float> zoomLevels = function_.getCoveringStops(tileZoom, tileZoom + 1); + ConstantSymbolSizeBinder(const float tileZoom, const style::PropertyExpression<float>& expression_, const float /*defaultValue*/) + : layoutSize(expression_.evaluate(tileZoom + 1)), + expression(expression_) { + const Range<float> zoomLevels = expression_.getCoveringStops(tileZoom, tileZoom + 1); coveringRanges = std::make_tuple( zoomLevels, - Range<float> { function_.evaluate(zoomLevels.min), function_.evaluate(zoomLevels.max) } + Range<float> { expression_.evaluate(zoomLevels.min), expression_.evaluate(zoomLevels.max) } ); } @@ -157,7 +156,7 @@ public: ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override { float size = layoutSize; - bool isZoomConstant = !(coveringRanges || function); + bool isZoomConstant = !(coveringRanges || expression); if (coveringRanges) { // Even though we could get the exact value of the camera function // at z = currentZoom, we intentionally do not: instead, we interpolate @@ -167,12 +166,12 @@ public: const Range<float>& zoomLevels = std::get<0>(*coveringRanges); const Range<float>& sizeLevels = std::get<1>(*coveringRanges); float t = util::clamp( - function->interpolationFactor(zoomLevels, currentZoom), + expression->interpolationFactor(zoomLevels, currentZoom), 0.0f, 1.0f ); size = sizeLevels.min + t * (sizeLevels.max - sizeLevels.min); - } else if (function) { - size = function->evaluate(currentZoom); + } else if (expression) { + size = expression->evaluate(currentZoom); } const float unused = 0.0f; @@ -181,7 +180,7 @@ public: float layoutSize; optional<std::tuple<Range<float>, Range<float>>> coveringRanges; - optional<style::CameraFunction<float>> function; + optional<style::PropertyExpression<float>> expression; }; class SourceFunctionSymbolSizeBinder final : public SymbolSizeBinder { @@ -190,13 +189,13 @@ public: using VertexVector = gl::VertexVector<Vertex>; using VertexBuffer = gl::VertexBuffer<Vertex>; - SourceFunctionSymbolSizeBinder(const float /*tileZoom*/, const style::SourceFunction<float>& function_, const float defaultValue_) - : function(function_), + SourceFunctionSymbolSizeBinder(const float /*tileZoom*/, style::PropertyExpression<float> expression_, const float defaultValue_) + : expression(std::move(expression_)), defaultValue(defaultValue_) { } Range<float> getVertexSizeData(const GeometryTileFeature& feature) override { - const float size = function.evaluate(feature, defaultValue); + const float size = expression.evaluate(feature, defaultValue); return { size, size }; }; @@ -205,30 +204,30 @@ public: return { true, false, unused, unused, unused }; } - style::SourceFunction<float> function; + style::PropertyExpression<float> expression; const float defaultValue; }; class CompositeFunctionSymbolSizeBinder final : public SymbolSizeBinder { public: - CompositeFunctionSymbolSizeBinder(const float tileZoom, const style::CompositeFunction<float>& function_, const float defaultValue_) - : function(function_), + CompositeFunctionSymbolSizeBinder(const float tileZoom, style::PropertyExpression<float> expression_, const float defaultValue_) + : expression(std::move(expression_)), defaultValue(defaultValue_), layoutZoom(tileZoom + 1), - coveringZoomStops(function.getCoveringStops(tileZoom, tileZoom + 1)) + coveringZoomStops(expression.getCoveringStops(tileZoom, tileZoom + 1)) {} Range<float> getVertexSizeData(const GeometryTileFeature& feature) override { return { - function.evaluate(coveringZoomStops.min, feature, defaultValue), - function.evaluate(coveringZoomStops.max, feature, defaultValue) + expression.evaluate(coveringZoomStops.min, feature, defaultValue), + expression.evaluate(coveringZoomStops.max, feature, defaultValue) }; }; ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override { float sizeInterpolationT = util::clamp( - function.interpolationFactor(coveringZoomStops, currentZoom), + expression.interpolationFactor(coveringZoomStops, currentZoom), 0.0f, 1.0f ); @@ -236,7 +235,7 @@ public: return { false, false, sizeInterpolationT, unused, unused }; } - style::CompositeFunction<float> function; + style::PropertyExpression<float> expression; const float defaultValue; float layoutZoom; Range<float> coveringZoomStops; @@ -278,35 +277,45 @@ public: Shaders::fragmentSource)) { } + static typename AllUniforms::Values computeAllUniformValues( + const UniformValues& uniformValues, + const SymbolSizeBinder& symbolSizeBinder, + const PaintPropertyBinders& paintPropertyBinders, + const typename PaintProperties::PossiblyEvaluated& currentProperties, + float currentZoom) { + return uniformValues.concat(symbolSizeBinder.uniformValues(currentZoom)) + .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); + } + + static typename Attributes::Bindings computeAllAttributeBindings( + const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer, + const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>& dynamicLayoutVertexBuffer, + const gl::VertexBuffer<SymbolOpacityAttributes::Vertex>& opacityVertexBuffer, + const PaintPropertyBinders& paintPropertyBinders, + const typename PaintProperties::PossiblyEvaluated& currentProperties) { + assert(layoutVertexBuffer.vertexCount == dynamicLayoutVertexBuffer.vertexCount && + layoutVertexBuffer.vertexCount == opacityVertexBuffer.vertexCount); + return LayoutAttributes::bindings(layoutVertexBuffer) + .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer)) + .concat(SymbolOpacityAttributes::bindings(opacityVertexBuffer)) + .concat(paintPropertyBinders.attributeBindings(currentProperties)); + } + + static uint32_t activeBindingCount(const typename Attributes::Bindings& allAttributeBindings) { + return Attributes::activeBindingCount(allAttributeBindings); + } + template <class DrawMode> void draw(gl::Context& context, DrawMode drawMode, gl::DepthMode depthMode, gl::StencilMode stencilMode, gl::ColorMode colorMode, - const UniformValues& uniformValues, - const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer, - const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>& dynamicLayoutVertexBuffer, - const gl::VertexBuffer<SymbolOpacityAttributes::Vertex>& opacityVertexBuffer, - const SymbolSizeBinder& symbolSizeBinder, const gl::IndexBuffer<DrawMode>& indexBuffer, const SegmentVector<Attributes>& segments, - const PaintPropertyBinders& paintPropertyBinders, - const typename PaintProperties::PossiblyEvaluated& currentProperties, - float currentZoom, + const typename AllUniforms::Values& allUniformValues, + const typename Attributes::Bindings& allAttributeBindings, const std::string& layerID) { - typename AllUniforms::Values allUniformValues = uniformValues - .concat(symbolSizeBinder.uniformValues(currentZoom)) - .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)); - - typename Attributes::Bindings allAttributeBindings = LayoutAttributes::bindings(layoutVertexBuffer) - .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer)) - .concat(SymbolOpacityAttributes::bindings(opacityVertexBuffer)) - .concat(paintPropertyBinders.attributeBindings(currentProperties)); - - assert(layoutVertexBuffer.vertexCount == dynamicLayoutVertexBuffer.vertexCount && - layoutVertexBuffer.vertexCount == opacityVertexBuffer.vertexCount); - for (auto& segment : segments) { auto vertexArrayIt = segment.vertexArrays.find(layerID); @@ -346,7 +355,6 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_camera_to_center_distance, uniforms::u_pitch, uniforms::u_pitch_with_map, - uniforms::u_max_camera_distance, uniforms::u_rotate_symbol, uniforms::u_aspect_ratio>, style::IconPaintProperties> @@ -386,7 +394,6 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_camera_to_center_distance, uniforms::u_pitch, uniforms::u_pitch_with_map, - uniforms::u_max_camera_distance, uniforms::u_rotate_symbol, uniforms::u_aspect_ratio, uniforms::u_gamma_scale, @@ -408,8 +415,7 @@ public: uniforms::u_is_text, uniforms::u_camera_to_center_distance, uniforms::u_pitch, - uniforms::u_pitch_with_map, - uniforms::u_max_camera_distance, + uniforms::u_pitch_with_map, uniforms::u_rotate_symbol, uniforms::u_aspect_ratio, uniforms::u_gamma_scale, diff --git a/src/mbgl/renderer/backend_scope.cpp b/src/mbgl/renderer/backend_scope.cpp index fafeaabb39..ad430961aa 100644 --- a/src/mbgl/renderer/backend_scope.cpp +++ b/src/mbgl/renderer/backend_scope.cpp @@ -4,12 +4,20 @@ #include <cassert> -namespace mbgl { +namespace { + +mbgl::util::ThreadLocal<mbgl::BackendScope>& currentScope() { + static mbgl::util::ThreadLocal<mbgl::BackendScope> backendScope; + + return backendScope; +} + +} // namespace -static util::ThreadLocal<BackendScope> currentScope; +namespace mbgl { BackendScope::BackendScope(RendererBackend& backend_, ScopeType scopeType_) - : priorScope(currentScope.get()), + : priorScope(currentScope().get()), nextScope(nullptr), backend(backend_), scopeType(scopeType_) { @@ -21,7 +29,7 @@ BackendScope::BackendScope(RendererBackend& backend_, ScopeType scopeType_) activate(); - currentScope.set(this); + currentScope().set(this); } BackendScope::~BackendScope() { @@ -30,11 +38,11 @@ BackendScope::~BackendScope() { if (priorScope) { priorScope->activate(); - currentScope.set(priorScope); + currentScope().set(priorScope); assert(priorScope->nextScope == this); priorScope->nextScope = nullptr; } else { - currentScope.set(nullptr); + currentScope().set(nullptr); } } @@ -60,7 +68,7 @@ void BackendScope::deactivate() { } bool BackendScope::exists() { - return currentScope.get(); + return currentScope().get(); } } // namespace mbgl diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 9af511a03e..f48593ae49 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -2,6 +2,7 @@ #include <mbgl/util/noncopyable.hpp> #include <mbgl/tile/geometry_tile_data.hpp> +#include <mbgl/style/layer_type.hpp> #include <atomic> @@ -15,9 +16,27 @@ class RenderLayer; class Bucket : private util::noncopyable { public: - Bucket() = default; + Bucket(style::LayerType layerType_) + : layerType(layerType_) { + } + virtual ~Bucket() = default; + // Check whether this bucket is of the given subtype. + template <class T> + bool is() const; + + // Dynamically cast this bucket to the given subtype. + template <class T> + T* as() { + return is<T>() ? reinterpret_cast<T*>(this) : nullptr; + } + + template <class T> + const T* as() const { + return is<T>() ? reinterpret_cast<const T*>(this) : nullptr; + } + // Feature geometries are also used to populate the feature index. // Obtaining these is a costly operation, so we do it only once, and // pass-by-const-ref the geometries as a second parameter. @@ -39,6 +58,7 @@ public: } protected: + style::LayerType layerType; std::atomic<bool> uploaded { false }; }; diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp index c442b661de..d07c1f8dbe 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.cpp +++ b/src/mbgl/renderer/buckets/circle_bucket.cpp @@ -11,7 +11,8 @@ namespace mbgl { using namespace style; CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) - : mode(parameters.mode) { + : Bucket(LayerType::Circle), + mode(parameters.mode) { for (const auto& layer : layers) { paintPropertyBinders.emplace( std::piecewise_construct, diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index 78b6351bcb..3c5f96fb15 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp @@ -37,4 +37,9 @@ public: const MapMode mode; }; +template <> +inline bool Bucket::is<CircleBucket>() const { + return layerType == style::LayerType::Circle; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/fill_bucket.cpp b/src/mbgl/renderer/buckets/fill_bucket.cpp index 110db887a1..14be98c3af 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_bucket.cpp @@ -27,7 +27,8 @@ using namespace style; struct GeometryTooLongException : std::exception {}; -FillBucket::FillBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) { +FillBucket::FillBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) + : Bucket(LayerType::Fill) { for (const auto& layer : layers) { paintPropertyBinders.emplace( std::piecewise_construct, diff --git a/src/mbgl/renderer/buckets/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp index a50e1971f5..20b65da39c 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_bucket.hpp @@ -39,4 +39,9 @@ public: std::map<std::string, FillProgram::PaintPropertyBinders> paintPropertyBinders; }; +template <> +inline bool Bucket::is<FillBucket>() const { + return layerType == style::LayerType::Fill; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp index 5e2c937091..c6dba38db1 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp @@ -34,7 +34,8 @@ using namespace style; struct GeometryTooLongException : std::exception {}; -FillExtrusionBucket::FillExtrusionBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) { +FillExtrusionBucket::FillExtrusionBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) + : Bucket(LayerType::FillExtrusion) { for (const auto& layer : layers) { paintPropertyBinders.emplace(std::piecewise_construct, std::forward_as_tuple(layer->getID()), @@ -84,7 +85,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, if (nVertices == 0) continue; - auto edgeDistance = 0; + std::size_t edgeDistance = 0; for (uint32_t i = 0; i < nVertices; i++) { const auto& p1 = ring[i]; @@ -102,7 +103,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, const Point<double> perp = util::unit(util::perp(d1 - d2)); const auto dist = util::dist<int16_t>(d1, d2); - if (dist > std::numeric_limits<int16_t>::max()) { + if (edgeDistance + dist > std::numeric_limits<int16_t>::max()) { edgeDistance = 0; } diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index d57265ab16..ed98e01292 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp @@ -34,4 +34,9 @@ public: std::unordered_map<std::string, FillExtrusionProgram::PaintPropertyBinders> paintPropertyBinders; }; +template <> +inline bool Bucket::is<FillExtrusionBucket>() const { + return layerType == style::LayerType::FillExtrusion; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.cpp b/src/mbgl/renderer/buckets/heatmap_bucket.cpp index a185e04ad2..eff0c60280 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.cpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.cpp @@ -11,7 +11,8 @@ namespace mbgl { using namespace style; HeatmapBucket::HeatmapBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) - : mode(parameters.mode) { + : Bucket(LayerType::Heatmap), + mode(parameters.mode) { for (const auto& layer : layers) { paintPropertyBinders.emplace( std::piecewise_construct, diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.hpp b/src/mbgl/renderer/buckets/heatmap_bucket.hpp index 3b9f1edb81..86b6f10296 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.hpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.hpp @@ -37,4 +37,9 @@ public: const MapMode mode; }; +template <> +inline bool Bucket::is<HeatmapBucket>() const { + return layerType == style::LayerType::Heatmap; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.cpp b/src/mbgl/renderer/buckets/hillshade_bucket.cpp index 00b9536894..3ca217a840 100644 --- a/src/mbgl/renderer/buckets/hillshade_bucket.cpp +++ b/src/mbgl/renderer/buckets/hillshade_bucket.cpp @@ -8,10 +8,14 @@ namespace mbgl { using namespace style; -HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::DEMEncoding encoding): demdata(image_, encoding) { +HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::DEMEncoding encoding) + : Bucket(LayerType::Hillshade), + demdata(image_, encoding) { } -HillshadeBucket::HillshadeBucket(DEMData&& demdata_) : demdata(std::move(demdata_)) { +HillshadeBucket::HillshadeBucket(DEMData&& demdata_) + : Bucket(LayerType::Hillshade), + demdata(std::move(demdata_)) { } const DEMData& HillshadeBucket::getDEMData() const { diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.hpp b/src/mbgl/renderer/buckets/hillshade_bucket.hpp index 5335f7ceda..c9e435c661 100644 --- a/src/mbgl/renderer/buckets/hillshade_bucket.hpp +++ b/src/mbgl/renderer/buckets/hillshade_bucket.hpp @@ -56,4 +56,9 @@ private: bool prepared = false; }; +template <> +inline bool Bucket::is<HillshadeBucket>() const { + return layerType == style::LayerType::Hillshade; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index a96518df38..a10551a7d2 100644 --- a/src/mbgl/renderer/buckets/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -14,7 +14,8 @@ using namespace style; LineBucket::LineBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers, const style::LineLayoutProperties::Unevaluated& layout_) - : layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))), + : Bucket(LayerType::Line), + layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))), overscaling(parameters.tileID.overscaleFactor()), zoom(parameters.tileID.overscaledZ) { for (const auto& layer : layers) { diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp index 4fb77c377e..8fe7184941 100644 --- a/src/mbgl/renderer/buckets/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -64,4 +64,9 @@ private: float getLineWidth(const RenderLineLayer& layer) const; }; +template <> +inline bool Bucket::is<LineBucket>() const { + return layerType == style::LayerType::Line; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index a66dd42d74..45cf351d8e 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -7,12 +7,14 @@ namespace mbgl { using namespace style; -RasterBucket::RasterBucket(PremultipliedImage&& image_) { - image = std::make_shared<PremultipliedImage>(std::move(image_)); +RasterBucket::RasterBucket(PremultipliedImage&& image_) + : Bucket(LayerType::Raster), + image(std::make_shared<PremultipliedImage>(std::move(image_))) { } -RasterBucket::RasterBucket(std::shared_ptr<PremultipliedImage> image_): image(image_) { - +RasterBucket::RasterBucket(std::shared_ptr<PremultipliedImage> image_) + : Bucket(LayerType::Raster), + image(image_) { } void RasterBucket::upload(gl::Context& context) { diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index 3800eadec8..84b618a83d 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -38,4 +38,9 @@ public: optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; }; +template <> +inline bool Bucket::is<RasterBucket>() const { + return layerType == style::LayerType::Raster; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 4fe03eb453..0a1530ae74 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -20,7 +20,8 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo bool sortFeaturesByY_, const std::string bucketName_, const std::vector<SymbolInstance>&& symbolInstances_) - : layout(std::move(layout_)), + : Bucket(LayerType::Symbol), + layout(std::move(layout_)), sdfIcons(sdfIcons_), iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()), sortFeaturesByY(sortFeaturesByY_), @@ -192,11 +193,11 @@ void SymbolBucket::sortFeatures(const float angle) { std::sort(symbolInstanceIndexes.begin(), symbolInstanceIndexes.end(), [sin, cos, this](size_t &aIndex, size_t &bIndex) { const SymbolInstance& a = symbolInstances[aIndex]; const SymbolInstance& b = symbolInstances[bIndex]; - const int32_t aRotated = sin * a.anchor.point.x + cos * a.anchor.point.y; - const int32_t bRotated = sin * b.anchor.point.x + cos * b.anchor.point.y; + const int32_t aRotated = static_cast<int32_t>(std::lround(sin * a.anchor.point.x + cos * a.anchor.point.y)); + const int32_t bRotated = static_cast<int32_t>(std::lround(sin * b.anchor.point.x + cos * b.anchor.point.y)); return aRotated != bRotated ? aRotated < bRotated : - a.index > b.index; + a.dataFeatureIndex > b.dataFeatureIndex; }); text.triangles.clear(); @@ -207,7 +208,7 @@ void SymbolBucket::sortFeatures(const float angle) { for (auto i : symbolInstanceIndexes) { const SymbolInstance& symbolInstance = symbolInstances[i]; - featureSortOrder->push_back(symbolInstance.featureIndex); + featureSortOrder->push_back(symbolInstance.dataFeatureIndex); if (symbolInstance.placedTextIndex) { addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedTextIndex]); diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index e4aaf5ba30..4f01cf4e1c 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -138,4 +138,9 @@ public: std::shared_ptr<std::vector<size_t>> featureSortOrder; }; +template <> +inline bool Bucket::is<SymbolBucket>() const { + return layerType == style::LayerType::Symbol; +} + } // namespace mbgl diff --git a/src/mbgl/renderer/cross_faded_property_evaluator.cpp b/src/mbgl/renderer/cross_faded_property_evaluator.cpp index 4dff9dbf12..9a7af8636c 100644 --- a/src/mbgl/renderer/cross_faded_property_evaluator.cpp +++ b/src/mbgl/renderer/cross_faded_property_evaluator.cpp @@ -16,10 +16,10 @@ Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const { } template <typename T> -Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const style::CameraFunction<T>& function) const { - return calculate(function.evaluate(parameters.z - 1.0f), - function.evaluate(parameters.z), - function.evaluate(parameters.z + 1.0f)); +Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const style::PropertyExpression<T>& expression) const { + return calculate(expression.evaluate(parameters.z - 1.0f), + expression.evaluate(parameters.z), + expression.evaluate(parameters.z + 1.0f)); } template <typename T> diff --git a/src/mbgl/renderer/cross_faded_property_evaluator.hpp b/src/mbgl/renderer/cross_faded_property_evaluator.hpp index 40ecba5d93..1d17c5eb2f 100644 --- a/src/mbgl/renderer/cross_faded_property_evaluator.hpp +++ b/src/mbgl/renderer/cross_faded_property_evaluator.hpp @@ -27,7 +27,7 @@ public: Faded<T> operator()(const style::Undefined&) const; Faded<T> operator()(const T& constant) const; - Faded<T> operator()(const style::CameraFunction<T>&) const; + Faded<T> operator()(const style::PropertyExpression<T>&) const; private: Faded<T> calculate(const T& min, const T& mid, const T& max) const; diff --git a/src/mbgl/renderer/data_driven_property_evaluator.hpp b/src/mbgl/renderer/data_driven_property_evaluator.hpp index 79ecd0d495..f9452cc572 100644 --- a/src/mbgl/renderer/data_driven_property_evaluator.hpp +++ b/src/mbgl/renderer/data_driven_property_evaluator.hpp @@ -23,21 +23,18 @@ public: return ResultType(constant); } - ResultType operator()(const style::CameraFunction<T>& function) const { - if (!parameters.useIntegerZoom) { - return ResultType(function.evaluate(parameters.z)); + ResultType operator()(const style::PropertyExpression<T>& expression) const { + if (!expression.isFeatureConstant()) { + auto returnExpression = expression; + returnExpression.useIntegerZoom = parameters.useIntegerZoom; + return ResultType(returnExpression); + } else if (!parameters.useIntegerZoom) { + return ResultType(expression.evaluate(parameters.z)); } else { - return ResultType(function.evaluate(floor(parameters.z))); + return ResultType(expression.evaluate(floor(parameters.z))); } } - template <class Function> - ResultType operator()(const Function& function) const { - auto returnFunction = function; - returnFunction.useIntegerZoom = parameters.useIntegerZoom; - return ResultType(returnFunction); - } - private: const PropertyEvaluationParameters& parameters; T defaultValue; diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 44c3fffb6c..2dc5fe7339 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -50,6 +50,35 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { const Properties<>::PossiblyEvaluated properties; const BackgroundProgram::PaintPropertyBinders paintAttributeData(properties, 0); + auto draw = [&](auto& program, auto&& uniformValues) { + const auto allUniformValues = program.computeAllUniformValues( + std::move(uniformValues), + paintAttributeData, + properties, + parameters.state.getZoom() + ); + const auto allAttributeBindings = program.computeAllAttributeBindings( + parameters.staticData.tileVertexBuffer, + paintAttributeData, + properties + ); + + checkRenderability(parameters, program.activeBindingCount(allAttributeBindings)); + + program.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + parameters.staticData.quadTriangleIndexBuffer, + parameters.staticData.tileTriangleSegments, + allUniformValues, + allAttributeBindings, + getID() + ); + }; + if (!evaluated.get<BackgroundPattern>().to.empty()) { optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().from); optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().to); @@ -60,12 +89,8 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { parameters.imageManager.bind(parameters.context, 0); for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) { - parameters.programs.backgroundPattern.draw( - parameters.context, - gl::Triangles(), - parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - gl::StencilMode::disabled(), - parameters.colorModeForRenderPass(), + draw( + parameters.programs.backgroundPattern, BackgroundPatternUniforms::values( parameters.matrixForTile(tileID), evaluated.get<BackgroundOpacity>(), @@ -75,36 +100,18 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { evaluated.get<BackgroundPattern>(), tileID, parameters.state - ), - parameters.staticData.tileVertexBuffer, - parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.tileTriangleSegments, - paintAttributeData, - properties, - parameters.state.getZoom(), - getID() + ) ); } } else { for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) { - parameters.programs.background.draw( - parameters.context, - gl::Triangles(), - parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - gl::StencilMode::disabled(), - parameters.colorModeForRenderPass(), + draw( + parameters.programs.background, BackgroundProgram::UniformValues { uniforms::u_matrix::Value{ parameters.matrixForTile(tileID) }, uniforms::u_color::Value{ evaluated.get<BackgroundColor>() }, uniforms::u_opacity::Value{ evaluated.get<BackgroundOpacity>() }, - }, - parameters.staticData.tileVertexBuffer, - parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.tileTriangleSegments, - paintAttributeData, - properties, - parameters.state.getZoom(), - getID() + } ); } } diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index 56fccfe071..ce63ada770 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -56,17 +56,17 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) { const bool pitchWithMap = evaluated.get<CirclePitchAlignment>() == AlignmentType::Map; for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<CircleBucket*>(tile.tile.getBucket(*baseImpl))); - CircleBucket& bucket = *reinterpret_cast<CircleBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<CircleBucket>(*baseImpl); + if (!bucket_) { + continue; + } + CircleBucket& bucket = *bucket_; - parameters.programs.circle.get(evaluated).draw( - parameters.context, - gl::Triangles(), - parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - parameters.mapMode != MapMode::Continuous - ? parameters.stencilModeForClipping(tile.clip) - : gl::StencilMode::disabled(), - parameters.colorModeForRenderPass(), + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + auto& programInstance = parameters.programs.circle.get(evaluated); + + const auto allUniformValues = programInstance.computeAllUniformValues( CircleProgram::UniformValues { uniforms::u_matrix::Value{ tile.translatedMatrix(evaluated.get<CircleTranslate>(), @@ -82,12 +82,30 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) { uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() }, uniforms::u_pitch_with_map::Value{ pitchWithMap } }, + paintPropertyBinders, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *bucket.vertexBuffer, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + parameters.mapMode != MapMode::Continuous + ? parameters.stencilModeForClipping(tile.clip) + : gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), *bucket.indexBuffer, bucket.segments, - bucket.paintPropertyBinders.at(getID()), - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); } diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 871464223c..2f720284fc 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -68,24 +68,55 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* parameters.context.setStencilMode(gl::StencilMode::disabled()); parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {}); + auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues) { + const auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID()); + + const auto allUniformValues = programInstance.computeAllUniformValues( + std::move(uniformValues), + paintPropertyBinders, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( + *tileBucket.vertexBuffer, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeFor3D(gl::DepthMode::ReadWrite), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + *tileBucket.indexBuffer, + tileBucket.triangleSegments, + allUniformValues, + allAttributeBindings, + getID()); + }; + if (evaluated.get<FillExtrusionPattern>().from.empty()) { for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl))); - FillExtrusionBucket& bucket = - *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)); - - parameters.programs.fillExtrusion.get(evaluated).draw( - parameters.context, gl::Triangles(), - parameters.depthModeFor3D(gl::DepthMode::ReadWrite), - gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), + auto bucket_ = tile.tile.getBucket<FillExtrusionBucket>(*baseImpl); + if (!bucket_) { + continue; + } + FillExtrusionBucket& bucket = *bucket_; + + draw( + parameters.programs.fillExtrusion.get(evaluated), + bucket, FillExtrusionUniforms::values( tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(), evaluated.get<FillExtrusionTranslateAnchor>(), parameters.state), - parameters.state, parameters.evaluatedLight), - *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments, - bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(), - getID()); + parameters.state, + parameters.evaluatedLight + ) + ); } } else { optional<ImagePosition> imagePosA = @@ -100,14 +131,15 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* parameters.imageManager.bind(parameters.context, 0); for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl))); - FillExtrusionBucket& bucket = - *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)); - - parameters.programs.fillExtrusionPattern.get(evaluated).draw( - parameters.context, gl::Triangles(), - parameters.depthModeFor3D(gl::DepthMode::ReadWrite), - gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), + auto bucket_ = tile.tile.getBucket<FillExtrusionBucket>(*baseImpl); + if (!bucket_) { + continue; + } + FillExtrusionBucket& bucket = *bucket_; + + draw( + parameters.programs.fillExtrusionPattern.get(evaluated), + bucket, FillExtrusionPatternUniforms::values( tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(), evaluated.get<FillExtrusionTranslateAnchor>(), @@ -115,10 +147,9 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB, evaluated.get<FillExtrusionPattern>(), tile.id, parameters.state, -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f, - parameters.evaluatedLight), - *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments, - bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(), - getID()); + parameters.evaluatedLight + ) + ); } } @@ -131,19 +162,39 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); const Properties<>::PossiblyEvaluated properties; + const ExtrusionTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; + + auto& programInstance = parameters.programs.extrusionTexture; - parameters.programs.extrusionTexture.draw( - parameters.context, gl::Triangles(), gl::DepthMode::disabled(), - gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), + const auto allUniformValues = programInstance.computeAllUniformValues( ExtrusionTextureProgram::UniformValues{ uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, uniforms::u_image::Value{ 0 }, - uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } }, + uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( parameters.staticData.extrusionTextureVertexBuffer, + paintAttributeData, + properties + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + gl::DepthMode::disabled(), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.extrusionTextureSegments, - ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties, - parameters.state.getZoom(), getID()); + allUniformValues, + allAttributeBindings, + getID()); } } diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index efd3f4215c..f03eb66c88 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -61,20 +61,22 @@ bool RenderFillLayer::hasTransition() const { void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { if (evaluated.get<FillPattern>().from.empty()) { for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); - FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<FillBucket>(*baseImpl); + if (!bucket_) { + continue; + } + FillBucket& bucket = *bucket_; auto draw = [&] (auto& program, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments) { - program.get(evaluated).draw( - parameters.context, - drawMode, - depthMode, - parameters.stencilModeForClipping(tile.clip), - parameters.colorModeForRenderPass(), + auto& programInstance = program.get(evaluated); + + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + const auto allUniformValues = programInstance.computeAllUniformValues( FillProgram::UniformValues { uniforms::u_matrix::Value{ tile.translatedMatrix(evaluated.get<FillTranslate>(), @@ -83,12 +85,28 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { }, uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size }, }, + paintPropertyBinders, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *bucket.vertexBuffer, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + drawMode, + depthMode, + parameters.stencilModeForClipping(tile.clip), + parameters.colorModeForRenderPass(), indexBuffer, segments, - bucket.paintPropertyBinders.at(getID()), - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); }; @@ -131,20 +149,22 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { parameters.imageManager.bind(parameters.context, 0); for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); - FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<FillBucket>(*baseImpl); + if (!bucket_) { + continue; + } + FillBucket& bucket = *bucket_; auto draw = [&] (auto& program, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments) { - program.get(evaluated).draw( - parameters.context, - drawMode, - depthMode, - parameters.stencilModeForClipping(tile.clip), - parameters.colorModeForRenderPass(), + auto& programInstance = program.get(evaluated); + + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + const auto allUniformValues = programInstance.computeAllUniformValues( FillPatternUniforms::values( tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), @@ -157,12 +177,28 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { tile.id, parameters.state ), + paintPropertyBinders, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *bucket.vertexBuffer, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + drawMode, + depthMode, + parameters.stencilModeForClipping(tile.clip), + parameters.colorModeForRenderPass(), indexBuffer, segments, - bucket.paintPropertyBinders.at(getID()), - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); }; diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index 72c60446aa..c9ca477cbb 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -83,8 +83,11 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {}); for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<HeatmapBucket*>(tile.tile.getBucket(*baseImpl))); - HeatmapBucket& bucket = *reinterpret_cast<HeatmapBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<HeatmapBucket>(*baseImpl); + if (!bucket_) { + continue; + } + HeatmapBucket& bucket = *bucket_; const auto extrudeScale = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); @@ -92,23 +95,38 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { ? parameters.stencilModeForClipping(tile.clip) : gl::StencilMode::disabled(); - parameters.programs.heatmap.get(evaluated).draw( + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + auto& programInstance = parameters.programs.heatmap.get(evaluated); + + const auto allUniformValues = programInstance.computeAllUniformValues( + HeatmapProgram::UniformValues { + uniforms::u_intensity::Value{ evaluated.get<style::HeatmapIntensity>() }, + uniforms::u_matrix::Value{ tile.matrix }, + uniforms::heatmap::u_extrude_scale::Value{ extrudeScale } + }, + paintPropertyBinders, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( + *bucket.vertexBuffer, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( parameters.context, gl::Triangles(), parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), stencilMode, gl::ColorMode::additive(), - HeatmapProgram::UniformValues { - uniforms::u_intensity::Value{evaluated.get<style::HeatmapIntensity>()}, - uniforms::u_matrix::Value{tile.matrix}, - uniforms::heatmap::u_extrude_scale::Value{extrudeScale} - }, - *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, - bucket.paintPropertyBinders.at(getID()), - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); } @@ -123,20 +141,41 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); const Properties<>::PossiblyEvaluated properties; + const HeatmapTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; + + auto& programInstance = parameters.programs.heatmapTexture; - parameters.programs.heatmapTexture.draw( - parameters.context, gl::Triangles(), gl::DepthMode::disabled(), - gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), + const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapTextureProgram::UniformValues{ uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, uniforms::u_image::Value{ 0 }, uniforms::u_color_ramp::Value{ 1 }, - uniforms::u_opacity::Value{ evaluated.get<HeatmapOpacity>() } }, + uniforms::u_opacity::Value{ evaluated.get<HeatmapOpacity>() } + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( parameters.staticData.extrusionTextureVertexBuffer, + paintAttributeData, + properties + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + gl::DepthMode::disabled(), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.extrusionTextureSegments, - HeatmapTextureProgram::PaintPropertyBinders{ properties, 0 }, properties, - parameters.state.getZoom(), getID()); + allUniformValues, + allAttributeBindings, + getID() + ); } } diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index bcfd4ffe99..25eef98fcf 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -69,12 +69,11 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src const auto& indexBuffer, const auto& segments, const UnwrappedTileID& id) { - parameters.programs.hillshade.draw( - parameters.context, - gl::Triangles(), - parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - gl::StencilMode::disabled(), - parameters.colorModeForRenderPass(), + auto& programInstance = parameters.programs.hillshade; + + const HillshadeProgram::PaintPropertyBinders paintAttributeData{ evaluated, 0 }; + + const auto allUniformValues = programInstance.computeAllUniformValues( HillshadeProgram::UniformValues { uniforms::u_matrix::Value{ matrix }, uniforms::u_image::Value{ 0 }, @@ -84,12 +83,28 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src uniforms::u_light::Value{ getLight(parameters) }, uniforms::u_latrange::Value{ getLatRange(id) }, }, + paintAttributeData, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( vertexBuffer, + paintAttributeData, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), indexBuffer, segments, - HillshadeProgram::PaintPropertyBinders { evaluated, 0 }, - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); }; @@ -99,8 +114,12 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src matrix::translate(mat, mat, 0, -util::EXTENT, 0); for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<HillshadeBucket*>(tile.tile.getBucket(*baseImpl))); - HillshadeBucket& bucket = *reinterpret_cast<HillshadeBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<HillshadeBucket>(*baseImpl); + if (!bucket_) { + continue; + } + HillshadeBucket& bucket = *bucket_; + if (!bucket.hasData()){ continue; } @@ -112,13 +131,11 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src parameters.context.bindTexture(*bucket.dem, 0, gl::TextureFilter::Nearest, gl::TextureMipMap::No, gl::TextureWrap::Clamp, gl::TextureWrap::Clamp); const Properties<>::PossiblyEvaluated properties; + const HillshadePrepareProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; - parameters.programs.hillshadePrepare.draw( - parameters.context, - gl::Triangles(), - parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - gl::StencilMode::disabled(), - parameters.colorModeForRenderPass(), + auto& programInstance = parameters.programs.hillshadePrepare; + + const auto allUniformValues = programInstance.computeAllUniformValues( HillshadePrepareProgram::UniformValues { uniforms::u_matrix::Value { mat }, uniforms::u_dimension::Value { {{uint16_t(tilesize * 2), uint16_t(tilesize * 2) }} }, @@ -126,12 +143,28 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src uniforms::u_maxzoom::Value{ float(maxzoom) }, uniforms::u_image::Value{ 0 } }, + paintAttributeData, + properties, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( parameters.staticData.rasterVertexBuffer, + paintAttributeData, + properties + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments, - HillshadePrepareProgram::PaintPropertyBinders { properties, 0 }, - properties, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); bucket.texture = std::move(view.getTexture()); diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 02f61af0fa..4b6ea35e67 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -58,23 +58,41 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { } for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<LineBucket*>(tile.tile.getBucket(*baseImpl))); - LineBucket& bucket = *reinterpret_cast<LineBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<LineBucket>(*baseImpl); + if (!bucket_) { + continue; + } + LineBucket& bucket = *bucket_; auto draw = [&] (auto& program, auto&& uniformValues) { - program.get(evaluated).draw( + auto& programInstance = program.get(evaluated); + + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + const auto allUniformValues = programInstance.computeAllUniformValues( + std::move(uniformValues), + paintPropertyBinders, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( + *bucket.vertexBuffer, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( parameters.context, gl::Triangles(), parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), - std::move(uniformValues), - *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, - bucket.paintPropertyBinders.at(getID()), - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); }; diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index b41b2ac560..e2524697b5 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -73,16 +73,15 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source if (parameters.pass != RenderPass::Translucent) return; + RasterProgram::PaintPropertyBinders paintAttributeData{ evaluated, 0 }; + auto draw = [&] (const mat4& matrix, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments) { - parameters.programs.raster.draw( - parameters.context, - gl::Triangles(), - parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - gl::StencilMode::disabled(), - parameters.colorModeForRenderPass(), + auto& programInstance = parameters.programs.raster; + + const auto allUniformValues = programInstance.computeAllUniformValues( RasterProgram::UniformValues { uniforms::u_matrix::Value{ matrix }, uniforms::u_image0::Value{ 0 }, @@ -98,23 +97,41 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source uniforms::u_scale_parent::Value{ 1.0f }, uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} }, }, + paintAttributeData, + evaluated, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( vertexBuffer, + paintAttributeData, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( + parameters.context, + gl::Triangles(), + parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), indexBuffer, segments, - RasterProgram::PaintPropertyBinders { evaluated, 0 }, - evaluated, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); }; + const gl::TextureFilter filter = evaluated.get<RasterResampling>() == RasterResamplingType::Nearest ? gl::TextureFilter::Nearest : gl::TextureFilter::Linear; + if (RenderImageSource* imageSource = source->as<RenderImageSource>()) { if (imageSource->isEnabled() && imageSource->isLoaded() && !imageSource->bucket->needsUpload()) { RasterBucket& bucket = *imageSource->bucket; assert(bucket.texture); - parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear); - parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear); + parameters.context.bindTexture(*bucket.texture, 0, filter); + parameters.context.bindTexture(*bucket.texture, 1, filter); for (auto matrix_ : imageSource->matrices) { draw(matrix_, @@ -125,15 +142,18 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source } } else { for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<RasterBucket*>(tile.tile.getBucket(*baseImpl))); - RasterBucket& bucket = *reinterpret_cast<RasterBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<RasterBucket>(*baseImpl); + if (!bucket_) { + continue; + } + RasterBucket& bucket = *bucket_; if (!bucket.hasData()) continue; assert(bucket.texture); - parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear); - parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear); + parameters.context.bindTexture(*bucket.texture, 0, filter); + parameters.context.bindTexture(*bucket.texture, 1, filter); if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 9e493003c0..63fcb6cfd5 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -75,8 +75,11 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { } for (const RenderTile& tile : renderTiles) { - assert(dynamic_cast<SymbolBucket*>(tile.tile.getBucket(*baseImpl))); - SymbolBucket& bucket = *reinterpret_cast<SymbolBucket*>(tile.tile.getBucket(*baseImpl)); + auto bucket_ = tile.tile.getBucket<SymbolBucket>(*baseImpl); + if (!bucket_) { + continue; + } + SymbolBucket& bucket = *bucket_; const auto& layout = bucket.layout; @@ -88,7 +91,26 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { const auto& binders, const auto& paintProperties) { - program.get(paintProperties).draw( + auto& programInstance = program.get(paintProperties); + + const auto allUniformValues = programInstance.computeAllUniformValues( + std::move(uniformValues), + *symbolSizeBinder, + binders, + paintProperties, + parameters.state.getZoom() + ); + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( + *buffers.vertexBuffer, + *buffers.dynamicVertexBuffer, + *buffers.opacityVertexBuffer, + binders, + paintProperties + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw( parameters.context, gl::Triangles(), values_.pitchAlignment == AlignmentType::Map @@ -96,16 +118,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { : gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), - std::move(uniformValues), - *buffers.vertexBuffer, - *buffers.dynamicVertexBuffer, - *buffers.opacityVertexBuffer, - *symbolSizeBinder, *buffers.indexBuffer, buffers.segments, - binders, - paintProperties, - parameters.state.getZoom(), + allUniformValues, + allAttributeBindings, getID() ); }; @@ -117,7 +133,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { auto values = iconPropertyValues(layout); auto paintPropertyValues = iconPaintProperties(); - const bool alongLine = layout.get<SymbolPlacement>() == SymbolPlacementType::Line && + const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point && layout.get<IconRotationAlignment>() == AlignmentType::Map; if (alongLine) { @@ -178,7 +194,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { auto values = textPropertyValues(layout); auto paintPropertyValues = textPaintProperties(); - const bool alongLine = layout.get<SymbolPlacement>() == SymbolPlacementType::Line && + const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point && layout.get<TextRotationAlignment>() == AlignmentType::Map; if (alongLine) { @@ -221,7 +237,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); - auto scale = std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)); + const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); std::array<float,2> extrudeScale = {{ parameters.pixelsToGLUnits[0] / (pixelRatio * scale), @@ -254,7 +270,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); - auto scale = std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)); + const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); std::array<float,2> extrudeScale = {{ parameters.pixelsToGLUnits[0] / (pixelRatio * scale), @@ -322,24 +338,11 @@ style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::S evaluated.get<style::IconTranslateAnchor>(), evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 && evaluated.get<style::IconHaloWidth>().constantOr(1), - evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0, - 10.0f + evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0 }; } style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const { - // We hide line labels with viewport alignment as they move into the distance - // because the approximations we use for drawing their glyphs get progressively worse - // The "1.5" here means we start hiding them when the distance from the label - // to the camera is 50% greater than the distance from the center of the map - // to the camera. Depending on viewport properties, you might expect this to filter - // the top third of the screen at pitch 60, and do almost nothing at pitch 45 - // "10" is effectively infinite at any pitch we support - const bool limitMaxDistance = - layout_.get<style::SymbolPlacement>() == style::SymbolPlacementType::Line - && layout_.get<style::TextRotationAlignment>() == style::AlignmentType::Map - && layout_.get<style::TextPitchAlignment>() == style::AlignmentType::Viewport; - return style::SymbolPropertyValues { layout_.get<style::TextPitchAlignment>(), layout_.get<style::TextRotationAlignment>(), @@ -348,8 +351,7 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S evaluated.get<style::TextTranslateAnchor>(), evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 && evaluated.get<style::TextHaloWidth>().constantOr(1), - evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0, - limitMaxDistance ? 1.5f : 10.0f + evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0 }; } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 83709b5122..5b73b30294 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -48,8 +48,6 @@ public: bool hasHalo; bool hasFill; - - float maxCameraDistance; // 1.5 for road labels, or 10 (essentially infinite) for everything else }; } // namespace style diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 3a49882f12..aade672ae7 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -130,13 +130,13 @@ public: using Attribute = ZoomInterpolatedAttributeType<A>; using AttributeBinding = typename Attribute::Binding; - SourceFunctionPaintPropertyBinder(style::SourceFunction<T> function_, T defaultValue_) - : function(std::move(function_)), + SourceFunctionPaintPropertyBinder(style::PropertyExpression<T> expression_, T defaultValue_) + : expression(std::move(expression_)), defaultValue(std::move(defaultValue_)) { } void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) override { - auto evaluated = function.evaluate(feature, defaultValue); + auto evaluated = expression.evaluate(feature, defaultValue); this->statistics.add(evaluated); auto value = attributeValue(evaluated); for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) { @@ -170,7 +170,7 @@ public: } private: - style::SourceFunction<T> function; + style::PropertyExpression<T> expression; T defaultValue; gl::VertexVector<BaseVertex> vertexVector; optional<gl::VertexBuffer<BaseVertex>> vertexBuffer; @@ -187,14 +187,14 @@ public: using AttributeBinding = typename Attribute::Binding; using Vertex = gl::detail::Vertex<Attribute>; - CompositeFunctionPaintPropertyBinder(style::CompositeFunction<T> function_, float zoom, T defaultValue_) - : function(std::move(function_)), + CompositeFunctionPaintPropertyBinder(style::PropertyExpression<T> expression_, float zoom, T defaultValue_) + : expression(std::move(expression_)), defaultValue(std::move(defaultValue_)), zoomRange({zoom, zoom + 1}) { } void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) override { - Range<T> range = function.evaluate(zoomRange, feature, defaultValue); + Range<T> range = expression.evaluate(zoomRange, feature, defaultValue); this->statistics.add(range.min); this->statistics.add(range.max); AttributeValue value = zoomInterpolatedAttributeValue( @@ -218,10 +218,10 @@ public: } float interpolationFactor(float currentZoom) const override { - if (function.useIntegerZoom) { - return function.interpolationFactor(zoomRange, std::floor(currentZoom)); + if (expression.useIntegerZoom) { + return expression.interpolationFactor(zoomRange, std::floor(currentZoom)); } else { - return function.interpolationFactor(zoomRange, currentZoom); + return expression.interpolationFactor(zoomRange, currentZoom); } } @@ -235,7 +235,7 @@ public: } private: - style::CompositeFunction<T> function; + style::PropertyExpression<T> expression; T defaultValue; Range<float> zoomRange; gl::VertexVector<Vertex> vertexVector; @@ -249,11 +249,12 @@ PaintPropertyBinder<T, A>::create(const PossiblyEvaluatedPropertyValue<T>& value [&] (const T& constant) -> std::unique_ptr<PaintPropertyBinder<T, A>> { return std::make_unique<ConstantPaintPropertyBinder<T, A>>(constant); }, - [&] (const style::SourceFunction<T>& function) { - return std::make_unique<SourceFunctionPaintPropertyBinder<T, A>>(function, defaultValue); - }, - [&] (const style::CompositeFunction<T>& function) { - return std::make_unique<CompositeFunctionPaintPropertyBinder<T, A>>(function, zoom, defaultValue); + [&] (const style::PropertyExpression<T>& expression) -> std::unique_ptr<PaintPropertyBinder<T, A>> { + if (expression.isZoomConstant()) { + return std::make_unique<SourceFunctionPaintPropertyBinder<T, A>>(expression, defaultValue); + } else { + return std::make_unique<CompositeFunctionPaintPropertyBinder<T, A>>(expression, zoom, defaultValue); + } } ); } diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index e662d5dfb1..f2d265f2f7 100644 --- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp +++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp @@ -1,7 +1,6 @@ #pragma once -#include <mbgl/style/function/source_function.hpp> -#include <mbgl/style/function/composite_function.hpp> +#include <mbgl/style/property_expression.hpp> #include <mbgl/util/interpolate.hpp> #include <mbgl/util/variant.hpp> @@ -12,8 +11,7 @@ class PossiblyEvaluatedPropertyValue { private: using Value = variant< T, - style::SourceFunction<T>, - style::CompositeFunction<T>>; + style::PropertyExpression<T>>; Value value; @@ -45,17 +43,14 @@ public: template <class Feature> T evaluate(const Feature& feature, float zoom, T defaultValue) const { return this->match( - [&] (const T& constant_) { return constant_; }, - [&] (const style::SourceFunction<T>& function) { - return function.evaluate(feature, defaultValue); - }, - [&] (const style::CompositeFunction<T>& function) { - if (useIntegerZoom) { - return function.evaluate(floor(zoom), feature, defaultValue); - } else { - return function.evaluate(zoom, feature, defaultValue); - } + [&] (const T& constant_) { return constant_; }, + [&] (const style::PropertyExpression<T>& expression) { + if (useIntegerZoom) { + return expression.evaluate(floor(zoom), feature, defaultValue); + } else { + return expression.evaluate(zoom, feature, defaultValue); } + } ); } diff --git a/src/mbgl/renderer/property_evaluator.hpp b/src/mbgl/renderer/property_evaluator.hpp index 3ac0573920..03e0f5a002 100644 --- a/src/mbgl/renderer/property_evaluator.hpp +++ b/src/mbgl/renderer/property_evaluator.hpp @@ -16,7 +16,7 @@ public: T operator()(const style::Undefined&) const { return defaultValue; } T operator()(const T& constant) const { return constant; } - T operator()(const style::CameraFunction<T>& fn) const { return fn.evaluate(parameters.z); } + T operator()(const style::PropertyExpression<T>& fn) const { return fn.evaluate(parameters.z); } private: const PropertyEvaluationParameters& parameters; diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index bcdc175f14..a667d5837e 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -9,8 +9,10 @@ #include <mbgl/renderer/layers/render_raster_layer.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/renderer/layers/render_heatmap_layer.hpp> +#include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/style/types.hpp> #include <mbgl/renderer/render_tile.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { @@ -73,5 +75,32 @@ void RenderLayer::setRenderTiles(std::vector<std::reference_wrapper<RenderTile>> renderTiles = std::move(tiles); } +void RenderLayer::checkRenderability(const PaintParameters& parameters, + const uint32_t activeBindingCount) { + // Only warn once for every layer. + if (hasRenderFailures) { + return; + } + + if (activeBindingCount > parameters.context.maximumVertexBindingCount) { + Log::Error(Event::OpenGL, + "The layer '%s' uses more data-driven properties than the current device " + "supports, and will have rendering errors. To ensure compatibility with this " + "device, use %d fewer data driven properties in this layer.", + getID().c_str(), + activeBindingCount - parameters.context.minimumRequiredVertexBindingCount); + hasRenderFailures = true; + } else if (activeBindingCount > parameters.context.minimumRequiredVertexBindingCount) { + Log::Error(Event::OpenGL, + "The layer '%s' uses more data-driven properties than some devices may support. " + "Though it will render correctly on this device, it may have rendering errors " + "on other devices. To ensure compatibility with all devices, use %d fewer " + "data-driven properties in this layer.", + getID().c_str(), + activeBindingCount - parameters.context.minimumRequiredVertexBindingCount); + hasRenderFailures = true; + } +} + } //namespace mbgl diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index 04a1608564..3e2f1d7525 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -85,6 +85,11 @@ public: friend std::string layoutKey(const RenderLayer&); protected: + // Checks whether the current hardware can render this layer. If it can't, we'll show a warning + // in the console to inform the developer. + void checkRenderability(const PaintParameters&, uint32_t activeBindingCount); + +protected: // renderTiles are exposed directly to CrossTileSymbolIndex and Placement so they // can update opacities in the symbol buckets immediately before rendering friend class CrossTileSymbolIndex; @@ -95,6 +100,12 @@ protected: // Stores what render passes this layer is currently enabled for. This depends on the // evaluated StyleProperties object and is updated accordingly. RenderPass passes = RenderPass::None; + +private: + // Some layers may not render correctly on some hardware when the vertex attribute limit of + // that GPU is exceeded. More attributes are used when adding many data driven paint properties + // to a layer. + bool hasRenderFailures = false; }; } // namespace mbgl diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 35b34833e4..64790938ef 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -74,6 +74,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { static const style::Properties<>::PossiblyEvaluated properties {}; static const DebugProgram::PaintPropertyBinders paintAttributeData(properties, 0); + auto& program = parameters.programs.debug; + if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() || tile.debugBucket->complete != tile.isComplete() || @@ -85,41 +87,51 @@ void RenderTile::finishRender(PaintParameters& parameters) { tile.expires, parameters.debugOptions, parameters.context); } - parameters.programs.debug.draw( + const auto allAttributeBindings = program.computeAllAttributeBindings( + *tile.debugBucket->vertexBuffer, + paintAttributeData, + properties + ); + + program.draw( parameters.context, gl::Lines { 4.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), - DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::white() } - }, - *tile.debugBucket->vertexBuffer, *tile.debugBucket->indexBuffer, tile.debugBucket->segments, - paintAttributeData, - properties, - parameters.state.getZoom(), + program.computeAllUniformValues( + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::white() } + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ), + allAttributeBindings, "debug" ); - parameters.programs.debug.draw( + program.draw( parameters.context, gl::Lines { 2.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), - DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::black() } - }, - *tile.debugBucket->vertexBuffer, *tile.debugBucket->indexBuffer, tile.debugBucket->segments, - paintAttributeData, - properties, - parameters.state.getZoom(), + program.computeAllUniformValues( + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::black() } + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ), + allAttributeBindings, "debug" ); } @@ -131,16 +143,22 @@ void RenderTile::finishRender(PaintParameters& parameters) { gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), - DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::red() } - }, - parameters.staticData.tileVertexBuffer, parameters.staticData.tileBorderIndexBuffer, parameters.staticData.tileBorderSegments, - paintAttributeData, - properties, - parameters.state.getZoom(), + program.computeAllUniformValues( + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::red() } + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ), + program.computeAllAttributeBindings( + parameters.staticData.tileVertexBuffer, + paintAttributeData, + properties + ), "debug" ); } diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 3db02393d2..bfa695586c 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -22,7 +22,7 @@ public: RenderTile& operator=(const RenderTile&) = delete; RenderTile& operator=(RenderTile&&) = default; - const UnwrappedTileID id; + UnwrappedTileID id; Tile& tile; ClipID clip; mat4 matrix; diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index ded07a0909..fea27403c9 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -380,12 +380,15 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { } for (auto it = order.rbegin(); it != order.rend(); ++it) { if (it->layer.is<RenderSymbolLayer>()) { - if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>())) symbolBucketsChanged = true; + const float lng = parameters.state.getLatLng().longitude(); + if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>(), lng)) symbolBucketsChanged = true; } } bool placementChanged = false; if (!placement->stillRecent(parameters.timePoint)) { + placementChanged = true; + auto newPlacement = std::make_unique<Placement>(parameters.state, parameters.mapMode); std::set<std::string> usedSymbolLayers; for (auto it = order.rbegin(); it != order.rend(); ++it) { @@ -395,13 +398,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { } } - placementChanged = newPlacement->commit(*placement, parameters.timePoint); + newPlacement->commit(*placement, parameters.timePoint); crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers); - if (placementChanged || symbolBucketsChanged) { - placement = std::move(newPlacement); - } - - placement->setRecent(parameters.timePoint); + placement = std::move(newPlacement); updateFadingTiles(); } else { @@ -486,7 +485,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { static const ClippingMaskProgram::PaintPropertyBinders paintAttributeData(properties, 0); for (const auto& clipID : parameters.clipIDGenerator.getClipIDs()) { - parameters.staticData.programs.clippingMask.draw( + auto& program = parameters.staticData.programs.clippingMask; + + program.draw( parameters.context, gl::Triangles(), gl::DepthMode::disabled(), @@ -499,15 +500,21 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { gl::StencilMode::Replace }, gl::ColorMode::disabled(), - ClippingMaskProgram::UniformValues { - uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) }, - }, - parameters.staticData.tileVertexBuffer, parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.tileTriangleSegments, - paintAttributeData, - properties, - parameters.state.getZoom(), + program.computeAllUniformValues( + ClippingMaskProgram::UniformValues { + uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) }, + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ), + program.computeAllAttributeBindings( + parameters.staticData.tileVertexBuffer, + paintAttributeData, + properties + ), "clipping" ); } diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 5c497e8144..2ce046a7a0 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -58,24 +58,32 @@ void RenderImageSource::finishRender(PaintParameters& parameters) { static const style::Properties<>::PossiblyEvaluated properties {}; static const DebugProgram::PaintPropertyBinders paintAttributeData(properties, 0); + auto& programInstance = parameters.programs.debug; + for (auto matrix : matrices) { - parameters.programs.debug.draw( + programInstance.draw( parameters.context, gl::LineStrip { 4.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), gl::StencilMode::disabled(), gl::ColorMode::unblended(), - DebugProgram::UniformValues { - uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ Color::red() } - }, - parameters.staticData.tileVertexBuffer, parameters.staticData.tileBorderIndexBuffer, parameters.staticData.tileBorderSegments, - paintAttributeData, - properties, - parameters.state.getZoom(), - "debug" + programInstance.computeAllUniformValues( + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::red() } + }, + paintAttributeData, + properties, + parameters.state.getZoom() + ), + programInstance.computeAllAttributeBindings( + parameters.staticData.tileVertexBuffer, + paintAttributeData, + properties + ), + "image" ); } } @@ -131,7 +139,7 @@ void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_, auto dx = nePoint.x - swPoint.x; auto dy = nePoint.y - swPoint.y; auto dMax = std::max(dx, dy); - double zoom = std::max(0.0, std::floor(-util::log2(dMax))); + double zoom = std::max(0.0, std::floor(-::log2(dMax))); // Only enable if the long side of the image is > 2 pixels. Resulting in a // display of at least 2 x 1 px image diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index d28e95181b..fd4356ca02 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -90,6 +90,8 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer return; } + handleWrapJump(parameters.transformState.getLatLng().longitude()); + // Determine the overzooming/underzooming amounts and required tiles. int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize); int32_t tileZoom = overscaledZoom; @@ -238,6 +240,44 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer } } +void TilePyramid::handleWrapJump(float lng) { + // On top of the regular z/x/y values, TileIDs have a `wrap` value that specify + // which cppy of the world the tile belongs to. For example, at `lng: 10` you + // might render z/x/y/0 while at `lng: 370` you would render z/x/y/1. + // + // When lng values get wrapped (going from `lng: 370` to `long: 10`) you expect + // to see the same thing on the screen (370 degrees and 10 degrees is the same + // place in the world) but all the TileIDs will have different wrap values. + // + // In order to make this transition seamless, we calculate the rounded difference of + // "worlds" between the last frame and the current frame. If the map panned by + // a world, then we can assign all the tiles new TileIDs with updated wrap values. + // For example, assign z/x/y/1 a new id: z/x/y/0. It is the same tile, just rendered + // in a different position. + // + // This enables us to reuse the tiles at more ideal locations and prevent flickering. + + const float lngDifference = lng - prevLng; + const float worldDifference = lngDifference / 360; + const int wrapDelta = ::round(worldDifference); + prevLng = lng; + + if (wrapDelta) { + std::map<OverscaledTileID, std::unique_ptr<Tile>> newTiles; + for (auto& tile : tiles) { + auto newID = tile.second->id.unwrapTo(tile.second->id.wrap + wrapDelta); + tile.second->id = newID; + newTiles.emplace(newID, std::move(tile.second)); + } + tiles = std::move(newTiles); + + for (auto& renderTile : renderTiles) { + renderTile.id = renderTile.id.unwrapTo(renderTile.id.wrap + wrapDelta); + } + } +} + + std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index 0cef9e2c40..4e5f50fd52 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -49,6 +49,8 @@ public: std::vector<std::reference_wrapper<RenderTile>> getRenderTiles(); Tile* getTile(const OverscaledTileID&); + void handleWrapJump(float lng); + std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, @@ -72,6 +74,8 @@ public: std::vector<RenderTile> renderTiles; TileObserver* observer = nullptr; + + float prevLng = 0; }; } // namespace mbgl diff --git a/src/mbgl/shaders/background.cpp b/src/mbgl/shaders/background.cpp index 3eafa47b49..b0d176f07d 100644 --- a/src/mbgl/shaders/background.cpp +++ b/src/mbgl/shaders/background.cpp @@ -1,34 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/background.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* background::name = "background"; -const char* background::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; - -uniform mat4 u_matrix; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); -} - -)MBGL_SHADER"; -const char* background::fragmentSource = R"MBGL_SHADER( -uniform vec4 u_color; -uniform float u_opacity; - -void main() { - gl_FragColor = u_color * u_opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* background::vertexSource = source() + 2738; +const char* background::fragmentSource = source() + 2850; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/background_pattern.cpp b/src/mbgl/shaders/background_pattern.cpp index 6fd0a53d19..f80a86a0d9 100644 --- a/src/mbgl/shaders/background_pattern.cpp +++ b/src/mbgl/shaders/background_pattern.cpp @@ -1,65 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/background_pattern.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* background_pattern::name = "background_pattern"; -const char* background_pattern::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_pattern_size_a; -uniform vec2 u_pattern_size_b; -uniform vec2 u_pixel_coord_upper; -uniform vec2 u_pixel_coord_lower; -uniform float u_scale_a; -uniform float u_scale_b; -uniform float u_tile_units_to_pixels; - -attribute vec2 a_pos; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); - - v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos); - v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos); -} - -)MBGL_SHADER"; -const char* background_pattern::fragmentSource = R"MBGL_SHADER( -uniform vec2 u_pattern_tl_a; -uniform vec2 u_pattern_br_a; -uniform vec2 u_pattern_tl_b; -uniform vec2 u_pattern_br_b; -uniform vec2 u_texsize; -uniform float u_mix; -uniform float u_opacity; - -uniform sampler2D u_image; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; - -void main() { - vec2 imagecoord = mod(v_pos_a, 1.0); - vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); - vec4 color1 = texture2D(u_image, pos); - - vec2 imagecoord_b = mod(v_pos_b, 1.0); - vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b); - vec4 color2 = texture2D(u_image, pos2); - - gl_FragColor = mix(color1, color2, u_mix) * u_opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* background_pattern::vertexSource = source() + 3019; +const char* background_pattern::fragmentSource = source() + 3663; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp index c14335914b..1ba1865504 100644 --- a/src/mbgl/shaders/circle.cpp +++ b/src/mbgl/shaders/circle.cpp @@ -1,287 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/circle.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* circle::name = "circle"; -const char* circle::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform bool u_scale_with_map; -uniform bool u_pitch_with_map; -uniform vec2 u_extrude_scale; -uniform highp float u_camera_to_center_distance; - -attribute vec2 a_pos; - - -#ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; -attribute highp vec4 a_color; -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_radius -uniform lowp float a_radius_t; -attribute mediump vec2 a_radius; -varying mediump float radius; -#else -uniform mediump float u_radius; -#endif - - -#ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; -attribute lowp vec2 a_blur; -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_color -uniform lowp float a_stroke_color_t; -attribute highp vec4 a_stroke_color; -varying highp vec4 stroke_color; -#else -uniform highp vec4 u_stroke_color; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_width -uniform lowp float a_stroke_width_t; -attribute mediump vec2 a_stroke_width; -varying mediump float stroke_width; -#else -uniform mediump float u_stroke_width; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_opacity -uniform lowp float a_stroke_opacity_t; -attribute lowp vec2 a_stroke_opacity; -varying lowp float stroke_opacity; -#else -uniform lowp float u_stroke_opacity; -#endif - - -varying vec3 v_data; - -void main(void) { - -#ifndef HAS_UNIFORM_u_color - color = unpack_mix_vec4(a_color, a_color_t); -#else - highp vec4 color = u_color; -#endif - - -#ifndef HAS_UNIFORM_u_radius - radius = unpack_mix_vec2(a_radius, a_radius_t); -#else - mediump float radius = u_radius; -#endif - - -#ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); -#else - lowp float blur = u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_color - stroke_color = unpack_mix_vec4(a_stroke_color, a_stroke_color_t); -#else - highp vec4 stroke_color = u_stroke_color; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_width - stroke_width = unpack_mix_vec2(a_stroke_width, a_stroke_width_t); -#else - mediump float stroke_width = u_stroke_width; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_opacity - stroke_opacity = unpack_mix_vec2(a_stroke_opacity, a_stroke_opacity_t); -#else - lowp float stroke_opacity = u_stroke_opacity; -#endif - - - // unencode the extrusion vector that we snuck into the a_pos vector - vec2 extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); - - // multiply a_pos by 0.5, since we had it * 2 in order to sneak - // in extrusion data - vec2 circle_center = floor(a_pos * 0.5); - if (u_pitch_with_map) { - vec2 corner_position = circle_center; - if (u_scale_with_map) { - corner_position += extrude * (radius + stroke_width) * u_extrude_scale; - } else { - // Pitching the circle with the map effectively scales it with the map - // To counteract the effect for pitch-scale: viewport, we rescale the - // whole circle based on the pitch scaling effect at its central point - vec4 projected_center = u_matrix * vec4(circle_center, 0, 1); - corner_position += extrude * (radius + stroke_width) * u_extrude_scale * (projected_center.w / u_camera_to_center_distance); - } - - gl_Position = u_matrix * vec4(corner_position, 0, 1); - } else { - gl_Position = u_matrix * vec4(circle_center, 0, 1); - - if (u_scale_with_map) { - gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * u_camera_to_center_distance; - } else { - gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * gl_Position.w; - } - } - - // This is a minimum blur distance that serves as a faux-antialiasing for - // the circle. since blur is a ratio of the circle's size and the intent is - // to keep the blur at roughly 1px, the two are inversely related. - lowp float antialiasblur = 1.0 / DEVICE_PIXEL_RATIO / (radius + stroke_width); - - v_data = vec3(extrude.x, extrude.y, antialiasblur); -} - -)MBGL_SHADER"; -const char* circle::fragmentSource = R"MBGL_SHADER( - -#ifndef HAS_UNIFORM_u_color -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_radius -varying mediump float radius; -#else -uniform mediump float u_radius; -#endif - - -#ifndef HAS_UNIFORM_u_blur -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_color -varying highp vec4 stroke_color; -#else -uniform highp vec4 u_stroke_color; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_width -varying mediump float stroke_width; -#else -uniform mediump float u_stroke_width; -#endif - - -#ifndef HAS_UNIFORM_u_stroke_opacity -varying lowp float stroke_opacity; -#else -uniform lowp float u_stroke_opacity; -#endif - - -varying vec3 v_data; - -void main() { - -#ifdef HAS_UNIFORM_u_color - highp vec4 color = u_color; -#endif - - -#ifdef HAS_UNIFORM_u_radius - mediump float radius = u_radius; -#endif - - -#ifdef HAS_UNIFORM_u_blur - lowp float blur = u_blur; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - -#ifdef HAS_UNIFORM_u_stroke_color - highp vec4 stroke_color = u_stroke_color; -#endif - - -#ifdef HAS_UNIFORM_u_stroke_width - mediump float stroke_width = u_stroke_width; -#endif - - -#ifdef HAS_UNIFORM_u_stroke_opacity - lowp float stroke_opacity = u_stroke_opacity; -#endif - - - vec2 extrude = v_data.xy; - float extrude_length = length(extrude); - - lowp float antialiasblur = v_data.z; - float antialiased_blur = -max(blur, antialiasblur); - - float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0); - - float color_t = stroke_width < 0.01 ? 0.0 : smoothstep( - antialiased_blur, - 0.0, - extrude_length - radius / (radius + stroke_width) - ); - - gl_FragColor = opacity_t * mix(color * opacity, stroke_color * stroke_opacity, color_t); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* circle::vertexSource = source() + 4415; +const char* circle::fragmentSource = source() + 8663; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/clipping_mask.cpp b/src/mbgl/shaders/clipping_mask.cpp index fb08d7cb00..dff0e08ced 100644 --- a/src/mbgl/shaders/clipping_mask.cpp +++ b/src/mbgl/shaders/clipping_mask.cpp @@ -1,27 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/clipping_mask.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* clipping_mask::name = "clipping_mask"; -const char* clipping_mask::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; - -uniform mat4 u_matrix; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); -} - -)MBGL_SHADER"; -const char* clipping_mask::fragmentSource = R"MBGL_SHADER( -void main() { - gl_FragColor = vec4(1.0); -} - -)MBGL_SHADER"; +const char* clipping_mask::vertexSource = source() + 10630; +const char* clipping_mask::fragmentSource = source() + 10742; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/collision_box.cpp b/src/mbgl/shaders/collision_box.cpp index bc5d9bc6f9..e09881e87d 100644 --- a/src/mbgl/shaders/collision_box.cpp +++ b/src/mbgl/shaders/collision_box.cpp @@ -1,63 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/collision_box.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* collision_box::name = "collision_box"; -const char* collision_box::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; -attribute vec2 a_anchor_pos; -attribute vec2 a_extrude; -attribute vec2 a_placed; - -uniform mat4 u_matrix; -uniform vec2 u_extrude_scale; -uniform float u_camera_to_center_distance; - -varying float v_placed; -varying float v_notUsed; - -void main() { - vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); - highp float camera_to_anchor_distance = projectedPoint.w; - highp float collision_perspective_ratio = clamp( - 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), - 0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles - 4.0); - - gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); - gl_Position.xy += a_extrude * u_extrude_scale * gl_Position.w * collision_perspective_ratio; - - v_placed = a_placed.x; - v_notUsed = a_placed.y; -} - -)MBGL_SHADER"; -const char* collision_box::fragmentSource = R"MBGL_SHADER( - -varying float v_placed; -varying float v_notUsed; - -void main() { - - float alpha = 0.5; - - // Red = collision, hide label - gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha; - - // Blue = no collision, label is showing - if (v_placed > 0.5) { - gl_FragColor = vec4(0.0, 0.0, 1.0, 0.5) * alpha; - } - - if (v_notUsed > 0.5) { - // This box not used, fade it out - gl_FragColor *= .1; - } -} -)MBGL_SHADER"; +const char* collision_box::vertexSource = source() + 14425; +const char* collision_box::fragmentSource = source() + 15249; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/collision_circle.cpp b/src/mbgl/shaders/collision_circle.cpp index 82ebbf05a0..9188d728d8 100644 --- a/src/mbgl/shaders/collision_circle.cpp +++ b/src/mbgl/shaders/collision_circle.cpp @@ -1,87 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/collision_circle.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* collision_circle::name = "collision_circle"; -const char* collision_circle::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; -attribute vec2 a_anchor_pos; -attribute vec2 a_extrude; -attribute vec2 a_placed; - -uniform mat4 u_matrix; -uniform vec2 u_extrude_scale; -uniform float u_camera_to_center_distance; - -varying float v_placed; -varying float v_notUsed; -varying float v_radius; - -varying vec2 v_extrude; -varying vec2 v_extrude_scale; - -void main() { - vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); - highp float camera_to_anchor_distance = projectedPoint.w; - highp float collision_perspective_ratio = clamp( - 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), - 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles - 4.0); - - gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); - - highp float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur - gl_Position.xy += a_extrude * u_extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio; - - v_placed = a_placed.x; - v_notUsed = a_placed.y; - v_radius = abs(a_extrude.y); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius - - v_extrude = a_extrude * padding_factor; - v_extrude_scale = u_extrude_scale * u_camera_to_center_distance * collision_perspective_ratio; -} - -)MBGL_SHADER"; -const char* collision_circle::fragmentSource = R"MBGL_SHADER( -uniform float u_overscale_factor; - -varying float v_placed; -varying float v_notUsed; -varying float v_radius; -varying vec2 v_extrude; -varying vec2 v_extrude_scale; - -void main() { - float alpha = 0.5; - - // Red = collision, hide label - vec4 color = vec4(1.0, 0.0, 0.0, 1.0) * alpha; - - // Blue = no collision, label is showing - if (v_placed > 0.5) { - color = vec4(0.0, 0.0, 1.0, 0.5) * alpha; - } - - if (v_notUsed > 0.5) { - // This box not used, fade it out - color *= .2; - } - - float extrude_scale_length = length(v_extrude_scale); - float extrude_length = length(v_extrude) * extrude_scale_length; - float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor; - float radius = v_radius * extrude_scale_length; - - float distance_to_edge = abs(extrude_length - radius); - float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge); - - gl_FragColor = opacity_t * color; -} - -)MBGL_SHADER"; +const char* collision_circle::vertexSource = source() + 15668; +const char* collision_circle::fragmentSource = source() + 16974; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/debug.cpp b/src/mbgl/shaders/debug.cpp index 9012cfa755..25f2cb2675 100644 --- a/src/mbgl/shaders/debug.cpp +++ b/src/mbgl/shaders/debug.cpp @@ -1,29 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/debug.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* debug::name = "debug"; -const char* debug::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; - -uniform mat4 u_matrix; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); -} - -)MBGL_SHADER"; -const char* debug::fragmentSource = R"MBGL_SHADER( -uniform highp vec4 u_color; - -void main() { - gl_FragColor = u_color; -} - -)MBGL_SHADER"; +const char* debug::vertexSource = source() + 17916; +const char* debug::fragmentSource = source() + 18028; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/extrusion_texture.cpp b/src/mbgl/shaders/extrusion_texture.cpp index c756db181c..a9de78da1f 100644 --- a/src/mbgl/shaders/extrusion_texture.cpp +++ b/src/mbgl/shaders/extrusion_texture.cpp @@ -1,39 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/extrusion_texture.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* extrusion_texture::name = "extrusion_texture"; -const char* extrusion_texture::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_world; -attribute vec2 a_pos; -varying vec2 v_pos; - -void main() { - gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1); - - v_pos.x = a_pos.x; - v_pos.y = 1.0 - a_pos.y; -} - -)MBGL_SHADER"; -const char* extrusion_texture::fragmentSource = R"MBGL_SHADER( -uniform sampler2D u_image; -uniform float u_opacity; -varying vec2 v_pos; - -void main() { - gl_FragColor = texture2D(u_image, v_pos) * u_opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(0.0); -#endif -} - -)MBGL_SHADER"; +const char* extrusion_texture::vertexSource = source() + 31747; +const char* extrusion_texture::fragmentSource = source() + 31963; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/fill.cpp b/src/mbgl/shaders/fill.cpp index 3ba00836a2..146dbfb737 100644 --- a/src/mbgl/shaders/fill.cpp +++ b/src/mbgl/shaders/fill.cpp @@ -1,91 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/fill.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* fill::name = "fill"; -const char* fill::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; - -uniform mat4 u_matrix; - - -#ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; -attribute highp vec4 a_color; -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_color - color = unpack_mix_vec4(a_color, a_color_t); -#else - highp vec4 color = u_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - - gl_Position = u_matrix * vec4(a_pos, 0, 1); -} - -)MBGL_SHADER"; -const char* fill::fragmentSource = R"MBGL_SHADER( - -#ifndef HAS_UNIFORM_u_color -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_color - highp vec4 color = u_color; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - gl_FragColor = color * opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* fill::vertexSource = source() + 18102; +const char* fill::fragmentSource = source() + 18807; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/fill_extrusion.cpp b/src/mbgl/shaders/fill_extrusion.cpp index 5bb2b9cd07..ece4635dc4 100644 --- a/src/mbgl/shaders/fill_extrusion.cpp +++ b/src/mbgl/shaders/fill_extrusion.cpp @@ -1,164 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/fill_extrusion.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* fill_extrusion::name = "fill_extrusion"; -const char* fill_extrusion::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec3 u_lightcolor; -uniform lowp vec3 u_lightpos; -uniform lowp float u_lightintensity; - -attribute vec2 a_pos; -attribute vec4 a_normal_ed; - -varying vec4 v_color; - - -#ifndef HAS_UNIFORM_u_base -uniform lowp float a_base_t; -attribute lowp vec2 a_base; -varying lowp float base; -#else -uniform lowp float u_base; -#endif - - -#ifndef HAS_UNIFORM_u_height -uniform lowp float a_height_t; -attribute lowp vec2 a_height; -varying lowp float height; -#else -uniform lowp float u_height; -#endif - - - -#ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; -attribute highp vec4 a_color; -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_base - base = unpack_mix_vec2(a_base, a_base_t); -#else - lowp float base = u_base; -#endif - - -#ifndef HAS_UNIFORM_u_height - height = unpack_mix_vec2(a_height, a_height_t); -#else - lowp float height = u_height; -#endif - - -#ifndef HAS_UNIFORM_u_color - color = unpack_mix_vec4(a_color, a_color_t); -#else - highp vec4 color = u_color; -#endif - - - vec3 normal = a_normal_ed.xyz; - - base = max(0.0, base); - height = max(0.0, height); - - float t = mod(normal.x, 2.0); - - gl_Position = u_matrix * vec4(a_pos, t > 0.0 ? height : base, 1); - - // Relative luminance (how dark/bright is the surface color?) - float colorvalue = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; - - v_color = vec4(0.0, 0.0, 0.0, 1.0); - - // Add slight ambient lighting so no extrusions are totally black - vec4 ambientlight = vec4(0.03, 0.03, 0.03, 1.0); - color += ambientlight; - - // Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray - float directional = clamp(dot(normal / 16384.0, u_lightpos), 0.0, 1.0); - - // Adjust directional so that - // the range of values for highlight/shading is narrower - // with lower light intensity - // and with lighter/brighter surface colors - directional = mix((1.0 - u_lightintensity), max((1.0 - colorvalue + u_lightintensity), 1.0), directional); - - // Add gradient along z axis of side surfaces - if (normal.y != 0.0) { - directional *= clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0); - } - - // Assign final color based on surface + ambient light color, diffuse light directional, and light color - // with lower bounds adjusted to hue of light - // so that shading is tinted with the complementary (opposite) color to the light color - v_color.r += clamp(color.r * directional * u_lightcolor.r, mix(0.0, 0.3, 1.0 - u_lightcolor.r), 1.0); - v_color.g += clamp(color.g * directional * u_lightcolor.g, mix(0.0, 0.3, 1.0 - u_lightcolor.g), 1.0); - v_color.b += clamp(color.b * directional * u_lightcolor.b, mix(0.0, 0.3, 1.0 - u_lightcolor.b), 1.0); -} - -)MBGL_SHADER"; -const char* fill_extrusion::fragmentSource = R"MBGL_SHADER( -varying vec4 v_color; - -#ifndef HAS_UNIFORM_u_base -varying lowp float base; -#else -uniform lowp float u_base; -#endif - - -#ifndef HAS_UNIFORM_u_height -varying lowp float height; -#else -uniform lowp float u_height; -#endif - - -#ifndef HAS_UNIFORM_u_color -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_base - lowp float base = u_base; -#endif - - -#ifdef HAS_UNIFORM_u_height - lowp float height = u_height; -#endif - - -#ifdef HAS_UNIFORM_u_color - highp vec4 color = u_color; -#endif - - - gl_FragColor = v_color; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* fill_extrusion::vertexSource = source() + 24858; +const char* fill_extrusion::fragmentSource = source() + 27694; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/fill_extrusion_pattern.cpp b/src/mbgl/shaders/fill_extrusion_pattern.cpp index 466d0e04fe..1d7a2d4428 100644 --- a/src/mbgl/shaders/fill_extrusion_pattern.cpp +++ b/src/mbgl/shaders/fill_extrusion_pattern.cpp @@ -1,158 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/fill_extrusion_pattern.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* fill_extrusion_pattern::name = "fill_extrusion_pattern"; -const char* fill_extrusion_pattern::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_pattern_size_a; -uniform vec2 u_pattern_size_b; -uniform vec2 u_pixel_coord_upper; -uniform vec2 u_pixel_coord_lower; -uniform float u_scale_a; -uniform float u_scale_b; -uniform float u_tile_units_to_pixels; -uniform float u_height_factor; - -uniform vec3 u_lightcolor; -uniform lowp vec3 u_lightpos; -uniform lowp float u_lightintensity; - -attribute vec2 a_pos; -attribute vec4 a_normal_ed; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; -varying vec4 v_lighting; -varying float v_directional; - - -#ifndef HAS_UNIFORM_u_base -uniform lowp float a_base_t; -attribute lowp vec2 a_base; -varying lowp float base; -#else -uniform lowp float u_base; -#endif - - -#ifndef HAS_UNIFORM_u_height -uniform lowp float a_height_t; -attribute lowp vec2 a_height; -varying lowp float height; -#else -uniform lowp float u_height; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_base - base = unpack_mix_vec2(a_base, a_base_t); -#else - lowp float base = u_base; -#endif - - -#ifndef HAS_UNIFORM_u_height - height = unpack_mix_vec2(a_height, a_height_t); -#else - lowp float height = u_height; -#endif - - - vec3 normal = a_normal_ed.xyz; - float edgedistance = a_normal_ed.w; - - base = max(0.0, base); - height = max(0.0, height); - - float t = mod(normal.x, 2.0); - float z = t > 0.0 ? height : base; - - gl_Position = u_matrix * vec4(a_pos, z, 1); - - vec2 pos = normal.x == 1.0 && normal.y == 0.0 && normal.z == 16384.0 - ? a_pos // extrusion top - : vec2(edgedistance, z * u_height_factor); // extrusion side - - v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, pos); - v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, pos); - - v_lighting = vec4(0.0, 0.0, 0.0, 1.0); - float directional = clamp(dot(normal / 16383.0, u_lightpos), 0.0, 1.0); - directional = mix((1.0 - u_lightintensity), max((0.5 + u_lightintensity), 1.0), directional); - - if (normal.y != 0.0) { - directional *= clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0); - } - - v_lighting.rgb += clamp(directional * u_lightcolor, mix(vec3(0.0), vec3(0.3), 1.0 - u_lightcolor), vec3(1.0)); -} - -)MBGL_SHADER"; -const char* fill_extrusion_pattern::fragmentSource = R"MBGL_SHADER( -uniform vec2 u_pattern_tl_a; -uniform vec2 u_pattern_br_a; -uniform vec2 u_pattern_tl_b; -uniform vec2 u_pattern_br_b; -uniform vec2 u_texsize; -uniform float u_mix; - -uniform sampler2D u_image; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; -varying vec4 v_lighting; - - -#ifndef HAS_UNIFORM_u_base -varying lowp float base; -#else -uniform lowp float u_base; -#endif - - -#ifndef HAS_UNIFORM_u_height -varying lowp float height; -#else -uniform lowp float u_height; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_base - lowp float base = u_base; -#endif - - -#ifdef HAS_UNIFORM_u_height - lowp float height = u_height; -#endif - - - vec2 imagecoord = mod(v_pos_a, 1.0); - vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); - vec4 color1 = texture2D(u_image, pos); - - vec2 imagecoord_b = mod(v_pos_b, 1.0); - vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b); - vec4 color2 = texture2D(u_image, pos2); - - vec4 mixedColor = mix(color1, color2, u_mix); - - gl_FragColor = mixedColor * v_lighting; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* fill_extrusion_pattern::vertexSource = source() + 28334; +const char* fill_extrusion_pattern::fragmentSource = source() + 30619; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp index 9ade598d10..873e49f8c2 100644 --- a/src/mbgl/shaders/fill_outline.cpp +++ b/src/mbgl/shaders/fill_outline.cpp @@ -1,99 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/fill_outline.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* fill_outline::name = "fill_outline"; -const char* fill_outline::vertexSource = R"MBGL_SHADER( -attribute vec2 a_pos; - -uniform mat4 u_matrix; -uniform vec2 u_world; - -varying vec2 v_pos; - - -#ifndef HAS_UNIFORM_u_outline_color -uniform lowp float a_outline_color_t; -attribute highp vec4 a_outline_color; -varying highp vec4 outline_color; -#else -uniform highp vec4 u_outline_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_outline_color - outline_color = unpack_mix_vec4(a_outline_color, a_outline_color_t); -#else - highp vec4 outline_color = u_outline_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - - gl_Position = u_matrix * vec4(a_pos, 0, 1); - v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world; -} - -)MBGL_SHADER"; -const char* fill_outline::fragmentSource = R"MBGL_SHADER( - -#ifndef HAS_UNIFORM_u_outline_color -varying highp vec4 outline_color; -#else -uniform highp vec4 u_outline_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -varying vec2 v_pos; - -void main() { - -#ifdef HAS_UNIFORM_u_outline_color - highp vec4 outline_color = u_outline_color; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - float dist = length(v_pos - gl_FragCoord.xy); - float alpha = 1.0 - smoothstep(0.0, 1.0, dist); - gl_FragColor = outline_color * (alpha * opacity); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* fill_outline::vertexSource = source() + 19276; +const char* fill_outline::fragmentSource = source() + 20180; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/fill_outline_pattern.cpp b/src/mbgl/shaders/fill_outline_pattern.cpp index 11cddb7d07..d1bcaa95bb 100644 --- a/src/mbgl/shaders/fill_outline_pattern.cpp +++ b/src/mbgl/shaders/fill_outline_pattern.cpp @@ -1,107 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/fill_outline_pattern.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* fill_outline_pattern::name = "fill_outline_pattern"; -const char* fill_outline_pattern::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_world; -uniform vec2 u_pattern_size_a; -uniform vec2 u_pattern_size_b; -uniform vec2 u_pixel_coord_upper; -uniform vec2 u_pixel_coord_lower; -uniform float u_scale_a; -uniform float u_scale_b; -uniform float u_tile_units_to_pixels; - -attribute vec2 a_pos; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; -varying vec2 v_pos; - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - - gl_Position = u_matrix * vec4(a_pos, 0, 1); - - v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos); - v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos); - - v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world; -} - -)MBGL_SHADER"; -const char* fill_outline_pattern::fragmentSource = R"MBGL_SHADER( -uniform vec2 u_pattern_tl_a; -uniform vec2 u_pattern_br_a; -uniform vec2 u_pattern_tl_b; -uniform vec2 u_pattern_br_b; -uniform vec2 u_texsize; -uniform float u_mix; - -uniform sampler2D u_image; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; -varying vec2 v_pos; - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - vec2 imagecoord = mod(v_pos_a, 1.0); - vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); - vec4 color1 = texture2D(u_image, pos); - - vec2 imagecoord_b = mod(v_pos_b, 1.0); - vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b); - vec4 color2 = texture2D(u_image, pos2); - - // find distance to outline for alpha interpolation - - float dist = length(v_pos - gl_FragCoord.xy); - float alpha = 1.0 - smoothstep(0.0, 1.0, dist); - - - gl_FragColor = mix(color1, color2, u_mix) * alpha * opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* fill_outline_pattern::vertexSource = source() + 20838; +const char* fill_outline_pattern::fragmentSource = source() + 21901; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/fill_pattern.cpp b/src/mbgl/shaders/fill_pattern.cpp index a3817c4426..88b4fc92a2 100644 --- a/src/mbgl/shaders/fill_pattern.cpp +++ b/src/mbgl/shaders/fill_pattern.cpp @@ -1,96 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/fill_pattern.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* fill_pattern::name = "fill_pattern"; -const char* fill_pattern::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_pattern_size_a; -uniform vec2 u_pattern_size_b; -uniform vec2 u_pixel_coord_upper; -uniform vec2 u_pixel_coord_lower; -uniform float u_scale_a; -uniform float u_scale_b; -uniform float u_tile_units_to_pixels; - -attribute vec2 a_pos; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - - gl_Position = u_matrix * vec4(a_pos, 0, 1); - - v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos); - v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos); -} - -)MBGL_SHADER"; -const char* fill_pattern::fragmentSource = R"MBGL_SHADER( -uniform vec2 u_pattern_tl_a; -uniform vec2 u_pattern_br_a; -uniform vec2 u_pattern_tl_b; -uniform vec2 u_pattern_br_b; -uniform vec2 u_texsize; -uniform float u_mix; - -uniform sampler2D u_image; - -varying vec2 v_pos_a; -varying vec2 v_pos_b; - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - vec2 imagecoord = mod(v_pos_a, 1.0); - vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); - vec4 color1 = texture2D(u_image, pos); - - vec2 imagecoord_b = mod(v_pos_b, 1.0); - vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b); - vec4 color2 = texture2D(u_image, pos2); - - gl_FragColor = mix(color1, color2, u_mix) * opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* fill_pattern::vertexSource = source() + 22998; +const char* fill_pattern::fragmentSource = source() + 23950; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/heatmap.cpp b/src/mbgl/shaders/heatmap.cpp index 19927cfcc6..c669e8e0af 100644 --- a/src/mbgl/shaders/heatmap.cpp +++ b/src/mbgl/shaders/heatmap.cpp @@ -1,128 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/heatmap.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* heatmap::name = "heatmap"; -const char* heatmap::vertexSource = R"MBGL_SHADER( - -#ifndef HAS_UNIFORM_u_weight -uniform lowp float a_weight_t; -attribute highp vec2 a_weight; -varying highp float weight; -#else -uniform highp float u_weight; -#endif - - -#ifndef HAS_UNIFORM_u_radius -uniform lowp float a_radius_t; -attribute mediump vec2 a_radius; -#else -uniform mediump float u_radius; -#endif - - -uniform mat4 u_matrix; -uniform float u_extrude_scale; -uniform float u_opacity; -uniform float u_intensity; - -attribute vec2 a_pos; - -varying vec2 v_extrude; - -// Effective "0" in the kernel density texture to adjust the kernel size to; -// this empirically chosen number minimizes artifacts on overlapping kernels -// for typical heatmap cases (assuming clustered source) -const highp float ZERO = 1.0 / 255.0 / 16.0; - -// Gaussian kernel coefficient: 1 / sqrt(2 * PI) -#define GAUSS_COEF 0.3989422804014327 - -void main(void) { - -#ifndef HAS_UNIFORM_u_weight - weight = unpack_mix_vec2(a_weight, a_weight_t); -#else - highp float weight = u_weight; -#endif - - -#ifndef HAS_UNIFORM_u_radius - mediump float radius = unpack_mix_vec2(a_radius, a_radius_t); -#else - mediump float radius = u_radius; -#endif - - - // unencode the extrusion vector that we snuck into the a_pos vector - vec2 unscaled_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); - - // This 'extrude' comes in ranging from [-1, -1], to [1, 1]. We'll use - // it to produce the vertices of a square mesh framing the point feature - // we're adding to the kernel density texture. We'll also pass it as - // a varying, so that the fragment shader can determine the distance of - // each fragment from the point feature. - // Before we do so, we need to scale it up sufficiently so that the - // kernel falls effectively to zero at the edge of the mesh. - // That is, we want to know S such that - // weight * u_intensity * GAUSS_COEF * exp(-0.5 * 3.0^2 * S^2) == ZERO - // Which solves to: - // S = sqrt(-2.0 * log(ZERO / (weight * u_intensity * GAUSS_COEF))) / 3.0 - float S = sqrt(-2.0 * log(ZERO / weight / u_intensity / GAUSS_COEF)) / 3.0; - - // Pass the varying in units of radius - v_extrude = S * unscaled_extrude; - - // Scale by radius and the zoom-based scale factor to produce actual - // mesh position - vec2 extrude = v_extrude * radius * u_extrude_scale; - - // multiply a_pos by 0.5, since we had it * 2 in order to sneak - // in extrusion data - vec4 pos = vec4(floor(a_pos * 0.5) + extrude, 0, 1); - - gl_Position = u_matrix * pos; -} - -)MBGL_SHADER"; -const char* heatmap::fragmentSource = R"MBGL_SHADER( - -#ifndef HAS_UNIFORM_u_weight -varying highp float weight; -#else -uniform highp float u_weight; -#endif - - -uniform highp float u_intensity; -varying vec2 v_extrude; - -// Gaussian kernel coefficient: 1 / sqrt(2 * PI) -#define GAUSS_COEF 0.3989422804014327 - -void main() { - -#ifdef HAS_UNIFORM_u_weight - highp float weight = u_weight; -#endif - - - // Kernel density estimation with a Gaussian kernel of size 5x5 - float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude); - float val = weight * u_intensity * GAUSS_COEF * exp(d); - - gl_FragColor = vec4(val, 1.0, 1.0, 1.0); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* heatmap::vertexSource = source() + 10789; +const char* heatmap::fragmentSource = source() + 13245; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/heatmap_texture.cpp b/src/mbgl/shaders/heatmap_texture.cpp index c5d35c48ae..8f5ec1f176 100644 --- a/src/mbgl/shaders/heatmap_texture.cpp +++ b/src/mbgl/shaders/heatmap_texture.cpp @@ -1,42 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/heatmap_texture.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* heatmap_texture::name = "heatmap_texture"; -const char* heatmap_texture::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_world; -attribute vec2 a_pos; -varying vec2 v_pos; - -void main() { - gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1); - - v_pos.x = a_pos.x; - v_pos.y = 1.0 - a_pos.y; -} - -)MBGL_SHADER"; -const char* heatmap_texture::fragmentSource = R"MBGL_SHADER( -uniform sampler2D u_image; -uniform sampler2D u_color_ramp; -uniform float u_opacity; -varying vec2 v_pos; - -void main() { - float t = texture2D(u_image, v_pos).r; - vec4 color = texture2D(u_color_ramp, vec2(t, 0.5)); - gl_FragColor = color * u_opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(0.0); -#endif -} - -)MBGL_SHADER"; +const char* heatmap_texture::vertexSource = source() + 13886; +const char* heatmap_texture::fragmentSource = source() + 14102; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/hillshade.cpp b/src/mbgl/shaders/hillshade.cpp index 4083faa4b4..ea81d7c10c 100644 --- a/src/mbgl/shaders/hillshade.cpp +++ b/src/mbgl/shaders/hillshade.cpp @@ -1,80 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/hillshade.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* hillshade::name = "hillshade"; -const char* hillshade::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; - -attribute vec2 a_pos; -attribute vec2 a_texture_pos; - -varying vec2 v_pos; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); - v_pos = a_texture_pos / 8192.0; -} - -)MBGL_SHADER"; -const char* hillshade::fragmentSource = R"MBGL_SHADER( -uniform sampler2D u_image; -varying vec2 v_pos; - -uniform vec2 u_latrange; -uniform vec2 u_light; -uniform vec4 u_shadow; -uniform vec4 u_highlight; -uniform vec4 u_accent; - -#define PI 3.141592653589793 - -void main() { - vec4 pixel = texture2D(u_image, v_pos); - - vec2 deriv = ((pixel.rg * 2.0) - 1.0); - - // We divide the slope by a scale factor based on the cosin of the pixel's approximate latitude - // to account for mercator projection distortion. see #4807 for details - float scaleFactor = cos(radians((u_latrange[0] - u_latrange[1]) * (1.0 - v_pos.y) + u_latrange[1])); - // We also multiply the slope by an arbitrary z-factor of 1.25 - float slope = atan(1.25 * length(deriv) / scaleFactor); - float aspect = deriv.x != 0.0 ? atan(deriv.y, -deriv.x) : PI / 2.0 * (deriv.y > 0.0 ? 1.0 : -1.0); - - float intensity = u_light.x; - // We add PI to make this property match the global light object, which adds PI/2 to the light's azimuthal - // position property to account for 0deg corresponding to north/the top of the viewport in the style spec - // and the original shader was written to accept (-illuminationDirection - 90) as the azimuthal. - float azimuth = u_light.y + PI; - - // We scale the slope exponentially based on intensity, using a calculation similar to - // the exponential interpolation function in the style spec: - // https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/expression/definitions/interpolate.js#L217-L228 - // so that higher intensity values create more opaque hillshading. - float base = 1.875 - intensity * 1.75; - float maxValue = 0.5 * PI; - float scaledSlope = intensity != 0.5 ? ((pow(base, slope) - 1.0) / (pow(base, maxValue) - 1.0)) * maxValue : slope; - - // The accent color is calculated with the cosine of the slope while the shade color is calculated with the sine - // so that the accent color's rate of change eases in while the shade color's eases out. - float accent = cos(scaledSlope); - // We multiply both the accent and shade color by a clamped intensity value - // so that intensities >= 0.5 do not additionally affect the color values - // while intensity values < 0.5 make the overall color more transparent. - vec4 accent_color = (1.0 - accent) * u_accent * clamp(intensity * 2.0, 0.0, 1.0); - float shade = abs(mod((aspect + azimuth) / PI + 0.5, 2.0) - 1.0); - vec4 shade_color = mix(u_shadow, u_highlight, shade) * sin(scaledSlope) * clamp(intensity * 2.0, 0.0, 1.0); - gl_FragColor = accent_color * (1.0 - shade_color.a) + shade_color; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* hillshade::vertexSource = source() + 34909; +const char* hillshade::fragmentSource = source() + 35108; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/hillshade_prepare.cpp b/src/mbgl/shaders/hillshade_prepare.cpp index 8d0571f6a4..fb610f01b2 100644 --- a/src/mbgl/shaders/hillshade_prepare.cpp +++ b/src/mbgl/shaders/hillshade_prepare.cpp @@ -1,100 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/hillshade_prepare.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* hillshade_prepare::name = "hillshade_prepare"; -const char* hillshade_prepare::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; - -attribute vec2 a_pos; -attribute vec2 a_texture_pos; - -varying vec2 v_pos; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); - v_pos = (a_texture_pos / 8192.0) / 2.0 + 0.25; -} - -)MBGL_SHADER"; -const char* hillshade_prepare::fragmentSource = R"MBGL_SHADER( -#ifdef GL_ES -precision highp float; -#endif - -uniform sampler2D u_image; -varying vec2 v_pos; -uniform vec2 u_dimension; -uniform float u_zoom; -uniform float u_maxzoom; - -float getElevation(vec2 coord, float bias) { - // Convert encoded elevation value to meters - vec4 data = texture2D(u_image, coord) * 255.0; - return (data.r + data.g * 256.0 + data.b * 256.0 * 256.0) / 4.0; -} - -void main() { - vec2 epsilon = 1.0 / u_dimension; - - // queried pixels: - // +-----------+ - // | | | | - // | a | b | c | - // | | | | - // +-----------+ - // | | | | - // | d | e | f | - // | | | | - // +-----------+ - // | | | | - // | g | h | i | - // | | | | - // +-----------+ - - float a = getElevation(v_pos + vec2(-epsilon.x, -epsilon.y), 0.0); - float b = getElevation(v_pos + vec2(0, -epsilon.y), 0.0); - float c = getElevation(v_pos + vec2(epsilon.x, -epsilon.y), 0.0); - float d = getElevation(v_pos + vec2(-epsilon.x, 0), 0.0); - float e = getElevation(v_pos, 0.0); - float f = getElevation(v_pos + vec2(epsilon.x, 0), 0.0); - float g = getElevation(v_pos + vec2(-epsilon.x, epsilon.y), 0.0); - float h = getElevation(v_pos + vec2(0, epsilon.y), 0.0); - float i = getElevation(v_pos + vec2(epsilon.x, epsilon.y), 0.0); - - // here we divide the x and y slopes by 8 * pixel size - // where pixel size (aka meters/pixel) is: - // circumference of the world / (pixels per tile * number of tiles) - // which is equivalent to: 8 * 40075016.6855785 / (512 * pow(2, u_zoom)) - // which can be reduced to: pow(2, 19.25619978527 - u_zoom) - // we want to vertically exaggerate the hillshading though, because otherwise - // it is barely noticeable at low zooms. to do this, we multiply this by some - // scale factor pow(2, (u_zoom - u_maxzoom) * a) where a is an arbitrary value - // Here we use a=0.3 which works out to the expression below. see - // nickidlugash's awesome breakdown for more info - // https://github.com/mapbox/mapbox-gl-js/pull/5286#discussion_r148419556 - float exaggeration = u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3; - - vec2 deriv = vec2( - (c + f + f + i) - (a + d + d + g), - (g + h + h + i) - (a + b + b + c) - ) / pow(2.0, (u_zoom - u_maxzoom) * exaggeration + 19.2562 - u_zoom); - - gl_FragColor = clamp(vec4( - deriv.x / 2.0 + 0.5, - deriv.y / 2.0 + 0.5, - 1.0, - 1.0), 0.0, 1.0); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* hillshade_prepare::vertexSource = source() + 32175; +const char* hillshade_prepare::fragmentSource = source() + 32389; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp index 68d2dcc468..1ba2a9f403 100644 --- a/src/mbgl/shaders/line.cpp +++ b/src/mbgl/shaders/line.cpp @@ -1,240 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/line.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* line::name = "line"; -const char* line::vertexSource = R"MBGL_SHADER( - - -// the distance over which the line edge fades out. -// Retina devices need a smaller distance to avoid aliasing. -#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0 - -// floor(127 / 2) == 63.0 -// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is -// stored in a byte (-128..127). we scale regular normals up to length 63, but -// there are also "special" normals that have a bigger length (of up to 126 in -// this case). -// #define scale 63.0 -#define scale 0.015873016 - -attribute vec4 a_pos_normal; -attribute vec4 a_data; - -uniform mat4 u_matrix; -uniform mediump float u_ratio; -uniform vec2 u_gl_units_to_pixels; - -varying vec2 v_normal; -varying vec2 v_width2; -varying float v_gamma_scale; -varying highp float v_linesofar; - - -#ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; -attribute highp vec4 a_color; -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; -attribute lowp vec2 a_blur; -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; -attribute mediump vec2 a_gapwidth; -#else -uniform mediump float u_gapwidth; -#endif - - -#ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; -attribute lowp vec2 a_offset; -#else -uniform lowp float u_offset; -#endif - - -#ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; -attribute mediump vec2 a_width; -#else -uniform mediump float u_width; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_color - color = unpack_mix_vec4(a_color, a_color_t); -#else - highp vec4 color = u_color; -#endif - - -#ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); -#else - lowp float blur = u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); -#else - mediump float gapwidth = u_gapwidth; -#endif - - -#ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); -#else - lowp float offset = u_offset; -#endif - - -#ifndef HAS_UNIFORM_u_width - mediump float width = unpack_mix_vec2(a_width, a_width_t); -#else - mediump float width = u_width; -#endif - - - vec2 a_extrude = a_data.xy - 128.0; - float a_direction = mod(a_data.z, 4.0) - 1.0; - - v_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0; - - vec2 pos = a_pos_normal.xy; - - // x is 1 if it's a round cap, 0 otherwise - // y is 1 if the normal points up, and -1 if it points down - mediump vec2 normal = a_pos_normal.zw; - v_normal = normal; - - // these transformations used to be applied in the JS and native code bases. - // moved them into the shader for clarity and simplicity. - gapwidth = gapwidth / 2.0; - float halfwidth = width / 2.0; - offset = -1.0 * offset; - - float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); - float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING; - - // Scale the extrusion vector down to a normal and then up by the line width - // of this vertex. - mediump vec2 dist = outset * a_extrude * scale; - - // Calculate the offset when drawing a line that is to the side of the actual line. - // We do this by creating a vector that points towards the extrude, but rotate - // it when we're drawing round end points (a_direction = -1 or 1) since their - // extrude vector points in another direction. - mediump float u = 0.5 * a_direction; - mediump float t = 1.0 - abs(u); - mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); - gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; - - // calculate how much the perspective view squishes or stretches the extrude - float extrude_length_without_perspective = length(dist); - float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels); - v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; - - v_width2 = vec2(outset, inset); -} - -)MBGL_SHADER"; -const char* line::fragmentSource = R"MBGL_SHADER( - -#ifndef HAS_UNIFORM_u_color -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_blur -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -varying vec2 v_width2; -varying vec2 v_normal; -varying float v_gamma_scale; - -void main() { - -#ifdef HAS_UNIFORM_u_color - highp vec4 color = u_color; -#endif - - -#ifdef HAS_UNIFORM_u_blur - lowp float blur = u_blur; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - // Calculate the distance of the pixel from the line in pixels. - float dist = length(v_normal) * v_width2.s; - - // Calculate the antialiasing fade factor. This is either when fading in - // the line in case of an offset line (v_width2.t) or when fading out - // (v_width2.s) - float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale; - float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); - - gl_FragColor = color * (alpha * opacity); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* line::vertexSource = source() + 37744; +const char* line::fragmentSource = source() + 42206; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp index be88255e3c..56eac4a666 100644 --- a/src/mbgl/shaders/line_pattern.cpp +++ b/src/mbgl/shaders/line_pattern.cpp @@ -1,241 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/line_pattern.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* line_pattern::name = "line_pattern"; -const char* line_pattern::vertexSource = R"MBGL_SHADER( -// floor(127 / 2) == 63.0 -// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is -// stored in a byte (-128..127). we scale regular normals up to length 63, but -// there are also "special" normals that have a bigger length (of up to 126 in -// this case). -// #define scale 63.0 -#define scale 0.015873016 - -// We scale the distance before adding it to the buffers so that we can store -// long distances for long segments. Use this value to unscale the distance. -#define LINE_DISTANCE_SCALE 2.0 - -// the distance over which the line edge fades out. -// Retina devices need a smaller distance to avoid aliasing. -#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0 - -attribute vec4 a_pos_normal; -attribute vec4 a_data; - -uniform mat4 u_matrix; -uniform mediump float u_ratio; -uniform vec2 u_gl_units_to_pixels; - -varying vec2 v_normal; -varying vec2 v_width2; -varying float v_linesofar; -varying float v_gamma_scale; - - -#ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; -attribute lowp vec2 a_blur; -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; -attribute lowp vec2 a_offset; -#else -uniform lowp float u_offset; -#endif - - -#ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; -attribute mediump vec2 a_gapwidth; -#else -uniform mediump float u_gapwidth; -#endif - - -#ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; -attribute mediump vec2 a_width; -#else -uniform mediump float u_width; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); -#else - lowp float blur = u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); -#else - lowp float offset = u_offset; -#endif - - -#ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); -#else - mediump float gapwidth = u_gapwidth; -#endif - - -#ifndef HAS_UNIFORM_u_width - mediump float width = unpack_mix_vec2(a_width, a_width_t); -#else - mediump float width = u_width; -#endif - - - vec2 a_extrude = a_data.xy - 128.0; - float a_direction = mod(a_data.z, 4.0) - 1.0; - float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; - - vec2 pos = a_pos_normal.xy; - - // x is 1 if it's a round cap, 0 otherwise - // y is 1 if the normal points up, and -1 if it points down - mediump vec2 normal = a_pos_normal.zw; - v_normal = normal; - - // these transformations used to be applied in the JS and native code bases. - // moved them into the shader for clarity and simplicity. - gapwidth = gapwidth / 2.0; - float halfwidth = width / 2.0; - offset = -1.0 * offset; - - float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); - float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING; - - // Scale the extrusion vector down to a normal and then up by the line width - // of this vertex. - mediump vec2 dist = outset * a_extrude * scale; - - // Calculate the offset when drawing a line that is to the side of the actual line. - // We do this by creating a vector that points towards the extrude, but rotate - // it when we're drawing round end points (a_direction = -1 or 1) since their - // extrude vector points in another direction. - mediump float u = 0.5 * a_direction; - mediump float t = 1.0 - abs(u); - mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); - gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; - - // calculate how much the perspective view squishes or stretches the extrude - float extrude_length_without_perspective = length(dist); - float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels); - v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; - - v_linesofar = a_linesofar; - v_width2 = vec2(outset, inset); -} - -)MBGL_SHADER"; -const char* line_pattern::fragmentSource = R"MBGL_SHADER( -uniform vec2 u_pattern_size_a; -uniform vec2 u_pattern_size_b; -uniform vec2 u_pattern_tl_a; -uniform vec2 u_pattern_br_a; -uniform vec2 u_pattern_tl_b; -uniform vec2 u_pattern_br_b; -uniform vec2 u_texsize; -uniform float u_fade; - -uniform sampler2D u_image; - -varying vec2 v_normal; -varying vec2 v_width2; -varying float v_linesofar; -varying float v_gamma_scale; - - -#ifndef HAS_UNIFORM_u_blur -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_blur - lowp float blur = u_blur; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - // Calculate the distance of the pixel from the line in pixels. - float dist = length(v_normal) * v_width2.s; - - // Calculate the antialiasing fade factor. This is either when fading in - // the line in case of an offset line (v_width2.t) or when fading out - // (v_width2.s) - float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale; - float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); - - float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0); - float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0); - - // v_normal.y is 0 at the midpoint of the line, -1 at the lower edge, 1 at the upper edge - // we clamp the line width outset to be between 0 and half the pattern height plus padding (2.0) - // to ensure we don't sample outside the designated symbol on the sprite sheet. - // 0.5 is added to shift the component to be bounded between 0 and 1 for interpolation of - // the texture coordinate - float y_a = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (u_pattern_size_a.y + 2.0) / 2.0) / u_pattern_size_a.y); - float y_b = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (u_pattern_size_b.y + 2.0) / 2.0) / u_pattern_size_b.y); - vec2 pos_a = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, vec2(x_a, y_a)); - vec2 pos_b = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, vec2(x_b, y_b)); - - vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade); - - gl_FragColor = color * alpha * opacity; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* line_pattern::vertexSource = source() + 43378; +const char* line_pattern::fragmentSource = source() + 47787; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp index c5d50566e8..f36cf2ba00 100644 --- a/src/mbgl/shaders/line_sdf.cpp +++ b/src/mbgl/shaders/line_sdf.cpp @@ -1,302 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/line_sdf.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* line_sdf::name = "line_sdf"; -const char* line_sdf::vertexSource = R"MBGL_SHADER( -// floor(127 / 2) == 63.0 -// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is -// stored in a byte (-128..127). we scale regular normals up to length 63, but -// there are also "special" normals that have a bigger length (of up to 126 in -// this case). -// #define scale 63.0 -#define scale 0.015873016 - -// We scale the distance before adding it to the buffers so that we can store -// long distances for long segments. Use this value to unscale the distance. -#define LINE_DISTANCE_SCALE 2.0 - -// the distance over which the line edge fades out. -// Retina devices need a smaller distance to avoid aliasing. -#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0 - -attribute vec4 a_pos_normal; -attribute vec4 a_data; - -uniform mat4 u_matrix; -uniform mediump float u_ratio; -uniform vec2 u_patternscale_a; -uniform float u_tex_y_a; -uniform vec2 u_patternscale_b; -uniform float u_tex_y_b; -uniform vec2 u_gl_units_to_pixels; - -varying vec2 v_normal; -varying vec2 v_width2; -varying vec2 v_tex_a; -varying vec2 v_tex_b; -varying float v_gamma_scale; - - -#ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; -attribute highp vec4 a_color; -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; -attribute lowp vec2 a_blur; -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; -attribute mediump vec2 a_gapwidth; -#else -uniform mediump float u_gapwidth; -#endif - - -#ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; -attribute lowp vec2 a_offset; -#else -uniform lowp float u_offset; -#endif - - -#ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; -attribute mediump vec2 a_width; -varying mediump float width; -#else -uniform mediump float u_width; -#endif - - -#ifndef HAS_UNIFORM_u_floorwidth -uniform lowp float a_floorwidth_t; -attribute lowp vec2 a_floorwidth; -varying lowp float floorwidth; -#else -uniform lowp float u_floorwidth; -#endif - - -void main() { - -#ifndef HAS_UNIFORM_u_color - color = unpack_mix_vec4(a_color, a_color_t); -#else - highp vec4 color = u_color; -#endif - - -#ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); -#else - lowp float blur = u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); -#else - mediump float gapwidth = u_gapwidth; -#endif - - -#ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); -#else - lowp float offset = u_offset; -#endif - - -#ifndef HAS_UNIFORM_u_width - width = unpack_mix_vec2(a_width, a_width_t); -#else - mediump float width = u_width; -#endif - - -#ifndef HAS_UNIFORM_u_floorwidth - floorwidth = unpack_mix_vec2(a_floorwidth, a_floorwidth_t); -#else - lowp float floorwidth = u_floorwidth; -#endif - - - vec2 a_extrude = a_data.xy - 128.0; - float a_direction = mod(a_data.z, 4.0) - 1.0; - float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; - - vec2 pos = a_pos_normal.xy; - - // x is 1 if it's a round cap, 0 otherwise - // y is 1 if the normal points up, and -1 if it points down - mediump vec2 normal = a_pos_normal.zw; - v_normal = normal; - - // these transformations used to be applied in the JS and native code bases. - // moved them into the shader for clarity and simplicity. - gapwidth = gapwidth / 2.0; - float halfwidth = width / 2.0; - offset = -1.0 * offset; - - float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); - float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING; - - // Scale the extrusion vector down to a normal and then up by the line width - // of this vertex. - mediump vec2 dist =outset * a_extrude * scale; - - // Calculate the offset when drawing a line that is to the side of the actual line. - // We do this by creating a vector that points towards the extrude, but rotate - // it when we're drawing round end points (a_direction = -1 or 1) since their - // extrude vector points in another direction. - mediump float u = 0.5 * a_direction; - mediump float t = 1.0 - abs(u); - mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); - gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; - - // calculate how much the perspective view squishes or stretches the extrude - float extrude_length_without_perspective = length(dist); - float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels); - v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; - - v_tex_a = vec2(a_linesofar * u_patternscale_a.x / floorwidth, normal.y * u_patternscale_a.y + u_tex_y_a); - v_tex_b = vec2(a_linesofar * u_patternscale_b.x / floorwidth, normal.y * u_patternscale_b.y + u_tex_y_b); - - v_width2 = vec2(outset, inset); -} - -)MBGL_SHADER"; -const char* line_sdf::fragmentSource = R"MBGL_SHADER( - -uniform sampler2D u_image; -uniform float u_sdfgamma; -uniform float u_mix; - -varying vec2 v_normal; -varying vec2 v_width2; -varying vec2 v_tex_a; -varying vec2 v_tex_b; -varying float v_gamma_scale; - - -#ifndef HAS_UNIFORM_u_color -varying highp vec4 color; -#else -uniform highp vec4 u_color; -#endif - - -#ifndef HAS_UNIFORM_u_blur -varying lowp float blur; -#else -uniform lowp float u_blur; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_width -varying mediump float width; -#else -uniform mediump float u_width; -#endif - - -#ifndef HAS_UNIFORM_u_floorwidth -varying lowp float floorwidth; -#else -uniform lowp float u_floorwidth; -#endif - - -void main() { - -#ifdef HAS_UNIFORM_u_color - highp vec4 color = u_color; -#endif - - -#ifdef HAS_UNIFORM_u_blur - lowp float blur = u_blur; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - -#ifdef HAS_UNIFORM_u_width - mediump float width = u_width; -#endif - - -#ifdef HAS_UNIFORM_u_floorwidth - lowp float floorwidth = u_floorwidth; -#endif - - - // Calculate the distance of the pixel from the line in pixels. - float dist = length(v_normal) * v_width2.s; - - // Calculate the antialiasing fade factor. This is either when fading in - // the line in case of an offset line (v_width2.t) or when fading out - // (v_width2.s) - float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale; - float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); - - float sdfdist_a = texture2D(u_image, v_tex_a).a; - float sdfdist_b = texture2D(u_image, v_tex_b).a; - float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix); - alpha *= smoothstep(0.5 - u_sdfgamma / floorwidth, 0.5 + u_sdfgamma / floorwidth, sdfdist); - - gl_FragColor = color * (alpha * opacity); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* line_sdf::vertexSource = source() + 50098; +const char* line_sdf::fragmentSource = source() + 55464; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/preludes.cpp b/src/mbgl/shaders/preludes.cpp index 6baa488a10..f4b0349355 100644 --- a/src/mbgl/shaders/preludes.cpp +++ b/src/mbgl/shaders/preludes.cpp @@ -1,106 +1,13 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/preludes.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { -const char* vertexPrelude = R"MBGL_SHADER( -#ifdef GL_ES -precision highp float; -#else - -#if !defined(lowp) -#define lowp -#endif - -#if !defined(mediump) -#define mediump -#endif - -#if !defined(highp) -#define highp -#endif - -#endif - -// Unpack a pair of values that have been packed into a single float. -// The packed values are assumed to be 8-bit unsigned integers, and are -// packed like so: -// packedValue = floor(input[0]) * 256 + input[1], -vec2 unpack_float(const float packedValue) { - int packedIntValue = int(packedValue); - int v0 = packedIntValue / 256; - return vec2(v0, packedIntValue - v0 * 256); -} - -vec2 unpack_opacity(const float packedOpacity) { - int intOpacity = int(packedOpacity) / 2; - return vec2(float(intOpacity) / 127.0, mod(packedOpacity, 2.0)); -} - -// To minimize the number of attributes needed, we encode a 4-component -// color into a pair of floats (i.e. a vec2) as follows: -// [ floor(color.r * 255) * 256 + color.g * 255, -// floor(color.b * 255) * 256 + color.g * 255 ] -vec4 decode_color(const vec2 encodedColor) { - return vec4( - unpack_float(encodedColor[0]) / 255.0, - unpack_float(encodedColor[1]) / 255.0 - ); -} - -// Unpack a pair of paint values and interpolate between them. -float unpack_mix_vec2(const vec2 packedValue, const float t) { - return mix(packedValue[0], packedValue[1], t); -} - -// Unpack a pair of paint values and interpolate between them. -vec4 unpack_mix_vec4(const vec4 packedColors, const float t) { - vec4 minColor = decode_color(vec2(packedColors[0], packedColors[1])); - vec4 maxColor = decode_color(vec2(packedColors[2], packedColors[3])); - return mix(minColor, maxColor, t); -} - -// The offset depends on how many pixels are between the world origin and the edge of the tile: -// vec2 offset = mod(pixel_coord, size) -// -// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile. -// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that. -// -// The pixel_coord is passed in as two 16 bit values: -// pixel_coord_upper = floor(pixel_coord / 2^16) -// pixel_coord_lower = mod(pixel_coord, 2^16) -// -// The offset is calculated in a series of steps that should preserve this precision: -vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower, - const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) { - - vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size); - return (tile_units_to_pixels * pos + offset) / pattern_size; -} - -)MBGL_SHADER"; -const char* fragmentPrelude = R"MBGL_SHADER( -#ifdef GL_ES -precision mediump float; -#else - -#if !defined(lowp) -#define lowp -#endif - -#if !defined(mediump) -#define mediump -#endif - -#if !defined(highp) -#define highp -#endif - -#endif - -)MBGL_SHADER"; +const char* vertexPrelude = source() + 0; +const char* fragmentPrelude = source() + 2557; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/raster.cpp b/src/mbgl/shaders/raster.cpp index 98291bfec6..5348f23257 100644 --- a/src/mbgl/shaders/raster.cpp +++ b/src/mbgl/shaders/raster.cpp @@ -1,90 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/raster.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* raster::name = "raster"; -const char* raster::vertexSource = R"MBGL_SHADER( -uniform mat4 u_matrix; -uniform vec2 u_tl_parent; -uniform float u_scale_parent; -uniform float u_buffer_scale; - -attribute vec2 a_pos; -attribute vec2 a_texture_pos; - -varying vec2 v_pos0; -varying vec2 v_pos1; - -void main() { - gl_Position = u_matrix * vec4(a_pos, 0, 1); - // We are using Int16 for texture position coordinates to give us enough precision for - // fractional coordinates. We use 8192 to scale the texture coordinates in the buffer - // as an arbitrarily high number to preserve adequate precision when rendering. - // This is also the same value as the EXTENT we are using for our tile buffer pos coordinates, - // so math for modifying either is consistent. - v_pos0 = (((a_texture_pos / 8192.0) - 0.5) / u_buffer_scale ) + 0.5; - v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent; -} - -)MBGL_SHADER"; -const char* raster::fragmentSource = R"MBGL_SHADER( -uniform float u_fade_t; -uniform float u_opacity; -uniform sampler2D u_image0; -uniform sampler2D u_image1; -varying vec2 v_pos0; -varying vec2 v_pos1; - -uniform float u_brightness_low; -uniform float u_brightness_high; - -uniform float u_saturation_factor; -uniform float u_contrast_factor; -uniform vec3 u_spin_weights; - -void main() { - - // read and cross-fade colors from the main and parent tiles - vec4 color0 = texture2D(u_image0, v_pos0); - vec4 color1 = texture2D(u_image1, v_pos1); - if (color0.a > 0.0) { - color0.rgb = color0.rgb / color0.a; - } - if (color1.a > 0.0) { - color1.rgb = color1.rgb / color1.a; - } - vec4 color = mix(color0, color1, u_fade_t); - color.a *= u_opacity; - vec3 rgb = color.rgb; - - // spin - rgb = vec3( - dot(rgb, u_spin_weights.xyz), - dot(rgb, u_spin_weights.zxy), - dot(rgb, u_spin_weights.yzx)); - - // saturation - float average = (color.r + color.g + color.b) / 3.0; - rgb += (average - rgb) * u_saturation_factor; - - // contrast - rgb = (rgb - 0.5) * u_contrast_factor + 0.5; - - // brightness - vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low); - vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high); - - gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb) * color.a, color.a); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* raster::vertexSource = source() + 57390; +const char* raster::fragmentSource = source() + 58203; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/source.cpp b/src/mbgl/shaders/source.cpp new file mode 100644 index 0000000000..d5a4593ad9 --- /dev/null +++ b/src/mbgl/shaders/source.cpp @@ -0,0 +1,1468 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/shaders/source.hpp> +#include <mbgl/util/compression.hpp> + +#include <cstdint> + +namespace mbgl { +namespace shaders { + +const char* source() { + static const uint8_t compressed[] = { + 0x78, 0xda, 0xed, 0x7d, 0x6b, 0x73, 0x1b, 0x37, + 0xb2, 0xe8, 0x7e, 0xf6, 0xaf, 0x40, 0x36, 0x55, + 0xc7, 0xa4, 0xcc, 0xb7, 0x24, 0x5b, 0x96, 0x56, + 0x27, 0xe5, 0x93, 0x38, 0x39, 0xbe, 0x37, 0x9b, + 0xb8, 0x22, 0x67, 0xb3, 0x75, 0x5c, 0x5e, 0xd6, + 0x0c, 0x39, 0x24, 0x67, 0x3d, 0x9c, 0x61, 0x66, + 0x86, 0xa2, 0xe4, 0x73, 0xf3, 0xdf, 0x6f, 0x3f, + 0xf0, 0x9c, 0x97, 0x28, 0x59, 0x92, 0x65, 0x87, + 0x5b, 0xab, 0x58, 0x1a, 0x00, 0x8d, 0x06, 0xd0, + 0x68, 0x74, 0x37, 0x1a, 0xdd, 0x5f, 0x87, 0xb3, + 0x69, 0x30, 0x13, 0x3f, 0xfc, 0x38, 0x7e, 0x79, + 0xf6, 0x68, 0x95, 0x06, 0x93, 0x30, 0x0b, 0x93, + 0x58, 0x2c, 0xc2, 0xf9, 0x62, 0x25, 0x66, 0x51, + 0xe2, 0xe5, 0x27, 0x8f, 0xbe, 0x0e, 0xa2, 0x2c, + 0x78, 0xf4, 0xe8, 0xeb, 0x70, 0x26, 0xbe, 0x82, + 0xca, 0x61, 0x1c, 0x4c, 0x5b, 0x51, 0xb2, 0x59, + 0xb5, 0x1f, 0x7d, 0xcd, 0x7f, 0x0a, 0xfc, 0x0b, + 0xaa, 0xc5, 0xd3, 0x70, 0x56, 0xa8, 0xb7, 0x0c, + 0xa6, 0xe1, 0x7a, 0x69, 0x55, 0x95, 0x1f, 0xaa, + 0x6b, 0x53, 0xb7, 0xa6, 0x2e, 0xfd, 0x69, 0x6a, + 0xca, 0x7f, 0xfb, 0x7d, 0xf1, 0x6b, 0xbc, 0xf2, + 0x26, 0xef, 0x85, 0x27, 0x56, 0x5e, 0x98, 0x8a, + 0x64, 0x26, 0xce, 0xbd, 0x68, 0x1d, 0x64, 0x22, + 0x5f, 0x78, 0xb9, 0x58, 0x78, 0xe7, 0x81, 0xf0, + 0x83, 0x20, 0x16, 0x58, 0x29, 0x98, 0x8a, 0x30, + 0xce, 0x13, 0xa8, 0x9b, 0x85, 0xf1, 0x3c, 0x0a, + 0x78, 0x50, 0x3d, 0x84, 0xf2, 0x66, 0x11, 0xa8, + 0x2a, 0xb2, 0xbd, 0x97, 0x06, 0xc2, 0xcb, 0xb2, + 0x35, 0x20, 0x29, 0xa0, 0x8d, 0x1f, 0x88, 0xa3, + 0xae, 0x1f, 0xe6, 0x62, 0x1d, 0x67, 0xe1, 0x3c, + 0x66, 0x50, 0xc1, 0x3c, 0x48, 0xb3, 0x8e, 0xf0, + 0xe2, 0x29, 0x56, 0x47, 0x38, 0x12, 0x46, 0x14, + 0xbe, 0x0f, 0x44, 0x96, 0x1c, 0x9b, 0x4f, 0xff, + 0x40, 0xa8, 0xe2, 0x14, 0xbb, 0x4c, 0xd2, 0x56, + 0x18, 0xaf, 0xd6, 0xf9, 0xdb, 0xc1, 0xbb, 0xb6, + 0xd8, 0x13, 0xa3, 0xc3, 0xa7, 0xe2, 0x89, 0xe0, + 0x2f, 0xc3, 0x77, 0x9d, 0x47, 0xe7, 0xc1, 0x64, + 0x04, 0xbd, 0x60, 0xb3, 0x31, 0x21, 0xd8, 0x9a, + 0x24, 0x71, 0x96, 0x33, 0xb2, 0x36, 0xb4, 0xb6, + 0xf8, 0xdf, 0x47, 0x02, 0xfe, 0x07, 0x88, 0xc8, + 0xcf, 0xaf, 0xe2, 0x5c, 0xf5, 0x03, 0x1f, 0x5b, + 0x76, 0xdd, 0x13, 0x5d, 0xf5, 0x7c, 0x00, 0xc5, + 0x85, 0xfa, 0x7d, 0xc4, 0x82, 0xab, 0xa4, 0x41, + 0xbe, 0x4e, 0x63, 0x81, 0x58, 0xb4, 0xce, 0x07, + 0x9d, 0x62, 0xcd, 0x2e, 0xb6, 0x27, 0xa4, 0x01, + 0xe4, 0x1f, 0x8f, 0x1c, 0x6c, 0x13, 0xf8, 0x6f, + 0x98, 0x5f, 0x56, 0xe0, 0xfb, 0x33, 0x97, 0xd8, + 0x18, 0xc3, 0x8f, 0xfc, 0xea, 0x60, 0xab, 0x6b, + 0x02, 0x4a, 0x65, 0x84, 0x78, 0x3e, 0x4c, 0x53, + 0xac, 0x36, 0x1c, 0x3d, 0xeb, 0x01, 0x9e, 0xcb, + 0x64, 0xea, 0x82, 0xe8, 0x88, 0x51, 0x6f, 0xd0, + 0x66, 0x2c, 0x71, 0x85, 0x13, 0xb1, 0x0c, 0xe3, + 0x70, 0x19, 0x7e, 0x08, 0x80, 0x36, 0x02, 0x11, + 0xaf, 0x97, 0x7e, 0x40, 0x04, 0xe3, 0xe5, 0x79, + 0x1a, 0xfa, 0xeb, 0x1c, 0x16, 0x3d, 0x0e, 0x82, + 0x69, 0x30, 0xed, 0x88, 0x4d, 0x20, 0x82, 0x78, + 0x92, 0x4c, 0x81, 0x04, 0xc4, 0x41, 0x77, 0x92, + 0x2c, 0x57, 0x49, 0x1c, 0xc4, 0x39, 0xc2, 0x99, + 0x24, 0x51, 0x92, 0x2a, 0x3a, 0x52, 0x34, 0x47, + 0x78, 0x65, 0xa2, 0x15, 0xf6, 0x82, 0x1e, 0x7c, + 0x46, 0x5c, 0xdb, 0x40, 0x3d, 0x62, 0x96, 0x44, + 0xb0, 0x1f, 0x32, 0xa2, 0x83, 0xb7, 0x72, 0xed, + 0x09, 0x40, 0x2f, 0xa5, 0x49, 0x3c, 0x34, 0x04, + 0xc0, 0x9f, 0xe7, 0xfc, 0xb9, 0x83, 0x0d, 0x84, + 0xd3, 0xc0, 0x6f, 0x6c, 0x20, 0xde, 0xe1, 0x4a, + 0x1c, 0x88, 0x69, 0x80, 0x58, 0x8f, 0xa9, 0x4c, + 0xae, 0x03, 0xad, 0x10, 0x8f, 0x66, 0xfa, 0x2d, + 0x7e, 0x57, 0xab, 0x60, 0x26, 0xf6, 0xa0, 0x45, + 0x1f, 0xf0, 0x7f, 0x0e, 0xe1, 0xd9, 0xad, 0x88, + 0x5a, 0x91, 0x4e, 0x0e, 0x61, 0xb6, 0xb7, 0xa8, + 0x3e, 0x34, 0xd5, 0xa9, 0xb6, 0x5e, 0x88, 0xd2, + 0x86, 0x85, 0x7f, 0x91, 0x2c, 0xe5, 0xb6, 0x8b, + 0x79, 0x67, 0xa5, 0xab, 0x24, 0xf2, 0x72, 0xdc, + 0xbc, 0xf9, 0x06, 0xf7, 0x2f, 0x2c, 0xd9, 0xb2, + 0xf7, 0x88, 0x69, 0x4a, 0x76, 0xba, 0x0c, 0x2f, + 0xc6, 0x44, 0x15, 0xd6, 0x38, 0x2d, 0x92, 0xef, + 0x08, 0x9b, 0x0e, 0xf3, 0xc2, 0xa8, 0xa1, 0xb1, + 0xbd, 0x3f, 0x60, 0x74, 0x1d, 0xbb, 0x31, 0xee, + 0x44, 0x68, 0x73, 0x1b, 0x38, 0xd3, 0xba, 0xb8, + 0x28, 0x1f, 0x18, 0x94, 0x0f, 0x64, 0xaf, 0x34, + 0x69, 0x59, 0x0d, 0xce, 0x54, 0x0f, 0xa8, 0x97, + 0x2a, 0xc1, 0x76, 0x71, 0x56, 0x99, 0xa6, 0xc0, + 0x06, 0x62, 0x8d, 0x45, 0x7e, 0x80, 0xb5, 0x90, + 0x0c, 0x80, 0x21, 0x79, 0x17, 0x5b, 0x42, 0x1a, + 0x15, 0x21, 0xed, 0x6b, 0x48, 0xd6, 0x3c, 0x2a, + 0xcc, 0x3a, 0x1a, 0xb2, 0x3d, 0x77, 0xc8, 0x5a, + 0x93, 0xd9, 0x2c, 0x0b, 0x72, 0xe8, 0x6d, 0x05, + 0x8c, 0x3b, 0x13, 0x78, 0xaa, 0x24, 0x1b, 0xa8, + 0x1d, 0x5f, 0x8a, 0x55, 0x78, 0x01, 0x67, 0x0a, + 0xb1, 0x5b, 0x6b, 0xde, 0xc4, 0x26, 0x49, 0xa3, + 0xa9, 0x48, 0xd2, 0x70, 0x1e, 0xc6, 0x34, 0xc1, + 0xf8, 0x31, 0x98, 0xce, 0x11, 0x16, 0xfd, 0x9e, + 0x87, 0x51, 0x40, 0xfb, 0x8a, 0xd6, 0x5d, 0x76, + 0x70, 0xca, 0x6c, 0x00, 0x41, 0xc2, 0x98, 0x92, + 0x14, 0xb6, 0x72, 0x06, 0x1b, 0xbe, 0x0d, 0xf5, + 0xb0, 0xea, 0x8b, 0x9c, 0xce, 0x11, 0xf1, 0x21, + 0x49, 0x96, 0x22, 0x0a, 0xce, 0xb1, 0x63, 0x80, + 0x85, 0x9c, 0x1e, 0x7f, 0x80, 0xcf, 0xc7, 0xb4, + 0xb8, 0x8c, 0xd2, 0xb5, 0xd1, 0xd1, 0x27, 0xc9, + 0x3c, 0xca, 0x22, 0x91, 0xad, 0x82, 0x09, 0x8c, + 0x34, 0xba, 0x14, 0xf3, 0xb5, 0x97, 0x7a, 0x40, + 0x1f, 0x40, 0x2a, 0xc3, 0xa7, 0x02, 0x0e, 0x91, + 0x8c, 0x7a, 0xd1, 0x27, 0xec, 0x0c, 0x96, 0xc2, + 0x3a, 0x65, 0xb3, 0x9e, 0xf8, 0x2d, 0x20, 0x56, + 0x04, 0xa3, 0x49, 0x91, 0x5b, 0x79, 0x31, 0x1d, + 0x67, 0x3d, 0x39, 0x0c, 0x3a, 0xac, 0xcc, 0x18, + 0x45, 0x98, 0xc1, 0x22, 0x65, 0x19, 0x9d, 0x49, + 0xc8, 0x75, 0xf2, 0x4d, 0x22, 0x3b, 0x92, 0x14, + 0xca, 0xe7, 0x90, 0x69, 0x31, 0x5e, 0xaf, 0x56, + 0x41, 0xaa, 0x4f, 0x23, 0x1b, 0x16, 0x6c, 0xd9, + 0x7f, 0x0d, 0x9f, 0xb6, 0x8b, 0x0d, 0x80, 0x8b, + 0x51, 0x83, 0xd2, 0xf4, 0xaa, 0xda, 0x85, 0x95, + 0x06, 0x94, 0x26, 0x5e, 0x34, 0x59, 0xe3, 0x7e, + 0x60, 0xb4, 0x44, 0x16, 0xa4, 0x61, 0x40, 0x23, + 0xcf, 0xf2, 0x60, 0x25, 0x0f, 0xe8, 0x6c, 0x91, + 0xac, 0x61, 0x62, 0x61, 0x2e, 0xa0, 0xf8, 0x1c, + 0xc7, 0x8a, 0x83, 0x51, 0x33, 0x73, 0xcc, 0xc7, + 0xcb, 0x3c, 0xc8, 0xc7, 0x2b, 0xe0, 0xd2, 0x41, + 0x1a, 0x8f, 0x57, 0x49, 0xe6, 0xec, 0xf7, 0xe2, + 0xa0, 0xd4, 0x0e, 0x2a, 0x95, 0xd2, 0x08, 0x98, + 0x71, 0x39, 0xfc, 0x82, 0xc1, 0x22, 0x95, 0x14, + 0x36, 0x1f, 0x2c, 0xe8, 0x78, 0x1d, 0xc3, 0x62, + 0x8d, 0xf3, 0x64, 0xcc, 0x24, 0xe1, 0x02, 0x4f, + 0x32, 0xdc, 0x9f, 0x6a, 0x5b, 0x15, 0x68, 0x50, + 0xfd, 0x54, 0x20, 0x68, 0xf7, 0x29, 0xd9, 0x79, + 0x6f, 0x50, 0xf3, 0x19, 0xf8, 0x7c, 0x79, 0x10, + 0x6e, 0x55, 0x67, 0x3b, 0xb6, 0xaa, 0xd0, 0x06, + 0x60, 0x80, 0x2c, 0x80, 0x62, 0x0c, 0x91, 0x2f, + 0xdb, 0x10, 0x70, 0xa3, 0xfe, 0xe5, 0xeb, 0x6a, + 0xe1, 0x4f, 0x8a, 0x68, 0x0f, 0x53, 0xfc, 0xfb, + 0x8b, 0x3e, 0xb9, 0x79, 0x01, 0x3c, 0xa4, 0x8e, + 0x93, 0x47, 0x8f, 0x60, 0xf8, 0xb0, 0xa5, 0x96, + 0xc0, 0x5f, 0x72, 0xe0, 0xbc, 0x63, 0xf8, 0x27, + 0x0d, 0x2f, 0xe0, 0xfb, 0x79, 0x12, 0xc2, 0x96, + 0x02, 0xce, 0xdd, 0x52, 0x8c, 0x75, 0x1e, 0x8d, + 0x5f, 0x27, 0x59, 0x98, 0xe3, 0x50, 0x4f, 0x75, + 0x55, 0x98, 0x2f, 0x62, 0xd2, 0x04, 0xaf, 0x23, + 0x60, 0x6d, 0x86, 0xc4, 0xcd, 0xfe, 0xa2, 0x00, + 0x33, 0x4b, 0x67, 0xae, 0x79, 0xa2, 0xbb, 0x93, + 0x87, 0x93, 0x12, 0x83, 0xea, 0x3a, 0xfc, 0x3e, + 0xf5, 0xe6, 0x8a, 0xfd, 0x4a, 0x18, 0xd0, 0xa1, + 0xdd, 0x4c, 0xae, 0xc5, 0xcf, 0xff, 0x78, 0xf9, + 0xcb, 0x77, 0xbf, 0xbc, 0xf8, 0x6d, 0xfc, 0xea, + 0xa7, 0xb3, 0xd7, 0x2f, 0xbf, 0x7d, 0xf3, 0xf3, + 0x2f, 0x55, 0x20, 0x08, 0xd3, 0x21, 0x48, 0x3a, + 0x27, 0x6a, 0x5a, 0x2c, 0x44, 0x0b, 0x33, 0x60, + 0xe1, 0x0f, 0x42, 0xdb, 0xd8, 0x26, 0x82, 0xb1, + 0xd7, 0x5c, 0xec, 0x97, 0x8b, 0x8b, 0x94, 0xdd, + 0x58, 0x83, 0x28, 0xb7, 0x3c, 0x57, 0x19, 0x70, + 0x09, 0xa7, 0x6f, 0xb7, 0xc0, 0x2f, 0x17, 0x54, + 0x11, 0x38, 0xcc, 0x59, 0x0d, 0x29, 0x9c, 0x7b, + 0xe9, 0x25, 0xc8, 0xfa, 0xfc, 0xf1, 0x1c, 0x3f, + 0x62, 0x67, 0x15, 0x5f, 0xfd, 0x8f, 0xa6, 0x0f, + 0x66, 0x04, 0xdc, 0x05, 0x54, 0x2e, 0x32, 0xad, + 0x8a, 0x09, 0xeb, 0x54, 0xcd, 0x51, 0xc7, 0xcc, + 0x0a, 0x91, 0x85, 0xbb, 0x48, 0x9d, 0x9a, 0x19, + 0xe8, 0xf0, 0x88, 0xd5, 0x29, 0xcf, 0x43, 0xba, + 0x15, 0x2c, 0xfc, 0x32, 0x16, 0xfe, 0xd5, 0x58, + 0xb8, 0x9b, 0xc5, 0xa6, 0xa6, 0x3c, 0x6a, 0x20, + 0x35, 0x3f, 0x6d, 0x28, 0x84, 0x96, 0x7e, 0x53, + 0xcb, 0x72, 0x61, 0x1e, 0x5c, 0x30, 0x83, 0x2b, + 0x12, 0xd1, 0xd2, 0xde, 0x0d, 0xe5, 0x7d, 0xab, + 0x4a, 0x32, 0x6f, 0xb9, 0x8a, 0x82, 0x74, 0xf4, + 0x1d, 0x94, 0x86, 0x4b, 0x6f, 0x1e, 0x7c, 0x3c, + 0x45, 0x51, 0x05, 0x82, 0xc5, 0xe7, 0x2d, 0x9f, + 0x16, 0x12, 0x0e, 0x10, 0x12, 0x6d, 0x64, 0x5d, + 0x11, 0xd9, 0xf6, 0x29, 0xc9, 0x58, 0xee, 0x04, + 0x02, 0x07, 0xd7, 0xa3, 0xeb, 0x14, 0xe6, 0xcf, + 0x2d, 0x33, 0x5d, 0xd9, 0x12, 0x20, 0x71, 0x9d, + 0x21, 0x80, 0x86, 0x7a, 0x70, 0x6e, 0x04, 0xa3, + 0xef, 0x5a, 0x72, 0x84, 0x1d, 0xc1, 0x0b, 0x58, + 0x85, 0x2c, 0x51, 0x94, 0x41, 0xd7, 0xaf, 0x42, + 0x77, 0x54, 0x85, 0xaf, 0xdf, 0x80, 0xaf, 0x5f, + 0x87, 0xef, 0xd8, 0x2f, 0x61, 0x3c, 0xaa, 0xc5, + 0x78, 0xa4, 0x50, 0x2e, 0x70, 0x47, 0x44, 0x85, + 0x07, 0xdb, 0x91, 0x20, 0x3a, 0xbc, 0xfc, 0xed, + 0xfb, 0xe6, 0xb9, 0x7e, 0x92, 0x44, 0x7a, 0x53, + 0x6d, 0xc2, 0x7c, 0x01, 0x35, 0x56, 0xa5, 0xe2, + 0x55, 0x98, 0x4f, 0x16, 0x15, 0xc5, 0x92, 0xa0, + 0x61, 0xec, 0xe9, 0x1a, 0xe4, 0x75, 0x82, 0x62, + 0x4a, 0x2d, 0xe1, 0x11, 0x8f, 0x14, 0x6f, 0x19, + 0xa4, 0x1e, 0xee, 0xca, 0x49, 0x80, 0x5a, 0xc9, + 0x78, 0x1a, 0x66, 0xb9, 0x17, 0x4f, 0x82, 0x7a, + 0x36, 0x89, 0xc3, 0x8f, 0x71, 0xfc, 0xff, 0xfd, + 0xe2, 0x6c, 0xfc, 0xeb, 0x4f, 0xaf, 0xbe, 0xff, + 0xf9, 0x97, 0xbf, 0x8f, 0xe5, 0xe1, 0xa4, 0x7b, + 0xc1, 0xa3, 0x5d, 0x76, 0xe2, 0x71, 0xd1, 0x18, + 0x44, 0x02, 0x03, 0x91, 0xb1, 0xa0, 0xd5, 0xf2, + 0xd4, 0xd9, 0xa8, 0xf6, 0x85, 0x55, 0x26, 0x4b, + 0x58, 0x94, 0x70, 0x47, 0xe0, 0x9e, 0xab, 0xea, + 0xb4, 0xaf, 0x41, 0x2e, 0xf5, 0x40, 0x7c, 0xc8, + 0xaa, 0xb1, 0xe3, 0x32, 0x17, 0x3d, 0x25, 0xca, + 0xc8, 0x81, 0x73, 0x15, 0x83, 0xa1, 0x23, 0xe9, + 0x08, 0x55, 0xea, 0x62, 0xe9, 0xd6, 0x59, 0x8f, + 0x4d, 0xad, 0x46, 0x4c, 0xfd, 0x68, 0x5d, 0x33, + 0x8b, 0x58, 0xe2, 0x62, 0x49, 0xc5, 0x12, 0x45, + 0x2c, 0x35, 0x08, 0x5a, 0x0d, 0xb9, 0xc0, 0xc5, + 0xcd, 0x2a, 0x5e, 0x8f, 0x55, 0x85, 0x46, 0xb4, + 0x24, 0xf1, 0x57, 0x63, 0x26, 0x0b, 0xeb, 0x91, + 0xd3, 0x5b, 0xa7, 0x02, 0x3f, 0x5d, 0xd6, 0x80, + 0xa2, 0x55, 0xa7, 0x11, 0xcb, 0x2c, 0x4f, 0x93, + 0xf7, 0x41, 0x13, 0x29, 0xda, 0x35, 0x1a, 0x28, + 0xd2, 0xae, 0x56, 0x49, 0x98, 0x6e, 0x85, 0x06, + 0xfa, 0x2c, 0x56, 0xdc, 0x06, 0xff, 0x4d, 0x38, + 0xcd, 0x17, 0x8d, 0xf8, 0x53, 0x8d, 0x46, 0x92, + 0xb5, 0x2b, 0xd6, 0x11, 0xae, 0x5b, 0xa7, 0x99, + 0x7c, 0x8b, 0x75, 0xb7, 0x19, 0x47, 0x23, 0xd1, + 0xb8, 0x75, 0xea, 0x69, 0xc7, 0xad, 0x57, 0x49, + 0x42, 0xc5, 0x2a, 0x0d, 0x94, 0x54, 0xae, 0x2a, + 0x07, 0x62, 0x1d, 0xca, 0xfb, 0x70, 0x28, 0x4f, + 0xbd, 0xdc, 0x73, 0xce, 0x64, 0xfc, 0x4d, 0x9d, + 0xcb, 0x8d, 0x1c, 0x90, 0x95, 0x46, 0x29, 0xb2, + 0x17, 0x2c, 0x39, 0x92, 0xd5, 0x75, 0x0c, 0x4f, + 0x6c, 0x2b, 0x6c, 0xb1, 0x59, 0x91, 0xf1, 0x19, + 0xa1, 0xdf, 0x20, 0xda, 0xd0, 0xbf, 0x64, 0x72, + 0xa4, 0xe1, 0xd1, 0xaf, 0x25, 0x0c, 0x46, 0x2d, + 0xc5, 0xcb, 0x3a, 0x16, 0xe3, 0x73, 0x70, 0xa8, + 0x62, 0x6d, 0x84, 0x47, 0x91, 0x7f, 0x35, 0x20, + 0x42, 0x3c, 0x0c, 0xcb, 0xf1, 0x97, 0x4a, 0x24, + 0xb0, 0xa0, 0xa3, 0x79, 0x9a, 0x83, 0x40, 0x81, + 0x75, 0x51, 0xdf, 0x2e, 0x8b, 0x6a, 0xe8, 0x59, + 0x51, 0x1c, 0x56, 0x49, 0xb4, 0xc5, 0xb8, 0xdc, + 0x7f, 0xa2, 0xcc, 0xbe, 0x16, 0xf3, 0xaa, 0xc3, + 0xc2, 0x82, 0x53, 0xa6, 0x9b, 0x06, 0x5c, 0x1c, + 0x66, 0x84, 0xf5, 0xec, 0x0f, 0x95, 0xc4, 0x61, + 0x57, 0xe8, 0x94, 0x98, 0x55, 0x1d, 0xa9, 0x14, + 0xc1, 0xd6, 0xb0, 0x9c, 0xab, 0x31, 0x65, 0xb6, + 0x63, 0x61, 0x4a, 0x1f, 0x2a, 0xe7, 0xcf, 0xae, + 0xd0, 0x29, 0xb1, 0xa5, 0x06, 0x82, 0x2a, 0x42, + 0xae, 0xe1, 0x2b, 0x57, 0x23, 0x6b, 0xaf, 0xb4, + 0xfb, 0xa9, 0x09, 0x61, 0x6b, 0xdd, 0x8b, 0xfc, + 0xa7, 0x6e, 0xf9, 0xcb, 0xc0, 0xeb, 0x99, 0x08, + 0x36, 0xed, 0x83, 0x88, 0x1a, 0xcb, 0x0b, 0x01, + 0x32, 0xfc, 0xa1, 0x18, 0x46, 0xf6, 0x11, 0x40, + 0x25, 0x87, 0x25, 0x22, 0x5b, 0xd6, 0x26, 0x10, + 0x59, 0xbc, 0x9e, 0xbc, 0xe7, 0xcb, 0x01, 0xac, + 0x47, 0xe2, 0x95, 0xac, 0x63, 0xa4, 0x64, 0x29, + 0xc4, 0xb1, 0x1c, 0x39, 0x22, 0x2b, 0x91, 0xd4, + 0x24, 0xf1, 0xc2, 0x02, 0x2d, 0x3f, 0xbd, 0x81, + 0xe8, 0x4a, 0xd9, 0x5a, 0xf5, 0xbf, 0x5c, 0x47, + 0x79, 0xb8, 0x8a, 0x2e, 0x25, 0x4c, 0xff, 0x52, + 0x0c, 0x7a, 0x87, 0x68, 0xdd, 0x04, 0xb9, 0x0e, + 0x7b, 0x5e, 0x78, 0x53, 0x11, 0xe6, 0xd8, 0x18, + 0xad, 0x6d, 0x20, 0x3e, 0x07, 0x29, 0x5e, 0x5b, + 0x65, 0x71, 0xe0, 0xbd, 0x57, 0x30, 0xa0, 0xc0, + 0x60, 0x8e, 0xdc, 0xd0, 0xe0, 0x34, 0x09, 0xd3, + 0x09, 0xc8, 0xa5, 0x2c, 0x30, 0x6a, 0xc3, 0x20, + 0xf7, 0xb5, 0x87, 0x5d, 0xa9, 0x0b, 0xa4, 0x99, + 0x68, 0x15, 0xa5, 0x54, 0xc5, 0x42, 0x0d, 0xb0, + 0x24, 0x8d, 0x41, 0xec, 0x5c, 0x19, 0xcd, 0xd9, + 0x01, 0x7f, 0xa2, 0x6b, 0x33, 0x34, 0x57, 0x24, + 0xb6, 0xa1, 0x31, 0xdf, 0x75, 0x81, 0x3d, 0x39, + 0xd5, 0x13, 0xb8, 0x27, 0x5a, 0x92, 0x99, 0x3d, + 0x71, 0x88, 0x90, 0x65, 0xfb, 0x82, 0xac, 0xac, + 0xe0, 0xfd, 0x21, 0x90, 0x22, 0x0a, 0x9d, 0xc0, + 0xe4, 0xbc, 0xc6, 0x31, 0xe1, 0x69, 0x81, 0x0b, + 0xc7, 0xf8, 0x0a, 0xc4, 0x89, 0xfe, 0x06, 0xbc, + 0x44, 0x30, 0x9b, 0xc1, 0x42, 0x86, 0xe7, 0x01, + 0x2c, 0x02, 0xc1, 0xcc, 0x70, 0xc2, 0xed, 0x2a, + 0x45, 0x90, 0x6f, 0x12, 0xc0, 0x7e, 0x8d, 0x43, + 0xf6, 0x26, 0x39, 0x13, 0x0e, 0xc1, 0x20, 0x83, + 0x2f, 0xcd, 0x61, 0x97, 0x00, 0x1d, 0x8b, 0xf3, + 0x30, 0xd8, 0xac, 0x92, 0x34, 0xa7, 0x9b, 0xa7, + 0x34, 0xa0, 0xaf, 0xd8, 0xa0, 0x08, 0x71, 0xb3, + 0x48, 0x22, 0x8d, 0x9d, 0xef, 0xa1, 0xc9, 0x37, + 0x61, 0x03, 0x35, 0x81, 0x23, 0xbc, 0x70, 0x0c, + 0xb2, 0x1f, 0x20, 0x4a, 0x34, 0x36, 0xe3, 0xb4, + 0xa7, 0x5e, 0x04, 0x7a, 0x12, 0x50, 0xa6, 0x03, + 0x92, 0x2f, 0x20, 0xd2, 0xe4, 0xdf, 0x50, 0x3b, + 0x98, 0x9a, 0xe5, 0x2f, 0x5a, 0x3a, 0x9c, 0xf5, + 0xd3, 0x16, 0x8f, 0xdb, 0x5f, 0x26, 0xac, 0x5b, + 0x44, 0xa7, 0xb7, 0x21, 0x0d, 0xb1, 0x56, 0xab, + 0xb1, 0x10, 0xf9, 0xe3, 0x91, 0xfe, 0xb5, 0xd9, + 0x72, 0x53, 0xc0, 0xd6, 0x19, 0x51, 0x89, 0x40, + 0xae, 0x00, 0x55, 0x39, 0x35, 0xd7, 0x22, 0x71, + 0xab, 0x83, 0xde, 0xc5, 0xe5, 0xcd, 0xa7, 0xae, + 0x51, 0xf5, 0x6b, 0xa4, 0xff, 0xdb, 0xc2, 0xc0, + 0x86, 0xb3, 0xb1, 0xd7, 0xc5, 0x5a, 0x1d, 0xba, + 0x28, 0x08, 0x33, 0xbc, 0x22, 0xf0, 0xf8, 0x4a, + 0x76, 0xbd, 0x64, 0xb1, 0x40, 0x21, 0x2b, 0xaf, + 0x06, 0xf0, 0x42, 0x20, 0xc3, 0xfb, 0x0c, 0x4f, + 0xcc, 0xbc, 0xf5, 0x45, 0xd7, 0x8b, 0xf3, 0x10, + 0xc8, 0xdb, 0xc3, 0xcb, 0x7b, 0xdc, 0x42, 0x0a, + 0x9a, 0xd9, 0xb0, 0x3d, 0xc9, 0x0f, 0x09, 0x1a, + 0xc1, 0x4f, 0x3d, 0xc0, 0x45, 0xdd, 0xd1, 0x70, + 0xa5, 0xc7, 0x19, 0xdd, 0x09, 0xe9, 0x5b, 0x1c, + 0xbc, 0xb9, 0xc3, 0xfb, 0xe8, 0x4c, 0xc3, 0x4b, + 0xc4, 0xfb, 0x20, 0x58, 0x51, 0x21, 0x41, 0x42, + 0xa1, 0x29, 0x59, 0xcf, 0x17, 0xb0, 0xf1, 0x87, + 0xab, 0x8b, 0x0e, 0xdf, 0xf7, 0x6c, 0x12, 0xba, + 0x34, 0x0a, 0xe3, 0xf3, 0x20, 0xcd, 0x90, 0x27, + 0xa4, 0x01, 0x5d, 0x76, 0xf4, 0x8a, 0x87, 0x8d, + 0x46, 0x5b, 0x8a, 0x3e, 0xc0, 0xd7, 0x81, 0xa0, + 0xbf, 0x7b, 0xf9, 0x8f, 0x57, 0xdf, 0xbe, 0x1c, + 0xbf, 0x7e, 0xf5, 0xcf, 0x97, 0x3f, 0x8e, 0x7f, + 0x79, 0xf1, 0xe6, 0xd5, 0xcf, 0xf0, 0xb1, 0x66, + 0xaa, 0xb5, 0x6d, 0x11, 0x79, 0x36, 0x1f, 0x1b, + 0xfb, 0x2d, 0x39, 0xf5, 0x3d, 0xc0, 0x47, 0xfd, + 0x8a, 0x67, 0xa0, 0xdd, 0x19, 0xdb, 0xe1, 0x1a, + 0x25, 0xdb, 0xbb, 0xd7, 0xcf, 0xef, 0x4b, 0xbf, + 0xbe, 0x73, 0x35, 0xf9, 0x3e, 0xf5, 0xdc, 0x4f, + 0xa3, 0x9d, 0x7e, 0x5a, 0x8d, 0xf2, 0x13, 0x29, + 0x81, 0xb6, 0x02, 0xd8, 0xa4, 0xff, 0x5d, 0x47, + 0x91, 0x6b, 0xd4, 0xe3, 0xae, 0xad, 0x8d, 0x35, + 0x28, 0x63, 0xdb, 0x2b, 0x56, 0xcd, 0x7a, 0xd5, + 0x75, 0x55, 0xa3, 0x2d, 0x34, 0xa3, 0x9b, 0x6b, + 0x33, 0x5b, 0x28, 0x33, 0x1f, 0xa5, 0x80, 0x6c, + 0xa5, 0x7f, 0x7c, 0x84, 0xb6, 0x50, 0x14, 0xf2, + 0x89, 0xe6, 0xe0, 0x58, 0xe5, 0xf3, 0x90, 0x61, + 0xaa, 0x83, 0x33, 0x0a, 0xe2, 0x39, 0x21, 0xcd, + 0xbf, 0x28, 0xae, 0xae, 0x58, 0x7e, 0xc3, 0x31, + 0x22, 0xc1, 0x7e, 0xb0, 0xa1, 0xea, 0x3a, 0x20, + 0x3c, 0xc9, 0x6a, 0xdd, 0xa5, 0x77, 0xd1, 0x92, + 0xaa, 0x79, 0xe1, 0x6c, 0xb0, 0x1a, 0x6a, 0x8d, + 0x09, 0x5a, 0x64, 0xcb, 0x24, 0xc9, 0x17, 0x78, + 0x47, 0xdf, 0x1a, 0xe0, 0xbd, 0x74, 0x11, 0x68, + 0xa7, 0x88, 0xbc, 0xa3, 0xaa, 0x30, 0x3c, 0xa9, + 0xde, 0x22, 0x34, 0x7b, 0x6d, 0xfe, 0x06, 0x9a, + 0xc4, 0x60, 0x28, 0xbe, 0xc1, 0x7f, 0xc4, 0xb1, + 0xdd, 0x93, 0x16, 0x15, 0x4a, 0xbd, 0xe9, 0x92, + 0x81, 0xed, 0x77, 0x54, 0x42, 0x41, 0xee, 0xa3, + 0xda, 0x33, 0x54, 0xf9, 0x20, 0x55, 0x99, 0xf3, + 0xcd, 0xe8, 0xf7, 0xcc, 0x85, 0x01, 0xfc, 0xae, + 0x35, 0x4b, 0x87, 0x80, 0xf7, 0x44, 0x51, 0xf1, + 0x34, 0xca, 0xfc, 0x2d, 0x5c, 0x23, 0xdc, 0xf7, + 0x9d, 0xf6, 0x95, 0x77, 0xd4, 0x16, 0x96, 0xf5, + 0xd2, 0xc4, 0x26, 0x80, 0xed, 0x9e, 0x57, 0x5b, + 0x05, 0xb9, 0xac, 0xc6, 0x32, 0x3b, 0xd2, 0x15, + 0x8a, 0x36, 0x59, 0x6e, 0xae, 0xca, 0xaa, 0x0e, + 0x3c, 0xc5, 0xfb, 0x4d, 0x9d, 0xfb, 0xb8, 0x30, + 0xb8, 0xa6, 0xc8, 0x72, 0xc5, 0xb5, 0x90, 0x6a, + 0x57, 0x73, 0xb3, 0x53, 0x92, 0x22, 0x8a, 0x05, + 0x24, 0xbd, 0x66, 0x7c, 0x87, 0xb5, 0xdd, 0x1d, + 0xb8, 0xec, 0xe9, 0x84, 0x9c, 0xb3, 0x5e, 0x2a, + 0xa5, 0x56, 0xfc, 0x75, 0xf0, 0x57, 0x34, 0x10, + 0xa0, 0x6c, 0xfb, 0x3e, 0x00, 0xed, 0x28, 0x12, + 0x53, 0x06, 0xac, 0x6e, 0xdc, 0x50, 0x2e, 0xf6, + 0xa6, 0xff, 0x5e, 0x67, 0xb9, 0x5d, 0x89, 0x44, + 0xe9, 0x3c, 0x39, 0x79, 0x44, 0x82, 0x38, 0xc8, + 0xdc, 0xc1, 0x72, 0x15, 0xa6, 0x21, 0x8c, 0x02, + 0x44, 0xe2, 0xc9, 0x22, 0xc9, 0x82, 0x58, 0xb9, + 0x5a, 0x2a, 0xf7, 0x4b, 0x74, 0xf6, 0xca, 0xc3, + 0x19, 0xe8, 0xc4, 0xe4, 0x09, 0x96, 0x80, 0x00, + 0x1d, 0x79, 0xab, 0x15, 0xa2, 0xc8, 0x40, 0x33, + 0x04, 0x86, 0x3a, 0x72, 0x7e, 0xb9, 0x42, 0x48, + 0x62, 0x11, 0x78, 0x39, 0xaa, 0xe0, 0x13, 0x60, + 0x0b, 0x99, 0x68, 0x91, 0x5b, 0x2e, 0x56, 0x9f, + 0x44, 0x80, 0x4d, 0x90, 0x82, 0x16, 0x9c, 0x25, + 0xeb, 0x14, 0x54, 0xc1, 0x47, 0xec, 0x9f, 0x63, + 0x93, 0xc7, 0xff, 0xbc, 0xfc, 0xe5, 0x67, 0x2d, + 0x75, 0x93, 0x3b, 0x22, 0xfa, 0x8c, 0x3e, 0xed, + 0x0d, 0x78, 0x02, 0x7e, 0xf0, 0xd6, 0x59, 0x16, + 0x7a, 0xb1, 0x1a, 0xcf, 0x24, 0x01, 0xdd, 0x39, + 0x9c, 0x84, 0xa0, 0x12, 0x1c, 0x8b, 0x21, 0x54, + 0xcd, 0x7e, 0x4f, 0xf3, 0xd6, 0x08, 0xb6, 0xcf, + 0xeb, 0x57, 0xc6, 0x1d, 0xe5, 0x87, 0x17, 0xbf, + 0x9e, 0x9d, 0x8d, 0xbf, 0xfd, 0xf9, 0xe5, 0xf7, + 0xc0, 0x96, 0xf6, 0x9f, 0x1f, 0x3d, 0x3f, 0x18, + 0x8d, 0x8e, 0x06, 0x07, 0x83, 0xe1, 0xc1, 0xfe, + 0xe8, 0xd9, 0x35, 0x4d, 0xcc, 0x72, 0xeb, 0x60, + 0x0d, 0xfe, 0xb5, 0xd2, 0xd8, 0xc5, 0x45, 0x1d, + 0x6b, 0x3b, 0x55, 0xd8, 0x0e, 0xed, 0x2d, 0x43, + 0x7b, 0xbf, 0xb8, 0x33, 0xb6, 0xb3, 0x34, 0xd7, + 0x49, 0x28, 0x77, 0x66, 0x77, 0xbe, 0x03, 0x23, + 0xdb, 0x3a, 0xa6, 0x9d, 0x34, 0x1d, 0xdf, 0xc8, + 0xda, 0x46, 0x0a, 0xea, 0x63, 0xd9, 0xf4, 0x31, + 0x10, 0xc5, 0x12, 0xad, 0x3d, 0x31, 0x8c, 0x21, + 0x9e, 0x93, 0xf6, 0x99, 0x26, 0x4b, 0xf1, 0xb6, + 0x3b, 0xec, 0x88, 0x2e, 0x39, 0x8a, 0x26, 0xe2, + 0x2d, 0xfc, 0x3e, 0x7c, 0xd7, 0x13, 0xe2, 0xb7, + 0xe0, 0x71, 0x14, 0x89, 0xb5, 0x9c, 0x02, 0xb4, + 0xba, 0xe5, 0x58, 0xbe, 0x4a, 0x93, 0xe9, 0x7a, + 0xc2, 0x23, 0x03, 0x82, 0xcf, 0xc3, 0x09, 0xfb, + 0xc2, 0x79, 0x40, 0x60, 0x6b, 0x54, 0x24, 0xa1, + 0x87, 0x05, 0xc0, 0xf5, 0x96, 0xca, 0x06, 0x45, + 0xd6, 0x1a, 0x31, 0x03, 0xd2, 0x87, 0xcd, 0xa7, + 0x80, 0x6d, 0x82, 0xc7, 0xe8, 0xa9, 0x38, 0x9d, + 0x52, 0xad, 0xa4, 0x61, 0xbb, 0x6a, 0x54, 0xbc, + 0x28, 0x4b, 0xc8, 0x3f, 0x10, 0x31, 0xf1, 0xb4, + 0x96, 0xeb, 0x09, 0xc9, 0x17, 0xe0, 0x78, 0x4b, + 0x78, 0x6e, 0x11, 0x18, 0x60, 0x30, 0x5f, 0xa2, + 0x3e, 0x9c, 0x2d, 0x3c, 0xb4, 0x21, 0x4e, 0x60, + 0x6b, 0x4c, 0x03, 0xd8, 0x64, 0x4b, 0xa4, 0x7b, + 0xac, 0xa1, 0xb5, 0xf4, 0x64, 0xa6, 0x60, 0x05, + 0xde, 0x64, 0x61, 0x5a, 0xd2, 0xe4, 0x94, 0x46, + 0xd0, 0x53, 0x95, 0xff, 0x2b, 0x98, 0xa1, 0x57, + 0x23, 0x2c, 0xe4, 0x34, 0x81, 0xae, 0xc9, 0xe4, + 0x45, 0xce, 0x8e, 0x68, 0xae, 0x24, 0x3b, 0x02, + 0x7a, 0xd9, 0xaf, 0x44, 0xb6, 0x56, 0x1b, 0x11, + 0x0d, 0x6e, 0x06, 0x45, 0x05, 0x47, 0x0e, 0x7b, + 0x06, 0x9c, 0x26, 0x73, 0x8c, 0x73, 0x00, 0xe7, + 0x43, 0x90, 0x26, 0x42, 0x8e, 0xc8, 0xf6, 0xd2, + 0xc4, 0x49, 0xee, 0x99, 0x45, 0x46, 0xfb, 0x58, + 0x46, 0x08, 0x6c, 0x40, 0xee, 0x20, 0xc5, 0x3f, + 0x4e, 0x36, 0xe2, 0x0c, 0xfa, 0x9e, 0x2c, 0xa8, + 0x43, 0x33, 0xef, 0xb4, 0xa7, 0xf6, 0x6c, 0x8e, + 0x0b, 0x7f, 0x59, 0x7c, 0x60, 0x0f, 0x08, 0x76, + 0xd5, 0xea, 0x0e, 0x7a, 0x87, 0xf0, 0xeb, 0x7e, + 0x6f, 0xf0, 0x2f, 0xe4, 0x19, 0x67, 0xff, 0x1a, + 0xb5, 0xc5, 0xe9, 0x29, 0x31, 0x21, 0x05, 0xea, + 0xb7, 0x45, 0x88, 0x96, 0xba, 0x24, 0x42, 0xeb, + 0x46, 0x9e, 0x1c, 0xab, 0xef, 0x67, 0x28, 0x2d, + 0x21, 0xb3, 0xe9, 0x22, 0x45, 0xee, 0xc1, 0xf9, + 0x34, 0x6f, 0x11, 0xf3, 0x02, 0x99, 0xe6, 0xca, + 0xee, 0xdb, 0x6d, 0xf4, 0xea, 0xdb, 0x97, 0xbe, + 0xd6, 0xbc, 0xe1, 0x1a, 0x00, 0x4a, 0x78, 0x7d, + 0x07, 0x5e, 0xdf, 0x81, 0xc7, 0xe0, 0xcc, 0x96, + 0x78, 0x8d, 0x14, 0x44, 0xd4, 0x2b, 0x8f, 0x13, + 0xd8, 0x0e, 0xe4, 0xfe, 0x83, 0x73, 0x6b, 0x31, + 0x8f, 0x73, 0x6b, 0xc7, 0x9d, 0x21, 0xc6, 0x85, + 0x8d, 0x68, 0x20, 0x9e, 0xd1, 0x62, 0xfb, 0x97, + 0x8a, 0x33, 0x28, 0x83, 0x0c, 0x7a, 0xe7, 0x76, + 0xd9, 0xb8, 0xc9, 0xf4, 0x80, 0x47, 0x45, 0x92, + 0xda, 0xbb, 0x08, 0x3e, 0xac, 0xbd, 0x48, 0xdb, + 0xc6, 0x71, 0xeb, 0x28, 0x5b, 0x5e, 0xb5, 0x08, + 0x6e, 0xcc, 0x59, 0xb2, 0xb3, 0x0a, 0x0b, 0xf1, + 0xbd, 0x98, 0xda, 0x0f, 0xa4, 0x4f, 0x0f, 0x49, + 0x55, 0x65, 0x2b, 0x3b, 0x88, 0xad, 0x12, 0x2b, + 0xd7, 0x94, 0x58, 0x2b, 0xd4, 0xd1, 0x11, 0x7f, + 0xa5, 0x5c, 0x76, 0x6b, 0x92, 0x55, 0x75, 0x35, + 0x4b, 0x08, 0x69, 0x12, 0x36, 0xee, 0xf8, 0xac, + 0x6d, 0xd6, 0xe4, 0xad, 0x63, 0x76, 0xcb, 0xc3, + 0x52, 0xad, 0xe5, 0xff, 0x75, 0xf9, 0x6b, 0x90, + 0xe5, 0xe1, 0xd2, 0xa3, 0x95, 0x20, 0xe3, 0xbf, + 0x57, 0x1a, 0x17, 0xba, 0x38, 0xa3, 0x58, 0x74, + 0x78, 0x71, 0x68, 0x6d, 0x47, 0xf4, 0xf5, 0x32, + 0xec, 0x41, 0xff, 0x77, 0x9a, 0xe4, 0x2d, 0x3d, + 0x4f, 0x1d, 0x33, 0x65, 0x6d, 0x5b, 0xb1, 0x3b, + 0x07, 0x21, 0xe8, 0x74, 0x6b, 0x26, 0x34, 0xad, + 0xd1, 0x73, 0x88, 0xe6, 0x00, 0x14, 0xf9, 0x6d, + 0x99, 0xff, 0xb4, 0xef, 0xd1, 0xe5, 0x94, 0xfc, + 0xe8, 0x4f, 0x6a, 0x24, 0xd5, 0xb2, 0x13, 0xdd, + 0x4d, 0x15, 0x1c, 0x9a, 0x23, 0xea, 0xab, 0xc2, + 0x3d, 0xb3, 0x77, 0x01, 0xcd, 0x3c, 0xfe, 0xcd, + 0xf2, 0x97, 0xec, 0x5d, 0x4a, 0x31, 0xb1, 0x2b, + 0x0b, 0x2f, 0x1d, 0x37, 0xc6, 0x0a, 0x5f, 0xc0, + 0xaa, 0x22, 0xd6, 0x05, 0xe1, 0x18, 0x5f, 0x35, + 0x08, 0xf1, 0x5b, 0x0e, 0x54, 0x3a, 0xa2, 0x57, + 0x3b, 0xbd, 0x51, 0xb3, 0x76, 0x2f, 0x2d, 0xfa, + 0xc8, 0x15, 0x6a, 0x1b, 0x7c, 0x3a, 0x2c, 0x00, + 0x81, 0x0c, 0x89, 0x8c, 0x46, 0x92, 0x57, 0x61, + 0x65, 0x6f, 0xc7, 0x1b, 0x79, 0xb0, 0x95, 0x4a, + 0x5b, 0xfa, 0x0a, 0x42, 0xc5, 0x22, 0x49, 0x6b, + 0x0a, 0x35, 0x23, 0x29, 0x03, 0x8b, 0xbc, 0x49, + 0x30, 0x3d, 0xb9, 0x52, 0xd3, 0x6a, 0x76, 0xa1, + 0xdb, 0xc6, 0x79, 0x4e, 0x2d, 0x9b, 0xdc, 0x93, + 0xba, 0xe7, 0xe2, 0xf7, 0x38, 0xc9, 0x7f, 0xcd, + 0x08, 0xa5, 0x4a, 0xff, 0x4f, 0xeb, 0xc6, 0xed, + 0x35, 0x49, 0x48, 0x55, 0x44, 0x6c, 0x26, 0xc3, + 0xb9, 0x9c, 0xb2, 0x59, 0x97, 0x41, 0x55, 0x56, + 0xd6, 0x92, 0xd9, 0x69, 0xa1, 0x07, 0x75, 0x17, + 0xe3, 0xb4, 0x4e, 0xa2, 0x88, 0x7c, 0xfc, 0xc7, + 0xab, 0x20, 0xc5, 0xb7, 0x2a, 0x28, 0x3d, 0x8d, + 0xf9, 0xbe, 0x04, 0x08, 0x21, 0x02, 0x8a, 0x69, + 0x59, 0xb6, 0x97, 0x43, 0x38, 0x99, 0x98, 0x79, + 0xb5, 0x1a, 0x26, 0x09, 0x78, 0x78, 0x2d, 0x56, + 0x6d, 0xd7, 0x94, 0x43, 0x32, 0x45, 0x1a, 0x9c, + 0x03, 0x80, 0x8c, 0x74, 0x40, 0x64, 0x99, 0x53, + 0x90, 0x04, 0xbd, 0xb4, 0x3b, 0x0b, 0x83, 0x68, + 0x2a, 0xfc, 0xe4, 0x82, 0xa5, 0x6e, 0xba, 0xdb, + 0x0c, 0xa6, 0x7d, 0xac, 0x85, 0xc2, 0x01, 0xca, + 0x8a, 0x61, 0x14, 0x64, 0x1a, 0xde, 0x81, 0x11, + 0xde, 0xb7, 0xb3, 0x7e, 0x18, 0xce, 0x57, 0x7d, + 0xfb, 0xe5, 0x59, 0x02, 0xc3, 0x15, 0xb7, 0x5c, + 0xf0, 0x77, 0xc3, 0x54, 0x1a, 0xbe, 0x43, 0xb4, + 0xc2, 0x8c, 0x87, 0x7e, 0x35, 0xbc, 0x47, 0x92, + 0x8b, 0x5d, 0xc6, 0xac, 0xe7, 0xa3, 0x09, 0xce, + 0x36, 0x0d, 0x46, 0xab, 0x05, 0xde, 0x1d, 0xc1, + 0x1a, 0x1a, 0x49, 0xe7, 0x17, 0xea, 0x55, 0xa3, + 0xdf, 0x01, 0x02, 0x81, 0x21, 0x47, 0x9e, 0x1f, + 0x44, 0x4d, 0x7c, 0x5f, 0x4e, 0xa0, 0x9e, 0x45, + 0x98, 0x02, 0x02, 0x6f, 0x00, 0xff, 0x17, 0x3f, + 0x42, 0x8d, 0x13, 0x1b, 0x38, 0xc1, 0xc5, 0x6b, + 0xb9, 0x6c, 0x91, 0x6c, 0x00, 0x7d, 0xed, 0x50, + 0xa0, 0x67, 0xe7, 0x3f, 0x59, 0x06, 0x72, 0xae, + 0x5e, 0xab, 0xb8, 0x8b, 0xe9, 0x9b, 0x99, 0x99, + 0x41, 0xc0, 0xba, 0x67, 0x64, 0xc8, 0x6a, 0x72, + 0x4b, 0xa0, 0x95, 0x96, 0x07, 0x54, 0x06, 0x78, + 0xe6, 0xa8, 0xb1, 0xc1, 0x61, 0x31, 0x03, 0xa5, + 0x07, 0x85, 0xbb, 0x64, 0x9d, 0x57, 0x23, 0xb1, + 0x77, 0x2a, 0x7a, 0x43, 0xd5, 0xcf, 0x1f, 0x7f, + 0x5e, 0xd6, 0x56, 0x2c, 0x50, 0x2a, 0x7d, 0xad, + 0x00, 0x58, 0xfd, 0x5d, 0xcb, 0xde, 0x3b, 0x4e, + 0xf9, 0x11, 0x9c, 0x92, 0x2f, 0xb6, 0xef, 0x9c, + 0x57, 0x96, 0x66, 0x66, 0xc5, 0x86, 0x88, 0xb1, + 0x54, 0xd0, 0x50, 0x7c, 0x1a, 0x9d, 0xb0, 0xb2, + 0x38, 0x75, 0x2d, 0x1d, 0x59, 0x84, 0xa2, 0x2b, + 0x2b, 0xe7, 0x4b, 0xef, 0x7d, 0x20, 0x52, 0x7c, + 0x82, 0x89, 0x36, 0x3e, 0x34, 0xf8, 0x77, 0xc9, + 0xe2, 0x2f, 0xf4, 0xb5, 0xd6, 0x75, 0x19, 0x72, + 0x01, 0x8f, 0x7b, 0xe2, 0xd0, 0x5c, 0xa6, 0xcd, + 0x5a, 0x9e, 0x9f, 0xb5, 0x34, 0x9a, 0xbd, 0xcb, + 0x36, 0x4d, 0xc4, 0x6f, 0x68, 0xe5, 0x88, 0x1f, + 0xe7, 0xd2, 0x3f, 0xc7, 0x78, 0x21, 0x64, 0x64, + 0x76, 0xf1, 0x13, 0x50, 0x20, 0xb4, 0x16, 0x5d, + 0x69, 0xf5, 0x42, 0xdb, 0x50, 0xf0, 0x3b, 0x68, + 0xbb, 0xb8, 0xba, 0x20, 0xfa, 0x41, 0x65, 0x9c, + 0x06, 0x69, 0xfb, 0x91, 0x8a, 0x77, 0x49, 0xf3, + 0xb6, 0xe7, 0xcb, 0x9d, 0x9d, 0x13, 0xb7, 0xae, + 0x9c, 0xc3, 0xd3, 0xeb, 0xb9, 0x93, 0x5c, 0x35, + 0xa5, 0x96, 0xdc, 0xac, 0x85, 0x5f, 0x24, 0x5c, + 0x72, 0x83, 0x51, 0x78, 0xdc, 0x1e, 0xd3, 0xb9, + 0x35, 0x9e, 0xf3, 0x11, 0x67, 0xa5, 0x23, 0x81, + 0xdf, 0xff, 0x49, 0x39, 0xf9, 0xa4, 0x47, 0xe4, + 0x44, 0x9f, 0x8d, 0x23, 0xa7, 0x03, 0xf7, 0xb2, + 0x93, 0x97, 0xbf, 0x78, 0xe5, 0x59, 0x58, 0x97, + 0xf6, 0x36, 0xd7, 0xa4, 0x46, 0x4b, 0x26, 0x95, + 0xb7, 0x0c, 0xde, 0x06, 0x52, 0xb8, 0x1e, 0x1e, + 0x1e, 0x92, 0xde, 0x5d, 0x89, 0x54, 0xbf, 0x92, + 0x50, 0x0d, 0x28, 0xbd, 0xd9, 0xf5, 0xbe, 0xaf, + 0xeb, 0xde, 0x56, 0xfc, 0xe5, 0xa6, 0xc1, 0x7d, + 0x44, 0xc6, 0x48, 0xe6, 0x15, 0x35, 0x57, 0x98, + 0xce, 0xf8, 0x6b, 0xee, 0x65, 0xbb, 0xae, 0xaf, + 0x2e, 0xad, 0x74, 0xb7, 0xd8, 0xcd, 0x16, 0x97, + 0x9d, 0xf2, 0x02, 0xfe, 0x8f, 0x4f, 0xf7, 0x92, + 0xb6, 0xca, 0xaf, 0x68, 0xeb, 0x67, 0xb3, 0x37, + 0xc1, 0xfc, 0x73, 0x7c, 0xe9, 0xf4, 0xd0, 0x1e, + 0xea, 0x54, 0x9b, 0xdc, 0x1e, 0xe0, 0xeb, 0x89, + 0x7b, 0x7f, 0x3a, 0x70, 0x93, 0xad, 0xf0, 0xa9, + 0xfc, 0xf3, 0x6e, 0xdd, 0xaf, 0xed, 0xbe, 0x7d, + 0xaa, 0x6e, 0xe2, 0xc0, 0xd4, 0x64, 0xf4, 0xba, + 0xcd, 0xc7, 0xa0, 0xd7, 0xe3, 0x4a, 0xd5, 0x46, + 0xd2, 0x6a, 0x33, 0x61, 0xdd, 0x6a, 0xae, 0xf3, + 0x28, 0x8c, 0x1b, 0xdf, 0xc9, 0x39, 0x55, 0x1a, + 0x18, 0x9a, 0x53, 0xaf, 0x92, 0xb1, 0x15, 0x6a, + 0x34, 0x90, 0x62, 0xa9, 0xe6, 0x97, 0xc9, 0xe8, + 0xdc, 0xd9, 0x27, 0x76, 0x63, 0x7f, 0xa9, 0x64, + 0x7c, 0x4e, 0x8d, 0x4e, 0x79, 0x7d, 0xea, 0x18, + 0x61, 0x09, 0x72, 0xdd, 0x24, 0x7f, 0xd6, 0x8c, + 0x51, 0x9b, 0xe5, 0xa1, 0x66, 0xab, 0xa0, 0x0f, + 0xf6, 0x0b, 0xfa, 0xdd, 0x13, 0x96, 0xad, 0xfb, + 0x82, 0xef, 0x39, 0xf5, 0x06, 0xaa, 0x67, 0xae, + 0xee, 0x7a, 0x7d, 0x02, 0x0a, 0xbf, 0x3d, 0x12, + 0xdd, 0xee, 0x2a, 0xa1, 0x86, 0x83, 0x96, 0xc8, + 0xf6, 0x63, 0xe8, 0xec, 0x16, 0x39, 0xb4, 0x11, + 0x9c, 0x6d, 0x99, 0x1f, 0xa9, 0xa1, 0x6b, 0xd8, + 0x6f, 0x92, 0x82, 0x8a, 0x7e, 0xe9, 0xc8, 0xcb, + 0x4a, 0x73, 0xe3, 0x6b, 0x9c, 0xa2, 0x27, 0x23, + 0x29, 0x43, 0x08, 0xb4, 0xfa, 0xf2, 0xc3, 0x1d, + 0xf0, 0x9e, 0x68, 0x31, 0x34, 0x7d, 0x30, 0x7c, + 0x82, 0x7b, 0xb2, 0x5d, 0xc0, 0x96, 0xa6, 0xf0, + 0x1a, 0xd7, 0x3a, 0x1f, 0x3f, 0xdb, 0xa3, 0xe5, + 0xc1, 0xb3, 0xea, 0x5d, 0xe0, 0x1b, 0x0b, 0x8b, + 0xdb, 0x3a, 0xb8, 0x1e, 0x7c, 0xf4, 0x9c, 0x5b, + 0x0b, 0x92, 0x73, 0x93, 0x5d, 0x7c, 0xef, 0x3a, + 0xcb, 0x8d, 0x4f, 0xb2, 0x5d, 0xbc, 0x9f, 0xbb, + 0x8d, 0xf7, 0x83, 0x9e, 0xc2, 0x61, 0x3c, 0xb5, + 0xde, 0x0e, 0x26, 0xea, 0x20, 0xe7, 0xeb, 0x05, + 0x3a, 0xc3, 0x4d, 0x74, 0x4e, 0xf4, 0x10, 0xbb, + 0x27, 0x11, 0xe3, 0xfa, 0x01, 0x89, 0x0a, 0x02, + 0xc7, 0x2e, 0x14, 0xdc, 0x27, 0x0b, 0x05, 0xb7, + 0x93, 0x22, 0x76, 0x52, 0xc4, 0x2e, 0x7c, 0xde, + 0xfd, 0x08, 0x00, 0xbb, 0xc3, 0x7e, 0x77, 0xd8, + 0xdf, 0x7e, 0x70, 0xbf, 0xfb, 0x3d, 0x43, 0xf7, + 0xe1, 0x33, 0xb9, 0x38, 0x14, 0x62, 0xc2, 0x2a, + 0xf6, 0xaf, 0xcb, 0xe9, 0x2c, 0xaa, 0xa4, 0x57, + 0x2a, 0xbe, 0xfa, 0x39, 0x97, 0xf3, 0x15, 0xcd, + 0xb5, 0x31, 0x40, 0xf2, 0xa2, 0x71, 0x50, 0xb0, + 0x18, 0x1f, 0xc0, 0x06, 0x53, 0x17, 0x6a, 0x75, + 0xef, 0xe6, 0xbd, 0xea, 0xbd, 0xe3, 0x51, 0x49, + 0x43, 0x5c, 0x3a, 0x28, 0xad, 0x8e, 0x4b, 0x47, + 0x05, 0x4d, 0x0f, 0xee, 0x65, 0x85, 0x46, 0x1b, + 0xd9, 0xa2, 0xe1, 0x2d, 0xe1, 0xa2, 0xe2, 0x2d, + 0xa1, 0x8d, 0xda, 0xa2, 0xf0, 0x94, 0xd0, 0x6a, + 0xbc, 0xa8, 0xf4, 0x77, 0x77, 0xd0, 0x5b, 0x14, + 0x3d, 0xc0, 0x1f, 0xf6, 0x6d, 0xe1, 0xd6, 0xa7, + 0x3f, 0x2d, 0x34, 0x05, 0xef, 0x82, 0x5f, 0xaa, + 0x83, 0x77, 0x41, 0x41, 0x47, 0x2f, 0x7c, 0x6d, + 0xf0, 0x2e, 0xd9, 0xbc, 0xb0, 0x8e, 0x0d, 0x3d, + 0x2f, 0x2c, 0xaf, 0xfb, 0xfa, 0xc7, 0x6d, 0x0b, + 0xfd, 0xb8, 0x6d, 0x51, 0xf5, 0xb8, 0xad, 0xb4, + 0x88, 0x84, 0xc3, 0x62, 0xfb, 0xb7, 0x6d, 0xf7, + 0x72, 0x0f, 0xa9, 0xd8, 0xd9, 0xbe, 0xe0, 0x1d, + 0x49, 0x5e, 0x38, 0x7a, 0x73, 0x82, 0x1a, 0xf1, + 0x41, 0x72, 0x31, 0x39, 0x8b, 0xf8, 0x30, 0x9b, + 0x74, 0x06, 0xfc, 0x5b, 0x39, 0xad, 0xa9, 0xe1, + 0xe9, 0x42, 0xfe, 0xe2, 0xbe, 0xae, 0x56, 0x31, + 0xc6, 0x19, 0x38, 0x46, 0x00, 0x19, 0x5d, 0xd3, + 0xa9, 0x2b, 0x27, 0x67, 0x8f, 0x81, 0xf8, 0x46, + 0xf5, 0x78, 0x2c, 0x98, 0x02, 0x86, 0x6d, 0xdb, + 0xe3, 0x05, 0xf5, 0xa5, 0x73, 0xd8, 0x60, 0xf8, + 0xda, 0x92, 0x94, 0xab, 0x16, 0x86, 0xed, 0x9f, + 0x7a, 0xe9, 0xfb, 0xbe, 0x9f, 0x52, 0xbb, 0x90, + 0xdf, 0x04, 0x65, 0xeb, 0x74, 0xe6, 0x41, 0x39, + 0x4d, 0xc9, 0x37, 0xed, 0xe2, 0x4b, 0xf0, 0x73, + 0x99, 0x94, 0xc4, 0xa4, 0xbe, 0x18, 0xf4, 0x46, + 0xc3, 0x91, 0x9b, 0xc5, 0x62, 0xd0, 0x7b, 0x36, + 0x3c, 0x1c, 0xe9, 0x4f, 0x3e, 0x7d, 0x1a, 0x3c, + 0x1b, 0x8d, 0xb4, 0x6c, 0x58, 0xe3, 0xe3, 0x52, + 0xf4, 0x50, 0xc3, 0x40, 0xff, 0xd3, 0xa9, 0x74, + 0x39, 0x13, 0xde, 0xd2, 0xc7, 0x07, 0x26, 0x42, + 0xb2, 0xd7, 0x39, 0xba, 0x5d, 0xc5, 0x89, 0xf1, + 0xb3, 0xe2, 0xd4, 0x03, 0x79, 0x92, 0xd3, 0x8b, + 0x55, 0x3f, 0x02, 0xb2, 0x30, 0x07, 0x93, 0x6c, + 0x1c, 0xc9, 0x55, 0x51, 0x1d, 0xef, 0x53, 0xa7, + 0xfa, 0xbf, 0xe6, 0xa0, 0x64, 0x0c, 0xd1, 0x5f, + 0xcd, 0x6a, 0x68, 0xd0, 0xfa, 0x56, 0x85, 0xc4, + 0x87, 0x8a, 0x59, 0x0b, 0x26, 0x2e, 0xf7, 0xda, + 0x1d, 0xb1, 0xa1, 0x0c, 0x04, 0xf4, 0x97, 0x9a, + 0x4f, 0x8f, 0xd2, 0xd3, 0xa8, 0x04, 0x04, 0x6a, + 0x76, 0x25, 0x5d, 0x79, 0xa4, 0xee, 0xce, 0x66, + 0x6b, 0x20, 0x23, 0xc6, 0x2c, 0xf5, 0x2e, 0x1d, + 0x9d, 0x36, 0x45, 0x6f, 0xac, 0x24, 0x26, 0x1a, + 0x64, 0xff, 0x44, 0x7c, 0x65, 0x22, 0x9b, 0xe3, + 0xeb, 0xd7, 0xfd, 0xa3, 0x03, 0x9c, 0x34, 0x73, + 0x26, 0xb5, 0x6b, 0xa6, 0x91, 0x9e, 0xfb, 0xda, + 0x00, 0xe5, 0x43, 0x3c, 0x3b, 0xf6, 0x0e, 0x3e, + 0x8a, 0x0c, 0xac, 0xcc, 0x3b, 0x2a, 0x9d, 0x01, + 0xc1, 0xee, 0xe3, 0x3b, 0x42, 0x7a, 0x2e, 0x96, + 0x89, 0xd8, 0x4b, 0x53, 0x94, 0x8e, 0xf5, 0xa3, + 0x3a, 0x7c, 0x3e, 0xc3, 0x99, 0x05, 0x78, 0x1c, + 0xfa, 0xf4, 0xd3, 0x8f, 0x14, 0x61, 0xa8, 0x5c, + 0x0b, 0xcb, 0x83, 0x54, 0x92, 0x1d, 0x34, 0x70, + 0x28, 0x8e, 0xbd, 0x1b, 0xdd, 0x71, 0xa3, 0x70, + 0xd0, 0x62, 0x25, 0xbd, 0x78, 0xb6, 0xb6, 0x29, + 0x51, 0x85, 0x2a, 0xb5, 0x28, 0xf4, 0x49, 0x55, + 0x55, 0x9c, 0x92, 0x8e, 0x0d, 0xbc, 0x40, 0x67, + 0x73, 0xf4, 0xdb, 0x41, 0x0a, 0xf3, 0xa2, 0x04, + 0xc6, 0xf9, 0x41, 0x78, 0x17, 0x21, 0xa7, 0x39, + 0x40, 0x07, 0x31, 0x89, 0x67, 0xa6, 0xfd, 0xad, + 0xe4, 0xa6, 0xbd, 0x14, 0x5f, 0xa1, 0x83, 0xd9, + 0xc0, 0xf6, 0xb7, 0xb2, 0x07, 0xb0, 0xa7, 0x56, + 0xae, 0x95, 0x03, 0x5a, 0xc4, 0x22, 0xe8, 0xb5, + 0xd7, 0xa6, 0xb5, 0x50, 0x6f, 0xf7, 0x86, 0x87, + 0x03, 0xe5, 0xdd, 0xd5, 0xa1, 0xe1, 0xc2, 0x0e, + 0xc2, 0x3f, 0x9f, 0x1f, 0x75, 0x44, 0xed, 0xc0, + 0x0d, 0xad, 0x9a, 0x70, 0x4c, 0x2f, 0x32, 0x4c, + 0x69, 0x84, 0x76, 0x14, 0x2f, 0x92, 0x24, 0xac, + 0x63, 0x8b, 0xa9, 0x79, 0x7e, 0xe2, 0x6e, 0x24, + 0x21, 0xd9, 0xa5, 0x4b, 0x87, 0xd6, 0x00, 0x38, + 0x2b, 0x92, 0x55, 0xb7, 0x62, 0xd1, 0xfd, 0x64, + 0x8d, 0xd9, 0x40, 0xf8, 0x51, 0x39, 0x3f, 0x00, + 0x5d, 0xac, 0x89, 0x92, 0x22, 0x7d, 0x6a, 0x40, + 0x0b, 0xf5, 0xf6, 0xd3, 0xa2, 0x24, 0x1a, 0xd2, + 0xd4, 0x04, 0x5f, 0xc3, 0x0c, 0x3d, 0x51, 0x80, + 0xaf, 0x4f, 0xe1, 0x5c, 0x15, 0xad, 0x64, 0x45, + 0xaf, 0x01, 0x61, 0xca, 0x78, 0x34, 0xd2, 0x59, + 0xb2, 0x88, 0x8d, 0xe4, 0x28, 0x3d, 0xda, 0xb1, + 0x3c, 0xdb, 0x86, 0x43, 0x39, 0x8b, 0xe1, 0x48, + 0x77, 0xbd, 0x54, 0x4d, 0x37, 0xcd, 0xfe, 0x7e, + 0x61, 0xb6, 0x65, 0x1d, 0x67, 0xae, 0x55, 0x4f, + 0xf3, 0x62, 0x4f, 0xf3, 0xe6, 0x9e, 0xe6, 0x5b, + 0xf4, 0x34, 0xaf, 0xec, 0xc9, 0x2f, 0xf6, 0xe4, + 0x37, 0xf7, 0xe4, 0x6f, 0xd1, 0x93, 0xaf, 0x7b, + 0xc2, 0xb8, 0x11, 0xd5, 0xa2, 0x66, 0x83, 0x00, + 0x72, 0xd7, 0x02, 0xe3, 0x2d, 0xc9, 0x7c, 0x77, + 0xee, 0x8e, 0xb3, 0xad, 0x1a, 0xaa, 0xa5, 0xb6, + 0xed, 0x25, 0xb0, 0x46, 0x01, 0xec, 0x7a, 0x62, + 0xd4, 0xc7, 0xfa, 0xed, 0x54, 0x2a, 0x57, 0x36, + 0x99, 0xec, 0xec, 0x9a, 0xd7, 0xb3, 0x6b, 0x16, + 0x6b, 0x49, 0x51, 0x59, 0x7b, 0x53, 0x3f, 0x68, + 0x6d, 0xf4, 0x3a, 0xb7, 0x40, 0xc8, 0x4e, 0x94, + 0xb4, 0x56, 0xf6, 0xf9, 0xb6, 0x78, 0xd8, 0x4e, + 0xb3, 0xbd, 0x39, 0x97, 0xdb, 0xe9, 0x8e, 0xa5, + 0xa7, 0xde, 0x57, 0xe8, 0x6e, 0x96, 0x57, 0xfa, + 0x74, 0x1e, 0x58, 0x2f, 0x88, 0xec, 0x9a, 0x9b, + 0xbb, 0xd6, 0xf1, 0x4c, 0x8d, 0x0f, 0x68, 0x2f, + 0xab, 0xd6, 0xe3, 0xae, 0xa3, 0x0a, 0x7e, 0xb0, + 0xcd, 0xef, 0xc6, 0x2c, 0xa9, 0xfa, 0xc5, 0xe8, + 0x15, 0x28, 0x0a, 0xfc, 0xc7, 0x7f, 0x08, 0x2d, + 0xb9, 0x9e, 0x92, 0xe4, 0x6a, 0x7d, 0xfa, 0x40, + 0xb5, 0x58, 0xab, 0xd0, 0xd2, 0xec, 0x37, 0x32, + 0x7e, 0x02, 0xc6, 0x07, 0xd1, 0x8f, 0x5a, 0xf2, + 0xc4, 0x44, 0xc9, 0x3d, 0xe6, 0x07, 0xc9, 0xf6, + 0x6c, 0x02, 0x3a, 0x24, 0x98, 0x38, 0xbc, 0x8d, + 0x5f, 0xd2, 0x18, 0x18, 0x28, 0x57, 0x7f, 0xea, + 0xeb, 0x82, 0x87, 0x70, 0x59, 0xe0, 0x38, 0x1c, + 0x68, 0xf5, 0xb6, 0x49, 0x3d, 0xbe, 0xa6, 0x8e, + 0xb8, 0xdf, 0xa4, 0x23, 0xde, 0x48, 0xe3, 0xe2, + 0xd7, 0x71, 0xd7, 0x51, 0xb2, 0x1e, 0xa2, 0xca, + 0x64, 0x66, 0xbb, 0x97, 0xce, 0x2d, 0x41, 0xbb, + 0x5e, 0xbc, 0xe6, 0xce, 0x28, 0x6e, 0xeb, 0x80, + 0x46, 0x2a, 0x7f, 0xdd, 0x6f, 0x57, 0x09, 0xda, + 0xaa, 0x7c, 0xa8, 0xf2, 0x97, 0xfe, 0x39, 0xbd, + 0x41, 0x5c, 0x39, 0xe0, 0x4b, 0x50, 0x2d, 0x1e, + 0xb6, 0xe4, 0xbf, 0xbb, 0xc2, 0xba, 0x87, 0x2b, + 0x2c, 0x99, 0xca, 0xf5, 0x42, 0x66, 0x54, 0x6d, + 0xbc, 0xc5, 0xaa, 0xbd, 0xf5, 0x52, 0x8d, 0xf7, + 0xdc, 0x1d, 0xb2, 0x0b, 0xe2, 0xf2, 0x11, 0x41, + 0x5c, 0x6e, 0x1a, 0xa4, 0xa5, 0x30, 0xad, 0xb5, + 0x91, 0x5a, 0x6e, 0x3d, 0xaa, 0x4a, 0xdd, 0x0b, + 0xb7, 0x2d, 0x43, 0x12, 0x48, 0x44, 0x6b, 0x9d, + 0x63, 0x3e, 0xfa, 0x95, 0x9f, 0xe3, 0x08, 0xe9, + 0xf4, 0x07, 0x3b, 0xea, 0x68, 0xf8, 0x7c, 0x64, + 0x5c, 0x1f, 0xf1, 0xc1, 0xfc, 0xe8, 0xb0, 0x29, + 0x0f, 0x69, 0x21, 0x09, 0x3d, 0x33, 0xac, 0x86, + 0x55, 0xad, 0x1a, 0x4f, 0x81, 0x8a, 0xa7, 0xe1, + 0x12, 0x8f, 0xf8, 0x24, 0x2e, 0xd3, 0x00, 0x3e, + 0x9c, 0xaf, 0x38, 0xe8, 0xbc, 0x0b, 0x2e, 0x90, + 0x69, 0xa8, 0x41, 0xde, 0x7b, 0x19, 0x05, 0xe7, + 0xe4, 0x53, 0xd6, 0x92, 0x89, 0x2f, 0x28, 0x27, + 0xae, 0x64, 0xd8, 0xa1, 0x97, 0xa9, 0x79, 0x43, + 0xdb, 0x7f, 0x82, 0x91, 0xe2, 0x73, 0x95, 0x89, + 0x5b, 0x04, 0xaa, 0x29, 0x9b, 0xcd, 0xe9, 0x61, + 0x3c, 0xc6, 0xd9, 0xcb, 0x0c, 0x9b, 0x90, 0xe1, + 0xde, 0x2b, 0x48, 0x8a, 0x19, 0x26, 0xa7, 0xfe, + 0xc6, 0x20, 0x6d, 0x76, 0x06, 0x58, 0x0a, 0x0b, + 0x9c, 0xc2, 0x9c, 0xd2, 0x2f, 0x73, 0x2b, 0x93, + 0x2c, 0x7d, 0xf0, 0xf5, 0x07, 0xf9, 0x2f, 0x2e, + 0xc2, 0x01, 0x02, 0xf9, 0xa3, 0x36, 0x5f, 0x61, + 0xb0, 0xca, 0xc2, 0x88, 0x96, 0x9c, 0xc3, 0x68, + 0x3a, 0x93, 0xa7, 0x06, 0xf8, 0xfb, 0x1a, 0x13, + 0xfc, 0x4e, 0x65, 0xf6, 0x64, 0x1d, 0xd6, 0xee, + 0x49, 0xd7, 0xfc, 0xef, 0x89, 0xfa, 0xf8, 0xff, + 0xe0, 0x1f, 0xfd, 0x63, 0x3e, 0x7a, 0xf0, 0xe3, + 0xc3, 0xcf, 0xc4, 0xfe, 0x58, 0x51, 0xf3, 0x3a, + 0x30, 0xa7, 0xf0, 0x13, 0xc0, 0xcf, 0xec, 0x16, + 0x61, 0xce, 0xe1, 0x67, 0x01, 0x3f, 0xe1, 0xb5, + 0x60, 0xda, 0x4e, 0x84, 0xac, 0x2e, 0x58, 0xe4, + 0x33, 0xe6, 0x0c, 0xbd, 0xa4, 0x11, 0x75, 0xe5, + 0x7c, 0xa3, 0xd6, 0xa7, 0x7f, 0xbf, 0x64, 0xf1, + 0xdb, 0x91, 0xe2, 0xfd, 0x46, 0x30, 0x83, 0x2b, + 0x5a, 0x4f, 0x1a, 0x5b, 0x6f, 0x8b, 0xc3, 0x74, + 0xeb, 0xa1, 0x0c, 0x2a, 0x5a, 0x07, 0x95, 0xad, + 0xcb, 0xf5, 0x66, 0xdb, 0xe2, 0x5a, 0xd5, 0xc9, + 0x7c, 0x6b, 0x14, 0x9b, 0x06, 0xba, 0xb8, 0x6a, + 0xb2, 0x9b, 0x1a, 0x87, 0xdb, 0xe2, 0x5f, 0x06, + 0xa2, 0x88, 0x89, 0x6e, 0x09, 0x31, 0x6a, 0x66, + 0x78, 0x1e, 0xca, 0x10, 0xa9, 0x17, 0x74, 0xc9, + 0x72, 0x29, 0xb2, 0x28, 0x59, 0x05, 0x14, 0xa9, + 0xf0, 0x08, 0x35, 0x1e, 0xdc, 0x80, 0x14, 0x81, + 0x4e, 0xdf, 0xb9, 0x50, 0x5b, 0xf3, 0x1d, 0xf8, + 0xf1, 0x7b, 0x4f, 0xb2, 0x9b, 0x3e, 0x7d, 0x6e, + 0x8b, 0xd0, 0x6c, 0x59, 0x8c, 0x50, 0xb1, 0x5e, + 0xce, 0xa0, 0x0d, 0x87, 0xf9, 0xb4, 0x32, 0xa0, + 0xf7, 0x45, 0x4b, 0xe6, 0x94, 0xc6, 0x04, 0xe2, + 0xa8, 0x97, 0x42, 0x87, 0x32, 0xbe, 0x2f, 0x56, + 0xc4, 0x50, 0x23, 0x6d, 0xd3, 0x2d, 0x46, 0xba, + 0xc4, 0x98, 0xc0, 0xbf, 0xaf, 0x43, 0xe0, 0x72, + 0x01, 0xc5, 0xd8, 0x3c, 0x26, 0x24, 0x0f, 0x06, + 0x83, 0x67, 0x87, 0x83, 0xe1, 0xd3, 0xde, 0xd3, + 0xa3, 0xc3, 0xc3, 0x67, 0x47, 0x87, 0x08, 0xf9, + 0x70, 0x38, 0x92, 0x0a, 0x1b, 0x89, 0x40, 0xc8, + 0x6c, 0xdb, 0x05, 0x60, 0x18, 0x8e, 0xd4, 0xc7, + 0x14, 0x39, 0x18, 0x06, 0x72, 0x4a, 0xd0, 0x64, + 0xfd, 0xe1, 0x73, 0x38, 0x42, 0x9e, 0x0e, 0x9f, + 0x3f, 0x07, 0x60, 0xa3, 0x67, 0xa4, 0x51, 0x11, + 0x00, 0x13, 0xc1, 0x53, 0x07, 0xf9, 0xe4, 0xa8, + 0x24, 0x74, 0xdf, 0x1b, 0x5c, 0x78, 0xf3, 0x79, + 0x90, 0xe2, 0x95, 0x2c, 0x0e, 0x72, 0x11, 0x46, + 0x91, 0xba, 0x66, 0xca, 0x17, 0x98, 0xf3, 0xa3, + 0x03, 0xdd, 0x4d, 0x3c, 0xbc, 0xe2, 0x4a, 0x30, + 0x53, 0xfc, 0x26, 0x74, 0x02, 0xbb, 0x62, 0x70, + 0x04, 0x2f, 0xc5, 0xa0, 0xa3, 0x71, 0x82, 0x81, + 0x4e, 0x3c, 0x1f, 0x26, 0x04, 0x96, 0x1b, 0x04, + 0x6e, 0x0a, 0x63, 0x99, 0xf5, 0xb0, 0xbf, 0x69, + 0x42, 0xa1, 0x91, 0x29, 0xd0, 0xa8, 0x0e, 0x2e, + 0x49, 0xc1, 0x92, 0x7d, 0x8c, 0x6c, 0xba, 0xd4, + 0x10, 0x9d, 0x70, 0x97, 0x72, 0x5c, 0x2d, 0x1e, + 0x07, 0x0d, 0x48, 0x9e, 0x40, 0xe4, 0x2a, 0xdc, + 0x96, 0xab, 0x4a, 0x77, 0xc6, 0x30, 0x2b, 0x5e, + 0xea, 0x87, 0x79, 0x8a, 0xd7, 0x5f, 0x74, 0x9e, + 0x28, 0x90, 0xff, 0x2d, 0xa9, 0x06, 0x47, 0xe0, + 0x9d, 0x82, 0xc6, 0x29, 0x27, 0x12, 0x96, 0xf3, + 0x7d, 0x86, 0x9e, 0xd2, 0xea, 0x72, 0x2c, 0xb8, + 0xc0, 0x24, 0xec, 0x74, 0xd8, 0xfa, 0x01, 0xe0, + 0xdf, 0x13, 0x59, 0x10, 0x08, 0x05, 0x26, 0x0e, + 0x27, 0xef, 0xc3, 0x69, 0xb4, 0x9e, 0x7b, 0xd9, + 0xe2, 0x31, 0xf4, 0xb7, 0x09, 0x10, 0x6f, 0xe1, + 0xa7, 0x81, 0xf7, 0x7e, 0x9a, 0x6c, 0x38, 0x87, + 0x3d, 0x65, 0xab, 0x0f, 0xe3, 0x59, 0xa2, 0x49, + 0x36, 0xcf, 0x57, 0xd9, 0x71, 0xbf, 0x3f, 0x0f, + 0xf3, 0xc5, 0xda, 0xef, 0x4d, 0x92, 0x65, 0x7f, + 0xe9, 0xad, 0xfc, 0xe4, 0x42, 0xfe, 0xd3, 0x9d, + 0x47, 0xdd, 0x7f, 0x03, 0x05, 0xae, 0xa3, 0xa8, + 0x7f, 0x38, 0x3a, 0x7a, 0xfa, 0xf5, 0x34, 0xcc, + 0x26, 0x6b, 0x42, 0x62, 0x9c, 0x0e, 0x0f, 0x8e, + 0x0e, 0x86, 0xcf, 0x0f, 0x0f, 0x9f, 0x3a, 0xf1, + 0x20, 0xe4, 0x72, 0x29, 0x01, 0x84, 0xa6, 0xe6, + 0x6f, 0x24, 0x44, 0x60, 0x54, 0xf9, 0x03, 0x71, + 0x6c, 0x3e, 0x1e, 0xf4, 0x0e, 0xe9, 0xe3, 0xfe, + 0x21, 0x7c, 0x85, 0x7f, 0x6c, 0xa5, 0x61, 0x0a, + 0x67, 0xd5, 0xb9, 0x8a, 0x09, 0xac, 0xad, 0x09, + 0xad, 0x09, 0xec, 0xc8, 0x99, 0xfc, 0x09, 0xdb, + 0x30, 0xe7, 0x2d, 0x0f, 0xcf, 0x4d, 0xf9, 0x33, + 0xb7, 0x02, 0xf3, 0xb4, 0xe6, 0xf0, 0x61, 0x21, + 0x7f, 0x4c, 0x55, 0x5f, 0xfe, 0x4c, 0x64, 0xc0, + 0x79, 0x20, 0x6b, 0x5e, 0x48, 0x34, 0x3b, 0xd4, + 0x2c, 0xa5, 0x33, 0xa8, 0x27, 0x92, 0x90, 0x47, + 0x86, 0x82, 0xab, 0xd5, 0x00, 0x36, 0x39, 0x90, + 0xdc, 0x65, 0xac, 0x21, 0x38, 0x2a, 0x90, 0x8c, + 0x8d, 0x54, 0x75, 0xd8, 0x29, 0x14, 0x5e, 0x56, + 0x17, 0x0e, 0xed, 0xe0, 0xfa, 0x6c, 0x8c, 0x19, + 0xdc, 0x47, 0x78, 0xc8, 0x07, 0x29, 0xad, 0x56, + 0x0b, 0xab, 0x57, 0x29, 0x12, 0x95, 0x48, 0x15, + 0x64, 0xce, 0x08, 0x30, 0x40, 0x6f, 0x89, 0x92, + 0x30, 0x2a, 0x1d, 0x45, 0x0a, 0x09, 0xe6, 0x91, + 0x15, 0x25, 0x9b, 0xd2, 0x67, 0xed, 0x5c, 0x51, + 0x2a, 0xf1, 0x26, 0x18, 0xa8, 0x07, 0x17, 0x4c, + 0x06, 0x4f, 0x7d, 0xfd, 0x4a, 0xec, 0xf7, 0x86, + 0x07, 0xc3, 0xc3, 0xe7, 0xa3, 0xa7, 0x87, 0xfb, + 0x87, 0x47, 0xcf, 0x9f, 0x3d, 0xdf, 0xaf, 0x0f, + 0xb6, 0x45, 0x07, 0x44, 0x83, 0x0e, 0x53, 0xb5, + 0x83, 0x5a, 0x7c, 0x20, 0xf4, 0xd2, 0x39, 0xc7, + 0xd2, 0x6e, 0x97, 0x82, 0x69, 0xff, 0xe6, 0x9c, + 0x59, 0x74, 0x56, 0x21, 0xe3, 0xf3, 0x5c, 0x76, + 0xe7, 0x64, 0x33, 0x9b, 0xc0, 0xb2, 0xc5, 0xea, + 0xe4, 0x21, 0xf8, 0xc8, 0x74, 0x56, 0xab, 0x34, + 0xb9, 0xc0, 0xd8, 0xab, 0x18, 0x77, 0x27, 0xa7, + 0x38, 0x48, 0x56, 0xce, 0x26, 0x18, 0x3b, 0x26, + 0x5b, 0x63, 0x4e, 0x14, 0xa4, 0x13, 0x8f, 0x98, + 0x28, 0x47, 0xf7, 0xa2, 0x28, 0xbc, 0x61, 0x06, + 0x5f, 0xe8, 0xe5, 0x15, 0xb1, 0xb6, 0xaf, 0x0f, + 0x8e, 0x06, 0xcf, 0xa8, 0xf6, 0x34, 0xc8, 0xbd, + 0x30, 0xca, 0xec, 0x90, 0x31, 0x88, 0xd9, 0xf7, + 0x2a, 0xaa, 0x15, 0x3a, 0xeb, 0xa0, 0x93, 0x87, + 0x17, 0x67, 0xad, 0x96, 0x59, 0xc4, 0xb7, 0x83, + 0x77, 0x6c, 0xb8, 0x53, 0x7f, 0x0f, 0xdf, 0xe1, + 0x76, 0x96, 0x26, 0x50, 0xa9, 0x8e, 0xb6, 0xd9, + 0xde, 0x69, 0x55, 0x91, 0xc4, 0xc6, 0x13, 0x43, + 0xc1, 0xb9, 0xad, 0x33, 0xc1, 0x9e, 0x1f, 0x9b, + 0xa7, 0x7f, 0xe8, 0xca, 0x69, 0x82, 0x39, 0x19, + 0x02, 0x7f, 0xb0, 0x71, 0xa5, 0x06, 0x40, 0xb5, + 0xb9, 0x17, 0xb7, 0xb0, 0x0c, 0x43, 0x3d, 0xf3, + 0x7b, 0x16, 0x5a, 0x23, 0xe4, 0x41, 0xd6, 0x78, + 0xdc, 0xc7, 0x2c, 0x14, 0xb8, 0x09, 0x1a, 0x2b, + 0xce, 0xc1, 0x16, 0x56, 0xb4, 0xdd, 0x23, 0x34, + 0xc9, 0x32, 0x30, 0xb8, 0x0c, 0x97, 0xb7, 0x81, + 0x93, 0x02, 0x49, 0xa9, 0x07, 0x6b, 0xaa, 0x82, + 0xbe, 0x85, 0x18, 0x52, 0x5e, 0x8f, 0x6e, 0x29, + 0x1f, 0x88, 0x09, 0x57, 0x7b, 0xaa, 0x88, 0x5d, + 0xa9, 0xed, 0x72, 0x1e, 0xa6, 0x53, 0x04, 0xac, + 0xa2, 0x83, 0xd1, 0xe1, 0x08, 0x6b, 0x07, 0x42, + 0x06, 0xb4, 0x81, 0x15, 0x97, 0xb1, 0xb3, 0xe6, + 0x51, 0xe2, 0x7b, 0x91, 0x74, 0xe4, 0x48, 0x7c, + 0x5c, 0xda, 0x8e, 0x3c, 0xd0, 0x00, 0x42, 0x06, + 0x20, 0xfa, 0x23, 0xc7, 0xdb, 0x03, 0xc9, 0xe6, + 0x43, 0xb8, 0x5c, 0xe7, 0x0b, 0x13, 0x2e, 0x5a, + 0xe7, 0xa8, 0xd3, 0x1d, 0x14, 0xa8, 0x67, 0x30, + 0x0d, 0xe6, 0x98, 0xd0, 0x0e, 0xce, 0xc3, 0x55, + 0x12, 0xab, 0x50, 0xeb, 0x31, 0x10, 0xcf, 0xa2, + 0x4f, 0xb9, 0xbf, 0x92, 0x95, 0xa2, 0x4d, 0x95, + 0xb8, 0x4f, 0xa5, 0x4e, 0xc8, 0xf2, 0x4b, 0x20, + 0x69, 0x9c, 0x55, 0xdb, 0x85, 0x09, 0x4b, 0x92, + 0x34, 0x9c, 0x93, 0x83, 0x8d, 0x0c, 0xac, 0xbe, + 0xf1, 0x32, 0xb1, 0x49, 0xc3, 0x1c, 0x26, 0x46, + 0xf6, 0x1f, 0xac, 0x72, 0xd1, 0xea, 0x82, 0x04, + 0x42, 0xee, 0x76, 0x88, 0xe1, 0x77, 0xca, 0xa0, + 0x0c, 0xf4, 0xf4, 0x1c, 0x76, 0x96, 0x27, 0xbd, + 0xc3, 0xd4, 0x88, 0x7a, 0xf6, 0x52, 0xf2, 0x47, + 0x6b, 0x82, 0x2f, 0x81, 0xf4, 0x5e, 0xbf, 0x72, + 0xf6, 0xa1, 0x4e, 0x2c, 0x28, 0xa9, 0x06, 0x0e, + 0xfd, 0x24, 0x0e, 0x28, 0xe5, 0x0a, 0x3a, 0xbf, + 0xa9, 0x2d, 0xa8, 0x97, 0x0b, 0xc4, 0x30, 0xca, + 0xb6, 0xe6, 0x81, 0xe0, 0xc5, 0xae, 0x6b, 0x7c, + 0x01, 0xb3, 0x0c, 0x23, 0x0f, 0xdd, 0x6a, 0x6c, + 0x37, 0x30, 0x0b, 0x96, 0xfb, 0xde, 0x4a, 0xcc, + 0xd6, 0x31, 0x8f, 0xa2, 0x34, 0x49, 0xc7, 0xd7, + 0x94, 0x14, 0x7c, 0x58, 0x7f, 0xf8, 0x82, 0x49, + 0x1f, 0xfa, 0x59, 0x3a, 0xe9, 0x13, 0xa4, 0x2e, + 0x42, 0xea, 0x1b, 0xf9, 0xa5, 0x4f, 0xbc, 0x8f, + 0x96, 0x38, 0xeb, 0x1b, 0x4c, 0x82, 0xde, 0xbf, + 0xb3, 0xaf, 0x7f, 0x1c, 0x0d, 0x9f, 0x75, 0x7f, + 0x1c, 0x8d, 0x8e, 0x8a, 0xce, 0x45, 0xc8, 0x53, + 0x61, 0x55, 0x0c, 0xa1, 0x4a, 0x67, 0xb6, 0x09, + 0x48, 0x38, 0x98, 0x0b, 0x04, 0x45, 0x9b, 0x64, + 0xe5, 0x81, 0x92, 0x6b, 0x0b, 0x89, 0xf6, 0x02, + 0x48, 0x03, 0xed, 0xb0, 0x77, 0xf4, 0xec, 0x10, + 0xd6, 0xcb, 0x8e, 0xd0, 0x3c, 0xec, 0x3d, 0x3b, + 0xb4, 0xb7, 0x1d, 0x1c, 0xfe, 0xff, 0x90, 0x2e, + 0x91, 0x1c, 0x29, 0x10, 0x97, 0xa9, 0xc0, 0x7d, + 0xa6, 0x67, 0x72, 0x5f, 0x1b, 0x40, 0x5f, 0x71, + 0xf5, 0x6f, 0x90, 0xe7, 0x82, 0x4c, 0xc1, 0xf7, + 0xae, 0xb4, 0x90, 0x8a, 0xe9, 0x92, 0x7c, 0xae, + 0x8b, 0x54, 0x37, 0xaa, 0x14, 0xb9, 0x93, 0xee, + 0xfa, 0x98, 0x5b, 0xda, 0x39, 0x0f, 0x02, 0xc1, + 0xe7, 0x87, 0x74, 0xea, 0x80, 0x2d, 0xa8, 0x56, + 0xdd, 0xf5, 0xb5, 0xca, 0xf0, 0x64, 0x91, 0x1b, + 0x80, 0xe9, 0x08, 0xb6, 0xa0, 0xa2, 0x2b, 0xa4, + 0xee, 0x66, 0x00, 0xd8, 0xbc, 0x38, 0xfd, 0x79, + 0xa1, 0x73, 0xd8, 0xb7, 0x24, 0x94, 0x43, 0x2f, + 0x93, 0x05, 0xf9, 0x17, 0x06, 0x94, 0xfb, 0x03, + 0x28, 0xa8, 0xb2, 0x2f, 0xa8, 0xcf, 0x15, 0x40, + 0xa2, 0x75, 0x76, 0x05, 0xc3, 0x64, 0x1e, 0x6e, + 0xcd, 0xab, 0xc3, 0x84, 0x35, 0xff, 0xa5, 0x70, + 0x7c, 0x16, 0x2a, 0xb8, 0x77, 0xed, 0x01, 0xd1, + 0xa9, 0x45, 0x82, 0x17, 0x8c, 0xa7, 0x40, 0x2a, + 0xc5, 0x11, 0xa9, 0xe2, 0x10, 0x90, 0xfa, 0x4f, + 0x5e, 0xb8, 0x69, 0x42, 0x61, 0xd4, 0x30, 0x1c, + 0x1f, 0xdf, 0x12, 0x61, 0x8c, 0x79, 0xce, 0xd4, + 0xc9, 0x13, 0x8b, 0x7d, 0x30, 0xdd, 0x59, 0x5a, + 0x4f, 0x14, 0x94, 0xa9, 0xf2, 0x6f, 0x04, 0x4f, + 0xb2, 0xca, 0x80, 0x82, 0x42, 0x02, 0x34, 0x09, + 0x81, 0x68, 0x15, 0xcf, 0x9b, 0x6c, 0x05, 0xba, + 0x49, 0x2c, 0xe7, 0x83, 0xfd, 0x33, 0x68, 0x5c, + 0xda, 0x91, 0x56, 0x1e, 0x55, 0xfc, 0x95, 0x2d, + 0x94, 0x72, 0xe4, 0x7b, 0x52, 0xbe, 0xb4, 0xa9, + 0x78, 0x54, 0x7b, 0x9b, 0xc8, 0x73, 0xc4, 0x61, + 0xcd, 0xd0, 0xfe, 0xde, 0x92, 0xe7, 0xca, 0x13, + 0xc5, 0x95, 0x90, 0x30, 0x81, 0xbd, 0xb3, 0xd0, + 0xe9, 0x4a, 0x09, 0x1a, 0x37, 0x02, 0xa2, 0x51, + 0x63, 0x1b, 0x3d, 0x0b, 0x40, 0x1d, 0x5b, 0xe6, + 0xe9, 0x70, 0x45, 0xc4, 0x16, 0x08, 0xc9, 0x59, + 0xd3, 0xad, 0xb1, 0x2e, 0x08, 0xac, 0xce, 0xac, + 0xe8, 0x03, 0xdc, 0xc2, 0xa7, 0xe7, 0xe1, 0x31, + 0x6e, 0x7d, 0xb8, 0x15, 0x91, 0xf8, 0xd1, 0x23, + 0xc9, 0x39, 0x4d, 0x46, 0x8d, 0x73, 0x3c, 0x18, + 0xe8, 0x38, 0xe3, 0x13, 0x2c, 0x96, 0xe9, 0x2b, + 0x30, 0xe6, 0x9e, 0xa4, 0x6d, 0x72, 0xcc, 0xce, + 0xe1, 0x80, 0x80, 0x33, 0xfb, 0x9c, 0x62, 0x6b, + 0x52, 0xf2, 0x0c, 0x90, 0xa6, 0x96, 0x40, 0x02, + 0x41, 0xea, 0xbc, 0x84, 0xf5, 0x48, 0xd2, 0x53, + 0x49, 0x33, 0x7b, 0x5a, 0x2c, 0x7c, 0xf1, 0xd3, + 0x9b, 0x57, 0x2f, 0x7e, 0x7c, 0xf5, 0xe2, 0xec, + 0xd5, 0x4f, 0x3f, 0x34, 0x25, 0xa4, 0x84, 0xc9, + 0x23, 0x2c, 0x39, 0x51, 0xc1, 0x10, 0xf4, 0x6a, + 0xf8, 0x46, 0x19, 0x2d, 0x9e, 0x62, 0xae, 0x09, + 0x89, 0x3f, 0xf0, 0x14, 0x4a, 0xe2, 0x09, 0xfd, + 0x27, 0x1b, 0xc0, 0x65, 0x19, 0xe6, 0xe4, 0xd2, + 0xbb, 0x64, 0x0d, 0x19, 0x65, 0x05, 0xb9, 0xc5, + 0x97, 0x09, 0xfa, 0x68, 0xf6, 0x4c, 0xa4, 0xcb, + 0xa9, 0xf6, 0x6a, 0x0e, 0x29, 0xeb, 0x0f, 0x8a, + 0x68, 0xb4, 0xb7, 0x60, 0x40, 0xfe, 0x25, 0x30, + 0x80, 0x56, 0x77, 0x38, 0x3a, 0xea, 0xf5, 0xa0, + 0xeb, 0x76, 0x8f, 0x92, 0xbf, 0xd0, 0x09, 0x96, + 0x06, 0xf3, 0x35, 0x9e, 0x40, 0xdc, 0x36, 0xc3, + 0x74, 0x21, 0x30, 0x5a, 0x19, 0x49, 0xef, 0xe9, + 0x3e, 0x28, 0xed, 0xeb, 0x5c, 0x62, 0x87, 0x2a, + 0x72, 0x2a, 0x05, 0xad, 0xbf, 0x22, 0x59, 0xc2, + 0xf9, 0xf4, 0x57, 0xdd, 0x90, 0x79, 0xbf, 0x77, + 0x8e, 0x7a, 0xb4, 0x1f, 0xa2, 0x1a, 0xa6, 0xa0, + 0xb4, 0x80, 0xf5, 0x30, 0x58, 0x74, 0x54, 0x0f, + 0x63, 0x9d, 0xe0, 0x08, 0x93, 0x10, 0xb5, 0x69, + 0x1d, 0xd4, 0x6c, 0x32, 0x4e, 0x34, 0x23, 0xee, + 0x27, 0xcc, 0x76, 0x76, 0x78, 0xf4, 0x6c, 0x7f, + 0x30, 0x7c, 0xfa, 0xa8, 0xec, 0x2a, 0x85, 0x77, + 0x54, 0x8c, 0x47, 0x85, 0x1f, 0x95, 0xcc, 0x53, + 0x78, 0xc5, 0x85, 0x4c, 0x39, 0xfb, 0x14, 0x85, + 0xdf, 0x2c, 0x28, 0x17, 0x40, 0x8c, 0xe5, 0x57, + 0xb2, 0x05, 0x75, 0x45, 0x21, 0x52, 0xf8, 0x4c, + 0x11, 0x06, 0x47, 0x65, 0x2f, 0xac, 0xb9, 0xb7, + 0x5c, 0x7a, 0x2a, 0x90, 0x66, 0x55, 0x76, 0x09, + 0xbc, 0x98, 0x8a, 0x83, 0x2c, 0x99, 0x79, 0xe9, + 0x67, 0x1a, 0x75, 0x8f, 0xa2, 0xd1, 0x56, 0xfb, + 0x90, 0x51, 0x86, 0xfb, 0x5a, 0x1f, 0x32, 0xca, + 0xbf, 0x78, 0xe7, 0xe9, 0x48, 0x1f, 0xca, 0x13, + 0xe4, 0x6a, 0x2c, 0xe7, 0xde, 0x8a, 0xb3, 0x35, + 0x56, 0xa2, 0xa9, 0x4a, 0x1b, 0xf3, 0xad, 0xa9, + 0x4a, 0x57, 0x65, 0x5c, 0xb3, 0xeb, 0x35, 0xcf, + 0xdc, 0x6c, 0x96, 0x05, 0x35, 0xde, 0x77, 0x5c, + 0xd6, 0x30, 0x6f, 0x54, 0xde, 0x3c, 0x35, 0xba, + 0x4a, 0x23, 0x16, 0x0d, 0xd3, 0x72, 0xf5, 0x9c, + 0x6c, 0x35, 0x21, 0xc5, 0xd9, 0xf8, 0x6c, 0xc2, + 0x35, 0xea, 0xf8, 0xcf, 0x2a, 0x97, 0x69, 0xd9, + 0xd5, 0x90, 0x13, 0x59, 0xca, 0x1d, 0x58, 0xeb, + 0x6a, 0xd8, 0x9c, 0x0a, 0xf5, 0x21, 0x3c, 0x8f, + 0x6f, 0xc0, 0x45, 0x6f, 0x9d, 0x72, 0x0a, 0x35, + 0x55, 0x54, 0x89, 0x9b, 0x2a, 0xec, 0x38, 0x1b, + 0xac, 0x21, 0x21, 0x9b, 0x0d, 0xad, 0x62, 0x17, + 0x35, 0x4d, 0x17, 0xef, 0xa4, 0xe2, 0x80, 0xe9, + 0x6b, 0xf5, 0xbc, 0x51, 0x51, 0xc7, 0xda, 0x68, + 0xb5, 0xb3, 0xa6, 0x81, 0x94, 0x36, 0x54, 0x53, + 0x0e, 0xbd, 0x9a, 0x09, 0xab, 0x9f, 0x2d, 0x3d, + 0x55, 0x57, 0xcf, 0x93, 0x99, 0xa4, 0xe2, 0xce, + 0xd2, 0xc6, 0x30, 0xcf, 0x09, 0xbd, 0x2d, 0xf3, + 0xbd, 0xa2, 0x88, 0x0b, 0xb2, 0xcb, 0xc0, 0x31, + 0xb8, 0x18, 0xff, 0x65, 0xe9, 0xab, 0x22, 0xab, + 0x7f, 0xe8, 0x50, 0x64, 0x76, 0x16, 0x8b, 0x2d, + 0xaf, 0x3e, 0x79, 0x86, 0xa2, 0xb0, 0xae, 0xb2, + 0x45, 0x71, 0x7d, 0xbe, 0xb5, 0x45, 0xb9, 0x54, + 0x7e, 0xc1, 0x38, 0xe7, 0x4f, 0x0f, 0x74, 0x4e, + 0xbb, 0xb2, 0x4b, 0xa7, 0x2d, 0x71, 0x50, 0x3a, + 0x5a, 0xa5, 0x64, 0x5c, 0xa0, 0x94, 0x36, 0x44, + 0x57, 0xbb, 0x90, 0x0c, 0x26, 0x98, 0xed, 0x1c, + 0x34, 0x9f, 0x89, 0xb7, 0x02, 0xc9, 0xb9, 0x7c, + 0xef, 0x71, 0xa9, 0xab, 0xa3, 0x18, 0x27, 0xc5, + 0x37, 0xca, 0xf5, 0x86, 0x82, 0x18, 0x3f, 0xfc, + 0xe9, 0x4a, 0x70, 0xea, 0x3b, 0xde, 0x11, 0x38, + 0x53, 0x4b, 0x78, 0x59, 0xce, 0xb6, 0x16, 0x6a, + 0x1f, 0x36, 0x26, 0xee, 0xba, 0x2c, 0x57, 0xd2, + 0x89, 0x65, 0x6f, 0xc8, 0xa4, 0x8e, 0x83, 0x2c, + 0x90, 0xcc, 0x0c, 0x19, 0xc5, 0xa7, 0x46, 0x81, + 0xcd, 0x0f, 0xd0, 0x56, 0x18, 0x85, 0x2c, 0x48, + 0x22, 0x92, 0xff, 0xe7, 0x8c, 0xb0, 0x8a, 0xf9, + 0x3d, 0x23, 0xa5, 0x18, 0x44, 0x15, 0x39, 0xd3, + 0xb9, 0xe0, 0x96, 0x20, 0x7a, 0x93, 0x9d, 0x66, + 0x69, 0x12, 0x0b, 0x4a, 0x43, 0x0d, 0x5a, 0x84, + 0x40, 0xad, 0x48, 0x71, 0x2f, 0x93, 0x42, 0x18, + 0x2e, 0x01, 0x36, 0x6e, 0x67, 0x6e, 0x6d, 0x6d, + 0x23, 0xfd, 0x6b, 0x9f, 0x57, 0xc0, 0xba, 0x3c, + 0xf4, 0xa2, 0x99, 0xaa, 0x55, 0xaa, 0xa2, 0x69, + 0x1e, 0x0d, 0x67, 0xf8, 0x74, 0x5d, 0x12, 0xbe, + 0x63, 0x40, 0xe3, 0x1a, 0xba, 0x87, 0x27, 0xa2, + 0xa5, 0x7f, 0x57, 0xd6, 0x37, 0x47, 0xaa, 0x3f, + 0x2e, 0xdd, 0x41, 0x82, 0xfa, 0x50, 0x02, 0x62, + 0xf0, 0xda, 0xab, 0x00, 0x38, 0x22, 0x73, 0xde, + 0x90, 0xc9, 0xac, 0x65, 0x8d, 0x41, 0x59, 0x09, + 0x39, 0x8f, 0xaf, 0xdd, 0x6f, 0xbb, 0x98, 0xdf, + 0xad, 0x32, 0xa8, 0x3d, 0x5d, 0x19, 0xa1, 0x7e, + 0x62, 0xbf, 0x69, 0x84, 0x9a, 0x31, 0x8a, 0xdc, + 0xfe, 0xa5, 0xd1, 0x7e, 0xcc, 0xc6, 0x06, 0x80, + 0x64, 0x72, 0x08, 0x33, 0xba, 0xbf, 0x0b, 0x2e, + 0x7a, 0x65, 0x7a, 0x92, 0xd1, 0x7c, 0xe4, 0x40, + 0xf7, 0x9c, 0x28, 0xf8, 0x85, 0x24, 0x6f, 0xe6, + 0x29, 0x26, 0x29, 0xd0, 0xbc, 0x02, 0x1b, 0xc4, + 0x60, 0x9a, 0x7a, 0x1b, 0xb6, 0x79, 0x45, 0x9c, + 0xf2, 0xd0, 0xe3, 0x67, 0xae, 0x92, 0x28, 0xd0, + 0x8e, 0x2d, 0x6d, 0x1f, 0x9c, 0x85, 0x8e, 0xaa, + 0xf5, 0x6c, 0x63, 0x77, 0xa2, 0x2f, 0xf7, 0xc8, + 0x7a, 0xc4, 0xc0, 0xec, 0x24, 0x96, 0x72, 0x53, + 0xe4, 0xc9, 0xc6, 0x4b, 0xa7, 0x99, 0xad, 0x0d, + 0x91, 0xe6, 0x02, 0xfb, 0x2f, 0x07, 0xcc, 0xac, + 0x7b, 0x46, 0x42, 0x8c, 0x73, 0x3f, 0x2a, 0xf4, + 0x78, 0x8f, 0x02, 0x27, 0x52, 0xd0, 0x5a, 0x2e, + 0x6f, 0x81, 0x1d, 0x08, 0xdd, 0x0d, 0xdb, 0x32, + 0x6f, 0x1d, 0xf4, 0x11, 0xea, 0x37, 0x78, 0x6a, + 0x56, 0x24, 0x4e, 0x12, 0x00, 0x2a, 0x5d, 0x31, + 0xed, 0x76, 0xe3, 0x56, 0xdb, 0xab, 0xe0, 0x87, + 0x6b, 0x6d, 0xb6, 0xb2, 0x7a, 0x3c, 0xa9, 0xa8, + 0x98, 0x1b, 0x5f, 0x2c, 0x3f, 0x6b, 0xad, 0xdb, + 0x27, 0xe5, 0x15, 0xe3, 0x89, 0x47, 0xbf, 0x39, + 0xb9, 0x04, 0x15, 0x8b, 0x86, 0x37, 0xcc, 0xca, + 0x03, 0x18, 0x0d, 0x58, 0x39, 0x25, 0xb1, 0xea, + 0xae, 0x3b, 0x02, 0xfe, 0x9f, 0x3b, 0x8e, 0x75, + 0x3a, 0x99, 0x87, 0xc5, 0x8f, 0x8b, 0xf7, 0x3e, + 0x44, 0x24, 0x7d, 0xa5, 0x2c, 0x19, 0x27, 0xe9, + 0x72, 0x32, 0xa0, 0x8a, 0xc6, 0x7c, 0x69, 0xaf, + 0xb0, 0x2e, 0x42, 0x91, 0x3b, 0xa5, 0x84, 0x85, + 0x21, 0x3b, 0x6d, 0x0f, 0x13, 0xf8, 0x92, 0x7a, + 0xb9, 0x96, 0x9a, 0xbe, 0x95, 0x42, 0x81, 0x4c, + 0xca, 0x98, 0x14, 0x34, 0xcc, 0x16, 0xa8, 0xf3, + 0xa7, 0x18, 0xbf, 0x3e, 0xc0, 0xa4, 0x1e, 0x0e, + 0xa1, 0xd4, 0x06, 0xc9, 0x1f, 0xa3, 0x9d, 0x0d, + 0x76, 0x80, 0x9d, 0x96, 0xc1, 0x44, 0xb8, 0xb2, + 0xa2, 0x5f, 0xd6, 0x36, 0xae, 0x6e, 0x59, 0x1a, + 0x54, 0x55, 0x40, 0xbb, 0xbd, 0x4a, 0x6d, 0x53, + 0x5f, 0xaf, 0x59, 0x5a, 0x23, 0x00, 0xde, 0x02, + 0xef, 0xfe, 0x55, 0xf8, 0xe9, 0x93, 0x92, 0x15, + 0x55, 0x75, 0xa3, 0xcb, 0x1c, 0xa0, 0xc3, 0x6c, + 0xf3, 0xd3, 0x86, 0xd9, 0x26, 0xa1, 0xf6, 0xce, + 0xb5, 0xc1, 0xbb, 0x8a, 0x27, 0x5b, 0xd4, 0xff, + 0x6b, 0xac, 0x05, 0x95, 0x66, 0x81, 0x7b, 0x0f, + 0x08, 0xae, 0xf5, 0x87, 0xed, 0x75, 0x81, 0x5b, + 0x0c, 0xfe, 0x53, 0x3a, 0x54, 0xac, 0x44, 0xb9, + 0xe6, 0x1e, 0xd3, 0x64, 0xc7, 0xa5, 0xd3, 0x85, + 0x32, 0xf6, 0xe0, 0x1e, 0xe9, 0x35, 0x04, 0xa5, + 0xe3, 0xd9, 0x6e, 0x93, 0xbb, 0x2f, 0x2f, 0x48, + 0x2f, 0xab, 0x3b, 0xc9, 0x3c, 0xba, 0x80, 0x61, + 0x7b, 0x1f, 0xa7, 0xea, 0xe0, 0x8b, 0xc3, 0x1e, + 0xa7, 0xf2, 0x40, 0x67, 0x9c, 0x90, 0x58, 0x3c, + 0x1d, 0x29, 0x33, 0xf9, 0xa2, 0x3a, 0xb6, 0x2f, + 0x72, 0x14, 0x62, 0x68, 0xe8, 0xa2, 0x14, 0xc5, + 0xb1, 0x62, 0xce, 0x54, 0xd2, 0xd2, 0x48, 0xe4, + 0x6d, 0x64, 0x4f, 0x36, 0x20, 0x95, 0x13, 0x04, + 0x20, 0x99, 0x6a, 0x99, 0x1d, 0x0f, 0x02, 0x97, + 0x01, 0xb7, 0x69, 0x8b, 0x16, 0xe6, 0x49, 0xad, + 0xf1, 0x91, 0x47, 0xeb, 0xd0, 0x53, 0x39, 0x06, + 0x1f, 0x5b, 0x7b, 0x97, 0x40, 0x60, 0x34, 0x65, + 0x5d, 0x1b, 0x37, 0xf8, 0x8b, 0xfa, 0xc2, 0xc7, + 0x14, 0x1a, 0x13, 0xf8, 0x48, 0x1c, 0x10, 0xba, + 0xa4, 0xc2, 0x72, 0xd4, 0x83, 0x9a, 0xd8, 0xf0, + 0x77, 0x13, 0x0b, 0x78, 0x67, 0x59, 0xbd, 0x15, + 0xcb, 0x6a, 0xf1, 0x6e, 0x53, 0x6f, 0x3c, 0x9f, + 0x53, 0x4d, 0xcb, 0x74, 0xd9, 0xa1, 0xf6, 0x75, + 0xf2, 0xd7, 0xb3, 0x19, 0x9c, 0x21, 0xfa, 0xae, + 0x06, 0x46, 0x8f, 0x8e, 0x65, 0x34, 0x45, 0x08, + 0x8d, 0x02, 0x39, 0x28, 0x28, 0x1c, 0xd0, 0x82, + 0x3e, 0x65, 0x01, 0x65, 0xb8, 0xce, 0x7a, 0xe2, + 0xd7, 0x4c, 0x5e, 0x52, 0x6b, 0xe7, 0x5d, 0x99, + 0xe7, 0xd8, 0x41, 0xc0, 0x18, 0xdc, 0x7f, 0x7c, + 0xf5, 0xd3, 0xcb, 0xf1, 0x77, 0xaf, 0xce, 0xde, + 0xbc, 0xf8, 0x09, 0xe8, 0xfc, 0xec, 0xdb, 0x17, + 0x3f, 0xbe, 0xd4, 0xc6, 0xf5, 0xcf, 0xe0, 0x0a, + 0xe0, 0x8b, 0xb2, 0x5d, 0x5b, 0x86, 0xe9, 0xe6, + 0xf3, 0x6b, 0x67, 0x18, 0xbe, 0x7d, 0xc3, 0xf0, + 0xc3, 0x30, 0xc2, 0x3e, 0x44, 0xf3, 0xf4, 0x03, + 0x36, 0x0c, 0xef, 0x0c, 0xb3, 0x0f, 0xd2, 0xea, + 0xf9, 0x19, 0x58, 0x8a, 0xbf, 0x38, 0xc3, 0xac, + 0xdd, 0xe2, 0xa6, 0xd6, 0xd9, 0x0a, 0x61, 0x60, + 0x67, 0xad, 0xdd, 0x59, 0x6b, 0x77, 0xd6, 0xda, + 0x9d, 0xb5, 0x76, 0x67, 0xad, 0xdd, 0x59, 0x6b, + 0xff, 0x04, 0xd6, 0x5a, 0xfb, 0xe4, 0xf4, 0x6c, + 0x85, 0x6c, 0x4b, 0x63, 0xee, 0xed, 0x46, 0xf9, + 0x7a, 0x48, 0xd1, 0x34, 0x50, 0xcd, 0xbf, 0x5e, + 0x38, 0x8d, 0x4f, 0xa1, 0xfd, 0x7e, 0x46, 0xf6, + 0xec, 0x6d, 0x43, 0x6e, 0xec, 0x6c, 0xc7, 0x3b, + 0xdb, 0xf1, 0x47, 0xda, 0x8e, 0xb9, 0x83, 0x0b, + 0x0a, 0x48, 0xc5, 0x61, 0x48, 0x0c, 0x9f, 0xeb, + 0x97, 0xd8, 0x14, 0xbe, 0xf6, 0x2d, 0x3a, 0x52, + 0x5f, 0x58, 0x21, 0x4c, 0x1a, 0xda, 0xfa, 0xa6, + 0xad, 0x9a, 0x32, 0xb5, 0xd2, 0x3d, 0x92, 0xf7, + 0x8d, 0x59, 0x38, 0x9c, 0x92, 0xbc, 0xa0, 0xe8, + 0x08, 0x81, 0x76, 0x50, 0xda, 0x90, 0xe5, 0x1c, + 0x88, 0x15, 0x0d, 0x8c, 0x00, 0x50, 0x7d, 0xa4, + 0x50, 0x55, 0xf4, 0xd1, 0x7a, 0x3c, 0x4b, 0xf3, + 0x55, 0x10, 0xf5, 0x94, 0xec, 0xc6, 0x52, 0xbc, + 0x0a, 0x57, 0x3c, 0x20, 0xf9, 0x10, 0xe5, 0x4f, + 0x26, 0x5d, 0xc6, 0x5c, 0x45, 0x9e, 0x59, 0x45, + 0xeb, 0x4c, 0xa5, 0xa4, 0x17, 0xf8, 0x2e, 0xb2, + 0x6d, 0xbd, 0xe1, 0x0a, 0xe2, 0x6c, 0x2d, 0x5f, + 0x39, 0x27, 0xf1, 0xe3, 0x5c, 0xb2, 0x3f, 0xea, + 0x46, 0xbd, 0x1f, 0x9b, 0x06, 0x18, 0xac, 0x96, + 0x5e, 0x14, 0x64, 0x97, 0x4b, 0x3f, 0x89, 0xd4, + 0x9b, 0xb1, 0x6c, 0x05, 0x42, 0x3f, 0xea, 0x01, + 0x41, 0x90, 0x6b, 0x01, 0x0f, 0x25, 0x1f, 0x7c, + 0x1f, 0x3b, 0x9d, 0xb2, 0xb2, 0x91, 0x2d, 0xc2, + 0x59, 0xae, 0x43, 0xc6, 0xd2, 0x7b, 0x15, 0x85, + 0x3d, 0x4a, 0x68, 0x50, 0xc9, 0x1d, 0xc5, 0x90, + 0x14, 0x0a, 0xf7, 0x39, 0x4b, 0x32, 0xb3, 0x29, + 0x5e, 0x3e, 0x96, 0xe3, 0x90, 0x0c, 0xf8, 0x6e, + 0xc7, 0x3e, 0xec, 0x2f, 0xc7, 0x32, 0x8f, 0x3c, + 0x4a, 0xe4, 0xd6, 0x12, 0x29, 0x47, 0x75, 0x43, + 0x5d, 0x92, 0x9a, 0x5a, 0x25, 0x2a, 0xc1, 0x57, + 0x3c, 0x26, 0x54, 0x46, 0xbb, 0x8a, 0x90, 0xdc, + 0x04, 0x45, 0x97, 0x44, 0x43, 0x1f, 0xd1, 0xa7, + 0x7f, 0x75, 0x9f, 0xbe, 0xee, 0x53, 0x69, 0xac, + 0x4c, 0xf4, 0x1f, 0x11, 0x08, 0x88, 0x8e, 0xfa, + 0x0b, 0x8c, 0x31, 0x04, 0x93, 0xd6, 0x2e, 0x42, + 0xf7, 0x3f, 0x32, 0x6c, 0x8f, 0x84, 0xee, 0x23, + 0x74, 0xbf, 0xed, 0x48, 0xa1, 0xf6, 0x8b, 0x83, + 0xea, 0xe0, 0x3d, 0x63, 0x8c, 0xd2, 0x5d, 0x53, + 0x84, 0x31, 0x71, 0xf9, 0xd4, 0xbe, 0xe2, 0x06, + 0xe9, 0x2e, 0x72, 0x3b, 0xed, 0xee, 0x8f, 0x76, + 0xf7, 0x47, 0xbb, 0xfb, 0xa3, 0xc6, 0xfb, 0x23, + 0xc9, 0x12, 0x6a, 0x83, 0xf0, 0xc2, 0xb6, 0x1e, + 0x5f, 0xd6, 0x8b, 0xf6, 0xf5, 0x31, 0x7a, 0xa9, + 0x9d, 0x7f, 0x97, 0xf7, 0x55, 0xf2, 0x33, 0xf6, + 0xe4, 0x55, 0x7e, 0xf5, 0x6f, 0x28, 0xc2, 0xef, + 0x9e, 0x5d, 0xec, 0x9e, 0x5d, 0xec, 0x9e, 0x5d, + 0x5c, 0xff, 0x76, 0x4d, 0x2d, 0x5e, 0xc5, 0x2d, + 0xc4, 0x75, 0xaf, 0xde, 0xaa, 0x91, 0xa4, 0xc3, + 0xbc, 0x01, 0x53, 0x53, 0x5e, 0x3f, 0x65, 0xa6, + 0x4e, 0x25, 0xb5, 0xd9, 0xc5, 0x0d, 0xb3, 0xea, + 0x56, 0xdb, 0x3d, 0x24, 0xd9, 0x3d, 0x24, 0xf9, + 0xb3, 0x3d, 0x24, 0xb9, 0xdb, 0x1b, 0xca, 0x06, + 0x14, 0x2c, 0x26, 0x20, 0x95, 0x3a, 0xf9, 0x67, + 0x25, 0x32, 0xa6, 0xb8, 0x53, 0x60, 0x10, 0x75, + 0x13, 0xe3, 0x02, 0xac, 0xde, 0xe9, 0xbb, 0xfb, + 0xd3, 0xdd, 0xfd, 0xe9, 0xee, 0xfe, 0xf4, 0xb3, + 0xb8, 0x3f, 0xdd, 0x5d, 0x9f, 0xee, 0xae, 0x4f, + 0x77, 0xd7, 0xa7, 0x7f, 0xae, 0xeb, 0x53, 0x32, + 0x09, 0xa8, 0xeb, 0x51, 0xfb, 0x1c, 0xdd, 0x2b, + 0x59, 0x3c, 0x28, 0x1a, 0xa0, 0x2d, 0x24, 0x58, + 0xd4, 0x55, 0xaa, 0x7b, 0x49, 0xc1, 0xca, 0xa4, + 0x49, 0x44, 0x0f, 0x84, 0x4c, 0x0d, 0x5b, 0xf5, + 0xe6, 0x5f, 0xa3, 0x37, 0xdf, 0xe9, 0xcd, 0x6f, + 0x5f, 0xe3, 0x25, 0xcf, 0x35, 0xa2, 0x79, 0x67, + 0xd3, 0x19, 0xad, 0x43, 0x5d, 0xda, 0x82, 0x07, + 0x69, 0x99, 0xd9, 0xbd, 0x46, 0xda, 0x46, 0x97, + 0xbf, 0x4f, 0x6d, 0xfc, 0x5e, 0x14, 0xe9, 0x2f, + 0xf0, 0x61, 0x54, 0x3d, 0xb4, 0x2b, 0x1d, 0x43, + 0xeb, 0x34, 0xa6, 0x2b, 0x15, 0xa6, 0x1b, 0xa8, + 0x3a, 0xbb, 0xeb, 0xf7, 0x2f, 0xe7, 0xfa, 0x1d, + 0x38, 0x3e, 0xd6, 0x1b, 0x7b, 0x75, 0x81, 0x4c, + 0x89, 0x6b, 0xb7, 0x7b, 0xde, 0x49, 0x45, 0x23, + 0xbf, 0xa9, 0x91, 0x5f, 0xdd, 0x48, 0x5e, 0x1d, + 0xea, 0x7e, 0x3b, 0x06, 0x9a, 0x49, 0xe4, 0x81, + 0xad, 0xe4, 0x0d, 0xe0, 0xa9, 0xc8, 0x96, 0x09, + 0x48, 0x9e, 0x59, 0x1e, 0xac, 0x28, 0x21, 0x52, + 0xd7, 0x3a, 0xa7, 0x0a, 0xc7, 0xa7, 0xca, 0x97, + 0x54, 0x53, 0x2c, 0x3b, 0xfa, 0x24, 0x6f, 0xd7, + 0xb6, 0x4b, 0x15, 0x92, 0x47, 0x63, 0x0e, 0x42, + 0x57, 0x97, 0xfe, 0xb0, 0xae, 0x94, 0xaf, 0xd8, + 0xf4, 0x79, 0x79, 0x4b, 0x61, 0x82, 0x07, 0x55, + 0x61, 0x7a, 0x87, 0xb7, 0x12, 0x3c, 0x58, 0xc6, + 0x31, 0x4d, 0x03, 0x19, 0x32, 0xf3, 0x55, 0x9c, + 0x0f, 0x9f, 0x92, 0x3a, 0xad, 0x3c, 0x04, 0x74, + 0xdc, 0x51, 0xe3, 0x2a, 0x40, 0x9a, 0xd6, 0x1c, + 0x85, 0xbf, 0x35, 0xec, 0xee, 0x18, 0x03, 0x8e, + 0x0b, 0x93, 0xf4, 0x62, 0x66, 0xb2, 0xe6, 0xce, + 0x52, 0x4f, 0x65, 0x96, 0xb2, 0x5a, 0xf7, 0xb0, + 0x4b, 0x8c, 0xec, 0x8d, 0x11, 0x8a, 0xc9, 0xbd, + 0x41, 0x2b, 0xa1, 0x65, 0xb7, 0x84, 0x4c, 0x99, + 0x07, 0x78, 0x6a, 0x75, 0x7c, 0x52, 0x27, 0x7a, + 0x78, 0x18, 0x5d, 0xd2, 0x59, 0xa3, 0x62, 0xba, + 0x03, 0x4c, 0x0c, 0xab, 0x19, 0xa4, 0x78, 0x0f, + 0x3b, 0x0d, 0x7e, 0x5f, 0x23, 0xb3, 0x32, 0x18, + 0x12, 0x03, 0x81, 0x05, 0xc4, 0x38, 0xb0, 0x2a, + 0x1a, 0x26, 0x85, 0x92, 0x64, 0x7e, 0x45, 0x57, + 0xbb, 0xa4, 0x48, 0x7a, 0xcb, 0x40, 0x5e, 0x75, + 0xca, 0x18, 0xa6, 0x2f, 0xff, 0xf9, 0xe6, 0xe5, + 0x4f, 0x6f, 0xf0, 0xe6, 0xd4, 0x4c, 0x19, 0x4e, + 0x56, 0xb2, 0x96, 0x61, 0xe5, 0x19, 0x4b, 0x32, + 0xe6, 0x58, 0x63, 0xe8, 0x58, 0x61, 0x16, 0x61, + 0x45, 0x16, 0x32, 0xee, 0x38, 0xd0, 0x24, 0x2d, + 0xaa, 0x64, 0x90, 0x78, 0x17, 0x9c, 0xc4, 0x19, + 0x6c, 0x0d, 0x13, 0xfe, 0x90, 0x96, 0x9f, 0xe2, + 0x15, 0xd7, 0x26, 0x23, 0xe9, 0x52, 0x62, 0x30, + 0x52, 0x74, 0x6c, 0xf2, 0x13, 0x6d, 0x0e, 0x5c, + 0x68, 0x05, 0x89, 0xc6, 0xd4, 0x44, 0x2d, 0x09, + 0x72, 0xaf, 0x40, 0xcb, 0x1c, 0xf1, 0xd7, 0x22, + 0x7c, 0x6b, 0xb3, 0xd8, 0x5e, 0x7e, 0xe3, 0xbc, + 0x21, 0xf9, 0x4c, 0xad, 0x88, 0x3b, 0x68, 0x28, + 0x1b, 0x9e, 0x5c, 0x87, 0xe4, 0x4b, 0x3b, 0x8e, + 0x52, 0x6b, 0x83, 0x6c, 0x9f, 0x61, 0x5a, 0xba, + 0x93, 0xa6, 0x72, 0xa4, 0x90, 0x0a, 0x08, 0x99, + 0x07, 0x93, 0x4a, 0xd6, 0x29, 0x9d, 0x95, 0xb4, + 0x58, 0x05, 0x96, 0x05, 0xc8, 0x2c, 0xcb, 0x4b, + 0x15, 0x64, 0x56, 0xd2, 0x6c, 0x15, 0xc6, 0xe3, + 0x0d, 0x79, 0x0a, 0x95, 0x63, 0x7a, 0xab, 0xb5, + 0x4f, 0x03, 0x6f, 0x4a, 0x36, 0x94, 0x49, 0x9a, + 0x64, 0x59, 0x77, 0xa6, 0x03, 0x74, 0x66, 0xe6, + 0x88, 0xc6, 0x46, 0x54, 0x87, 0x57, 0x81, 0x33, + 0x13, 0x14, 0x9c, 0x3e, 0x06, 0x55, 0xdc, 0x7e, + 0x20, 0x83, 0x5d, 0x0f, 0xb6, 0xcb, 0x47, 0x35, + 0x94, 0xd5, 0x15, 0x1b, 0xc0, 0x7c, 0x75, 0x0c, + 0xbc, 0xe7, 0xb1, 0x65, 0xc9, 0x4e, 0x57, 0x27, + 0x4b, 0x30, 0x6b, 0xdc, 0xa9, 0xfd, 0x47, 0x5f, + 0xfd, 0xe1, 0xa9, 0x44, 0x73, 0x0e, 0xac, 0x61, + 0x2d, 0xac, 0xa1, 0x0d, 0x6b, 0x68, 0xc3, 0x1a, + 0xba, 0xb0, 0x4a, 0xae, 0x2e, 0xdc, 0xa1, 0x4c, + 0x39, 0x35, 0xec, 0x68, 0xa2, 0xb4, 0x33, 0xd9, + 0xf7, 0xe8, 0xb8, 0xb2, 0xc8, 0x52, 0xa7, 0xc9, + 0xb4, 0x7a, 0xc5, 0x4e, 0x8d, 0x48, 0x83, 0x0b, + 0xc8, 0xe9, 0x68, 0xe6, 0x52, 0x67, 0xdc, 0xb7, + 0xe2, 0xd3, 0x27, 0x79, 0x0b, 0xbe, 0x77, 0x0a, + 0x0b, 0x8d, 0xf9, 0x35, 0xad, 0xd0, 0xfa, 0x75, + 0xb5, 0x3e, 0x5c, 0x5c, 0x6e, 0x51, 0xeb, 0xf2, + 0xc3, 0x45, 0xdb, 0x32, 0xcb, 0x19, 0x9a, 0xb4, + 0x85, 0x10, 0x8c, 0x97, 0x3a, 0x47, 0xb5, 0x5c, + 0x27, 0xfc, 0x7e, 0x22, 0x74, 0x86, 0x6e, 0xa1, + 0xb2, 0x5d, 0xc3, 0x54, 0xee, 0xeb, 0xec, 0x3a, + 0x9c, 0xe8, 0xaf, 0xa5, 0x9a, 0x76, 0xf1, 0x0b, + 0x87, 0x4c, 0xad, 0x20, 0x7b, 0x6d, 0x01, 0x91, + 0xe4, 0x6e, 0xcd, 0x08, 0x22, 0xad, 0x38, 0xcd, + 0x5e, 0x79, 0x47, 0x28, 0x56, 0xa3, 0x20, 0x98, + 0x5d, 0x67, 0x26, 0x9f, 0xa3, 0xa1, 0xe2, 0x0d, + 0x80, 0x9a, 0xe1, 0xe2, 0xee, 0xed, 0x88, 0xab, + 0xbf, 0xb4, 0x4f, 0x6c, 0x88, 0xf0, 0xa1, 0x16, + 0x20, 0xf6, 0xd6, 0x11, 0xdb, 0x7c, 0xaa, 0x91, + 0x44, 0xe8, 0xc8, 0x64, 0xf7, 0x2d, 0x85, 0x79, + 0xc7, 0xf4, 0xd9, 0x51, 0x53, 0x29, 0x69, 0xae, + 0xa3, 0x7e, 0xb9, 0x1d, 0x41, 0x05, 0x4f, 0x82, + 0x5c, 0x2e, 0xfc, 0xeb, 0x57, 0x50, 0xab, 0x14, + 0x10, 0xff, 0xa4, 0xc6, 0x41, 0x45, 0x59, 0xa6, + 0x6b, 0x1c, 0x54, 0x9c, 0xcf, 0xfb, 0xd8, 0x46, + 0x5b, 0x8d, 0x0a, 0xd2, 0x89, 0xbe, 0xbf, 0xc5, + 0x1d, 0x66, 0x1c, 0xc0, 0x14, 0xef, 0xf3, 0x93, + 0x24, 0x42, 0x1e, 0x9e, 0xb1, 0x73, 0x1d, 0x26, + 0x7d, 0x18, 0x13, 0xd6, 0x9e, 0x2d, 0x19, 0x15, + 0x6a, 0xcd, 0x02, 0x8f, 0x8e, 0xb0, 0x72, 0x45, + 0x3b, 0x0c, 0xe7, 0x9a, 0x2b, 0xe7, 0x94, 0x42, + 0x55, 0xdd, 0x18, 0x58, 0x31, 0xb1, 0xb5, 0xbb, + 0x23, 0x25, 0xa6, 0xc8, 0xf2, 0x64, 0x95, 0xf1, + 0xa1, 0x4e, 0x69, 0x62, 0xf0, 0x08, 0x67, 0x47, + 0xc9, 0x0c, 0x5d, 0x2b, 0x55, 0x1c, 0xef, 0x86, + 0x9e, 0x4c, 0x3f, 0x0e, 0x14, 0x0a, 0xac, 0x4c, + 0x5d, 0x20, 0x4b, 0x96, 0xa8, 0x0b, 0x85, 0x7a, + 0x0d, 0xbc, 0x09, 0x08, 0x0d, 0xa9, 0x87, 0x96, + 0x35, 0x0c, 0xcf, 0x0b, 0xa7, 0xb1, 0xd2, 0xca, + 0xea, 0x86, 0xba, 0x0a, 0xf3, 0xc9, 0xa2, 0x34, + 0x61, 0x6c, 0x5f, 0x1e, 0xb3, 0xb3, 0x68, 0x5d, + 0x53, 0x0e, 0x58, 0x5c, 0xf4, 0x21, 0x72, 0x8e, + 0x6b, 0x8e, 0x43, 0x7d, 0xf2, 0xd9, 0x78, 0x88, + 0x5c, 0xe5, 0x3e, 0xc5, 0x9f, 0x23, 0xcf, 0x0f, + 0x40, 0x54, 0x89, 0xbc, 0x38, 0xa8, 0xab, 0x32, + 0x57, 0xd9, 0x6a, 0x75, 0xd2, 0x8e, 0x32, 0x49, + 0xe2, 0xb9, 0x58, 0x9a, 0x79, 0x5a, 0x0f, 0xb6, + 0x62, 0x2e, 0xbd, 0x55, 0x39, 0x1b, 0x86, 0x7e, + 0x04, 0x51, 0x61, 0x42, 0x2b, 0x1b, 0xd0, 0x0a, + 0x9b, 0x67, 0x6b, 0x67, 0x84, 0x7b, 0xbf, 0x92, + 0xb7, 0x6f, 0x4f, 0xed, 0xbb, 0x48, 0x66, 0x27, + 0x74, 0x17, 0x69, 0xd5, 0xd0, 0xd7, 0x61, 0x4e, + 0xa5, 0x0f, 0x9b, 0x13, 0x07, 0x0e, 0xcc, 0x88, + 0x7d, 0x03, 0xeb, 0x40, 0xa0, 0x4d, 0xa6, 0x0b, + 0x75, 0x4b, 0x9b, 0xc0, 0xa5, 0xe3, 0xe1, 0x18, + 0x28, 0x98, 0xac, 0xd1, 0xdd, 0x02, 0xb3, 0x7a, + 0x3b, 0x7a, 0xe7, 0x2a, 0xd1, 0xb4, 0x2c, 0x4a, + 0x06, 0xf9, 0xaa, 0x86, 0x37, 0x61, 0x06, 0xe8, + 0xaf, 0xea, 0x39, 0x92, 0x2d, 0xac, 0x48, 0x1c, + 0xf1, 0x0c, 0x60, 0x84, 0xdf, 0x0e, 0xde, 0x75, + 0x24, 0xee, 0x6f, 0x87, 0xef, 0x3a, 0x9a, 0x51, + 0xe1, 0xa1, 0x3b, 0x1c, 0xa8, 0x53, 0xf7, 0x0f, + 0x81, 0xb3, 0x4f, 0x48, 0xdc, 0x1a, 0x0e, 0xba, + 0xff, 0xba, 0x9e, 0x9a, 0x86, 0x7b, 0xad, 0x9e, + 0x24, 0x4b, 0xb4, 0xe1, 0x37, 0xd7, 0xa9, 0xba, + 0xdc, 0x79, 0x4d, 0xee, 0xfb, 0xdb, 0x68, 0xa0, + 0xf6, 0x82, 0x1b, 0xde, 0x09, 0x0c, 0x73, 0x91, + 0x18, 0xde, 0x09, 0x90, 0x5c, 0xd0, 0xbd, 0x8d, + 0xd6, 0x5f, 0xcf, 0x02, 0x72, 0x8b, 0x27, 0x17, + 0x55, 0x54, 0x16, 0x99, 0x65, 0xa2, 0xf1, 0xa1, + 0xc7, 0x97, 0x90, 0xa5, 0x6e, 0x14, 0x54, 0x66, + 0x9c, 0x84, 0xa5, 0xbb, 0xe9, 0xc5, 0x37, 0x46, + 0x5e, 0xad, 0x45, 0xa9, 0xdf, 0xc4, 0xec, 0xc5, + 0xb1, 0x86, 0xd0, 0x54, 0xab, 0x5f, 0x0f, 0xbf, + 0x3c, 0x3b, 0xd6, 0x9d, 0x8a, 0xc6, 0x9c, 0x0d, + 0x52, 0xba, 0x2f, 0xfc, 0x1f, 0x5b, 0x5f, 0xf8, + 0xf6, 0xcf, 0x1d, 0x69, 0xa7, 0x50, 0x0f, 0x56, + 0x01, 0xe6, 0xef, 0x75, 0x1a, 0x9c, 0xd3, 0xdc, + 0xa1, 0x13, 0x2e, 0x2e, 0xeb, 0x54, 0xc4, 0x81, + 0x97, 0x76, 0x67, 0x61, 0x10, 0xa9, 0xd7, 0x0a, + 0x19, 0xdb, 0x0d, 0xf1, 0x8a, 0x6b, 0xda, 0xc7, + 0x7a, 0x48, 0x62, 0x78, 0x2c, 0x6b, 0xfd, 0x44, + 0xfd, 0xef, 0xc0, 0x58, 0xb6, 0x88, 0x56, 0x40, + 0x12, 0x2f, 0xe1, 0xed, 0x6c, 0xda, 0x19, 0x48, + 0x92, 0x67, 0xf2, 0xba, 0x49, 0x33, 0x65, 0xf1, + 0x0d, 0xb7, 0xee, 0x8b, 0xd1, 0x01, 0x5d, 0x5f, + 0x4b, 0x8e, 0x5b, 0xe2, 0x10, 0xbc, 0xd6, 0x74, + 0x58, 0xb2, 0xc9, 0x43, 0x6f, 0x0d, 0xde, 0x7d, + 0xce, 0x31, 0x6a, 0x13, 0xfb, 0xd6, 0x84, 0xa3, + 0x69, 0x9b, 0x79, 0xdc, 0xeb, 0xad, 0x28, 0x5c, + 0xa5, 0xc8, 0x1b, 0xca, 0xd4, 0x7e, 0x56, 0x1e, + 0x58, 0xc3, 0x02, 0xcb, 0x44, 0x4d, 0xd7, 0x75, + 0xd5, 0x84, 0xae, 0x9b, 0xf9, 0xfa, 0x22, 0xf6, + 0x75, 0x45, 0xe3, 0xca, 0x92, 0x8d, 0xd5, 0x75, + 0x79, 0xc6, 0x28, 0x67, 0x4e, 0x0b, 0x2f, 0xb6, + 0xba, 0x02, 0x5f, 0x65, 0x10, 0x61, 0xdb, 0x92, + 0x45, 0x47, 0xe0, 0x0d, 0x19, 0x16, 0x5e, 0xb8, + 0x19, 0xc5, 0xed, 0x95, 0x20, 0x1e, 0x3d, 0xc6, + 0xfc, 0x47, 0xa7, 0x9c, 0xe1, 0xc0, 0xe1, 0xdd, + 0x4f, 0x8a, 0xfd, 0x56, 0x6c, 0x7e, 0x86, 0x30, + 0xa1, 0xa3, 0x87, 0xf2, 0x5e, 0x6c, 0x05, 0x01, + 0xef, 0x9a, 0x85, 0xfa, 0xa6, 0x96, 0xe2, 0x94, + 0xaf, 0xa0, 0x35, 0xc4, 0x8e, 0xf2, 0xda, 0xd0, + 0x58, 0x76, 0xca, 0xbf, 0x4e, 0x9c, 0x54, 0x51, + 0xf6, 0x45, 0x35, 0x1f, 0x87, 0x55, 0x52, 0x87, + 0xb5, 0xe8, 0x76, 0x6d, 0x58, 0x8b, 0xaa, 0xec, + 0x0d, 0x8e, 0x65, 0xae, 0x20, 0x9f, 0xe8, 0xdb, + 0xeb, 0x02, 0x1c, 0x9b, 0x20, 0xe8, 0xd3, 0x06, + 0xa6, 0xa2, 0x38, 0x5e, 0xb4, 0x96, 0xaa, 0x23, + 0x19, 0xb4, 0x3f, 0x4e, 0x73, 0xa4, 0x37, 0x56, + 0xbb, 0x6c, 0x74, 0x3e, 0xd7, 0x47, 0x33, 0xfe, + 0xdb, 0xb7, 0xa5, 0x1a, 0x4d, 0x68, 0xb6, 0xe4, + 0x62, 0x44, 0x0f, 0xf9, 0xa1, 0xe5, 0xaa, 0x05, + 0x6e, 0xd6, 0x4b, 0x23, 0x77, 0x42, 0x3b, 0xbb, + 0x1a, 0x9c, 0x99, 0x64, 0x11, 0xc0, 0x6c, 0x30, + 0x8e, 0x7c, 0x8a, 0xe9, 0x97, 0x0a, 0x02, 0x2b, + 0xa3, 0x59, 0x40, 0x62, 0xe9, 0x5d, 0xb4, 0x68, + 0x2c, 0x68, 0x82, 0xc7, 0xec, 0x6f, 0x2e, 0x78, + 0x38, 0x1d, 0x9f, 0xd8, 0xdd, 0x17, 0xf2, 0xd0, + 0xdb, 0xa6, 0x27, 0x69, 0x12, 0x39, 0xf9, 0x64, + 0x31, 0x0a, 0x6f, 0x2e, 0x2d, 0xde, 0xe2, 0x0b, + 0x4e, 0x5b, 0xda, 0x97, 0x57, 0x1c, 0xaa, 0xd1, + 0x5e, 0x09, 0x9d, 0x2b, 0xf2, 0x46, 0xcb, 0xdf, + 0xe5, 0xbd, 0x43, 0x5b, 0x3d, 0x1e, 0xfa, 0xc2, + 0xb5, 0x61, 0x69, 0x2e, 0xe1, 0x03, 0x74, 0xa6, + 0xe4, 0x5a, 0x5c, 0x57, 0x37, 0x37, 0x5c, 0x7e, + 0xb9, 0xa2, 0xbb, 0x2d, 0x9d, 0xbd, 0x8b, 0xd3, + 0xef, 0x28, 0xbd, 0x13, 0x0d, 0xc2, 0xff, 0x8b, + 0x33, 0xd8, 0x09, 0x01, 0xdc, 0x1f, 0x5d, 0x84, + 0x42, 0x4f, 0x5e, 0xbe, 0x47, 0xcf, 0x36, 0x29, + 0xac, 0x65, 0x4a, 0xf6, 0x44, 0xe5, 0x14, 0x8e, + 0x76, 0xcc, 0xdb, 0x39, 0xd5, 0xb5, 0xb2, 0x64, + 0x9d, 0x4e, 0x8c, 0xba, 0xcb, 0x89, 0x3b, 0xfd, + 0x30, 0x46, 0x14, 0xa2, 0x4b, 0xf8, 0x8f, 0xb2, + 0x65, 0xe3, 0x33, 0x49, 0x3e, 0xe0, 0x8e, 0x39, + 0x1b, 0x18, 0x7d, 0x05, 0xdc, 0x8a, 0x08, 0x88, + 0x00, 0x8b, 0xe8, 0xd1, 0x22, 0xdd, 0x08, 0xe0, + 0xfb, 0xc3, 0x75, 0x4a, 0x86, 0x49, 0x29, 0x47, + 0x5a, 0x28, 0x16, 0xd5, 0xed, 0xec, 0x18, 0xcb, + 0xde, 0x12, 0x89, 0x10, 0xb4, 0x16, 0xbd, 0xda, + 0xfc, 0x1f, 0x10, 0x1c, 0xce, 0x40, 0x61, 0xef, + 0x28, 0x10, 0xed, 0x0e, 0xd6, 0x13, 0x56, 0x3d, + 0x7a, 0xc8, 0x59, 0xae, 0x27, 0xde, 0xed, 0x4c, + 0x0f, 0xca, 0xf4, 0x50, 0x7b, 0xf9, 0x1f, 0x46, + 0x51, 0xd3, 0x43, 0x19, 0x53, 0xde, 0xf0, 0x5a, + 0xc6, 0x54, 0xaa, 0x7c, 0x32, 0x63, 0x17, 0x37, + 0x78, 0x76, 0xb8, 0xd5, 0x1a, 0x5d, 0x16, 0x16, + 0x5e, 0x94, 0x34, 0x61, 0x6d, 0xca, 0x1b, 0xb0, + 0x36, 0x95, 0x2a, 0xb1, 0xb6, 0x8b, 0x1b, 0xb0, + 0x76, 0xab, 0x7d, 0x01, 0x6f, 0x6b, 0x68, 0x40, + 0x0d, 0x8f, 0x33, 0x4c, 0x79, 0x3d, 0xae, 0xa6, + 0x4e, 0x25, 0xba, 0x76, 0x71, 0x03, 0xc6, 0x6e, + 0xb5, 0xab, 0x91, 0xae, 0x7f, 0x52, 0xa5, 0x8b, + 0xaf, 0x40, 0xb9, 0xf6, 0x71, 0x95, 0x55, 0x7a, + 0x15, 0xc2, 0x05, 0x0f, 0xa2, 0x87, 0x67, 0x9e, + 0xba, 0x27, 0xa3, 0xe2, 0xb5, 0x8d, 0x9c, 0xd5, + 0x56, 0xc8, 0x6d, 0x6d, 0x69, 0x78, 0x3a, 0xbb, + 0x77, 0x80, 0xfb, 0xf2, 0xeb, 0xf0, 0x3a, 0x56, + 0x34, 0x8b, 0x1f, 0x92, 0x7c, 0xaa, 0xff, 0xac, + 0x7c, 0xdc, 0x63, 0x8a, 0x3b, 0x05, 0x5e, 0x59, + 0xf7, 0xcc, 0xc7, 0x05, 0x58, 0xc9, 0xf3, 0x1a, + 0xb0, 0xb3, 0xf8, 0x1e, 0xc1, 0xd5, 0x7f, 0x56, + 0x62, 0x67, 0x8a, 0x3b, 0x05, 0x9e, 0x58, 0x87, + 0x9d, 0x0b, 0xb0, 0x92, 0xb7, 0x7d, 0x26, 0x8f, + 0x82, 0x2c, 0x2e, 0xa6, 0x67, 0xaa, 0xfe, 0x75, + 0x89, 0x29, 0xee, 0x14, 0x38, 0x5c, 0x1d, 0x5e, + 0x2e, 0xc0, 0x4a, 0x56, 0x75, 0x15, 0x76, 0xda, + 0x5b, 0x4d, 0xff, 0x55, 0x8f, 0x9b, 0x7a, 0xc7, + 0x65, 0x31, 0xb2, 0x46, 0xcc, 0xb4, 0xd7, 0x5b, + 0x15, 0x4b, 0xfa, 0x4c, 0xed, 0xb6, 0x45, 0xb3, + 0xed, 0xce, 0x6e, 0xfb, 0x27, 0xb3, 0xdb, 0xbe, + 0x92, 0xb1, 0x5d, 0xf0, 0xac, 0x44, 0x91, 0x57, + 0x9a, 0x17, 0x4d, 0xc6, 0xd5, 0x25, 0xbe, 0x6d, + 0x8a, 0xbc, 0xcb, 0x64, 0x4d, 0xaf, 0x3b, 0xa6, + 0x89, 0x72, 0x5f, 0xe4, 0x7a, 0x19, 0x6c, 0xad, + 0xa0, 0x63, 0xa5, 0x1c, 0x9d, 0x2c, 0x28, 0xb7, + 0x68, 0xc6, 0x20, 0xb5, 0xe3, 0x90, 0xc6, 0x45, + 0xc5, 0x09, 0x48, 0x83, 0x88, 0xdf, 0x18, 0x81, + 0x64, 0xaf, 0x33, 0x21, 0x13, 0x34, 0xfb, 0x89, + 0x08, 0x25, 0x56, 0x0e, 0xd0, 0x81, 0x09, 0x9d, + 0x31, 0x64, 0x28, 0x1a, 0xf4, 0xc6, 0xe7, 0xd4, + 0xa7, 0xfe, 0xa5, 0x4e, 0xc0, 0x8a, 0x07, 0x94, + 0x7c, 0x0f, 0x63, 0x3b, 0xc6, 0xd3, 0x01, 0xda, + 0xab, 0x19, 0x2d, 0x86, 0x89, 0xa9, 0x1e, 0x30, + 0x45, 0x91, 0xd1, 0xc3, 0x8e, 0x0b, 0x18, 0x5e, + 0x67, 0xbc, 0x91, 0x97, 0xce, 0x0b, 0xc3, 0xc5, + 0x72, 0x49, 0x4a, 0xa0, 0xa9, 0xd0, 0xfb, 0x14, + 0xcb, 0x11, 0x73, 0xd9, 0xdb, 0x6e, 0xe0, 0x94, + 0x17, 0xfd, 0xea, 0x51, 0xff, 0x39, 0x4c, 0xee, + 0xdb, 0x98, 0xdb, 0x6f, 0xdf, 0xd4, 0xfe, 0x19, + 0x99, 0xd9, 0x99, 0xa5, 0x48, 0x1a, 0x25, 0x5a, + 0x7f, 0xac, 0x00, 0x75, 0xbd, 0x28, 0x9c, 0xc7, + 0x78, 0x56, 0x1c, 0x23, 0xf1, 0x3f, 0x26, 0xaf, + 0x3a, 0x58, 0x91, 0xf0, 0x03, 0x60, 0xeb, 0x45, + 0x5c, 0x1b, 0xf3, 0x99, 0x53, 0xb2, 0xe1, 0x84, + 0x5d, 0xec, 0xe8, 0xe5, 0x8a, 0xdd, 0xc1, 0x9b, + 0x04, 0xe4, 0xb0, 0x39, 0xea, 0xc7, 0xb8, 0x65, + 0x88, 0x56, 0xf9, 0xe4, 0x09, 0x63, 0xc3, 0x7d, + 0xe4, 0xf6, 0xa1, 0xed, 0x95, 0x7a, 0x1b, 0x0c, + 0x1b, 0xb2, 0xc0, 0x5d, 0x65, 0xf5, 0xa6, 0xdc, + 0x90, 0xb1, 0x17, 0x1b, 0xbe, 0x6c, 0x29, 0x41, + 0x89, 0x30, 0xe7, 0xe7, 0x93, 0xcb, 0xc0, 0xa3, + 0xb0, 0x4f, 0x80, 0x4d, 0x6d, 0x7f, 0xbd, 0xdd, + 0x15, 0xc2, 0xee, 0x0a, 0xe1, 0x8b, 0xbb, 0x42, + 0x30, 0x5c, 0xc5, 0x7d, 0x2d, 0xe6, 0x3c, 0x34, + 0xb3, 0x25, 0xca, 0xcf, 0xe2, 0xb2, 0x41, 0x3d, + 0xe2, 0xd5, 0xa6, 0xbe, 0xe9, 0x2d, 0xdc, 0x3e, + 0xc8, 0x6b, 0x0c, 0x52, 0x67, 0xd5, 0xe3, 0x30, + 0x7c, 0x17, 0x7b, 0x41, 0xa1, 0xb9, 0x4c, 0x3c, + 0x32, 0x56, 0x6d, 0x95, 0x1f, 0x9b, 0x35, 0xad, + 0x1d, 0xc1, 0xa1, 0xc0, 0x6a, 0xf1, 0xe2, 0x2b, + 0x0e, 0x15, 0xdf, 0xe8, 0xec, 0xbb, 0xef, 0xc7, + 0xaf, 0xff, 0x29, 0x8e, 0xac, 0xd0, 0x51, 0x2f, + 0xbf, 0xfb, 0xe1, 0xe5, 0xf8, 0x87, 0x17, 0x7f, + 0xff, 0xfb, 0x0b, 0x98, 0x8c, 0xe1, 0xe0, 0xb0, + 0x5f, 0x7e, 0xfb, 0x50, 0x65, 0x7c, 0x40, 0x55, + 0xe3, 0x64, 0x0b, 0x3b, 0xe3, 0x7d, 0x5b, 0x08, + 0xef, 0xd5, 0xb6, 0x77, 0x7f, 0xc6, 0xb9, 0x7b, + 0xb6, 0xab, 0xdd, 0x89, 0x51, 0xac, 0xf2, 0x7e, + 0xad, 0xda, 0x80, 0xe4, 0xbc, 0xb3, 0xa9, 0xb3, + 0x7c, 0xdd, 0x86, 0x51, 0xe8, 0x4a, 0x9b, 0xd0, + 0xcd, 0xac, 0x39, 0x57, 0x1b, 0x73, 0x6e, 0x64, + 0x86, 0xb9, 0xeb, 0xf7, 0x6b, 0x05, 0x3b, 0xca, + 0xcd, 0x2c, 0x20, 0x57, 0x19, 0x40, 0x6e, 0x66, + 0xbd, 0xe0, 0x33, 0x42, 0x2e, 0xb2, 0x36, 0x3a, + 0x54, 0x1d, 0x33, 0x72, 0xc9, 0x7b, 0x17, 0x45, + 0x23, 0x82, 0x55, 0x76, 0x59, 0x3a, 0x23, 0xcc, + 0x8c, 0xc9, 0x3a, 0x45, 0xef, 0xb1, 0x6b, 0x4b, + 0xc8, 0xca, 0xde, 0x6c, 0x3c, 0xd4, 0x6d, 0x8a, + 0x29, 0xca, 0x26, 0xfc, 0x12, 0xea, 0xd4, 0x66, + 0xc7, 0x7d, 0xd1, 0x32, 0x9d, 0xee, 0xb9, 0xbb, + 0x42, 0x1e, 0x0c, 0xf6, 0xd3, 0xc7, 0xf5, 0x6c, + 0x86, 0x9e, 0xd8, 0xa3, 0xc3, 0xa7, 0xf4, 0x60, + 0x9f, 0xe3, 0x8a, 0x00, 0x62, 0xf8, 0xb7, 0x2d, + 0x8c, 0x4b, 0xe6, 0x5d, 0xf2, 0xba, 0x87, 0xc6, + 0x36, 0xed, 0xa9, 0x32, 0x85, 0x58, 0xcb, 0x2c, + 0xd6, 0x1e, 0x1c, 0xf4, 0xc3, 0xe7, 0x00, 0x5b, + 0x1e, 0x27, 0x4f, 0x2c, 0xac, 0xdb, 0xdb, 0xa0, + 0x4d, 0x51, 0x8c, 0x24, 0xbe, 0x8c, 0xad, 0x45, + 0x5f, 0x7d, 0x4b, 0xae, 0xd0, 0x7d, 0x38, 0x52, + 0xa1, 0x35, 0x6a, 0xf9, 0x56, 0xad, 0xf2, 0xa2, + 0x19, 0xaf, 0x99, 0xd5, 0x7b, 0x81, 0xd2, 0x54, + 0x33, 0x3e, 0x53, 0x0a, 0xa5, 0x81, 0x03, 0xdc, + 0x13, 0xa5, 0xb7, 0x7d, 0x8e, 0xe8, 0x28, 0xaf, + 0xbf, 0xad, 0x57, 0x6e, 0x34, 0x80, 0xae, 0x03, + 0xad, 0xc3, 0xa3, 0x7a, 0x52, 0xf8, 0x78, 0x83, + 0xe7, 0x6c, 0x28, 0x5d, 0xb9, 0xa7, 0xf8, 0x2d, + 0x5c, 0x93, 0xff, 0x7f, 0xc9, 0x73, 0xe5, 0xd5 + }; + static std::string decompressed = util::decompress(std::string(reinterpret_cast<const char*>(compressed), sizeof(compressed))); + return decompressed.c_str(); +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/source.hpp b/src/mbgl/shaders/source.hpp new file mode 100644 index 0000000000..38a5ea6ece --- /dev/null +++ b/src/mbgl/shaders/source.hpp @@ -0,0 +1,11 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace shaders { + +const char* source(); + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index c037c81005..9e33b99def 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -1,149 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/symbol_icon.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* symbol_icon::name = "symbol_icon"; -const char* symbol_icon::vertexSource = R"MBGL_SHADER( -const float PI = 3.141592653589793; - -attribute vec4 a_pos_offset; -attribute vec4 a_data; -attribute vec3 a_projected_pos; -attribute float a_fade_opacity; - -uniform bool u_is_size_zoom_constant; -uniform bool u_is_size_feature_constant; -uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function -uniform highp float u_size; // used when size is both zoom and feature constant -uniform highp float u_camera_to_center_distance; -uniform highp float u_pitch; -uniform bool u_rotate_symbol; -uniform highp float u_aspect_ratio; -uniform float u_fade_change; - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -uniform mat4 u_matrix; -uniform mat4 u_label_plane_matrix; -uniform mat4 u_gl_coord_matrix; - -uniform bool u_is_text; -uniform bool u_pitch_with_map; - -uniform vec2 u_texsize; - -varying vec2 v_tex; -varying float v_fade_opacity; - -void main() { - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - - vec2 a_pos = a_pos_offset.xy; - vec2 a_offset = a_pos_offset.zw; - - vec2 a_tex = a_data.xy; - vec2 a_size = a_data.zw; - - highp float segment_angle = -a_projected_pos[2]; - - float size; - if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { - size = mix(a_size[0], a_size[1], u_size_t) / 10.0; - } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { - size = a_size[0] / 10.0; - } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { - size = u_size; - } else { - size = u_size; - } - - vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); - highp float camera_to_anchor_distance = projectedPoint.w; - // See comments in symbol_sdf.vertex - highp float distance_ratio = u_pitch_with_map ? - camera_to_anchor_distance / u_camera_to_center_distance : - u_camera_to_center_distance / camera_to_anchor_distance; - highp float perspective_ratio = clamp( - 0.5 + 0.5 * distance_ratio, - 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles - 4.0); - - size *= perspective_ratio; - - float fontScale = u_is_text ? size / 24.0 : size; - - highp float symbol_rotation = 0.0; - if (u_rotate_symbol) { - // See comments in symbol_sdf.vertex - vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); - - vec2 a = projectedPoint.xy / projectedPoint.w; - vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; - - symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); - } - - highp float angle_sin = sin(segment_angle + symbol_rotation); - highp float angle_cos = cos(segment_angle + symbol_rotation); - mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); - - vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); - gl_Position = u_gl_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); - - v_tex = a_tex / u_texsize; - vec2 fade_opacity = unpack_opacity(a_fade_opacity); - float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; - v_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); -} - -)MBGL_SHADER"; -const char* symbol_icon::fragmentSource = R"MBGL_SHADER( -uniform sampler2D u_texture; - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -varying vec2 v_tex; -varying float v_fade_opacity; - -void main() { - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - - lowp float alpha = opacity * v_fade_opacity; - gl_FragColor = texture2D(u_texture, v_tex) * alpha; - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* symbol_icon::vertexSource = source() + 59607; +const char* symbol_icon::fragmentSource = source() + 63011; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index b584c00315..3443b4f21c 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -1,304 +1,14 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/shaders/symbol_sdf.hpp> +#include <mbgl/shaders/source.hpp> namespace mbgl { namespace shaders { const char* symbol_sdf::name = "symbol_sdf"; -const char* symbol_sdf::vertexSource = R"MBGL_SHADER( -const float PI = 3.141592653589793; - -attribute vec4 a_pos_offset; -attribute vec4 a_data; -attribute vec3 a_projected_pos; -attribute float a_fade_opacity; - -// contents of a_size vary based on the type of property value -// used for {text,icon}-size. -// For constants, a_size is disabled. -// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. -// For composite functions: -// [ text-size(lowerZoomStop, feature), -// text-size(upperZoomStop, feature) ] -uniform bool u_is_size_zoom_constant; -uniform bool u_is_size_feature_constant; -uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function -uniform highp float u_size; // used when size is both zoom and feature constant - - -#ifndef HAS_UNIFORM_u_fill_color -uniform lowp float a_fill_color_t; -attribute highp vec4 a_fill_color; -varying highp vec4 fill_color; -#else -uniform highp vec4 u_fill_color; -#endif - - -#ifndef HAS_UNIFORM_u_halo_color -uniform lowp float a_halo_color_t; -attribute highp vec4 a_halo_color; -varying highp vec4 halo_color; -#else -uniform highp vec4 u_halo_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; -attribute lowp vec2 a_opacity; -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_halo_width -uniform lowp float a_halo_width_t; -attribute lowp vec2 a_halo_width; -varying lowp float halo_width; -#else -uniform lowp float u_halo_width; -#endif - - -#ifndef HAS_UNIFORM_u_halo_blur -uniform lowp float a_halo_blur_t; -attribute lowp vec2 a_halo_blur; -varying lowp float halo_blur; -#else -uniform lowp float u_halo_blur; -#endif - - -uniform mat4 u_matrix; -uniform mat4 u_label_plane_matrix; -uniform mat4 u_gl_coord_matrix; - -uniform bool u_is_text; -uniform bool u_pitch_with_map; -uniform highp float u_pitch; -uniform bool u_rotate_symbol; -uniform highp float u_aspect_ratio; -uniform highp float u_camera_to_center_distance; -uniform float u_fade_change; - -uniform vec2 u_texsize; - -varying vec2 v_data0; -varying vec3 v_data1; - -void main() { - -#ifndef HAS_UNIFORM_u_fill_color - fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t); -#else - highp vec4 fill_color = u_fill_color; -#endif - - -#ifndef HAS_UNIFORM_u_halo_color - halo_color = unpack_mix_vec4(a_halo_color, a_halo_color_t); -#else - highp vec4 halo_color = u_halo_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); -#else - lowp float opacity = u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_halo_width - halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t); -#else - lowp float halo_width = u_halo_width; -#endif - - -#ifndef HAS_UNIFORM_u_halo_blur - halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t); -#else - lowp float halo_blur = u_halo_blur; -#endif - - - vec2 a_pos = a_pos_offset.xy; - vec2 a_offset = a_pos_offset.zw; - - vec2 a_tex = a_data.xy; - vec2 a_size = a_data.zw; - - highp float segment_angle = -a_projected_pos[2]; - float size; - - if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { - size = mix(a_size[0], a_size[1], u_size_t) / 10.0; - } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { - size = a_size[0] / 10.0; - } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { - size = u_size; - } else { - size = u_size; - } - - vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); - highp float camera_to_anchor_distance = projectedPoint.w; - // If the label is pitched with the map, layout is done in pitched space, - // which makes labels in the distance smaller relative to viewport space. - // We counteract part of that effect by multiplying by the perspective ratio. - // If the label isn't pitched with the map, we do layout in viewport space, - // which makes labels in the distance larger relative to the features around - // them. We counteract part of that effect by dividing by the perspective ratio. - highp float distance_ratio = u_pitch_with_map ? - camera_to_anchor_distance / u_camera_to_center_distance : - u_camera_to_center_distance / camera_to_anchor_distance; - highp float perspective_ratio = clamp( - 0.5 + 0.5 * distance_ratio, - 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles - 4.0); - - size *= perspective_ratio; - - float fontScale = u_is_text ? size / 24.0 : size; - - highp float symbol_rotation = 0.0; - if (u_rotate_symbol) { - // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units - // To figure out that angle in projected space, we draw a short horizontal line in tile - // space, project it, and measure its angle in projected space. - vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); - - vec2 a = projectedPoint.xy / projectedPoint.w; - vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; - - symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); - } - - highp float angle_sin = sin(segment_angle + symbol_rotation); - highp float angle_cos = cos(segment_angle + symbol_rotation); - mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); - - vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); - gl_Position = u_gl_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); - float gamma_scale = gl_Position.w; - - vec2 tex = a_tex / u_texsize; - vec2 fade_opacity = unpack_opacity(a_fade_opacity); - float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; - float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); - - v_data0 = vec2(tex.x, tex.y); - v_data1 = vec3(gamma_scale, size, interpolated_fade_opacity); -} - -)MBGL_SHADER"; -const char* symbol_sdf::fragmentSource = R"MBGL_SHADER( -#define SDF_PX 8.0 -#define EDGE_GAMMA 0.105/DEVICE_PIXEL_RATIO - -uniform bool u_is_halo; - -#ifndef HAS_UNIFORM_u_fill_color -varying highp vec4 fill_color; -#else -uniform highp vec4 u_fill_color; -#endif - - -#ifndef HAS_UNIFORM_u_halo_color -varying highp vec4 halo_color; -#else -uniform highp vec4 u_halo_color; -#endif - - -#ifndef HAS_UNIFORM_u_opacity -varying lowp float opacity; -#else -uniform lowp float u_opacity; -#endif - - -#ifndef HAS_UNIFORM_u_halo_width -varying lowp float halo_width; -#else -uniform lowp float u_halo_width; -#endif - - -#ifndef HAS_UNIFORM_u_halo_blur -varying lowp float halo_blur; -#else -uniform lowp float u_halo_blur; -#endif - - -uniform sampler2D u_texture; -uniform highp float u_gamma_scale; -uniform bool u_is_text; - -varying vec2 v_data0; -varying vec3 v_data1; - -void main() { - -#ifdef HAS_UNIFORM_u_fill_color - highp vec4 fill_color = u_fill_color; -#endif - - -#ifdef HAS_UNIFORM_u_halo_color - highp vec4 halo_color = u_halo_color; -#endif - - -#ifdef HAS_UNIFORM_u_opacity - lowp float opacity = u_opacity; -#endif - - -#ifdef HAS_UNIFORM_u_halo_width - lowp float halo_width = u_halo_width; -#endif - - -#ifdef HAS_UNIFORM_u_halo_blur - lowp float halo_blur = u_halo_blur; -#endif - - - vec2 tex = v_data0.xy; - float gamma_scale = v_data1.x; - float size = v_data1.y; - float fade_opacity = v_data1[2]; - - float fontScale = u_is_text ? size / 24.0 : size; - - lowp vec4 color = fill_color; - highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); - lowp float buff = (256.0 - 64.0) / 256.0; - if (u_is_halo) { - color = halo_color; - gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); - buff = (6.0 - halo_width / fontScale) / SDF_PX; - } - - lowp float dist = texture2D(u_texture, tex).a; - highp float gamma_scaled = gamma * gamma_scale; - highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); - - gl_FragColor = color * (alpha * opacity * fade_opacity); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} - -)MBGL_SHADER"; +const char* symbol_sdf::vertexSource = source() + 63461; +const char* symbol_sdf::fragmentSource = source() + 69382; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/sprite/sprite_loader.cpp b/src/mbgl/sprite/sprite_loader.cpp index 93d6dfd9ae..df4fe6e8df 100644 --- a/src/mbgl/sprite/sprite_loader.cpp +++ b/src/mbgl/sprite/sprite_loader.cpp @@ -86,7 +86,7 @@ void SpriteLoader::emitSpriteLoadedIfComplete() { return; } - loader->worker.invoke(&SpriteLoaderWorker::parse, loader->image, loader->json); + loader->worker.self().invoke(&SpriteLoaderWorker::parse, loader->image, loader->json); } void SpriteLoader::onParsed(std::vector<std::unique_ptr<style::Image>>&& result) { diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp index 207dd2ee69..c51db44548 100644 --- a/src/mbgl/storage/resource.cpp +++ b/src/mbgl/storage/resource.cpp @@ -21,7 +21,7 @@ static std::string getQuadKey(int32_t x, int32_t y, int8_t z) { } static mapbox::geometry::point<double> getMercCoord(int32_t x, int32_t y, int8_t z) { - double resolution = (util::M2PI * util::EARTH_RADIUS_M / 256) / std::pow(2.0f, z); + double resolution = (util::M2PI * util::EARTH_RADIUS_M / 256) / std::pow(2, z); return { x * resolution - util::M2PI * util::EARTH_RADIUS_M / 2, y * resolution - util::M2PI * util::EARTH_RADIUS_M / 2, @@ -30,7 +30,7 @@ static mapbox::geometry::point<double> getMercCoord(int32_t x, int32_t y, int8_t static std::string getTileBBox(int32_t x, int32_t y, int8_t z) { // Alter the y for the Google/OSM tile scheme. - y = std::pow(2.0f, z) - y - 1; + y = std::pow(2, z) - y - 1; auto min = getMercCoord(x * 256, y * 256, z); auto max = getMercCoord((x + 1) * 256, (y + 1) * 256, z); @@ -79,13 +79,13 @@ Resource Resource::spriteJSON(const std::string& base, float pixelRatio) { Resource Resource::glyphs(const std::string& urlTemplate, const FontStack& fontStack, const std::pair<uint16_t, uint16_t>& glyphRange) { return Resource { Resource::Kind::Glyphs, - util::replaceTokens(urlTemplate, [&](const std::string& token) { + util::replaceTokens(urlTemplate, [&](const std::string& token) -> optional<std::string> { if (token == "fontstack") { return util::percentEncode(fontStackToString(fontStack)); } else if (token == "range") { return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second); } else { - return std::string(); + return {}; } }) }; @@ -104,7 +104,7 @@ Resource Resource::tile(const std::string& urlTemplate, } return Resource { Resource::Kind::Tile, - util::replaceTokens(urlTemplate, [&](const std::string& token) { + util::replaceTokens(urlTemplate, [&](const std::string& token) -> optional<std::string> { if (token == "z") { return util::toString(z); } else if (token == "x") { @@ -123,7 +123,7 @@ Resource Resource::tile(const std::string& urlTemplate, } else if (token == "ratio") { return std::string(pixelRatio > 1.0 ? "@2x" : ""); } else { - return std::string(); + return {}; } }), Resource::TileData { diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp index 3c941945fd..b690c96388 100644 --- a/src/mbgl/style/conversion/filter.cpp +++ b/src/mbgl/style/conversion/filter.cpp @@ -1,17 +1,43 @@ #include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/expression/literal.hpp> #include <mbgl/util/geometry.hpp> #include <mbgl/style/expression/expression.hpp> #include <mbgl/style/expression/type.hpp> -#include <mbgl/style/expression/parsing_context.hpp> +#include <mbgl/style/expression/compound_expression.hpp> +#include <mbgl/style/expression/boolean_operator.hpp> namespace mbgl { namespace style { namespace conversion { -using GeometryValue = mapbox::geometry::value; +using namespace mbgl::style::expression; + +static bool isExpression(const Convertible& filter); +ParseResult convertLegacyFilter(const Convertible& values, Error& error); +optional<mbgl::Value> serializeLegacyFilter(const Convertible& values); + +optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const { + if (isExpression(value)) { + ParsingContext parsingContext(type::Boolean); + ParseResult parseResult = parsingContext.parseExpression(value); + if (!parseResult) { + error = { parsingContext.getCombinedErrors() }; + return {}; + } else { + return { Filter(std::move(parseResult)) }; + } + } else { + ParseResult expression = convertLegacyFilter(value, error); + if (!expression) { + assert(error.message.size() > 0); + return {}; + } + return Filter(optional<std::unique_ptr<Expression>>(std::move(*expression)), serializeLegacyFilter(value)); + } +} // This is a port from https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/feature_filter/index.js -static bool isExpressionFilter(const Convertible& filter) { +bool isExpression(const Convertible& filter) { if (!isArray(filter) || arrayLength(filter) == 0) { return false; } @@ -20,7 +46,7 @@ static bool isExpressionFilter(const Convertible& filter) { if (!op) { return false; - + } else if (*op == "has") { if (arrayLength(filter) < 2) return false; optional<std::string> operand = toString(arrayMember(filter, 1)); @@ -30,12 +56,12 @@ static bool isExpressionFilter(const Convertible& filter) { return false; } else if (*op == "==" || *op == "!=" || *op == ">" || *op == ">=" || *op == "<" || *op == "<=") { - return arrayLength(filter) == 3 && (isArray(arrayMember(filter, 1)) || isArray(arrayMember(filter, 2))); + return arrayLength(filter) != 3 || isArray(arrayMember(filter, 1)) || isArray(arrayMember(filter, 2)); } else if (*op == "any" || *op == "all") { for (std::size_t i = 1; i < arrayLength(filter); i++) { Convertible f = arrayMember(filter, i); - if (!isExpressionFilter(f) && !toBool(f)) { + if (!isExpression(f) && !toBool(f)) { return false; } } @@ -46,257 +72,169 @@ static bool isExpressionFilter(const Convertible& filter) { } } -static optional<GeometryValue> normalizeValue(const optional<GeometryValue>& value, Error& error) { - if (!value) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; +ParseResult createExpression(std::string op, optional<std::vector<std::unique_ptr<Expression>>> args, Error& error) { + if (!args) return {}; + assert(std::all_of(args->begin(), args->end(), [](const std::unique_ptr<Expression> &e) { + return bool(e.get()); + })); + + if (op == "any") { + return {std::make_unique<Any>(std::move(*args))}; + } else if (op == "all") { + return {std::make_unique<All>(std::move(*args))}; } else { - return *value; + ParsingContext parsingContext(type::Boolean); + ParseResult parseResult = createCompoundExpression(op, std::move(*args), parsingContext); + if (!parseResult) { + error = { parsingContext.getCombinedErrors() }; + return {}; + } else { + return parseResult; + } } } -static optional<FeatureType> toFeatureType(const Convertible& value, Error& error) { - optional<std::string> type = toString(value); - if (!type) { - error = { "value for $type filter must be a string" }; - return {}; - } else if (*type == "Point") { - return FeatureType::Point; - } else if (*type == "LineString") { - return FeatureType::LineString; - } else if (*type == "Polygon") { - return FeatureType::Polygon; - } else { - error = { "value for $type filter must be Point, LineString, or Polygon" }; +ParseResult createExpression(std::string op, ParseResult arg, Error& error) { + if (!arg) { return {}; } + + std::vector<std::unique_ptr<Expression>> args; + args.push_back(std::move(*arg)); + return createExpression(op, std::move(args), error); } -static optional<FeatureIdentifier> toFeatureIdentifier(const Convertible& value, Error& error) { - optional<GeometryValue> identifier = toValue(value); - if (!identifier) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; +ParseResult convertLiteral(const Convertible& convertible, Error& error) { + ParsingContext parsingContext; + ParseResult parseResult = Literal::parse(convertible, parsingContext); + if (parseResult) { + return parseResult; } else { - return (*identifier).match( - [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( double t) -> optional<FeatureIdentifier> { return { t }; }, - [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; }, - [&] (const auto&) -> optional<FeatureIdentifier> { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - }); - } -} - -template <class FilterType, class IdentifierFilterType> -optional<Filter> convertUnaryFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 2) { - error = { "filter expression must have 2 elements" }; + error = { parsingContext.getCombinedErrors() }; return {}; } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$id") { - return { IdentifierFilterType {} }; - } else { - return { FilterType { *key } }; - } } -template <class FilterType, class TypeFilterType, class IdentifierFilterType> -optional<Filter> convertEqualityFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$type") { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error); - if (!filterValue) { +optional<std::vector<std::unique_ptr<Expression>>> convertLiteralArray(const Convertible &input, Error& error, std::size_t startIndex = 0) { + std::vector<std::unique_ptr<Expression>> output; + for (std::size_t i = startIndex; i < arrayLength(input); i++) { + ParseResult literal = convertLiteral(arrayMember(input, i), error); + if (!literal) { return {}; } - - return { TypeFilterType { *filterValue } }; - - } else if (*key == "$id") { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { IdentifierFilterType { *filterValue } }; - - } else { - optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { - return {}; - } - - return { FilterType { *key, *filterValue } }; + output.push_back(std::move(*literal)); } + return {std::move(output)}; } -template <class FilterType> -optional<Filter> convertBinaryFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { +ParseResult convertLegacyComparisonFilter(const Convertible& values, Error& error, optional<std::string> opOverride = {}) { + optional<std::string> op = opOverride ? opOverride : toString(arrayMember(values, 0)); + optional<std::string> property = toString(arrayMember(values, 1)); + + if (!property) { + error = { "filter property must be a string" }; return {}; + } else if (*property == "$type") { + return createExpression("filter-type-" + *op, convertLiteralArray(values, error, 2), error); + } else if (*property == "$id") { + return createExpression("filter-id-" + *op, convertLiteralArray(values, error, 2), error); + } else { + return createExpression("filter-" + *op, convertLiteralArray(values, error, 1), error); } - - return { FilterType { *key, *filterValue } }; } - -template <class FilterType, class TypeFilterType, class IdentifierFilterType> -optional<Filter> convertSetFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 2) { - error = { "filter expression must at least 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; + +ParseResult convertLegacyHasFilter(const Convertible& values, Error& error) { + optional<std::string> property = toString(arrayMember(values, 1)); + + if (!property) { + error = { "filter property must be a string" }; return {}; + } else if (*property == "$type") { + return {std::make_unique<Literal>(true)}; + } else if (*property == "$id") { + return createExpression("filter-has-id", std::vector<std::unique_ptr<Expression>>(), error); + } else { + return createExpression("filter-has", {std::make_unique<Literal>(*property)}, error); } +} - if (*key == "$type") { - std::vector<FeatureType> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { TypeFilterType { std::move(values) } }; - - } else if (*key == "$id") { - std::vector<FeatureIdentifier> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { IdentifierFilterType { std::move(values) } }; - +ParseResult convertLegacyInFilter(const Convertible& values, Error& error) { + optional<std::string> property = toString(arrayMember(values, 1)); + + if (!property) { + error = { "filter property must be a string" }; + return {}; + } else if (arrayLength(values) == 0) { + return {std::make_unique<Literal>(false)}; + } else if (*property == "$type") { + return createExpression("filter-type-in", convertLiteralArray(values, error, 2), error); + } else if (*property == "$id") { + return createExpression("filter-id-in", convertLiteralArray(values, error, 2), error); } else { - std::vector<GeometryValue> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { FilterType { *key, std::move(values) } }; + return createExpression("filter-in", convertLiteralArray(values, error, 1), error); } } -template <class FilterType> -optional<Filter> convertCompoundFilter(const Convertible& value, Error& error) { - std::vector<Filter> filters; - for (std::size_t i = 1; i < arrayLength(value); ++i) { - optional<Filter> element = convert<Filter>(arrayMember(value, i), error); - if (!element) { +optional<std::vector<std::unique_ptr<Expression>>> convertLegacyFilterArray(const Convertible &input, Error& error, std::size_t startIndex = 0) { + std::vector<std::unique_ptr<Expression>> output; + for (std::size_t i = startIndex; i < arrayLength(input); i++) { + optional<std::unique_ptr<Expression>> child = convertLegacyFilter(arrayMember(input, i), error); + if (!child) { return {}; } - filters.push_back(*element); + output.push_back(std::move(*child)); } - - return { FilterType { std::move(filters) } }; + return {std::move(output)}; } -optional<Filter> convertExpressionFilter(const Convertible& value, Error& error) { - expression::ParsingContext ctx(expression::type::Boolean); - expression::ParseResult expression = ctx.parseExpression(value); - if (!expression) { - error = { ctx.getCombinedErrors() }; - return {}; - } - - return { ExpressionFilter { std::move(*expression) } }; -} - -optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const { - if (isExpressionFilter(value)) { - return convertExpressionFilter(value, error); +ParseResult convertLegacyFilter(const Convertible& values, Error& error) { + if (isUndefined(values)) { + return {std::make_unique<Literal>(true)}; } - if (!isArray(value)) { - error = { "filter expression must be an array" }; - return {}; - } - - if (arrayLength(value) < 1) { - error = { "filter expression must have at least 1 element" }; - return {}; - } + optional<std::string> op = toString(arrayMember(values, 0)); - optional<std::string> op = toString(arrayMember(value, 0)); if (!op) { error = { "filter operator must be a string" }; return {}; + } else if (arrayLength(values) <= 1) { + return {std::make_unique<Literal>(*op != "any")}; + } else { + return { + *op == "==" || + *op == "<" || + *op == ">" || + *op == "<=" || + *op == ">=" ? convertLegacyComparisonFilter(values, error) : + *op == "!=" ? createExpression("!", convertLegacyComparisonFilter(values, error, {"=="}), error) : + *op == "any" ? createExpression("any", convertLegacyFilterArray(values, error, 1), error) : + *op == "all" ? createExpression("all", convertLegacyFilterArray(values, error, 1), error) : + *op == "none" ? createExpression("!", createExpression("any", convertLegacyFilterArray(values, error, 1), error), error) : + *op == "in" ? convertLegacyInFilter(values, error) : + *op == "!in" ? createExpression("!", convertLegacyInFilter(values, error), error) : + *op == "has" ? convertLegacyHasFilter(values, error) : + *op == "!has" ? createExpression("!", convertLegacyHasFilter(values, error), error) : + ParseResult(std::make_unique<Literal>(true)) + }; } +} - if (*op == "==") { - return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); - } else if (*op == "!=") { - return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); - } else if (*op == ">") { - return convertBinaryFilter<GreaterThanFilter>(value, error); - } else if (*op == ">=") { - return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); - } else if (*op == "<") { - return convertBinaryFilter<LessThanFilter>(value, error); - } else if (*op == "<=") { - return convertBinaryFilter<LessThanEqualsFilter>(value, error); - } else if (*op == "in") { - return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); - } else if (*op == "!in") { - return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); - } else if (*op == "all") { - return convertCompoundFilter<AllFilter>(value, error); - } else if (*op == "any") { - return convertCompoundFilter<AnyFilter>(value, error); - } else if (*op == "none") { - return convertCompoundFilter<NoneFilter>(value, error); - } else if (*op == "has") { - return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); - } else if (*op == "!has") { - return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); +optional<mbgl::Value> serializeLegacyFilter(const Convertible& values) { + if (isUndefined(values)) { + return {}; + } else if (isArray(values)) { + std::vector<mbgl::Value> result; + for (std::size_t i = 0; i < arrayLength(values); i++) { + auto arrayValue = serializeLegacyFilter(arrayMember(values, i)); + if (arrayValue) { + result.push_back(*arrayValue); + } else { + result.push_back(NullValue()); + } + } + return (mbgl::Value)result; } - - error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; - return {}; + return toValue(values); } } // namespace conversion diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp new file mode 100644 index 0000000000..61b45fcbe5 --- /dev/null +++ b/src/mbgl/style/conversion/function.cpp @@ -0,0 +1,724 @@ +#include <mbgl/style/conversion/function.hpp> +#include <mbgl/style/expression/dsl.hpp> +#include <mbgl/style/expression/step.hpp> +#include <mbgl/style/expression/interpolate.hpp> +#include <mbgl/style/expression/match.hpp> +#include <mbgl/style/expression/case.hpp> +#include <mbgl/style/expression/array_assertion.hpp> +#include <mbgl/util/string.hpp> + +#include <cassert> + +namespace mbgl { +namespace style { +namespace conversion { + +using namespace expression; +using namespace expression::dsl; + +const static std::string tokenReservedChars = "{}"; + +bool hasTokens(const std::string& source) { + auto pos = source.begin(); + const auto end = source.end(); + + while (pos != end) { + auto brace = std::find(pos, end, '{'); + if (brace == end) + return false; + for (brace++; brace != end && tokenReservedChars.find(*brace) == std::string::npos; brace++); + if (brace != end && *brace == '}') { + return true; + } + pos = brace; + } + + return false; +} + +std::unique_ptr<Expression> convertTokenStringToExpression(const std::string& source) { + std::vector<std::unique_ptr<Expression>> inputs; + + auto pos = source.begin(); + const auto end = source.end(); + + while (pos != end) { + auto brace = std::find(pos, end, '{'); + if (pos != brace) { + inputs.push_back(literal(std::string(pos, brace))); + } + pos = brace; + if (pos != end) { + for (brace++; brace != end && tokenReservedChars.find(*brace) == std::string::npos; brace++); + if (brace != end && *brace == '}') { + inputs.push_back(toString(get(literal(std::string(pos + 1, brace))))); + pos = brace + 1; + } else { + inputs.push_back(literal(std::string(pos, brace))); + pos = brace; + } + } + } + + switch (inputs.size()) { + case 0: + return literal(source); + case 1: + return std::move(inputs[0]); + default: + return concat(std::move(inputs)); + } +} + +// Ad-hoc Converters for double and int64_t. We should replace float with double wholesale, +// and promote the int64_t Converter to general use (and it should check that the input is +// an integer). +template <> +struct Converter<double> { + optional<double> operator()(const Convertible& value, Error& error) const { + auto converted = convert<float>(value, error); + if (!converted) { + return {}; + } + return *converted; + } +}; + +template <> +struct Converter<int64_t> { + optional<int64_t> operator()(const Convertible& value, Error& error) const { + auto converted = convert<float>(value, error); + if (!converted) { + return {}; + } + return *converted; + } +}; + +enum class FunctionType { + Interval, + Exponential, + Categorical, + Identity, + Invalid +}; + +static bool interpolatable(type::Type type) { + return type.match( + [&] (const type::NumberType&) { + return true; + }, + [&] (const type::ColorType&) { + return true; + }, + [&] (const type::Array& array) { + return array.N && array.itemType == type::Number; + }, + [&] (const auto&) { + return false; + } + ); +} + +static optional<std::unique_ptr<Expression>> convertLiteral(type::Type type, const Convertible& value, Error& error, bool convertTokens = false) { + return type.match( + [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> { + auto result = convert<float>(value, error); + if (!result) { + return {}; + } + return literal(double(*result)); + }, + [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> { + auto result = convert<bool>(value, error); + if (!result) { + return {}; + } + return literal(*result); + }, + [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> { + auto result = convert<std::string>(value, error); + if (!result) { + return {}; + } + return convertTokens ? convertTokenStringToExpression(*result) : literal(*result); + }, + [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> { + auto result = convert<Color>(value, error); + if (!result) { + return {}; + } + return literal(*result); + }, + [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> { + if (!isArray(value)) { + error = { "value must be an array" }; + return {}; + } + if (array.N && arrayLength(value) != *array.N) { + error = { "value must be an array of length " + util::toString(*array.N) }; + return {}; + } + return array.itemType.match( + [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> { + std::vector<expression::Value> result; + result.reserve(arrayLength(value)); + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<float> number = toNumber(arrayMember(value, i)); + if (!number) { + error = { "value must be an array of numbers" }; + return {}; + } + result.push_back(double(*number)); + } + return literal(result); + }, + [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> { + std::vector<expression::Value> result; + result.reserve(arrayLength(value)); + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<std::string> string = toString(arrayMember(value, i)); + if (!string) { + error = { "value must be an array of strings" }; + return {}; + } + result.push_back(*string); + } + return literal(result); + }, + [&] (const auto&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + } + ); + }, + [&] (const type::NullType&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::ObjectType&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::ErrorType&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::ValueType&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::CollatorType&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + } + ); +} + +static optional<std::map<double, std::unique_ptr<Expression>>> convertStops(type::Type type, + const Convertible& value, + Error& error, + bool convertTokens) { + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + error = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + error = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + error = { "function must have at least one stop" }; + return {}; + } + + std::map<double, std::unique_ptr<Expression>> stops; + for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { + const auto& stopValue = arrayMember(*stopsValue, i); + + if (!isArray(stopValue)) { + error = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(stopValue) != 2) { + error = { "function stop must have two elements" }; + return {}; + } + + optional<float> t = convert<float>(arrayMember(stopValue, 0), error); + if (!t) { + return {}; + } + + optional<std::unique_ptr<Expression>> e = convertLiteral(type, arrayMember(stopValue, 1), error, convertTokens); + if (!e) { + return {}; + } + + stops.emplace(*t, std::move(*e)); + } + + return { std::move(stops) }; +} + +template <class T> +optional<std::map<T, std::unique_ptr<Expression>>> convertBranches(type::Type type, + const Convertible& value, + Error& error) { + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + error = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + error = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + error = { "function must have at least one stop" }; + return {}; + } + + std::map<T, std::unique_ptr<Expression>> stops; + for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { + const auto& stopValue = arrayMember(*stopsValue, i); + + if (!isArray(stopValue)) { + error = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(stopValue) != 2) { + error = { "function stop must have two elements" }; + return {}; + } + + optional<T> t = convert<T>(arrayMember(stopValue, 0), error); + if (!t) { + return {}; + } + + optional<std::unique_ptr<Expression>> e = convertLiteral(type, arrayMember(stopValue, 1), error); + if (!e) { + return {}; + } + + stops.emplace(*t, std::move(*e)); + } + + return { std::move(stops) }; +} + +static optional<double> convertBase(const Convertible& value, Error& error) { + auto baseValue = objectMember(value, "base"); + + if (!baseValue) { + return 1.0; + } + + auto base = toNumber(*baseValue); + if (!base) { + error = { "function base must be a number" }; + return {}; + } + + return *base; +} + +static std::unique_ptr<Expression> step(type::Type type, std::unique_ptr<Expression> input, std::map<double, std::unique_ptr<Expression>> stops) { + return std::make_unique<Step>(type, std::move(input), std::move(stops)); +} + +static std::unique_ptr<Expression> interpolate(type::Type type, Interpolator interpolator, std::unique_ptr<Expression> input, std::map<double, std::unique_ptr<Expression>> stops) { + ParsingContext ctx; + auto result = createInterpolate(type, std::move(interpolator), std::move(input), std::move(stops), ctx); + if (!result) { + assert(false); + return {}; + } + return std::move(*result); +} + +template <class T> +std::unique_ptr<Expression> categorical(type::Type type, const std::string& property, std::map<T, std::unique_ptr<Expression>> branches) { + std::unordered_map<T, std::shared_ptr<Expression>> convertedBranches; + for (auto& b : branches) { + convertedBranches[b.first] = std::move(b.second); + } + return std::make_unique<Match<T>>(type, get(literal(property)), std::move(convertedBranches), error("replaced with default")); +} + +template <> +std::unique_ptr<Expression> categorical<bool>(type::Type type, const std::string& property, std::map<bool, std::unique_ptr<Expression>> branches) { + auto it = branches.find(true); + std::unique_ptr<Expression> trueCase = it == branches.end() ? + error("replaced with default") : + std::move(it->second); + + it = branches.find(false); + std::unique_ptr<Expression> falseCase = it == branches.end() ? + error("replaced with default") : + std::move(it->second); + + std::vector<typename Case::Branch> trueBranch; + trueBranch.emplace_back(get(literal(property)), std::move(trueCase)); + + return std::make_unique<Case>(type, std::move(trueBranch), std::move(falseCase)); +} + +static optional<std::unique_ptr<Expression>> convertIntervalFunction(type::Type type, + const Convertible& value, + Error& error, + std::unique_ptr<Expression> input, + bool convertTokens = false) { + auto stops = convertStops(type, value, error, convertTokens); + if (!stops) { + return {}; + } + return step(type, std::move(input), std::move(*stops)); +} + +static optional<std::unique_ptr<Expression>> convertExponentialFunction(type::Type type, + const Convertible& value, + Error& error, + std::unique_ptr<Expression> input, + bool convertTokens = false) { + auto stops = convertStops(type, value, error, convertTokens); + if (!stops) { + return {}; + } + auto base = convertBase(value, error); + if (!base) { + return {}; + } + return interpolate(type, exponential(*base), std::move(input), std::move(*stops)); +} + +static optional<std::unique_ptr<Expression>> convertCategoricalFunction(type::Type type, + const Convertible& value, + Error& err, + const std::string& property) { + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + err = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + err = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + err = { "function must have at least one stop" }; + return {}; + } + + const auto& first = arrayMember(*stopsValue, 0); + + if (!isArray(first)) { + err = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(first) != 2) { + err = { "function stop must have two elements" }; + return {}; + } + + if (toBool(arrayMember(first, 0))) { + auto branches = convertBranches<bool>(type, value, err); + if (!branches) { + return {}; + } + return categorical(type, property, std::move(*branches)); + } + + if (toNumber(arrayMember(first, 0))) { + auto branches = convertBranches<int64_t>(type, value, err); + if (!branches) { + return {}; + } + return categorical(type, property, std::move(*branches)); + } + + if (toString(arrayMember(first, 0))) { + auto branches = convertBranches<std::string>(type, value, err); + if (!branches) { + return {}; + } + return categorical(type, property, std::move(*branches)); + } + + err = { "stop domain value must be a number, string, or boolean" }; + return {}; +} + +template <class T, class Fn> +optional<std::unique_ptr<Expression>> composite(type::Type type, + const Convertible& value, + Error& error, + const Fn& makeInnerExpression) { + auto base = convertBase(value, error); + if (!base) { + return {}; + } + + auto stopsValue = objectMember(value, "stops"); + + // Checked by caller. + assert(stopsValue); + assert(isArray(*stopsValue)); + + std::map<float, std::map<T, std::unique_ptr<Expression>>> map; + + for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { + const auto& stopValue = arrayMember(*stopsValue, i); + + if (!isArray(stopValue)) { + error = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(stopValue) != 2) { + error = { "function stop must have two elements" }; + return {}; + } + + const auto& stopInput = arrayMember(stopValue, 0); + + if (!isObject(stopInput)) { + error = { "stop input must be an object" }; + return {}; + } + + auto zoomValue = objectMember(stopInput, "zoom"); + if (!zoomValue) { + error = { "stop input must specify zoom" }; + return {}; + } + + auto sourceValue = objectMember(stopInput, "value"); + if (!sourceValue) { + error = { "stop input must specify value" }; + return {}; + } + + optional<float> z = convert<float>(*zoomValue, error); + if (!z) { + return {}; + } + + optional<T> d = convert<T>(*sourceValue, error); + if (!d) { + return {}; + } + + optional<std::unique_ptr<Expression>> r = convertLiteral(type, arrayMember(stopValue, 1), error); + if (!r) { + return {}; + } + + map[*z].emplace(*d, std::move(*r)); + } + + std::map<double, std::unique_ptr<Expression>> stops; + + for (auto& e : map) { + stops.emplace(e.first, makeInnerExpression(type, *base, std::move(e.second))); + } + + if (interpolatable(type)) { + return interpolate(type, linear(), zoom(), std::move(stops)); + } else { + return step(type, zoom(), std::move(stops)); + } +} + +optional<std::unique_ptr<Expression>> convertFunctionToExpression(type::Type type, + const Convertible& value, + Error& err, + bool convertTokens) { + if (!isObject(value)) { + err = { "function must be an object" }; + return {}; + } + + FunctionType functionType = FunctionType::Invalid; + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + functionType = interpolatable(type) ? FunctionType::Exponential : FunctionType::Interval; + } else { + optional<std::string> string = toString(*typeValue); + if (string) { + if (*string == "interval") + functionType = FunctionType::Interval; + if (*string == "exponential" && interpolatable(type)) + functionType = FunctionType::Exponential; + if (*string == "categorical") + functionType = FunctionType::Categorical; + if (*string == "identity") + functionType = FunctionType::Identity; + } + } + + if (!objectMember(value, "property")) { + // Camera function. + switch (functionType) { + case FunctionType::Interval: + return convertIntervalFunction(type, value, err, zoom(), convertTokens); + case FunctionType::Exponential: + return convertExponentialFunction(type, value, err, zoom(), convertTokens); + default: + err = { "unsupported function type" }; + return {}; + } + } + + auto propertyValue = objectMember(value, "property"); + if (!propertyValue) { + err = { "function must specify property" }; + return {}; + } + + auto property = toString(*propertyValue); + if (!property) { + err = { "function property must be a string" }; + return {}; + } + + if (functionType == FunctionType::Identity) { + return type.match( + [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> { + return string(get(literal(*property))); + }, + [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> { + return number(get(literal(*property))); + }, + [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> { + return boolean(get(literal(*property))); + }, + [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> { + return toColor(get(literal(*property))); + }, + [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> { + return std::unique_ptr<Expression>( + std::make_unique<ArrayAssertion>(array, get(literal(*property)))); + }, + [&] (const auto&) -> optional<std::unique_ptr<Expression>> { + assert(false); // No properties use this type. + return {}; + } + ); + } + + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + err = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + err = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + err = { "function must have at least one stop" }; + return {}; + } + + const auto& first = arrayMember(*stopsValue, 0); + + if (!isArray(first)) { + err = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(first) != 2) { + err = { "function stop must have two elements" }; + return {}; + } + + const auto& stop = arrayMember(first, 0); + + if (!isObject(stop)) { + // Source function. + switch (functionType) { + case FunctionType::Interval: + return convertIntervalFunction(type, value, err, number(get(literal(*property)))); + case FunctionType::Exponential: + return convertExponentialFunction(type, value, err, number(get(literal(*property)))); + case FunctionType::Categorical: + return convertCategoricalFunction(type, value, err, *property); + default: + err = { "unsupported function type" }; + return {}; + } + } else { + // Composite function. + auto sourceValue = objectMember(stop, "value"); + if (!sourceValue) { + err = { "stop must specify value" }; + return {}; + } + + if (toBool(*sourceValue)) { + switch (functionType) { + case FunctionType::Categorical: + return composite<bool>(type, value, err, [&] (type::Type type_, double, std::map<bool, std::unique_ptr<Expression>> stops) { + return categorical<bool>(type_, *property, std::move(stops)); + }); + default: + err = { "unsupported function type" }; + return {}; + } + } + + if (toNumber(*sourceValue)) { + switch (functionType) { + case FunctionType::Interval: + return composite<double>(type, value, err, [&] (type::Type type_, double, std::map<double, std::unique_ptr<Expression>> stops) { + return step(type_, number(get(literal(*property))), std::move(stops)); + }); + case FunctionType::Exponential: + return composite<double>(type, value, err, [&] (type::Type type_, double base, std::map<double, std::unique_ptr<Expression>> stops) { + return interpolate(type_, exponential(base), number(get(literal(*property))), std::move(stops)); + }); + case FunctionType::Categorical: + return composite<int64_t>(type, value, err, [&] (type::Type type_, double, std::map<int64_t, std::unique_ptr<Expression>> stops) { + return categorical<int64_t>(type_, *property, std::move(stops)); + }); + default: + err = { "unsupported function type" }; + return {}; + } + } + + if (toString(*sourceValue)) { + switch (functionType) { + case FunctionType::Categorical: + return composite<std::string>(type, value, err, [&] (type::Type type_, double, std::map<std::string, std::unique_ptr<Expression>> stops) { + return categorical<std::string>(type_, *property, std::move(stops)); + }); + default: + err = { "unsupported function type" }; + return {}; + } + } + + err = { "stop domain value must be a number, string, or boolean" }; + return {}; + } +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/light.cpp b/src/mbgl/style/conversion/light.cpp index f521f74386..57b61eb340 100644 --- a/src/mbgl/style/conversion/light.cpp +++ b/src/mbgl/style/conversion/light.cpp @@ -18,7 +18,7 @@ optional<Light> Converter<Light>::operator()(const Convertible& value, Error& er const auto anchor = objectMember(value, "anchor"); if (anchor) { optional<PropertyValue<LightAnchorType>> convertedAnchor = - convert<PropertyValue<LightAnchorType>>(*anchor, error); + convert<PropertyValue<LightAnchorType>>(*anchor, error, false); if (convertedAnchor) { light.setAnchor(*convertedAnchor); @@ -41,7 +41,7 @@ optional<Light> Converter<Light>::operator()(const Convertible& value, Error& er const auto color = objectMember(value, "color"); if (color) { optional<PropertyValue<Color>> convertedColor = - convert<PropertyValue<Color>>(*color, error); + convert<PropertyValue<Color>>(*color, error, false); if (convertedColor) { light.setColor(*convertedColor); @@ -64,7 +64,7 @@ optional<Light> Converter<Light>::operator()(const Convertible& value, Error& er const auto position = objectMember(value, "position"); if (position) { optional<PropertyValue<Position>> convertedPosition = - convert<PropertyValue<Position>>(*position, error); + convert<PropertyValue<Position>>(*position, error, false); if (convertedPosition) { light.setPosition(*convertedPosition); @@ -87,7 +87,7 @@ optional<Light> Converter<Light>::operator()(const Convertible& value, Error& er const auto intensity = objectMember(value, "intensity"); if (intensity) { optional<PropertyValue<float>> convertedIntensity = - convert<PropertyValue<float>>(*intensity, error); + convert<PropertyValue<float>>(*intensity, error, false); if (convertedIntensity) { light.setIntensity(*convertedIntensity); diff --git a/src/mbgl/style/conversion/make_property_setters.hpp b/src/mbgl/style/conversion/make_property_setters.hpp index 25c8fdb1ca..64826106f0 100644 --- a/src/mbgl/style/conversion/make_property_setters.hpp +++ b/src/mbgl/style/conversion/make_property_setters.hpp @@ -41,7 +41,7 @@ inline auto makeLayoutPropertySetters() { result["icon-size"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconSize>; result["icon-text-fit"] = &setProperty<SymbolLayer, PropertyValue<IconTextFitType>, &SymbolLayer::setIconTextFit>; result["icon-text-fit-padding"] = &setProperty<SymbolLayer, PropertyValue<std::array<float, 4>>, &SymbolLayer::setIconTextFitPadding>; - result["icon-image"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setIconImage>; + result["icon-image"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setIconImage, true>; result["icon-rotate"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconRotate>; result["icon-padding"] = &setProperty<SymbolLayer, PropertyValue<float>, &SymbolLayer::setIconPadding>; result["icon-keep-upright"] = &setProperty<SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconKeepUpright>; @@ -50,7 +50,7 @@ inline auto makeLayoutPropertySetters() { result["icon-pitch-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconPitchAlignment>; result["text-pitch-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextPitchAlignment>; result["text-rotation-alignment"] = &setProperty<SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextRotationAlignment>; - result["text-field"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setTextField>; + result["text-field"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setTextField, true>; result["text-font"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<std::vector<std::string>>, &SymbolLayer::setTextFont>; result["text-size"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextSize>; result["text-max-width"] = &setProperty<SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextMaxWidth>; @@ -174,7 +174,7 @@ inline auto makePaintPropertySetters() { result["heatmap-weight-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapWeightTransition>; result["heatmap-intensity"] = &setProperty<HeatmapLayer, PropertyValue<float>, &HeatmapLayer::setHeatmapIntensity>; result["heatmap-intensity-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapIntensityTransition>; - result["heatmap-color"] = &setProperty<HeatmapLayer, HeatmapColorPropertyValue, &HeatmapLayer::setHeatmapColor>; + result["heatmap-color"] = &setProperty<HeatmapLayer, ColorRampPropertyValue, &HeatmapLayer::setHeatmapColor>; result["heatmap-color-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapColorTransition>; result["heatmap-opacity"] = &setProperty<HeatmapLayer, PropertyValue<float>, &HeatmapLayer::setHeatmapOpacity>; result["heatmap-opacity-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapOpacityTransition>; @@ -206,6 +206,8 @@ inline auto makePaintPropertySetters() { result["raster-saturation-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterSaturationTransition>; result["raster-contrast"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterContrast>; result["raster-contrast-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterContrastTransition>; + result["raster-resampling"] = &setProperty<RasterLayer, PropertyValue<RasterResamplingType>, &RasterLayer::setRasterResampling>; + result["raster-resampling-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterResamplingTransition>; result["raster-fade-duration"] = &setProperty<RasterLayer, PropertyValue<float>, &RasterLayer::setRasterFadeDuration>; result["raster-fade-duration-transition"] = &setTransition<RasterLayer, &RasterLayer::setRasterFadeDurationTransition>; diff --git a/src/mbgl/style/conversion/make_property_setters.hpp.ejs b/src/mbgl/style/conversion/make_property_setters.hpp.ejs new file mode 100644 index 0000000000..2b8925817d --- /dev/null +++ b/src/mbgl/style/conversion/make_property_setters.hpp.ejs @@ -0,0 +1,46 @@ +#pragma once + +// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. + +#include <mbgl/style/conversion/property_setter.hpp> + +<% for (const layer of locals.layers) { -%> +#include <mbgl/style/layers/<%- layer.type.replace('-', '_') %>_layer.hpp> +<% } -%> + +#include <unordered_map> + +namespace mbgl { +namespace style { +namespace conversion { + +inline auto makeLayoutPropertySetters() { + std::unordered_map<std::string, PropertySetter> result; + + result["visibility"] = &setVisibility; + +<% for (const layer of locals.layers) { -%> +<% for (const property of layer.layoutProperties) { -%> + result["<%- property.name %>"] = &setProperty<<%- camelize(layer.type) %>Layer, <%- propertyValueType(property) %>, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %><%- property.name === 'icon-image' || property.name === 'text-field' ? ', true' : '' %>>; +<% } -%> + +<% } -%> + return result; +} + +inline auto makePaintPropertySetters() { + std::unordered_map<std::string, PropertySetter> result; + +<% for (const layer of locals.layers) { -%> +<% for (const property of layer.paintProperties) { -%> + result["<%- property.name %>"] = &setProperty<<%- camelize(layer.type) %>Layer, <%- propertyValueType(property) %>, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>>; + result["<%- property.name %>-transition"] = &setTransition<<%- camelize(layer.type) %>Layer, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>Transition>; +<% } -%> + +<% } -%> + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/property_setter.hpp b/src/mbgl/style/conversion/property_setter.hpp index e3716a18dc..8791e36e1f 100644 --- a/src/mbgl/style/conversion/property_setter.hpp +++ b/src/mbgl/style/conversion/property_setter.hpp @@ -1,11 +1,12 @@ #pragma once #include <mbgl/style/layer.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/color_ramp_property_value.hpp> #include <mbgl/style/conversion/constant.hpp> #include <mbgl/style/conversion/property_value.hpp> #include <mbgl/style/conversion/data_driven_property_value.hpp> -#include <mbgl/style/conversion/heatmap_color_property_value.hpp> #include <mbgl/style/conversion/transition_options.hpp> #include <string> @@ -16,7 +17,7 @@ namespace conversion { using PropertySetter = optional<Error> (*) (Layer&, const Convertible&); -template <class L, class PropertyValue, void (L::*setter)(PropertyValue)> +template <class L, class PropertyValue, void (L::*setter)(PropertyValue), bool convertTokens = false> optional<Error> setProperty(Layer& layer, const Convertible& value) { auto* typedLayer = layer.as<L>(); if (!typedLayer) { @@ -24,7 +25,7 @@ optional<Error> setProperty(Layer& layer, const Convertible& value) { } Error error; - optional<PropertyValue> typedValue = convert<PropertyValue>(value, error); + optional<PropertyValue> typedValue = convert<PropertyValue>(value, error, convertTokens); if (!typedValue) { return error; } diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index 7b7727d7c4..77a39c51f9 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -126,162 +126,9 @@ void stringify(Writer& writer, const FeatureIdentifier& id) { } template <class Writer> -class StringifyFilter { -public: - Writer& writer; - - void operator()(const NullFilter&) { - writer.Null(); - } - - void operator()(const EqualsFilter& f) { - stringifyBinaryFilter(f, "=="); - } - - void operator()(const NotEqualsFilter& f) { - stringifyBinaryFilter(f, "!="); - } - - void operator()(const LessThanFilter& f) { - stringifyBinaryFilter(f, "<"); - } - - void operator()(const LessThanEqualsFilter& f) { - stringifyBinaryFilter(f, "<="); - } - - void operator()(const GreaterThanFilter& f) { - stringifyBinaryFilter(f, ">"); - } - - void operator()(const GreaterThanEqualsFilter& f) { - stringifyBinaryFilter(f, ">="); - } - - void operator()(const InFilter& f) { - stringifySetFilter(f, "in"); - } - - void operator()(const NotInFilter& f) { - stringifySetFilter(f, "!in"); - } - - void operator()(const AllFilter& f) { - stringifyCompoundFilter(f, "all"); - } - - void operator()(const AnyFilter& f) { - stringifyCompoundFilter(f, "any"); - } - - void operator()(const NoneFilter& f) { - stringifyCompoundFilter(f, "none"); - } - - void operator()(const HasFilter& f) { - stringifyUnaryFilter("has", f.key); - } - - void operator()(const NotHasFilter& f) { - stringifyUnaryFilter("!has", f.key); - } - - void operator()(const TypeEqualsFilter& f) { - stringifyBinaryFilter(f, "==", "$type"); - } - - void operator()(const TypeNotEqualsFilter& f) { - stringifyBinaryFilter(f, "!=", "$type"); - } - - void operator()(const TypeInFilter& f) { - stringifySetFilter(f, "in", "$type"); - } - - void operator()(const TypeNotInFilter& f) { - stringifySetFilter(f, "!in", "$type"); - } - - void operator()(const IdentifierEqualsFilter& f) { - stringifyBinaryFilter(f, "==", "$id"); - } - - void operator()(const IdentifierNotEqualsFilter& f) { - stringifyBinaryFilter(f, "!=", "$id"); - } - - void operator()(const IdentifierInFilter& f) { - stringifySetFilter(f, "in", "$id"); - } - - void operator()(const IdentifierNotInFilter& f) { - stringifySetFilter(f, "!in", "$id"); - } - - void operator()(const HasIdentifierFilter&) { - stringifyUnaryFilter("has", "$id"); - } - - void operator()(const NotHasIdentifierFilter&) { - stringifyUnaryFilter("!has", "$id"); - } - - void operator()(const ExpressionFilter& filter) { - stringify(writer, filter.expression->serialize()); - } - -private: - template <class F> - void stringifyBinaryFilter(const F& f, const char * op) { - stringifyBinaryFilter(f, op, f.key); - } - - template <class F> - void stringifyBinaryFilter(const F& f, const char * op, const std::string& key) { - writer.StartArray(); - writer.String(op); - writer.String(key); - stringify(writer, f.value); - writer.EndArray(); - } - - template <class F> - void stringifySetFilter(const F& f, const char * op) { - stringifySetFilter(f, op, f.key); - } - - template <class F> - void stringifySetFilter(const F& f, const char * op, const std::string& key) { - writer.StartArray(); - writer.String(op); - writer.String(key); - for (const auto& value : f.values) { - stringify(writer, value); - } - writer.EndArray(); - } - - template <class F> - void stringifyCompoundFilter(const F& f, const char * op) { - writer.StartArray(); - writer.String(op); - for (const auto& filter : f.filters) { - Filter::visit(filter, *this); - } - writer.EndArray(); - } - - void stringifyUnaryFilter(const char * op, const std::string& key) { - writer.StartArray(); - writer.String(op); - writer.String(key); - writer.EndArray(); - } -}; - -template <class Writer> -void stringify(Writer& writer, const Filter& f) { - Filter::visit(f, StringifyFilter<Writer> { writer }); +void stringify(Writer& writer, const Filter& filter) { + if (!filter.expression) writer.Null(); + else stringify(writer, (*filter.expression)->serialize()); } template <class Writer> @@ -291,17 +138,7 @@ void stringify(Writer& writer, const Undefined&) { } template <class Writer, class T> -void stringify(Writer& writer, const CameraFunction<T>& fn) { - stringify(writer, fn.getExpression().serialize()); -} - -template <class Writer, class T> -void stringify(Writer& writer, const SourceFunction<T>& fn) { - stringify(writer, fn.getExpression().serialize()); -} - -template <class Writer, class T> -void stringify(Writer& writer, const CompositeFunction<T>& fn) { +void stringify(Writer& writer, const PropertyExpression<T>& fn) { stringify(writer, fn.getExpression().serialize()); } diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp index a2c4aa80b3..fe3254b149 100644 --- a/src/mbgl/style/conversion/tileset.cpp +++ b/src/mbgl/style/conversion/tileset.cpp @@ -1,14 +1,11 @@ #include <mbgl/style/conversion/tileset.hpp> #include <mbgl/util/geo.hpp> +#include <mbgl/math/clamp.hpp> namespace mbgl { namespace style { namespace conversion { -bool validateLatitude(const double lat) { - return lat <= 90 && lat >= -90; -} - optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const { Tileset result; @@ -95,16 +92,20 @@ optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error error = { "bounds array must contain numeric longitude and latitude values" }; return {}; } - if (!validateLatitude(*bottom) || !validateLatitude(*top) || top <= bottom){ - error = { "bounds latitude values must be between -90 and 90 with bottom less than top" }; + + bottom = util::clamp(*bottom, -90.0, 90.0); + top = util::clamp(*top, -90.0, 90.0); + if (top <= bottom){ + error = { "bounds bottom latitude must be smaller than top latitude" }; return {}; } + if(*left >= *right) { error = { "bounds left longitude should be less than right longitude" }; return {}; } - *left = util::max(-180.0, *left); - *right = util::min(180.0, *right); + left = util::max(-180.0, *left); + right = util::min(180.0, *right); result.bounds = LatLngBounds::hull({ *bottom, *left }, { *top, *right }); } diff --git a/src/mbgl/style/conversion/transition_options.cpp b/src/mbgl/style/conversion/transition_options.cpp index 8a60c5bfd8..116d44f9d9 100644 --- a/src/mbgl/style/conversion/transition_options.cpp +++ b/src/mbgl/style/conversion/transition_options.cpp @@ -10,7 +10,7 @@ optional<TransitionOptions> Converter<TransitionOptions>::operator()(const Conve return {}; } - TransitionOptions result; + optional<TransitionOptions> result = TransitionOptions{}; auto duration = objectMember(value, "duration"); if (duration) { @@ -19,7 +19,7 @@ optional<TransitionOptions> Converter<TransitionOptions>::operator()(const Conve error = { "duration must be a number" }; return {}; } - result.duration = { std::chrono::milliseconds(int64_t(*number)) }; + result->duration = { std::chrono::milliseconds(int64_t(*number)) }; } auto delay = objectMember(value, "delay"); @@ -29,7 +29,7 @@ optional<TransitionOptions> Converter<TransitionOptions>::operator()(const Conve error = { "delay must be a number" }; return {}; } - result.delay = { std::chrono::milliseconds(int64_t(*number)) }; + result->delay = { std::chrono::milliseconds(int64_t(*number)) }; } return result; diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index d6f3f1b584..2434d7a2f8 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -6,6 +6,14 @@ namespace style { namespace expression { using namespace mbgl::style::conversion; + +Assertion::Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_) : + Expression(Kind::Assertion, type_), + inputs(std::move(inputs_)) +{ + assert(!inputs.empty()); +} + ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { {"string", type::String}, @@ -64,7 +72,8 @@ void Assertion::eachChild(const std::function<void(const Expression&)>& visit) c }; bool Assertion::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Assertion*>(&e)) { + if (e.getKind() == Kind::Assertion) { + auto rhs = static_cast<const Assertion*>(&e); return getType() == rhs->getType() && Expression::childrenEqual(inputs, rhs->inputs); } return false; diff --git a/src/mbgl/style/expression/boolean_operator.cpp b/src/mbgl/style/expression/boolean_operator.cpp index 8d277450ba..68e96129aa 100644 --- a/src/mbgl/style/expression/boolean_operator.cpp +++ b/src/mbgl/style/expression/boolean_operator.cpp @@ -20,7 +20,8 @@ void Any::eachChild(const std::function<void(const Expression&)>& visit) const { } bool Any::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Any*>(&e)) { + if (e.getKind() == Kind::Any) { + auto rhs = static_cast<const Any*>(&e); return Expression::childrenEqual(inputs, rhs->inputs); } return false; @@ -47,7 +48,8 @@ void All::eachChild(const std::function<void(const Expression&)>& visit) const { } bool All::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const All*>(&e)) { + if (e.getKind() == Kind::All) { + auto rhs = static_cast<const All*>(&e); return Expression::childrenEqual(inputs, rhs->inputs); } return false; diff --git a/src/mbgl/style/expression/case.cpp b/src/mbgl/style/expression/case.cpp index 295e694189..e885c0ce6b 100644 --- a/src/mbgl/style/expression/case.cpp +++ b/src/mbgl/style/expression/case.cpp @@ -28,7 +28,8 @@ void Case::eachChild(const std::function<void(const Expression&)>& visit) const } bool Case::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Case*>(&e)) { + if (e.getKind() == Kind::Case) { + auto rhs = static_cast<const Case*>(&e); return *otherwise == *(rhs->otherwise) && Expression::childrenEqual(branches, rhs->branches); } return false; diff --git a/src/mbgl/style/expression/coalesce.cpp b/src/mbgl/style/expression/coalesce.cpp index 872a9abbef..0090f16009 100644 --- a/src/mbgl/style/expression/coalesce.cpp +++ b/src/mbgl/style/expression/coalesce.cpp @@ -21,7 +21,8 @@ void Coalesce::eachChild(const std::function<void(const Expression&)>& visit) co } bool Coalesce::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Coalesce*>(&e)) { + if (e.getKind() == Kind::Coalesce) { + auto rhs = static_cast<const Coalesce*>(&e); return Expression::childrenEqual(args, rhs->args); } return false; diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index d9cd3ffdc9..f5a4d70f66 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -13,7 +13,7 @@ EvaluationResult toNumber(const Value& v) { [](const std::string& s) -> optional<double> { try { return util::stof(s); - } catch(std::exception) { + } catch (const std::exception&) { return optional<double>(); } }, @@ -68,9 +68,10 @@ EvaluationResult toColor(const Value& colorValue) { } Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_) : - Expression(std::move(type_)), + Expression(Kind::Coercion, std::move(type_)), inputs(std::move(inputs_)) { + assert(!inputs.empty()); type::Type t = getType(); if (t.is<type::NumberType>()) { coerceSingleValue = toNumber; @@ -137,7 +138,8 @@ void Coercion::eachChild(const std::function<void(const Expression&)>& visit) co }; bool Coercion::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Coercion*>(&e)) { + if (e.getKind() == Kind::Coercion) { + auto rhs = static_cast<const Coercion*>(&e); return getType() == rhs->getType() && Expression::childrenEqual(inputs, rhs->inputs); } return false; diff --git a/src/mbgl/style/expression/collator_expression.cpp b/src/mbgl/style/expression/collator_expression.cpp new file mode 100644 index 0000000000..b27eedbc76 --- /dev/null +++ b/src/mbgl/style/expression/collator_expression.cpp @@ -0,0 +1,121 @@ +#include <mbgl/style/expression/collator.hpp> +#include <mbgl/style/expression/collator_expression.hpp> +#include <mbgl/style/expression/literal.hpp> +#include <mbgl/util/string.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +CollatorExpression::CollatorExpression(std::unique_ptr<Expression> caseSensitive_, + std::unique_ptr<Expression> diacriticSensitive_, + optional<std::unique_ptr<Expression>> locale_) + : Expression(Kind::CollatorExpression, type::Collator) + , caseSensitive(std::move(caseSensitive_)) + , diacriticSensitive(std::move(diacriticSensitive_)) + , locale(std::move(locale_)) +{} + +using namespace mbgl::style::conversion; + +ParseResult CollatorExpression::parse(const Convertible& value, ParsingContext& ctx) { + if (arrayLength(value) != 2) { + ctx.error("Expected one argument."); + return ParseResult(); + } + + auto options = arrayMember(value, 1); + if (!isObject(options)) { + ctx.error("Collator options argument must be an object."); + return ParseResult(); + } + + const optional<Convertible> caseSensitiveOption = objectMember(options, "case-sensitive"); + ParseResult caseSensitive; + if (caseSensitiveOption) { + caseSensitive = ctx.parse(*caseSensitiveOption, 1, {type::Boolean}); + } else { + caseSensitive = { std::make_unique<Literal>(false) }; + } + if (!caseSensitive) { + return ParseResult(); + } + + const optional<Convertible> diacriticSensitiveOption = objectMember(options, "diacritic-sensitive"); + ParseResult diacriticSensitive; + if (diacriticSensitiveOption) { + diacriticSensitive = ctx.parse(*diacriticSensitiveOption, 1, {type::Boolean}); + } else { + diacriticSensitive = { std::make_unique<Literal>(false) }; + } + if (!diacriticSensitive) { + return ParseResult(); + } + + const optional<Convertible> localeOption = objectMember(options, "locale"); + ParseResult locale; + if (localeOption) { + locale = ctx.parse(*localeOption, 1, {type::String}); + if (!locale) { + return ParseResult(); + } + } + + return ParseResult(std::make_unique<CollatorExpression>(std::move(*caseSensitive), std::move(*diacriticSensitive), std::move(locale))); +} + +void CollatorExpression::eachChild(const std::function<void(const Expression&)>& fn) const { + fn(*caseSensitive); + fn(*diacriticSensitive); + if (locale) { + fn(**locale); + } +} + +bool CollatorExpression::operator==(const Expression& e) const { + if (e.getKind() == Kind::CollatorExpression) { + auto rhs = static_cast<const CollatorExpression*>(&e); + if ((locale && (!rhs->locale || **locale != **(rhs->locale))) || + (!locale && rhs->locale)) { + return false; + } + return *caseSensitive == *(rhs->caseSensitive) && + *diacriticSensitive == *(rhs->diacriticSensitive); + } + return false; +} + +mbgl::Value CollatorExpression::serialize() const { + std::unordered_map<std::string, mbgl::Value> options; + options["case-sensitive"] = caseSensitive->serialize(); + options["diacritic-sensitive"] = diacriticSensitive->serialize(); + if (locale) { + options["locale"] = (*locale)->serialize(); + } + return std::vector<mbgl::Value>{{ std::string("collator"), options }}; +} + +EvaluationResult CollatorExpression::evaluate(const EvaluationContext& params) const { + auto caseSensitiveResult = caseSensitive->evaluate(params); + if (!caseSensitiveResult) { + return caseSensitiveResult.error(); + } + auto diacriticSensitiveResult = diacriticSensitive->evaluate(params); + if (!diacriticSensitiveResult) { + return diacriticSensitiveResult.error(); + } + + if (locale) { + auto localeResult = (*locale)->evaluate(params); + if (!localeResult) { + return localeResult.error(); + } + return Collator(caseSensitiveResult->get<bool>(), diacriticSensitiveResult->get<bool>(), localeResult->get<std::string>()); + } else { + return Collator(caseSensitiveResult->get<bool>(), diacriticSensitiveResult->get<bool>()); + } +} + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index bcde09e1b6..46b0c7fe18 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -1,3 +1,5 @@ +#include <boost/algorithm/string/join.hpp> +#include <mbgl/style/expression/collator.hpp> #include <mbgl/style/expression/compound_expression.hpp> #include <mbgl/style/expression/check_subtype.hpp> #include <mbgl/style/expression/util.hpp> @@ -19,7 +21,7 @@ namespace detail { The Signature<Fn> structs are wrappers around an "evaluate()" function whose purpose is to extract the necessary Type data from the evaluate function's type. There are three key (partial) specializations: - + Signature<R (Params...)>: Wraps a simple evaluate function (const T0&, const T1&, ...) -> Result<U> @@ -30,9 +32,9 @@ namespace detail { Signature<R (const EvaluationContext&, Params...)>: Wraps an evaluate function that needs to access the expression evaluation parameters in addition to its subexpressions, i.e., - (const EvaluationParams& const T0&, const T1&, ...) -> Result<U>. Needed + (const EvaluationParams&, const T0&, const T1&, ...) -> Result<U>. Needed for expressions like ["zoom"], ["get", key], etc. - + In each of the above evaluate signatures, T0, T1, etc. are the types of the successfully evaluated subexpressions. */ @@ -43,7 +45,7 @@ struct Signature; template <class R, class... Params> struct Signature<R (Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - + Signature(R (*evaluate_)(Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), @@ -55,7 +57,7 @@ struct Signature<R (Params...)> : SignatureBase { EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{}); } - + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); @@ -80,7 +82,7 @@ private: template <class R, typename T> struct Signature<R (const Varargs<T>&)> : SignatureBase { using Args = std::vector<std::unique_ptr<Expression>>; - + Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), @@ -89,11 +91,11 @@ struct Signature<R (const Varargs<T>&)> : SignatureBase { ), evaluate(evaluate_) {} - + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args)); }; - + EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { Varargs<T> evaluated; evaluated.reserve(args.size()); @@ -115,7 +117,7 @@ struct Signature<R (const Varargs<T>&)> : SignatureBase { template <class R, class... Params> struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - + Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), @@ -124,17 +126,17 @@ struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase { ), evaluate(evaluate_) {} - + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); } - + EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{}); } - + private: template <std::size_t ...I> EvaluationResult applyImpl(const EvaluationContext& evaluationParameters, const Args& args, std::index_sequence<I...>) const { @@ -150,6 +152,41 @@ private: R (*evaluate)(const EvaluationContext&, Params...); }; + +// Evaluate function needing EvaluationContext and Varargs +// (const EvaluationContext&, const Varargs<T>&) -> Result<U> +template <class R, typename T> +struct Signature<R (const EvaluationContext&, const Varargs<T>&)> : SignatureBase { + using Args = std::vector<std::unique_ptr<Expression>>; + + Signature(R (*evaluate_)(const EvaluationContext&, const Varargs<T>&), std::string name_) : + SignatureBase( + valueTypeToExpressionType<std::decay_t<typename R::Value>>(), + VarargsType { valueTypeToExpressionType<T>() }, + std::move(name_) + ), + evaluate(evaluate_) + {} + + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { + return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args)); + }; + + EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { + Varargs<T> evaluated; + evaluated.reserve(args.size()); + for (const auto& arg : args) { + const EvaluationResult evaluatedArg = arg->evaluate(evaluationParameters); + if(!evaluatedArg) return evaluatedArg.error(); + evaluated.push_back(*fromExpressionValue<std::decay_t<T>>(*evaluatedArg)); + } + const R value = evaluate(evaluationParameters, evaluated); + if (!value) return value.error(); + return *value; + } + + R (*evaluate)(const EvaluationContext&, const Varargs<T>&); +}; // Machinery to pull out function types from class methods, lambdas, etc. template <class R, class... Params> @@ -181,29 +218,104 @@ static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name)); } +Value featureIdAsExpressionValue(EvaluationContext params) { + assert(params.feature); + auto id = params.feature->getID(); + if (!id) return Null; + return id->match([](const auto& idid) { + return toExpressionValue(mbgl::Value(idid)); + }); +}; + +optional<Value> featurePropertyAsExpressionValue(EvaluationContext params, const std::string& key) { + assert(params.feature); + auto property = params.feature->getValue(key); + return property ? toExpressionValue(*property) : optional<Value>(); +}; + +optional<std::string> featureTypeAsString(FeatureType type) { + switch(type) { + case FeatureType::Point: + return optional<std::string>("Point"); + case FeatureType::LineString: + return optional<std::string>("LineString"); + case FeatureType::Polygon: + return optional<std::string>("Polygon"); + case FeatureType::Unknown: + return optional<std::string>("Unknown"); + default: + return {}; + } +}; + +optional<double> featurePropertyAsDouble(EvaluationContext params, const std::string& key) { + assert(params.feature); + auto property = params.feature->getValue(key); + if (!property) return {}; + return property->match( + [](double value) { return value; }, + [](uint64_t value) { return optional<double>(static_cast<double>(value)); }, + [](int64_t value) { return optional<double>(static_cast<double>(value)); }, + [](auto) { return optional<double>(); } + ); +}; + +optional<std::string> featurePropertyAsString(EvaluationContext params, const std::string& key) { + assert(params.feature); + auto property = params.feature->getValue(key); + if (!property) return {}; + return property->match( + [](std::string value) { return value; }, + [](auto) { return optional<std::string>(); } + ); +}; + +optional<double> featureIdAsDouble(EvaluationContext params) { + assert(params.feature); + auto id = params.feature->getID(); + if (!id) return optional<double>(); + return id->match( + [](double value) { return value; }, + [](uint64_t value) { return optional<double>(static_cast<double>(value)); }, + [](int64_t value) { return optional<double>(static_cast<double>(value)); }, + [](auto) { return optional<double>(); } + ); +}; + +optional<std::string> featureIdAsString(EvaluationContext params) { + assert(params.feature); + auto id = params.feature->getID(); + if (!id) return optional<std::string>(); + return id->match( + [](std::string value) { return value; }, + [](auto) { return optional<std::string>(); } + ); +}; + std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() { std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions; auto define = [&](std::string name, auto fn) { definitions[name].push_back(makeSignature(fn, name)); }; - + define("e", []() -> Result<double> { return 2.718281828459045; }); define("pi", []() -> Result<double> { return 3.141592653589793; }); define("ln2", []() -> Result<double> { return 0.6931471805599453; }); define("typeof", [](const Value& v) -> Result<std::string> { return toString(typeOf(v)); }); - + define("to-string", [](const Value& value) -> Result<std::string> { return value.match( + [](const NullValue&) -> Result<std::string> { return std::string(); }, [](const Color& c) -> Result<std::string> { return c.stringify(); }, // avoid quoting [](const std::string& s) -> Result<std::string> { return s; }, // avoid quoting [](const auto& v) -> Result<std::string> { return stringify(v); } ); }); - + define("to-boolean", [](const Value& v) -> Result<bool> { return v.match( - [&] (double f) { return (bool)f; }, + [&] (double f) { return static_cast<bool>(f); }, [&] (const std::string& s) { return s.length() > 0; }, [&] (bool b) { return b; }, [&] (const NullValue&) { return false; }, @@ -213,10 +325,10 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali define("to-rgba", [](const Color& color) -> Result<std::array<double, 4>> { return color.toArray(); }); - + define("rgba", rgba); define("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); }); - + define("zoom", [](const EvaluationContext& params) -> Result<double> { if (!params.zoom) { return EvaluationError { @@ -225,7 +337,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return *(params.zoom); }); - + define("heatmap-density", [](const EvaluationContext& params) -> Result<double> { if (!params.heatmapDensity) { return EvaluationError { @@ -241,7 +353,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali "Feature data is unavailable in the current evaluation context." }; } - + return params.feature->getValue(key) ? true : false; }); define("has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> { @@ -267,7 +379,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return object.at(key); }); - + define("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> { if (!params.feature) { return EvaluationError { @@ -281,14 +393,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return result; }); - + define("geometry-type", [](const EvaluationContext& params) -> Result<std::string> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." }; } - + auto type = params.feature->getType(); if (type == FeatureType::Point) { return "Point"; @@ -300,14 +412,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return "Unknown"; } }); - + define("id", [](const EvaluationContext& params) -> Result<Value> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." }; } - + auto id = params.feature->getID(); if (!id) { return Null; @@ -318,7 +430,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } ); }); - + define("+", [](const Varargs<double>& args) -> Result<double> { double sum = 0.0f; for (auto arg : args) { @@ -341,14 +453,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali define("sqrt", [](double x) -> Result<double> { return sqrt(x); }); define("log10", [](double x) -> Result<double> { return log10(x); }); define("ln", [](double x) -> Result<double> { return log(x); }); - define("log2", [](double x) -> Result<double> { return util::log2(x); }); + define("log2", [](double x) -> Result<double> { return log2(x); }); define("sin", [](double x) -> Result<double> { return sin(x); }); define("cos", [](double x) -> Result<double> { return cos(x); }); define("tan", [](double x) -> Result<double> { return tan(x); }); define("asin", [](double x) -> Result<double> { return asin(x); }); define("acos", [](double x) -> Result<double> { return acos(x); }); define("atan", [](double x) -> Result<double> { return atan(x); }); - + define("min", [](const Varargs<double>& args) -> Result<double> { double result = std::numeric_limits<double>::infinity(); for (double arg : args) { @@ -371,13 +483,17 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali define(">", [](double lhs, double rhs) -> Result<bool> { return lhs > rhs; }); define(">", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs > rhs; }); + define(">", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) > 0; }); define(">=", [](double lhs, double rhs) -> Result<bool> { return lhs >= rhs; }); define(">=",[](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs >= rhs; }); + define(">=", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) >= 0; }); define("<", [](double lhs, double rhs) -> Result<bool> { return lhs < rhs; }); define("<", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs < rhs; }); + define("<", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) < 0; }); define("<=", [](double lhs, double rhs) -> Result<bool> { return lhs <= rhs; }); define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; }); - + define("<=", [](const std::string& lhs, const std::string& rhs, const Collator& c) -> Result<bool> { return c.compare(lhs, rhs) <= 0; }); + define("!", [](bool e) -> Result<bool> { return !e; }); define("is-supported-script", [](const std::string& x) -> Result<bool> { @@ -397,89 +513,153 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return s; }); + define("resolved-locale", [](const Collator& collator) -> Result<std::string> { + return collator.resolvedLocale(); + }); + define("error", [](const std::string& input) -> Result<type::ErrorType> { return EvaluationError { input }; }); - - return definitions; -} -std::unordered_map<std::string, Definition> CompoundExpressionRegistry::definitions = initializeDefinitions(); + // Legacy Filters + define("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> { + const auto rhs = featurePropertyAsExpressionValue(params, key); + return rhs ? lhs == *rhs : false; + }); -using namespace mbgl::style::conversion; -ParseResult parseCompoundExpression(const std::string name, const Convertible& value, ParsingContext& ctx) { - assert(isArray(value) && arrayLength(value) > 0); + define("filter-id-==", [](const EvaluationContext& params, const Value &lhs) -> Result<bool> { + return lhs == featureIdAsExpressionValue(params); + }); - auto it = CompoundExpressionRegistry::definitions.find(name); - if (it == CompoundExpressionRegistry::definitions.end()) { - ctx.error( - R"(Unknown expression ")" + name + R"(". If you wanted a literal array, use ["literal", [...]].)", - 0 - ); - return ParseResult(); - } - const CompoundExpressionRegistry::Definition& definition = it->second; + define("filter-type-==", [](const EvaluationContext& params, const std::string &lhs) -> Result<bool> { + if (!params.feature) return false; + return featureTypeAsString(params.feature->getType()) == lhs; + }); + + define("filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { + auto rhs = featurePropertyAsDouble(params, key); + return rhs ? rhs < lhs : false; + }); + + define("filter-<", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { + auto rhs = featurePropertyAsString(params, key); + return rhs ? rhs < lhs : false; + }); + + define("filter-id-<", [](const EvaluationContext& params, double lhs) -> Result<bool> { + auto rhs = featureIdAsDouble(params); + return rhs ? rhs < lhs : false; + }); + + define("filter-id-<", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { + auto rhs = featureIdAsString(params); + return rhs ? rhs < lhs : false; + }); + + define("filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { + auto rhs = featurePropertyAsDouble(params, key); + return rhs ? rhs > lhs : false; + }); + + define("filter->", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { + auto rhs = featurePropertyAsString(params, key); + return rhs ? rhs > lhs : false; + }); + + define("filter-id->", [](const EvaluationContext& params, double lhs) -> Result<bool> { + auto rhs = featureIdAsDouble(params); + return rhs ? rhs > lhs : false; + }); + + define("filter-id->", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { + auto rhs = featureIdAsString(params); + return rhs ? rhs > lhs : false; + }); + + define("filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { + auto rhs = featurePropertyAsDouble(params, key); + return rhs ? rhs <= lhs : false; + }); - auto length = arrayLength(value); + define("filter-<=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { + auto rhs = featurePropertyAsString(params, key); + return rhs ? rhs <= lhs : false; + }); - // Check if we have a single signature with the correct number of - // parameters. If so, then use that signature's parameter types for parsing - // (and inferring the types of) the arguments. - optional<std::size_t> singleMatchingSignature; - for (std::size_t j = 0; j < definition.size(); j++) { - const std::unique_ptr<detail::SignatureBase>& signature = definition[j]; - if ( - signature->params.is<VarargsType>() || - signature->params.get<std::vector<type::Type>>().size() == length - 1 - ) { - if (singleMatchingSignature) { - singleMatchingSignature = {}; - } else { - singleMatchingSignature = j; - } - } - } + define("filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> { + auto rhs = featureIdAsDouble(params); + return rhs ? rhs <= lhs : false; + }); + + define("filter-id-<=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { + auto rhs = featureIdAsString(params); + return rhs ? rhs <= lhs : false; + }); - // parse subexpressions first - std::vector<std::unique_ptr<Expression>> args; - args.reserve(length - 1); - for (std::size_t i = 1; i < length; i++) { - optional<type::Type> expected; - - if (singleMatchingSignature) { - expected = definition[*singleMatchingSignature]->params.match( - [](const VarargsType& varargs) { return varargs.type; }, - [&](const std::vector<type::Type>& params_) { return params_[i - 1]; } - ); - } + define("filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { + auto rhs = featurePropertyAsDouble(params, key); + return rhs ? rhs >= lhs : false; + }); - auto parsed = ctx.parse(arrayMember(value, i), i, expected); - if (!parsed) { - return parsed; - } - args.push_back(std::move(*parsed)); - } - return createCompoundExpression(definition, std::move(args), ctx); -} + define("filter->=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { + auto rhs = featurePropertyAsString(params, key); + return rhs ? rhs >= lhs : false; + }); + define("filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> { + auto rhs = featureIdAsDouble(params); + return rhs ? rhs >= lhs : false; + }); -ParseResult createCompoundExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args, - ParsingContext& ctx) -{ - return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); + define("filter-id->=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { + auto rhs = featureIdAsString(params); + return rhs ? rhs >= lhs : false; + }); + + define("filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> { + assert(params.feature); + return bool(params.feature->getValue(key)); + }); + + define("filter-has-id", [](const EvaluationContext& params) -> Result<bool> { + assert(params.feature); + return bool(params.feature->getID()); + }); + + define("filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> { + assert(params.feature); + optional<std::string> type = featureTypeAsString(params.feature->getType()); + return std::find(types.begin(), types.end(), type) != types.end(); + }); + + define("filter-id-in", [](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> { + auto id = featureIdAsExpressionValue(params); + return std::find(ids.begin(), ids.end(), id) != ids.end(); + }); + + define("filter-in", [](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> { + if (varargs.size() < 2) return false; + assert(varargs[0].is<std::string>()); + auto value = featurePropertyAsExpressionValue(params, varargs[0].get<std::string>()); + return value ? std::find(varargs.begin() + 1, varargs.end(), *value) != varargs.end() : false; + }); + + return definitions; } +std::unordered_map<std::string, Definition> CompoundExpressionRegistry::definitions = initializeDefinitions(); -ParseResult createCompoundExpression(const Definition& definition, - std::vector<std::unique_ptr<Expression>> args, - ParsingContext& ctx) +using namespace mbgl::style::conversion; + +static ParseResult createCompoundExpression(const Definition& definition, + std::vector<std::unique_ptr<Expression>> args, + ParsingContext& ctx) { ParsingContext signatureContext(ctx.getKey()); - + for (const std::unique_ptr<detail::SignatureBase>& signature : definition) { signatureContext.clearErrors(); - + if (signature->params.is<std::vector<type::Type>>()) { const std::vector<type::Type>& params = signature->params.get<std::vector<type::Type>>(); if (params.size() != args.size()) { @@ -507,35 +687,44 @@ ParseResult createCompoundExpression(const Definition& definition, } } } - + if (signatureContext.getErrors().size() == 0) { return ParseResult(signature->makeExpression(std::move(args))); } } - + if (definition.size() == 1) { ctx.appendErrors(std::move(signatureContext)); } else { - std::string signatures; + std::vector<std::string> availableOverloads; // Only used if there are no overloads with matching number of args + std::vector<std::string> overloads; for (const auto& signature : definition) { - signatures += (signatures.size() > 0 ? " | " : ""); signature->params.match( [&](const VarargsType& varargs) { - signatures += "(" + toString(varargs.type) + ")"; + std::string overload = "(" + toString(varargs.type) + ")"; + overloads.push_back(overload); }, [&](const std::vector<type::Type>& params) { - signatures += "("; + std::string overload = "("; bool first = true; for (const type::Type& param : params) { - if (!first) signatures += ", "; - signatures += toString(param); + if (!first) overload += ", "; + overload += toString(param); first = false; } - signatures += ")"; + overload += ")"; + if (params.size() == args.size()) { + overloads.push_back(overload); + } else { + availableOverloads.push_back(overload); + } } ); - + } + std::string signatures = overloads.empty() ? + boost::algorithm::join(availableOverloads, " | ") : + boost::algorithm::join(overloads, " | "); std::string actualTypes; for (const auto& arg : args) { if (actualTypes.size() > 0) { @@ -545,10 +734,73 @@ ParseResult createCompoundExpression(const Definition& definition, } ctx.error("Expected arguments of type " + signatures + ", but found (" + actualTypes + ") instead."); } - + return ParseResult(); } +ParseResult parseCompoundExpression(const std::string name, const Convertible& value, ParsingContext& ctx) { + assert(isArray(value) && arrayLength(value) > 0); + + auto it = CompoundExpressionRegistry::definitions.find(name); + if (it == CompoundExpressionRegistry::definitions.end()) { + ctx.error( + R"(Unknown expression ")" + name + R"(". If you wanted a literal array, use ["literal", [...]].)", + 0 + ); + return ParseResult(); + } + const CompoundExpressionRegistry::Definition& definition = it->second; + + auto length = arrayLength(value); + + // Check if we have a single signature with the correct number of + // parameters. If so, then use that signature's parameter types for parsing + // (and inferring the types of) the arguments. + optional<std::size_t> singleMatchingSignature; + for (std::size_t j = 0; j < definition.size(); j++) { + const std::unique_ptr<detail::SignatureBase>& signature = definition[j]; + if ( + signature->params.is<VarargsType>() || + signature->params.get<std::vector<type::Type>>().size() == length - 1 + ) { + if (singleMatchingSignature) { + singleMatchingSignature = {}; + } else { + singleMatchingSignature = j; + } + } + } + + // parse subexpressions first + std::vector<std::unique_ptr<Expression>> args; + args.reserve(length - 1); + for (std::size_t i = 1; i < length; i++) { + optional<type::Type> expected; + + if (singleMatchingSignature) { + expected = definition[*singleMatchingSignature]->params.match( + [](const VarargsType& varargs) { return varargs.type; }, + [&](const std::vector<type::Type>& params_) { return params_[i - 1]; } + ); + } + + auto parsed = ctx.parse(arrayMember(value, i), i, expected); + if (!parsed) { + return parsed; + } + args.push_back(std::move(*parsed)); + } + + return createCompoundExpression(definition, std::move(args), ctx); +} + +ParseResult createCompoundExpression(const std::string& name, + std::vector<std::unique_ptr<Expression>> args, + ParsingContext& ctx) +{ + return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp new file mode 100644 index 0000000000..a851d82e16 --- /dev/null +++ b/src/mbgl/style/expression/dsl.cpp @@ -0,0 +1,183 @@ +#include <mbgl/style/expression/dsl.hpp> +#include <mbgl/style/expression/error.hpp> +#include <mbgl/style/expression/literal.hpp> +#include <mbgl/style/expression/assertion.hpp> +#include <mbgl/style/expression/coercion.hpp> +#include <mbgl/style/expression/equals.hpp> +#include <mbgl/style/expression/step.hpp> +#include <mbgl/style/expression/interpolate.hpp> +#include <mbgl/style/expression/compound_expression.hpp> + +namespace mbgl { +namespace style { +namespace expression { +namespace dsl { + +static std::unique_ptr<Expression> compound(const char* op, std::vector<std::unique_ptr<Expression>> args) { + ParsingContext ctx; + ParseResult result = createCompoundExpression(op, std::move(args), ctx); + assert(result); + return std::move(*result); +} + +template <class... Args> +static std::unique_ptr<Expression> compound(const char* op, Args... args) { + return compound(op, vec(std::move(args)...)); +} + +std::unique_ptr<Expression> error(std::string message) { + return std::make_unique<Error>(std::move(message)); +} + +std::unique_ptr<Expression> literal(const char* value) { + return literal(std::string(value)); +} + +std::unique_ptr<Expression> literal(Value value) { + return std::make_unique<Literal>(value); +} + +std::unique_ptr<Expression> literal(std::initializer_list<double> value) { + std::vector<Value> values; + for (auto i : value) { + values.push_back(i); + } + return literal(values); +} + +std::unique_ptr<Expression> literal(std::initializer_list<const char *> value) { + std::vector<Value> values; + for (auto i : value) { + values.push_back(std::string(i)); + } + return literal(values); +} + +std::unique_ptr<Expression> number(std::unique_ptr<Expression> value) { + return std::make_unique<Assertion>(type::Number, vec(std::move(value))); +} + +std::unique_ptr<Expression> string(std::unique_ptr<Expression> value) { + return std::make_unique<Assertion>(type::String, vec(std::move(value))); +} + +std::unique_ptr<Expression> boolean(std::unique_ptr<Expression> value) { + return std::make_unique<Assertion>(type::Boolean, vec(std::move(value))); +} + +std::unique_ptr<Expression> toColor(std::unique_ptr<Expression> value) { + return std::make_unique<Coercion>(type::Color, vec(std::move(value))); +} + +std::unique_ptr<Expression> toString(std::unique_ptr<Expression> value) { + return compound("to-string", std::move(value)); +} + +std::unique_ptr<Expression> get(const char* value) { + return get(literal(value)); +} + +std::unique_ptr<Expression> get(std::unique_ptr<Expression> property) { + return compound("get", std::move(property)); +} + +std::unique_ptr<Expression> id() { + return compound("id"); +} + +std::unique_ptr<Expression> zoom() { + return compound("zoom"); +} + +std::unique_ptr<Expression> eq(std::unique_ptr<Expression> lhs, + std::unique_ptr<Expression> rhs) { + return std::make_unique<Equals>(std::move(lhs), std::move(rhs), nullopt, false); +} + +std::unique_ptr<Expression> ne(std::unique_ptr<Expression> lhs, + std::unique_ptr<Expression> rhs) { + return std::make_unique<Equals>(std::move(lhs), std::move(rhs), nullopt, true); +} + +std::unique_ptr<Expression> gt(std::unique_ptr<Expression> lhs, + std::unique_ptr<Expression> rhs) { + return compound(">", std::move(lhs), std::move(rhs)); +} + +std::unique_ptr<Expression> lt(std::unique_ptr<Expression> lhs, + std::unique_ptr<Expression> rhs) { + return compound("<", std::move(lhs), std::move(rhs)); +} + +std::unique_ptr<Expression> step(std::unique_ptr<Expression> input, + std::unique_ptr<Expression> output0, + double input1, std::unique_ptr<Expression> output1) { + type::Type type = output0->getType(); + std::map<double, std::unique_ptr<Expression>> stops; + stops[-std::numeric_limits<double>::infinity()] = std::move(output0); + stops[input1] = std::move(output1); + return std::make_unique<Step>(type, std::move(input), std::move(stops)); +} + +Interpolator linear() { + return ExponentialInterpolator(1.0); +} + +Interpolator exponential(double base) { + return ExponentialInterpolator(base); +} + +Interpolator cubicBezier(double x1, double y1, double x2, double y2) { + return CubicBezierInterpolator(x1, y1, x2, y2); +} + +std::unique_ptr<Expression> interpolate(Interpolator interpolator, + std::unique_ptr<Expression> input, + double input1, std::unique_ptr<Expression> output1) { + type::Type type = output1->getType(); + std::map<double, std::unique_ptr<Expression>> stops; + stops[input1] = std::move(output1); + ParsingContext ctx; + ParseResult result = createInterpolate(type, interpolator, std::move(input), std::move(stops), ctx); + assert(result); + return std::move(*result); +} + +std::unique_ptr<Expression> interpolate(Interpolator interpolator, + std::unique_ptr<Expression> input, + double input1, std::unique_ptr<Expression> output1, + double input2, std::unique_ptr<Expression> output2) { + type::Type type = output1->getType(); + std::map<double, std::unique_ptr<Expression>> stops; + stops[input1] = std::move(output1); + stops[input2] = std::move(output2); + ParsingContext ctx; + ParseResult result = createInterpolate(type, interpolator, std::move(input), std::move(stops), ctx); + assert(result); + return std::move(*result); +} + +std::unique_ptr<Expression> interpolate(Interpolator interpolator, + std::unique_ptr<Expression> input, + double input1, std::unique_ptr<Expression> output1, + double input2, std::unique_ptr<Expression> output2, + double input3, std::unique_ptr<Expression> output3) { + type::Type type = output1->getType(); + std::map<double, std::unique_ptr<Expression>> stops; + stops[input1] = std::move(output1); + stops[input2] = std::move(output2); + stops[input3] = std::move(output3); + ParsingContext ctx; + ParseResult result = createInterpolate(type, interpolator, std::move(input), std::move(stops), ctx); + assert(result); + return std::move(*result); +} + +std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inputs) { + return compound("concat", std::move(inputs)); +} + +} // namespace dsl +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/expression/equals.cpp b/src/mbgl/style/expression/equals.cpp index 6d963cc1d8..73e2baf71b 100644 --- a/src/mbgl/style/expression/equals.cpp +++ b/src/mbgl/style/expression/equals.cpp @@ -1,14 +1,25 @@ +#include <mbgl/style/expression/collator.hpp> #include <mbgl/style/expression/equals.hpp> namespace mbgl { namespace style { namespace expression { -Equals::Equals(std::unique_ptr<Expression> lhs_, std::unique_ptr<Expression> rhs_, bool negate_) - : Expression(type::Boolean), +static bool isComparableType(const type::Type& type) { + return type == type::String || + type == type::Number || + type == type::Boolean || + type == type::Null; +} + +Equals::Equals(std::unique_ptr<Expression> lhs_, std::unique_ptr<Expression> rhs_, optional<std::unique_ptr<Expression>> collator_, bool negate_) + : Expression(Kind::Equals, type::Boolean), lhs(std::move(lhs_)), rhs(std::move(rhs_)), + collator(std::move(collator_)), negate(negate_) { + assert(isComparableType(lhs->getType()) || isComparableType(rhs->getType())); + assert(lhs->getType() == rhs->getType() || lhs->getType() == type::Value || rhs->getType() == type::Value); } EvaluationResult Equals::evaluate(const EvaluationContext& params) const { @@ -18,7 +29,15 @@ EvaluationResult Equals::evaluate(const EvaluationContext& params) const { EvaluationResult rhsResult = rhs->evaluate(params); if (!rhsResult) return lhsResult; - bool result = *lhsResult == *rhsResult; + bool result; + + if (collator) { + auto collatorResult = (*collator)->evaluate(params); + const Collator& c = collatorResult->get<Collator>(); + result = c.compare(lhsResult->get<std::string>(), rhsResult->get<std::string>()) == 0; + } else { + result = *lhsResult == *rhsResult; + } if (negate) { result = !result; } @@ -28,10 +47,14 @@ EvaluationResult Equals::evaluate(const EvaluationContext& params) const { void Equals::eachChild(const std::function<void(const Expression&)>& visit) const { visit(*lhs); visit(*rhs); + if (collator) { + visit(**collator); + } } bool Equals::operator==(const Expression& e) const { - if (auto eq = dynamic_cast<const Equals*>(&e)) { + if (e.getKind() == Kind::Equals) { + auto eq = static_cast<const Equals*>(&e); return eq->negate == negate && *eq->lhs == *lhs && *eq->rhs == *rhs; } return false; @@ -41,19 +64,12 @@ std::vector<optional<Value>> Equals::possibleOutputs() const { return {{ true }, { false }}; } -static bool isComparableType(const type::Type& type) { - return type == type::String || - type == type::Number || - type == type::Boolean || - type == type::Null; -} - using namespace mbgl::style::conversion; ParseResult Equals::parse(const Convertible& value, ParsingContext& ctx) { std::size_t length = arrayLength(value); - if (length != 3) { - ctx.error("Expected two arguments."); + if (length != 3 && length != 4) { + ctx.error("Expected two or three arguments."); return ParseResult(); } @@ -78,8 +94,18 @@ ParseResult Equals::parse(const Convertible& value, ParsingContext& ctx) { ctx.error("Cannot compare " + toString(lhsType) + " and " + toString(rhsType) + "."); return ParseResult(); } + + ParseResult collatorParseResult; + if (length == 4) { + if (lhsType != type::String && rhsType != type::String) { + ctx.error("Cannot use collator to compare non-string types."); + return ParseResult(); + } + collatorParseResult = ctx.parse(arrayMember(value, 3), 3, {type::Collator}); + if (!collatorParseResult) return ParseResult(); + } - return ParseResult(std::make_unique<Equals>(std::move(*lhs), std::move(*rhs), negate)); + return ParseResult(std::make_unique<Equals>(std::move(*lhs), std::move(*rhs), std::move(collatorParseResult), negate)); } } // namespace expression diff --git a/src/mbgl/style/function/expression.cpp b/src/mbgl/style/expression/expression.cpp index d9dbbfa1d3..d9dbbfa1d3 100644 --- a/src/mbgl/style/function/expression.cpp +++ b/src/mbgl/style/expression/expression.cpp diff --git a/src/mbgl/style/expression/find_zoom_curve.cpp b/src/mbgl/style/expression/find_zoom_curve.cpp index 5d39e0791e..a27f8560ef 100644 --- a/src/mbgl/style/expression/find_zoom_curve.cpp +++ b/src/mbgl/style/expression/find_zoom_curve.cpp @@ -2,6 +2,7 @@ #include <mbgl/style/expression/compound_expression.hpp> #include <mbgl/style/expression/let.hpp> #include <mbgl/style/expression/coalesce.hpp> +#include <mbgl/style/expression/is_constant.hpp> #include <mbgl/util/variant.hpp> #include <mbgl/util/optional.hpp> @@ -10,12 +11,17 @@ namespace mbgl { namespace style { namespace expression { -optional<variant<const InterpolateBase*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e) { - optional<variant<const InterpolateBase*, const Step*, ParsingError>> result; +optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e) { + optional<variant<const Interpolate*, const Step*, ParsingError>> result; - if (auto let = dynamic_cast<const Let*>(e)) { + switch (e->getKind()) { + case Kind::Let: { + auto let = static_cast<const Let*>(e); result = findZoomCurve(let->getResult()); - } else if (auto coalesce = dynamic_cast<const Coalesce*>(e)) { + break; + } + case Kind::Coalesce: { + auto coalesce = static_cast<const Coalesce*>(e); std::size_t length = coalesce->getLength(); for (std::size_t i = 0; i < length; i++) { result = findZoomCurve(coalesce->getChild(i)); @@ -23,16 +29,30 @@ optional<variant<const InterpolateBase*, const Step*, ParsingError>> findZoomCur break; } } - } else if (auto curve = dynamic_cast<const InterpolateBase*>(e)) { - auto z = dynamic_cast<CompoundExpressionBase*>(curve->getInput().get()); - if (z && z->getName() == "zoom") { - result = {curve}; + break; + } + case Kind::Interpolate: { + auto curve = static_cast<const Interpolate*>(e); + if (curve->getInput()->getKind() == Kind::CompoundExpression) { + auto z = static_cast<CompoundExpressionBase*>(curve->getInput().get()); + if (z && z->getName() == "zoom") { + result = {curve}; + } } - } else if (auto step = dynamic_cast<const Step*>(e)) { - auto z = dynamic_cast<CompoundExpressionBase*>(step->getInput().get()); - if (z && z->getName() == "zoom") { - result = {step}; + break; + } + case Kind::Step: { + auto step = static_cast<const Step*>(e); + if (step->getInput()->getKind() == Kind::CompoundExpression) { + auto z = static_cast<CompoundExpressionBase*>(step->getInput().get()); + if (z && z->getName() == "zoom") { + result = {step}; + } } + break; + } + default: + break; } if (result && result->is<ParsingError>()) { @@ -40,7 +60,7 @@ optional<variant<const InterpolateBase*, const Step*, ParsingError>> findZoomCur } e->eachChild([&](const Expression& child) { - optional<variant<const InterpolateBase*, const Step*, ParsingError>> childResult(findZoomCurve(&child)); + optional<variant<const Interpolate*, const Step*, ParsingError>> childResult(findZoomCurve(&child)); if (childResult) { if (childResult->is<ParsingError>()) { result = childResult; @@ -59,14 +79,17 @@ optional<variant<const InterpolateBase*, const Step*, ParsingError>> findZoomCur return result; } -variant<const InterpolateBase*, const Step*> findZoomCurveChecked(const expression::Expression* e) { +variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression* e) { + if (isZoomConstant(*e)) { + return nullptr; + } return findZoomCurve(e)->match( - [](const ParsingError&) -> variant<const InterpolateBase*, const Step*> { + [](const ParsingError&) -> variant<std::nullptr_t, const Interpolate*, const Step*> { assert(false); - return {}; + return nullptr; }, - [](auto zoomCurve) -> variant<const InterpolateBase*, const Step*> { - return {std::move(zoomCurve)}; + [](auto zoomCurve) -> variant<std::nullptr_t, const Interpolate*, const Step*> { + return zoomCurve; } ); } diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index daad8523f2..54fbc6e1d7 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -5,11 +5,77 @@ namespace mbgl { namespace style { namespace expression { -using Interpolator = variant<ExponentialInterpolator, - CubicBezierInterpolator>; - using namespace mbgl::style::conversion; +template <typename T> +class InterpolateImpl : public Interpolate { +public: + InterpolateImpl(type::Type type_, + Interpolator interpolator_, + std::unique_ptr<Expression> input_, + std::map<double, std::unique_ptr<Expression>> stops_ + ) : Interpolate(std::move(type_), std::move(interpolator_), std::move(input_), std::move(stops_)) + { + static_assert(util::Interpolatable<T>::value, "Interpolate expression requires an interpolatable value type."); + } + + EvaluationResult evaluate(const EvaluationContext& params) const override { + const EvaluationResult evaluatedInput = input->evaluate(params); + if (!evaluatedInput) { + return evaluatedInput.error(); + } + + float x = *fromExpressionValue<float>(*evaluatedInput); + if (std::isnan(x)) { + return EvaluationError { "Input is not a number." }; + } + + if (stops.empty()) { + return EvaluationError { "No stops in exponential curve." }; + } + + auto it = stops.upper_bound(x); + if (it == stops.end()) { + return stops.rbegin()->second->evaluate(params); + } else if (it == stops.begin()) { + return stops.begin()->second->evaluate(params); + } else { + float t = interpolationFactor({ std::prev(it)->first, it->first }, x); + + if (t == 0.0f) { + return std::prev(it)->second->evaluate(params); + } + if (t == 1.0f) { + return it->second->evaluate(params); + } + + EvaluationResult lower = std::prev(it)->second->evaluate(params); + if (!lower) { + return lower.error(); + } + EvaluationResult upper = it->second->evaluate(params); + if (!upper) { + return upper.error(); + } + + if (!lower->is<T>()) { + return EvaluationError { + "Expected value to be of type " + toString(valueTypeToExpressionType<T>()) + + ", but found " + toString(typeOf(*lower)) + " instead." + }; + } + + if (!upper->is<T>()) { + return EvaluationError { + "Expected value to be of type " + toString(valueTypeToExpressionType<T>()) + + ", but found " + toString(typeOf(*upper)) + " instead." + }; + } + return util::interpolate(lower->get<T>(), upper->get<T>(), t); + } + } +}; + ParseResult parseInterpolate(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); @@ -104,23 +170,23 @@ ParseResult parseInterpolate(const Convertible& value, ParsingContext& ctx) { labelValue->match( [&](uint64_t n) { if (n > std::numeric_limits<double>::max()) { - label = {std::numeric_limits<double>::infinity()}; + label = optional<double>{std::numeric_limits<double>::infinity()}; } else { - label = {static_cast<double>(n)}; + label = optional<double>{static_cast<double>(n)}; } }, [&](int64_t n) { if (n > std::numeric_limits<double>::max()) { - label = {std::numeric_limits<double>::infinity()}; + label = optional<double>{std::numeric_limits<double>::infinity()}; } else { - label = {static_cast<double>(n)}; + label = optional<double>{static_cast<double>(n)}; } }, [&](double n) { if (n > std::numeric_limits<double>::max()) { - label = {std::numeric_limits<double>::infinity()}; + label = optional<double>{std::numeric_limits<double>::infinity()}; } else { - label = {static_cast<double>(n)}; + label = optional<double>{n}; } }, [&](const auto&) {} @@ -154,59 +220,58 @@ ParseResult parseInterpolate(const Convertible& value, ParsingContext& ctx) { } assert(outputType); - - if ( - *outputType != type::Number && - *outputType != type::Color && - !( - outputType->is<type::Array>() && - outputType->get<type::Array>().itemType == type::Number && - outputType->get<type::Array>().N - ) - ) - { - ctx.error("Type " + toString(*outputType) + " is not interpolatable."); - return ParseResult(); - } - - return outputType->match( + + return createInterpolate(*outputType, + *interpolator, + std::move(*input), + std::move(stops), + ctx); +} + +ParseResult createInterpolate(type::Type type, + Interpolator interpolator, + std::unique_ptr<Expression> input, + std::map<double, std::unique_ptr<Expression>> stops, + ParsingContext& ctx) { + return type.match( [&](const type::NumberType&) -> ParseResult { - return interpolator->match([&](const auto& interpolator_) { - return ParseResult(std::make_unique<Interpolate<double>>( - *outputType, interpolator_, std::move(*input), std::move(stops) - )); - }); + return ParseResult(std::make_unique<InterpolateImpl<double>>( + type, interpolator, std::move(input), std::move(stops) + )); }, [&](const type::ColorType&) -> ParseResult { - return interpolator->match([&](const auto& interpolator_) { - return ParseResult(std::make_unique<Interpolate<Color>>( - *outputType, interpolator_, std::move(*input), std::move(stops) - )); - }); + return ParseResult(std::make_unique<InterpolateImpl<Color>>( + type, interpolator, std::move(input), std::move(stops) + )); }, [&](const type::Array& arrayType) -> ParseResult { - return interpolator->match( - [&](const auto& continuousInterpolator) { - if (arrayType.itemType != type::Number || !arrayType.N) { - assert(false); // interpolability already checked above. - return ParseResult(); - } - return ParseResult(std::make_unique<Interpolate<std::vector<Value>>>( - *outputType, continuousInterpolator, std::move(*input), std::move(stops) - )); - } - ); + if (arrayType.itemType != type::Number || !arrayType.N) { + ctx.error("Type " + toString(type) + " is not interpolatable."); + return ParseResult(); + } + return ParseResult(std::make_unique<InterpolateImpl<std::vector<Value>>>( + type, interpolator, std::move(input), std::move(stops) + )); }, [&](const auto&) { - // unreachable: Null, Boolean, String, Object, Value output types - // are not interpolatable, and interpolability was already checked above - assert(false); + ctx.error("Type " + toString(type) + " is not interpolatable."); return ParseResult(); } ); } -std::vector<optional<Value>> InterpolateBase::possibleOutputs() const { +Interpolate::Interpolate(const type::Type& type_, + Interpolator interpolator_, + std::unique_ptr<Expression> input_, + std::map<double, std::unique_ptr<Expression>> stops_) + : Expression(Kind::Interpolate, type_), + interpolator(std::move(interpolator_)), + input(std::move(input_)), + stops(std::move(stops_)) { + assert(input->getType() == type::Number); +} + +std::vector<optional<Value>> Interpolate::possibleOutputs() const { std::vector<optional<Value>> result; for (const auto& stop : stops) { for (auto& output : stop.second->possibleOutputs()) { @@ -216,8 +281,7 @@ std::vector<optional<Value>> InterpolateBase::possibleOutputs() const { return result; } -template <typename T> -mbgl::Value Interpolate<T>::serialize() const { +mbgl::Value Interpolate::serialize() const { std::vector<mbgl::Value> serialized; serialized.emplace_back(getOperator()); diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp index 0ebb37faa9..3b1f1aba8c 100644 --- a/src/mbgl/style/expression/is_constant.cpp +++ b/src/mbgl/style/expression/is_constant.cpp @@ -1,17 +1,25 @@ #include <mbgl/style/expression/is_constant.hpp> +#include <mbgl/style/expression/collator_expression.hpp> + namespace mbgl { namespace style { namespace expression { +constexpr static const char filter[] = "filter-"; + bool isFeatureConstant(const Expression& expression) { - if (auto e = dynamic_cast<const CompoundExpressionBase*>(&expression)) { + if (expression.getKind() == Kind::CompoundExpression) { + auto e = static_cast<const CompoundExpressionBase*>(&expression); const std::string name = e->getName(); optional<std::size_t> parameterCount = e->getParameterCount(); if (name == "get" && parameterCount && *parameterCount == 1) { return false; } else if (name == "has" && parameterCount && *parameterCount == 1) { return false; + } else if (std::equal(std::begin(filter), std::end(filter) - 1, name.begin())) { + // Legacy filters begin with "filter-" and are never constant. + return false; } else if ( name == "properties" || name == "geometry-type" || @@ -20,6 +28,13 @@ bool isFeatureConstant(const Expression& expression) { return false; } } + + if (expression.getKind() == Kind::CollatorExpression) { + // Although the results of a Collator expression with fixed arguments + // generally shouldn't change between executions, we can't serialize them + // as constant expressions because results change based on environment. + return false; + } bool featureConstant = true; expression.eachChild([&](const Expression& e) { diff --git a/src/mbgl/style/expression/length.cpp b/src/mbgl/style/expression/length.cpp index 258353ae4e..ad7a15675a 100644 --- a/src/mbgl/style/expression/length.cpp +++ b/src/mbgl/style/expression/length.cpp @@ -6,7 +6,7 @@ namespace style { namespace expression { Length::Length(std::unique_ptr<Expression> input_) - : Expression(type::Number), + : Expression(Kind::Length, type::Number), input(std::move(input_)) { } @@ -30,7 +30,8 @@ void Length::eachChild(const std::function<void(const Expression&)>& visit) cons } bool Length::operator==(const Expression& e) const { - if (auto eq = dynamic_cast<const Length*>(&e)) { + if (e.getKind() == Kind::Length) { + auto eq = static_cast<const Length*>(&e); return *eq->input == *input; } return false; diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 8a63980dba..345a52de9b 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -113,4 +113,3 @@ mbgl::Value Literal::serialize() const { } // namespace expression } // namespace style } // namespace mbgl - diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 3d41f0bdd3..4b4984811f 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -18,7 +18,8 @@ void Match<T>::eachChild(const std::function<void(const Expression&)>& visit) co template <typename T> bool Match<T>::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Match*>(&e)) { + if (e.getKind() == Kind::Match) { + auto rhs = static_cast<const Match*>(&e); return (*input == *(rhs->input) && *otherwise == *(rhs->otherwise) && Expression::childrenEqual(branches, rhs->branches)); @@ -83,6 +84,10 @@ template<> EvaluationResult Match<std::string>::evaluate(const EvaluationContext return inputValue.error(); } + if (!inputValue->is<std::string>()) { + return otherwise->evaluate(params); + } + auto it = branches.find(inputValue->get<std::string>()); if (it != branches.end()) { return (*it).second->evaluate(params); @@ -96,7 +101,11 @@ template<> EvaluationResult Match<int64_t>::evaluate(const EvaluationContext& pa if (!inputValue) { return inputValue.error(); } - + + if (!inputValue->is<double>()) { + return otherwise->evaluate(params); + } + const auto numeric = inputValue->get<double>(); int64_t rounded = std::floor(numeric); if (numeric == rounded) { @@ -129,7 +138,7 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext& pa parentContext.error("Branch labels must be integers no larger than " + util::toString(Value::maxSafeInteger()) + ".", index); } else { type = {type::Number}; - result = {static_cast<int64_t>(n)}; + result = optional<InputType>{static_cast<int64_t>(n)}; } }, [&] (int64_t n) { @@ -137,7 +146,7 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext& pa parentContext.error("Branch labels must be integers no larger than " + util::toString(Value::maxSafeInteger()) + ".", index); } else { type = {type::Number}; - result = {n}; + result = optional<InputType>{n}; } }, [&] (double n) { @@ -147,7 +156,7 @@ optional<InputType> parseInputValue(const Convertible& input, ParsingContext& pa parentContext.error("Numeric branch labels must be integer values.", index); } else { type = {type::Number}; - result = {static_cast<int64_t>(n)}; + result = optional<InputType>{static_cast<int64_t>(n)}; } }, [&] (const std::string& s) { @@ -280,7 +289,7 @@ ParseResult parseMatch(const Convertible& value, ParsingContext& ctx) { branches.push_back(std::make_pair(std::move(labels), std::move(*output))); } - auto input = ctx.parse(arrayMember(value, 1), 1, inputType); + auto input = ctx.parse(arrayMember(value, 1), 1, {type::Value}); if (!input) { return ParseResult(); } @@ -292,6 +301,12 @@ ParseResult parseMatch(const Convertible& value, ParsingContext& ctx) { assert(inputType && outputType); + optional<std::string> err; + if ((*input)->getType() != type::Value && (err = type::checkSubtype(*inputType, (*input)->getType()))) { + ctx.error(*err, 1); + return ParseResult(); + } + return inputType->match( [&](const type::NumberType&) { return create<int64_t>(*outputType, std::move(*input), std::move(branches), std::move(*otherwise), ctx); diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index b522aeff9a..a4c04b03b1 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -32,19 +32,21 @@ namespace style { namespace expression { bool isConstant(const Expression& expression) { - if (auto varExpression = dynamic_cast<const Var*>(&expression)) { + if (expression.getKind() == Kind::Var) { + auto varExpression = static_cast<const Var*>(&expression); return isConstant(*varExpression->getBoundExpression()); } - if (auto compound = dynamic_cast<const CompoundExpressionBase*>(&expression)) { + if (expression.getKind() == Kind::CompoundExpression) { + auto compound = static_cast<const CompoundExpressionBase*>(&expression); if (compound->getName() == "error") { return false; } } - bool isTypeAnnotation = dynamic_cast<const Coercion*>(&expression) || - dynamic_cast<const Assertion*>(&expression) || - dynamic_cast<const ArrayAssertion*>(&expression); + bool isTypeAnnotation = expression.getKind() == Kind::Coercion || + expression.getKind() == Kind::Assertion || + expression.getKind() == Kind::ArrayAssertion; bool childrenConstant = true; expression.eachChild([&](const Expression& child) { @@ -58,7 +60,7 @@ bool isConstant(const Expression& expression) { if (isTypeAnnotation) { childrenConstant = childrenConstant && isConstant(child); } else { - childrenConstant = childrenConstant && dynamic_cast<const Literal*>(&child); + childrenConstant = childrenConstant && child.getKind() == Kind::Literal; } }); if (!childrenConstant) { @@ -102,6 +104,7 @@ const ExpressionRegistry& getExpressionRegistry() { {"boolean", Assertion::parse}, {"case", Case::parse}, {"coalesce", Coalesce::parse}, + {"collator", CollatorExpression::parse}, {"interpolate", parseInterpolate}, {"length", Length::parse}, {"let", Let::parse}, @@ -185,7 +188,7 @@ ParseResult ParsingContext::parse(const Convertible& value, TypeAnnotationOption // If an expression's arguments are all constant, we can evaluate // it immediately and replace it with a literal value in the // parsed result. - if (!dynamic_cast<Literal *>(parsed->get()) && isConstant(**parsed)) { + if ((*parsed)->getKind() != Kind::Literal && isConstant(**parsed)) { EvaluationContext params(nullptr); EvaluationResult evaluated((*parsed)->evaluate(params)); if (!evaluated) { @@ -216,7 +219,7 @@ ParseResult ParsingContext::parseExpression(const Convertible& value, TypeAnnota ParseResult ParsingContext::parseLayerPropertyExpression(const Convertible& value, TypeAnnotationOption typeAnnotationOption) { ParseResult parsed = parse(value, typeAnnotationOption); if (parsed && !isZoomConstant(**parsed)) { - optional<variant<const InterpolateBase*, const Step*, ParsingError>> zoomCurve = findZoomCurve(parsed->get()); + optional<variant<const Interpolate*, const Step*, ParsingError>> zoomCurve = findZoomCurve(parsed->get()); if (!zoomCurve) { error(R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)"); return ParseResult(); diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index ddaf9417cb..a1ca0a702e 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -8,6 +8,16 @@ namespace mbgl { namespace style { namespace expression { +Step::Step(const type::Type& type_, + std::unique_ptr<Expression> input_, + std::map<double, std::unique_ptr<Expression>> stops_) + : Expression(Kind::Step, type_), + input(std::move(input_)), + stops(std::move(stops_)) +{ + assert(input->getType() == type::Number); +} + EvaluationResult Step::evaluate(const EvaluationContext& params) const { const EvaluationResult evaluatedInput = input->evaluate(params); if (!evaluatedInput) { @@ -47,7 +57,8 @@ void Step::eachStop(const std::function<void(double, const Expression&)>& visit) } bool Step::operator==(const Expression& e) const { - if (auto rhs = dynamic_cast<const Step*>(&e)) { + if (e.getKind() == Kind::Step) { + auto rhs = static_cast<const Step*>(&e); return *input == *(rhs->input) && Expression::childrenEqual(stops, rhs->stops); } return false; @@ -116,23 +127,23 @@ ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, Parsi labelValue->match( [&](uint64_t n) { if (n > std::numeric_limits<double>::max()) { - label = {std::numeric_limits<double>::infinity()}; + label = optional<double>{std::numeric_limits<double>::infinity()}; } else { - label = {static_cast<double>(n)}; + label = optional<double>{static_cast<double>(n)}; } }, [&](int64_t n) { if (n > std::numeric_limits<double>::max()) { - label = {std::numeric_limits<double>::infinity()}; + label = optional<double>{std::numeric_limits<double>::infinity()}; } else { - label = {static_cast<double>(n)}; + label = optional<double>{static_cast<double>(n)}; } }, [&](double n) { if (n > std::numeric_limits<double>::max()) { - label = {std::numeric_limits<double>::infinity()}; + label = optional<double>{std::numeric_limits<double>::infinity()}; } else { - label = {static_cast<double>(n)}; + label = optional<double>{n}; } }, [&](const auto&) {} diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index 1b3257c755..ddf1ff0ca4 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -12,6 +12,7 @@ type::Type typeOf(const Value& value) { [&](double) -> type::Type { return type::Number; }, [&](const std::string&) -> type::Type { return type::String; }, [&](const Color&) -> type::Type { return type::Color; }, + [&](const Collator&) -> type::Type { return type::Collator; }, [&](const NullValue&) -> type::Type { return type::Null; }, [&](const std::unordered_map<std::string, Value>&) -> type::Type { return type::Object; }, [&](const std::vector<Value>& arr) -> type::Type { @@ -43,6 +44,11 @@ void writeJSON(rapidjson::Writer<rapidjson::StringBuffer>& writer, const Value& }, [&] (const std::string& s) { writer.String(s); }, [&] (const Color& c) { writer.String(c.stringify()); }, + [&] (const Collator&) { + // Collators are excluded from constant folding and there's no Literal parser + // for them so there shouldn't be any way to serialize this value. + assert(false); + }, [&] (const std::vector<Value>& arr) { writer.StartArray(); for(const auto& item : arr) { @@ -115,6 +121,12 @@ mbgl::Value ValueConverter<mbgl::Value>::fromExpressionValue(const Value& value) array[3], }; }, + [&](const Collator&)->mbgl::Value { + // fromExpressionValue can't be used for Collator values, + // because they have no meaningful representation as an mbgl::Value + assert(false); + return mbgl::Value(); + }, [&](const std::vector<Value>& values)->mbgl::Value { std::vector<mbgl::Value> converted; converted.reserve(values.size()); @@ -229,27 +241,6 @@ optional<T> ValueConverter<T, std::enable_if_t< std::is_enum<T>::value >>::fromE ); } - -Value toExpressionValue(const Value& v) { - return v; -} - -template <typename T, typename Enable> -Value toExpressionValue(const T& value) { - return ValueConverter<T>::toExpressionValue(value); -} - -optional<Value> fromExpressionValue(const Value& v) { - return optional<Value>(v); -} - -template <typename T> -std::enable_if_t< !std::is_convertible<T, Value>::value, -optional<T>> fromExpressionValue(const Value& v) -{ - return ValueConverter<T>::fromExpressionValue(v); -} - template <typename T> type::Type valueTypeToExpressionType() { return ValueConverter<T>::expressionType(); @@ -261,6 +252,7 @@ template <> type::Type valueTypeToExpressionType<bool>() { return type::Boolean; template <> type::Type valueTypeToExpressionType<double>() { return type::Number; } template <> type::Type valueTypeToExpressionType<std::string>() { return type::String; } template <> type::Type valueTypeToExpressionType<Color>() { return type::Color; } +template <> type::Type valueTypeToExpressionType<Collator>() { return type::Collator; } template <> type::Type valueTypeToExpressionType<std::unordered_map<std::string, Value>>() { return type::Object; } template <> type::Type valueTypeToExpressionType<std::vector<Value>>() { return type::Array(type::Value); } @@ -268,86 +260,64 @@ template <> type::Type valueTypeToExpressionType<std::vector<Value>>() { return template <> type::Type valueTypeToExpressionType<type::ErrorType>() { return type::Error; } -template Value toExpressionValue(const mbgl::Value&); -template optional<mbgl::Value> fromExpressionValue<mbgl::Value>(const Value&); - // for to_rgba expression template type::Type valueTypeToExpressionType<std::array<double, 4>>(); -template optional<std::array<double, 4>> fromExpressionValue<std::array<double, 4>>(const Value&); -template Value toExpressionValue(const std::array<double, 4>&); +template struct ValueConverter<std::array<double, 4>>; // layout/paint property types template type::Type valueTypeToExpressionType<float>(); -template optional<float> fromExpressionValue<float>(const Value&); -template Value toExpressionValue(const float&); +template type::Type valueTypeToExpressionType<Position>(); template type::Type valueTypeToExpressionType<std::array<float, 2>>(); -template optional<std::array<float, 2>> fromExpressionValue<std::array<float, 2>>(const Value&); -template Value toExpressionValue(const std::array<float, 2>&); +template struct ValueConverter<std::array<float, 2>>; template type::Type valueTypeToExpressionType<std::array<float, 4>>(); -template optional<std::array<float, 4>> fromExpressionValue<std::array<float, 4>>(const Value&); -template Value toExpressionValue(const std::array<float, 4>&); +template struct ValueConverter<std::array<float, 4>>; template type::Type valueTypeToExpressionType<std::vector<float>>(); -template optional<std::vector<float>> fromExpressionValue<std::vector<float>>(const Value&); -template Value toExpressionValue(const std::vector<float>&); +template struct ValueConverter<std::vector<float>>; template type::Type valueTypeToExpressionType<std::vector<std::string>>(); -template optional<std::vector<std::string>> fromExpressionValue<std::vector<std::string>>(const Value&); -template Value toExpressionValue(const std::vector<std::string>&); +template struct ValueConverter<std::vector<std::string>>; template type::Type valueTypeToExpressionType<AlignmentType>(); -template optional<AlignmentType> fromExpressionValue<AlignmentType>(const Value&); -template Value toExpressionValue(const AlignmentType&); +template struct ValueConverter<AlignmentType>; template type::Type valueTypeToExpressionType<CirclePitchScaleType>(); -template optional<CirclePitchScaleType> fromExpressionValue<CirclePitchScaleType>(const Value&); -template Value toExpressionValue(const CirclePitchScaleType&); +template struct ValueConverter<CirclePitchScaleType>; template type::Type valueTypeToExpressionType<IconTextFitType>(); -template optional<IconTextFitType> fromExpressionValue<IconTextFitType>(const Value&); -template Value toExpressionValue(const IconTextFitType&); +template struct ValueConverter<IconTextFitType>; template type::Type valueTypeToExpressionType<LineCapType>(); -template optional<LineCapType> fromExpressionValue<LineCapType>(const Value&); -template Value toExpressionValue(const LineCapType&); +template struct ValueConverter<LineCapType>; template type::Type valueTypeToExpressionType<LineJoinType>(); -template optional<LineJoinType> fromExpressionValue<LineJoinType>(const Value&); -template Value toExpressionValue(const LineJoinType&); +template struct ValueConverter<LineJoinType>; template type::Type valueTypeToExpressionType<SymbolPlacementType>(); -template optional<SymbolPlacementType> fromExpressionValue<SymbolPlacementType>(const Value&); -template Value toExpressionValue(const SymbolPlacementType&); +template struct ValueConverter<SymbolPlacementType>; template type::Type valueTypeToExpressionType<SymbolAnchorType>(); -template optional<SymbolAnchorType> fromExpressionValue<SymbolAnchorType>(const Value&); -template Value toExpressionValue(const SymbolAnchorType&); +template struct ValueConverter<SymbolAnchorType>; template type::Type valueTypeToExpressionType<TextJustifyType>(); -template optional<TextJustifyType> fromExpressionValue<TextJustifyType>(const Value&); -template Value toExpressionValue(const TextJustifyType&); +template struct ValueConverter<TextJustifyType>; template type::Type valueTypeToExpressionType<TextTransformType>(); -template optional<TextTransformType> fromExpressionValue<TextTransformType>(const Value&); -template Value toExpressionValue(const TextTransformType&); +template struct ValueConverter<TextTransformType>; template type::Type valueTypeToExpressionType<TranslateAnchorType>(); -template optional<TranslateAnchorType> fromExpressionValue<TranslateAnchorType>(const Value&); -template Value toExpressionValue(const TranslateAnchorType&); +template struct ValueConverter<TranslateAnchorType>; + +template type::Type valueTypeToExpressionType<RasterResamplingType>(); +template struct ValueConverter<RasterResamplingType>; template type::Type valueTypeToExpressionType<HillshadeIlluminationAnchorType>(); -template optional<HillshadeIlluminationAnchorType> fromExpressionValue<HillshadeIlluminationAnchorType>(const Value&); -template Value toExpressionValue(const HillshadeIlluminationAnchorType&); +template struct ValueConverter<HillshadeIlluminationAnchorType>; template type::Type valueTypeToExpressionType<LightAnchorType>(); -template optional<LightAnchorType> fromExpressionValue<LightAnchorType>(const Value&); -template Value toExpressionValue(const LightAnchorType&); - -template type::Type valueTypeToExpressionType<Position>(); -template optional<Position> fromExpressionValue<Position>(const Value&); -template Value toExpressionValue(const Position&); +template struct ValueConverter<LightAnchorType>; } // namespace expression } // namespace style diff --git a/src/mbgl/style/filter.cpp b/src/mbgl/style/filter.cpp index 51aa6bcf82..18b8b0a7f4 100644 --- a/src/mbgl/style/filter.cpp +++ b/src/mbgl/style/filter.cpp @@ -1,12 +1,20 @@ #include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/tile/geometry_tile_data.hpp> namespace mbgl { namespace style { bool Filter::operator()(const expression::EvaluationContext &context) const { - return FilterBase::visit(*this, FilterEvaluator { context }); + + if (!this->expression) return true; + + const expression::EvaluationResult result = (*this->expression)->evaluate(context); + if (result) { + const optional<bool> typed = expression::fromExpressionValue<bool>(*result); + return typed ? *typed : false; + } else { + return false; + } } } // namespace style diff --git a/src/mbgl/style/filter_evaluator.cpp b/src/mbgl/style/filter_evaluator.cpp deleted file mode 100644 index 72022172f4..0000000000 --- a/src/mbgl/style/filter_evaluator.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> - -namespace mbgl { -namespace style { - -template <class Op> -struct Comparator { - const Op& op; - - template <class T> - bool operator()(const T& lhs, const T& rhs) const { - return op(lhs, rhs); - } - - template <class T0, class T1> - auto operator()(const T0& lhs, const T1& rhs) const - -> typename std::enable_if_t<std::is_arithmetic<T0>::value && !std::is_same<T0, bool>::value && - std::is_arithmetic<T1>::value && !std::is_same<T1, bool>::value, bool> { - return op(double(lhs), double(rhs)); - } - - template <class T0, class T1> - auto operator()(const T0&, const T1&) const - -> typename std::enable_if_t<!std::is_arithmetic<T0>::value || std::is_same<T0, bool>::value || - !std::is_arithmetic<T1>::value || std::is_same<T1, bool>::value, bool> { - return false; - } - - bool operator()(const NullValue&, - const NullValue&) const { - // Should be unreachable; null is not currently allowed by the style specification. - assert(false); - return false; - } - - bool operator()(const std::vector<Value>&, - const std::vector<Value>&) const { - // Should be unreachable; nested values are not currently allowed by the style specification. - assert(false); - return false; - } - - bool operator()(const PropertyMap&, - const PropertyMap&) const { - // Should be unreachable; nested values are not currently allowed by the style specification. - assert(false); - return false; - } -}; - -template <class Op> -bool compare(const Value& lhs, const Value& rhs, const Op& op) { - return Value::binary_visit(lhs, rhs, Comparator<Op> { op }); -} - -bool equal(const Value& lhs, const Value& rhs) { - return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; }); -} - -bool FilterEvaluator::operator()(const NullFilter&) const { - return true; -} - -bool FilterEvaluator::operator()(const EqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && equal(*actual, filter.value); -} - -bool FilterEvaluator::operator()(const NotEqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return !actual || !equal(*actual, filter.value); -} - -bool FilterEvaluator::operator()(const LessThanFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; }); -} - -bool FilterEvaluator::operator()(const LessThanEqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; }); -} - -bool FilterEvaluator::operator()(const GreaterThanFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; }); -} - -bool FilterEvaluator::operator()(const GreaterThanEqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; }); -} - -bool FilterEvaluator::operator()(const InFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - if (!actual) - return false; - for (const auto& v: filter.values) { - if (equal(*actual, v)) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const NotInFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - if (!actual) - return true; - for (const auto& v: filter.values) { - if (equal(*actual, v)) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const AnyFilter& filter) const { - for (const auto& f: filter.filters) { - if (Filter::visit(f, *this)) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const AllFilter& filter) const { - for (const auto& f: filter.filters) { - if (!Filter::visit(f, *this)) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const NoneFilter& filter) const { - for (const auto& f: filter.filters) { - if (Filter::visit(f, *this)) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const HasFilter& filter) const { - return bool(context.feature->getValue(filter.key)); -} - -bool FilterEvaluator::operator()(const NotHasFilter& filter) const { - return !context.feature->getValue(filter.key); -} - -bool FilterEvaluator::operator()(const TypeEqualsFilter& filter) const { - return context.feature->getType() == filter.value; -} - -bool FilterEvaluator::operator()(const TypeNotEqualsFilter& filter) const { - return context.feature->getType() != filter.value; -} - -bool FilterEvaluator::operator()(const TypeInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getType() == v) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const TypeNotInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getType() == v) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const IdentifierEqualsFilter& filter) const { - return context.feature->getID() == filter.value; -} - -bool FilterEvaluator::operator()(const IdentifierNotEqualsFilter& filter) const { - return context.feature->getID() != filter.value; -} - -bool FilterEvaluator::operator()(const IdentifierInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getID() == v) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const IdentifierNotInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getID() == v) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const HasIdentifierFilter&) const { - return bool(context.feature->getID()); -} - -bool FilterEvaluator::operator()(const NotHasIdentifierFilter&) const { - return !context.feature->getID(); -} - -bool FilterEvaluator::operator()(const ExpressionFilter& filter) const { - const expression::EvaluationResult result = filter.expression->evaluate(context); - if (result) { - const optional<bool> typed = expression::fromExpressionValue<bool>(*result); - return typed ? *typed : false; - } - return false; -} - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp deleted file mode 100644 index dd179f5376..0000000000 --- a/src/mbgl/style/function/categorical_stops.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include <mbgl/style/function/categorical_stops.hpp> -#include <mbgl/style/types.hpp> -#include <mbgl/util/color.hpp> - -#include <array> - -namespace mbgl { -namespace style { - -optional<CategoricalValue> categoricalValue(const Value& value) { - return value.match( - [] (bool t) { return optional<CategoricalValue>(t); }, - [] (uint64_t t) { return optional<CategoricalValue>(int64_t(t)); }, - [] (int64_t t) { return optional<CategoricalValue>(t); }, - [] (double t) { return optional<CategoricalValue>(int64_t(t)); }, - [] (const std::string& t) { return optional<CategoricalValue>(t); }, - [] (const auto&) { return optional<CategoricalValue>(); } - ); -} - -template <class T> -optional<T> CategoricalStops<T>::evaluate(const Value& value) const { - auto v = categoricalValue(value); - if (!v) { - return {}; - } - auto it = stops.find(*v); - return it == stops.end() ? optional<T>() : it->second; -} - -template class CategoricalStops<float>; -template class CategoricalStops<Color>; -template class CategoricalStops<std::array<float, 2>>; -template class CategoricalStops<std::string>; -template class CategoricalStops<TextTransformType>; -template class CategoricalStops<TextJustifyType>; -template class CategoricalStops<SymbolAnchorType>; -template class CategoricalStops<LineJoinType>; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp deleted file mode 100644 index 0ac6fda846..0000000000 --- a/src/mbgl/style/function/identity_stops.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include <mbgl/style/function/identity_stops.hpp> -#include <mbgl/style/types.hpp> -#include <mbgl/util/enum.hpp> -#include <mbgl/util/color.hpp> - -#include <array> - -namespace mbgl { -namespace style { - -template <> -optional<float> IdentityStops<float>::evaluate(const Value& value) const { - return numericValue<float>(value); -} - -template <> -optional<std::string> IdentityStops<std::string>::evaluate(const Value& value) const { - if (!value.is<std::string>()) { - return {}; - } - - return value.get<std::string>(); -} - -template <> -optional<Color> IdentityStops<Color>::evaluate(const Value& value) const { - if (!value.is<std::string>()) { - return {}; - } - - return Color::parse(value.get<std::string>()); -} - -template <> -optional<TextTransformType> IdentityStops<TextTransformType>::evaluate(const Value& value) const { - if (!value.is<std::string>()) { - return {}; - } - - return Enum<TextTransformType>::toEnum(value.get<std::string>()); -} - -template <> -optional<TextJustifyType> IdentityStops<TextJustifyType>::evaluate(const Value& value) const { - if (!value.is<std::string>()) { - return {}; - } - - return Enum<TextJustifyType>::toEnum(value.get<std::string>()); -} - -template <> -optional<SymbolAnchorType> IdentityStops<SymbolAnchorType>::evaluate(const Value& value) const { - if (!value.is<std::string>()) { - return {}; - } - - return Enum<SymbolAnchorType>::toEnum(value.get<std::string>()); -} - -template <> -optional<LineJoinType> IdentityStops<LineJoinType>::evaluate(const Value& value) const { - if (!value.is<std::string>()) { - return {}; - } - - return Enum<LineJoinType>::toEnum(value.get<std::string>()); -} - -template <> -optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const { - if (!value.is<std::vector<Value>>()) { - return {}; - } - - const auto& vector = value.get<std::vector<Value>>(); - if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) { - return {}; - } - - std::array<float, 2> array {{ - *numericValue<float>(vector[0]), - *numericValue<float>(vector[1]) - }}; - return array; -} - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 3f7881ddd3..c2a1545a00 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -5,8 +5,8 @@ #include <mbgl/style/layer_observer.hpp> // for constructing default heatmap-color ramp expression from style JSON #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/color_ramp_property_value.hpp> #include <mbgl/style/conversion/json.hpp> -#include <mbgl/style/conversion/heatmap_color_property_value.hpp> namespace mbgl { namespace style { @@ -181,17 +181,17 @@ TransitionOptions HeatmapLayer::getHeatmapIntensityTransition() const { return impl().paint.template get<HeatmapIntensity>().options; } -HeatmapColorPropertyValue HeatmapLayer::getDefaultHeatmapColor() { +ColorRampPropertyValue HeatmapLayer::getDefaultHeatmapColor() { conversion::Error error; std::string rawValue = R"JSON(["interpolate",["linear"],["heatmap-density"],0,"rgba(0, 0, 255, 0)",0.1,"royalblue",0.3,"cyan",0.5,"lime",0.7,"yellow",1,"red"])JSON"; - return *conversion::convertJSON<HeatmapColorPropertyValue>(rawValue, error); + return *conversion::convertJSON<ColorRampPropertyValue>(rawValue, error); } -HeatmapColorPropertyValue HeatmapLayer::getHeatmapColor() const { +ColorRampPropertyValue HeatmapLayer::getHeatmapColor() const { return impl().paint.template get<HeatmapColor>().value; } -void HeatmapLayer::setHeatmapColor(HeatmapColorPropertyValue value) { +void HeatmapLayer::setHeatmapColor(ColorRampPropertyValue value) { if (value == getHeatmapColor()) return; auto impl_ = mutableImpl(); diff --git a/src/mbgl/style/layers/heatmap_layer_properties.hpp b/src/mbgl/style/layers/heatmap_layer_properties.hpp index f7afa5fbeb..fe7257a78a 100644 --- a/src/mbgl/style/layers/heatmap_layer_properties.hpp +++ b/src/mbgl/style/layers/heatmap_layer_properties.hpp @@ -24,6 +24,8 @@ struct HeatmapIntensity : PaintProperty<float> { static float defaultValue() { return 1; } }; +using HeatmapColor = ColorRampProperty; + struct HeatmapOpacity : PaintProperty<float> { static float defaultValue() { return 1; } }; diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs new file mode 100644 index 0000000000..a9b6d9d02d --- /dev/null +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -0,0 +1,179 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> +#include <mbgl/style/layer_observer.hpp> +<% if (type === 'heatmap') { -%> +// for constructing default heatmap-color ramp expression from style JSON +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/color_ramp_property_value.hpp> +#include <mbgl/style/conversion/json.hpp> +<% } -%> + +namespace mbgl { +namespace style { + +<% if (type === 'background') { -%> +<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID) + : Layer(makeMutable<Impl>(LayerType::<%- camelize(type) %>, layerID, std::string())) { +} +<% } else { -%> +<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID) + : Layer(makeMutable<Impl>(LayerType::<%- camelize(type) %>, layerID, sourceID)) { +} +<% } -%> + +<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { +} + +<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default; + +const <%- camelize(type) %>Layer::Impl& <%- camelize(type) %>Layer::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +Mutable<<%- camelize(type) %>Layer::Impl> <%- camelize(type) %>Layer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> <%- camelize(type) %>Layer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = <%- camelize(type) %>PaintProperties::Transitionable(); + return std::make_unique<<%- camelize(type) %>Layer>(std::move(impl_)); +} + +<% if (layoutProperties.length) { -%> +void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const { + layout.stringify(writer); +} +<% } else { -%> +void <%- camelize(type) %>Layer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { +} +<% } -%> + +<% if (type !== 'background') { -%> +// Source + +const std::string& <%- camelize(type) %>Layer::getSourceID() const { + return impl().source; +} + +<% if (type !== 'raster' && type !== 'hillshade') { -%> +void <%- camelize(type) %>Layer::setSourceLayer(const std::string& sourceLayer) { + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); +} + +const std::string& <%- camelize(type) %>Layer::getSourceLayer() const { + return impl().sourceLayer; +} + +// Filter + +void <%- camelize(type) %>Layer::setFilter(const Filter& filter) { + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +const Filter& <%- camelize(type) %>Layer::getFilter() const { + return impl().filter; +} +<% } -%> +<% } -%> + +// Visibility + +void <%- camelize(type) %>Layer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void <%- camelize(type) %>Layer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void <%- camelize(type) %>Layer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Layout properties + +<% for (const property of layoutProperties) { -%> +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { + return <%- camelize(property.name) %>::defaultValue(); +} + +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { + return impl().layout.get<<%- camelize(property.name) %>>(); +} + +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) { + if (value == get<%- camelize(property.name) %>()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get<<%- camelize(property.name) %>>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +<% } -%> + +// Paint properties +<% for (const property of paintProperties) { %> +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { +<% if (property.name === 'heatmap-color') { -%> + conversion::Error error; + std::string rawValue = R"JSON(<%- JSON.stringify(property.default) %>)JSON"; + return *conversion::convertJSON<<%- propertyValueType(property)%>>(rawValue, error); +<% } else { -%> + return { <%- defaultValue(property) %> }; +<% } -%> +} + +<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { + return impl().paint.template get<<%- camelize(property.name) %>>().value; +} + +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) { + if (value == get<%- camelize(property.name) %>()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<<%- camelize(property.name) %>>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<<%- camelize(property.name) %>>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition() const { + return impl().paint.template get<<%- camelize(property.name) %>>().options; +} +<% } -%> + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/layer_properties.cpp.ejs b/src/mbgl/style/layers/layer_properties.cpp.ejs new file mode 100644 index 0000000000..e5523e5439 --- /dev/null +++ b/src/mbgl/style/layers/layer_properties.cpp.ejs @@ -0,0 +1,14 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_properties.hpp> + +namespace mbgl { +namespace style { + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs new file mode 100644 index 0000000000..5b774933a6 --- /dev/null +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -0,0 +1,54 @@ +<% + const type = locals.type; + const layoutProperties = locals.layoutProperties; + const paintProperties = locals.paintProperties; +-%> +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#pragma once + +#include <mbgl/style/types.hpp> +#include <mbgl/style/layout_property.hpp> +#include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> + +namespace mbgl { +namespace style { + +<% for (const property of layoutProperties) { -%> +struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) %> { + static constexpr const char * key = "<%- property.name %>"; + static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } +}; + +<% } -%> +<% for (const property of paintProperties) { -%> +<% if (property['property-type'] === 'color-ramp') { -%> +using <%- camelize(property.name) %> = ColorRampProperty; +<% } else { -%> +struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> { + static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } +}; +<% } -%> + +<% } -%> +<% if (layoutProperties.length) { -%> +class <%- camelize(type) %>LayoutProperties : public Properties< +<% for (const property of layoutProperties.slice(0, -1)) { -%> + <%- camelize(property.name) %>, +<% } -%> + <%- camelize(layoutProperties.slice(-1)[0].name) %> +> {}; + +<% } -%> +class <%- camelize(type) %>PaintProperties : public Properties< +<% for (const property of paintProperties.slice(0, -1)) { -%> + <%- camelize(property.name) %>, +<% } -%> + <%- camelize(paintProperties.slice(-1)[0].name) %> +> {}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 36b2e3e027..e5b03df0f6 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -236,6 +236,33 @@ TransitionOptions RasterLayer::getRasterContrastTransition() const { return impl().paint.template get<RasterContrast>().options; } +PropertyValue<RasterResamplingType> RasterLayer::getDefaultRasterResampling() { + return { RasterResamplingType::Linear }; +} + +PropertyValue<RasterResamplingType> RasterLayer::getRasterResampling() const { + return impl().paint.template get<RasterResampling>().value; +} + +void RasterLayer::setRasterResampling(PropertyValue<RasterResamplingType> value) { + if (value == getRasterResampling()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterResampling>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void RasterLayer::setRasterResamplingTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<RasterResampling>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions RasterLayer::getRasterResamplingTransition() const { + return impl().paint.template get<RasterResampling>().options; +} + PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() { return { 300 }; } diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp index 12df09f32c..08818c9fb3 100644 --- a/src/mbgl/style/layers/raster_layer_properties.hpp +++ b/src/mbgl/style/layers/raster_layer_properties.hpp @@ -36,6 +36,10 @@ struct RasterContrast : PaintProperty<float> { static float defaultValue() { return 0; } }; +struct RasterResampling : PaintProperty<RasterResamplingType> { + static RasterResamplingType defaultValue() { return RasterResamplingType::Linear; } +}; + struct RasterFadeDuration : PaintProperty<float> { static float defaultValue() { return 300; } }; @@ -47,6 +51,7 @@ class RasterPaintProperties : public Properties< RasterBrightnessMax, RasterSaturation, RasterContrast, + RasterResampling, RasterFadeDuration > {}; diff --git a/src/mbgl/style/light.cpp.ejs b/src/mbgl/style/light.cpp.ejs new file mode 100644 index 0000000000..45241c60fd --- /dev/null +++ b/src/mbgl/style/light.cpp.ejs @@ -0,0 +1,60 @@ +<% + const properties = locals.properties; +-%> +// This file is generated. Do not edit. + +#include <mbgl/style/light.hpp> +#include <mbgl/style/light_impl.hpp> +#include <mbgl/style/light_observer.hpp> + +namespace mbgl { +namespace style { + +static LightObserver nullObserver; + +Light::Light() + : impl(makeMutable<Impl>()), + observer(&nullObserver) { +} + +Light::~Light() = default; + +void Light::setObserver(LightObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + +Mutable<Light::Impl> Light::mutableImpl() const { + return makeMutable<Impl>(*impl); +} + +<% for (const property of properties) { -%> +<%- evaluatedType(property) %> Light::getDefault<%- camelize(property.name) %>() { + return Light<%- camelize(property.name) %>::defaultValue(); +} + +<%- propertyValueType(property) %> Light::get<%- camelize(property.name) %>() const { + return impl->properties.template get<Light<%- camelize(property.name) %>>().value; +} + +void Light::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> property) { + auto impl_ = mutableImpl(); + impl_->properties.template get<Light<%- camelize(property.name) %>>().value = property; + impl = std::move(impl_); + observer->onLightChanged(*this); +} + +void Light::set<%- camelize(property.name) %>Transition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->properties.template get<Light<%- camelize(property.name) %>>().options = options; + impl = std::move(impl_); + observer->onLightChanged(*this); +} + +TransitionOptions Light::get<%- camelize(property.name) %>Transition() const { + return impl->properties.template get<Light<%- camelize(property.name) %>>().options; +} + +<% } -%> + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index 195eb645a9..d51a6760c5 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -1,8 +1,8 @@ #pragma once +#include <mbgl/style/color_ramp_property_value.hpp> #include <mbgl/style/properties.hpp> #include <mbgl/style/property_value.hpp> -#include <mbgl/style/heatmap_color_property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/renderer/property_evaluator.hpp> #include <mbgl/renderer/cross_faded_property_evaluator.hpp> @@ -50,19 +50,19 @@ public: }; /* - * Special-case paint property traits for heatmap-color, needed because - * heatmap-color values do not fit into the + * Special-case paint property traits for heatmap-color and line-gradient, + * needed because these values do not fit into the * Undefined | Value | {Camera,Source,Composite}Function taxonomy that applies * to all other paint properties. * - * These traits are provided here--despite the fact that heatmap-color + * These traits are provided here--despite the fact that color ramps * is not used like other paint properties--to allow the parameter-pack-based * batch evaluation of paint properties to compile properly. */ -class HeatmapColor { +class ColorRampProperty { public: - using TransitionableType = Transitionable<HeatmapColorPropertyValue>; - using UnevaluatedType = Transitioning<HeatmapColorPropertyValue>; + using TransitionableType = Transitionable<ColorRampPropertyValue>; + using UnevaluatedType = Transitioning<ColorRampPropertyValue>; using EvaluatorType = PropertyEvaluator<Color>; using PossiblyEvaluatedType = Color; using Type = Color; diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp index dfcf7993a7..9206e96982 100644 --- a/src/mbgl/style/properties.hpp +++ b/src/mbgl/style/properties.hpp @@ -154,10 +154,7 @@ public: [&] (const T& t) { return t; }, - [&] (const SourceFunction<T>& t) { - return t.evaluate(feature, defaultValue); - }, - [&] (const CompositeFunction<T>& t) { + [&] (const PropertyExpression<T>& t) { return t.evaluate(z, feature, defaultValue); }); } diff --git a/src/mbgl/style/sources/custom_geometry_source.cpp b/src/mbgl/style/sources/custom_geometry_source.cpp index b37490a5ce..6ce7c1be11 100644 --- a/src/mbgl/style/sources/custom_geometry_source.cpp +++ b/src/mbgl/style/sources/custom_geometry_source.cpp @@ -30,15 +30,15 @@ void CustomGeometrySource::loadDescription(FileSource&) { void CustomGeometrySource::setTileData(const CanonicalTileID& tileID, const GeoJSON& data) { - loader->invoke(&CustomTileLoader::setTileData, tileID, data); + loader->self().invoke(&CustomTileLoader::setTileData, tileID, data); } void CustomGeometrySource::invalidateTile(const CanonicalTileID& tileID) { - loader->invoke(&CustomTileLoader::invalidateTile, tileID); + loader->self().invoke(&CustomTileLoader::invalidateTile, tileID); } void CustomGeometrySource::invalidateRegion(const LatLngBounds& bounds) { - loader->invoke(&CustomTileLoader::invalidateRegion, bounds, impl().getZoomRange()); + loader->self().invoke(&CustomTileLoader::invalidateRegion, bounds, impl().getZoomRange()); } } // namespace style diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp index bdfa20a047..46de0173de 100644 --- a/src/mbgl/style/types.cpp +++ b/src/mbgl/style/types.cpp @@ -25,6 +25,11 @@ MBGL_DEFINE_ENUM(TranslateAnchorType, { { TranslateAnchorType::Viewport, "viewport" }, }); +MBGL_DEFINE_ENUM(RasterResamplingType, { + { RasterResamplingType::Linear, "linear" }, + { RasterResamplingType::Nearest, "nearest" }, +}); + MBGL_DEFINE_ENUM(HillshadeIlluminationAnchorType, { { HillshadeIlluminationAnchorType::Map, "map" }, { HillshadeIlluminationAnchorType::Viewport, "viewport" }, @@ -57,6 +62,7 @@ MBGL_DEFINE_ENUM(LineJoinType, { MBGL_DEFINE_ENUM(SymbolPlacementType, { { SymbolPlacementType::Point, "point" }, { SymbolPlacementType::Line, "line" }, + { SymbolPlacementType::LineCenter, "line-center" }, }); MBGL_DEFINE_ENUM(SymbolAnchorType, { diff --git a/src/mbgl/text/collision_feature.cpp b/src/mbgl/text/collision_feature.cpp index 6d6f2aabc7..ac4dbff2af 100644 --- a/src/mbgl/text/collision_feature.cpp +++ b/src/mbgl/text/collision_feature.cpp @@ -1,5 +1,6 @@ #include <mbgl/text/collision_feature.hpp> #include <mbgl/util/math.hpp> +#include <mbgl/math/log2.hpp> namespace mbgl { @@ -15,7 +16,7 @@ CollisionFeature::CollisionFeature(const GeometryCoordinates& line, IndexedSubfeature indexedFeature_, const float overscaling) : indexedFeature(std::move(indexedFeature_)) - , alongLine(placement == style::SymbolPlacementType::Line) { + , alongLine(placement != style::SymbolPlacementType::Point) { if (top == 0 && bottom == 0 && left == 0 && right == 0) return; const float y1 = top * boxScale - padding; @@ -41,7 +42,8 @@ CollisionFeature::CollisionFeature(const GeometryCoordinates& line, void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoordinate& anchorPoint, const int segment, const float labelLength, const float boxSize, const float overscaling) { const float step = boxSize / 2; - const int nBoxes = std::floor(labelLength / step); + const int nBoxes = std::max(static_cast<int>(std::floor(labelLength / step)), 1); + // We calculate line collision circles out to 300% of what would normally be our // max size, to allow collision detection to work on labels that expand as // they move into the distance @@ -50,7 +52,7 @@ void CollisionFeature::bboxifyLabel(const GeometryCoordinates& line, GeometryCoo // symbol spacing will put labels very close together in a pitched map. // To reduce the cost of adding extra collision circles, we slowly increase // them for overscaled tiles. - const float overscalingPaddingFactor = 1 + .4 * std::log(overscaling) / std::log(2); + const float overscalingPaddingFactor = 1 + .4 * ::log2(static_cast<double>(overscaling)); const int nPitchPaddingBoxes = std::floor(nBoxes * overscalingPaddingFactor / 2); // offset the center of the first box by half a box so that the edge of the diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp index b0c3511ce3..98b9af1f94 100644 --- a/src/mbgl/text/cross_tile_symbol_index.cpp +++ b/src/mbgl/text/cross_tile_symbol_index.cpp @@ -61,6 +61,32 @@ void TileLayerIndex::findMatches(std::vector<SymbolInstance>& symbolInstances, c CrossTileSymbolLayerIndex::CrossTileSymbolLayerIndex() { } +/* + * Sometimes when a user pans across the antimeridian the longitude value gets wrapped. + * To prevent labels from flashing out and in we adjust the tileID values in the indexes + * so that they match the new wrapped version of the map. + */ +void CrossTileSymbolLayerIndex::handleWrapJump(float newLng) { + + const int wrapDelta = ::round((newLng - lng) / 360); + if (wrapDelta != 0) { + std::map<uint8_t, std::map<OverscaledTileID,TileLayerIndex>> newIndexes; + for (auto& zoomIndex : indexes) { + std::map<OverscaledTileID,TileLayerIndex> newZoomIndex; + for (auto& index : zoomIndex.second) { + // change the tileID's wrap and move its index + index.second.coord = index.second.coord.unwrapTo(index.second.coord.wrap + wrapDelta); + newZoomIndex.emplace(index.second.coord, std::move(index.second)); + } + newIndexes.emplace(zoomIndex.first, std::move(newZoomIndex)); + } + + indexes = std::move(newIndexes); + } + + lng = newLng; +} + bool CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& tileID, SymbolBucket& bucket, uint32_t& maxCrossTileID) { const auto& thisZoomIndexes = indexes[tileID.overscaledZ]; auto previousIndex = thisZoomIndexes.find(tileID); @@ -138,21 +164,26 @@ bool CrossTileSymbolLayerIndex::removeStaleBuckets(const std::unordered_set<uint CrossTileSymbolIndex::CrossTileSymbolIndex() {} -bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer) { +bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer, float lng) { auto& layerIndex = layerIndexes[symbolLayer.getID()]; bool symbolBucketsChanged = false; std::unordered_set<uint32_t> currentBucketIDs; + layerIndex.handleWrapJump(lng); + for (RenderTile& renderTile : symbolLayer.renderTiles) { if (!renderTile.tile.isRenderable()) { continue; } - auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl); - assert(dynamic_cast<SymbolBucket*>(bucket)); - SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket); + auto bucket = renderTile.tile.getBucket<SymbolBucket>(*symbolLayer.baseImpl); + if (!bucket) { + continue; + } + SymbolBucket& symbolBucket = *bucket; + if (symbolBucket.bucketLeaderID != symbolLayer.getID()) { // Only add this layer if it's the "group leader" for the bucket continue; diff --git a/src/mbgl/text/cross_tile_symbol_index.hpp b/src/mbgl/text/cross_tile_symbol_index.hpp index 541c2e3661..051573e1d2 100644 --- a/src/mbgl/text/cross_tile_symbol_index.hpp +++ b/src/mbgl/text/cross_tile_symbol_index.hpp @@ -45,18 +45,20 @@ public: CrossTileSymbolLayerIndex(); bool addBucket(const OverscaledTileID&, SymbolBucket&, uint32_t& maxCrossTileID); bool removeStaleBuckets(const std::unordered_set<uint32_t>& currentIDs); + void handleWrapJump(float newLng); private: void removeBucketCrossTileIDs(uint8_t zoom, const TileLayerIndex& removedBucket); std::map<uint8_t, std::map<OverscaledTileID,TileLayerIndex>> indexes; std::map<uint8_t, std::set<uint32_t>> usedCrossTileIDs; + float lng = 0; }; class CrossTileSymbolIndex { public: CrossTileSymbolIndex(); - bool addLayer(RenderSymbolLayer&); + bool addLayer(RenderSymbolLayer&, float lng); void pruneUnusedLayers(const std::set<std::string>&); void reset(); diff --git a/src/mbgl/text/get_anchors.cpp b/src/mbgl/text/get_anchors.cpp index d41faf2a71..160ee21edf 100644 --- a/src/mbgl/text/get_anchors.cpp +++ b/src/mbgl/text/get_anchors.cpp @@ -7,6 +7,20 @@ #include <cmath> namespace mbgl { + +float getAngleWindowSize(const float textLeft, const float textRight, const float glyphSize, const float boxScale) { + return (textLeft - textRight) != 0.0f ? + 3.0f / 5.0f * glyphSize * boxScale : + 0; +} + +float getLineLength(const GeometryCoordinates& line) { + float lineLength = 0; + for (auto it = line.begin(), end = line.end() - 1; it != end; it++) { + lineLength += util::dist<float>(*(it), *(it + 1)); + } + return lineLength; +} static Anchors resample(const GeometryCoordinates& line, const float offset, @@ -17,10 +31,7 @@ static Anchors resample(const GeometryCoordinates& line, const bool continuedLine, const bool placeAtMiddle) { const float halfLabelLength = labelLength / 2.0f; - float lineLength = 0; - for (auto it = line.begin(), end = line.end() - 1; it != end; it++) { - lineLength += util::dist<float>(*(it), *(it + 1)); - } + const float lineLength = getLineLength(line); float distance = 0; float markedDistance = offset - spacing; @@ -91,19 +102,18 @@ Anchors getAnchors(const GeometryCoordinates& line, // potential label passes text-max-angle check and has enough froom to fit // on the line. - const float angleWindowSize = (textLeft - textRight) != 0.0f ? - 3.0f / 5.0f * glyphSize * boxScale : - 0; + const float angleWindowSize = getAngleWindowSize(textLeft, textRight, glyphSize, boxScale); - const float labelLength = fmax(textRight - textLeft, iconRight - iconLeft); + const float shapedLabelLength = fmax(textRight - textLeft, iconRight - iconLeft); + const float labelLength = shapedLabelLength * boxScale; // Is the line continued from outside the tile boundary? const bool continuedLine = (line[0].x == 0 || line[0].x == util::EXTENT || line[0].y == 0 || line[0].y == util::EXTENT); // Is the label long, relative to the spacing? // If so, adjust the spacing so there is always a minimum space of `spacing / 4` between label edges. - if (spacing - labelLength * boxScale < spacing / 4) { - spacing = labelLength * boxScale + spacing / 4; + if (spacing - labelLength < spacing / 4) { + spacing = labelLength + spacing / 4; } // Offset the first anchor by: @@ -114,10 +124,53 @@ Anchors getAnchors(const GeometryCoordinates& line, const float fixedExtraOffset = glyphSize * 2; const float offset = !continuedLine ? - std::fmod((labelLength / 2 + fixedExtraOffset) * boxScale * overscaling, spacing) : + std::fmod((shapedLabelLength / 2 + fixedExtraOffset) * boxScale * overscaling, spacing) : std::fmod(spacing / 2 * overscaling, spacing); - return resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength * boxScale, continuedLine, false); + return resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength, continuedLine, false); +} + +optional<Anchor> getCenterAnchor(const GeometryCoordinates& line, + const float maxAngle, + const float textLeft, + const float textRight, + const float iconLeft, + const float iconRight, + const float glyphSize, + const float boxScale) { + if (line.empty()) { + return {}; + } + + const float angleWindowSize = getAngleWindowSize(textLeft, textRight, glyphSize, boxScale); + const float labelLength = fmax(textRight - textLeft, iconRight - iconLeft) * boxScale; + + float prevDistance = 0; + const float centerDistance = getLineLength(line) / 2; + + int i = 0; + for (auto it = line.begin(), end = line.end() - 1; it != end; it++, i++) { + const GeometryCoordinate& a = *(it); + const GeometryCoordinate& b = *(it + 1); + + const auto segmentDistance = util::dist<float>(a, b); + + if (prevDistance + segmentDistance > centerDistance) { + // The center is on this segment + float t = (centerDistance - prevDistance) / segmentDistance, + x = util::interpolate(float(a.x), float(b.x), t), + y = util::interpolate(float(a.y), float(b.y), t); + + Anchor anchor(::round(x), ::round(y), util::angle_to(b, a), 0.5f, i); + + if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) { + return anchor; + } + } + + prevDistance += segmentDistance; + } + return {}; } } // namespace mbgl diff --git a/src/mbgl/text/get_anchors.hpp b/src/mbgl/text/get_anchors.hpp index 48f3013093..8fd22051a4 100644 --- a/src/mbgl/text/get_anchors.hpp +++ b/src/mbgl/text/get_anchors.hpp @@ -17,4 +17,14 @@ Anchors getAnchors(const GeometryCoordinates& line, const float boxScale, const float overscaling); +optional<Anchor> getCenterAnchor(const GeometryCoordinates& line, + const float maxAngle, + const float textLeft, + const float textRight, + const float iconLeft, + const float iconRight, + const float glyphSize, + const float boxScale); + + } // namespace mbgl diff --git a/src/mbgl/text/language_tag.cpp b/src/mbgl/text/language_tag.cpp new file mode 100644 index 0000000000..4c2712f103 --- /dev/null +++ b/src/mbgl/text/language_tag.cpp @@ -0,0 +1,237 @@ +#include <mbgl/text/language_tag.hpp> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wshadow" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#pragma clang diagnostic pop +#pragma GCC diagnostic pop + +#include <sstream> + +/* + ABNF for BCP 47 from: https://tools.ietf.org/html/bcp47 + + Language-Tag = langtag ; normal language tags + / privateuse ; private use tag + / grandfathered ; grandfathered tags NOT IMPLEMENTED + + langtag = language + ["-" script] + ["-" region] + *("-" variant) + *("-" extension) + ["-" privateuse] + + language = 2*3ALPHA ; shortest ISO 639 code + ["-" extlang] ; sometimes followed by + ; extended language subtags + / 4ALPHA ; or reserved for future use + / 5*8ALPHA ; or registered language subtag + + extlang = 3ALPHA ; selected ISO 639 codes + *2("-" 3ALPHA) ; permanently reserved + + script = 4ALPHA ; ISO 15924 code + + region = 2ALPHA ; ISO 3166-1 code + / 3DIGIT ; UN M.49 code + + variant = 5*8alphanum ; registered variants + / (DIGIT 3alphanum) + + extension = singleton 1*("-" (2*8alphanum)) + + ; Single alphanumerics + ; "x" reserved for private use + singleton = DIGIT ; 0 - 9 + / %x41-57 ; A - W + / %x59-5A ; Y - Z + / %x61-77 ; a - w + / %x79-7A ; y - z + + privateuse = "x" 1*("-" (1*8alphanum)) + + grandfathered = irregular ; non-redundant tags registered + / regular ; during the RFC 3066 era + + irregular = "en-GB-oed" ; irregular tags do not match + / "i-ami" ; the 'langtag' production and + / "i-bnn" ; would not otherwise be + / "i-default" ; considered 'well-formed' + / "i-enochian" ; These tags are all valid, + / "i-hak" ; but most are deprecated + / "i-klingon" ; in favor of more modern + / "i-lux" ; subtags or subtag + / "i-mingo" ; combination + / "i-navajo" + / "i-pwn" + / "i-tao" + / "i-tay" + / "i-tsu" + / "sgn-BE-FR" + / "sgn-BE-NL" + / "sgn-CH-DE" + + regular = "art-lojban" ; these tags match the 'langtag' + / "cel-gaulish" ; production, but their subtags + / "no-bok" ; are not extended language + / "no-nyn" ; or variant subtags: their meaning + / "zh-guoyu" ; is defined by their registration + / "zh-hakka" ; and all of these are deprecated + / "zh-min" ; in favor of a more modern + / "zh-min-nan" ; subtag or sequence of subtags + / "zh-xiang" + + alphanum = (ALPHA / DIGIT) ; letters and numbers + +*/ + +namespace mbgl { + +namespace qi = boost::spirit::qi; +namespace phoenix = boost::phoenix; +namespace ascii = boost::spirit::ascii; + +template <typename Iterator> +struct bcp47_parser : qi::grammar<Iterator> +{ + bcp47_parser() : bcp47_parser::base_type(start) + { + using qi::lit; + using qi::repeat; + using qi::inf; + using qi::eoi; + using ascii::char_; + using ascii::no_case; + using ascii::digit; + using ascii::alnum; + using ascii::alpha; + + using boost::spirit::qi::_1; + + start %= no_case[langtag | privateuse | grandfathered]; + + langtag %= (language) [phoenix::ref(languageTag.language) = _1] + >> -("-" >> (script)[phoenix::ref(languageTag.script) = _1]) + >> -("-" >> (region)[phoenix::ref(languageTag.region) = _1]) + >> *("-" >> variant) + >> *("-" >> extension) + >> -("-" >> privateuse); + + language %= (repeat(2,3)[alpha] >> -("-" >> extlang)) // shortest ISO 639 code + // sometimes followed by extended language subtags + | repeat(4)[alpha] // or reserved for future use + | repeat(5,8)[alpha]; // or registered language subtag + + // We add lookaheads for "-"/eoi so that spurious matches on subtags don't prevent backtracking + extlang = repeat(3)[alpha] >> (&lit('-') | eoi) >> repeat(0,2)["-" >> repeat(3)[alpha] >> (&lit('-') | eoi)]; + + script = repeat(4)[alpha] >> (&lit('-') | eoi); + + region = (repeat(2)[alpha] | repeat(3)[digit]) >> (&lit('-') | eoi); + + variant = (repeat(5,8)[alnum] | (digit >> repeat(3,inf)[alnum])) >> (&lit('-') | eoi); + + extension = singleton >> +("-" >> repeat(2,8)[alnum]) >> (&lit('-') | eoi); + + singleton = digit | char_('a','w') | char_('y','z'); // "no-case" handles A-W and Y-Z + + privateuse = "x" >> +("-" >> repeat(1,8)[alnum]) >> (&lit('-') | eoi); + + grandfathered = regular | irregular; + + irregular = lit("en-GB-oed") + | "i-ami" + | "i-bnn" + | "i-default" + | "i-enochian" + | "i-hak" + | "i-klingon" + | "i-lux" + | "i-mingo" + | "i-navajo" + | "i-pwn" + | "i-tao" + | "i-tay" + | "i-tsu" + | "sgn-BE-FR" + | "sgn-BE-NL" + | "sgn-CH-DE"; + + regular = lit("art-lojban") + | "cel-gaulish" + | "no-bok" + | "no-nyn" + | "zh-guoyu" + | "zh-hakka" + | "zh-min" + | "zh-min-nan" + | "zh-xiang"; + } + + qi::rule<Iterator> start; + qi::rule<Iterator> langtag; + qi::rule<Iterator, std::string()> language; + qi::rule<Iterator> extlang; + qi::rule<Iterator, std::string()> script; + qi::rule<Iterator, std::string()> region; + qi::rule<Iterator> variant; + qi::rule<Iterator> extension; + qi::rule<Iterator> singleton; + qi::rule<Iterator> privateuse; + qi::rule<Iterator> grandfathered; + qi::rule<Iterator> irregular; + qi::rule<Iterator> regular; + + LanguageTag languageTag; +}; + +LanguageTag LanguageTag::fromBCP47(const std::string& bcp47Tag) { + typedef std::string::const_iterator iterator_type; + typedef bcp47_parser<iterator_type> bcp47_parser; + + bcp47_parser parser; + std::string::const_iterator iter = bcp47Tag.begin(); + std::string::const_iterator end = bcp47Tag.end(); + bool r = parse(iter, end, parser); + if (r && iter == end) { + return parser.languageTag; + } else { + // Invalid tags are treated as empty/"default" + return LanguageTag(); + } +} + +LanguageTag::LanguageTag(optional<std::string> language_, optional<std::string> script_, optional<std::string> region_) + : language(std::move(language_)) + , script(std::move(script_)) + , region(std::move(region_)) +{} + +std::string LanguageTag::toBCP47() const { + std::stringstream bcp47; + if (!language) { + // BCP 47 requires a language, but we're matching implementations that accept "" + // to mean something like "default" + return bcp47.str(); + } else { + bcp47 << *language; + } + + if (script) { + bcp47 << "-" << *script; + } + + if (region) { + bcp47 << "-" << *region; + } + return bcp47.str(); +} +} // end namespace mbgl diff --git a/src/mbgl/text/language_tag.hpp b/src/mbgl/text/language_tag.hpp new file mode 100644 index 0000000000..7a6a16531f --- /dev/null +++ b/src/mbgl/text/language_tag.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include <mbgl/util/optional.hpp> + +#include <string> + +/* + Use LanguageTag to go back and forth between BCP 47 language tags + and their component language/script/region. + + This implementation accepts but will not round-trip additional + variant/extension/privateuse/grandfathered information in a BCP 47 tag. + + Why implement this? + Mapbox Style Spec specifies locales with BCP 47 + Android and Intl.Collator implementations speak BCP 47 out of the box + Darwin implementation requires translation to "Language Identifier" + We're OK with not supporting extensions, but we want to succesfully + parse any valid BCP 47 tag and get out the base language/script/region. + + Mozilla's version: https://dxr.mozilla.org/mozilla-central/source/intl/locale/MozLocale.cpp + Looks like it actually supports a subset of BCP 47. + See https://bugzilla.mozilla.org/show_bug.cgi?id=bcp47 + + Chromium is based on ICU version: https://ssl.icu-project.org/apiref/icu4c/uloc_8h.html + Getting all the locale information is overkill for us, we just want + language/script/region. + */ + +namespace mbgl { + +struct LanguageTag { + LanguageTag() = default; + LanguageTag(optional<std::string> language_, optional<std::string> script_, optional<std::string> region_); + + static LanguageTag fromBCP47(const std::string& bcp47Tag); + std::string toBCP47() const; + + optional<std::string> language; // ISO 639 + optional<std::string> script; // ISO 15924 + optional<std::string> region; // ISO 3316-1 || UN M.49 +}; + +} // end namespace mbgl diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 9883a1f456..16dd94b374 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -38,7 +38,6 @@ Placement::Placement(const TransformState& state_, MapMode mapMode_) : collisionIndex(state_) , state(state_) , mapMode(mapMode_) - , recentUntil(TimePoint::min()) {} void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatrix, bool showCollisionBoxes) { @@ -51,12 +50,13 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri } assert(dynamic_cast<GeometryTile*>(&renderTile.tile)); GeometryTile& geometryTile = static_cast<GeometryTile&>(renderTile.tile); - - - auto bucket = geometryTile.getBucket(*symbolLayer.baseImpl); - assert(dynamic_cast<SymbolBucket*>(bucket)); - SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket); - + + auto bucket = renderTile.tile.getBucket<SymbolBucket>(*symbolLayer.baseImpl); + if (!bucket) { + continue; + } + SymbolBucket& symbolBucket = *bucket; + if (symbolBucket.bucketLeaderID != symbolLayer.getID()) { // Only place this layer if it's the "group leader" for the bucket continue; @@ -188,7 +188,7 @@ void Placement::placeLayerBucket( bucket.justReloaded = false; } -bool Placement::commit(const Placement& prevPlacement, TimePoint now) { +void Placement::commit(const Placement& prevPlacement, TimePoint now) { commitTime = now; bool placementChanged = false; @@ -222,7 +222,7 @@ bool Placement::commit(const Placement& prevPlacement, TimePoint now) { } } - return placementChanged; + fadeStartTime = placementChanged ? commitTime : prevPlacement.fadeStartTime; } void Placement::updateLayerOpacities(RenderSymbolLayer& symbolLayer) { @@ -232,9 +232,12 @@ void Placement::updateLayerOpacities(RenderSymbolLayer& symbolLayer) { continue; } - auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl); - assert(dynamic_cast<SymbolBucket*>(bucket)); - SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket); + auto bucket = renderTile.tile.getBucket<SymbolBucket>(*symbolLayer.baseImpl); + if (!bucket) { + continue; + } + SymbolBucket& symbolBucket = *bucket; + if (symbolBucket.bucketLeaderID != symbolLayer.getID()) { // Only update opacities this layer if it's the "group leader" for the bucket continue; @@ -302,24 +305,36 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& } auto updateCollisionBox = [&](const auto& feature, const bool placed) { + if (feature.alongLine) { + return; + } + auto dynamicVertex = CollisionBoxDynamicAttributes::vertex(placed, false); + for (size_t i = 0; i < feature.boxes.size() * 4; i++) { + bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); + } + }; + + auto updateCollisionCircles = [&](const auto& feature, const bool placed) { + if (!feature.alongLine) { + return; + } for (const CollisionBox& box : feature.boxes) { - if (feature.alongLine) { - auto dynamicVertex = CollisionBoxDynamicAttributes::vertex(placed, !box.used); - bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); - bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); - bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); - bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); - } else { - auto dynamicVertex = CollisionBoxDynamicAttributes::vertex(placed, false); - bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); - bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); - bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); - bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); - } + auto dynamicVertex = CollisionBoxDynamicAttributes::vertex(placed, !box.used); + bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); + bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); + bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); + bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); } }; - updateCollisionBox(symbolInstance.textCollisionFeature, opacityState.text.placed); - updateCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed); + + if (bucket.hasCollisionBoxData()) { + updateCollisionBox(symbolInstance.textCollisionFeature, opacityState.text.placed); + updateCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed); + } + if (bucket.hasCollisionCircleData()) { + updateCollisionCircles(symbolInstance.textCollisionFeature, opacityState.text.placed); + updateCollisionCircles(symbolInstance.iconCollisionFeature, opacityState.icon.placed); + } } bucket.updateOpacity(); @@ -339,18 +354,15 @@ float Placement::symbolFadeChange(TimePoint now) const { } bool Placement::hasTransitions(TimePoint now) const { - return symbolFadeChange(now) < 1.0 || stale; + if (mapMode == MapMode::Continuous) { + return stale || std::chrono::duration<float>(now - fadeStartTime) < Duration(std::chrono::milliseconds(300)); + } else { + return false; + } } bool Placement::stillRecent(TimePoint now) const { - return mapMode == MapMode::Continuous && recentUntil > now; -} -void Placement::setRecent(TimePoint now) { - stale = false; - if (mapMode == MapMode::Continuous) { - // Only set in continuous mode because "now" isn't defined in still mode - recentUntil = now + Duration(std::chrono::milliseconds(300)); - } + return mapMode == MapMode::Continuous && commitTime + Duration(std::chrono::milliseconds(300)) > now; } void Placement::setStale() { diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index 0e1751b127..24de4c054a 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -63,7 +63,7 @@ class Placement { public: Placement(const TransformState&, MapMode mapMode); void placeLayer(RenderSymbolLayer&, const mat4&, bool showCollisionBoxes); - bool commit(const Placement& prevPlacement, TimePoint); + void commit(const Placement& prevPlacement, TimePoint); void updateLayerOpacities(RenderSymbolLayer&); float symbolFadeChange(TimePoint now) const; bool hasTransitions(TimePoint now) const; @@ -94,12 +94,12 @@ private: TransformState state; MapMode mapMode; + TimePoint fadeStartTime; TimePoint commitTime; std::unordered_map<uint32_t, JointPlacement> placements; std::unordered_map<uint32_t, JointOpacityState> opacities; - TimePoint recentUntil; bool stale = false; std::unordered_map<uint32_t, RetainedQueryData> retainedQueryData; diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 0014ae8d01..ec4461ac6d 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -117,7 +117,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, const float rectBuffer = 3.0f + glyphPadding; const float halfAdvance = glyph.metrics.advance / 2.0; - const bool alongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && placement == SymbolPlacementType::Line; + const bool alongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && placement != SymbolPlacementType::Point; const Point<float> glyphOffset = alongLine ? Point<float>{ positionedGlyph.x + halfAdvance, positionedGlyph.y } : diff --git a/src/mbgl/tile/custom_geometry_tile.cpp b/src/mbgl/tile/custom_geometry_tile.cpp index a2fefcfa9f..24f3526184 100644 --- a/src/mbgl/tile/custom_geometry_tile.cpp +++ b/src/mbgl/tile/custom_geometry_tile.cpp @@ -3,7 +3,6 @@ #include <mbgl/renderer/query.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/actor/scheduler.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/util/string.hpp> #include <mbgl/tile/tile_observer.hpp> #include <mbgl/style/custom_tile_loader.hpp> @@ -39,9 +38,9 @@ void CustomGeometryTile::setTileData(const GeoJSON& geoJSON) { vtOptions.extent = util::EXTENT; vtOptions.buffer = ::round(scale * options.buffer); vtOptions.tolerance = scale * options.tolerance; - featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON, id.canonical.z, id.canonical.x, id.canonical.y, vtOptions, options.wrap, options.clip).features; - } else { - setNecessity(TileNecessity::Optional); + featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON, + id.canonical.z, id.canonical.x, id.canonical.y, + vtOptions, options.wrap, options.clip).features; } setData(std::make_unique<GeoJSONTileData>(std::move(featureData))); } diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index f211c03569..7a83da2267 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -2,7 +2,6 @@ #include <mbgl/tile/geojson_tile_data.hpp> #include <mbgl/renderer/query.hpp> #include <mbgl/renderer/tile_parameters.hpp> -#include <mbgl/style/filter_evaluator.hpp> namespace mbgl { diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 8efe12d54f..d686d8440b 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -16,7 +16,6 @@ #include <mbgl/storage/file_source.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/map/transform_state.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/actor/scheduler.hpp> @@ -87,7 +86,7 @@ void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) { pending = true; ++correlationID; - worker.invoke(&GeometryTileWorker::setData, std::move(data_), correlationID); + worker.self().invoke(&GeometryTileWorker::setData, std::move(data_), correlationID); } @@ -113,14 +112,14 @@ void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers) } ++correlationID; - worker.invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID); + worker.self().invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID); } void GeometryTile::setShowCollisionBoxes(const bool showCollisionBoxes_) { if (showCollisionBoxes != showCollisionBoxes_) { showCollisionBoxes = showCollisionBoxes_; ++correlationID; - worker.invoke(&GeometryTileWorker::setShowCollisionBoxes, showCollisionBoxes, correlationID); + worker.self().invoke(&GeometryTileWorker::setShowCollisionBoxes, showCollisionBoxes, correlationID); } } @@ -154,7 +153,7 @@ void GeometryTile::onError(std::exception_ptr err, const uint64_t resultCorrelat } void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) { - worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs)); + worker.self().invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs)); } void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { @@ -162,7 +161,7 @@ void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { } void GeometryTile::onImagesAvailable(ImageMap images, uint64_t imageCorrelationID) { - worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), imageCorrelationID); + worker.self().invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), imageCorrelationID); } void GeometryTile::getImages(ImageRequestPair pair) { diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 449d8cab28..bd64a1d153 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -22,19 +22,19 @@ class GeometryCoordinates : public std::vector<GeometryCoordinate> { public: using coordinate_type = int16_t; - GeometryCoordinates() = default; - GeometryCoordinates(const std::vector<GeometryCoordinate>& v) - : std::vector<GeometryCoordinate>(v) {} - GeometryCoordinates(std::vector<GeometryCoordinate>&& v) - : std::vector<GeometryCoordinate>(std::move(v)) {} - - using std::vector<GeometryCoordinate>::vector; + template <class... Args> + GeometryCoordinates(Args&&... args) : std::vector<GeometryCoordinate>(std::forward<Args>(args)...) {} + GeometryCoordinates(std::initializer_list<GeometryCoordinate> args) + : std::vector<GeometryCoordinate>(std::move(args)) {} }; class GeometryCollection : public std::vector<GeometryCoordinates> { public: using coordinate_type = int16_t; - using std::vector<GeometryCoordinates>::vector; + template <class... Args> + GeometryCollection(Args&&... args) : std::vector<GeometryCoordinates>(std::forward<Args>(args)...) {} + GeometryCollection(std::initializer_list<GeometryCoordinates> args) + : std::vector<GeometryCoordinates>(std::move(args)) {} }; class GeometryTileFeature { diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 2e7d588d9b..31f4b89801 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -5,7 +5,6 @@ #include <mbgl/renderer/bucket_parameters.hpp> #include <mbgl/renderer/group_by_layout.hpp> #include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/renderer/buckets/symbol_bucket.hpp> @@ -13,6 +12,7 @@ #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/exception.hpp> +#include <mbgl/util/stopwatch.hpp> #include <unordered_set> @@ -320,6 +320,7 @@ void GeometryTileWorker::parse() { return; } + MBGL_TIMING_START(watch) std::vector<std::string> symbolOrder; for (auto it = layers->rbegin(); it != layers->rend(); it++) { if ((*it)->type == LayerType::Symbol) { @@ -404,6 +405,11 @@ void GeometryTileWorker::parse() { requestNewGlyphs(glyphDependencies); requestNewImages(imageDependencies); + MBGL_TIMING_FINISH(watch, + " Action: " << "Parsing," << + " SourceID: " << sourceID.c_str() << + " Canonical: " << static_cast<int>(id.canonical.z) << "/" << id.canonical.x << "/" << id.canonical.y << + " Time"); performSymbolLayout(); } @@ -425,6 +431,7 @@ void GeometryTileWorker::performSymbolLayout() { return; } + MBGL_TIMING_START(watch) optional<AlphaImage> glyphAtlasImage; optional<PremultipliedImage> iconAtlasImage; @@ -467,6 +474,11 @@ void GeometryTileWorker::performSymbolLayout() { firstLoad = false; + MBGL_TIMING_FINISH(watch, + " Action: " << "SymbolLayout," << + " SourceID: " << sourceID.c_str() << + " Canonical: " << static_cast<int>(id.canonical.z) << "/" << id.canonical.x << "/" << id.canonical.y << + " Time"); parent.invoke(&GeometryTile::onLayout, GeometryTile::LayoutResult { std::move(buckets), std::move(featureIndex), diff --git a/src/mbgl/tile/raster_dem_tile.cpp b/src/mbgl/tile/raster_dem_tile.cpp index 5db298cf4c..f29861ee71 100644 --- a/src/mbgl/tile/raster_dem_tile.cpp +++ b/src/mbgl/tile/raster_dem_tile.cpp @@ -48,7 +48,7 @@ void RasterDEMTile::setMetadata(optional<Timestamp> modified_, optional<Timestam void RasterDEMTile::setData(std::shared_ptr<const std::string> data) { pending = true; ++correlationID; - worker.invoke(&RasterDEMTileWorker::parse, data, correlationID, encoding); + worker.self().invoke(&RasterDEMTileWorker::parse, data, correlationID, encoding); } void RasterDEMTile::onParsed(std::unique_ptr<HillshadeBucket> result, const uint64_t resultCorrelationID) { diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp index ff23d4493e..cc71c04ba1 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -37,7 +37,7 @@ void RasterTile::setMetadata(optional<Timestamp> modified_, optional<Timestamp> void RasterTile::setData(std::shared_ptr<const std::string> data) { pending = true; ++correlationID; - worker.invoke(&RasterTileWorker::parse, data, correlationID); + worker.self().invoke(&RasterTileWorker::parse, data, correlationID); } void RasterTile::onParsed(std::unique_ptr<RasterBucket> result, const uint64_t resultCorrelationID) { diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index 23d6864205..5cf74abff5 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -48,6 +48,12 @@ public: virtual void upload(gl::Context&) = 0; virtual Bucket* getBucket(const style::Layer::Impl&) const = 0; + template <class T> + T* getBucket(const style::Layer::Impl& layer) const { + Bucket* bucket = getBucket(layer); + return bucket ? bucket->as<T>() : nullptr; + } + virtual void setShowCollisionBoxes(const bool) {} virtual void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) {} virtual void setMask(TileMask&&) {} @@ -113,7 +119,7 @@ public: void dumpDebugLogs() const; - const OverscaledTileID id; + OverscaledTileID id; optional<Timestamp> modified; optional<Timestamp> expires; diff --git a/src/mbgl/util/chrono.cpp b/src/mbgl/util/chrono.cpp index a880093b74..c304548cf1 100644 --- a/src/mbgl/util/chrono.cpp +++ b/src/mbgl/util/chrono.cpp @@ -1,6 +1,6 @@ #include <mbgl/util/chrono.hpp> -#include <parsedate/parsedate.h> +#include <parsedate/parsedate.hpp> #include <cstdio> #include <ctime> diff --git a/src/mbgl/util/event.cpp b/src/mbgl/util/event.cpp index 3a3be20f5c..0c08d72a8c 100644 --- a/src/mbgl/util/event.cpp +++ b/src/mbgl/util/event.cpp @@ -28,6 +28,7 @@ MBGL_DEFINE_ENUM(Event, { { Event::Android, "Android" }, { Event::Crash, "Crash" }, { Event::Glyph, "Glyph" }, + { Event::Timing, "Timing" }, { Event(-1), "Unknown" }, }); diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp index 5921edfb14..4d9e2bf84c 100644 --- a/src/mbgl/util/http_header.cpp +++ b/src/mbgl/util/http_header.cpp @@ -7,7 +7,10 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wshadow" #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wtautological-constant-compare" #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> diff --git a/src/mbgl/util/interpolate.cpp b/src/mbgl/util/interpolate.cpp index 066fa9c462..6b5736f15f 100644 --- a/src/mbgl/util/interpolate.cpp +++ b/src/mbgl/util/interpolate.cpp @@ -13,7 +13,8 @@ float interpolationFactor(float base, Range<float> range, float z) { } else if (base == 1.0f) { return zoomProgress / zoomDiff; } else { - return (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1); + return (std::pow(static_cast<double>(base), zoomProgress) - 1) / + (std::pow(static_cast<double>(base), zoomDiff) - 1); } } diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp index 6a6ed7b250..c84634ac88 100644 --- a/src/mbgl/util/io.cpp +++ b/src/mbgl/util/io.cpp @@ -2,6 +2,7 @@ #include <cstdio> #include <cerrno> +#include <cstring> #include <iostream> #include <sstream> #include <fstream> @@ -9,6 +10,10 @@ namespace mbgl { namespace util { +IOException::IOException(int err, const std::string& msg) + : std::runtime_error(msg + ": " + std::strerror(errno)), code(err) { +} + void write_file(const std::string &filename, const std::string &data) { FILE *fd = fopen(filename.c_str(), "wb"); if (fd) { @@ -20,7 +25,7 @@ void write_file(const std::string &filename, const std::string &data) { } std::string read_file(const std::string &filename) { - std::ifstream file(filename); + std::ifstream file(filename, std::ios::binary); if (file.good()) { std::stringstream data; data << file.rdbuf(); @@ -31,7 +36,7 @@ std::string read_file(const std::string &filename) { } optional<std::string> readFile(const std::string &filename) { - std::ifstream file(filename); + std::ifstream file(filename, std::ios::binary); if (file.good()) { std::stringstream data; data << file.rdbuf(); @@ -42,9 +47,21 @@ optional<std::string> readFile(const std::string &filename) { void deleteFile(const std::string& filename) { const int ret = std::remove(filename.c_str()); - if (ret != 0) { - throw IOException(errno, "failed to unlink file"); + if (ret != 0 && errno != ENOENT) { + throw IOException(errno, "Could not delete file " + filename); + } +} + +void copyFile(const std::string& destination, const std::string& source) { + std::ifstream src(source, std::ios::binary); + if (!src.good()) { + throw IOException(errno, "Cannot read file " + destination); + } + std::ofstream dst(destination, std::ios::binary); + if (!dst.good()) { + throw IOException(errno, "Cannot write file " + destination); } + dst << src.rdbuf(); } } // namespace util diff --git a/src/mbgl/util/io.hpp b/src/mbgl/util/io.hpp index 847271acf0..e628e82124 100644 --- a/src/mbgl/util/io.hpp +++ b/src/mbgl/util/io.hpp @@ -9,8 +9,7 @@ namespace mbgl { namespace util { struct IOException : std::runtime_error { - IOException(int err, const char* msg) : std::runtime_error(msg), code(err) { - } + IOException(int err, const std::string& msg); const int code = 0; }; @@ -19,6 +18,7 @@ std::string read_file(const std::string &filename); optional<std::string> readFile(const std::string &filename); void deleteFile(const std::string& filename); +void copyFile(const std::string& destination, const std::string& source); } // namespace util } // namespace mbgl diff --git a/src/mbgl/util/logging.cpp b/src/mbgl/util/logging.cpp index 0552eb36cb..d322bd3670 100644 --- a/src/mbgl/util/logging.cpp +++ b/src/mbgl/util/logging.cpp @@ -38,8 +38,14 @@ void Log::record(EventSeverity severity, Event event, const char* format, ...) { record(severity, event, -1, msg); } -void Log::record(EventSeverity severity, Event event, int64_t code) { - record(severity, event, code, std::string()); +void Log::record(EventSeverity severity, Event event, int64_t code, const char* format, ...) { + va_list args; + va_start(args, format); + char msg[4096]; + vsnprintf(msg, sizeof(msg), format, args); + va_end(args); + + record(severity, event, code, std::string{ msg }); } void Log::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) { diff --git a/src/mbgl/util/stopwatch.hpp b/src/mbgl/util/stopwatch.hpp index 6214dae958..0c91342a57 100644 --- a/src/mbgl/util/stopwatch.hpp +++ b/src/mbgl/util/stopwatch.hpp @@ -4,9 +4,24 @@ #include <mbgl/util/chrono.hpp> #include <string> +#include <sstream> namespace mbgl { namespace util { + +#ifdef MBGL_TIMING +// Declare 'watch' as a shared_ptr so it can be captured by value in a lambda function +#define MBGL_TIMING_START(watch) std::shared_ptr<util::stopwatch> watch = std::make_unique<util::stopwatch>(Event::Timing); +#define MBGL_TIMING_FINISH(watch, message) \ + do { \ + std::stringstream messageStream; \ + messageStream << message; \ + watch->report(messageStream.str()); \ + } while (0); +#else +#define MBGL_TIMING_START(watch) +#define MBGL_TIMING_FINISH(watch, message) +#endif #ifndef DISABLE_STOPWATCH class stopwatch { diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp index bcd1c8444f..b6bdc5f590 100644 --- a/src/mbgl/util/tile_coordinate.hpp +++ b/src/mbgl/util/tile_coordinate.hpp @@ -20,7 +20,7 @@ public: static TileCoordinate fromLatLng(double zoom, const LatLng& latLng) { const double scale = std::pow(2.0, zoom); - return { Projection::project(latLng, scale) / double(util::tileSize), zoom }; + return { Projection::project(latLng, scale) / util::tileSize, zoom }; } static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& screenCoordinate) { diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index 488e6b88ce..3f39e53d40 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -130,7 +130,7 @@ std::vector<UnwrappedTileID> tileCover(const Point<double>& tl, } // namespace int32_t coveringZoomLevel(double zoom, style::SourceType type, uint16_t size) { - zoom += std::log(util::tileSize / size) / std::log(2); + zoom += ::log2(util::tileSize / size); if (type == style::SourceType::Raster || type == style::SourceType::Video) { return ::round(zoom); } else { diff --git a/src/mbgl/util/tile_cover_impl.cpp b/src/mbgl/util/tile_cover_impl.cpp index b3fc07f7dd..799ff2666a 100644 --- a/src/mbgl/util/tile_cover_impl.cpp +++ b/src/mbgl/util/tile_cover_impl.cpp @@ -17,8 +17,7 @@ struct TileSpan { bool winding; }; - -// Find the first local minimum going forward in the list. +// Reorder a ring of points such that it starts at a point with a local minimum y-coordinate void start_list_on_local_minimum(PointList& points) { auto prev_pt = std::prev(points.end(), 2); auto pt = points.begin(); @@ -33,6 +32,8 @@ void start_list_on_local_minimum(PointList& points) { next_pt++; if (next_pt == points.end()) { next_pt = std::next(points.begin()); } } + if (pt == points.end()) + return; //Re-close linear rings with first_pt = last_pt if (points.back() == points.front()) { points.pop_back(); @@ -42,37 +43,25 @@ void start_list_on_local_minimum(PointList& points) { } //Create a bound towards a local maximum point, starting from pt. +// Traverse from current pt until the next pt changes y-direction, and copy +// all points from start to end (inclusive) into a Bound. Bound create_bound_towards_maximum(PointList& points, PointList::iterator& pt) { if (std::distance(pt, points.end()) < 2) { return {}; } - if (std::distance(pt, points.end()) == 2) { - Bound bnd; - if (pt->y < std::next(pt)->y) { - std::copy(pt, points.end(), std::back_inserter(bnd.points)); - bnd.winding = true; - } - else { - std::reverse_copy(pt, points.end(), std::back_inserter(bnd.points)); - bnd.winding = false; - } - pt = points.end(); - return bnd; - } + const auto begin = pt; - auto prev_pt = pt == points.begin() ? std::prev(points.end(), 2) : std::prev(pt); - auto next_pt = std::next(pt) == points.end() ? std::next(points.begin()) : std::next(pt); - while (pt != points.end()) { - if ((pt->y >= prev_pt->y) && - (pt->y > next_pt->y )) { - break; - } - prev_pt = pt; + auto next_pt = std::next(begin); + while (pt->y <= next_pt->y) { pt++; next_pt++; - if (next_pt == points.end()) { next_pt = std::next(points.begin()); } + if (next_pt == points.end()) { pt++; break; } + } + + const auto pt_distance = std::distance(begin, next_pt); + if (pt_distance < 2) { + return {}; } Bound bnd; - if (std::next(pt) == points.end()) { next_pt = points.end(); pt++; }; bnd.points.reserve(static_cast<std::size_t>(std::distance(begin, next_pt))); std::copy(begin, next_pt, std::back_inserter(bnd.points)); bnd.winding = true; @@ -80,37 +69,24 @@ Bound create_bound_towards_maximum(PointList& points, PointList::iterator& pt) { } //Create a bound towards a local minimum point, starting from pt. +// Traverse from current pt until the next pt changes y-direction, and copy +// all points from start to end (inclusive) into a Bound. Bound create_bound_towards_minimum(PointList& points, PointList::iterator& pt) { if (std::distance(pt, points.end()) < 2) { return {}; } - if (std::distance(pt, points.end()) == 2) { - Bound bnd; - if (pt->y < std::next(pt)->y) { - std::copy(pt, points.end(), std::back_inserter(bnd.points)); - bnd.winding = true; - } - else { - std::reverse_copy(pt, points.end(), std::back_inserter(bnd.points)); - bnd.winding = false; - } - pt = points.end(); - return bnd; - } + auto begin = pt; - auto prev_pt = pt == points.begin() ? std::prev(points.end(), 2) : std::prev(pt); - auto next_pt = std::next(pt) == points.end() ? std::next(points.begin()) : std::next(pt); - while (pt != points.end()) { - if ((pt->y <= prev_pt->y) && - (pt->y < next_pt->y)) { - break; - } - prev_pt = pt; + auto next_pt = std::next(begin); + while (pt->y > next_pt->y) { pt++; next_pt++; - if (next_pt == points.end()) { next_pt = std::next(points.begin()); } + if (next_pt == points.end()) { pt++; break; } } + const auto pt_distance = std::distance(begin, next_pt); + if (pt_distance < 2) { + return {}; + } Bound bnd; - if (std::next(pt) == points.end()) { next_pt = points.end(); pt++; }; bnd.points.reserve(static_cast<std::size_t>(std::distance(begin, next_pt))); //For bounds that start at a max, reverse copy so that all bounds start at a min std::reverse_copy(begin, next_pt, std::back_inserter(bnd.points)); @@ -118,10 +94,14 @@ Bound create_bound_towards_minimum(PointList& points, PointList::iterator& pt) { return bnd; } -//Build a map of bounds and their starting Y tile coordinate. +// Given a set of points (ring or list) representing a shape, compute a set of +// Bounds, where each Bound represents edges going from a local minima to a local +// maxima point. The BoundsMap is an edge table indexed on the starting Y-tile +// of each Bound. void build_bounds_map(PointList& points, uint32_t maxTile, BoundsMap& et, bool closed = false) { if (points.size() < 2) return; - //While traversing closed rings, start the bounds at a local minimum + //While traversing closed rings, start the bounds at a local minimum. + // (For linestrings the starting point is always a local maxima/minima) if (closed) { start_list_on_local_minimum(points); } @@ -131,12 +111,12 @@ void build_bounds_map(PointList& points, uint32_t maxTile, BoundsMap& et, bool c Bound to_max = create_bound_towards_maximum(points, pointsIter); Bound to_min = create_bound_towards_minimum(points, pointsIter); - if (to_max.points.size() > 0) { + if (to_max.points.size() >= 2) { // Projections may result in values beyond the bounds, clamp to max tile coordinates const auto y = static_cast<uint32_t>(std::floor(clamp(to_max.points.front().y, 0.0, (double)maxTile))); et[y].push_back(to_max); } - if (to_min.points.size() > 0) { + if (to_min.points.size() >= 2) { const auto y = static_cast<uint32_t>(std::floor(clamp(to_min.points.front().y, 0.0, (double)maxTile))); et[y].push_back(to_min); } @@ -149,16 +129,19 @@ void update_span(TileSpan& xp, double x) { xp.xmax = std::max(xp.xmax, static_cast<int32_t>(std::ceil(x))); } -//Build a vector of X tile-coordinates spanned by each bound. -std::vector<TileSpan> scan_row(uint32_t y, Bounds& aet) { +// Use the active bounds, an accumulation of all bounds that enter the y tile row, +// or start in that row. +// Iterate all points of a bound until it exits the row (or ends) and compute the +// set of X tiles it spans across. The winding direction of the bound is also +// captured for each span to later fill tiles between bounds for polygons +std::vector<TileSpan> scan_row(uint32_t y, Bounds& activeBounds) { std::vector<TileSpan> tile_range; - tile_range.reserve(aet.size()); + tile_range.reserve(activeBounds.size()); - for(Bound& b: aet) { + for(Bound& b: activeBounds) { TileSpan xp = { INT_MAX, 0, b.winding }; double x; const auto numEdges = b.points.size() - 1; - assert(numEdges >= 1); while (b.currentPoint < numEdges) { x = b.interpolate(y); update_span(xp, x); @@ -170,7 +153,7 @@ std::vector<TileSpan> scan_row(uint32_t y, Bounds& aet) { x = b.interpolate(y+1); update_span(xp, x); break; - } else if(b.currentPoint == numEdges - 1) { + } else if (b.currentPoint == numEdges - 1) { // For last edge, consider x-intercept at the end of the edge. x = p1.x; update_span(xp, x); @@ -181,11 +164,11 @@ std::vector<TileSpan> scan_row(uint32_t y, Bounds& aet) { } // Erase bounds in the active table whose current edge ends inside this row, // or there are no more edges - auto bound = aet.begin(); - while (bound != aet.end()) { + auto bound = activeBounds.begin(); + while (bound != activeBounds.end()) { if ( bound->currentPoint == bound->points.size() - 1 && bound->points[bound->currentPoint].y <= y+1) { - bound = aet.erase(bound); + bound = activeBounds.erase(bound); } else { bound++; } @@ -225,7 +208,7 @@ struct BuildBoundsMap { BoundsMap operator()(const Point<double>&p) const { Bound bnd; auto point = p; - if(project) { + if (project) { point = Projection::project(LatLng{p.y, p.x}, zoom); } bnd.points.insert(bnd.points.end(), 2, point); @@ -241,7 +224,7 @@ struct BuildBoundsMap { for (const Point<double>& p: points) { Bound bnd; auto point = p; - if(project) { + if (project) { point = Projection::project(LatLng{p.y, p.x}, zoom); } bnd.points.insert(bnd.points.end(), 2, point); @@ -302,20 +285,26 @@ TileCover::Impl::Impl(int32_t z, const Geometry<double>& geom, bool project) tileX = tileXSpans.front().first; } +// Aggregate all Bounds that start in or enter into the next tileY row. Multi-geoms +// may have discontinuity in the BoundMap, so skip forward to the next tileY row +// when the current/next row has no more bounds in it. +// Use scan_row to generate the tileX spans. Merge spans to avoid duplicate tiles +// in TileCoverImpl::next(). For closed geometry, use the non-zero rule to expand +// (fill) tiles between pairs of spans. void TileCover::Impl::nextRow() { - // Update AET for next row + // Update activeBounds for next row if (currentBounds != boundsMap.end()) { if (activeBounds.size() == 0 && currentBounds->first > tileY) { //For multi-geoms: use the next row with an edge table starting point tileY = currentBounds->first; } if (tileY == currentBounds->first) { - - std::move(currentBounds->second.begin(), currentBounds->second.end(), std::back_inserter(activeBounds)); + std::move(currentBounds->second.begin(), currentBounds->second.end(), + std::back_inserter(activeBounds)); currentBounds++; } } - //Scan aet and update currenRange with x_min, x_max pairs + //Scan the active bounds and update currentRange with x_min, x_max pairs auto xps = util::scan_row(tileY, activeBounds); if (xps.size() == 0) { return; @@ -339,7 +328,9 @@ void TileCover::Impl::nextRow() { } bool TileCover::Impl::hasNext() const { - return (!tileXSpans.empty() && tileX < tileXSpans.front().second && tileY < (1u << zoom)); + return (!tileXSpans.empty() + && tileX < tileXSpans.front().second + && tileY < (1u << zoom)); } optional<UnwrappedTileID> TileCover::Impl::next() { @@ -350,7 +341,7 @@ optional<UnwrappedTileID> TileCover::Impl::next() { tileX++; if (tileX >= tileXSpans.front().second) { tileXSpans.pop(); - if(tileXSpans.empty()) { + if (tileXSpans.empty()) { tileY++; nextRow(); } diff --git a/src/mbgl/util/tile_cover_impl.hpp b/src/mbgl/util/tile_cover_impl.hpp index 7c16718984..e9c06e44aa 100644 --- a/src/mbgl/util/tile_cover_impl.hpp +++ b/src/mbgl/util/tile_cover_impl.hpp @@ -60,6 +60,22 @@ struct Bound { } }; +// Implements a modified scan-line algorithm to provide a streaming interface for +// tile cover on arbitrary shapes. +// A `BoundsMap` is genereted from the input geometry where each tuple indicates +// the set of Bounds that start at a y tile coordinate. Each bound represents +// a chain of edges from a local y-minima to a local y-maxima. +// For each row, the activeBounds list aggregates all bounds that enter into or +// begin in that row. This running list of bounds is scanned, capturing the +// x-coordinates spanned by edges in a bound until the bound exits the row (or +// ends). The result is a set of (possibly overlapping) min,max pairs of x coordinates +// (spans). In the simplest case a span represents the x-coordinates at which a +// single edge intersects the top and bottom of a tile row. Interior tiles of a +// polygon are captured by merging spans using the non-zero rule. +// The result of a scan using `nextRow()` is a list of spans (tileXSpans) of x-coordinates +// that includes edges and interiors of polygons. +// next() returns a tileID for each x-coordinate from (first, second] in each +// span in tileXSpans. class TileCover::Impl { public: Impl(int32_t z, const Geometry<double>& geom, bool project = true); diff --git a/src/mbgl/util/token.hpp b/src/mbgl/util/token.hpp index 149661e47e..dea12f9412 100644 --- a/src/mbgl/util/token.hpp +++ b/src/mbgl/util/token.hpp @@ -1,5 +1,7 @@ #pragma once +#include <mbgl/util/optional.hpp> + #include <map> #include <string> #include <algorithm> @@ -25,7 +27,14 @@ std::string replaceTokens(const std::string &source, const Lookup &lookup) { if (pos != end) { for (brace++; brace != end && tokenReservedChars.find(*brace) == std::string::npos; brace++); if (brace != end && *brace == '}') { - result.append(lookup({ pos + 1, brace })); + std::string key { pos + 1, brace }; + if (optional<std::string> replacement = lookup(key)) { + result.append(*replacement); + } else { + result.append("{"); + result.append(key); + result.append("}"); + } pos = brace + 1; } else { result.append(pos, brace); diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp index 1f6dab9639..a4263502ef 100644 --- a/src/mbgl/util/url.cpp +++ b/src/mbgl/util/url.cpp @@ -130,7 +130,7 @@ Path::Path(const std::string& str, const size_t pos, const size_t count) } std::string transformURL(const std::string& tpl, const std::string& str, const URL& url) { - auto result = util::replaceTokens(tpl, [&](const std::string& token) -> std::string { + auto result = util::replaceTokens(tpl, [&](const std::string& token) -> optional<std::string> { if (token == "path") { return str.substr(url.path.first, url.path.second); } else if (token == "domain") { @@ -146,8 +146,9 @@ std::string transformURL(const std::string& tpl, const std::string& str, const U } else if (token == "extension") { const Path path(str, url.path.first, url.path.second); return str.substr(path.extension.first, path.extension.second); + } else { + return {}; } - return ""; }); // Append the query string if it exists. diff --git a/src/parsedate/parsedate.c b/src/parsedate/parsedate.cpp index 7228c4edbc..ff945589bb 100644 --- a/src/parsedate/parsedate.c +++ b/src/parsedate/parsedate.cpp @@ -73,7 +73,7 @@ */ -#include "parsedate.h" +#include "parsedate.hpp" @@ -671,7 +671,7 @@ static int parsedate(const char *date, time_t *output) time_t parse_date(const char *p) { - time_t parsed; + time_t parsed = -1; int rc = parsedate(p, &parsed); switch(rc) { diff --git a/src/parsedate/parsedate.h b/src/parsedate/parsedate.hpp index 6905e361d4..6905e361d4 100644 --- a/src/parsedate/parsedate.h +++ b/src/parsedate/parsedate.hpp diff --git a/vendor/nunicode/LICENSE b/vendor/nunicode/LICENSE new file mode 100644 index 0000000000..1cf5af29d2 --- /dev/null +++ b/vendor/nunicode/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Aleksey Tulinov <aleksey.tulinov@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/nunicode/files.txt b/vendor/nunicode/files.txt new file mode 100644 index 0000000000..03b92272aa --- /dev/null +++ b/vendor/nunicode/files.txt @@ -0,0 +1,20 @@ +include/libnu/casemap.h +include/libnu/casemap_internal.h +include/libnu/config.h +include/libnu/defines.h +include/libnu/ducet.h +include/libnu/mph.h +include/libnu/strcoll.h +include/libnu/strcoll_internal.h +include/libnu/strings.h +include/libnu/udb.h +include/libnu/unaccent.h +include/libnu/utf8.h +include/libnu/utf8_internal.h +src/libnu/ducet.c +src/libnu/strcoll.c +src/libnu/strings.c +src/libnu/tolower.c +src/libnu/tounaccent.c +src/libnu/toupper.c +src/libnu/utf8.c diff --git a/vendor/nunicode/include/libnu/casemap.h b/vendor/nunicode/include/libnu/casemap.h new file mode 100644 index 0000000000..e851ab40ca --- /dev/null +++ b/vendor/nunicode/include/libnu/casemap.h @@ -0,0 +1,140 @@ +#ifndef NU_TOUPPER_H +#define NU_TOUPPER_H + +#include <stdint.h> + +#include <libnu/config.h> +#include <libnu/defines.h> +#include <libnu/strings.h> +#include <libnu/udb.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +/** + * @example folding.c + * @example special_casing.c + */ + +/** Synonim to nu_casemap_read. It is recommended to use + * nu_casemap_read instead. + */ +#define NU_CASEMAP_DECODING_FUNCTION NU_UDB_DECODING_FUNCTION +/** Read (decoding) function for use with transformation results of + * casemapping functions. E.g. nu_casemap_read(nu_tolower(0x0041)); + * will read first codepoint of 'A' transformed to lower case. + */ +#define nu_casemap_read (nu_udb_read) + +/** Casemap codepoint + * + * @ingroup transformations + */ +typedef nu_transformation_t nu_casemapping_t; + +#ifdef NU_WITH_TOUPPER + +/** Return uppercase value of codepoint. Uncoditional casemapping. + * + * @ingroup transformations + * @param codepoint unicode codepoint + * @return uppercase codepoint or 0 if mapping doesn't exist + */ +NU_EXPORT +const char* nu_toupper(uint32_t codepoint); + +/** Return uppercase value of codepoint. Context-sensitivity is not + * implemented internally, returned result is equal to calling nu_toupper() + * on corresponding codepoint. + * + * @ingroup transformations_internal + * @param encoded pointer to encoded string + * @param limit memory limit of encoded string or NU_UNLIMITED + * @param read read (decoding) function + * @param u (optional) codepoint which was (or wasn't) transformed + * @param transform output value of codepoint transformed into uppercase or 0 + * if mapping doesn't exist. Can't be NULL, supposed to be decoded with + * nu_casemap_read + * @param context not used + * @return pointer to the next codepoint in string + */ +NU_EXPORT +const char* _nu_toupper(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context); + +#endif /* NU_WITH_TOUPPER */ + +#ifdef NU_WITH_TOLOWER + +/** Return lowercase value of codepoint. Unconditional casemapping. + * + * @ingroup transformations + * @param codepoint unicode codepoint + * @return lowercase codepoint or 0 if mapping doesn't exist + */ +NU_EXPORT +const char* nu_tolower(uint32_t codepoint); + +/** Return lowercase value of codepoint. Will transform uppercase + * Sigma ('Σ') into final sigma ('ς') if it occurs at string boundary or + * followed by U+0000. Might require single read-ahead when + * encountering Sigma. + * + * @ingroup transformations_internal + * @param encoded pointer to encoded string + * @param limit memory limit of encoded string or NU_UNLIMITED + * @param read read (decoding) function + * @param u (optional) codepoint which was (or wasn't) transformed + * @param transform output value of codepoint transformed into lowercase or 0 + * if mapping doesn't exist. Can't be NULL, supposed to be decoded with + * nu_casemap_read + * @param context not used + * @return pointer to the next codepoint in string + */ +NU_EXPORT +const char* _nu_tolower(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context); + +#endif /* NU_WITH_TOLOWER */ + +#ifdef NU_WITH_TOFOLD + +/** Return value of codepoint with case differences eliminated + * + * @ingroup transformations + * @param codepoint unicode codepoint + * @return casefolded codepoint or 0 if mapping doesn't exist + */ +NU_EXPORT +const char* nu_tofold(uint32_t codepoint); + +/** Return value of codepoint with case differences eliminated. + * Context-sensitivity is not implemented internally, returned result is equal + * to calling nu_tofold() on corresponding codepoint. + * + * @ingroup transformations_internal + * @param encoded pointer to encoded string + * @param limit memory limit of encoded string or NU_UNLIMITED + * @param read read (decoding) function + * @param u (optional) codepoint which was (or wasn't) transformed + * @param transform output value of casefolded codepoint or 0 + * if mapping doesn't exist. Can't be NULL, supposed to be decoded with + * nu_casemap_read + * @param context not used + * @return pointer to the next codepoint in string + */ +NU_EXPORT +const char* _nu_tofold(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context); + +#endif /* NU_WITH_TOFOLD */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_TOUPPER_H */ diff --git a/vendor/nunicode/include/libnu/casemap_internal.h b/vendor/nunicode/include/libnu/casemap_internal.h new file mode 100644 index 0000000000..b97f37c6bf --- /dev/null +++ b/vendor/nunicode/include/libnu/casemap_internal.h @@ -0,0 +1,21 @@ +#ifndef NU_CASEMAP_INTERNAL_H +#define NU_CASEMAP_INTERNAL_H + +#include <stdint.h> +#include <sys/types.h> + +#include <libnu/udb.h> + +/** Casemap codepoint + * + * @ingroup transformations_internal + */ +static inline +const char* _nu_to_something(uint32_t codepoint, + const int16_t *G, size_t G_SIZE, + const uint32_t *VALUES_C, const uint16_t *VALUES_I, const uint8_t *COMBINED) { + + return nu_udb_lookup(codepoint, G, G_SIZE, VALUES_C, VALUES_I, COMBINED); +} + +#endif /* NU_CASEMAP_INTERNAL_H */ diff --git a/vendor/nunicode/include/libnu/config.h b/vendor/nunicode/include/libnu/config.h new file mode 100644 index 0000000000..6948815b6c --- /dev/null +++ b/vendor/nunicode/include/libnu/config.h @@ -0,0 +1,201 @@ +#ifndef NU_BUILD_CONFIG_H +#define NU_BUILD_CONFIG_H + +// Hardcoded defines for vendored copy +#define NU_WITH_UTF8 +#define NU_WITH_TOUPPER +#define NU_WITH_TOLOWER +#define NU_WITH_UNACCENT +#define NU_WITH_Z_COLLATION + +/** @file config.h + * + * This file list available build options and provide some shortcuts, + * like NU_WITH_UTF16 will enable NU_WITH_UTF16LE + NU_WITH_UTF16BE. + * + * At build time you might set either particular option or shortcut. Either + * way you don't have to and shouldn't modify this file, just set build flags + * at the environment. + * + * This file will also enable several dependencies for you: case-mapping + * depends on NU_WITH_UDB, NU_UTF8_READER and so. + */ + +/* Definitions not covered in this file which should be defined + * externally. + * + * NU_BUILD_STATIC: will change functions visibility to "hidden" (GCC). + * @see defines.h + * + * NU_DISABLE_CONTRACTIONS: disables forward-reading during collation, + * only weights of a single codepoints will be compared (enabled in release build) + */ + +/* Enable everything, see below for details on a specific option */ +#ifdef NU_WITH_EVERYTHING +# define NU_WITH_UTF8 +# define NU_WITH_CESU8 +# define NU_WITH_UTF16 +# define NU_WITH_UTF16HE +# define NU_WITH_UTF32 +# define NU_WITH_UTF32HE +# define NU_WITH_STRINGS +# define NU_WITH_EXTRA +# define NU_WITH_REVERSE_READ +# define NU_WITH_VALIDATION +# define NU_WITH_COLLATION +# define NU_WITH_CASEMAP +# define NU_WITH_UNACCENT +#endif /* NU_WITH_EVERYTHING */ + +/* Enable UTF-8 decoding and encoding */ +#ifdef NU_WITH_UTF8 +# define NU_WITH_UTF8_READER /* UTF-8 decoding functions */ +# define NU_WITH_UTF8_WRITER /* UTF-8 encoding functions */ +#endif /* NU_WITH_UTF8 */ + +/* Enable CESU-8 decoding and encoding */ +#ifdef NU_WITH_CESU8 +# define NU_WITH_CESU8_READER +# define NU_WITH_CESU8_WRITER +#endif /* NU_WITH_CESU8 */ + +/* Enable UTF-16LE decoding and encoding */ +#ifdef NU_WITH_UTF16LE +# define NU_WITH_UTF16LE_READER +# define NU_WITH_UTF16LE_WRITER +#endif /* NU_WITH_UTF16LE */ + +/* Enable UTF-16BE decoding and encoding */ +#ifdef NU_WITH_UTF16BE +# define NU_WITH_UTF16BE_READER +# define NU_WITH_UTF16BE_WRITER +#endif /* NU_WITH_UTF16BE */ + +/* Enable UTF-16HE decoding and encoding */ +#ifdef NU_WITH_UTF16HE +# define NU_WITH_UTF16HE_READER +# define NU_WITH_UTF16HE_WRITER +#endif /* NU_WITH_UTF16HE */ + +/* Enable all UTF-16 options */ +#ifdef NU_WITH_UTF16 +# define NU_WITH_UTF16_READER +# define NU_WITH_UTF16_WRITER +#endif /* NU_WITH_UTF16 */ + +/* Enable UTF-16LE and BE decoders of UTF-16 decoder is requested */ +#ifdef NU_WITH_UTF16_READER +# define NU_WITH_UTF16LE_READER +# define NU_WITH_UTF16BE_READER +#endif /* NU_WITH_UTF16_READER */ + +/* Enable UTF-16LE and BE encoders of UTF-16 encoder is requested */ +#ifdef NU_WITH_UTF16_WRITER +# define NU_WITH_UTF16LE_WRITER +# define NU_WITH_UTF16BE_WRITER +#endif /* NU_WITH_UTF16_WRITER */ + +/* Enable UTF-32LE decoding and encoding */ +#ifdef NU_WITH_UTF32LE +# define NU_WITH_UTF32LE_READER +# define NU_WITH_UTF32LE_WRITER +#endif /* NU_WITH_UTF32LE */ + +/* Enable UTF-32BE decoding and encoding */ +#ifdef NU_WITH_UTF32BE +# define NU_WITH_UTF32BE_READER +# define NU_WITH_UTF32BE_WRITER +#endif /* NU_WITH_UTF32BE */ + +/* Enable UTF-32HE decoding and encoding */ +#ifdef NU_WITH_UTF32HE +# define NU_WITH_UTF32HE_READER +# define NU_WITH_UTF32HE_WRITER +#endif /* NU_WITH_UTF32HE */ + +/* Enable all UTF-32 options */ +#ifdef NU_WITH_UTF32 +# define NU_WITH_UTF32_READER +# define NU_WITH_UTF32_WRITER +#endif /* NU_WITH_UTF32 */ + +/* Enable UTF-32LE and BE decoders of UTF-32 decoder is requested */ +#ifdef NU_WITH_UTF32_READER +# define NU_WITH_UTF32LE_READER +# define NU_WITH_UTF32BE_READER +#endif /* NU_WITH_UTF32_READER */ + +/* Enable UTF-32LE and BE encoders of UTF-32 encoder is requested */ +#ifdef NU_WITH_UTF32_WRITER +# define NU_WITH_UTF32LE_WRITER +# define NU_WITH_UTF32BE_WRITER +#endif /* NU_WITH_UTF32_WRITER */ + +/* Shortcut for all string functions */ +#ifdef NU_WITH_STRINGS +# define NU_WITH_Z_STRINGS /* 0-terminated string functions */ +# define NU_WITH_N_STRINGS /* unterminated string functions */ +#endif /* NU_WITH_STRINGS */ + +/* Shortcut for extra string functions */ +#ifdef NU_WITH_EXTRA +# define NU_WITH_Z_EXTRA /* extra functions for 0-terminated strings */ +# define NU_WITH_N_EXTRA /* extra functions for unterminated strings */ +#endif /* NU_WITH_STRINGS */ + +/* Enable collation functions */ +#ifdef NU_WITH_COLLATION +# define NU_WITH_Z_COLLATION /* collation functions for 0-terminated strings */ +# define NU_WITH_N_COLLATION /* collation functions for unterminated strings */ +#endif /* NU_WITH_COLLATION */ + +/* Requirements for collation functions on 0-terminated strings */ +#ifdef NU_WITH_Z_COLLATION +# define NU_WITH_Z_STRINGS +# define NU_WITH_TOUPPER /* nu_toupper() */ +#endif + +/* Requirements for collation functions + * on unterminated strings */ +#ifdef NU_WITH_N_COLLATION +# define NU_WITH_N_STRINGS +# define NU_WITH_TOUPPER +#endif + +/* Requirements for casemap functions */ +#ifdef NU_WITH_CASEMAP +# define NU_WITH_TOLOWER /* nu_tolower() */ +# define NU_WITH_TOUPPER +# define NU_WITH_TOFOLD +#endif /* NU_WITH_CASEMAP */ + +/* More requirements for collation functions all collation functions depends + * on NU_WITH_DUCET */ +#if (defined NU_WITH_Z_COLLATION) || (defined NU_WITH_N_COLLATION) +# ifndef NU_WITH_DUCET +# define NU_WITH_DUCET +# endif +#endif + +/* All collation and casemapping functions depends on NU_WITH_UDB */ +#if (defined NU_WITH_Z_COLLATION) || (defined NU_WITH_N_COLLATION) \ +|| (defined NU_WITH_TOLOWER) || (defined NU_WITH_TOUPPER) || (defined NU_WITH_TOFOLD) \ +|| (defined NU_WITH_UNACCENT) +# ifndef NU_WITH_UDB +# define NU_WITH_UDB /* nu_udb_* functions, pretty much internal stuff */ +# endif /* NU_WITH_UDB */ +#endif + +/* DUCET implementation depends on NU_WITH_UDB */ +#ifdef NU_WITH_DUCET +# define NU_WITH_UDB +#endif /* NU_WITH_DUCET */ + +/* NU_WITH_UDB depends on NU_WITH_UTF8_READER because internal encoding + * of UDB is UTF-8 */ +#ifdef NU_WITH_UDB +# define NU_WITH_UTF8_READER +#endif /* NU_WITH_UDB */ + +#endif /* NU_BUILD_CONFIG_H */ diff --git a/vendor/nunicode/include/libnu/defines.h b/vendor/nunicode/include/libnu/defines.h new file mode 100644 index 0000000000..2678013f94 --- /dev/null +++ b/vendor/nunicode/include/libnu/defines.h @@ -0,0 +1,43 @@ +#ifndef NU_DEFINES_H +#define NU_DEFINES_H + +/** @file + */ + +/** @defgroup defines Defines + */ + +#ifndef NU_EXPORT + +# ifdef _WIN32 +# define NU_EXPORT __declspec(dllexport) + +# elif __GNUC__ >= 4 +# ifdef NU_BUILD_STATIC +# define NU_EXPORT __attribute__ ((visibility ("hidden"))) +# else +# define NU_EXPORT __attribute__ ((visibility ("default"))) +# endif + +# else +# define NU_EXPORT +# endif + +#endif /* NU_EXPORT */ + +/** Integer version of Unicode specification implemented. 900 == 9.0.0 + * + * @ingroup defines + */ +#define NU_UNICODE_VERSION 1000 +/** Special limit value to unset limit on string. Used internally by nunicode. + * + * @ingroup defines + */ +#define NU_UNLIMITED ((const void *)(-1)) + +#ifdef _MSC_VER +#define ssize_t ptrdiff_t +#endif + +#endif /* NU_DEFINES_H */ diff --git a/vendor/nunicode/include/libnu/ducet.h b/vendor/nunicode/include/libnu/ducet.h new file mode 100644 index 0000000000..ecc65e84d8 --- /dev/null +++ b/vendor/nunicode/include/libnu/ducet.h @@ -0,0 +1,37 @@ +#ifndef NU_DUCET_H +#define NU_DUCET_H + +#include <stdint.h> + +#include <libnu/config.h> +#include <libnu/defines.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +#ifdef NU_WITH_DUCET + +/** Get DUCET value of codepoint + * + * Normally, for unlisted codepoints, this function will return number greater + * than max weight of listed codepoints, hence putting all unlisted codepoints + * (not letters and not numbers) to the end of the sorted list (in codepoint + * order). + * + * @ingroup udb + * @param codepoint codepoint + * @param weight previous weight for compound weight (not used here) + * @param context pointer passed to nu_strcoll() + * @return comparable weight of the codepoint + */ +NU_EXPORT +int32_t nu_ducet_weight(uint32_t codepoint, int32_t *weight, void *context); + +#endif /* NU_WITH_DUCET */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_DUCET_H */ diff --git a/vendor/nunicode/include/libnu/mph.h b/vendor/nunicode/include/libnu/mph.h new file mode 100644 index 0000000000..53f2043ad1 --- /dev/null +++ b/vendor/nunicode/include/libnu/mph.h @@ -0,0 +1,71 @@ +#ifndef NU_MPH_H +#define NU_MPH_H + +/* Intentionally undocumented + * + * http://iswsa.acm.org/mphf/index.html + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <libnu/config.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +#ifdef NU_WITH_UDB + +/* those need to be the same values as used in MPH generation */ +#define PRIME 0x01000193 + +/** Calculate G offset from codepoint + */ +static inline +uint32_t _nu_hash(uint32_t hash, uint32_t codepoint) { + if (hash == 0) { + hash = PRIME; + } + + return hash ^ codepoint; +} + +/** Get hash value of Unicode codepoint + */ +static inline +uint32_t nu_mph_hash(const int16_t *G, size_t G_SIZE, + uint32_t codepoint) { + + uint32_t h = _nu_hash(0, codepoint); + int16_t offset = G[h % G_SIZE]; + if (offset < 0) { + return (uint32_t)(-offset - 1); + } + return (_nu_hash(offset, codepoint) % G_SIZE); +} + +/** Lookup value in MPH + */ +static inline +uint32_t nu_mph_lookup(const uint32_t *V_C, const uint16_t *V_I, + uint32_t codepoint, uint32_t hash) { + + const uint32_t *c = (V_C + hash); + const uint16_t *i = (V_I + hash); + + /* due to nature of minimal perfect hash, it will always + * produce collision for codepoints outside of MPH original set. + * thus VALUES_C contain original codepoint to check if + * collision occurred */ + + return (*c != codepoint ? 0 : *i); +} + +#endif /* NU_WITH_UDB */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_MPH_H */ diff --git a/vendor/nunicode/include/libnu/strcoll.h b/vendor/nunicode/include/libnu/strcoll.h new file mode 100644 index 0000000000..3300e0a013 --- /dev/null +++ b/vendor/nunicode/include/libnu/strcoll.h @@ -0,0 +1,199 @@ +#ifndef NU_STRCOLL_H +#define NU_STRCOLL_H + +/** @defgroup collation Collation functions + * + * All functions in this group are following full Unicode collation rules, + * i.e. nu_strstr(haystack, "Æ") will find "AE" in haystack and + * nu_strstr(haystack, "ß") will find "ss". + * + * Same applies for *every* function, nu_strchr(str, 0x00DF), as you would + * guess, will also find "ss" in str. + * + * Please expect this. + * + * Note on "n" functions variant: please see comment on this topic + * in strings.h + */ + +#include <sys/types.h> + +#include <libnu/config.h> +#include <libnu/casemap.h> +#include <libnu/defines.h> +#include <libnu/strings.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +#ifdef NU_WITH_TOFOLD +# define NU_FOLDING_FUNCTION nu_tofold +#else +# define NU_FOLDING_FUNCTION nu_toupper +#endif /* NU_WITH_TOFOLD */ + +#ifdef NU_WITH_Z_COLLATION + +/** Locate codepoint in string + * + * @ingroup collation + * @param encoded encoded string + * @param c charater to locate + * @param read read (decode) function for encoded string + * @return pointer to codepoint in string or 0 + */ +NU_EXPORT +const char* nu_strchr(const char *encoded, uint32_t c, nu_read_iterator_t read); + +/** Locate codepoint in string ignoring case + * + * @ingroup collation + * @see nu_strchr + */ +NU_EXPORT +const char* nu_strcasechr(const char *encoded, uint32_t c, nu_read_iterator_t read); + +/** Locate codepoint in string in reverse direction + * + * @ingroup collation + * @param encoded encoded string + * @param c charater to locate + * @param read read (decode) function for encoded string + * @return pointer to codepoint in string or 0 + */ +NU_EXPORT +const char* nu_strrchr(const char *encoded, uint32_t c, nu_read_iterator_t read); + +/** Locate codepoint in string in reverse direction, case-insensitive + * + * @ingroup collation + * @see nu_strrchr + */ +NU_EXPORT +const char* nu_strrcasechr(const char *encoded, uint32_t c, nu_read_iterator_t read); + +/** Compare strings in case-sensitive manner. + * + * @ingroup collation + * @param s1 first encoded strings + * @param s2 second encoded strings + * @param s1_read read (decode) function for first string + * @param s2_read read (decode) function for second string + * @return -1, 0, 1 + */ +NU_EXPORT +int nu_strcoll(const char *s1, const char *s2, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read); + +/** Compare strings in case-insensitive manner. + * + * @ingroup collation + * @see nu_strcoll + */ +NU_EXPORT +int nu_strcasecoll(const char *s1, const char *s2, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read); + +/** Find needle in haystack + * + * @ingroup collation + * @param haystack encoded haystack + * @param needle encoded needle + * @param haystack_read haystack read (decode) function + * @param needle_read needle read (decode) function + * @return pointer to found string or 0, will return + * haystack if needle is empty string + */ +NU_EXPORT +const char* nu_strstr(const char *haystack, const char *needle, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read); + +/** Find needle in haystack (case-insensitive) + * + * @ingroup collation + * @see nu_strstr + */ +NU_EXPORT +const char* nu_strcasestr(const char *haystack, const char *needle, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read); + +#endif /* NU_WITH_Z_COLLATION */ + +#ifdef NU_WITH_N_COLLATION + +/** + * @ingroup collation + * @see nu_strchr + */ +NU_EXPORT +const char* nu_strnchr(const char *encoded, size_t max_len, uint32_t c, + nu_read_iterator_t read); + +/** + * @ingroup collation + * @see nu_strcasechr + */ +NU_EXPORT +const char* nu_strcasenchr(const char *encoded, size_t max_len, uint32_t c, + nu_read_iterator_t read); + +/** + * @ingroup collation + * @see nu_strrchr + */ +NU_EXPORT +const char* nu_strrnchr(const char *encoded, size_t max_len, uint32_t c, + nu_read_iterator_t read); + +/** + * @ingroup collation + * @see nu_strrcasechr + */ +NU_EXPORT +const char* nu_strrcasenchr(const char *encoded, size_t max_len, uint32_t c, + nu_read_iterator_t read); + +/** + * @ingroup collation + * @see nu_strcoll + */ +NU_EXPORT +int nu_strncoll(const char *s1, size_t s1_max_len, + const char *s2, size_t s2_max_len, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read); + +/** + * @ingroup collation + * @see nu_strncoll + */ +NU_EXPORT +int nu_strcasencoll(const char *s1, size_t s1_max_len, + const char *s2, size_t s2_max_len, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read); + +/** + * @ingroup collation + * @see nu_strstr + */ +NU_EXPORT +const char* nu_strnstr(const char *haystack, size_t haystack_max_len, + const char *needle, size_t needle_max_len, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read); + +/** + * @ingroup collation + * @see nu_strcasestr + */ +NU_EXPORT +const char* nu_strcasenstr(const char *haystack, size_t haystack_max_len, + const char *needle, size_t needle_max_len, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read); + +#endif /* NU_WITH_N_COLLATION */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_STRCOLL_H */ diff --git a/vendor/nunicode/include/libnu/strcoll_internal.h b/vendor/nunicode/include/libnu/strcoll_internal.h new file mode 100644 index 0000000000..570cb14f87 --- /dev/null +++ b/vendor/nunicode/include/libnu/strcoll_internal.h @@ -0,0 +1,232 @@ +#ifndef NU_STRCOLL_INTERNAL_H +#define NU_STRCOLL_INTERNAL_H + +/** @defgroup collation_internal Internal collation functions + * + * Functions in this group are mostly for the internal use. PLease use them + * with care. + */ + +#include <libnu/config.h> +#include <libnu/casemap.h> +#include <libnu/defines.h> +#include <libnu/strings.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +/** Read (decode) iterator with transformation applied inside of it + * + * @ingroup collation_internal + * @see nu_default_compound_read + * @see nu_nocase_compound_read + */ +typedef const char* (*nu_compound_read_t)( + const char *encoded, const char *encoded_limit, nu_read_iterator_t encoded_read, + uint32_t *unicode, const char **tail); + +/** Weight unicode codepoint (or several codepoints) + * + * 0 should always be weighted to 0. If your weight function need more + * than one codepoint - return negative value, which will be passed back to + * this function along with next codepoint. + * + * When function decided on weight and returned positive result, it has to + * fill weight with how many (Unicode) codepoints nunicode should rollback. + * E.g. function consumed "ZZS" and decided weight (in Hungarian collation), + * it fills 0 to \*weight because no rollback is needed. Then function + * consumed "ZZZ" and no weight available for such contraction - it + * returns weight for "Z" and fills \*weight with 2, to rollback + * redundant "ZZ". + * + * If string suddenly ends before weight function can decide (string limit + * reached), 0 will be passed additionally to the previous string to signal + * end of the string. + * + * @ingroup collation_internal + * @param u unicode codepoint to weight + * @param weight 0 at first call or (on sequential calls) pointer to negative + * weight previously returned by this function + * @param context pointer passed to _nu_strcoll() or _nu_strstr() + * @return positive codepoint weight or negative value if function need more + * codepoints + */ +typedef int32_t (*nu_codepoint_weight_t)(uint32_t u, int32_t *weight, void *context); + +#if (defined NU_WITH_Z_COLLATION) || (defined NU_WITH_N_COLLATION) + +/** Default compound read, equal to simply calling encoded_read(encoded, &unicode) + * + * @ingroup collation_internal + * @param encoded encoded string + * @param encoded_limit upper limit for encoded. NU_UNLIMITED for 0-terminated + * strings + * @param encoded_read read (decode) function + * @param unicode output unicode codepoint + * @param tail output pointer to compound tail, should never be 0 + * @return pointer to next encoded codepoint + */ +static inline +const char* nu_default_compound_read(const char *encoded, const char *encoded_limit, + nu_read_iterator_t encoded_read, uint32_t *unicode, + const char **tail) { + (void)(encoded_limit); + (void)(tail); + + return encoded_read(encoded, unicode); +} + +/** Case-ignoring compound read, equal to calling + * encoded_read(encoded, &unicode) with nu_toupper() applied internally + * + * @ingroup collation_internal + * @param encoded encoded string + * @param encoded_limit upper limit for encoded. NU_UNLIMITED for 0-terminated + * strings + * @param encoded_read read (decode) function + * @param unicode output unicode codepoint + * @param tail output pointer to compound tail, should never be 0 + * @return pointer to next encoded codepoint + */ +static inline +const char* nu_nocase_compound_read(const char *encoded, const char *encoded_limit, + nu_read_iterator_t encoded_read, uint32_t *unicode, + const char **tail) { + + /* re-entry with tail != 0 */ + if (*tail != 0) { + *tail = nu_casemap_read(*tail, unicode); + + if (*unicode != 0) { + return encoded; + } + + *tail = 0; // fall thru + } + + if (encoded >= encoded_limit) { + *unicode = 0; + return encoded; + } + + const char *p = encoded_read(encoded, unicode); + + if (*unicode == 0) { + return p; + } + + const char *map = NU_FOLDING_FUNCTION(*unicode); + if (map != 0) { + *tail = nu_casemap_read(map, unicode); + } + + return p; +} + +/** Internal interface for nu_strcoll + * + * @ingroup collation_internal + * @param lhs left-hand side encoded string + * @param lhs_limit upper limit for lhs, use NU_UNLIMITED for 0-terminated + * strings + * @param rhs right-hand side encoded string + * @param rhs_limit upper limit for rhs, use NU_UNLIMITED for 0-terminated + * strings + * @param it1 lhs read (decoding) function + * @param it2 rhs read (decoding) function + * @param com1 lhs compound read function + * @param com2 rhs compound read function + * @param weight codepoint weighting function + * @param context pointer which will be passed to weight + * @param collated_left (optional) number of codepoints collated in lhs + * @param collated_right (optional) number of codepoints collated in rhs + * + * @see nu_strcoll + * @see nu_default_compound_read + * @see nu_nocase_compound_read + * @see nu_ducet_weight + */ +NU_EXPORT +int _nu_strcoll(const char *lhs, const char *lhs_limit, + const char *rhs, const char *rhs_limit, + nu_read_iterator_t it1, nu_read_iterator_t it2, + nu_compound_read_t com1, nu_compound_read_t com2, + nu_codepoint_weight_t weight, void *context, + ssize_t *collated_left, ssize_t *collated_right); + +/** Internal interface for nu_strchr + * + * @ingroup collation_internal + * @param lhs left-hand side encoded string + * @param lhs_limit upper limit for lhs, use NU_UNLIMITED for 0-terminated + * strings + * @param c unicode codepoint to look for + * @param read lhs read (decoding) function + * @param com lhs compound read function + * @param casemap casemapping function + * @param casemap_read casemapping result decoding function + * + * @see nu_strchr + * @see nu_default_compound_read + * @see nu_nocase_compound_read + * @see nu_toupper + * @see nu_tolower + */ +NU_EXPORT +const char* _nu_strchr(const char *lhs, const char *lhs_limit, + uint32_t c, nu_read_iterator_t read, + nu_compound_read_t com, + nu_casemapping_t casemap, nu_read_iterator_t casemap_read); + +/** Internal interface for nu_strchr + * + * @ingroup collation_internal + * @see _nu_strchr + */ +NU_EXPORT +const char* _nu_strrchr(const char *encoded, const char *limit, + uint32_t c, nu_read_iterator_t read, + nu_compound_read_t com, + nu_casemapping_t casemap, nu_read_iterator_t casemap_read); + +/** Internal interface for nu_strcoll + * + * @ingroup collation_internal + * @param haystack encoded haystack + * @param haystack_limit upper limit for haystack, use NU_UNLIMITED for + * 0-terminated strings + * @param needle encoded needle string + * @param needle_limit upper limit for needle, use NU_UNLIMITED for + * 0-terminated strings + * @param it1 haystack read (decoding) function + * @param it2 needle read (decoding) function + * @param com1 haystack compound read function + * @param com2 needle compound read function + * @param casemap casemapping function + * @param casemap_read casemapping result decoding function + * @param weight codepoint weighting function + * @param context pointer which will be passed to weight + * + * @see nu_strstr + * @see nu_default_compound_read + * @see nu_nocase_compound_read + * @see nu_toupper + * @see nu_tolower + * @see nu_ducet_weight + */ +NU_EXPORT +const char* _nu_strstr(const char *haystack, const char *haystack_limit, + const char *needle, const char *needle_limit, + nu_read_iterator_t it1, nu_read_iterator_t it2, + nu_compound_read_t com1, nu_compound_read_t com2, + nu_casemapping_t casemap, nu_read_iterator_t casemap_read, + nu_codepoint_weight_t weight, void *context); + +#endif /* (defined NU_WITH_Z_COLLATION) || (defined NU_WITH_N_COLLATION) */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_STRCOLL_INTERNAL_H */ diff --git a/vendor/nunicode/include/libnu/strings.h b/vendor/nunicode/include/libnu/strings.h new file mode 100644 index 0000000000..989ef5ba3f --- /dev/null +++ b/vendor/nunicode/include/libnu/strings.h @@ -0,0 +1,142 @@ +#ifndef NU_STRINGS_H +#define NU_STRINGS_H + +/** @defgroup strings String functions + * + * Note on "n" functions variant: "n" is in bytes in all functions, + * note though that those are not for memory overrun control. + * They are just for strings not having terminating 0 byte and those + * functions won't go further than m-th *codepoint* in string, but might go + * further than n-th byte in case of multibyte sequence. + * + * E.g.: ``nu_strnlen("абв", 3, nu_utf8_read);``. + * Since codepoints are 2-byte sequences, nu_strnlen() won't go further than 2nd + * codepoint, but will go further than 3rd byte while reading "б". + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <libnu/config.h> +#include <libnu/defines.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +/** + * @defgroup iterators Iterators + * @defgroup transformations Codepoint transformations + * @defgroup transformations_internal Codepoint transformations (internal) + */ + +/** Read (decode) iterator + * + * @ingroup iterators + * @see nu_utf8_read + */ +typedef const char* (*nu_read_iterator_t)(const char *encoded, uint32_t *unicode); + +/** Read (decode) backwards iterator + * + * Arguments intentionally reversed to not mix this with nu_read_iterator_t. + * Reverse read is not compatible with any of string functions. + * + * @ingroup iterators + * @see nu_utf8_revread + */ +typedef const char* (*nu_revread_iterator_t)(uint32_t *unicode, const char *encoded); + +/** Write (encode) iterator + * + * @ingroup iterators + * @see nu_utf8_write + */ +typedef char* (*nu_write_iterator_t)(uint32_t unicode, char *encoded); + +/** Transform codepoint + * + * @ingroup transformations + * @see nu_toupper + * @see nu_tolower + */ +typedef const char* (*nu_transformation_t)(uint32_t codepoint); + +/** Transform codepoint (used internally). This kind of transformation + * delegates iteration on string to transformation implementation. + * + * @ingroup transformations_internal + * @see _nu_toupper + * @see _nu_tolower + */ +typedef const char* (*nu_transform_read_t)( + const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transformed, + void *context); + +#if (defined NU_WITH_Z_STRINGS) || (defined NU_WITH_N_STRINGS) + +#endif /* NU_WITH_Z_STRINGS NU_WITH_N_STRINGS */ + +#ifdef NU_WITH_Z_STRINGS + +/** Get decoded string codepoints length + * + * @ingroup strings + * @param encoded encoded string + * @param it decoding function + * @return string length or negative error + * + * @see nu_strnlen + */ +NU_EXPORT +ssize_t nu_strlen(const char *encoded, nu_read_iterator_t it); + +/** Get encoded string bytes length (encoding variant) + * + * @ingroup strings + * @param unicode unicode codepoints + * @param it encoding function + * @return byte length or negative error + * + * @see nu_bytenlen + */ +NU_EXPORT +ssize_t nu_bytelen(const uint32_t *unicode, nu_write_iterator_t it); + +/** Get encoded string bytes length + * + * @ingroup strings + * @param encoded encoded string + * @param it decoding function + * @return string length or negative error + */ +NU_EXPORT +ssize_t nu_strbytelen(const char *encoded, nu_read_iterator_t it); + +#endif /* NU_WITH_Z_STRINGS */ + +#ifdef NU_WITH_N_STRINGS + +/** + * @ingroup strings + * @see nu_strlen + */ +NU_EXPORT +ssize_t nu_strnlen(const char *encoded, size_t max_len, nu_read_iterator_t it); + +/** + * @ingroup strings + * @see nu_bytelen + */ +NU_EXPORT +ssize_t nu_bytenlen(const uint32_t *unicode, size_t max_len, + nu_write_iterator_t it); + +#endif /* NU_WITH_N_STRINGS */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_STRINGS_H */ diff --git a/vendor/nunicode/include/libnu/udb.h b/vendor/nunicode/include/libnu/udb.h new file mode 100644 index 0000000000..39a785bc69 --- /dev/null +++ b/vendor/nunicode/include/libnu/udb.h @@ -0,0 +1,81 @@ +#ifndef NU_UDB_H +#define NU_UDB_H + +#include <stdint.h> +#include <sys/types.h> + +#include <libnu/config.h> +#include <libnu/defines.h> +#include <libnu/mph.h> +#include <libnu/strings.h> +#include <libnu/utf8.h> + +/** @defgroup udb Unicode database + * + * Note: never use it directly, it is subject to change in next releases + */ + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +#ifdef NU_WITH_UDB + +#define NU_UDB_DECODING_FUNCTION (nu_utf8_read) +#define nu_udb_read (nu_utf8_read) + +/** Lookup value in UDB + * + * Similar to nu_udb_lookup(), but doesn't look into COMBINED + * + * @ingroup udb + * @see nu_udb_lookup + * @return raw value from VALUES_I or 0 if value wasn't found + */ +static inline +uint32_t nu_udb_lookup_value(uint32_t codepoint, + const int16_t *G, size_t G_SIZE, + const uint32_t *VALUES_C, const uint16_t *VALUES_I) { + + uint32_t hash = nu_mph_hash(G, G_SIZE, codepoint); + uint32_t value = nu_mph_lookup(VALUES_C, VALUES_I, codepoint, hash); + + return value; +} + +/** Lookup data in UDB + * + * Returned data is encoded, therefore you need to use p = it(p, &u) to + * fetch it. Returned string might contain more than 1 codepoint. + * + * @ingroup udb + * @param codepoint unicode codepoint + * @param G first MPH table + * @param G_SIZE first table number of elements (original MPH set size) + * @param VALUES_C codepoints array + * @param VALUES_I offsets array + * @param COMBINED joined values addressed by index stored in VALUES + * @return looked up data or 0 + */ +static inline +const char* nu_udb_lookup(uint32_t codepoint, + const int16_t *G, size_t G_SIZE, + const uint32_t *VALUES_C, const uint16_t *VALUES_I, const uint8_t *COMBINED) { + + uint32_t combined_offset = nu_udb_lookup_value(codepoint, + G, G_SIZE, VALUES_C, VALUES_I); + + if (combined_offset == 0) { + return 0; + } + + return (const char *)(COMBINED + combined_offset); +} + +#endif /* NU_WITH_UDB */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_UDB_H */ diff --git a/vendor/nunicode/include/libnu/unaccent.h b/vendor/nunicode/include/libnu/unaccent.h new file mode 100644 index 0000000000..1486a43f34 --- /dev/null +++ b/vendor/nunicode/include/libnu/unaccent.h @@ -0,0 +1,57 @@ +#ifndef NU_UNACCENT_H +#define NU_UNACCENT_H + +#include <libnu/casemap.h> +#include <libnu/strings.h> + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +/** + * @example unaccent.c + */ + +#ifdef NU_WITH_UNACCENT + +/** Return unaccented value of codepoint. If codepoint is + * accent (disacritic) itself, returns empty string. + * + * @note This is nunicode extenstion. + * + * @ingroup transformations + * @param codepoint unicode codepoint + * @return unaccented codepoint, 0 if mapping doesn't exist + * and empty string if codepoint is accent + */ +NU_EXPORT +const char* nu_tounaccent(uint32_t codepoint); + +/** Return unaccented value of codepoint. If codepoint is + * accent (disacritic) itself, returns empty string. + * + * @note This is nunicode extenstion. + * + * @ingroup transformations_internal + * @param encoded pointer to encoded string + * @param limit memory limit of encoded string or NU_UNLIMITED + * @param read read (decoding) function + * @param u (optional) codepoint which was (or wasn't) transformed + * @param transform output value of codepoint unaccented or 0 if + * mapping doesn't exist, or empty string if codepoint is accent. + * Can't be NULL, supposed to be decoded with nu_casemap_read + * @param context not used + * @return pointer to the next codepoint in string + */ +NU_EXPORT +const char* _nu_tounaccent(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context); + +#endif /* NU_WITH_UNACCENT */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_UNACCENT_H */ diff --git a/vendor/nunicode/include/libnu/utf8.h b/vendor/nunicode/include/libnu/utf8.h new file mode 100644 index 0000000000..6f654e24c4 --- /dev/null +++ b/vendor/nunicode/include/libnu/utf8.h @@ -0,0 +1,130 @@ +#ifndef NU_UTF8_H +#define NU_UTF8_H + +#include <stdint.h> +#include <sys/types.h> + +#include <libnu/config.h> +#include <libnu/defines.h> +#include <libnu/utf8_internal.h> + +/** @defgroup utf8 UTF-8 support + * + * Note: There is no utf8_string[i] equivalent - it will be slow, + * use nu_utf8_read() and nu_utf8_revread() instead + * + * @example utf8.c + * @example revread.c + */ + +#if defined (__cplusplus) || defined (c_plusplus) +extern "C" { +#endif + +#ifdef NU_WITH_UTF8_READER + +/** Read codepoint from UTF-8 string + * + * @ingroup utf8 + * @param utf8 pointer to UTF-8 encoded string + * @param unicode output unicode codepoint or 0 + * @return pointer to next codepoint in UTF-8 string + */ +static inline +const char* nu_utf8_read(const char *utf8, uint32_t *unicode) { + uint32_t c = *(unsigned char *)(utf8); + + if (c >= 0x80) { + if (c < 0xE0) { + if (unicode != 0) { + utf8_2b(utf8, unicode); + } + return utf8 + 2; + } + else if (c < 0xF0) { + if (unicode != 0) { + utf8_3b(utf8, unicode); + } + return utf8 + 3; + } + else { + if (unicode != 0) { + utf8_4b(utf8, unicode); + } + return utf8 + 4; + } + } + else if (unicode != 0) { + *unicode = c; + } + + return utf8 + 1; +} + +#ifdef NU_WITH_REVERSE_READ + +/** Read codepoint from UTF-8 string in backward direction + * + * Note that it is your responsibility to check that this call + * is not going under beginning of encoded string. Normally you + * shouldn't call it like this: nu_utf8_revread(&u, "hello"); which + * will result in undefined behavior + * + * @ingroup utf8 + * @param unicode output unicode codepoint or 0 + * @param utf8 pointer to UTF-8 encoded string + * @return pointer to previous codepoint in UTF-8 string + */ +static inline +const char* nu_utf8_revread(uint32_t *unicode, const char *utf8) { + /* valid UTF-8 has either 10xxxxxx (continuation byte) + * or beginning of byte sequence */ + const char *p = utf8 - 1; + while (((unsigned char)(*p) & 0xC0) == 0x80) { /* skip every 0b10000000 */ + --p; + } + + if (unicode != 0) { + nu_utf8_read(p, unicode); + } + + return p; +} + +#endif /* NU_WITH_REVERSE_READ */ + +#ifdef NU_WITH_VALIDATION + +/** Validate codepoint in string + * + * @ingroup utf8 + * @param encoded buffer with encoded string + * @param max_len buffer length + * @return codepoint length or 0 on error + */ +NU_EXPORT +int nu_utf8_validread(const char *encoded, size_t max_len); + +#endif /* NU_WITH_VALIDATION */ +#endif /* NU_WITH_UTF8_READER */ + +#ifdef NU_WITH_UTF8_WRITER + +/** Write unicode codepoints into UTF-8 encoded string + * + * @ingroup utf8 + * @param unicode unicode codepoint + * @param utf8 pointer to buffer to write UTF-8 encoded text to, + * should be large enough to hold encoded value + * @return pointer to byte after last written + */ +NU_EXPORT +char* nu_utf8_write(uint32_t unicode, char *utf8); + +#endif /* NU_WITH_UTF8_WRITER */ + +#if defined (__cplusplus) || defined (c_plusplus) +} +#endif + +#endif /* NU_UTF8_H */ diff --git a/vendor/nunicode/include/libnu/utf8_internal.h b/vendor/nunicode/include/libnu/utf8_internal.h new file mode 100644 index 0000000000..77b7eb5ced --- /dev/null +++ b/vendor/nunicode/include/libnu/utf8_internal.h @@ -0,0 +1,168 @@ +#ifndef NU_UTF8_INTERNAL_H +#define NU_UTF8_INTERNAL_H + +#include <sys/types.h> + +static inline +unsigned utf8_char_length(const char c) { + const unsigned char uc = c; + + if ((uc & 0x80) == 0) return 1; + if ((uc & 0xE0) == 0xC0) return 2; + if ((uc & 0xF0) == 0xE0) return 3; + if ((uc & 0xF8) == 0xF0) return 4; + + return 0; /* undefined */ +} + +static inline +void utf8_2b(const char *p, uint32_t *codepoint) { + const unsigned char *up = (const unsigned char *)(p); + + /* UTF-8: 110xxxxx 10xxxxxx + * |__ 1st unicode octet + * 110xxx00 << 6 -> 00000xxx 00000000 | + * -------- + * 110000xx << 6 -> 00000xxx xx000000 |__ 2nd unicode octet + * 10xxxxxx -> 00000xxx xxxxxxxx | + * -------- */ + *codepoint = (*(up) & 0x1C) << 6 + | ((*(up) & 0x03) << 6 | (*(up + 1) & 0x3F)); +} + +static inline +void utf8_3b(const char *p, uint32_t *codepoint) { + const unsigned char *up = (const unsigned char *)(p); + + /* UTF-8: 1110xxxx 10xxxxxx 10xxxxxx + * + * 1110xxxx << 12 -> xxxx0000 0000000 |__ 1st unicode octet + * 10xxxx00 << 6 -> xxxxxxxx 0000000 | + * -------- + * 100000xx << 6 -> xxxxxxxx xx00000 |__ 2nd unicode octet + * 10xxxxxx -> xxxxxxxx xxxxxxx | + * ------- */ + *codepoint = + ((*(up) & 0x0F) << 12 | (*(up + 1) & 0x3C) << 6) + | ((*(up + 1) & 0x03) << 6 | (*(up + 2) & 0x3F)); +} + +static inline +void utf8_4b(const char *p, uint32_t *codepoint) { + const unsigned char *up = (const unsigned char *)(p); + + /* UTF-8: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * 11110xxx << 18 -> 00xxx00 00000000 00000000 |__ 1st unicode octet + * 10xx0000 << 12 -> 00xxxxx 00000000 00000000 | + * ------- + * 1000xxxx << 12 -> 00xxxxx xxxx0000 00000000 |__ 2nd unicode octet + * 10xxxx00 << 6 -> 00xxxxx xxxxxxxx 00000000 | + * -------- + * 100000xx << 6 -> 00xxxxx xxxxxxxx xx000000 |__ 3rd unicode octet + * 10xxxxxx -> 00xxxxx xxxxxxxx xxxxxxxx | + * --------- */ + *codepoint = + ((*(up) & 0x07) << 18 | (*(up + 1) & 0x30) << 12) + | ((*(up + 1) & 0x0F) << 12 | (*(up + 2) & 0x3C) << 6) + | ((*(up + 2) & 0x03) << 6 | (*(up + 3) & 0x3F)); +} + +static inline +unsigned utf8_codepoint_length(uint32_t codepoint) { + if (codepoint < 128) return 1; + if (codepoint < 0x0800) return 2; + if (codepoint < 0x10000) return 3; + + return 4; /* de facto max length in UTF-8 */ +} + +static inline +void b2_utf8(uint32_t codepoint, char *p) { + unsigned char *up = (unsigned char *)(p); + + /* UNICODE: 00000xxx xxxxxxxx + * + * 00000xxx >> 6 -> 110xxx00 10000000 |__ 1st UTF-8 octet + * xxxxxxxx >> 6 -> 110xxxxx 10000000 | + * -------- + * |__ 2nd UTF-8 octet + * xxxxxxxx -> 110xxxxx 10xxxxxx | + * -------- */ + *(up) = (0xC0 | (codepoint & 0xFF00) >> 6 | (codepoint & 0xFF) >> 6); + *(up + 1) = (0x80 | (codepoint & 0x3F)); +} + +static inline +void b3_utf8(uint32_t codepoint, char *p) { + unsigned char *up = (unsigned char *)(p); + + /* UNICODE: xxxxxxxx xxxxxxxx + * |__ 1st UTF-8 octet + * xxxxxxxx >> 12 -> 1110xxxx 10000000 10000000 | + * -------- + * xxxxxxxx >> 6 -> 1110xxxx 10xxxx00 10000000 |__ 2nd UTF-8 octet + * xxxxxxxx >> 6 -> 1110xxxx 10xxxxxx 10000000 | + * -------- + * |__ 3rd UTF-8 octet + * xxxxxxxx -> 1110xxxx 10xxxxxx 10xxxxxx | + * -------- */ + *(up) = (0xE0 | (codepoint & 0xF000) >> 12); + *(up + 1) = (0x80 | (codepoint & 0x0F00) >> 6 | (codepoint & 0xC0) >> 6); + *(up + 2) = (0x80 | (codepoint & 0x3F)); +} + +static inline +void b4_utf8(uint32_t codepoint, char *p) { + unsigned char *up = (unsigned char *)(p); + + /* UNICODE: 000xxxxx xxxxxxxx xxxxxxxx + * |__ 1st UTF-8 octet + * 000xxxxx >> 18 -> 11110xxx 1000000 10000000 10000000 | + * -------- + * 000xxxxx >> 12 -> 11110xxx 10xx000 10000000 10000000 |__ 2nd UTF-8 octet + * xxxxxxxx >> 12 -> 11110xxx 10xxxxx 10000000 10000000 | + * ------- + * xxxxxxxx >> 6 -> 11110xxx 10xxxxx 10xxxxx0 10000000 |__ 3rd UTF-8 octet + * xxxxxxxx >> 6 -> 11110xxx 10xxxxx 10xxxxxx 10000000 | + * -------- + * |__ 4th UTF-8 octet + * xxxxxxxx -> 11110xxx 10xxxxx 10xxxxxx 10000000 | */ + *(up) = (0xF0 | ((codepoint & 0x1C0000) >> 18)); + *(up + 1) = (0x80 | (codepoint & 0x030000) >> 12 | (codepoint & 0x00E000) >> 12); + *(up + 2) = (0x80 | (codepoint & 0x001F00) >> 6 | (codepoint & 0x0000E0) >> 6); + *(up + 3) = (0x80 | (codepoint & 0x3F)); +} + +static inline +int utf8_validread_basic(const char *p, size_t max_len) { + const unsigned char *up = (const unsigned char *)(p); + + /* it should be 0xxxxxxx or 110xxxxx or 1110xxxx or 11110xxx + * latter should be followed by number of 10xxxxxx */ + + unsigned len = utf8_char_length(*p); + + /* codepoints longer than 6 bytes does not currently exist + * and not currently supported + * TODO: longer UTF-8 sequences support + */ + if (max_len < len) { + return 0; + } + + switch (len) { + case 1: return 1; /* one byte codepoint */ + case 2: return ((*(up + 1) & 0xC0) == 0x80 ? 2 : 0); + case 3: return ((*(up + 1) & 0xC0) == 0x80 + && (*(up + 2) & 0xC0) == 0x80 ? 3 : 0); + + case 4: return ((*(up + 1) & 0xC0) == 0x80 + && (*(up + 2) & 0xC0) == 0x80 + && (*(up + 3) & 0xC0) == 0x80 ? 4 : 0); + } + + return 0; +} + +#endif /* NU_UTF8_INTERNAL_H */ diff --git a/vendor/nunicode/src/libnu/ducet.c b/vendor/nunicode/src/libnu/ducet.c new file mode 100644 index 0000000000..b634538481 --- /dev/null +++ b/vendor/nunicode/src/libnu/ducet.c @@ -0,0 +1,65 @@ +#include <assert.h> + +#include <libnu/ducet.h> +#include <libnu/udb.h> + +#ifdef NU_WITH_DUCET + +#include "gen/_ducet.c" + +#ifndef NU_DISABLE_CONTRACTIONS +# include "gen/_ducet_switch.c" +#else + const size_t _NU_DUCET_CONTRACTIONS = 0; +#endif + +static size_t _nu_ducet_weights_count() { + return NU_DUCET_G_SIZE + _NU_DUCET_CONTRACTIONS; +} + +int32_t nu_ducet_weight(uint32_t codepoint, int32_t *weight, void *context) { + (void)(weight); + (void)(context); + + assert(_nu_ducet_weights_count() < 0x7FFFFFFF - 0x10FFFF); + +#ifndef NU_DISABLE_CONTRACTIONS + int32_t switch_value = _nu_ducet_weight_switch(codepoint, weight, context); + /* weight switch should return weight (if any) and fill value of *weight + * with fallback (if needed). returned value of 0 is impossible result - this + * special case is already handled above, this return value indicates that switch + * couldn't find weight for a codepoint */ + if (switch_value != 0) { + return switch_value; + } +#endif + + /* special case switch after contractions switch + * to let state-machine figure out its state on abort */ + if (codepoint == 0) { + return 0; + } + + uint32_t mph_value = nu_udb_lookup_value(codepoint, NU_DUCET_G, NU_DUCET_G_SIZE, + NU_DUCET_VALUES_C, NU_DUCET_VALUES_I); + + return (mph_value != 0 + ? (int32_t)(mph_value) + : (int32_t)(codepoint + _nu_ducet_weights_count())); + + /* ISO/IEC 14651 requests that codepoints with undefined weight should be + * sorted before max weight in collation table. This way all codepoints + * defined in ducet would have weight under a value of _nu_ducet_weights_count(), + * all undefined codepoints would have weight under + * 0x10FFFF + _nu_ducet_weights_count() - 1, max weight will be + * 0x10FFFF + _nu_ducet_weights_count() */ + + /* Regarding integer overflow: + * + * int32_t can hold 0xFFFFFFFF / 2 = 0x7FFFFFFF positive numbers, this + * function can safely offset codepoint value up to +2146369536 without + * risk of overflow. Thus max collation table size supported is + * 2146369536 (0x7FFFFFFF - 0x10FFFF) */ +} + +#endif /* NU_WITH_DUCET */ diff --git a/vendor/nunicode/src/libnu/gen/_ducet.c b/vendor/nunicode/src/libnu/gen/_ducet.c new file mode 100644 index 0000000000..715bc913e8 --- /dev/null +++ b/vendor/nunicode/src/libnu/gen/_ducet.c @@ -0,0 +1,6197 @@ +/* Automatically generated file (mph.py), 1490539895 + * + * Tag : NU_DUCET + * Prime : 01000193, + * G size : 20027, + * Combined length : 0, + * Encoding : UTF-8 + */ + +#include <stdint.h> + +const int16_t NU_DUCET_G[] = { + -20026, -20025, -20024, -20023, -20022, -20021, -20020, -20019, -20018, -20017, -20016, -20015, + -20013, 6, 49, 26, 52, 49, 56, -20011, 57, 50, 48, 83, + 68, 133, 139, 141, 144, -20010, -20005, -19999, -19998, -19997, -19996, -19994, + -19993, -19991, -19990, -19989, -19988, -19987, -19986, -19985, -19984, -19983, -19981, -19980, + -19979, -19978, -19971, -19969, -19967, -19961, -19957, -19956, -19951, -19950, -19948, -19947, + -19946, -19943, -19942, -19941, -19939, -19938, -19937, -19934, -19933, 3, 1, -19932, + -19931, -19930, -19917, -19916, -19897, -19896, -19895, -19894, -19893, -19892, -19891, -19890, + -19889, -19888, -19887, -19886, -19885, -19884, -19883, -19882, -19881, -19880, -19879, -19878, + -19877, -19876, -19874, -19873, -19872, -19871, -19870, -19869, -19868, -19867, -19866, -19865, + -19864, -19863, -19862, -19861, -19860, 0, -19859, -19858, -19857, -19856, -19855, -19854, + -19853, -19852, -19851, -19850, -19849, -19848, -19847, -19846, -19845, -19844, -19843, -19842, + -19841, -19840, -19839, -19838, -19837, -19836, -19835, -19834, -19833, -19832, -19831, -19830, + -19829, -19828, -19827, -19826, -19825, -19824, -19823, -19822, -19821, -19820, -19819, -19818, + -19817, -19816, -19815, -19814, -19813, -19812, -19811, -19810, -19809, -19808, -19807, -19806, + -19805, -19804, -19803, -19802, -19672, 1, 1, 1, 4, 1, 1, 8, + 8, 3, 4, 6, 17, 20, 17, 24, 24, -19671, -19670, -19669, + -19668, 32, -19666, -19665, -19664, 10, 16, 16, 40, 42, 40, 22, + 46, 64, 10, 54, 80, -19663, -19662, -19661, -19660, -19659, -19658, -19657, + -19656, -19655, -19654, -19653, -19652, 82, 1, 5, 1, 8, 8, 8, + 8, 1, 1, 1, 17, 17, 17, 17, 17, 5, 1, 1, + 1, 5, 1, 1, 1, 5, 1, 1, 4, 20, 25, 29, + 25, 32, 1, 3, 1, 3, -19651, -19650, -19649, -19648, -19647, -19646, + -19645, -19644, -19643, -19642, -19641, -19640, 2, 4, 2, 8, 2, 2, + 2, -19639, -19638, -19637, 2, -19636, -19635, -19634, -19633, 1, -19632, -19631, + -19630, -19629, -19628, -19627, -19626, -19625, -19624, -19623, -19622, -19621, -19620, -19619, + -19618, 1, -19617, -19616, -19615, -19614, -19613, -19612, -19611, -19610, -19609, -19608, + -19607, -19606, -19605, -19604, -19603, -19602, 5, 3, 4, 2, 9, 9, + 9, 3, -19601, -19600, 1, 5, -19599, -19598, -19597, -19596, 1, 3, + 1, 3, 1, 3, 1, 3, -19595, -19594, 1, 1, -19593, -19592, + -19591, -19590, -19589, -19588, 3, 1, -19587, -19586, -19585, -19584, -19583, -19582, + -19581, -19580, -19579, -19578, -19577, -19576, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -19575, 1, -19574, -19573, + 1, 1, -19572, -19571, -19570, -19569, -19568, -19567, -19566, -19565, -19564, -19563, + -19562, -19561, 1, 1, 1, 1, 1, 1, 1, -19560, 1, 1, + 1, -19559, -19558, -19557, -19556, 1, -19555, -19554, 1, 1, -19553, -19552, + -19551, -19550, -19549, -19548, -19547, -19546, -19545, -19544, -19543, -19542, 1, 1, + 1, 9, 2, 8, 1, 3, 1, 5, 16, 16, 16, 16, + 16, 1, -19541, -19540, -19539, 2, -19538, -19537, -19536, -19535, -19534, -19533, + -19532, -19531, -19530, -19529, 0, -19528, 15, 17, 22, 16, 24, 50, + 55, -19527, 48, 48, 64, 52, -19526, 64, -19525, 64, 64, 70, + 64, -19524, 66, 72, 74, 66, -19523, 65, 82, 64, -19522, -19521, + -19520, -19519, 1, 1, 5, -19518, 14, 3, 50, 2, 48, 11, + 51, -19517, -19516, 128, 144, 25, 29, 1, 49, 130, 129, 129, + 137, 62, 128, 128, 128, -19515, -19514, 134, 131, -19513, -19512, -19511, + -19510, -19509, -19508, -19507, -19506, -19505, -19504, -19503, -19502, -19501, -19500, -19499, + -19498, -19497, -19496, -19495, -19494, -19493, -19492, -19491, -19490, -19489, -19488, -19487, + -19486, -19485, -19484, -19483, -19482, 1, 4, 10, 12, 10, 8, 10, + 21, 22, 18, 22, 33, -19481, -19480, 39, 40, 32, 1, 3, + 4, 9, 1, 9, 2, 19, -19479, -19478, -19477, 4, -19476, -19475, + -19474, -19473, 1, 1, 1, 1, 3, 18, 21, 23, -19472, 16, + 18, 16, 81, 16, -19471, -19470, 50, 64, 64, 2, 64, 75, + 64, 72, 64, 83, 64, 37, 81, 97, 92, 120, 8, 8, + -19469, -19468, -19467, 9, 9, -19466, -19465, -19464, -19463, -19462, -19461, -19460, + -19459, 144, 28, 6, 2, -19458, -19457, -19456, -19455, 128, 67, 90, + 128, 128, 130, 136, 129, -19454, -19453, -19452, -19451, -19450, -19449, -19448, + -19447, -19446, -19445, -19444, -19443, -19442, -19440, -19439, -19438, -19437, -19436, -19435, + -19434, -19433, -19432, -19431, -19430, -19429, -19428, -19427, -19426, -19425, -19424, -19423, + -19422, 16, 8, 13, 72, 216, 220, 11, 220, 218, 256, 183, + 257, 248, 265, 211, 280, 163, 149, 218, 154, 273, 222, 218, + 259, 154, 258, 273, 278, 282, 332, 352, 352, 278, 286, 280, + 324, 213, 328, 280, 337, 337, 337, 294, 336, 281, 336, -19421, + -19420, 336, 1, 1, 1, -19419, -19418, -19416, -19415, -19414, -19413, -19412, + -19411, 1, 1, 1, -19410, 1, 2, 4, 4, 9, 10, 2, + 2, 6, 1, 16, 1, 25, 4, 25, 22, 2, 1, 1, + 7, 5, 8, 53, 53, -19409, 52, 64, 64, -19407, -19406, -19405, + -19404, 5, 1, 9, 11, -19402, -19401, 64, 64, -19400, -19399, -19398, + -19397, -19396, 0, 0, 0, -19395, 69, 71, 69, 76, 79, 90, + 97, 100, -19394, 98, 98, 98, -19393, -19392, -19391, -19390, 2, 10, + 12, 9, 9, 16, 9, 16, -19389, -19388, 16, -19387, 0, 0, + -19386, -19385, -19384, -19383, -19382, -19381, -19380, -19379, -19378, -19377, -19376, -19375, + -19374, -19373, -19372, -19371, -19370, -19369, -19368, -19367, -19366, -19365, -19364, -19363, + -19362, -19361, -19360, -19359, -19358, -19357, -19356, -19355, -19354, -19353, 9, 13, + 41, 36, 43, 64, 46, 64, 64, 64, 64, 64, -19352, 64, + 64, -19351, -19350, -19349, 29, -19348, -19347, -19346, -19345, -19344, -19343, -19342, + -19341, -19340, -19339, -19338, -19337, 45, -19336, -19335, -19334, -19333, -19332, -19331, + -19330, -19329, -19328, -19327, -19326, -19325, -19324, -19323, -19322, -19321, -19320, -19319, + -19318, -19317, -19316, -19315, -19314, -19313, -19312, -19311, -19310, 0, 0, 0, + 0, -19309, 1, 1, -19308, 1, 2, 21, 5, 32, 20, 26, + 32, 32, 32, 36, 32, -19307, 0, 0, 0, 0, -19306, -19305, + 0, 0, -19304, -19303, -19302, -19301, -19300, -19299, -19298, -19297, -19296, -19295, + -19294, -19293, 0, 0, 0, -19292, 0, 0, 0, 0, 0, 0, + 0, 0, -19291, -19290, -19289, -19288, -19287, -19286, -19285, -19284, -19283, -19282, + -19281, -19280, 0, 0, -19279, -19278, -19275, -19274, -19273, -19272, -19271, -19270, + -19269, -19268, -19267, -19266, -19265, -19264, -19263, -19262, -19261, -19260, -19259, -19258, + -19253, -19246, -19213, 0, 0, -19193, -19192, -19191, -19190, -19189, -19188, -19187, + -19186, -19185, -19184, -19183, -19182, -19181, -19180, -19179, -19178, -19177, -19173, -19172, + -19171, -19169, -19168, -19167, -19166, -19165, -19164, -19163, -19162, -19161, -19160, -19159, + -19158, -19157, 0, -19156, 0, -19155, 0, 0, 0, 0, -19154, -19153, + -19152, -19151, -19150, -19149, -19148, -19147, -19146, -19145, -19144, -19143, -19142, -19141, + -19140, -19139, -19138, -19137, -19136, -19135, -19134, -19133, -19132, -19131, -19130, -19129, + -19128, -19127, -19126, -19125, -19124, -19123, -19122, -19121, -19120, -19119, 0, 0, + -19118, -19117, 0, 0, 0, 0, 0, 0, 0, 0, -19116, -19115, + -19114, -19113, -19112, -19111, -19110, -19109, -19108, -19107, -19106, -19105, -19104, -19103, + -19102, -19101, -19100, -19099, -19098, -19097, -19096, -19095, -19094, -19093, 0, 0, + -19092, -19091, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -19090, -19089, 19, 20, + 16, 19, 19, 28, 37, 67, 68, 70, -19088, -19087, -19086, -19085, + 31, 59, 64, 66, 64, 66, 64, 66, 64, -19084, 65, 66, + 88, 91, 65, 66, 97, 125, 81, 99, 103, 117, 124, 288, + 295, 315, 384, 388, -19083, -19082, -19081, -19080, 310, 1, 228, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 18, 42, 10, 33, 33, 37, 33, 45, 82, 88, -19079, -19078, + -19077, -19076, -19075, -19074, -19073, -19072, 74, 74, 76, 78, 97, 101, + 96, 96, 96, 96, 96, 96, 96, 111, 96, 155, 1, 4, + 4, 1, 8, 8, 8, -19071, -19070, -19069, -19068, -19067, -19066, -19065, + -19064, 6, 3, -19063, -19062, -19061, 32, 32, 32, 36, 32, 36, + 38, 44, 44, 44, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 85, -19060, -19059, + -19058, 83, -19057, 0, -19056, -19055, -19054, -19053, -19052, -19051, 274, 274, + 0, 259, 1, 1, 1, 257, 256, 256, 257, -19050, 262, -19049, + -19048, -19047, -19046, -19045, -19044, 1, 1, 1, 1, 9, 9, 1, + 1, 1, 1, 1, 1, 263, 265, 1, 1, 1, 264, -19043, + 260, -19042, -19041, 265, 261, -19040, 259, -19039, 288, -19038, 288, -19037, + -19036, 289, 1, 1, 1, 1, -19035, -19034, 1, 1, 278, -19033, + 288, 288, 288, -19032, -19031, 256, 1, 1, 1, 1, 1, 1, + 1, 256, 257, 6, 28, 265, -19030, 265, -19029, 1, 264, -19028, + 267, 0, -19027, 276, -19026, 258, 1, 1, 1, 1, 1, 1, + 1, 12, 2, 11, 13, 16, -19025, -19024, -19023, -19022, -19021, -19020, + -19019, -19018, -19017, -19016, -19015, -19014, 1, 1, 4, 1, 1, 8, + 1, 3, 4, 6, 2, -19013, -19012, -19011, -19010, 1, 2, 4, + 1, 8, 8, 2, 2, 1, -19009, -19008, 4, 2, -19007, -19006, + -19005, -19004, -19003, -19002, -19001, -19000, 65, 68, 65, -18999, 72, 71, + 119, 73, -18998, -18997, -18996, -18995, -18994, -18993, -18992, -18991, -18990, -18989, + -18988, -18987, -18986, -18985, -18984, -18983, -18982, -18981, -18980, -18979, -18978, -18977, + -18976, -18975, -18974, -18973, -18972, -18971, -18970, -18969, -18968, -18967, -18966, -18965, + -18964, -18963, 118, 120, 120, 69, 123, 204, 126, 116, -18962, -18961, + 192, 71, -18960, -18959, -18958, -18957, 160, 160, 209, 317, 219, 336, + 292, 160, -18956, -18955, 337, 339, -18954, -18953, -18952, -18951, -18950, -18949, + -18948, -18947, -18946, -18945, -18944, -18943, -18942, -18941, -18940, -18939, -18938, -18937, + 48, 8, 139, 141, 161, 161, 172, 204, 5, 272, 284, 286, + -18936, -18935, -18934, 324, -18933, -18932, -18931, -18930, -18929, -18928, -18927, -18926, + -18925, -18924, -18923, -18922, -18921, -18920, -18919, -18918, -18917, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -18916, -18915, + -18914, -18913, 0, -18912, -18911, -18910, 0, 0, 0, 0, 0, 0, + 0, 0, -18909, -18908, -18907, -18906, -18905, -18904, -18903, -18902, -18901, -18900, + -18899, -18898, -18897, -18896, -18895, -18894, -18893, -18892, -18891, -18890, -18889, -18888, + -18887, -18886, -18885, -18884, -18883, -18882, -18881, -18880, -18879, -18878, -18877, -18876, + -18875, -18874, -18873, -18872, -18871, -18870, -18869, -18868, -18867, -18866, -18865, -18864, + -18863, -18862, -18861, -18860, -18859, -18858, 0, 0, 0, -18857, 0, 0, + 0, 0, 0, 0, 0, -18856, 12, 16, 16, 19, 17, 19, + 27, 38, 49, 38, 48, 54, 48, 144, 151, 144, -18855, -18854, + -18853, -18852, -18851, -18850, -18849, -18848, -18847, -18846, -18845, -18844, -18843, -18842, + -18841, -18840, -18839, -18838, -18837, 0, -18836, -18835, -18834, 0, 0, 0, + 0, 0, 0, 0, 0, -18833, 1, 1, 1, 1, 1, 1, + 1, 1, -18832, 4, 4, 17, -18831, -18830, -18829, -18828, 1, 1, + 1, -18827, -18826, 1, 1, -18825, -18824, -18823, -18822, -18821, -18820, -18819, + -18818, 1, -18817, -18816, -18815, -18814, -18813, -18812, -18811, -18810, -18809, -18808, + -18807, -18806, -18805, -18804, -18803, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -18802, -18801, -18800, + -18799, -18798, -18797, -18796, -18795, 0, 0, 0, 0, 0, 0, 0, + 0, -18794, -18793, -18792, -18791, -18790, -18789, -18788, -18787, -18786, -18785, -18784, + -18783, -18782, -18781, -18780, -18779, -18778, -18777, -18776, -18775, -18774, -18773, -18772, + -18771, -18770, -18769, -18768, -18767, -18766, -18765, -18764, -18763, -18762, -18761, -18760, + -18759, -18758, -18757, -18756, -18755, -18754, -18753, -18752, -18751, -18750, -18749, -18748, + -18747, -18746, 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, + 1, 1, 2, 2, 16, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 5, 31, 1, 32, 2, 4, -18745, -18744, + -18743, -18742, -18741, -18740, -18739, -18738, -18737, -18736, -18735, -18734, -18733, -18732, + -18731, -18730, 1, 1, 1, 5, 1, 1, 8, 5, 1, 3, + 1, 16, -18729, -18728, -18727, -18726, -18725, -18724, -18723, -18722, -18721, -18720, + -18719, -18718, -18717, -18716, -18715, -18714, -18713, -18712, -18711, -18710, -18709, -18708, + -18707, -18706, -18705, -18704, -18703, -18702, -18701, -18700, -18699, -18698, -18697, -18696, + -18695, -18694, 1, 1, 4, 8, 10, 8, 14, 16, 16, 16, + 16, -18693, 16, 16, 16, 3, -18692, -18691, -18690, -18689, -18688, -18687, + -18686, -18685, 3, -18684, -18683, -18682, 8, 2, 8, 10, -18681, -18680, + -18679, -18678, -18677, -18676, -18675, -18674, -18673, -18672, -18671, -18670, -18669, -18668, + -18667, -18666, 8, 10, 14, 18, 18, 21, 21, 18, -18665, -18664, + -18663, 18, -18662, -18661, -18660, -18659, -18658, -18657, -18656, -18655, -18654, -18653, + -18652, -18651, -18650, -18649, -18648, -18647, -18646, -18645, -18644, -18643, -18642, -18641, + -18640, -18639, -18638, -18637, -18636, -18635, -18634, -18633, -18632, -18631, -18630, -18629, + -18628, -18627, -18626, -18625, -18624, -18623, -18622, -18621, -18620, -18619, -18618, -18617, + -18616, -18615, -18614, -18613, -18612, -18611, -18610, -18609, -18608, -18607, -18606, -18605, + -18604, -18603, -18602, -18601, -18600, -18599, -18598, -18597, -18596, -18595, -18594, -18593, + 1, 1, -18592, 1, 1, -18591, -18590, -18589, -18588, -18587, -18586, -18585, + -18584, -18583, -18582, -18581, -18580, -18579, -18578, -18577, -18576, 0, -18575, -18574, + -18573, -18572, 1, 1, -18571, 1, 1, 1, 1, 1, 2, 2, + 8, 3, 1, 3, 1, 17, 1, 16, 1, 7, 1, -18570, + -18569, 1, 1, 5, 1, 1, 1, 6, 1, 39, 2, 50, + 13, 11, -18568, -18567, -18566, -18565, -18564, -18563, -18562, -18561, -18560, -18559, + -18558, -18557, -18556, -18555, -18554, -18553, 16, 16, 16, 16, -18552, -18551, + -18550, -18549, -18548, -18547, -18546, -18545, -18544, -18543, -18542, -18541, 1, 5, + 5, 1, 8, 12, 8, 26, 2, 2, 2, 38, 3, 33, + 44, 48, 32, 32, 32, 32, 32, 40, 32, 32, -18540, -18539, + 32, -18538, -18537, -18536, -18535, -18534, 24, 24, 68, 24, 64, 64, + 72, 64, -18533, -18532, -18531, -18530, -18529, -18528, -18527, -18526, 88, 88, + 88, 88, 128, 128, 128, -18525, -18524, 128, 128, -18523, -18522, -18521, + -18520, 141, 2, 4, 1, 3, 8, 2, 2, 1, 1, 1, + 1, 16, 1, 17, 1, -18519, -18518, -18517, -18516, -18515, -18514, -18513, + -18512, -18511, -18510, -18509, -18508, -18507, -18506, -18505, -18504, -18503, -18502, -18501, + -18500, -18499, -18498, -18497, 0, -18496, -18495, -18494, -18493, -18492, 0, -18491, + 0, -18490, -18489, -18488, -18487, -18486, -18485, -18484, -18483, -18482, -18481, -18480, + -18479, -18478, -18477, -18476, -18475, -18474, -18473, -18472, -18471, -18470, -18469, -18468, + 0, 0, -18467, -18466, -18465, -18464, 0, 0, 0, -18463, 1, 1, + -18462, -18461, 1, 1, -18460, 1, 1, 1, 1, -18459, -18457, -18451, + -18449, 1, 1, 1, -18448, -18447, 1, 1, -18444, 1, 1, 1, + 1, 1, -18443, -18442, -18441, -18440, -18439, -18438, -18437, -18436, -18435, -18434, + -18433, -18432, -18431, -18430, -18429, -18428, 0, 0, 0, -18427, -18426, -18425, + -18424, 1, 0, 0, -18423, 1, 1, 4, 4, 1, -18422, -18421, + 9, -18420, -18419, -18418, -18417, -18416, -18415, -18414, -18413, -18412, -18411, -18410, + -18409, -18408, -18407, -18406, -18405, -18404, -18403, -18402, -18401, -18400, -18399, -18398, + -18397, -18396, -18395, -18394, -18393, -18392, -18391, -18390, -18389, -18388, 2, 5, + 12, -18387, -18386, 10, 26, 34, -18385, -18384, -18383, 33, 37, 44, + 44, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, -18382, + 1, -18381, 1, -18380, 1, -18379, 1, 1, 4, 6, -18378, -18377, + 24, 9, 16, 32, 16, 32, -18376, -18375, 18, 2, 1, 1, + 4, -18374, -18373, 2, 2, 2, 1, -18372, 5, 50, -18371, -18370, + 3, 1, 4, 6, 12, 12, -18369, 23, 21, -18368, -18367, -18366, + 16, 116, -18365, -18364, 22, 14, 5, 10, 34, 2, 35, 64, + 66, 69, 64, 64, 64, 64, 66, 64, 79, 1, 1, 6, + 8, -18363, -18362, 9, 13, 27, 23, 7, 32, 22, 32, 23, + 32, 28, 14, 16, 16, 19, 16, 16, 25, 16, 16, 43, + 130, 47, 136, 143, 148, 3, 3, 7, 9, -18361, 9, 20, + 15, 31, 17, 129, -18360, 24, 131, 136, 142, 16, 16, 20, + 20, 16, 27, 31, 154, 145, 170, 144, 186, 152, 184, 165, + 185, -18359, -18358, 3, 3, -18357, -18356, -18355, -18354, -18353, -18352, -18351, + -18350, -18349, -18348, -18347, -18346, 1, 7, 13, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 18, 16, 33, -18345, -18341, -18340, + -18339, -18338, -18337, -18336, -18335, -18334, -18333, -18332, -18331, -18330, -18329, -18328, + -18327, -18326, -18325, -18324, -18323, -18322, -18321, -18320, -18319, 2, 1, 1, + -18318, 5, 11, 2, 13, -18317, -18316, -18315, -18314, -18313, -18312, -18311, + -18310, -18309, -18308, -18307, -18306, -18305, -18304, -18303, -18302, -18301, -18300, -18299, + -18298, -18297, -18296, -18295, -18294, -18293, -18292, -18291, -18290, -18289, -18288, -18287, + -18286, -18285, -18284, -18283, -18282, -18281, -18280, -18279, -18278, -18277, -18276, -18275, + -18274, -18273, -18272, -18271, -18270, -18269, -18268, -18267, -18266, -18265, -18264, -18263, + -18262, -18261, -18260, -18259, -18258, -18257, -18256, -18255, -18254, 1, 1, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 30, 32, 18, 16, 20, 16, 26, 16, 30, 86, 17, 38, + 87, 96, 108, 108, 112, 112, 96, 96, 96, -18253, -18252, 96, + 96, -18251, -18250, -18249, -18248, -18247, -18246, -18245, -18244, 98, -18243, -18242, + -18241, -18240, -18239, -18238, -18237, -18236, -18235, -18234, -18233, -18232, -18231, -18230, + -18229, -18228, 1, 6, 6, -18227, -18226, 9, 12, 1, -18225, -18224, + 1, 4, -18223, -18222, -18221, -18220, -18219, -18218, -18217, -18216, -18215, -18214, + -18213, -18212, -18211, -18210, -18209, -18208, -18207, -18206, -18205, 0, -18204, -18203, + -18202, 0, 0, 0, 0, -18201, -18200, -18199, -18198, -18197, -18196, -18195, + -18194, -18193, -18192, -18191, -18190, -18189, -18188, -18187, -18186, -18185, -18184, -18183, + -18182, -18181, -18180, -18179, -18178, -18177, -18176, -18175, -18174, -18173, -18172, -18171, + -18170, -18169, -18168, -18167, -18166, -18165, -18164, -18163, -18162, -18161, -18160, -18159, + -18158, -18157, -18156, -18155, -18154, -18153, -18152, -18151, -18150, -18149, -18148, -18147, + -18146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -18145, -18144, -18143, -18142, 0, 0, + -18141, 0, -18140, -18139, -18138, 0, 0, 0, -18137, 1, -18136, 1, + -18135, -18134, 1, -18133, -18132, -18131, 1, 1, -18130, -18129, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -18128, -18127, + -18126, 1, 1, 1, 1, -18125, 0, 0, 0, 0, 0, -18124, + 0, -18123, -18122, -18121, 0, -18120, -18119, 0, -18118, 1, 1, 1, + 1, -18117, -18116, -18115, 1, 1, -18114, -18113, -18112, 1, 1, 1, + 1, 1, -18111, -18110, -18109, -18108, 1, 1, -18107, -18106, -18105, -18104, + -18103, 3, -18102, 2, -18101, 0, -18100, -18099, 17, -18098, -18097, -18096, + -18095, -18094, -18093, -18092, -18091, -18090, -18089, -18088, -18087, 1, 1, 1, + 4, -18086, -18085, -18084, -18083, -18082, -18081, -18080, -18079, -18078, -18077, -18076, + -18075, 3, -18074, -18073, -18072, -18071, -18070, -18069, -18068, -18067, -18066, -18065, + -18064, -18063, -18062, -18061, -18060, 0, -18059, -18058, -18057, -18056, -18055, -18054, + -18053, -18052, 0, 0, -18051, -18050, 0, 0, 0, -18049, -18048, -18047, + -18046, -18045, -18044, -18043, -18042, 0, 0, 0, 0, 0, 0, 0, + 0, -18041, -18040, -18039, -18038, -18037, -18036, -18035, -18034, -18033, -18032, -18031, + -18030, 0, -18029, -18028, -18027, -18026, -18025, -18024, -18023, -18022, -18021, -18020, + -18019, -18018, -18017, -18016, -18015, -18014, -18013, -18012, -18011, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -18010, -18009, -18008, -18007, -18006, 0, 0, -18005, -18004, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -18003, -18002, -18001, -18000, -17999, -17998, -17997, -17996, -17995, -17994, -17993, + -17992, -17991, -17990, -17989, -17988, -17987, -17986, -17985, -17984, -17983, -17982, -17981, + -17980, -17979, -17978, -17977, -17976, -17975, -17974, -17973, -17972, 0, -17971, -17970, + -17969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17968, -17967, -17966, -17965, -17964, -17963, -17962, -17961, -17960, -17959, -17958, + -17957, -17956, -17955, -17954, -17953, -17952, -17951, -17950, -17949, -17948, -17947, -17946, + -17945, -17944, -17943, -17942, -17941, -17940, -17939, -17938, -17937, -17936, -17935, -17934, + -17933, -17932, -17931, -17930, -17929, -17928, -17927, -17926, -17925, -17924, -17923, -17922, + -17921, 0, -17920, -17919, -17918, 0, 0, 0, 0, -17917, -17916, 0, + 0, -17915, -17914, -17913, -17912, -17911, -17910, -17909, -17908, -17907, -17906, -17905, + -17904, -17903, -17902, -17901, -17900, -17899, -17898, -17897, -17896, -17895, -17894, -17893, + -17892, -17891, -17890, -17889, -17888, -17887, -17886, -17885, -17884, -17883, -17882, -17881, + -17880, -17879, -17878, -17877, -17876, -17875, -17874, -17873, -17872, -17871, -17870, -17869, + -17868, -17867, -17866, -17865, -17864, -17863, -17862, -17861, -17860, -17859, -17858, -17857, + -17856, -17855, -17854, -17853, -17852, -17851, -17850, -17849, -17848, -17847, -17846, -17845, + -17844, -17843, -17842, -17841, -17840, -17839, -17838, -17837, -17836, -17835, -17834, -17833, + -17832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17831, -17830, -17829, -17828, -17827, -17826, -17825, + -17824, 0, 0, 0, -17823, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -17822, -17821, -17820, -17819, -17818, -17817, + -17816, -17815, -17814, -17813, -17812, -17811, 0, 0, 0, 0, -17810, -17809, + -17808, -17807, -17806, -17805, -17804, -17803, -17802, -17801, -17800, -17799, -17798, -17797, + -17796, -17795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17794, -17793, -17792, -17791, -17790, -17789, -17788, + -17787, -17786, -17785, -17784, -17783, 0, -17782, -17781, -17780, -17779, -17778, -17777, + -17776, -17775, -17774, -17773, -17772, -17771, -17770, -17769, -17768, -17767, -17766, -17765, + -17764, -17763, -17762, -17761, -17760, -17759, -17758, -17757, -17756, -17755, -17754, -17753, + -17749, -17748, -17747, -17746, -17745, -17744, -17743, -17742, -17741, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, -17740, -17739, -17738, + -17737, 0, 0, 0, 0, 0, -17736, -17735, 0, 0, -17734, -17733, + -17732, 1, -17730, -17729, -17728, -17727, -17726, -17724, -17723, -17722, -17721, -17720, + -17719, -17718, -17716, -17714, -17713, -17712, -17708, -17706, -17703, -17702, -17700, -17699, + -17698, 0, -17697, -17696, -17692, 0, 0, 0, -17691, -17690, -17686, -17682, + 0, 0, 0, 0, -17681, 0, 0, 0, 0, 0, 0, 0, + 0, -17680, -17677, -17676, -17675, 0, 0, 0, -17674, 0, 0, 0, + 0, 0, 0, 0, 0, -17673, -17672, -17671, 0, -17670, -17669, -17668, + -17667, -17666, -17665, -17664, -17663, -17662, -17661, -17660, -17659, -17658, -17657, -17656, + -17655, -17654, -17653, -17652, -17651, -17650, -17649, -17648, -17647, -17646, -17645, -17644, + -17643, -17642, -17641, -17640, -17639, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, -17638, -17637, -17636, -17635, 1, 1, -17634, + -17633, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, -17632, -17631, -17630, -17629, 0, 0, 0, 0, 0, 0, 0, + 0, -17628, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, -17627, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -17626, -17625, + -17624, 0, -17623, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17622, -17621, -17620, -17619, -17618, -17617, -17616, -17615, -17614, -17613, -17612, + -17611, -17610, -17609, -17608, -17607, -17606, -17605, -17604, -17603, -17602, -17601, -17600, + -17599, -17598, -17597, -17596, -17595, -17594, -17593, -17592, -17591, -17590, 0, 0, + 0, -17589, -17588, -17587, -17586, -17585, -17584, -17583, -17582, -17581, -17580, -17579, + -17578, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17577, -17576, -17575, -17574, -17573, -17572, -17571, + -17570, -17569, -17568, -17567, -17566, -17565, -17564, -17563, -17562, -17561, -17560, -17559, + -17558, -17557, -17556, -17555, -17554, -17553, -17552, -17551, -17550, -17549, -17548, -17547, + -17546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17545, -17544, -17543, -17542, -17541, -17540, -17539, + -17538, 0, 0, -17537, -17536, 0, 0, 0, 0, -17535, -17534, -17533, + -17532, -17531, -17530, -17529, -17528, 0, 0, 0, -17527, 0, 0, 0, + 0, -17526, -17525, -17524, -17523, -17522, -17521, -17520, -17519, -17518, -17517, -17516, + -17515, -17514, -17513, -17512, -17511, -17510, 0, 0, 0, -17509, 1, 1, + -17508, -17507, 1, 1, 1, 1, 1, 1, 1, 1, -17506, -17505, + -17504, -17503, -17502, -17501, -17500, 0, 0, 0, 0, 0, 0, 0, + 0, -17499, -17498, -17497, -17496, -17495, -17494, -17493, -17492, -17491, -17490, -17489, + -17488, -17487, -17486, -17485, -17484, -17483, -17482, 0, 0, -17481, -17480, -17479, + -17478, -17477, -17476, -17475, -17474, -17473, -17472, -17471, -17470, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17469, -17468, -17467, -17466, -17465, -17464, -17463, + -17462, -17461, -17460, -17459, -17458, -17457, -17456, -17455, -17454, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17453, 0, 0, -17452, -17451, -17450, -17449, + -17448, -17447, -17446, -17445, -17444, -17443, -17442, -17441, -17440, 0, 0, 0, + 0, -17439, -17438, -17437, 0, -17436, -17435, -17434, -17433, -17432, 0, 0, + -17431, -17430, -17429, 0, -17428, -17427, -17426, -17425, 0, 0, 0, -17424, + -17423, 0, 0, -17422, 0, -17421, -17420, -17419, -17418, -17417, -17416, -17415, + -17414, -17413, -17412, 0, -17411, -17410, -17409, -17408, -17407, 0, 0, 0, + -17406, 0, 0, 0, 0, 0, 0, 0, 0, -17405, -17404, -17403, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -17402, + -17401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17400, -17399, -17398, -17397, -17396, -17395, -17394, -17393, -17392, -17391, -17390, + -17389, -17388, 0, -17387, -17386, -17385, -17384, -17383, -17382, 0, -17381, -17380, + -17379, -17378, -17377, 0, -17376, -17375, 0, -17374, -17373, -17372, -17371, -17370, + -17369, -17368, -17367, -17366, -17365, -17364, -17363, -17362, -17361, -17360, -17359, -17358, + -17357, -17356, -17355, -17354, -17353, -17352, -17351, -17350, -17349, 0, 0, 0, + -17348, 0, 0, 0, 0, -17347, -17346, -17345, -17344, -17343, -17342, -17341, + -17340, -17339, -17338, -17337, -17336, 0, -17335, -17334, -17333, -17332, -17331, -17330, + -17329, -17328, -17327, -17326, -17325, -17324, -17323, -17322, -17321, -17320, -17319, -17318, + -17317, -17316, -17315, -17314, -17313, -17312, -17311, -17310, -17309, 0, 0, -17308, + -17307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -17306, 0, -17305, + -17304, -17303, -17302, -17301, -17300, -17299, -17298, -17297, -17296, -17295, -17294, -17293, + -17292, -17291, -17258, -17257, -17256, -17255, -17254, -17253, -17252, -17251, -17249, -17248, + -17247, -17246, -17234, -17230, -17229, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -17223, -17204, -17202, + -17201, -17200, -17199, -17198, -17196, -17195, -17189, -17188, -17187, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -17186, -17185, -17182, -17180, -17166, -17162, -17160, + -17159, -17158, -17157, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, -17156, 1, 1, 1, 1, 1, 1, 1, 1, + 1, -17155, -17154, -17153, -17151, -17150, -17149, -17148, -17147, -17146, -17145, 0, + 0, 0, 0, 0, 0, -17144, -17143, -17142, -17141, -17140, -17139, -17138, + -17137, -17136, -17135, -17134, -17133, 0, -17132, -17131, -17130, 0, 0, 0, + 0, 0, 0, 0, 0, -17129, -17128, -17127, -17126, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -17125, + -17124, -17123, -17122, -17121, -17120, -17119, -17118, -17117, -17116, -17115, -17114, -17113, + -17112, -17111, -17110, -17109, -17108, -17107, -17106, -17105, -17104, -17103, -17102, -17101, + -17100, -17099, -17098, -17097, -17096, -17095, -17094, -17093, -17092, -17091, -17090, -17089, + -17088, -17087, -17086, -17085, -17084, -17083, -17082, -17081, -17080, -17079, -17078, -17077, + -17076, -17075, -17074, -17073, -17072, -17071, -17070, -17069, -17068, -17067, -17066, -17065, + -17064, -17063, -17062, -17061, -17060, -17059, -17058, -17057, -17056, -17054, -17053, -17052, + -17051, -17049, -17048, -17047, -17046, -17045, -17044, -17043, -17042, -17041, -17040, -17038, + -17037, -17036, -17035, -17034, -17033, -17032, -17031, -17030, -17029, -17028, -17027, -17025, + -17024, -17023, -17022, -17021, -17020, -17019, -17018, -17016, -17015, -17014, -17013, -17012, + -17011, -17010, -17009, -17008, -17007, -17006, -17004, -17002, -17000, 1, 1, 4, + 4, 1, 1, 12, 12, 20, 20, 16, 16, 24, 24, 24, + 24, 2, 2, 41, 42, 40, 43, 41, 42, 32, 48, 52, + 55, 56, 56, 56, 56, -16998, -16997, -16996, -16995, -16994, -16991, -16990, + -16985, -16984, -16983, -16981, -16980, -16979, -16977, -16973, -16970, 16, 16, 16, + 16, 25, 26, 28, 31, 19, 64, 64, 64, 64, 64, 64, + 64, 2, 2, 2, 2, 18, 18, 2, 1, -16969, -16967, 1, + 1, -16966, -16965, -16964, -16963, -16962, -16961, -16960, -16959, 1, -16958, 2, + 4, -16957, -16956, -16955, -16953, -16946, -16942, -16941, -16940, -16939, -16938, -16937, + -16936, -16935, -16934, -16933, -16932, -16931, -16930, -16929, -16928, -16927, -16926, -16925, + -16924, -16923, -16922, -16921, -16920, -16919, -16918, -16917, -16916, -16915, -16914, -16913, + -16912, -16911, -16910, -16909, -16908, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, -16907, -16906, -16905, -16904, -16903, -16902, -16901, -16900, -16899, + -16898, -16897, -16896, -16895, -16894, -16893, -16892, -16891, -16890, -16889, -16888, -16887, + -16886, -16885, -16884, -16883, -16882, 0, 0, 0, -16881, 0, 0, 0, + 0, 0, 0, 0, 0, -16880, -16879, -16878, -16877, -16876, -16875, -16874, + -16873, -16872, -16871, -16870, -16869, -16868, -16867, -16866, -16865, -16864, -16863, -16862, + -16861, -16860, -16859, -16858, -16857, 0, 0, -16856, -16855, 0, 0, 0, + 0, 0, 0, 0, 0, -16854, 0, 0, 0, 0, -16853, -16852, + -16851, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -16850, -16849, -16848, + -16847, -16846, -16845, -16844, -16843, 0, 0, -16842, -16841, 0, 0, 0, + 0, -16839, -16838, -16837, -16836, -16835, -16833, -16830, -16829, -16828, -16826, -16825, + -16824, -16823, -16822, -16821, -16820, -16819, -16818, -16817, -16816, -16815, -16814, -16813, + -16812, -16811, -16810, -16809, -16806, 0, 0, 0, 0, 0, -16805, -16803, + -16799, -16782, 0, -16781, -16780, -16778, 0, 0, 0, 0, 0, 0, + 0, 0, -16776, -16775, -16773, -16772, -16769, -16768, -16767, -16766, -16764, -16763, + -16762, -16761, -16760, -16759, -16758, -16757, -16756, -16755, -16754, -16752, 0, -16751, + -16750, -16749, -16748, -16747, -16746, -16745, 0, -16744, -16743, -16742, -16740, -16739, + -16738, -16737, 0, -16736, -16735, -16734, -16733, -16732, -16731, -16730, 0, -16729, + -16728, -16727, -16726, -16725, -16724, -16723, 0, -16722, -16721, -16720, -16719, -16718, + -16717, -16716, 0, -16715, -16714, 1, 1, 1, 1, 1, -16713, 1, + 1, 1, 1, 1, 1, 1, -16712, 1, 1, 1, -16711, -16710, + -16709, -16708, -16707, -16706, -16705, -16704, -16703, -16702, -16701, -16700, -16699, -16698, + -16697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -16696, 1, 1, 1, 1, 1, 1, + 1, -16695, 1, 1, 1, -16694, -16693, -16692, -16691, -16690, -16689, -16688, + -16687, -16686, -16685, -16684, -16683, -16682, -16681, -16680, -16679, -16678, -16677, -16676, + -16675, 1, 1, 1, 1, 1, 1, 1, 1, -16674, -16673, 1, + 1, -16672, -16671, -16670, -16669, -16668, -16667, -16666, -16665, -16664, -16663, 0, + -16662, -16661, 0, 0, 0, 0, 0, 0, -16660, 0, -16659, -16658, + -16657, -16656, -16655, -16654, -16653, -16652, -16651, -16634, -16631, -16606, -16602, -16601, + -16598, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, -16597, -16596, -16595, -16594, -16593, -16592, + -16591, -16590, -16589, -16588, -16587, -16586, -16585, -16584, -16583, 0, -16582, -16581, + -16580, -16579, -16578, -16577, -16576, -16575, 0, 0, 0, 0, 0, 0, + 0, -16574, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, -16573, -16572, 1, 1, -16571, -16570, -16569, -16568, -16567, -16566, -16565, + -16564, -16563, -16562, -16561, 1, -16560, -16559, -16558, -16557, -16556, -16555, -16554, + -16553, -16552, -16551, -16550, -16549, -16548, -16547, -16546, -16545, -16544, -16543, -16542, + -16541, -16540, -16539, -16538, -16537, -16536, -16535, -16534, -16533, -16532, -16531, -16530, + -16529, -16528, -16527, -16526, -16525, -16524, -16523, -16522, -16521, -16520, -16519, -16518, + -16517, -16516, -16515, -16514, -16513, -16512, -16511, -16510, -16509, -16508, -16507, -16506, + -16497, -16496, -16495, -16494, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -16493, 0, -16492, -16491, -16490, -16489, 0, 0, + 0, -16486, -16483, 0, 0, 0, 0, -16482, -16481, -16480, -16479, -16477, + -16476, -16475, -16471, -16470, -16469, -16468, -16466, -16465, -16464, -16463, -16462, -16461, + -16460, -16459, -16442, -16437, -16435, -16417, -16408, -16394, -16393, -16392, -16391, -16390, + -16389, -16388, -16387, -16386, -16385, -16384, -16383, -16382, -16381, -16380, -16379, -16378, + -16377, -16376, -16375, -16374, -16373, -16372, -16371, -16370, -16369, -16367, -16366, -16365, + -16364, -16363, -16362, -16361, -16360, -16359, -16358, -16357, -16356, -16355, 0, -16354, + -16353, -16352, -16351, -16350, -16349, -16348, -16347, -16346, -16345, -16344, -16343, -16342, + -16339, -16334, 0, -16330, -16329, -16328, -16327, -16326, -16325, -16324, -16323, -16322, + -16321, -16320, -16319, -16318, -16317, -16316, -16315, -16314, -16313, -16312, -16311, -16310, + -16309, -16308, -16307, -16306, -16305, -16304, -16303, -16302, -16301, -16300, -16299, -16298, + 0, 0, -16297, -16296, -16295, -16294, -16293, -16292, -16291, -16290, -16289, -16288, + -16287, -16286, -16285, -16284, -16283, -16282, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -16281, -16280, -16279, + -16278, -16277, -16276, -16275, -16274, -16273, -16272, -16271, -16270, -16269, -16268, -16267, + -16266, -16265, -16264, -16263, -16262, -16261, -16260, -16259, -16258, -16257, -16256, -16255, + -16254, -16253, -16252, -16251, -16250, -16249, -16248, -16247, -16246, -16245, -16244, -16243, + -16242, -16241, -16240, -16239, -16238, -16237, -16236, -16235, -16234, -16233, -16232, -16231, + -16230, -16229, -16228, -16227, -16226, -16225, -16224, -16223, -16222, -16221, -16220, -16219, + -16218, 0, -16217, -16216, -16215, 0, 0, 0, 0, 0, 0, 0, + 0, -16214, 0, 0, 0, -16213, -16212, -16211, -16210, -16209, -16208, -16207, + -16206, -16205, -16204, -16203, -16190, -16185, -16182, -16181, -16179, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -16178, -16177, -16176, -16175, -16173, -16172, + -16171, -16170, -16169, -16168, -16167, -16166, -16165, -16164, -16163, -16162, -16161, -16160, + -16159, -16157, -16155, -16140, -16138, -16135, -16134, -16133, -16131, -16127, -16124, -16122, + -16121, -16120, -16119, -16118, -16117, -16116, -16115, -16114, -16113, -16112, -16111, -16110, + -16109, -16108, -16107, -16106, -16105, -16104, -16103, -16102, -16101, -16100, -16099, -16098, + -16097, -16095, -16094, -16093, -16092, -16091, -16090, -16089, -16088, -16087, -16086, -16084, + -16083, -16082, -16081, -16080, -16079, -16078, -16077, -16076, -16075, -16059, -16053, -16049, + -16048, -16047, -16045, -16044, -16043, -16042, -16038, -16037, -16036, -16035, -16031, -16030, + -16028, -16025, -16024, -16023, -16020, -16019, -16018, -16017, -16014, -16010, -16009, -16008, + -16007, -16006, -16005, -16004, -16003, -16002, -16001, -16000, -15999, -15998, -15997, -15996, + -15995, -15994, -15993, -15992, -15991, -15990, -15989, -15988, -15987, -15986, -15985, -15984, + -15983, -15982, -15981, -15980, -15979, -15978, -15977, -15976, -15975, -15974, -15973, -15972, + -15971, -15970, -15969, -15968, -15967, -15966, -15965, -15964, -15963, -15962, -15961, -15960, + -15959, -15958, -15957, -15956, -15955, -15954, -15953, -15952, -15951, -15950, -15949, -15948, + -15947, -15946, -15945, -15944, -15943, -15942, -15941, -15940, -15939, -15938, -15937, -15936, + -15935, -15934, -15933, -15932, -15931, -15930, -15929, -15928, -15926, -15925, -15924, -15923, + -15922, -15921, -15920, -15919, -15918, -15917, -15916, -15915, -15914, -15913, -15912, -15911, + -15910, -15909, -15908, -15907, -15906, -15905, -15904, -15903, -15902, -15901, -15900, -15899, + -15897, -15896, -15895, -15894, -15893, -15892, -15891, -15890, -15889, -15888, -15887, -15886, + -15885, -15884, -15883, -15882, -15880, -15879, -15878, -15877, -15876, -15874, -15873, -15872, + -15871, -15870, 2, 1, -15869, -15868, -15867, -15866, 1, 1, -15865, -15864, + -15863, -15862, -15861, -15860, -15859, -15858, 1, 2, 4, 1, 1, 2, + 6, 8, 1, 3, 4, 15, -15857, 5, 3, 4, 1, 3, + 4, 16, 1, 1, 5, 7, -15856, 3, 3, 12, -15855, -15854, + -15853, -15852, 1, 1, 4, 1, 1, 1, 1, 8, 1, 1, + 1, 1, 1, 3, 16, 16, -15851, -15849, -15847, -15843, -15842, -15841, + -15840, -15839, -15838, -15835, -15834, -15833, -15832, -15831, -15830, -15829, -15828, -15827, + -15826, -15825, -15824, -15823, -15822, -15821, -15820, -15819, -15818, -15817, -15816, -15815, + -15814, 1, 1, 1, 1, 1, 8, 8, 3, 12, 1, 1, + 5, 1, 16, 16, 17, 24, -15813, -15812, -15811, -15810, -15809, -15808, + -15807, -15806, -15805, -15804, -15803, -15798, -15797, -15796, -15794, -15793, 6, 6, + 8, 8, 4, 4, 4, 4, 4, 4, 5, 41, 4, 4, + 24, 1, 2, 2, 6, 6, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 94, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 79, 1, 75, 1, 81, -15792, 89, + 147, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1, + 13, 14, 5, 32, 2, 33, 40, 32, 46, 137, 21, 29, + 5, 60, 7, 119, 146, 1, 144, 144, 144, 2, 2, 56, + 84, 154, 16, 116, 118, 130, 132, 147, 181, 191, 9, 158, + 209, 211, 240, 240, 256, 4, 4, 17, 69, 22, 261, 83, + 8, 6, 149, 257, 272, 148, 92, 272, 268, -15791, 57, 207, + 9, 211, -15790, -15789, -15788, -15787, -15786, -15785, -15784, 52, 52, 58, + 52, -15782, -15781, -15780, -15779, -15778, 1, 1, 4, 1, 3, 10, + 16, 16, 12, 1, 15, 2, 1, 1, 4, 177, 206, 265, + 282, 299, 304, 304, 308, 304, 307, 312, 314, 316, 258, 272, + 274, 272, 275, 280, 282, 274, 272, 274, 272, 303, 306, 274, + 317, -15776, -15775, -15774, -15773, -15772, -15771, -15770, -15769, -15768, -15767, -15766, + -15765, -15764, -15763, -15762, -15761, -15760, -15759, -15758, -15757, -15756, -15755, -15754, + -15753, -15752, 0, -15751, -15750, -15749, -15748, 0, 0, 0, -15747, -15746, + -15745, -15744, -15743, -15742, -15741, -15740, -15739, -15738, -15737, -15736, -15735, -15734, + -15733, -15732, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 96, + -15731, -15730, -15729, -15728, -15727, -15726, -15725, -15724, -15723, -15722, -15721, -15720, + -15719, -15718, -15717, -15716, -15715, -15714, -15713, 73, 82, 97, -15712, -15711, + -15710, 67, 113, 114, 112, -15709, -15708, -15707, -15706, -15705, 0, 0, + -15704, -15703, 0, 0, 0, 0, -15701, -15700, -15699, -15698, 1, 1, + 9, 34, 35, 38, 49, 50, 49, 57, 56, 1, 4, 8, + 8, 22, 8, 8, 14, 16, 16, 20, 22, 4, 23, 44, + 24, 32, 2, 2, 15, 128, 128, 128, 128, 128, -15697, 128, + 128, 128, 128, 128, 128, -15696, -15694, -15693, 2, -15691, 3, 6, + 4, 128, 128, 128, 128, 128, -15690, -15689, -15688, 128, 4, 4, + 11, -15687, 8, -15686, 16, 2, 20, 1, 65, 67, 65, 2, + 68, 6, 110, 128, 128, 128, -15685, -15684, -15683, 0, 0, -15682, + -15681, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15680, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15678, -15674, + -15673, -15672, -15671, -15670, -15669, -15668, -15667, -15666, -15665, 9, 11, 47, + 16, 48, -15664, -15663, -15662, -15661, -15660, -15659, -15658, -15657, -15656, -15655, + -15654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15653, -15652, + -15651, -15650, -15649, -15648, -15647, -15646, -15645, -15644, -15643, -15642, 0, 0, + -15641, -15640, -15639, -15638, -15637, -15636, -15635, -15634, -15633, -15632, -15631, -15630, + -15629, -15628, -15627, -15622, -15618, -15616, -15614, -15613, -15612, -15610, -15609, -15597, + -15596, -15595, -15594, -15593, -15592, -15591, -15590, -15589, -15588, -15587, -15586, -15585, + -15584, -15583, -15582, -15581, -15580, -15579, 0, 0, 0, -15574, 0, 0, + 0, 0, -15573, -15572, -15570, -15569, -15568, -15567, -15566, -15565, -15564, -15563, + -15562, 48, 53, 151, 60, 146, 164, 56, 167, 13, 7, 148, + 96, 100, 160, 153, 164, 221, -15561, 325, 325, 241, 188, 184, + 189, 190, 338, -15560, 341, 322, 341, 358, 347, -15558, -15557, -15556, + -15555, -15548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -15547, -15546, -15543, -15542, -15541, 322, 322, 334, 334, 336, 336, + 336, -15540, -15538, -15537, 336, 135, 67, 79, 96, 126, 152, 152, + 156, 166, -15536, -15535, 186, 168, -15533, -15532, -15531, 0, -15530, -15529, + 3, 0, -15528, -15527, -15526, -15525, -15524, -15523, -15522, -15521, -15520, -15519, + -15518, 248, -15517, 0, 0, -15516, -15515, -15514, -15513, -15512, -15511, -15510, + -15509, -15508, -15507, -15506, -15505, -15504, -15503, -15502, -15501, -15500, -15499, -15494, + -15493, -15492, -15490, -15486, -15482, 0, 0, 0, -15476, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15474, -15472, + -15469, -15467, -15466, -15464, -15463, -15434, 0, 0, -15433, -15432, 0, 0, + 0, 0, -15430, -15429, -15427, 0, -15426, -15425, -15422, -15421, -15420, -15419, + -15416, -15414, -15401, -15399, -15397, -15390, 0, 0, 0, 0, 0, 0, + 0, 0, -15386, -15385, -15384, -15383, -15382, -15381, -15380, -15379, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -15378, -15377, -15376, -15375, -15374, -15373, -15372, + -15371, -15241, -15240, -15239, -15238, -15198, -15197, -15196, -15195, -15188, -15187, -15185, + -15178, -15177, -15176, -15175, -15174, -15173, -15172, -15171, -15170, -15169, -15168, -15167, + -15166, -15165, -15164, -15163, -15162, -15161, -15160, -15159, -15158, -15157, -15156, -15155, + -15154, -15153, -15152, -15151, -15150, -15149, -15148, -15147, -15146, -15145, -15144, -15143, + -15142, -15141, -15140, -15139, -15138, -15137, -15136, -15135, -15134, -15133, -15132, -15131, + -15130, -15129, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 64, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, -15128, -15127, -15126, 2, -15125, 1, + 2, 2, 1, 1, 2, 8, 10, -15124, -15123, 2, 2, 8, + 31, 2, -15122, 5, 29, 1, 32, 32, 32, 1, 1, -15121, + -15120, -15119, 1, -15118, -15117, -15116, -15115, -15114, -15113, -15112, -15111, -15110, + -15109, -15108, -15107, -15106, -15105, -15104, -15103, -15102, -15101, -15100, -15099, -15098, + -15097, -15096, -15095, -15094, -15093, -15092, -15091, -15090, -15089, -15088, -15087, -15086, + -15085, -15084, -15083, -15082, -15080, -15079, -15078, -15077, -15076, -15075, -15074, -15073, + -15072, -15071, -15070, -15069, -15068, -15067, -15066, -15065, -15064, -15063, -15062, -15061, + -15060, -15059, -15058, -15057, -15056, -15054, -15053, -15052, -15051, -15050, -15049, -15048, + -15047, -15046, -15045, -15044, -15043, -15042, -15041, -15040, -15039, -15038, -15037, -15036, + -15035, -15034, -15033, -15032, -15031, -15030, -15029, -15028, -15027, -15026, -15025, -15024, + -15023, -15022, -15021, -15020, -15018, -15016, -15015, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 24, + 24, 28, 28, 25, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 150, 160, 160, 160, 128, 128, 133, + 134, 128, 131, 136, 136, 128, 132, 192, 192, 144, 192, 219, + 221, 192, 208, 202, 226, 208, 237, -15013, -15011, -15010, 222, 224, + 224, 233, 234, 232, 235, 2, 4, -15009, 8, 56, 59, -15008, + -15007, -15006, -15005, -15004, -15003, -15002, -15001, -15000, -14999, -14998, -14997, -14995, + -14994, -14993, -14992, -14987, -14986, -14975, -14973, -14972, -14970, -14967, -14925, -14924, + -14923, -14922, -14921, -14920, -14919, -14918, -14917, -14916, -14915, -14914, -14913, -14912, + -14911, -14910, -14909, -14908, -14907, -14906, -14905, -14904, -14903, -14902, -14900, -14899, + -14898, -14897, -14896, -14895, -14894, -14893, -14892, -14891, -14890, -14889, -14888, -14887, + -14886, -14885, -14884, -14883, -14882, -14881, -14880, -14879, -14878, -14877, -14875, -14874, + -14873, -14872, -14871, -14870, -14869, -14868, -14867, -14866, -14865, -14864, -14863, -14862, + -14861, -14860, -14859, -14858, -14857, -14856, -14855, -14854, -14853, -14852, -14851, -14850, + -14849, -14848, -14847, -14846, -14845, -14844, -14843, -14842, -14841, -14840, -14839, -14838, + -14837, -14836, -14835, -14834, -14833, -14832, -14831, -14830, -13567, -13566, -13529, -13528, + -13527, -13526, -13525, -13524, -13523, -13522, -13521, -13520, -13519, 0, 0, -13518, + -13517, 0, 0, 0, 0, -13516, -13515, -13514, -13513, -13512, -13511, -13510, + -13509, -13508, -13507, -13506, -13505, -13504, -13503, -13502, -13501, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -13500, -13499, -13498, + -13497, -13496, -13495, -13494, -13493, -13492, -13491, -13490, -13489, -13488, -13487, -13486, + -13485, -13484, -13483, -13482, -13481, -13480, -13479, -13478, -13477, -13476, -13475, -13474, + -13473, -13469, -13468, 5, 13, 1, 1, 4, 1, 1, 1, 1, + 4, 1, 1, 4, 16, 1, 1, 1, 4, 1, 1, 4, + 1, 1, 1, 1, 38, 1, 1, 4, 1, 1, 1, 1, + 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 60, 76, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 42, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, + 1, 8, 8, 1, 1, 1, 1, 1, 1, 55, 95, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 42, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, + 48, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 16, 1, 3, 16, 30, 1, 1, 2, 6, + 1, 1, 2, 14, 1, 1, 2, 6, 46, 3, 438, 658, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 1, 1, 8, 8, 1, + 1, 1, 1, 1, 1, 32, 48, 96, 96, 10, 16, 22, + 96, 96, 96, 96, 101, 96, 96, 97, 112, 96, 96, 96, + 96, 100, 100, 96, 96, 104, 104, 96, 96, 96, 96, 96, + 552, 124, 124, 68, 557, 519, 520, 522, 525, 557, 558, 556, + 577, 600, 768, 768, 768, 768, 768, 768, 768, 769, 772, 768, + 768, 768, 776, 768, 768, 768, 768, 768, 768, 768, 789, 768, + 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, + 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, + 768, 768, 768, 768, 768, 768, 768, 768, 768, -13467, -13464, -13463, + -13462, -13461, -13460, -13459, -13458, -13457, -13456, -13455, -13454, -13453, -13450, -13448, + -13447, -13446, -13444, -13443, -13442, -13441, -13440, -13439, -13438, -13437, -13436, -13435, + -13434, -13433, -13430, -13429, -13428, -13427, -13422, -13420, -13419, -13418, -13416, -13415, + -13413, -13412, -13411, -13409, -13407, -13402, -13400, -13396, -13394, -13392, -13391, -13390, + -13389, -13388, -13387, -13386, -13385, -13384, -13383, -13382, -13381, -13380, -13379, -13378, + -13377, -13367, -13364, -13363, -13361, -13356, -13355, -13354, -13352, -13349, -13347, -13344, + -13343, -13342, -13341, -13340, -13339, -13338, -13337, -13336, -13335, -13334, -13333, -13332, + -13331, -13330, -13329, -13328, 92, 94, 283, 289, 933, 935, 939, 941, + 947, 952, 952, 952, 952, 1051, 1017, 952, -13327, -13326, -13325, -13324, + -13323, -13322, -13321, -13320, -13319, -13318, -13317, -13316, -13315, -13314, -13313, -12052, + 1012, 1016, 1015, 915, 918, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 514, 1, 1, 1, + 1, 515, 517, 514, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 1, 16, -12051, -12050, -12049, -12048, + 1, 1, 1, 1, 24, 1, 1, 1, 1, 1, 15, 35, + 57, 3, 4, 2, -12047, -12046, -12045, -12044, -12043, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12042, -12041, -12040, -12039, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12038, -12037, -12036, -12035, -12034, -12033, -12032, -12031, -12030, -12029, -12028, + -12027, -12026, -12025, -12024, -12023, -12022, -12021, -12020, -12019, -12018, -12017, -12016, + -12015, -12014, -12013, -12012, -12011, -12010, -12009, -12008, -12007, -12006, -12005, -12004, + -12003, -12002, -12001, -12000, -11999, -11998, -11997, -11996, -11995, -11994, -11993, -11992, + -11991, -11990, -11989, -11988, -11987, -11986, -11985, -11984, -11983, -11982, -11981, -11980, + -11979, -11978, -11977, -11976, -11975, -11974, -11973, -11972, -11971, -11970, -11969, -11968, + -11967, -11966, -11965, -11964, -11963, -11962, -11961, -11960, -11959, -11958, -11957, -11956, + -11955, -11954, -11953, -11952, -11951, -11950, -11949, -11948, -11947, -11946, -11945, -11944, + -11943, -11942, -11941, -11940, -11939, -11938, -11937, -11936, -11935, -11934, -11933, -11932, + -11931, -11930, -11929, -11928, -11927, -11926, -11925, -11924, -11923, -11922, -11921, -11920, + -11919, -11918, -11917, -11916, -11915, -11914, -11913, -11912, -11911, -11910, -11909, -11908, + -11907, -11906, -11905, -11904, -11903, -11902, -11901, -11900, -11899, -11898, -11897, -11896, + -11895, -11894, -11893, -11892, -11891, -11890, -11889, -11888, -11887, -11886, -11885, -11884, + -11883, -11882, -11881, -11880, -11879, -11878, -11877, -11876, -11875, -11874, -11873, -11872, + -11871, -11870, -11869, -11868, -11867, -11866, -11865, -11864, -11863, -11862, -11861, -11860, + -11859, -11858, -11857, -11856, -11855, -11854, -11853, -11852, -11851, -11850, -11849, -11848, + -11847, -11846, -11845, -11844, -11843, -11842, -11841, -11840, -11839, -11838, -11837, -11836, + -11835, -11834, -11833, -11832, -11831, -11830, -11829, -11828, -11827, -11826, -11825, -11824, + -11823, -11822, -11821, -11820, -11819, -11818, -11817, -11816, -11815, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -11814, -11813, -11812, -11811, -11810, -11809, -11808, -11807, -11806, -11805, -11804, + -11803, 0, -11802, -11801, -11800, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11799, + -11798, -11797, -11796, -11795, -11794, -11793, -11792, -11791, -11790, -11789, -11788, 0, + 0, -11787, -11786, -11785, -11784, -11783, -11782, -11781, -11780, -11779, -11778, -11777, + -11776, -11775, -11774, -11773, -11772, -11771, -11770, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -11769, -11768, -11767, + -11766, -11765, -11764, -11763, -11762, -11761, -11760, -11759, -11758, -11757, -11756, -11755, + -11754, -11753, -11752, -11751, -11750, -11749, -11748, -11747, -11746, -11745, -11744, -11743, + -11741, -11740, -11739, -11738, -11737, -11736, -11735, -11734, -11733, -11732, -11731, -11730, + -11729, -11727, -11719, -11712, -11711, -11710, -11709, -11708, -11707, -11706, -11705, -11704, + -11703, -11702, -11701, -11700, -11699, -11698, -11697, -11696, -11695, -11694, -11693, -11692, + -11691, -11690, -11689, -11688, -11687, -11686, -11685, -11684, -11683, -11682, -11681, -11680, + -11679, -11678, -11677, -11676, -11675, -11674, -11673, -11672, -11671, -11670, -11669, -11668, + -11667, -11666, -11665, -11664, -11663, -11662, -11661, -11660, -11659, -11658, -11657, -11656, + -11655, -11654, -11653, -11652, -11651, -11650, -11649, -11648, -11647, -11646, -11645, -11644, + -11643, -11642, -11641, -11640, -11639, -11638, -11637, -11636, -11635, -11634, -11633, -11632, + -11631, -11630, -11629, -11628, -11627, -11626, -11625, -11624, -11623, -11622, -11621, -11620, + -11619, -11618, -11617, -11616, -11615, -11613, -11612, -11611, -11610, -11609, -11608, -11607, + -11606, -11605, -11604, -11603, -11602, -11601, -11584, -11583, -11582, -11581, -11579, -11578, + -11574, -11568, -11567, -11566, -11565, -11564, -11563, -11562, -11561, -11560, -11559, -11558, + -11557, -11556, -11555, -11554, -11553, -11552, -11551, -11550, -11549, -11546, -11542, -11536, + -11535, -11533, -11532, -11531, -11530, -11529, -11528, -11527, -11526, -11525, -11524, -11523, + -11522, -11521, -11520, -11519, -11518, -11517, -11516, -11515, -11514, -11513, -11512, -11511, + -11510, -11509, -11508, -11507, -11506, -11505, -11504, -11503, -11502, -11501, -11500, -11499, + -11498, -11497, -11496, -11495, -11494, -11493, -11492, -11491, -11490, -11489, -11488, -11487, + -11486, -11485, -11484, -11483, -11482, -11481, -11480, -11479, -11478, -11477, -11476, -11475, + -11474, -11473, -11472, -11471, -11470, -11469, -11468, -11467, -11466, -11465, -11464, -11463, + -11462, -11461, -11460, -11459, -11458, -11457, -11456, -11455, -11454, -11453, -11452, -11451, + -11450, -11449, -11448, -11447, -11446, -11444, -11443, -11442, -11441, -11440, -11439, -11438, + -11437, -11436, -11435, -11434, -11433, -11432, -11431, -11430, -11429, -11428, -11427, -11426, + -11425, -11408, -11407, -11406, -11405, -11403, -11402, -11398, -11392, -11391, -11390, -11389, + -11388, -11387, -11386, -11385, -11384, -11383, -11382, -11381, -11380, -11379, -11378, -11377, + -11376, -11375, -11374, -11373, -11372, -11371, -11370, -11369, -11368, -11367, -11366, -11365, + -11364, -11363, -11362, -11361, -11360, -11359, -11358, -11357, -11356, -11355, -11354, -11353, + -11352, -11351, -11350, -11349, -11348, -11347, -11346, -11345, -11344, -11343, -11342, -11341, + -11340, -11339, -11338, -11337, -11336, -11335, -11334, -11333, -11332, -11331, -11330, -11329, + -11328, -11327, -11326, -11325, -11324, -11323, -11322, -11321, -11320, -11319, -11318, -11317, + -11316, -11315, -11314, -11313, -11312, -11311, -11310, -11309, -11308, -11307, -11306, -11305, + -11304, -11303, -11302, -11301, -11300, -11299, -11298, -11297, -11296, -11295, -11294, -11293, + -11292, -11291, -11290, -11279, -11278, -11277, -11276, -11275, -11274, -11273, -11272, -11271, + -11270, -11269, -11268, -11267, -11266, -11265, -11264, -11263, -11262, -11261, -11260, -11258, + -11250, -11247, -11239, -11231, -11230, -11229, -11228, -11227, -11226, -11225, -11224, -11223, + -11222, -11221, -11220, -11219, -11217, -11216, -11215, -11214, -11213, -11212, -11211, -11210, + -11209, -11208, -11207, -11206, -11205, -11204, -11203, -11202, -11201, -11200, -11199, -11198, + -11197, -11196, -11195, -11194, -11193, -11192, -11191, -11190, -11189, -11188, -11187, -11186, + -11185, -11184, -11183, -11182, -11181, -11180, -11179, -11178, -11167, -11166, -11165, -11164, + -11163, -11162, -11161, -11160, -11159, -11158, -11156, -11155, -11154, -11153, -11152, -11151, + -11150, -11149, -11148, -11147, -11146, -11145, -11144, -11143, -11142, -11141, -11140, -11139, + -11138, -11137, -11136, -11122, -11103, -11102, -11101, -11100, -11099, -11098, -11097, -11096, + -11095, -11094, -11093, -11092, -11091, -11089, -11088, -11087, -11086, -11085, -11084, -11083, + -11082, -11081, -11080, -11079, -11078, -11077, -11076, -11075, -11074, -11073, -11072, -11071, + -11070, -11069, -11068, -11067, -11066, -11065, -11064, -11063, -11062, -11061, -11060, -11059, + -11058, -11057, -11056, -11055, -11054, -11053, -11052, -11051, -11050, -11049, -11048, -11047, + -11046, -11045, -11044, -11043, -11042, -11041, -11040, -11039, -11038, -11037, -11036, -11035, + -11034, -11033, -11032, -11031, -11030, -11029, -11028, -11027, -11026, -11025, -11024, -11023, + -11022, -11021, -11020, -11019, -11018, -11017, -11016, -11015, -11014, -11013, -11012, -11011, + -11010, -11009, -11008, -11007, -11006, -11005, -11004, -11003, -11002, -11001, -11000, -10999, + -10998, -10997, -10996, -10995, -10994, -10993, -10992, -10987, -10986, -10983, -10982, -10981, + -10980, -10979, -10978, -10977, -10976, -10964, -10959, -10958, -10957, -10956, -10955, -10954, + -10953, -10952, -10951, -10950, -10949, -10948, -10947, -10946, -10945, -10944, -10943, -10942, + -10941, -10940, -10939, -10938, -10937, -10936, -10935, -10934, -10933, -10932, -10931, -10930, + -10929, -10928, -10927, -10926, -10925, -10924, -10923, -10922, -10921, -10920, -10919, -10918, + -10917, -10916, -10915, -10914, -10913, -10912, -10911, -10910, -10909, -10908, -10907, -10906, + -10905, -10904, -10903, -10902, -10901, -10900, -10899, -10898, -10897, -10896, -10895, -10894, + -10893, -10892, -10891, -10890, -10889, -10888, -10887, -10886, -10885, -10884, -10883, -10882, + -10881, -10880, -10879, -10878, -10877, -10876, -10875, -10874, -10873, -10872, -10871, -10870, + -10869, -10868, -10867, -10866, -10865, -10864, -10863, -10862, -10861, -10860, -10859, -10858, + -10857, -10856, -10855, -10854, -10853, -10852, -10851, -10850, -10849, -10848, -10847, -10846, + -10845, -10844, -10843, -10842, -10841, -10840, -10839, -10838, -10837, -10836, -10835, -10834, + -10833, -10832, -10831, -10830, -10829, -10828, -10827, -10826, -10825, -10824, -10823, -10822, + -10821, -10820, -10819, -10818, -10817, -10816, -10811, -10807, -10806, -10805, -10804, -10803, + -10802, -10801, -10800, -10799, -10798, -10797, -10796, -10795, -10794, -10790, -10788, -10783, + -10782, -10781, -10780, -10779, -10778, -10777, -10776, -10771, -10770, -10769, -10703, -10702, + -10701, -10700, -10699, -10698, -10695, -10694, -10693, -10692, -10689, -10688, -10683, -10682, + -10681, -10680, -10679, -10678, -10677, -10676, -10675, -10674, -10673, -10672, -10671, -10670, + -10669, -10668, -10667, -10666, -10665, -10664, -10663, -10662, -10661, -10660, -10659, -10658, + -10657, -10656, -10655, -10654, -10653, -10652, -10651, -10650, -10649, -10648, -10647, -10646, + -10645, -10644, -10643, -10642, -10641, -10640, -10639, -10638, -10637, -10636, -10635, -10634, + -10633, -10632, -10631, -10630, -10629, -10628, -10627, -10626, -10625, -10624, -10623, -10622, + -10621, -10620, -10619, -10618, -10617, -10616, -10615, -10614, -10613, -10612, -10611, -10610, + -10609, -10608, -10607, -10606, -10605, -10604, -10601, -10600, -10591, -10590, -10589, -10588, + -10587, -10586, -10585, -10584, -10583, -10581, -10580, -10579, -10578, -10577, -10576, -10575, + -10574, -10573, -10572, -10571, -10570, -10553, -10552, -10550, -10549, -10547, -10545, -10544, + -10543, -10542, -10539, -10538, -10537, -10536, -10535, -10534, -10533, -10532, -10531, -10530, + -10529, -10528, -10527, -10526, -10525, -10524, -10523, -10522, -10518, -10489, -10488, -10487, + -10486, -10485, -10484, -10483, -10482, -10479, -10478, -10477, -10476, -10475, -10474, -10471, + -10470, -10469, -10468, -10465, -10464, -10463, -10462, -10459, -10458, -10457, -10456, -10455, + -10454, -10453, -10452, -10451, -10450, -10449, -10448, -10447, -10446, -10445, -10444, -10443, + -10442, -10441, -10440, -10439, -10438, -10437, -10436, -10435, -10434, -10433, -10432, -10431, + -10430, -10429, -10428, -10427, -10426, -10425, -10424, -10423, -10422, -10421, -10420, -10419, + -10418, -10417, -10416, -10415, -10414, -10413, -10412, -10411, -10410, -10409, -10408, -10407, + -10406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -10405, -10404, -10403, -10402, -10401, -10400, -10399, -10398, -10397, -10396, -10395, + -10394, -10393, -10392, -10391, -10390, -10389, -10388, -10387, -10386, -10385, -10384, -10383, + -10382, -10381, -10380, -10379, -10378, -10377, -10376, -10375, -10374, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -10373, -10372, -10371, -10370, -10369, -10368, -10367, -10366, -10365, -10364, -10363, + -10362, 0, -10361, -10360, -10359, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -10358, -10357, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10356, + -10355, -10354, -10353, -10352, -10351, -10350, -10349, -10348, -10347, -10346, -10345, -10344, + -10343, -10342, -10341, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -10340, -10339, -10338, -10337, -10336, + -10335, -10334, -10333, -10332, -10331, -10330, -10329, -10328, -10327, -10326, -10325, -10324, + -10323, -10322, -10321, -10320, -10319, -10317, -10316, -10315, -10314, -10313, -10312, -10311, + -10310, -10309, -10308, -10307, -10306, -10305, -10304, -10303, -10302, -10301, -10300, -10299, + -10298, -10297, -10296, -10295, -10294, -10293, -10292, -10291, -10290, -10289, -10288, -10287, + -10286, -10285, -10284, -10283, -10282, -10281, -10280, -10279, -10278, -10277, -10276, -10275, + -10274, -10273, -10272, -10271, -10270, -10269, -10268, -10267, -10266, -10265, -10264, -10263, + -10262, -10261, -10260, -10259, -10258, -10257, -10256, -10255, -10254, -10253, -10252, -10251, + -10250, -10249, -10248, -10247, -10246, -10245, -10244, -10243, -10242, -10241, -10240, -10239, + -10238, -10237, -10236, -10235, -10234, -10233, -10232, -10231, -10230, -10229, -10228, -10227, + -10226, -10225, -10224, -10223, -10222, -10221, -10220, -10219, -10218, -10217, -10216, -10215, + -10214, -10213, -10212, -10211, -10210, -10209, -10208, -10207, -10206, 0, -10205, -10204, + -10203, -10202, -10201, -10200, -10199, 0, -10198, -10197, -10195, -10194, -10193, -10192, + 0, -10191, -10190, 0, -10189, -10188, -10187, -10186, -10185, -10184, 0, -10183, + -10182, -10181, -10180, -10179, -10178, -10177, -10176, -10175, 0, -10174, -10173, 0, + -10171, -10170, -10169, -10168, -10167, -10165, -10164, -10162, -10161, -10160, -10159, -10158, + -10157, -10156, -10155, -10154, -10153, -10152, -10151, -10150, -10149, 0, -10148, -10147, + -10146, -10145, -10144, -10143, -10142, -10141, -10140, -10139, -10138, -10137, -10136, -10135, + -10134, -10133, -10130, 0, -10126, 0, -10102, -10101, -10100, 0, 0, -10099, + -10098, -10097, -10096, -10095, -10094, -10093, -10092, -10091, -10090, -10089, -10088, -10087, + -10086, -10085, -10084, -10083, -10082, -10081, -10080, -10079, -10078, -10077, -10076, -10075, + -10074, -10073, -10072, -10071, -10070, -10069, -10068, -10067, -10066, -10065, -10064, -10063, + -10062, -10061, -10060, -10059, -10058, -10057, -10056, -10055, -10054, -10053, -10052, -10051, + -10050, 0, -10049, -10048, -10047, -10046, -10045, -10044, -10043, -10042, -10041, -10040, + -10039, -10038, -10037, -10036, -10035, -10034, -10033, -10032, -10031, -10030, -10029, -10028, + -10027, -10026, -10025, -10024, 0, -10023, -10022, -10021, -10020, -10019, 0, 0, + -10018, 0, 0, 0, -10017, -10016, 0, -10015, -10014, -10013, 0, -10012, + -10011, 0, -10010, -10009, -10008, -10007, -10006, -10005, -10004, -10003, -10002, -10001, + -10000, -9999, -9998, -9997, -9996, -9995, -9994, -9993, -9992, -9991, -9990, -9989, + -9988, -9987, 0, -9986, -9985, -9984, -9983, -9982, -9981, -9980, -9979, -9978, + -9977, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, -9976, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, -9975, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, -9974, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -9973, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, -9972, -9971, 1, 1, -9969, -9968, -9967, -9966, -9965, -9964, -9963, + -9962, -9961, -9960, -9959, -9958, -9957, -9956, -9955, -9954, -9953, -9952, -9939, + -9938, -9937, -9936, -9935, -9934, -9933, -9932, -9931, -9930, -9929, -9928, -9927, + -9925, 73, 96, -9922, -9921, 0, -9920, 96, -9919, -9918, 96, 96, + -9917, -9916, 96, 96, 96, -9915, -9914, -9913, -9912, -9911, -9910, -9909, + -9908, -9907, 96, -9906, -9905, -9904, -9890, -9887, -9886, 64, 66, 64, + 66, 0, 65, 65, 73, 64, 69, 65, 80, 80, 80, 68, + 70, 68, 70, 72, 76, 76, 140, 64, 162, 192, 192, 192, + 192, 192, 192, 37, 144, 156, 156, 160, 160, -9885, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 178, 160, 160, 160, + 160, 160, 160, 160, 160, 184, 189, -9884, 512, 512, 512, 145, + 512, -9883, -9882, -9881, -9880, -9879, -9878, -9877, -9876, -9875, -9874, -9873, + -9872, -9861, -9860, -9859, -9858, -9857, -9856, -9855, -9854, -9853, -9852, -9851, + -9850, -9849, -9848, 0, -9847, -9846, -9845, -9844, -9839, 29, 64, 70, + 72, 128, 128, 55, 128, -9838, -9837, 128, 137, -9836, -9835, -9834, + -9833, -9832, -9831, -9830, -9829, -9828, -9827, -9826, -9825, -9824, -9811, -9810, + -9809, -9808, -9807, -9806, -9805, 128, 137, 129, 134, 144, 144, 144, + 144, -9804, 164, 161, 163, -9803, -9802, -9801, -9800, 161, 162, -9799, + 0, 160, 160, 132, 132, 160, 160, 160, 164, 160, 160, 134, + 148, 133, 145, 128, 128, 244, 244, -9798, 149, -9797, 652, 128, + 135, -9796, -9795, -9794, -9793, -9792, 770, 192, -9791, 768, 768, 768, + 768, 768, 772, 252, 768, 768, 771, 784, 784, 175, 183, 229, + 230, 228, 250, -9790, 829, 785, 830, 896, 896, 896, 896, 906, + 906, -9789, -9788, -9787, -9786, -9785, 901, -9784, -9783, -9782, 928, 904, + 904, 930, 933, -9781, 769, 805, 814, 896, 896, 896, 896, 906, + 912, 901, 924, 896, 896, 920, 941, 936, 936, 942, -9780, 896, + 946, 939, 984, 901, 977, 980, 1024, 985, 1024, 1024, 1024, 998, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, -9779, 900, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, -9778, -9777, -9776, -9775, -9774, -9773, -9772, + -9771, -9770, -9769, -9768, -9767, -9766, -9765, -9764, -9763, -9762, -9761, -9760, + -9759, -9758, -9757, -9756, -9755, -9754, -9753, -9752, -9751, -9750, -9749, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -9748, -9747, -9746, -9745, -9744, -9743, 0, + 0, -9742, 0, 0, 0, -9741, 0, -9740, -9739, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -9738, -9737, -9736, -9735, -9734, -9733, -9732, -9731, -9730, -9729, -9728, + -9727, -9726, -9725, -9724, -9723, -9722, -9721, -9720, -9719, -9718, -9717, -9716, + -9715, -9714, -9713, -9712, -9711, -9710, -9709, -9708, -9707, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -9706, -9705, -9704, -9703, -9702, -9701, -9700, -9699, -9698, -9697, -9696, + -9695, -9694, -9693, -9692, -9691, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -9690, -9689, -9688, + -9687, -9686, -9685, -9684, -9683, -9682, -9681, 134, 134, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 197, 224, 224, 212, + 212, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 256, 256, 128, 128, 128, 128, 128, + 128, 128, 257, 128, 128, 128, 128, 256, 256, 256, 256, 264, + 268, 256, 256, 256, 273, 270, 276, 286, 286, 257, 288, 288, + 288, 292, 296, 288, 288, -9680, -9679, -9678, -9677, -9676, -9675, -9674, + -9673, -9672, -9671, -9670, -9669, -9668, -9667, -9666, -9665, 2, 2, 2, + 2, 2, 2, 2, 2, -9664, -9663, -9662, -9661, -9660, -9659, -9658, + -9657, -9656, -9655, -9654, -9653, -9652, -9651, -9650, -9649, -9648, -9647, -9646, + -9645, -9644, -9643, -9642, -9641, -9640, -9639, -9638, -9637, -9636, -9635, -9634, + -9633, -9632, -9631, -9630, -9629, -9628, -9627, -9626, -9625, 34, 34, 40, + 40, 40, 40, 48, 48, 60, 60, 27, 48, 48, 48, 49, + 60, -9624, -9623, -9622, -9621, -9620, -9619, -9618, -9617, -9616, -9615, -9614, + -9613, -9612, -9611, -9610, -9609, -9608, 32, 32, 35, -9607, -9606, -9605, + -9604, -9603, -9601, -9600, -9599, -9598, -9597, -9596, -9595, 16, 24, 19, + 20, 106, 106, 16, 19, -9594, 130, 128, 132, -9593, -9592, -9591, + -9590, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1, + 1, 1, 1, 1, 1, 8, 8, 14, 14, 16, 16, 16, + 16, 6, 6, 26, 26, 30, 30, 32, 32, 1, 1, 1, + -9589, 2, 8, 2, 2, 10, 14, 1, 1, 4, 1, 1, + 1, 1, 4, 1, 1, 4, 1, 1, 1, 1, 4, 1, + 1, 4, 1, 72, 72, 1, 4, 1, 1, -9588, 1, 1, + 1, -9587, -9586, -9585, -9584, -9583, -9582, -9581, -9580, 1, 1, 1, + 1, 1, 1, 1, 1, 16, 1, 7, 16, 16, 16, 16, + 16, 9, 14, 34, 1, 45, 47, 57, 130, 51, 53, 25, + 26, 20, 29, 128, 128, 89, 128, 6, -9579, 1, 27, 44, + 127, 128, 128, 128, 133, 140, 143, 150, 160, 131, 145, 148, + 148, 154, 161, 167, 204, 194, 234, 512, 512, 480, 516, 512, + 512, 0, -9578, 460, 512, -9577, -9576, -9575, -9574, 512, 512, -9573, + -9572, 512, 512, 520, 520, 512, 512, 528, 530, 457, 529, 528, + 528, 536, 545, 512, 512, 512, 512, 512, 512, 520, 520, 513, + 526, 528, 528, 522, 528, 514, 514, 516, 516, 538, 598, 523, + 593, 512, 512, 443, 512, 514, 519, 524, 524, 524, 524, 514, + 514, 514, 514, 514, 514, 552, 552, 533, 544, 544, 544, 544, + 544, 550, 640, 512, 514, 512, 517, 513, 514, 520, 520, 512, + 512, 624, 640, 512, 640, 640, 640, 640, 640, 648, 652, 648, + 656, 640, 640, 645, 653, 674, 677, 673, 680, 645, 665, 672, + 680, 646, 673, 684, 689, 127, 644, 723, 724, 648, 679, 722, + 722, 683, 729, 27, 896, 896, 896, 896, 896, 896, 896, 896, + 900, 896, 896, 896, 909, 896, 896, 897, 901, 896, 896, 909, + 929, 896, 896, 896, 900, 896, 896, 896, 909, 896, 896, 897, + 900, 896, 896, 896, 908, 896, 896, 896, 900, 896, 896, 896, + 909, 896, 988, 905, 1097, 1086, 1112, 1792, 1792, 960, 960, 960, + 960, 960, 960, 961, 975, 961, 1121, 1792, 1792, 1792, 1792, 1792, + 1792, 1792, 1792, 1792, 1792, 1792, 1808, 1792, 1792, 1808, 1808, 1819, + 1823, 1856, 1856, 1856, 1856, 902, 999, 1112, 1824, 1826, 1829, 1825, + 1856, 1834, 1856, 1856, 1856, 1856, 1856, 1856, 1865, 1856, 1856, 1856, + 1856, 1856, 1856, 1857, 1874, 1856, 1856, 1856, 1856, 1856, 1856, 1892, + 1892, 10, 129, 129, 133, 27, 128, 130, 138, 129, 133, 128, + 128, 139, 143, 148, 148, 130, 130, 130, 130, 130, 137, 129, + 130, 128, 160, 164, 164, 129, 161, 176, 176, -9571, -9570, 182, + -9569, -9568, -9562, -9558, -9557, -9555, -9554, -9553, -9552, -9551, -9550, -9549, + -9548, 141, 152, 148, 148, -9547, -9545, 202, 202, -9544, -9543, -9542, + -9541, -9540, -9539, -9538, -9537, 136, 140, 130, 148, 152, 156, 144, + 389, 152, 384, 128, 128, 136, 136, 136, 136, 136, 142, 140, + 170, 137, 171, 174, 176, 404, 448, 152, 164, 157, 449, 448, + 448, -9536, -9535, -9534, -9533, -9532, -9531, -9530, -9529, -9528, -9527, -9526, + -9525, -9524, -9523, -9522, -9521, 449, 453, 144, 430, 144, 144, 460, + 460, -9520, 472, 452, 452, -9519, -9518, -9517, -9516, 492, 492, -9515, + 497, 507, 510, 502, 509, 487, 504, 325, 404, 64, 1030, 400, + 1025, -9514, -9512, -9511, -9510, -9509, -9508, -9507, -9506, -9505, -9504, -9503, + -9502, -9501, -9500, -9499, -9498, -9497, -9496, -9495, -9494, -9493, -9492, -9491, + -9490, -9489, -9488, -9487, -9486, -9485, -9484, -9483, -9482, 445, 1045, 1040, + 1042, 432, 1046, 1046, 1056, 1056, 1056, 1042, 1064, 1064, 1080, 1084, + 1084, 414, 1095, 1, 1090, 407, 1089, 1089, 1096, 1088, 1088, 1098, + 1152, 1152, 1152, 1152, 1152, -9481, -9480, -9479, -9478, -9477, -9476, -9475, + -9474, -9473, -9470, -9460, -9459, 1152, 1152, 1153, -9457, 1136, 1136, 1136, + 1141, 1129, 1136, 1168, 1168, 1153, 1158, 1177, 1185, 1188, 1188, 1194, + 1197, 1152, 1152, 1144, 1151, 1152, 1152, 1156, 1160, 1154, 1154, 1222, + 1222, 1188, 1188, 1237, 1241, 1296, 1298, 1301, 1304, 1296, 1311, 1315, + 1316, 1309, 1311, 189, 1305, 128, 135, 1311, 1323, 153, 177, 171, + 1322, 1324, 1344, 1360, 1360, 188, 2051, 1338, 1338, 2071, 2096, 2105, + 2168, 2057, 2172, 164, 2176, 2176, 2176, 2189, 2190, 2176, 2198, 2180, + 2186, 2188, 2208, 2208, 2208, 2177, 2186, 2178, 2233, 2240, 2242, 2244, + 2248, 2254, 2260, 2240, 2248, 2224, 2246, 2261, 2282, 2287, 2295, 2306, + 2306, -9456, -9455, 2304, -9453, -9452, -9451, -9450, -9449, -9448, -9447, -9446, + -9445, 2192, 2197, 2187, 2190, 2187, 2217, 2192, 2229, 2321, 2325, 2304, + 2304, 2192, 2237, 2317, 2336, 2309, 2351, 2356, 2359, 2368, 2368, 2368, + 2372, 2368, 2368, 2368, 2368, 2368, -9444, -9443, 2368, -9442, -9441, -9440, + -9439, -9438, -9437, -9436, -9435, -9434, -9433, -9432, -9431, 2368, 2370, -9430, + -9429, -9428, -9427, -9426, -9425, -9424, -9423, -9422, -9421, -9420, -9419, -9418, + -9417, -9416, -9415, -9414, -9413, -9412, -9411, -9410, -9409, -9408, -9407, -9406, + -9405, -9404, -9403, -9402, -9401, -9400, -9399, -9398, -9397, 36, 42, 63, + 138, 140, 162, 160, 245, 2066, 2124, 2135, 2144, 2176, 2182, 2184, + 2186, 938, 2176, 2176, 2176, 2176, 2176, 2177, 2187, 2190, 2202, 2176, + 2178, 2188, 2209, 2179, 2203, -9396, -9395, -9394, -9393, -9392, -9391, -9390, + -9389, -9388, -9387, -9386, -9385, -9384, -9383, -9382, -9381, 2180, 2186, 2183, + -9380, 2246, 2252, 2254, 2257, -9379, 2179, 2259, 2260, -9378, -9377, -9376, + -9375, 2242, 2275, 2282, -9374, 2304, 2306, 2282, 2309, 2277, 2279, 2304, + 2304, 2304, 2308, 2317, 2319, 2304, 2306, 2304, 2309, 2313, 2333, 2312, + 2336, -9373, -9372, 2307, 2308, 2304, 2336, -9371, -9370, 4, -9369, -9368, + 4, 1, 8, 8, 8, 1, 1, 1, 1, 22, 1, 21, + 23, -9367, -9366, -9365, 1, 1, 1, 1, -9364, 8, 8, 9, + 13, 35, -9363, -9362, 40, -9361, 8, -9360, 2, 4, 1, -9359, + -9358, -9357, -9356, 1, 1, -9355, -9354, 2, -9353, 2, 2, 4, + 22, 25, 27, 30, 64, 68, 72, -9352, 28, 73, 77, 80, + 80, -9351, -9350, -9349, -9348, -9347, -9346, -9345, -9342, -9332, -9331, -9329, + -9320, 6, -9317, 5, 9, -9316, -9315, -9313, -9312, -9311, -9310, -9309, + -9308, -9307, -9306, -9305, -9304, -9303, 2, -9302, -9301, -9300, -9299, 10, + 10, 15, 33, 36, 49, -9298, -9297, 42, 42, -9296, -9295, -9294, + 49, -9293, -9292, 32, 32, 36, 36, -9291, -9290, 35, 44, 45, + 47, 136, 138, 132, 132, 1, 1, 1, 4, 6, 8, 3, + 8, 12, 15, -9289, -9288, -9287, -9286, -9285, -9284, 0, 0, 0, + 0, -9283, -9282, -9281, -9280, -9279, -9278, 6, 6, 8, 8, 16, + 19, 8, 11, 1, 1, 16, 16, -9277, -9276, 0, -9275, -9274, + -9273, 0, 0, -9272, 0, -9271, -9270, -9269, -9268, -9267, -9266, -9265, + -9264, -9263, -9262, -9261, -9260, -9259, -9258, -9257, -9256, 0, 0, 0, + -9255, 0, 0, 0, 0, -9254, -9253, 15, 16, 16, 16, 16, + 16, -9252, -9251, -9250, -9249, -9248, -9247, -9246, -9245, -9244, -9243, 0, + 0, 0, 0, 0, 0, -9242, -9241, 0, 0, -9240, -9239, -9238, + -9237, -9236, -9235, 2, 1, 1, 2, 2, 1, -9234, -9233, -9232, + -9231, -9230, -9229, 0, 0, -9228, -9227, 6, 6, 9, 12, 8, + 15, -9226, -9225, -9224, -9223, -9222, -9221, -9220, -9219, -9218, -9217, -9216, + -9215, -9214, -9213, -9212, -9211, -9210, -9209, -9208, -9207, -9206, -9205, -9204, + -9203, -9202, -9201, -9200, -9199, -9198, -9197, -9196, -9195, 124, 124, 116, + 116, 116, 116, -9194, 121, 156, 156, 69, 73, -9193, -9192, 152, + 152, 79, 130, 205, 244, 144, 204, 240, 385, 153, 193, 217, + 384, 385, 394, 388, 397, -9191, -9190, -9189, -9188, -9187, -9186, -9185, + -9184, -9183, -9182, -9181, -9180, -9179, -9178, -9177, -9176, -9175, -9174, -9173, + -9172, -9171, -9170, -9169, -9168, -9167, -9166, -9165, -9164, -9163, -9162, -9161, + -9160, -9159, -9158, -9157, -9156, -9155, -9154, -9153, -9152, -9151, -9150, -9149, + -9148, -9147, -9146, -9145, -9144, -9143, -9142, -9141, -9140, -9139, -9138, -9137, + -9136, -9135, -9134, -9133, -9132, -9131, -9130, -9129, -9128, 134, 156, 148, + 163, -9127, -9126, 171, 203, -9125, -9124, -9123, -9122, -9121, -9120, -9119, + -9118, 29, 30, 28, 79, 51, 75, 131, 135, 35, 130, 132, + 144, 149, 160, 157, 168, -9117, -9116, -9115, 0, 0, 0, -9114, + -9113, -9112, -9111, -9110, -9109, -9108, -9107, -9106, -9105, -9104, -9103, 0, + 0, 0, 0, 0, 0, 0, 0, -9102, -9101, -9100, -9099, -9098, + -9097, 102, 123, 132, 139, 131, 173, -9096, 146, -9095, -9094, 0, + -9093, 0, 0, 0, 0, -9092, -9091, -9090, -9089, -9088, -9086, -9085, + -9082, -9081, -9080, -9079, -9078, -9077, -9076, -9075, -9074, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9073, + 0, -9072, -9071, 129, 154, -9070, -9069, 152, 163, -9068, 149, -9067, + -9066, 0, 0, 0, 0, -9065, -9064, 0, -9063, 0, 0, -9062, + -9061, 0, -9060, -9059, 0, -9058, -9057, 0, -9056, -9055, 0, 0, + 0, -9054, -9053, -9052, 0, 0, -9051, -9050, -9049, -9048, -9047, 0, + 0, -9046, -9045, -9044, -9043, -9042, -9041, -9040, -9039, 0, 0, 4, + 1, -9038, -9037, -9036, -9035, 3, -9034, -9033, -9032, -9031, -9030, -9029, + 10, -9028, 2, 28, 36, -9027, -9026, -9025, -9024, -9023, -9022, -9021, + 16, -9020, -9019, -9018, -9017, -9016, -9015, -9014, -9013, -9012, -9011, -9010, + -9009, -9008, -9007, -9006, -9005, -9004, -9003, -9002, -9001, -9000, -8999, -8998, + -8997, -8996, -8995, -8994, -8993, -8992, 8, 10, 19, -8991, -8990, -8988, + -8987, -8986, -8985, -8984, -8983, -8982, 0, -8981, -8980, -8979, -8978, -8977, + -8976, 1, 3, -8975, -8974, 2, 8, 20, 33, 41, 45, 34, + 49, 3, -8973, -8972, 5, 1, 5, 14, 24, 1, 2, 17, + 18, 45, 46, 19, 66, -8971, -8970, -8969, -8968, 35, 37, -8967, + 0, -8966, -8965, 66, 66, 76, -8964, -8962, 67, 53, 61, -8961, + 61, 64, 64, 68, -8960, -8959, -8958, 64, 64, -8957, -8956, 70, + -8955, 3, 64, 9, 67, 66, 72, 72, 72, 121, 122, -8954, + 112, 75, 108, 124, 127, -8953, -8952, -8951, -8950, -8949, -8948, -8947, + -8945, -8944, -8943, -8942, -8941, 315, -8940, 385, 396, -8939, -8938, -8937, + -8936, -8935, -8934, -8933, -8932, -8931, -8930, -8929, -8928, -8927, -8926, -8925, + -8924, 391, 397, 1, -8923, 386, 396, 448, 452, -8922, -8921, 0, + 0, 0, 0, 0, 0, 0, 0, -8920, -8919, -8918, -8917, 0, + 0, -8916, -8915, 500, 511, 366, 432, 948, 971, 51, -8914, 51, + 108, 43, 401, 262, 267, 94, 305, 212, 249, 266, 289, 263, + 920, -8913, -8912, -8911, -8910, 1, 1, 1, 271, 1, 1, 1, + 1, 1, 268, 1, 1, 1, 1, 390, 1, 1, 1, 407, + -8909, -8908, -8907, 68, 4099, -8906, -8905, 4099, -8904, 300, 624, 4112, + 4119, 4128, 4128, 4128, 4132, 127, 278, 418, 1, 1, 1, 1, + 1, 357, 383, 2055, 1, 2056, 2056, -8903, -8902, -8901, -8900, 271, + 2049, 2051, 2053, 2048, 2056, 2051, 2057, 2048, 2068, 2049, 2056, 2062, + 2068, 2057, 2065, 2056, 2072, 417, 2054, 2080, 2080, 2074, 2084, 2066, + 2070, 2083, 2085, 2056, 2092, 2088, 2095, 4096, -8899, -8898, -8897, -8896, + -8895, -8894, -8893, 4098, 4104, 4113, 4115, -8892, -8891, 4113, 4114, 1, + 1, 1, 1, 1, 1, 1, 2053, 2063, 1, 1, 1, 4241, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 532, 1024, 529, + 532, 1, 1, 1, 409, 1157, 1, 4224, 4226, 4225, -8890, 1154, + 1156, 3, 4, 1152, 1, 1167, 1, 1, 1165, 1185, 1220, 4274, + 1, 1182, 1195, -8889, -8888, 4256, 4256, 4256, 4268, 4266, 4309, 4308, + 4312, 4372, 4375, 1162, 1, 1, 1, 1, 1, 1185, 1222, 1220, + 1226, 1236, 1256, 1701, 1707, 1, 1, 1, 1615, 1164, 1, 1612, + 1, 1792, 1792, -8887, -8886, 1808, 1810, -8885, -8884, -8883, -8882, -8881, + -8880, -8879, -8878, -8877, -8876, 4231, 4253, -8875, -8874, -8873, -8872, -8871, + 4234, -8870, -8869, 1793, 1794, 1792, 1798, 1792, 1794, 1800, 1803, 1792, + 1796, 1, 1, -8868, 1809, 1, 1, 1, 1, 1, 1, 1, + 4243, 1864, 1, 1, 1, 1797, 1, 1, 1, 1, 1, 1562, + 1879, 1, 1, 1, 1, 1881, 1884, 1874, 1888, 2, 10, 10, + 342, 5, 18, 8, 1, 11, 37, 20, 32, 17, 1688, 3, + 5, 16, 36, 53, 57, 48, 48, 2, 1, 1702, 1857, 1, + 1686, 5, 1, 15, 16, 2, 21, 1, 12, 4, 18, 8, + 64, 25, 64, 4178, 4208, 1687, 1688, -8866, -8865, -8864, -8863, -8862, + -8860, -8859, -8858, -8857, -8856, -8855, -8854, -8853, -8852, 4125, 4137, 4142, + 4224, -8851, 4114, 4112, 4224, -8850, -8849, 1928, 1978, 1758, 1853, -8848, + 1764, 1946, 3304, -8847, -8846, -8845, -8844, -8843, -8842, -8841, -8840, 1804, + 3253, 3257, 3269, 3268, 3283, 3288, 3293, 3248, 3298, 1, 1, -8838, + -8837, 1735, 1, 4, 1, 5, 1, 1, 14, 40, 40, 3293, + 16, 3, 1, 10, 32, 34, 36, 7, 1, 35, 38, 46, + 46, 1760, 3333, 4299, 4302, 1, 3, 14, 1569, 10, 38, 32, + 39, 4100, 4130, 3856, 41, 6, 13, 21, 38, 25, 68, 68, + 72, 3864, 65, 68, 80, 4166, 4166, 4098, -8836, 4104, 4112, 4113, + 4193, 4099, 4114, 4118, 4125, 4100, 4196, 64, 70, 9, 73, 72, + 72, 3889, 4184, 4179, 4181, 4176, 1, 4, 4, 13, 14, 3, + 5, 7, 1, 4, 15, 4142, 4482, -8835, -8834, 4132, 4228, -8833, + -8832, -8831, -8830, -8829, -8828, -8827, 4100, -8826, -8825, 4149, 4153, 4152, + 4156, 4149, 4167, 4171, 4227, 4161, 4251, 4241, 26, 4238, 4240, 27, + 34, 4486, 4550, 1, 4141, 4130, 4142, -8824, -8823, 32, 4137, 4142, + 4512, 4180, 4516, 4521, 4543, 4106, 4132, -8822, 4165, 4096, 4140, 4142, + 4164, 4111, 4155, 25, 70, 28, 39, 31, 65, 4536, 4687, 5081, + 84, 930, 938, 931, -8821, 931, 945, 944, -8820, 929, 961, -8819, + -8818, 901, 4107, -8817, 929, 1012, 1023, 4419, -8816, -8815, -8814, 1844, + 4101, -8813, -8812, -8811, 0, 4673, 4686, -8810, -8809, -8808, -8806, -8805, + -8804, -8803, -8802, 0, 4215, 4720, 4871, -8801, -8800, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -8799, -8798, -8797, 4873, -8796, + 922, 940, 926, 1007, 930, 1096, 1019, 1131, 1016, 1121, 1156, 1158, + 1122, 1120, 1154, 1162, 1152, 1154, 17, 17, 1157, 1153, 1156, 1164, + 1152, 1176, 1182, 1184, 1190, 946, 1193, -8795, -8794, -8793, -8792, 768, + 768, 768, 768, -8791, -8790, 768, 768, 1, 1, 8, 8, 12, + 8, 2, 2, 1152, 15, 52, 54, 34, 42, 25, 30, 1, + 13, 9, 31, 1, 31, 1169, 1176, 1174, 930, 46, 64, 64, + 1280, 64, 64, 78, 64, 80, 82, 1174, 88, 66, 66, 88, + 90, 178, 82, 90, 101, 1280, 1280, 220, 83, 1282, 1291, 230, + 1288, 70, 64, 114, 72, 244, 246, 239, 118, 201, 115, 1285, + 227, 332, 336, 338, 352, 1312, 1312, 1195, 1291, 1192, 1292, 1193, + 1316, 1328, 2, 24, 266, 1325, 1321, 1329, 1284, 1284, 1296, 1300, + 1300, 1306, 1314, 1322, 1332, 1334, 1332, 1316, 1360, 1344, 1369, 1371, + 1360, 1360, 1364, 1360, 1360, 1374, 1446, 1440, 1445, 307, 165, 31, + 392, 1364, 384, 392, 309, 1409, 1414, 898, 900, 386, 389, -8789, + -8788, 898, 898, 900, 392, 427, 429, 898, 898, -8787, -8786, -8785, + -8784, -8783, -8780, -8778, -8777, -8776, -8775, 1288, 1284, 1288, -8774, -8773, + 1298, 1370, 1378, -8772, -8771, -8770, -8769, -8768, -8767, 4114, 4119, 1, + 1, 1281, -8766, -8765, 2, 1394, 1384, 1394, 1393, 1399, -8764, -8763, + 1406, 1536, 1538, 1553, 1536, 1563, 1566, 1572, 1572, 1541, 1577, 1548, + 1571, 1580, 1584, 1576, 1568, 1575, 1667, 1313, 1667, 1569, 1672, -8762, + 1664, 1580, 1664, 1666, 1664, 1666, 1674, -8761, 1664, 1664, 1664, 1546, + 1553, 1559, 1563, 1576, -8760, -8759, -8758, 0, -8757, -8756, -8755, 0, + 0, 0, 0, -8754, -8753, -8752, -8751, -8750, -8749, -8748, -8747, -8746, + -8745, -8744, -8743, -8742, -8741, -8740, -8739, -8738, -8737, -8736, -8735, -8734, + -8733, -8732, -8731, -8730, -8729, -8728, -8727, -8726, -8725, -8724, -8723, -8722, + -8721, -8720, -8719, 0, 0, -8718, -8717, 0, 0, 0, 0, 0, + 0, 0, 0, -8716, -8715, -8714, -8712, -8711, -8710, -8708, -8707, -8706, + 4288, 4303, 4325, 4349, 5025, 4512, 4801, 4320, 4526, 4335, 5025, 4335, + 4998, 36, 36, 36, 45, 5024, 5052, 5294, 5296, 5301, 5303, -8705, + -8704, 4596, -8703, -8702, 4598, 57, 5092, 62, 62, 3, 4238, 5001, + 5012, 24, 24, 24, 129, 93, 128, 128, 139, 19, 144, 129, + 145, 192, 192, 153, 155, 145, 218, 4346, 5961, 5971, 5982, 6172, + 6204, 4103, 4997, 144, 5005, -8701, -8700, -8699, -8698, -8697, 5120, -8696, + -8695, -8694, 5120, -8693, -8692, 0, 0, 0, 0, -8691, -8690, -8689, + -8688, 0, -8687, -8686, 5514, 0, 0, 0, 0, -8685, -8684, -8683, + -8682, -8681, -8680, -8679, -8678, -8677, -8676, 5151, 5152, -8674, -8673, -8672, + 5157, -8671, -8670, 0, -8669, 4392, 4397, -8668, -8667, -8666, -8665, 4393, + -8664, 4410, 4582, 5199, 5228, -8663, 4555, 4544, -8662, 5377, -8661, -8660, + 5216, -8659, 5390, -8658, 5477, -8657, -8656, 5525, -8655, 5617, 5620, -8654, + 5627, -8653, -8652, -8651, -8650, -8648, -8647, 0, 0, 0, 0, -8645, + 0, -8644, -8642, -8641, 0, -8640, 0, -8639, 0, -8638, -8637, -8636, + -8635, 5666, 5668, 5670, -8634, 5713, 5714, -8633, -8632, -8631, 5712, -8630, + -8629, 0, 0, 5834, 5834, 5834, 5834, 5843, 24, 1, 3, 280, + 280, 1837, 1920, -8628, 294, -8627, -8626, -8625, 1921, 1923, 1921, 1928, + 1253, 1920, 1928, 1935, 1941, 1943, 1941, -8624, -8623, -8622, -8621, 1933, + 1921, 1928, -8619, -8618, -8617, -8616, 1938, -8615, -8614, 0, 0, -8613, + -8612, 0, 0, -8611, -8610, -8609, -8608, -8607, 1926, 2, 10, 4, + 27, 40, 59, 32, 93, 60, 60, 461, 402, 466, 480, 485, + 385, -8606, -8605, -8604, -8603, 402, 404, 416, 395, 440, 4480, 4417, + 4481, 4483, 4488, 4488, -8602, -8601, -8600, 0, -8599, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -8598, 4481, 4483, 4481, + 4487, 4481, 4488, 4481, 432, 4480, 4480, 4484, 4484, 4480, 4496, 4496, + 434, 424, 4418, 436, 4422, 4481, 4483, 4481, 4484, -8597, -8596, 4480, + 4484, -8595, -8594, -8593, -8591, -8590, -8588, -8587, 433, -8583, -8580, 444, + -8578, 0, 0, 0, -8577, 0, -8576, 0, -8575, -8573, -8572, -8571, + 0, -8570, -8569, -8568, 0, 0, 0, 0, 0, 0, 0, 0, + -8567, -8566, -8565, -8564, 0, -8563, -8562, -8561, -8559, -8558, -8557, -8556, + 0, -8555, 0, -8554, -8553, 26, 128, 130, 128, 128, 128, 136, + 133, 130, -8552, 129, 130, 144, 144, 152, 128, 130, 128, 133, + 128, 141, 161, 141, 169, 170, 180, 178, 167, 207, 212, 261, + 151, -8551, 180, 192, 129, 193, -8549, 198, 142, 194, 284, 384, + 384, 384, 384, 384, 254, 289, 384, 295, 232, 384, 384, 384, + 388, 384, 384, 384, 396, 386, 399, 408, 384, 393, 393, 416, + 237, 416, 416, 422, 416, 419, 419, 427, 438, 442, 434, 444, + 492, 389, 468, 1027, 267, 1352, 1035, 1520, 1074, 1529, 1062, 7698, + 472, 7699, 1387, 7707, 1046, 410, 508, 1048, 258, 1064, 1097, 1368, + 7680, 7686, 7680, 7690, 1083, 7693, 7682, 8224, 1111, 8253, 8359, 8364, + 1495, 8392, 8397, 8421, 8422, 8424, 8452, 8452, 8455, 8456, 8456, 8456, + 8460, 1076, 101, 1083, 1032, 1315, 298, 8579, 315, 8577, 8586, 8594, + 8594, 8602, 8602, 8624, 1080, 1080, 1078, 8608, 1775, 8608, 8608, 8617, + -8546, -8540, 8608, 8646, -8539, -8537, -8536, -8535, 1066, 8599, 8640, 8640, + 118, 8644, 8650, 8654, 8662, 8664, 8672, 8664, 8672, 8672, 8672, 8672, + -8530, -8528, -8527, -8526, -8523, -8522, -8521, -8518, -8517, -8516, -8515, -8514, + -8513, -8510, -8508, -8507, -8505, -8496, -8495, -8493, -8492, -8491, -8490, -8489, + -8488, -8487, -8486, -8485, -8484, -8483, -8482, -8481, 8576, 8592, 8576, 8592, + 8592, 8592, 8592, 8592, 8598, 8592, 8704, 8592, 8709, 8712, 8712, 8712, + 8706, 8704, 8722, 8704, 8777, 8721, 8776, 8776, 8768, 8771, 8785, 8787, + 8784, 8786, 8793, 8798, 8768, 8770, 8768, 8772, 8777, 8771, 8776, 8784, + 8786, 8784, 8773, 8787, 8772, 8784, 8796, 8794, 8796, 1428, 1432, 1488, + 1488, 8769, 8774, 8772, 8774, -8480, -8479, 8768, 8790, -8477, -8476, -8475, + -8474, -8473, -8472, 1418, 8737, -8471, -8470, -8469, -8468, -8467, -8466, -8465, + -8458, -8457, 184, -8456, -8454, 1424, 1424, 1446, 8832, 8854, 8861, 8878, + 8730, 8947, 8957, 8960, 8960, 8960, 8960, 8960, 8705, 8712, 8723, 8960, + 8719, 8960, 8729, 8960, 8724, 8960, 8960, 8960, 8960, 8960, 8960, 8960, + 8960, 8725, 8754, 8759, 8960, 8960, 8960, 8960, 8960, 8960, 8960, 8960, + -8453, -8451, 8960, 8960, 8707, 8704, -8450, -8449, 1909, 8706, -8448, 8705, + 8709, -8446, -8444, -8439, -8438, -8436, -8435, 8705, -8434, 1846, 8705, 8708, + 8705, 8705, 8713, 8705, 8707, -8432, 8704, 8706, 8704, 8707, 8707, 8720, + -8430, 8704, 1885, 8707, 8711, 8706, 8706, 8713, 8714, 8704, 8704, 8704, + 8704, 8704, 8727, 8743, 8769, 8870, 8878, 8884, 8914, 8920, 8960, 8960, + 8960, 8960, 8960, 8960, 8960, 8962, 8960, 8970, -8417, -8415, -8414, -8413, + -8411, -8410, -8409, -8408, -8407, -8406, -8404, -8403, -8401, -8400, -8399, -8398, + 8960, -8397, -8395, -8394, -8393, -8392, -8391, -8390, 0, 0, 0, 0, + 0, -8389, 0, 0, -8388, 8976, 8993, 8976, 8997, 8992, 8992, 9000, + 9002, -8387, 9014, 8998, -8386, 0, 0, 0, 0, -8385, -8384, -8382, + -8381, 0, 0, -8380, -8379, -8378, -8377, 0, 0, 0, 0, -8376, + 8960, 8960, 8960, 8960, 8960, 8963, 8969, 8969, 8973, -8375, -8374, 8961, + 8976, -8373, -8372, -8371, -8368, -8366, -8351, -8350, 8960, 8960, 8960, 8960, + -8349, 8960, 8960, 8960, 8964, 8960, 8960, 8960, 8964, -8348, -8347, 8960, + -8346, -8345, 8961, 8961, -8344, -8343, -8342, -8341, 0, -8340, 8960, -8338, + -8336, -8335, -8334, -8333, -8332, -8331, -8330, -8329, -8328, -8327, -8326, -8325, + -8324, -8323, -8322, -8321, -8320, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, -8318, -8317, -8316, -8315, + -8314, -8313, -8312, -8311, -8310, -8309, -8308, -8306, -8305, -8304, -8303, -8302, + 8192, 8192, 8192, 8197, 8192, 8208, 8208, 8208, 8194, 8208, 8208, 8216, + 8216, 8220, 8220, 8240, 8216, 8193, 8202, 8205, 8207, 8208, 8213, 8208, + 8197, 8208, 8212, 8208, 8208, 8208, 8224, 8208, 8207, 8193, 8195, 8193, + 8202, 8193, 8202, 8193, 8224, 8224, 8224, 8224, 8224, 8224, 8224, 8224, + 8224, 8192, 8192, 8192, 8192, -8301, -8297, 8192, 8192, 8192, 8192, 8192, + 8192, -8296, -8294, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8210, 8212, 8221, 8293, 8304, 8304, 8304, 8308, 8304, 8192, 8192, -8284, + 8192, -8275, -8271, 8196, 8256, 8256, 8256, 8256, 8264, 8256, 8256, 8256, + 8265, 8273, 8265, 8278, 8306, 8336, 8272, 8336, 8277, 8336, 8336, 8344, + 8344, 8347, 8348, 8350, 8293, 8278, 8273, 8281, 8284, 8280, 8352, 9232, + 8295, 9241, 9243, 9241, 9255, 9265, 9267, 9265, 8286, 9252, 9252, 9257, + 9248, 9260, 9289, 9263, 8272, 9296, 9296, 9296, 9249, 9296, 9298, 9296, + 9256, 8248, 8248, 8252, 9217, 9227, 9220, 9248, 9231, -8270, 9256, 9258, + 9248, -8269, -8268, -8267, -8266, 9344, 9344, 9344, 9344, 9344, 9344, 9344, + 9344, 9346, 9344, 9349, 9344, 9456, 9441, 9456, 9413, 9409, 9409, 9456, + 9417, 9456, 9408, 9456, 9409, 9464, 9412, 9465, 9466, -8265, -8264, -8263, + 9419, -8262, -8261, -8260, -8259, -8258, -8257, -8256, -8251, 9425, 9477, 9482, + -8249, 9488, 9488, 9492, 9492, 9287, 9492, 9616, 9492, 9618, 9620, 9622, + 9696, 9707, 9709, 9728, 9728, 9728, 9728, 9728, 9446, 9456, 9458, 9456, + 9462, 9456, 9458, 9456, 9728, 9728, 9728, -8248, 9728, -8247, -8246, 1, + 1, 1, 1, 5120, 1, 748, 5120, 1, 1, 1, 1, 1, + 1, 5120, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5120, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5376, 1, 5376, 5376, 1, 1, 1, 1, 1, + 1058, 1452, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9223, + 9216, 1, 1, 9217, 9217, 9217, 9217, 1, 1, 1, 1, 9216, + 9216, 9220, 9220, 9226, 9216, 9216, 9216, 9223, -8244, 9234, 9236, 9233, + 9216, 9360, 9362, 9365, 9359, 9360, 9370, 9368, 9370, 9361, 9361, 9361, + 9361, 9401, 9403, 9401, 9369, 9376, -8238, -8234, 9376, 9381, 9424, 9424, + 9381, 9425, -8233, -8225, -8219, -8217, -8216, 1, 1, 1, 9409, 1415, + 1, 1, 1, 1, 1, 1, 9409, 1481, 1, 1, 1, 1, + 1530, 9412, 9412, 9412, 9416, 9418, 9423, 1520, 9425, 9434, 9436, 9446, + 9456, 9432, 9456, 1410, 1428, 1432, 1436, 1423, 1432, -8206, 9345, 1414, + 9348, 9344, 9347, -8205, 9348, -8204, -8203, 1348, 1, 1, 1, 1, + 1, 1, 1, 1, 9365, 9364, 1, 5376, 9370, -8202, -8201, -8200, + -8199, -8198, -8197, -8196, -8194, -8192, -8190, -8189, -8181, -8178, -8177, -8176, + -8175, -8174, -8173, 9376, 1, 1, 1, 1, 9729, 9730, 1, 1, + 9399, 1, 1, 1, 9728, 9728, 9728, -8172, 9728, 8329, 8329, -8171, + 8329, 8329, 8329, 8329, 8329, 8348, 8338, 8349, 8356, 8364, 8364, 8371, + 8345, 8320, 8320, 8320, 8352, 8321, 8356, 8356, -8170, 8352, 8354, 8352, + -8169, -8168, -8167, 589, 10, 3, 9, 8320, 22, 20, 36, 35, + 49, 49, 49, 61, 68, 61, 71, 64, 68, 72, 71, 8332, + 72, 72, 72, 90, 90, 70, 94, 88, 96, 96, 96, 86, + 8323, 8344, 8344, 8344, 65, 67, 8344, 8344, 67, 65, 68, 65, + 67, 76, 78, 72, 64, 64, 74, 64, 64, 74, 91, 66, + 74, 82, 96, 100, 100, 111, 129, 39, 40, 50, 52, 128, + 128, 128, 60, 40, 128, 128, 128, 128, 138, 128, 128, 54, + 128, 49, 132, 128, 137, 137, 170, 128, 183, 152, 186, 188, + 144, 192, 198, 133, 208, 154, 194, 196, 224, 257, 229, 208, + 227, 261, 265, 257, 265, 276, 280, 231, 261, 224, 224, 181, + 224, 224, 289, 260, 260, 290, 290, 281, 294, 288, 290, 8242, + 8244, 8195, 8196, 8196, 8199, 8205, 8194, 8313, 8448, 8450, 8448, 8452, + 8448, 8448, 8448, 8456, 8448, 8448, 8452, 8452, 8449, 8456, 8456, 8456, + 8452, 8451, 8465, 8472, -8166, -8165, -8164, 8474, 8448, 8451, 8452, 8452, + 8456, 8456, 8450, 8456, 8454, 8448, 8448, 8488, 8452, 8488, 8488, 8493, + -8163, -8162, -8161, -8160, -8159, -8158, -8156, -8155, -8153, -8148, -8147, -8146, + -8144, -8143, -8141, -8138, -8133, -8130, -8125, -8123, -8122, -8121, -8120, -8119, + -8118, -8117, -8116, -8115, -8114, -8083, -8072, -8069, -7486, -7479, -7412, -7381, + -7378, -7375, -7326, -7321, -6282, -6280, -6176, -6138, -6132, -6098, -6097, -6090, + -6082, -6079, -6058, -6051, -6049, -5951, -5950, -5948, -5945, -5944, -5943, -5939, + -5917, -5916, -5915, -5913, -5912, -5911, -5910, -5909, -5908, -5905, -5901, -5870, + -5607, -5443, -5438, -5432, -5169, -5117, -5003, -4390, -4206, -4197, -4193, }; + +const size_t NU_DUCET_G_SIZE = sizeof(NU_DUCET_G) / sizeof(*NU_DUCET_G); + +/* codepoints */ +const uint32_t NU_DUCET_VALUES_C[] = { + 0x000388, 0x000389, 0x000035, 0x000386, 0x01D6EE, 0x01D6EF, 0x01D6E2, 0x01D6E3, + 0x0000C8, 0x0000C9, 0x0000CA, 0x0000CB, 0x0003A7, 0x0003A3, 0x0000CE, 0x0000CF, + 0x01D772, 0x00042F, 0x0003A0, 0x0003BE, 0x0003BC, 0x0003BD, 0x00039C, 0x00039D, + 0x000398, 0x000399, 0x01D6FC, 0x01D6FD, 0x01D6FE, 0x01D6FF, 0x00039E, 0x00039F, + 0x0003A5, 0x0003A1, 0x01D618, 0x01D61D, 0x0003B4, 0x01D607, 0x0003BA, 0x0003BF, + 0x01D61A, 0x000471, 0x00038A, 0x00038E, 0x01D60B, 0x00038F, 0x000033, 0x01D61B, + 0x0003B0, 0x0003B1, 0x01D614, 0x01D615, 0x01D616, 0x01D617, 0x0003B6, 0x0003B7, + 0x0003B8, 0x0003B9, 0x01D619, 0x00045A, 0x01D61E, 0x01D61F, 0x0003BB, 0x0003B5, + 0x0000E0, 0x0000E1, 0x0000E2, 0x0000E3, 0x0000E4, 0x0000E5, 0x0000E6, 0x0000E7, + 0x01D602, 0x01D603, 0x0000C6, 0x0003AD, 0x01D605, 0x01D601, 0x0000FC, 0x01D61C, + 0x0000F0, 0x0000F1, 0x01D606, 0x0000EB, 0x0000F4, 0x0000F5, 0x0000F6, 0x0000EA, + 0x0000F8, 0x0000F9, 0x0000FA, 0x0000FB, 0x0000CC, 0x0000FD, 0x0000FE, 0x0000FF, + 0x01D6C0, 0x000428, 0x01D6C4, 0x01D6C5, 0x01D6F8, 0x01D6FA, 0x0000C4, 0x01D6C9, + 0x01D6CA, 0x01D6CB, 0x01D6C8, 0x01D6CD, 0x01D6CE, 0x01D6CC, 0x0000F2, 0x0000F3, + 0x0003A9, 0x0003F5, 0x000032, 0x01D633, 0x01D60F, 0x0003A4, 0x00042E, 0x000031, + 0x000030, 0x01D60A, 0x01D604, 0x01D609, 0x0000ED, 0x01D65B, 0x0003A6, 0x0003AB, + 0x01D6F2, 0x01D6F3, 0x000076, 0x000077, 0x0000C2, 0x0000C5, 0x01D6F9, 0x0000C3, + 0x0000D8, 0x0000C1, 0x00039B, 0x0000C7, 0x0000C0, 0x00038C, 0x0000DE, 0x0000DF, + 0x0000D2, 0x0000D1, 0x0000D0, 0x0000D3, 0x0000D5, 0x000069, 0x0003B3, 0x0000D6, + 0x0000D9, 0x0000DD, 0x0000DC, 0x0000DB, 0x0003B2, 0x0000D4, 0x01D6A1, 0x0000DA, + 0x01D6A0, 0x000061, 0x01D6A4, 0x01D6A5, 0x00039A, 0x01D6C7, 0x01D6A8, 0x01D6A9, + 0x01D6AE, 0x000394, 0x01D6AC, 0x01D6AD, 0x01D6F4, 0x01D6AF, 0x01D6F6, 0x01D6F5, + 0x01D6F7, 0x000038, 0x01D694, 0x01D695, 0x000034, 0x01D69E, 0x000036, 0x000037, + 0x01D69A, 0x000039, 0x01D6B8, 0x01D6BE, 0x01D6BF, 0x01D69F, 0x01D6D4, 0x01D6D5, + 0x000044, 0x000045, 0x01D6B4, 0x01D6B5, 0x000054, 0x000055, 0x000056, 0x000057, + 0x01D6BA, 0x01D6BB, 0x0000AA, 0x00004D, 0x01D6AA, 0x01D6AB, 0x01D6B6, 0x01D6B1, + 0x000051, 0x01D6CF, 0x0000B2, 0x000053, 0x01D6B7, 0x0000B5, 0x000050, 0x01D6B0, + 0x00004C, 0x0000B9, 0x0000BA, 0x000052, 0x0000BC, 0x0000BD, 0x0000BE, 0x01D6D0, + 0x000042, 0x000074, 0x000043, 0x000072, 0x01D6D2, 0x01D6F0, 0x000046, 0x000047, + 0x0000CD, 0x000049, 0x00004A, 0x00004B, 0x000048, 0x01D6DA, 0x00004E, 0x00004F, + 0x000070, 0x000071, 0x01D6D1, 0x01D6D3, 0x01D6D6, 0x01D6D7, 0x000073, 0x01D6DE, + 0x000059, 0x000079, 0x0000B3, 0x000058, 0x01D6F1, 0x01D6DF, 0x00005A, 0x000078, + 0x000101, 0x000100, 0x000103, 0x000102, 0x000105, 0x000104, 0x000107, 0x000106, + 0x000109, 0x000108, 0x00010B, 0x00010A, 0x00010D, 0x00010C, 0x00010F, 0x00010E, + 0x000111, 0x000110, 0x000113, 0x000112, 0x000115, 0x000114, 0x000117, 0x000116, + 0x000119, 0x000118, 0x00011B, 0x00011A, 0x00011D, 0x00011C, 0x00011F, 0x00011E, + 0x000121, 0x000120, 0x000123, 0x000122, 0x000125, 0x000124, 0x000127, 0x000126, + 0x000129, 0x000128, 0x01D691, 0x00012A, 0x00012D, 0x00012C, 0x00012F, 0x00012E, + 0x000131, 0x000130, 0x000133, 0x000132, 0x000135, 0x000134, 0x000137, 0x000136, + 0x000139, 0x000138, 0x00013B, 0x00013A, 0x00013D, 0x00013C, 0x00013F, 0x00013E, + 0x000141, 0x000140, 0x000143, 0x000142, 0x000145, 0x000144, 0x000147, 0x000146, + 0x000149, 0x000148, 0x01D69B, 0x00014A, 0x00014D, 0x00014C, 0x00014F, 0x00014E, + 0x000151, 0x000150, 0x000153, 0x000152, 0x000155, 0x000154, 0x000157, 0x000156, + 0x000159, 0x000158, 0x00015B, 0x00015A, 0x00015D, 0x00015C, 0x00015F, 0x00015E, + 0x000161, 0x000160, 0x000163, 0x000162, 0x000165, 0x000164, 0x000167, 0x000166, + 0x000169, 0x000168, 0x00016B, 0x00016A, 0x00016D, 0x00016C, 0x01D690, 0x01D697, + 0x000171, 0x000170, 0x000173, 0x000172, 0x000175, 0x000174, 0x000177, 0x000176, + 0x000179, 0x000178, 0x00017B, 0x00017A, 0x01D696, 0x00017C, 0x00017F, 0x00017E, + 0x000181, 0x000180, 0x000183, 0x000182, 0x000185, 0x000184, 0x000187, 0x000186, + 0x000189, 0x000188, 0x00018B, 0x00018A, 0x00018D, 0x00018C, 0x00018F, 0x00018E, + 0x000191, 0x000190, 0x000193, 0x000192, 0x000195, 0x000194, 0x000197, 0x000196, + 0x000199, 0x000198, 0x00019B, 0x00019A, 0x00019D, 0x00019C, 0x00019F, 0x00019E, + 0x0001A1, 0x0001A0, 0x0001A3, 0x0001A2, 0x0001A5, 0x0001A4, 0x0001A7, 0x0001A6, + 0x0001A9, 0x0001A8, 0x0001AB, 0x0001AA, 0x0001AD, 0x0001AC, 0x0001AF, 0x0001AE, + 0x0001B1, 0x0001B0, 0x0001B3, 0x0001B2, 0x0001B5, 0x0001B4, 0x0001B7, 0x0001B6, + 0x0001B9, 0x0001B8, 0x0001BB, 0x0001BA, 0x0001BD, 0x0001BC, 0x0001BF, 0x0001BE, + 0x0001C1, 0x0001C0, 0x0001C3, 0x0001C2, 0x0001C5, 0x0001C4, 0x0001C7, 0x0001C6, + 0x0001C9, 0x0001C8, 0x0001CB, 0x0001CA, 0x0001CD, 0x0001CC, 0x0001CF, 0x0001CE, + 0x0001D1, 0x0001D0, 0x0001D3, 0x0001D2, 0x0001D5, 0x0001D4, 0x0001D7, 0x0001D6, + 0x0001D9, 0x0001D8, 0x0001DB, 0x0001DA, 0x0001DD, 0x0001DC, 0x0001DF, 0x0001DE, + 0x0001E1, 0x0001E0, 0x0001E3, 0x0001E2, 0x0001E5, 0x0001E4, 0x0001E7, 0x0001E6, + 0x0001E9, 0x0001E8, 0x0001EB, 0x0001EA, 0x0001ED, 0x0001EC, 0x0001EF, 0x0001EE, + 0x0001F1, 0x0001F0, 0x0001F3, 0x0001F2, 0x0001F5, 0x0001F4, 0x01D711, 0x0001F6, + 0x0001F9, 0x0001F8, 0x0001FB, 0x0001FA, 0x0001FD, 0x0001FC, 0x0001FF, 0x0001FE, + 0x01D702, 0x01D703, 0x01D722, 0x01D721, 0x01D720, 0x01D723, 0x01D708, 0x01D725, + 0x01D726, 0x01D72B, 0x01D73C, 0x01D73D, 0x01D73E, 0x01D727, 0x01D710, 0x01D731, + 0x01D730, 0x01D73A, 0x01D736, 0x01D734, 0x01D753, 0x01D737, 0x01D718, 0x01D739, + 0x01D73B, 0x01D71B, 0x01D71C, 0x01D738, 0x01D73F, 0x01D71F, 0x01D781, 0x01D780, + 0x01D783, 0x01D782, 0x01D785, 0x01D784, 0x01D787, 0x01D786, 0x01D72A, 0x01D788, + 0x01D78B, 0x01D78A, 0x01D78D, 0x01D78C, 0x01D78F, 0x01D78E, 0x01D791, 0x01D790, + 0x01D793, 0x01D792, 0x01D795, 0x01D794, 0x01D797, 0x01D796, 0x01D799, 0x01D798, + 0x01D79B, 0x01D79A, 0x01D79D, 0x01D79C, 0x01D79F, 0x01D79E, 0x01D7A1, 0x01D7A0, + 0x01D7A3, 0x01D7A2, 0x01D7A5, 0x01D7A4, 0x01D7A7, 0x01D7A6, 0x01D724, 0x01D7A8, + 0x01D7AB, 0x01D7AA, 0x01D7AD, 0x01D7AC, 0x01D7AF, 0x01D7AE, 0x01D7B1, 0x01D7B0, + 0x01D7B3, 0x01D7B2, 0x01D7B5, 0x01D7B4, 0x01D7B7, 0x01D7B6, 0x01D7B9, 0x01D7B8, + 0x01D7BB, 0x01D7BA, 0x01D7BD, 0x01D7BC, 0x01D7BF, 0x01D7BE, 0x01D7C1, 0x01D7C0, + 0x01D752, 0x01D7C2, 0x01D7C5, 0x01D7C4, 0x01D7C7, 0x01D7C6, 0x01D7C9, 0x01D7C8, + 0x01D7CB, 0x01D7CA, 0x01D750, 0x01D751, 0x01D7CF, 0x01D7CE, 0x01D7D1, 0x01D7D0, + 0x01D7D3, 0x01D7D2, 0x01D7D5, 0x01D7D4, 0x01D7D7, 0x01D7D6, 0x01D7D9, 0x01D7D8, + 0x01D7DB, 0x01D7DA, 0x01D7DD, 0x01D7DC, 0x01D7DF, 0x01D7DE, 0x01D740, 0x01D741, + 0x01D773, 0x01D743, 0x01D744, 0x01D745, 0x01D746, 0x01D747, 0x01D728, 0x01D729, + 0x01D74A, 0x01D74B, 0x01D72C, 0x01D72D, 0x01D72E, 0x01D72F, 0x01D742, 0x01D749, + 0x01D7F3, 0x01D7F2, 0x01D754, 0x01D748, 0x01D756, 0x01D757, 0x01D758, 0x01D759, + 0x01D75A, 0x01D75B, 0x01D75C, 0x01D75D, 0x01D75E, 0x01D75F, 0x000218, 0x000219, + 0x000200, 0x000201, 0x000202, 0x000203, 0x000204, 0x000205, 0x000206, 0x000207, + 0x000208, 0x000209, 0x00020A, 0x00020B, 0x00020C, 0x00020D, 0x00020E, 0x00020F, + 0x000230, 0x000231, 0x000232, 0x000233, 0x000234, 0x000235, 0x000236, 0x000237, + 0x000238, 0x000239, 0x00023A, 0x00023B, 0x00021C, 0x00021D, 0x00021E, 0x00021F, + 0x000240, 0x000241, 0x000242, 0x000243, 0x000244, 0x000245, 0x000246, 0x000247, + 0x000248, 0x000249, 0x00024A, 0x00024B, 0x00024C, 0x00024D, 0x00022E, 0x00022F, + 0x000250, 0x000251, 0x000252, 0x000253, 0x000254, 0x000255, 0x000256, 0x000257, + 0x000258, 0x000259, 0x00025A, 0x00025B, 0x00025C, 0x00025D, 0x00025E, 0x00025F, + 0x000220, 0x000221, 0x000222, 0x000223, 0x000224, 0x000225, 0x000226, 0x000227, + 0x0000E8, 0x000229, 0x00022A, 0x00022B, 0x0000EC, 0x000228, 0x0000EE, 0x0000EF, + 0x000270, 0x000271, 0x000272, 0x000273, 0x000274, 0x000275, 0x00007A, 0x000277, + 0x00022C, 0x00022D, 0x00027A, 0x00027B, 0x00023C, 0x00023D, 0x00023E, 0x00023F, + 0x000728, 0x000771, 0x000772, 0x000773, 0x000724, 0x000770, 0x000776, 0x00072F, + 0x00046C, 0x00046D, 0x00072A, 0x00072B, 0x00044C, 0x00044D, 0x00044E, 0x00044F, + 0x00072C, 0x00072D, 0x000750, 0x000759, 0x000755, 0x000752, 0x00072E, 0x000756, + 0x00071E, 0x000761, 0x00075A, 0x00075B, 0x000754, 0x00071C, 0x000777, 0x000760, + 0x000460, 0x000461, 0x000462, 0x000463, 0x000465, 0x000392, 0x000466, 0x000467, + 0x000468, 0x000469, 0x00046A, 0x00046B, 0x00042C, 0x00042D, 0x00046E, 0x00046F, + 0x000726, 0x000721, 0x000720, 0x000725, 0x000474, 0x00047C, 0x000464, 0x000722, + 0x000478, 0x000479, 0x00047A, 0x000729, 0x000393, 0x00047D, 0x00047E, 0x00047F, + 0x000440, 0x000441, 0x000442, 0x000443, 0x000444, 0x000445, 0x00026E, 0x000447, + 0x000268, 0x000269, 0x00026A, 0x00026F, 0x00026C, 0x00026D, 0x00024E, 0x00024F, + 0x000470, 0x00047B, 0x000449, 0x000476, 0x000475, 0x000477, 0x000446, 0x000448, + 0x000458, 0x000459, 0x00044A, 0x00044B, 0x00045C, 0x00045D, 0x00045E, 0x00045F, + 0x000062, 0x000261, 0x000262, 0x000263, 0x000064, 0x000065, 0x000066, 0x000067, + 0x000068, 0x000267, 0x00026B, 0x00006B, 0x000396, 0x00006E, 0x00006A, 0x00006F, + 0x00027C, 0x000260, 0x000266, 0x000397, 0x000391, 0x00027D, 0x000390, 0x000276, + 0x000278, 0x000279, 0x000264, 0x000265, 0x00006C, 0x00006D, 0x00027E, 0x00027F, + 0x000692, 0x000698, 0x00069D, 0x000693, 0x000691, 0x00069A, 0x00069B, 0x000697, + 0x000690, 0x000696, 0x00A380, 0x00A381, 0x00A383, 0x00A38E, 0x00A384, 0x00A385, + 0x00A0EC, 0x00A382, 0x00A388, 0x00A389, 0x00A387, 0x00A38B, 0x00A38C, 0x00A38D, + 0x00A38A, 0x00A38F, 0x00A390, 0x00A391, 0x00A392, 0x00A39E, 0x00A394, 0x00A395, + 0x00A396, 0x00A397, 0x00A398, 0x00A399, 0x00A065, 0x00A39B, 0x00A39C, 0x00A39D, + 0x00A39A, 0x00A39F, 0x000680, 0x000687, 0x00A0EE, 0x00A3C4, 0x000768, 0x000769, + 0x000694, 0x00A386, 0x000688, 0x000689, 0x00A3A3, 0x00076C, 0x000695, 0x00069C, + 0x00076D, 0x00A0ED, 0x00A3B0, 0x00A3B1, 0x00A3B3, 0x00A3BE, 0x00A3B4, 0x00A3B5, + 0x00A3B2, 0x00A3B7, 0x00A3B8, 0x00A3B9, 0x00A3B6, 0x00A3BB, 0x000686, 0x00A3BD, + 0x00A3BA, 0x00A3BF, 0x00076E, 0x00076F, 0x00074D, 0x00A3C5, 0x00074E, 0x00074F, + 0x00A0E6, 0x00077C, 0x00A0EF, 0x00A0E8, 0x000684, 0x000685, 0x00A0CE, 0x00077D, + 0x000758, 0x000778, 0x00077E, 0x00077F, 0x00075C, 0x00075D, 0x00075E, 0x00075F, + 0x000779, 0x000765, 0x000762, 0x000763, 0x000774, 0x000775, 0x000766, 0x000767, + 0x00076A, 0x00076B, 0x00A3BC, 0x00A3AE, 0x000764, 0x00A0E3, 0x00A3A4, 0x00A3A5, + 0x00A0E5, 0x00A0E2, 0x00A3A8, 0x00A3A9, 0x00A3AA, 0x00A3AB, 0x00A3AD, 0x00A0E1, + 0x00A3AF, 0x00A0E0, 0x00077B, 0x00A0E7, 0x00077A, 0x00A0E9, 0x00A0F4, 0x00A0E4, + 0x00A0F6, 0x00A0F7, 0x000419, 0x000492, 0x000490, 0x000491, 0x00A0FC, 0x00A0FD, + 0x00A0EA, 0x00A0EB, 0x00A088, 0x00A0FE, 0x00A08C, 0x000497, 0x00A085, 0x00A084, + 0x000493, 0x00A08D, 0x00A098, 0x00A099, 0x00A08B, 0x00A089, 0x00A08E, 0x00A08F, + 0x00A09E, 0x00A09F, 0x00A091, 0x00A090, 0x00A093, 0x00A092, 0x00A09A, 0x00A09B, + 0x00A097, 0x00A096, 0x00A082, 0x00A083, 0x00A09C, 0x00A09D, 0x00A094, 0x00A095, + 0x00A080, 0x00A081, 0x00A0A4, 0x00A0A0, 0x00A0A3, 0x00A0A2, 0x00A0A5, 0x00A0A1, + 0x00A086, 0x00A087, 0x000495, 0x00A0A8, 0x00A0AB, 0x00A0AA, 0x00A0F5, 0x000496, + 0x00A0AF, 0x00A0AE, 0x00A0B4, 0x00A0B0, 0x00A0B3, 0x00A0B2, 0x00A0B5, 0x00A0B1, + 0x00A0B7, 0x00A0B6, 0x00A0BC, 0x00A0B8, 0x00A0BB, 0x00A0BA, 0x00A0BD, 0x00A0B9, + 0x00A0BF, 0x00A0BE, 0x00A1C0, 0x00A1C1, 0x00A1E2, 0x00A1E3, 0x00A0C3, 0x00A1E1, + 0x00A1E6, 0x00A1E7, 0x00A1E0, 0x00A1C8, 0x00A0C4, 0x00A0CA, 0x00A0C5, 0x00A0DD, + 0x000494, 0x00049B, 0x00A0C0, 0x00A0C1, 0x00A0C2, 0x00A0FF, 0x00A0D5, 0x00A0D4, + 0x00A0C6, 0x00A0C7, 0x00A0D9, 0x00A0D8, 0x00A0DB, 0x00A0DA, 0x00A1FC, 0x00A0DC, + 0x00A0DF, 0x00A0DE, 0x00A1FE, 0x00A1FF, 0x000413, 0x00A0F8, 0x00A0C9, 0x00A0F1, + 0x00049A, 0x00A0C8, 0x00A0F2, 0x00A0CB, 0x00A0F3, 0x00A1FA, 0x00A1F8, 0x00A0F0, + 0x00A0A6, 0x00A0A7, 0x00A1F0, 0x00A1F1, 0x00A1F2, 0x00A1F3, 0x00A1F4, 0x00A1F5, + 0x00A0CF, 0x00A1F9, 0x00A0F9, 0x00A0CC, 0x00A1F6, 0x00A1FB, 0x00A1FD, 0x00A0FB, + 0x00A0CD, 0x00A1F7, 0x00A128, 0x00A129, 0x00A12A, 0x00A12B, 0x00A184, 0x00A185, + 0x00A124, 0x00A125, 0x00A188, 0x00A189, 0x00A18A, 0x00A18B, 0x00A18C, 0x00A18D, + 0x00A18E, 0x00A18F, 0x00A12C, 0x00A12D, 0x00A178, 0x00A179, 0x00A192, 0x00A193, + 0x00A114, 0x00A115, 0x00A11A, 0x00A11B, 0x00A118, 0x00A119, 0x00A11E, 0x00A11F, + 0x00A12E, 0x00A12F, 0x00A180, 0x00A181, 0x00A182, 0x00A183, 0x00A1A4, 0x00A1A5, + 0x00A186, 0x00A187, 0x00A1A8, 0x00A1A9, 0x00A1AA, 0x00A1AB, 0x00A1AC, 0x00A1AD, + 0x00A1AE, 0x00A1AF, 0x00A190, 0x00A191, 0x00A1B2, 0x00A1B3, 0x00A194, 0x00A195, + 0x00A196, 0x00A197, 0x00A198, 0x00A199, 0x00A19A, 0x00A19B, 0x00A19C, 0x00A19D, + 0x00A19E, 0x00A19F, 0x00A1A0, 0x00A1A1, 0x00A1C2, 0x00A1C3, 0x00A1C4, 0x00A1C5, + 0x00A1C6, 0x00A1C7, 0x00A153, 0x00A1C9, 0x00A1CA, 0x00A1CB, 0x00A1CC, 0x00A1CD, + 0x00A1CE, 0x00A1CF, 0x00A1D0, 0x00A1D1, 0x00A1D2, 0x00A1D3, 0x00A1D4, 0x00A1D5, + 0x00A1D6, 0x00A1D7, 0x00A1D8, 0x00A1D9, 0x00A1DA, 0x00A1DB, 0x00A1DC, 0x00A1DD, + 0x00A1DE, 0x00A1DF, 0x00A150, 0x00A151, 0x00A152, 0x00A1A3, 0x00A144, 0x00A175, + 0x00A157, 0x00A1A2, 0x00A17B, 0x00A14A, 0x00A156, 0x00A14B, 0x00A174, 0x00A17E, + 0x00A17A, 0x00A17F, 0x00A1B0, 0x00A1B1, 0x00A1A6, 0x00A1A7, 0x00A1B4, 0x00A1B5, + 0x00A1B6, 0x00A1B7, 0x00A1B8, 0x00A1B9, 0x00A1BA, 0x00A1BB, 0x00A1BC, 0x00A1BD, + 0x00A1BE, 0x00A1BF, 0x000502, 0x000503, 0x00050A, 0x00050B, 0x000500, 0x000501, + 0x00050E, 0x00050F, 0x000508, 0x000509, 0x000504, 0x000505, 0x000506, 0x000507, + 0x000519, 0x000518, 0x00A02B, 0x000564, 0x00051D, 0x00051C, 0x00051F, 0x00051E, + 0x000521, 0x000520, 0x000523, 0x000527, 0x000525, 0x000524, 0x000522, 0x000526, + 0x000529, 0x000528, 0x00052B, 0x00052F, 0x00050C, 0x00050D, 0x00052A, 0x00052E, + 0x000531, 0x00053B, 0x000533, 0x000532, 0x00053A, 0x000537, 0x000534, 0x000535, + 0x000539, 0x000538, 0x000563, 0x00053F, 0x00053D, 0x00053C, 0x000536, 0x00053E, + 0x000541, 0x000540, 0x000543, 0x000542, 0x000545, 0x000544, 0x000547, 0x000546, + 0x00057B, 0x000565, 0x00A009, 0x00054A, 0x000575, 0x000481, 0x000549, 0x00057A, + 0x000551, 0x000550, 0x000553, 0x000571, 0x000555, 0x000554, 0x000552, 0x000556, + 0x000548, 0x000576, 0x000577, 0x00054B, 0x00054C, 0x00054D, 0x00054E, 0x00054F, + 0x000579, 0x00A01B, 0x000578, 0x00057E, 0x00052C, 0x00052D, 0x000567, 0x000561, + 0x0005EA, 0x0005E9, 0x0004D1, 0x00057F, 0x0005E8, 0x00A163, 0x00A164, 0x00A165, + 0x00A162, 0x000570, 0x00A168, 0x00A169, 0x00A16A, 0x00A16B, 0x00A16C, 0x00A16D, + 0x00A16E, 0x00A16F, 0x000573, 0x00A011, 0x000572, 0x000566, 0x0004B7, 0x00049F, + 0x000582, 0x000583, 0x000580, 0x000581, 0x000586, 0x000587, 0x000584, 0x000585, + 0x00A17C, 0x000623, 0x00A000, 0x00A001, 0x0005E6, 0x0005E7, 0x00A004, 0x00A005, + 0x000510, 0x000511, 0x000512, 0x000513, 0x000514, 0x000515, 0x000516, 0x000517, + 0x00A006, 0x00A007, 0x00051A, 0x00051B, 0x00A012, 0x00A013, 0x00A010, 0x00A00D, + 0x00A016, 0x00A017, 0x00A00A, 0x00A008, 0x00A01A, 0x00A00B, 0x00A01C, 0x00A01D, + 0x00A00E, 0x00A00F, 0x00A02C, 0x00A02D, 0x00A02E, 0x00A02F, 0x00A024, 0x00A025, + 0x00A022, 0x00A023, 0x00A038, 0x00A039, 0x00A02A, 0x00A029, 0x00A027, 0x00A00C, + 0x00A03E, 0x00A028, 0x00A030, 0x00A031, 0x00A032, 0x00A033, 0x00A03A, 0x00A03F, + 0x00A036, 0x00A037, 0x0005D9, 0x00A049, 0x00A03B, 0x00A021, 0x00A034, 0x00A035, + 0x00A03C, 0x00A03D, 0x00A042, 0x00A041, 0x00056C, 0x00A043, 0x00A046, 0x00A040, + 0x00A047, 0x0005F1, 0x0005F2, 0x0005F0, 0x00A04A, 0x00A04B, 0x00A044, 0x00A045, + 0x00A05B, 0x00A04F, 0x00A052, 0x00A053, 0x00A050, 0x00A051, 0x00A056, 0x00A057, + 0x0005DC, 0x00056E, 0x000562, 0x00056F, 0x0005D4, 0x0005D5, 0x0005DA, 0x0005DB, + 0x0005D8, 0x000569, 0x00056A, 0x00056B, 0x0005DD, 0x000568, 0x0005DE, 0x0005DF, + 0x0005D2, 0x0005D3, 0x0005E1, 0x0005E3, 0x0005E0, 0x0005E5, 0x000574, 0x0005E4, + 0x0005D0, 0x0005D1, 0x0005E2, 0x00056D, 0x00057C, 0x00057D, 0x0005D6, 0x0005D7, + 0x00A020, 0x00A026, 0x00A058, 0x00A059, 0x00A05A, 0x00A05D, 0x00A054, 0x00A055, + 0x00A05E, 0x00A05F, 0x0007CA, 0x00A340, 0x0007CC, 0x0007CD, 0x000631, 0x0007CE, + 0x00A346, 0x00A347, 0x00A364, 0x00A365, 0x00A36D, 0x0006B1, 0x00A215, 0x000633, + 0x000632, 0x00069E, 0x000683, 0x00A211, 0x00A369, 0x00A36E, 0x00A36C, 0x00069F, + 0x00A368, 0x00A210, 0x0007E3, 0x00A36F, 0x000699, 0x00A36A, 0x00A35C, 0x0007E2, + 0x0007E4, 0x0007E5, 0x000681, 0x00A21D, 0x0007E8, 0x0007E9, 0x00A37C, 0x00A214, + 0x00A362, 0x00A363, 0x0007EA, 0x000682, 0x00A2AB, 0x00A32E, 0x00A32C, 0x00068B, + 0x00A213, 0x00A20B, 0x00A21B, 0x00A374, 0x00A37E, 0x00A37F, 0x00A375, 0x00A06C, + 0x0004E8, 0x0004ED, 0x00A06B, 0x0004E6, 0x0004E5, 0x0004E7, 0x00A06E, 0x00A06F, + 0x00A06A, 0x0004E9, 0x0004CA, 0x00A060, 0x0004E4, 0x00A063, 0x0007E0, 0x0004EE, + 0x00A06D, 0x0007D4, 0x00A048, 0x00A35D, 0x00A062, 0x00A067, 0x00A04C, 0x00A04D, + 0x00A04E, 0x00A068, 0x0007DA, 0x00A291, 0x000719, 0x0004EC, 0x00A37A, 0x0007CB, + 0x00A07E, 0x00A066, 0x0004E2, 0x0004E3, 0x0004E1, 0x00A079, 0x00A05C, 0x00A078, + 0x00A07F, 0x0004EF, 0x00A064, 0x00A069, 0x0004FC, 0x0004E0, 0x0004EB, 0x00A07C, + 0x00A076, 0x00A061, 0x0004FE, 0x0004EA, 0x0004F4, 0x0004FD, 0x0004F6, 0x0004FF, + 0x0004F8, 0x0004F9, 0x0004FA, 0x0004FB, 0x00A072, 0x00A073, 0x00A074, 0x00A075, + 0x000480, 0x00A07A, 0x00A07D, 0x00A071, 0x00048C, 0x00048D, 0x00A070, 0x0004F7, + 0x00A07B, 0x00A077, 0x00048A, 0x00048B, 0x000718, 0x00071D, 0x00048E, 0x00048F, + 0x00A292, 0x00A297, 0x00A2B5, 0x00A2B9, 0x000636, 0x000635, 0x000412, 0x000727, + 0x000498, 0x000499, 0x00049E, 0x0004BA, 0x00049C, 0x00049D, 0x000723, 0x000417, + 0x0004A1, 0x0004B1, 0x0004B0, 0x0004BB, 0x0004B4, 0x0004B5, 0x0004AD, 0x0004B6, + 0x0004AA, 0x0004AB, 0x0004A2, 0x0004A3, 0x0004A8, 0x0004A9, 0x0004A0, 0x0004A5, + 0x00041B, 0x000416, 0x0004B2, 0x0004B3, 0x0004A4, 0x0004AF, 0x0004A6, 0x0004A7, + 0x0004B8, 0x0004B9, 0x000630, 0x000637, 0x0004BC, 0x0004BD, 0x0004BE, 0x0004BF, + 0x000757, 0x000634, 0x000411, 0x00041A, 0x000410, 0x00A2A5, 0x000414, 0x000415, + 0x00A2A9, 0x0004C9, 0x0004C8, 0x0004CE, 0x0004CD, 0x000753, 0x0004CC, 0x0004CF, + 0x0004D0, 0x0004D6, 0x0004D2, 0x0004D3, 0x0004C1, 0x0004D7, 0x0004DA, 0x0004DB, + 0x0004D4, 0x0004D5, 0x0004D8, 0x0004D9, 0x0004DE, 0x0004DF, 0x0004DC, 0x0004DD, + 0x0004C0, 0x000710, 0x00071A, 0x000715, 0x0004C4, 0x0004C5, 0x0004C6, 0x0004C7, + 0x000716, 0x000714, 0x0004C2, 0x0004C3, 0x000717, 0x0004CB, 0x00A3EE, 0x00A3E4, + 0x0004F0, 0x0004F1, 0x00A3E8, 0x00A3EC, 0x00A3EB, 0x0004F5, 0x00A3ED, 0x00A3EF, + 0x0004AE, 0x00A3EA, 0x0004F2, 0x0004F3, 0x00071B, 0x0004AC, 0x000712, 0x000713, + 0x000782, 0x000783, 0x000780, 0x000781, 0x000785, 0x000787, 0x000784, 0x0007B1, + 0x00079C, 0x00079D, 0x00A301, 0x00078B, 0x00A316, 0x00A317, 0x00078F, 0x000786, + 0x000791, 0x00079E, 0x00A393, 0x000792, 0x00079F, 0x000790, 0x000796, 0x000795, + 0x000798, 0x000799, 0x00079B, 0x00A318, 0x00A312, 0x00A313, 0x000794, 0x00079A, + 0x00A314, 0x00A315, 0x00A31A, 0x00A31B, 0x00A311, 0x00A319, 0x00A31E, 0x00A31D, + 0x00A31F, 0x00A310, 0x00078A, 0x00A300, 0x000788, 0x000789, 0x0007A3, 0x00078E, + 0x00A302, 0x00A303, 0x00A324, 0x00A32B, 0x0007A0, 0x0007A1, 0x00A334, 0x00A325, + 0x00A33A, 0x00A33B, 0x0007A2, 0x00A329, 0x00078C, 0x00078D, 0x00A328, 0x00A32D, + 0x00A306, 0x00A307, 0x00A335, 0x0007DB, 0x0007D0, 0x0007D5, 0x00A31C, 0x00A30B, + 0x00A32A, 0x00A32F, 0x0007D6, 0x0007C3, 0x0007C2, 0x0007C1, 0x0007C7, 0x0007D7, + 0x000751, 0x0007C9, 0x0007CF, 0x0007D1, 0x0007DC, 0x0007DD, 0x0007DE, 0x0007DF, + 0x0007D8, 0x0007D9, 0x00A359, 0x0007D3, 0x00A352, 0x00A353, 0x0007D2, 0x00071F, + 0x00A293, 0x00A35B, 0x00A350, 0x00A351, 0x00A354, 0x00A343, 0x00A341, 0x00A355, + 0x00A356, 0x00A357, 0x0007C0, 0x0007C5, 0x0007C8, 0x0007C6, 0x0007A4, 0x0007A5, + 0x00A342, 0x0007E1, 0x00A378, 0x00A379, 0x0007C4, 0x00A37B, 0x0007E6, 0x0007E7, + 0x00A35E, 0x00A3E5, 0x00A35A, 0x00A35F, 0x00A3E9, 0x00A358, 0x00A33E, 0x00A33F, + 0x00040D, 0x000401, 0x000402, 0x000403, 0x000400, 0x000405, 0x000406, 0x000407, + 0x000409, 0x000404, 0x00040A, 0x00040B, 0x000797, 0x000408, 0x00040E, 0x00040F, + 0x000450, 0x000451, 0x000452, 0x000453, 0x000455, 0x000472, 0x000456, 0x000457, + 0x000418, 0x000793, 0x00045B, 0x000454, 0x00041C, 0x00041D, 0x00041E, 0x00041F, + 0x000429, 0x000421, 0x000422, 0x000423, 0x000420, 0x000425, 0x000426, 0x000427, + 0x0003A8, 0x000424, 0x0003AA, 0x00042B, 0x0003AC, 0x00040C, 0x0003AE, 0x0003AF, + 0x00043C, 0x000431, 0x000432, 0x000433, 0x000430, 0x000435, 0x000436, 0x000437, + 0x000439, 0x000434, 0x00043A, 0x00043B, 0x000438, 0x00043D, 0x00043E, 0x00043F, + 0x0003C0, 0x0003C1, 0x0003C2, 0x0003C3, 0x0003C4, 0x0003C5, 0x0003C6, 0x0003C7, + 0x0003C8, 0x0003C9, 0x0003CA, 0x0003CB, 0x0003CC, 0x0003CD, 0x0003CE, 0x0003CF, + 0x0003D0, 0x0003D1, 0x0003D2, 0x0003D3, 0x0003D4, 0x0003D5, 0x0003D6, 0x0003D7, + 0x0003D8, 0x0003D9, 0x0003DA, 0x0003DB, 0x0003DC, 0x0003DD, 0x0003DE, 0x0003DF, + 0x0003E0, 0x0003E1, 0x0003E2, 0x0003E3, 0x0003E4, 0x0003E5, 0x0003E6, 0x0003E7, + 0x0003E8, 0x0003E9, 0x0003EA, 0x0003EB, 0x0003EC, 0x0003ED, 0x0003EE, 0x0003EF, + 0x0003F0, 0x0003F1, 0x0003F2, 0x0003F3, 0x0003F4, 0x000473, 0x00042A, 0x0003F7, + 0x0003F8, 0x0003F9, 0x0003FA, 0x0003FB, 0x0003FC, 0x0003FD, 0x0003FE, 0x0003FF, + 0x00A433, 0x00A40E, 0x00A404, 0x00A405, 0x00A435, 0x00A432, 0x00A408, 0x00A409, + 0x00A40A, 0x00A40B, 0x00A3C0, 0x00A3C1, 0x00A3E6, 0x00A3E7, 0x00A482, 0x00A483, + 0x00A3C6, 0x00A3C7, 0x00A480, 0x00A481, 0x00A48B, 0x00A48A, 0x00A3CC, 0x00A485, + 0x00A3CE, 0x00A484, 0x00A40C, 0x00A40D, 0x000802, 0x000801, 0x000803, 0x00A486, + 0x0008A2, 0x00A487, 0x00A488, 0x00A489, 0x0008BC, 0x0008BD, 0x0008BA, 0x0008BB, + 0x00080B, 0x000852, 0x00A3E0, 0x00A3E1, 0x00A3E2, 0x00A3E3, 0x00A43D, 0x00A46E, + 0x00A3A6, 0x00A3A7, 0x0008AB, 0x00A439, 0x000807, 0x000853, 0x00A3FE, 0x0008A7, + 0x00A436, 0x00A437, 0x00A3F0, 0x00A3F1, 0x00A3F2, 0x00A3F3, 0x00A3F4, 0x00A3F5, + 0x00A434, 0x00A3F7, 0x00A3F8, 0x00A3F9, 0x00A3FA, 0x00A3FB, 0x00A3FC, 0x00A3FD, + 0x00A3FF, 0x00A3F6, 0x00A4D0, 0x00A4D1, 0x00A4D2, 0x000806, 0x00A46F, 0x000800, + 0x00A4D6, 0x00A4D7, 0x00A3D8, 0x00A46A, 0x0008A0, 0x0008A5, 0x00A3DC, 0x00A3DD, + 0x00A43A, 0x00A43F, 0x00A3D0, 0x00A3D1, 0x00A3D2, 0x00A3D3, 0x00A3D4, 0x00A3D5, + 0x00A3D6, 0x00A3D7, 0x00A3C3, 0x00A3D9, 0x00A3DA, 0x00A3DB, 0x00A4D3, 0x00A3C2, + 0x00A3DE, 0x00A3DF, 0x0008A6, 0x0008AA, 0x0008A1, 0x00A465, 0x00A4E2, 0x00A4E3, + 0x0008A9, 0x00A3CD, 0x00A4E1, 0x00A4E6, 0x00A3CA, 0x00A3C9, 0x00A4E0, 0x00A3C8, + 0x00A3CF, 0x00A4E7, 0x00A4F1, 0x00A4F3, 0x00A4F0, 0x00A4F2, 0x00A438, 0x00A4F7, + 0x00A43B, 0x00A4F6, 0x00A464, 0x000804, 0x00A423, 0x000811, 0x000805, 0x00A43C, + 0x00080A, 0x00A46B, 0x00A58A, 0x00A516, 0x00A517, 0x000809, 0x000812, 0x00A589, + 0x00080D, 0x00A511, 0x00A50A, 0x00A508, 0x00A503, 0x000813, 0x00A504, 0x00A509, + 0x000808, 0x00A502, 0x00080F, 0x00A510, 0x00A513, 0x00A512, 0x00A51C, 0x00A51D, + 0x014503, 0x014500, 0x00A519, 0x00A518, 0x00080C, 0x00A51A, 0x014517, 0x000B6C, + 0x00A51F, 0x01450B, 0x00A539, 0x00A53F, 0x00A501, 0x00A538, 0x00080E, 0x014519, + 0x014518, 0x01451D, 0x01453F, 0x000810, 0x00A588, 0x01450A, 0x00A53A, 0x00A6E6, + 0x00A506, 0x00A58F, 0x014507, 0x01452B, 0x00A533, 0x00A532, 0x000815, 0x00A537, + 0x00A534, 0x00A535, 0x0008B6, 0x0008B7, 0x0008B0, 0x0008B1, 0x000854, 0x000864, + 0x00A522, 0x00A53B, 0x00A54A, 0x00A54B, 0x00A540, 0x0008B4, 0x0008B2, 0x0008B3, + 0x00A549, 0x00A576, 0x000AA2, 0x014535, 0x000857, 0x000851, 0x014506, 0x00A562, + 0x00A563, 0x000B6D, 0x00A57C, 0x000850, 0x00A557, 0x00A6E7, 0x014522, 0x000814, + 0x000861, 0x00A551, 0x00A572, 0x00A573, 0x00A57A, 0x00A57B, 0x00A578, 0x00A579, + 0x00A57D, 0x00A556, 0x00A568, 0x00A56D, 0x0008A3, 0x00A56C, 0x00A565, 0x00A564, + 0x00A56E, 0x0008B8, 0x00A521, 0x00A548, 0x00A56B, 0x00A54F, 0x00A56F, 0x00A520, + 0x00A56A, 0x00A569, 0x000860, 0x000856, 0x0008B9, 0x000865, 0x00A53C, 0x00086A, + 0x00A526, 0x00A527, 0x0145EE, 0x00A53D, 0x000A9C, 0x00A58E, 0x00090E, 0x00090F, + 0x00A53E, 0x00A54E, 0x01453C, 0x014523, 0x01453E, 0x01453D, 0x000908, 0x000909, + 0x000911, 0x000917, 0x000913, 0x000912, 0x000910, 0x00091A, 0x000915, 0x00091B, + 0x00A616, 0x0144DB, 0x01449E, 0x00A894, 0x000914, 0x00090D, 0x000916, 0x00090C, + 0x01456C, 0x0008AC, 0x00A97A, 0x0144EF, 0x0008AE, 0x0008A4, 0x000936, 0x000937, + 0x0008A8, 0x0008AD, 0x00A421, 0x00A585, 0x00A422, 0x00A427, 0x0008AF, 0x00A976, + 0x000931, 0x000930, 0x014488, 0x00A974, 0x00A420, 0x00A426, 0x00A944, 0x00A975, + 0x00A584, 0x000932, 0x0144BE, 0x000933, 0x0144BF, 0x00A977, 0x00A58B, 0x00A970, + 0x00A96B, 0x01448B, 0x01452E, 0x01452F, 0x0144F7, 0x014410, 0x01456E, 0x014564, + 0x000958, 0x00A43E, 0x01456F, 0x01457F, 0x00095C, 0x00095D, 0x00095E, 0x00095F, + 0x0144D8, 0x00A972, 0x00A971, 0x01456D, 0x014552, 0x00A97B, 0x000959, 0x014553, + 0x014545, 0x01454E, 0x014544, 0x01454F, 0x01454C, 0x014549, 0x014548, 0x01454B, + 0x01454A, 0x01454D, 0x00096E, 0x00096C, 0x0009EE, 0x00096D, 0x00096F, 0x0009EF, + 0x0009EC, 0x0009ED, 0x00A5E8, 0x00A5E5, 0x00A566, 0x00A567, 0x000968, 0x000969, + 0x00A5EE, 0x00A5EF, 0x00A5E9, 0x00A561, 0x00A560, 0x014570, 0x00A5ED, 0x00A5EC, + 0x00A5EA, 0x000978, 0x014563, 0x000979, 0x00097E, 0x00097C, 0x00097F, 0x00097D, + 0x000989, 0x000980, 0x00098A, 0x00098B, 0x000985, 0x000988, 0x000987, 0x000986, + 0x00099D, 0x00099F, 0x00A601, 0x00099C, 0x00A603, 0x00A602, 0x00A605, 0x00A604, + 0x00A607, 0x00A606, 0x00A609, 0x00A608, 0x000990, 0x00A60A, 0x000997, 0x000993, + 0x000999, 0x000998, 0x00099B, 0x00099A, 0x000994, 0x000995, 0x000996, 0x00099E, + 0x0009A2, 0x0009A3, 0x00A619, 0x00A618, 0x00098C, 0x0009A1, 0x00A61D, 0x00A61C, + 0x00A61F, 0x00A5B5, 0x00A621, 0x00A620, 0x00098F, 0x00A622, 0x00A2E2, 0x00A2E3, + 0x00A627, 0x00A626, 0x0009B0, 0x0009B7, 0x0009A8, 0x00A62A, 0x0009A0, 0x0009B6, + 0x0009B9, 0x0009B8, 0x0009B2, 0x0009A5, 0x00A2E7, 0x0009A6, 0x0009A7, 0x0009BD, + 0x0009E0, 0x0009E1, 0x0009E6, 0x0009E7, 0x0009E9, 0x0009F4, 0x0009EA, 0x0009E8, + 0x0009EB, 0x00A2E6, 0x00A2C0, 0x00A2C1, 0x0009CE, 0x0009FC, 0x00A2E0, 0x00A2E1, + 0x00A2C7, 0x0009F5, 0x0009F8, 0x0009F9, 0x00A2CC, 0x0009DC, 0x00A2CD, 0x0009F6, + 0x0009DD, 0x0009DF, 0x00A2D0, 0x00A2D1, 0x00A2D2, 0x00A2F2, 0x00A2F0, 0x00A2F1, + 0x00A2D6, 0x00A2D7, 0x0009AA, 0x0009AE, 0x0009A4, 0x00A2F6, 0x0009AF, 0x00A2F7, + 0x00A2CE, 0x00A2CF, 0x00A661, 0x00A660, 0x00A663, 0x00A662, 0x00A665, 0x0009AB, + 0x00A667, 0x00A666, 0x00A669, 0x00A668, 0x00A2F3, 0x00A66A, 0x00A66D, 0x00A66C, + 0x0009F7, 0x00A66E, 0x0009F0, 0x0009F1, 0x0009AC, 0x0009AD, 0x00A2F4, 0x00A2F5, + 0x00A2FE, 0x000B6F, 0x00A2F8, 0x00A2F9, 0x000A05, 0x00A2FF, 0x000A07, 0x000A06, + 0x00A2FC, 0x00A2FD, 0x00A692, 0x000A0A, 0x00A693, 0x00A2FB, 0x00A697, 0x00A2FA, + 0x00A6EA, 0x000A10, 0x000A13, 0x00A2A1, 0x00A2A2, 0x000A14, 0x000A17, 0x000A16, + 0x000A19, 0x000A18, 0x000A1B, 0x000A1A, 0x000A1D, 0x000A1C, 0x000A1F, 0x000A1E, + 0x00A290, 0x00A296, 0x00A2A0, 0x00A2D3, 0x00A2A6, 0x00A2A7, 0x00A2BC, 0x00A2BD, + 0x00A2BE, 0x000A28, 0x00A2C9, 0x00A2B4, 0x000A2D, 0x000A2C, 0x000A2F, 0x000A2E, + 0x000A33, 0x000A30, 0x00A2BA, 0x00A2BF, 0x000A35, 0x00A2BB, 0x000A32, 0x000A36, + 0x00A2B8, 0x000A38, 0x00A685, 0x00A2A3, 0x00A6BB, 0x00A6ED, 0x00A2C4, 0x00A2C5, + 0x00A6B5, 0x00A68A, 0x00A2C8, 0x00A684, 0x00A699, 0x00A2CB, 0x00A691, 0x00A698, + 0x00A690, 0x00A2CA, 0x00A682, 0x00A683, 0x00A6E9, 0x000A99, 0x00A6BD, 0x00A686, + 0x00A6BC, 0x00A613, 0x00A688, 0x00A689, 0x00A6CB, 0x00A68F, 0x00A6A0, 0x00A681, + 0x000A59, 0x0144DF, 0x000A5B, 0x000A5A, 0x00A6A2, 0x000A5C, 0x00A696, 0x000A5E, + 0x00A6E5, 0x000A98, 0x00A6EB, 0x00A6A6, 0x000B5F, 0x00A6A7, 0x000A67, 0x000A66, + 0x000A69, 0x000A68, 0x000A6B, 0x000A6A, 0x000A6D, 0x00A2A4, 0x000A6F, 0x000A6E, + 0x00A2AE, 0x0144D5, 0x00A2AA, 0x00A2A8, 0x00A6A1, 0x00A612, 0x00A2AC, 0x00A2AD, + 0x00A2AF, 0x014529, 0x00A6B8, 0x00A6B7, 0x00A6B2, 0x00A6B3, 0x00A6B4, 0x014524, + 0x00A6BE, 0x00A6BF, 0x0144D4, 0x00A6BA, 0x000A85, 0x00A6B9, 0x000A87, 0x000A86, + 0x000A89, 0x000A88, 0x000A8B, 0x000A8A, 0x000A8D, 0x000A8C, 0x000A8F, 0x00A7A8, + 0x00A722, 0x00A783, 0x00A217, 0x014565, 0x00A6CE, 0x00A212, 0x00A600, 0x000B68, + 0x014521, 0x00A6CF, 0x00A617, 0x00A61E, 0x00A782, 0x000B69, 0x00A781, 0x014520, + 0x000A93, 0x00A6E3, 0x000A91, 0x00A79E, 0x00A787, 0x00A611, 0x00A79F, 0x00A6E2, + 0x00A79C, 0x000AA8, 0x00A780, 0x00A7AA, 0x000AAD, 0x000AAC, 0x000AAF, 0x000AAE, + 0x000B74, 0x000AB0, 0x000AB3, 0x000AB2, 0x00A7A9, 0x000B75, 0x000AB7, 0x000AB6, + 0x00A786, 0x00A7AB, 0x00A21A, 0x00A610, 0x000A97, 0x00A732, 0x00A73E, 0x00A219, + 0x00A735, 0x00A733, 0x00A202, 0x00A203, 0x00A72A, 0x000A9B, 0x00A7AE, 0x00A216, + 0x00A73C, 0x00A723, 0x00A625, 0x00A74B, 0x00A6C5, 0x00A762, 0x00A6C8, 0x00A767, + 0x000B5C, 0x000AD0, 0x00A761, 0x00A6C4, 0x000AAB, 0x00A6C9, 0x00A744, 0x00A760, + 0x00A21E, 0x00A21F, 0x00A6E0, 0x000D93, 0x000B5D, 0x0144C5, 0x000B6E, 0x01448A, + 0x00A6D7, 0x00A766, 0x00A218, 0x00A74A, 0x00A6D6, 0x00A624, 0x00A653, 0x00A7FE, + 0x000AE9, 0x000AE8, 0x00A7FA, 0x00A76F, 0x000AED, 0x000AEC, 0x000AEF, 0x000AEE, + 0x00A765, 0x00A7FF, 0x00A769, 0x00A7FC, 0x000B73, 0x000B77, 0x00A76D, 0x00A768, + 0x00A76C, 0x00A76A, 0x000B76, 0x0144DA, 0x000A90, 0x000AB9, 0x00A77C, 0x000B72, + 0x00A76E, 0x00A763, 0x00A779, 0x00A6E8, 0x00A7FB, 0x00A778, 0x000B33, 0x000A96, + 0x000B19, 0x00A77D, 0x000B18, 0x00A623, 0x000B14, 0x000B30, 0x000B1D, 0x000B32, + 0x000B13, 0x00A79B, 0x00A795, 0x000B16, 0x00A794, 0x000B10, 0x000B17, 0x00A60B, + 0x000B1A, 0x00A6E1, 0x000B1B, 0x000B15, 0x01441D, 0x00A3CB, 0x00A8A5, 0x00A88D, + 0x000B23, 0x00A887, 0x000AB5, 0x000B06, 0x000B07, 0x014412, 0x014413, 0x01441E, + 0x000B21, 0x00A3A1, 0x014581, 0x0145B5, 0x000DEB, 0x01441F, 0x014403, 0x01459D, + 0x000B1E, 0x014417, 0x000B1F, 0x014411, 0x00A799, 0x014424, 0x014464, 0x014422, + 0x014420, 0x014421, 0x014425, 0x014428, 0x014426, 0x014468, 0x014427, 0x01442A, + 0x01442B, 0x014429, 0x000B2E, 0x000B0F, 0x014416, 0x014418, 0x01443B, 0x014414, + 0x00A79D, 0x014415, 0x000B08, 0x000B09, 0x01446C, 0x00A7A5, 0x01441C, 0x000B0C, + 0x000B2A, 0x000B2D, 0x000B2B, 0x000B2C, 0x00A2EE, 0x014405, 0x00A2EF, 0x00A3AC, + 0x000B28, 0x014401, 0x014402, 0x014406, 0x014400, 0x00A798, 0x000B1C, 0x00A79A, + 0x01444D, 0x01446A, 0x000B22, 0x000B20, 0x000B2F, 0x000B27, 0x014449, 0x00A6EC, + 0x014404, 0x00A7A4, 0x00A641, 0x014477, 0x000B24, 0x000B25, 0x000B26, 0x00A6EE, + 0x000B71, 0x000B35, 0x014444, 0x00A6EF, 0x00A6D1, 0x00A3A2, 0x000B36, 0x000B37, + 0x000B38, 0x000B39, 0x00A2ED, 0x000B3D, 0x00A2EA, 0x00A2EC, 0x014448, 0x00A2E5, + 0x00A2E4, 0x00A2E8, 0x00A3A0, 0x00A2E9, 0x014438, 0x014439, 0x014434, 0x01443A, + 0x00A2EB, 0x014435, 0x014469, 0x01446B, 0x000BA8, 0x000CB9, 0x0145DB, 0x000AA3, + 0x014465, 0x00A99E, 0x00A817, 0x000A95, 0x00A813, 0x000A9F, 0x01448D, 0x00A811, + 0x014496, 0x014484, 0x000A9D, 0x014485, 0x014489, 0x014510, 0x01448F, 0x000A94, + 0x000BA3, 0x014499, 0x01449F, 0x01448E, 0x01449B, 0x014493, 0x014497, 0x014483, + 0x000BAA, 0x014494, 0x01459A, 0x000A9A, 0x014492, 0x01449C, 0x000BA4, 0x014491, + 0x01448C, 0x014495, 0x01449D, 0x014590, 0x0145B6, 0x000BA9, 0x0144BB, 0x01458F, + 0x0144B6, 0x000BB8, 0x014482, 0x0144B2, 0x000AAA, 0x000BB9, 0x0145A5, 0x000A9E, + 0x000BD0, 0x00A810, 0x00AB9A, 0x000BEE, 0x0144B1, 0x0144B3, 0x000BEF, 0x0144B7, + 0x014481, 0x000BE8, 0x014486, 0x014487, 0x014498, 0x014480, 0x00A86E, 0x000BED, + 0x0144B0, 0x0144B5, 0x00A91E, 0x01449A, 0x0144E0, 0x0145BE, 0x0144E6, 0x00A86F, + 0x00A81A, 0x0144E7, 0x0144E8, 0x0144E9, 0x0144EB, 0x000BEC, 0x00A812, 0x00A844, + 0x0144EA, 0x00A816, 0x000BEA, 0x000BF0, 0x00A84B, 0x000BE6, 0x000BE7, 0x00A869, + 0x00A868, 0x000BEB, 0x0144FE, 0x0144FF, 0x00A863, 0x00A862, 0x0145BF, 0x00A86A, + 0x00A864, 0x00A865, 0x00A860, 0x00A861, 0x0144E3, 0x00A867, 0x0144E5, 0x0144E2, + 0x00A866, 0x0144E4, 0x000BF2, 0x000BF1, 0x00A86C, 0x000BE9, 0x00A86D, 0x0144E1, + 0x0144FC, 0x000C1E, 0x000C1B, 0x000C1C, 0x000C1A, 0x0144F5, 0x0144F3, 0x0144F2, + 0x0144B4, 0x0144F4, 0x0144F8, 0x0144F6, 0x0144F9, 0x00A885, 0x0144BA, 0x0144FA, + 0x000C12, 0x000C13, 0x0144FB, 0x00A884, 0x014501, 0x000C18, 0x000C1F, 0x014502, + 0x000C19, 0x014504, 0x00A889, 0x00A89F, 0x000C1D, 0x00A892, 0x00A893, 0x000C10, + 0x000C16, 0x00A89D, 0x00A899, 0x000C17, 0x014511, 0x00A898, 0x014513, 0x014512, + 0x00A88B, 0x000C07, 0x00A8AD, 0x014516, 0x00A8AC, 0x00A883, 0x01451E, 0x00A882, + 0x01451F, 0x01451C, 0x00A8A1, 0x00A8A8, 0x00A8AE, 0x00A8AF, 0x00A88A, 0x000C15, + 0x014525, 0x00A886, 0x014527, 0x014526, 0x00A891, 0x014528, 0x000C14, 0x01452A, + 0x00A890, 0x000C59, 0x00A896, 0x00A897, 0x00A89C, 0x000C05, 0x000C06, 0x000C09, + 0x000C08, 0x014534, 0x000C0A, 0x000C0B, 0x014539, 0x014538, 0x01453B, 0x01453A, + 0x00A88E, 0x000C34, 0x000C24, 0x000C21, 0x000C0C, 0x00A88F, 0x00A888, 0x00A88C, + 0x000C5A, 0x000C2A, 0x00A8D3, 0x00A8D0, 0x000C0E, 0x00A8D7, 0x00A8F6, 0x000C0F, + 0x00A8D1, 0x00A8D2, 0x000C22, 0x00A8D6, 0x000C36, 0x000C23, 0x000C79, 0x00A8FD, + 0x000C20, 0x000C31, 0x000C30, 0x000C38, 0x00A8B2, 0x00A8A3, 0x00A8A2, 0x000C35, + 0x000C32, 0x000C33, 0x00A8F2, 0x00A8A0, 0x014561, 0x014560, 0x00A8F7, 0x014562, + 0x00A8A6, 0x00A8A7, 0x014567, 0x014566, 0x014569, 0x014568, 0x01456B, 0x01456A, + 0x000C99, 0x00A8B3, 0x000C9D, 0x000C9F, 0x00A8FB, 0x000C37, 0x014573, 0x014572, + 0x014575, 0x014574, 0x014577, 0x014576, 0x014579, 0x00A902, 0x01457B, 0x01457A, + 0x01457D, 0x01457C, 0x00A90B, 0x01457E, 0x00A901, 0x00A903, 0x014583, 0x014582, + 0x00A91C, 0x00A90A, 0x00A911, 0x00A910, 0x00A918, 0x00A907, 0x00A905, 0x00A91F, + 0x00A917, 0x00A916, 0x00A91D, 0x00A909, 0x014591, 0x00A919, 0x014593, 0x014592, + 0x014595, 0x014594, 0x014597, 0x014596, 0x014599, 0x014598, 0x01459B, 0x00A900, + 0x00A906, 0x01459C, 0x01459F, 0x01459E, 0x00A93A, 0x00A923, 0x00A908, 0x00A938, + 0x00A93C, 0x000C9E, 0x00A935, 0x00A933, 0x00A93E, 0x00A932, 0x00A93B, 0x00A934, + 0x00A937, 0x00A90E, 0x00A921, 0x00A93D, 0x00A90F, 0x00A939, 0x00A90C, 0x00A90D, + 0x00A93F, 0x0145B4, 0x000C25, 0x000C28, 0x0145B9, 0x0145B8, 0x0145BB, 0x0145BA, + 0x000C26, 0x0145BC, 0x00A96C, 0x000C27, 0x000C80, 0x014585, 0x00A964, 0x00A965, + 0x00A96E, 0x00A96D, 0x014490, 0x000C3D, 0x0145B7, 0x000C9C, 0x000C98, 0x000C7A, + 0x000CF1, 0x000CED, 0x000C2B, 0x000CF2, 0x000CEC, 0x000C39, 0x000CEE, 0x000CEF, + 0x000CE9, 0x000CE8, 0x00A920, 0x00A960, 0x00A922, 0x00A962, 0x00A961, 0x00A96F, + 0x00A967, 0x00A963, 0x00A966, 0x00A968, 0x00A969, 0x0145E0, 0x0145E3, 0x0145E2, + 0x0145E5, 0x0145E4, 0x0145E7, 0x0145E6, 0x0145E9, 0x0145E8, 0x0145EB, 0x0145EA, + 0x000D10, 0x000D0B, 0x00A979, 0x00A978, 0x00A96A, 0x000D06, 0x000D07, 0x00A97C, + 0x0145F5, 0x0145F4, 0x00A984, 0x000D05, 0x0145F9, 0x0145F8, 0x0145FB, 0x0145FA, + 0x00A985, 0x0145FC, 0x0145FF, 0x00A988, 0x000D17, 0x00A98A, 0x000D30, 0x000D16, + 0x00A98F, 0x000D18, 0x00A991, 0x00A990, 0x00A993, 0x00A992, 0x000D19, 0x000D15, + 0x00A997, 0x00A996, 0x00A999, 0x00A998, 0x000D31, 0x000D0C, 0x000D2F, 0x00A99C, + 0x00A99F, 0x000D09, 0x00A9A1, 0x00A9A0, 0x000D0A, 0x00A9A2, 0x000D37, 0x000D08, + 0x00A9A7, 0x00A9A6, 0x000D1C, 0x000D1D, 0x000D14, 0x000D33, 0x00A9AD, 0x00A9AC, + 0x000D1E, 0x000D1B, 0x000D12, 0x000D13, 0x000D1F, 0x00A9B2, 0x000D1A, 0x000D32, + 0x01463F, 0x014635, 0x014636, 0x014637, 0x014633, 0x01461C, 0x01460C, 0x01460D, + 0x000C7B, 0x000C7C, 0x01460F, 0x000D6B, 0x000C2C, 0x01461D, 0x01461E, 0x01461F, + 0x000D54, 0x000D55, 0x000C58, 0x000D5C, 0x000D5A, 0x00F933, 0x000D5B, 0x000D56, + 0x000D5F, 0x000D5D, 0x000D59, 0x00A9D0, 0x00A9D3, 0x000D58, 0x000D7C, 0x000D5E, + 0x000D61, 0x00A9D6, 0x000D78, 0x000C2F, 0x000D2C, 0x000D2D, 0x000D7D, 0x000D2E, + 0x000D38, 0x000D29, 0x00A9E1, 0x00A9E0, 0x00A9E3, 0x00A9E2, 0x000D28, 0x00A9E4, + 0x00A9E7, 0x000D35, 0x000D36, 0x00A9E8, 0x00A9EB, 0x00A9EA, 0x00A9ED, 0x00A9EC, + 0x00A9EF, 0x00A9EE, 0x01463B, 0x000D3A, 0x000D34, 0x000D39, 0x000C2E, 0x000C2D, + 0x000DB5, 0x000D89, 0x00A9F9, 0x00A9F8, 0x000D8F, 0x000D87, 0x00A9FD, 0x00A9FC, + 0x00F90A, 0x000D88, 0x000DBA, 0x000DBB, 0x000D86, 0x000DB4, 0x000D8B, 0x000D85, + 0x000D91, 0x000D90, 0x000DB6, 0x000D92, 0x000D95, 0x000D94, 0x00A205, 0x000D96, + 0x000D8A, 0x000D8D, 0x000D9B, 0x000D9A, 0x000D9D, 0x000D9C, 0x000D9F, 0x000D9E, + 0x00A201, 0x000DA9, 0x000DB3, 0x000DA2, 0x000DA5, 0x000DA7, 0x000DA3, 0x000DB7, + 0x000DA4, 0x00A21C, 0x00AAA0, 0x000D8E, 0x000D8C, 0x00AAA2, 0x000DA1, 0x000DAB, + 0x000DA0, 0x00AAA7, 0x000DB1, 0x000DA6, 0x00AAAB, 0x000DB0, 0x000DAF, 0x00AAA6, + 0x000DAA, 0x000DB8, 0x00A200, 0x000DB9, 0x000DBD, 0x00AA6E, 0x00AAA4, 0x00AAAE, + 0x00AAAF, 0x01463C, 0x01463E, 0x000C6E, 0x000C6F, 0x00AAAA, 0x00AAAD, 0x014638, + 0x00A207, 0x014634, 0x014627, 0x00AA69, 0x014621, 0x014639, 0x01463A, 0x014620, + 0x01463D, 0x01462D, 0x00F9E3, 0x00F90C, 0x00ABE1, 0x00AADB, 0x00F90F, 0x00ABE0, + 0x00AA56, 0x00AA6F, 0x00AA6C, 0x00AA6D, 0x00F90D, 0x00AA68, 0x00AA55, 0x00F93D, + 0x000C68, 0x00AA54, 0x000DEC, 0x000C66, 0x00F93E, 0x000C67, 0x000DE7, 0x000DE6, + 0x000DA8, 0x000DE8, 0x000DEF, 0x000DEA, 0x000DED, 0x000DE9, 0x000DAE, 0x000DEE, + 0x000C78, 0x00AA65, 0x00AAA8, 0x00AAA9, 0x00ABE2, 0x000C7D, 0x014622, 0x014623, + 0x00AA64, 0x00AA6B, 0x00ABF0, 0x00AA6A, 0x00F9FD, 0x00F9FC, 0x000C7E, 0x00F935, + 0x00AAAC, 0x00F9FE, 0x00A204, 0x00F936, 0x00ABF2, 0x00ABF9, 0x00F93F, 0x00ABF8, + 0x00A206, 0x00ABF7, 0x00A20E, 0x000E10, 0x00A20F, 0x00A23A, 0x00AABA, 0x00AABB, + 0x014626, 0x000E13, 0x00A208, 0x00A209, 0x00A20A, 0x000E11, 0x00AAB5, 0x00A20D, + 0x000E12, 0x0006A0, 0x00A230, 0x00A221, 0x0006BC, 0x0006BD, 0x0006BE, 0x0006AF, + 0x00A236, 0x00A237, 0x0006A3, 0x0006A1, 0x00A20C, 0x0006D2, 0x000E1A, 0x000E1B, + 0x0006A2, 0x00063B, 0x00AA84, 0x00AA85, 0x0006BA, 0x000E16, 0x00AABC, 0x00AABD, + 0x0006B0, 0x00AA8A, 0x0006B8, 0x0006BF, 0x00F9EF, 0x000E15, 0x0006B6, 0x0006B7, + 0x0006B5, 0x00AA8B, 0x0006B4, 0x0006BB, 0x0006D3, 0x0006B9, 0x00A235, 0x000E17, + 0x00AAA5, 0x00A233, 0x00A232, 0x00A23B, 0x00AAB9, 0x00AAA3, 0x0006AC, 0x00A231, + 0x00A234, 0x000E14, 0x0006C1, 0x00A254, 0x0006C7, 0x00ABF6, 0x0006C0, 0x00A255, + 0x00ABA6, 0x00F9F6, 0x00F9F5, 0x0006C3, 0x00A225, 0x0006C5, 0x00A226, 0x0006C2, + 0x000638, 0x00A25F, 0x00A25B, 0x00A241, 0x00A259, 0x00A224, 0x00A25A, 0x0006CF, + 0x0006A8, 0x0006A5, 0x00ABD2, 0x00F9C8, 0x0006A6, 0x0006AB, 0x00F908, 0x0006A7, + 0x0006AE, 0x0006A9, 0x00F9F4, 0x00F9FF, 0x0006A4, 0x00A223, 0x000639, 0x0006C6, + 0x00A220, 0x0006C4, 0x00A23C, 0x0006CE, 0x00A222, 0x00A25E, 0x00063A, 0x00ABA1, + 0x0006AD, 0x00F9CC, 0x00ABA0, 0x00A258, 0x00A227, 0x00A23D, 0x0006AA, 0x00ABA7, + 0x00A23E, 0x000647, 0x00F9FA, 0x00A239, 0x00A238, 0x00A23F, 0x00AAA1, 0x00A240, + 0x00ABCD, 0x00068A, 0x000646, 0x000645, 0x00AB03, 0x00AB02, 0x00AB06, 0x00062E, + 0x00F943, 0x000672, 0x00A248, 0x00A249, 0x00A24E, 0x000644, 0x00A24C, 0x00A24D, + 0x00068F, 0x00A24F, 0x000649, 0x000671, 0x000648, 0x00067A, 0x00067B, 0x000675, + 0x000620, 0x000621, 0x000622, 0x00062F, 0x000625, 0x00062B, 0x000626, 0x000627, + 0x00F958, 0x000629, 0x000628, 0x00A261, 0x00A260, 0x00F95F, 0x00062D, 0x000624, + 0x00062A, 0x000673, 0x00A22A, 0x00A22B, 0x00068D, 0x00063D, 0x00063C, 0x00062C, + 0x00063E, 0x00A22F, 0x0006B3, 0x00A271, 0x00A272, 0x00A273, 0x00068E, 0x00063F, + 0x00A276, 0x000EC2, 0x000EC3, 0x00F9C6, 0x000EDC, 0x00AB89, 0x000641, 0x000643, + 0x000642, 0x00064A, 0x00A245, 0x00ABA2, 0x00A242, 0x00A243, 0x0006B2, 0x00F9C2, + 0x00F9AB, 0x00F9F0, 0x00F9C1, 0x00A25C, 0x00A247, 0x00F9A4, 0x00A25D, 0x00ABB9, + 0x00ABB8, 0x00F9F9, 0x00ABBF, 0x00ABB7, 0x00F9FB, 0x00F9DE, 0x00F9DD, 0x00F981, + 0x00F980, 0x00F9A6, 0x00F9A5, 0x00F9D4, 0x00F9D5, 0x00F9D8, 0x00F9C5, 0x00F9C0, + 0x00F9D9, 0x00F9DA, 0x00F9C3, 0x00F9CF, 0x00F9C7, 0x00F9C4, 0x00F9DF, 0x00F9A2, + 0x00A246, 0x00F9AF, 0x00F9A1, 0x00ABCC, 0x00068C, 0x00A244, 0x00F9AE, 0x00F9A7, + 0x00F9A8, 0x00ABB3, 0x00F9A3, 0x00F909, 0x00F9AC, 0x00F9CB, 0x00ABBD, 0x00F9BC, + 0x00F9F1, 0x00F9AD, 0x00F9AA, 0x00F9F2, 0x00F9BD, 0x00F9BE, 0x00F9A9, 0x00A24A, + 0x00F9B8, 0x00A24B, 0x00A805, 0x00A995, 0x0145EC, 0x00F9BF, 0x00F9F7, 0x0145EF, + 0x0145ED, 0x000CB0, 0x01458E, 0x00AB96, 0x00A99B, 0x000F31, 0x000F32, 0x000F33, + 0x00A99A, 0x00AB90, 0x000F23, 0x00F9D3, 0x00AB93, 0x000F30, 0x000F20, 0x000F21, + 0x00AB97, 0x0144C9, 0x00AB91, 0x0144CA, 0x000F27, 0x000C87, 0x000C85, 0x0144CE, + 0x000C8B, 0x00AB92, 0x00A801, 0x0144CF, 0x000C86, 0x00A858, 0x000C8F, 0x0144C8, + 0x00A85E, 0x000F29, 0x000F2A, 0x000F2B, 0x0144FD, 0x00A80A, 0x000CB3, 0x00A81C, + 0x00ABAC, 0x000C89, 0x00F9E9, 0x000C8A, 0x00A818, 0x00A803, 0x00A85B, 0x00F9E8, + 0x000F53, 0x00AB99, 0x0144CC, 0x000CB7, 0x000664, 0x00A819, 0x00A81F, 0x00F9D6, + 0x00A81D, 0x000CB6, 0x0144DE, 0x00A800, 0x00AB82, 0x00A871, 0x00066E, 0x000C8E, + 0x00AB84, 0x00AB85, 0x00ABBE, 0x00ABBB, 0x00A854, 0x00ABD3, 0x00A856, 0x00AB83, + 0x00F993, 0x00ABBC, 0x00AB8A, 0x00AB81, 0x00AB80, 0x00AB8B, 0x00F991, 0x00AB8F, + 0x000662, 0x000661, 0x00AB98, 0x000663, 0x00AB88, 0x000660, 0x00AB9C, 0x00AB9D, + 0x00AB86, 0x00AB9F, 0x000669, 0x00ABB2, 0x000668, 0x000665, 0x000667, 0x00066F, + 0x00067D, 0x000674, 0x000F2F, 0x00067C, 0x000676, 0x00AB8E, 0x00ABF3, 0x000677, + 0x000678, 0x000679, 0x00067E, 0x000666, 0x00ABBA, 0x00ABB5, 0x00ABB4, 0x00067F, + 0x000F5A, 0x00A808, 0x00A85A, 0x00A855, 0x00F997, 0x0144C4, 0x0144CB, 0x00A809, + 0x000F89, 0x000F88, 0x000E18, 0x00F98E, 0x00FBAF, 0x00F992, 0x000F8C, 0x000E04, + 0x00FBD5, 0x0144CD, 0x000E06, 0x00FBD6, 0x000E24, 0x000E07, 0x000F56, 0x000F57, + 0x00FBAC, 0x00FBE2, 0x00FBFB, 0x00A859, 0x00FBAD, 0x000E1C, 0x000E2C, 0x00FBDB, + 0x00FBE3, 0x00FBD3, 0x00FB72, 0x00FBE0, 0x00FB49, 0x000E05, 0x00FB70, 0x000F2C, + 0x00FB5C, 0x000F28, 0x00A842, 0x00A841, 0x0006EE, 0x000F2D, 0x000F2E, 0x0006EF, + 0x0006F4, 0x00FBDA, 0x00F99B, 0x000E0B, 0x00FBA8, 0x0006F5, 0x0006F6, 0x0006F7, + 0x0006F8, 0x0006F9, 0x0006FA, 0x0006FB, 0x0006FC, 0x00F995, 0x00A85F, 0x0006FF, + 0x0006CD, 0x000F50, 0x000F52, 0x00FBD4, 0x00F9D7, 0x0006F1, 0x00A85D, 0x0006F0, + 0x0006C8, 0x0006C9, 0x000F5B, 0x00FBAE, 0x000F55, 0x000E1F, 0x00F990, 0x000F54, + 0x000F51, 0x000F41, 0x0006D0, 0x0006D1, 0x000E19, 0x0006D5, 0x0011CD, 0x00FB90, + 0x000EC0, 0x000EC1, 0x0006CB, 0x0011C9, 0x0011CF, 0x0006F2, 0x00FB97, 0x0006CA, + 0x000CE0, 0x000CE1, 0x000EC4, 0x000C61, 0x000C60, 0x000E51, 0x000CE6, 0x000CE7, + 0x000C6A, 0x000C6B, 0x000CEA, 0x000CEB, 0x0006CC, 0x000C69, 0x000C6C, 0x000C6D, + 0x00F923, 0x000E40, 0x0011FF, 0x0011F9, 0x0011F4, 0x00FB17, 0x0006F3, 0x00FB14, + 0x000E1D, 0x000E45, 0x0011FA, 0x000E53, 0x0011FE, 0x0011FB, 0x000E1E, 0x00F9B0, + 0x00FAC7, 0x00F930, 0x00F937, 0x00FD82, 0x00F9B5, 0x00F9B6, 0x00F9B7, 0x00F93A, + 0x00F9B9, 0x00F9BA, 0x00F939, 0x00F938, 0x00FB9B, 0x00F93C, 0x0011F2, 0x00FB60, + 0x0011C8, 0x00FB64, 0x00FB68, 0x00FAA1, 0x00FB65, 0x00FB66, 0x0011C2, 0x00FB48, + 0x00FB6A, 0x00FB69, 0x00FB6B, 0x00FB4C, 0x00FB4D, 0x00FB4E, 0x00FB4F, 0x00FB6C, + 0x0011A4, 0x0011AE, 0x0011A2, 0x00FB6E, 0x0011A8, 0x0011A5, 0x0011A6, 0x0011A7, + 0x00FB6F, 0x0011A9, 0x0011AA, 0x0011AB, 0x0011AC, 0x0011AF, 0x00FB6D, 0x001114, + 0x0011DC, 0x00FD97, 0x00FB63, 0x00FB7C, 0x00FA5D, 0x0011AD, 0x00108E, 0x00FB61, + 0x0011B8, 0x0011B9, 0x00FB62, 0x00FDB1, 0x001116, 0x0011BD, 0x0011BE, 0x0011BF, + 0x00FB71, 0x00FB7D, 0x00FB7F, 0x00FB74, 0x00FB75, 0x00FB76, 0x0011C3, 0x00FB78, + 0x00FB79, 0x00FB7A, 0x00A5E0, 0x00FB7E, 0x00A840, 0x00A84F, 0x00FB7B, 0x00A843, + 0x00A846, 0x00A845, 0x00A849, 0x00A5C9, 0x00A5C8, 0x00A5CE, 0x00A848, 0x00A847, + 0x00A84E, 0x00A84A, 0x0011D3, 0x0011D2, 0x00A84C, 0x00A873, 0x00A872, 0x00A84D, + 0x0014B2, 0x0011DD, 0x00A85C, 0x00A870, 0x0014B3, 0x0011DF, 0x00FA92, 0x00FA82, + 0x00A5FE, 0x0011F3, 0x00A5E3, 0x00A5E1, 0x0011DE, 0x00148C, 0x0011D8, 0x00A5F8, + 0x00A5E2, 0x0011D1, 0x0011D9, 0x0011D5, 0x0011D4, 0x00A86B, 0x0011D6, 0x0011D7, + 0x0011DB, 0x0011DA, 0x00A5F9, 0x00A5F1, 0x00A5F2, 0x00A5F3, 0x00A5F0, 0x00A5F5, + 0x00A5F4, 0x00A5FF, 0x0011A3, 0x00A5F6, 0x00A5F7, 0x00A5FB, 0x0011A1, 0x00FB22, + 0x00118D, 0x00A5FA, 0x00AB21, 0x00A5A0, 0x00A986, 0x00A98E, 0x00A9A5, 0x00A987, + 0x00A989, 0x00A5C5, 0x00AB38, 0x00AB25, 0x00FA91, 0x00A98B, 0x00FA9F, 0x00AB0D, + 0x00AB0C, 0x00A5DE, 0x00A5C3, 0x00A5DF, 0x00AB36, 0x00AB37, 0x00A5D8, 0x00AB39, + 0x00A5C2, 0x00AB3F, 0x00A99D, 0x00AB3A, 0x00AB3D, 0x00A9B0, 0x0011BA, 0x00AB34, + 0x00AB3E, 0x00A5D9, 0x00A5A2, 0x00A5CB, 0x00AB33, 0x00A5A3, 0x00A5A7, 0x00A5CF, + 0x00A5BC, 0x00A5C4, 0x00A5CD, 0x00A9A3, 0x00AB31, 0x00A5CC, 0x00A98D, 0x00A5A1, + 0x00AB30, 0x00A9B1, 0x00AB35, 0x00A5B1, 0x00AB32, 0x00A5BD, 0x00A5B4, 0x00A5BE, + 0x00A5B0, 0x00AB3B, 0x00A5B8, 0x00A5B9, 0x00A5BA, 0x00A5BB, 0x00A5B6, 0x00A5A6, + 0x00A5BF, 0x00A5B7, 0x00A9A8, 0x0011C0, 0x00FA81, 0x00AB52, 0x00FA93, 0x00FB40, + 0x00AB51, 0x00FB44, 0x00A98C, 0x00FBA4, 0x00FA87, 0x00AB50, 0x00FB46, 0x00FB4A, + 0x00FB5D, 0x00FB67, 0x00FB93, 0x00A5D5, 0x00FB73, 0x00FBA6, 0x00FAA5, 0x00FAAB, + 0x00FB5E, 0x00FB91, 0x00FB92, 0x00AB53, 0x00FBA9, 0x00FBAA, 0x00A5DB, 0x00A9D1, + 0x00A5D4, 0x00A5DC, 0x00A9AA, 0x00FA97, 0x00A9A4, 0x00FBA5, 0x00FB77, 0x00FBA2, + 0x00FB21, 0x00FB20, 0x0011F0, 0x00FBA0, 0x00FB25, 0x00FB26, 0x00FB27, 0x00FB2A, + 0x00FB28, 0x00A9AB, 0x00FBA1, 0x00FB24, 0x00FB2F, 0x00FB2B, 0x00AA59, 0x0144EE, + 0x001180, 0x001183, 0x001182, 0x00FB2C, 0x001181, 0x00119D, 0x0011B2, 0x00A9A9, + 0x001185, 0x00AB57, 0x001187, 0x00FBA7, 0x00FB2D, 0x00FB2E, 0x00119E, 0x00119F, + 0x001190, 0x001194, 0x001192, 0x001191, 0x00FB4B, 0x00FB47, 0x001196, 0x001197, + 0x001199, 0x00119B, 0x001198, 0x00118C, 0x00119C, 0x001195, 0x00A994, 0x00FB52, + 0x00FB51, 0x00118B, 0x00FB53, 0x00FB43, 0x00FB50, 0x00148D, 0x00FB57, 0x001186, + 0x00FB54, 0x00A58D, 0x00FB56, 0x00AB22, 0x00AB28, 0x001184, 0x00AB24, 0x001188, + 0x00AB26, 0x0011B0, 0x00AB20, 0x00AB2B, 0x00AB2A, 0x00AB29, 0x00AB2C, 0x00AB2D, + 0x00AB2E, 0x00FB58, 0x0011B4, 0x001189, 0x00FB59, 0x0011D0, 0x00118A, 0x00FB5A, + 0x00118F, 0x00FB5B, 0x0011BC, 0x00FB55, 0x00FB41, 0x00FBAB, 0x001130, 0x00FB5F, + 0x0011A0, 0x00AB3C, 0x00A58C, 0x00AA40, 0x00AA41, 0x00AA42, 0x00AA4B, 0x00AA45, + 0x00F911, 0x00FB82, 0x00F917, 0x00F910, 0x00FB88, 0x00FB8E, 0x00AA44, 0x00F952, + 0x00FB81, 0x00AA47, 0x00118E, 0x00F916, 0x00A5B2, 0x00FB8F, 0x00FB80, 0x00FB85, + 0x00FB86, 0x00FB87, 0x00AA58, 0x00FB9C, 0x00FB95, 0x00F912, 0x00F913, 0x00AA48, + 0x00AA49, 0x00AA4A, 0x00AA66, 0x00FB9D, 0x00FB9E, 0x00FB9F, 0x00A5B3, 0x00F928, + 0x00AA74, 0x0011B1, 0x00FBB1, 0x0011B5, 0x00FBA3, 0x00F92E, 0x0011B7, 0x001112, + 0x00F941, 0x0011BB, 0x00F92F, 0x00F91A, 0x00F919, 0x00AA72, 0x00F91B, 0x00F942, + 0x00F946, 0x00F940, 0x00F951, 0x00AA71, 0x00F94B, 0x00F947, 0x00F915, 0x00FAD7, + 0x00AA73, 0x001193, 0x00AB01, 0x00F918, 0x00AB23, 0x00F914, 0x00AB16, 0x00FC41, + 0x00F953, 0x00FC43, 0x00FC42, 0x00F91D, 0x00FC44, 0x00FC47, 0x00F91C, 0x00FC49, + 0x00FC48, 0x00FC4B, 0x00FC4A, 0x00FC4D, 0x00FC4C, 0x00FC4F, 0x00F91F, 0x00F900, + 0x00AB12, 0x00F902, 0x00F903, 0x00AB11, 0x00F901, 0x00AB13, 0x00F907, 0x00F906, + 0x00F978, 0x00F90E, 0x00A628, 0x00A629, 0x00FC5C, 0x00F91E, 0x00F95E, 0x00FC61, + 0x00FC60, 0x00FC63, 0x00FC62, 0x00FC65, 0x00FC64, 0x00FC67, 0x00A62B, 0x00FC69, + 0x00FC68, 0x00FC6B, 0x00FC6A, 0x00FC6D, 0x00FC6C, 0x00FC6F, 0x00FC6E, 0x00FC71, + 0x00FC70, 0x00FC73, 0x00FC72, 0x00FC75, 0x00FC74, 0x00FC77, 0x00FC76, 0x00FC79, + 0x00FC78, 0x00FC7B, 0x00FC7A, 0x00FC7D, 0x00FC7C, 0x00FC7F, 0x00FC7E, 0x00A912, + 0x00A640, 0x00A64F, 0x00A914, 0x00A91B, 0x00A65E, 0x00A643, 0x00A915, 0x00A65C, + 0x00A65A, 0x00AB15, 0x00A658, 0x00A65F, 0x00A651, 0x00A652, 0x00A65D, 0x00A650, + 0x00A655, 0x00A657, 0x00A659, 0x00A64B, 0x00A642, 0x00A65B, 0x00A64A, 0x00A654, + 0x00A656, 0x00A645, 0x00A644, 0x00A664, 0x00A64E, 0x00A64C, 0x00A66B, 0x00A64D, + 0x00A646, 0x00A647, 0x00F905, 0x00F904, 0x00A649, 0x00ABCE, 0x00AB04, 0x00A648, + 0x00ABC8, 0x00ABCF, 0x00AB0E, 0x00A930, 0x00ABF4, 0x00F90B, 0x00ABF5, 0x00A895, + 0x00AB14, 0x00AB05, 0x00F932, 0x00AB0B, 0x00A91A, 0x00AB0A, 0x00F931, 0x00A940, + 0x00AB09, 0x00A973, 0x00FB96, 0x00ABC1, 0x00120D, 0x00120C, 0x00ABA4, 0x00ABA5, + 0x00F9E1, 0x00F9E2, 0x00F9EE, 0x00F9ED, 0x00ABAE, 0x00F9CD, 0x00AB8C, 0x00AB8D, + 0x00F9C9, 0x00F9CA, 0x00ABC4, 0x00F9CE, 0x00ABC2, 0x014419, 0x00F9EB, 0x00ABC5, + 0x00ABC6, 0x00ABC9, 0x01443F, 0x00ABC0, 0x00ABCA, 0x00ABCB, 0x00ABC7, 0x00ABAD, + 0x00AB9E, 0x00F9EA, 0x00F9DB, 0x00ABAA, 0x00F9EC, 0x00AA46, 0x00ABA8, 0x00ABF1, + 0x00ABA3, 0x001230, 0x001233, 0x014407, 0x001235, 0x001234, 0x001237, 0x001236, + 0x00F9E5, 0x001238, 0x00123B, 0x00F9E7, 0x00123D, 0x00ABB1, 0x00123F, 0x00123E, + 0x001241, 0x001240, 0x001243, 0x001242, 0x001245, 0x00ABB0, 0x001247, 0x001246, + 0x00ABB6, 0x00A89E, 0x00F9F3, 0x00124A, 0x00F9F8, 0x00ABD9, 0x00ABD4, 0x00F982, + 0x00F985, 0x00F987, 0x00F983, 0x00A9D9, 0x00A9D8, 0x00A943, 0x00F986, 0x00F984, + 0x00ABDA, 0x00ABDB, 0x00F98B, 0x00ABD5, 0x00ABD6, 0x00125C, 0x00A9D4, 0x00A9D5, + 0x001261, 0x00F98A, 0x001263, 0x001262, 0x001265, 0x00F99C, 0x00F989, 0x001266, + 0x001269, 0x00A945, 0x00126B, 0x00126A, 0x00F999, 0x00F998, 0x00F99D, 0x00F9A0, + 0x00ABD7, 0x00ABC3, 0x00ABDC, 0x00F98D, 0x00ABDE, 0x00ABDD, 0x00A9E9, 0x00F988, + 0x00F98F, 0x00A9FE, 0x00A9F2, 0x00A9F1, 0x00A9F3, 0x00127C, 0x00A9F6, 0x00ABDF, + 0x00A9F0, 0x00A9F7, 0x00A942, 0x00ABD0, 0x00ABD8, 0x00A9FB, 0x00ABD1, 0x00A9F5, + 0x00A9FA, 0x00A9F4, 0x00ABAB, 0x00ABA9, 0x00128D, 0x00128C, 0x00AB95, 0x00A9AE, + 0x00ABAF, 0x00A833, 0x00F9D2, 0x00A913, 0x00A9AF, 0x00F9D0, 0x00AB94, 0x00AB9B, + 0x00F9D1, 0x00F9DC, 0x00F9E0, 0x00AB87, 0x00F9E4, 0x00F9E6, 0x01E816, 0x01E815, + 0x0012A1, 0x0012A0, 0x0012A3, 0x0012A2, 0x0012A5, 0x0012A4, 0x0012A7, 0x0012A6, + 0x0012A9, 0x0012A8, 0x0012AB, 0x0012AA, 0x0012AD, 0x0012AC, 0x0012AF, 0x0012AE, + 0x01E811, 0x0012B0, 0x0012B3, 0x0012B2, 0x0012B5, 0x0012B4, 0x01E812, 0x01E810, + 0x0012B9, 0x0012B8, 0x0012BB, 0x0012BA, 0x0012BD, 0x0012BC, 0x01E81D, 0x0012BE, + 0x01E81F, 0x0012C0, 0x0012C3, 0x0012C2, 0x0012C5, 0x0012C4, 0x01E819, 0x01E818, + 0x0012C9, 0x01E81A, 0x0012CB, 0x0012CA, 0x0012CD, 0x0012CC, 0x01E814, 0x0012CE, + 0x0012D1, 0x0012D0, 0x0012D3, 0x0012D2, 0x0012D5, 0x0012D4, 0x01E81B, 0x0012D6, + 0x0012D9, 0x0012D8, 0x0012DB, 0x0012DA, 0x0012DD, 0x0012DC, 0x0012DF, 0x0012DE, + 0x01E82D, 0x01E803, 0x0012E3, 0x0012E2, 0x01E802, 0x01E800, 0x01E828, 0x01E801, + 0x01E82E, 0x01E82F, 0x01E804, 0x01E805, 0x01E806, 0x01E809, 0x01E80A, 0x01E80B, + 0x0012F1, 0x0012F0, 0x0012F3, 0x0012F2, 0x01E808, 0x01E80F, 0x0012F7, 0x0012F6, + 0x01E81E, 0x01E81C, 0x0012FB, 0x0012FA, 0x0012FD, 0x0012FC, 0x01E82A, 0x01E821, + 0x01E822, 0x01E851, 0x01E850, 0x01E833, 0x01E826, 0x01E827, 0x01E854, 0x01E82B, + 0x01E820, 0x01E823, 0x01E80C, 0x01E80D, 0x01E80E, 0x01E825, 0x01E841, 0x01E83D, + 0x01E83C, 0x01E85B, 0x01E853, 0x01E843, 0x01E835, 0x01E836, 0x01E839, 0x01E83A, + 0x01E852, 0x01E829, 0x01E838, 0x01E83E, 0x01E83F, 0x01E824, 0x01E860, 0x01E861, + 0x01E883, 0x00A931, 0x01E863, 0x01E865, 0x01E866, 0x00A9D7, 0x00A904, 0x00A9D2, + 0x01E84C, 0x00A941, 0x00A936, 0x01E84D, 0x00A946, 0x00F996, 0x01E891, 0x01E874, + 0x01E893, 0x01E892, 0x01E895, 0x01E894, 0x01E876, 0x01E896, 0x01E899, 0x01E87A, + 0x01E89B, 0x01E89A, 0x01E89D, 0x01E89C, 0x00A925, 0x01E89E, 0x01E8A1, 0x01E8A0, + 0x01E872, 0x01E8A2, 0x01E8A5, 0x01E8A4, 0x01E8A7, 0x01E8A6, 0x00A924, 0x01E8A8, + 0x01E8AB, 0x01E87B, 0x00F99A, 0x01E82C, 0x00F99F, 0x00F99E, 0x00F994, 0x00FE80, + 0x01E870, 0x01E877, 0x00FEB9, 0x00FEB8, 0x00FE8F, 0x00FE86, 0x00FE87, 0x00FE88, + 0x00FE89, 0x00FE8A, 0x00FE8B, 0x00FEBB, 0x00FE8D, 0x00FE8E, 0x01E8C1, 0x01E8C0, + 0x01E842, 0x01E8C2, 0x01E840, 0x01E8C4, 0x01E8C7, 0x01E847, 0x01E8C9, 0x01E8C8, + 0x01E8CB, 0x01E84B, 0x01E845, 0x00FE9D, 0x01E8CF, 0x01E846, 0x00FEB5, 0x01E849, + 0x01E867, 0x00FEBA, 0x01E85E, 0x01E855, 0x01E856, 0x01E857, 0x01E858, 0x01E859, + 0x01E85A, 0x00FE79, 0x01E85C, 0x01E85D, 0x01E84E, 0x01E85F, 0x00FEBF, 0x00FEB0, + 0x00FED1, 0x00FED2, 0x00FEB3, 0x00FEB4, 0x00FEB1, 0x00FED6, 0x00FED7, 0x00FEA2, + 0x00FEBC, 0x01E871, 0x00148E, 0x00FE78, 0x01E844, 0x00FEB7, 0x00FEB6, 0x00FEA5, + 0x01E848, 0x01E84F, 0x00FE72, 0x00FE70, 0x01E873, 0x00FE77, 0x00FEA7, 0x00FEAB, + 0x00FE7B, 0x00FE7A, 0x00FEAC, 0x01E84A, 0x00FE74, 0x00FE76, 0x01E901, 0x01E900, + 0x01E903, 0x01E902, 0x01E905, 0x01E904, 0x01E907, 0x01E906, 0x01E909, 0x01E908, + 0x01E90B, 0x01E90A, 0x01E90D, 0x01E90C, 0x01E90F, 0x01E90E, 0x01E911, 0x01E910, + 0x01E913, 0x01E912, 0x00FEA1, 0x00FEA0, 0x00FED0, 0x01E916, 0x01E919, 0x01E918, + 0x01E91B, 0x01E91A, 0x00FE71, 0x01E91C, 0x01E91F, 0x01E91E, 0x01E921, 0x01E920, + 0x01E923, 0x01E922, 0x00FEA3, 0x00FEA4, 0x00FE73, 0x01E926, 0x01E929, 0x01E928, + 0x01E92B, 0x01E92A, 0x00FEBD, 0x01E92C, 0x01E92F, 0x00FEBE, 0x01E931, 0x01E930, + 0x01E933, 0x01E932, 0x00FEB2, 0x01E934, 0x01E937, 0x01E936, 0x01E939, 0x01E938, + 0x01E93B, 0x01E93A, 0x01E93D, 0x01E93C, 0x01E93F, 0x01E93E, 0x01E941, 0x01E940, + 0x01E943, 0x01E942, 0x00FA90, 0x01E864, 0x00FA83, 0x00FAA2, 0x01E86E, 0x00FA80, + 0x01E868, 0x01E869, 0x00FAA0, 0x01E86D, 0x01E86C, 0x00FA95, 0x01E951, 0x01E950, + 0x01E953, 0x01E952, 0x01E955, 0x01E954, 0x01E957, 0x01E956, 0x01E959, 0x01E958, + 0x00FA9B, 0x00FC46, 0x00FE83, 0x00FE84, 0x00148F, 0x00FA86, 0x00FAA7, 0x00FE82, + 0x001504, 0x001505, 0x01E87C, 0x00FA8F, 0x00FE81, 0x01E862, 0x00151E, 0x01E87D, + 0x00FE85, 0x00FE8C, 0x00FE9C, 0x00151F, 0x01E86A, 0x01E86B, 0x00FA99, 0x01E878, + 0x001509, 0x001518, 0x01E875, 0x00151A, 0x01E86F, 0x01E87E, 0x001517, 0x00FE9A, + 0x001519, 0x00151C, 0x01E879, 0x00FA85, 0x01E87F, 0x00FE95, 0x00151B, 0x00FE90, + 0x00FE9B, 0x00FE92, 0x00FE93, 0x0014AE, 0x0014AF, 0x00FE94, 0x00FE97, 0x001506, + 0x00150A, 0x00150B, 0x00FE91, 0x00FE96, 0x00150E, 0x0014A8, 0x001508, 0x00150F, + 0x001488, 0x001461, 0x0011CB, 0x00FAB3, 0x001117, 0x0011C5, 0x00FAD1, 0x0011E0, + 0x00FAC3, 0x00FAD2, 0x00FAD3, 0x00FE7C, 0x00147C, 0x0014AD, 0x00146C, 0x00FE7D, + 0x00FE9E, 0x001440, 0x001443, 0x001442, 0x00FE7E, 0x001441, 0x001447, 0x001444, + 0x00FE99, 0x00FE7F, 0x00FE9F, 0x00FE98, 0x00144A, 0x001445, 0x001446, 0x00144B, + 0x001470, 0x001479, 0x001478, 0x00147D, 0x001462, 0x00144D, 0x00144E, 0x00147F, + 0x001449, 0x00FF4D, 0x00FF4F, 0x00FF4C, 0x001448, 0x00145C, 0x00144F, 0x00FF11, + 0x00FF10, 0x00FF13, 0x00FF12, 0x00FF15, 0x00FF14, 0x00FF17, 0x00FF16, 0x00FF19, + 0x00147E, 0x001463, 0x00147A, 0x00147B, 0x00FF7D, 0x00FF7E, 0x00FF7F, 0x00FF78, + 0x00FF7B, 0x00FF6E, 0x00FF6D, 0x00FF6C, 0x00FF66, 0x00FF67, 0x00FF79, 0x00FF6B, + 0x00FF68, 0x00FF7C, 0x00FF6A, 0x00FF6F, 0x00FF69, 0x00FF74, 0x001474, 0x00FF31, + 0x00FF30, 0x00FF33, 0x00FF32, 0x00FF35, 0x00FF34, 0x00FF71, 0x00FF73, 0x00FF39, + 0x00FF38, 0x00FF72, 0x00FF3A, 0x00FF7A, 0x00FF75, 0x00FF76, 0x00FF77, 0x0011C7, + 0x00FF42, 0x0014A0, 0x0014A3, 0x00F96C, 0x00F975, 0x0014A1, 0x0014A4, 0x00FF41, + 0x00FF43, 0x00F94A, 0x00F949, 0x0014AB, 0x0014A5, 0x00F962, 0x00F94F, 0x0014A7, + 0x00FF47, 0x00FF46, 0x00F94D, 0x00F977, 0x00F94E, 0x0011CE, 0x00F973, 0x00F971, + 0x00F948, 0x00F976, 0x00F97B, 0x00F974, 0x00F97A, 0x0011F5, 0x00F97E, 0x00FAB7, + 0x00FF45, 0x00F968, 0x00FA9A, 0x00FA94, 0x0145A8, 0x00FB83, 0x00FF44, 0x00F94C, + 0x0014A2, 0x0145A4, 0x0014BC, 0x0145AE, 0x0145AB, 0x0145A9, 0x0145A2, 0x0145A3, + 0x0145AF, 0x0145AD, 0x00FF4E, 0x0145AA, 0x00FF48, 0x00F96D, 0x00F972, 0x00FF49, + 0x00F96E, 0x00FF4B, 0x00FF4A, 0x00F970, 0x0145AC, 0x00F96F, 0x0145BD, 0x00FF81, + 0x00FF80, 0x00FF83, 0x00FF82, 0x00FF85, 0x00FAA6, 0x00FF87, 0x00FF86, 0x00FF89, + 0x0145D0, 0x0145DF, 0x00FF8A, 0x0145D6, 0x00FF8C, 0x0145C1, 0x0145DC, 0x00FF91, + 0x0145D4, 0x00FF93, 0x00FF92, 0x0145DD, 0x00FF94, 0x00FF97, 0x0145D3, 0x00FF99, + 0x00FF98, 0x00FF9B, 0x00FF9A, 0x00FF9D, 0x00FF9C, 0x0014A9, 0x0145D2, 0x00FEA9, + 0x0145DA, 0x0145D5, 0x0145D7, 0x0145D1, 0x0145C3, 0x00FEAF, 0x00FEA6, 0x0014F4, + 0x00FEA8, 0x0014AA, 0x0014FB, 0x0145C2, 0x01E813, 0x0145C6, 0x00FEAA, 0x00FFB1, + 0x0145C0, 0x00FFB3, 0x00FFB2, 0x0145C7, 0x00FEAD, 0x00FA22, 0x0145FD, 0x001093, + 0x00FA21, 0x00FEAE, 0x001092, 0x001081, 0x0145D8, 0x0145D9, 0x0145DE, 0x0145FE, + 0x00FED8, 0x00FFC3, 0x00FFC2, 0x00FFC5, 0x00FFC4, 0x00FFC7, 0x00FFC6, 0x0010B1, + 0x001110, 0x00FFCB, 0x00FFCA, 0x00FFCD, 0x00FFCC, 0x00FFCF, 0x00FFCE, 0x00FED4, + 0x00FA41, 0x00FA42, 0x0010B2, 0x0010B3, 0x00111C, 0x00FED3, 0x00110C, 0x001113, + 0x0015EE, 0x00FA50, 0x001111, 0x00FA84, 0x00FFDC, 0x00FA96, 0x00FEDB, 0x0015EF, + 0x00F961, 0x00F960, 0x00F963, 0x00F966, 0x001102, 0x00FA40, 0x00F967, 0x001489, + 0x00F969, 0x00F96A, 0x00F96B, 0x001103, 0x0015EC, 0x00148A, 0x00F965, 0x00FA20, + 0x001090, 0x001091, 0x00148B, 0x00FED5, 0x00F97D, 0x00FA9D, 0x00FA27, 0x00FEDA, + 0x00FEDF, 0x00F979, 0x00FED9, 0x00F97F, 0x0015E6, 0x00FEDE, 0x00FEDD, 0x0015CE, + 0x0015EA, 0x010003, 0x010034, 0x0015E4, 0x010007, 0x0015E9, 0x010035, 0x010018, + 0x010039, 0x01003A, 0x01003F, 0x01001C, 0x01001D, 0x01001E, 0x01001F, 0x010011, + 0x010010, 0x0015E1, 0x010012, 0x010016, 0x010014, 0x0015E5, 0x0015E2, 0x01001B, + 0x0015ED, 0x0015E0, 0x01001A, 0x010019, 0x010015, 0x010017, 0x0015E7, 0x010031, + 0x0015F0, 0x0015F1, 0x0015F8, 0x0015EB, 0x0015F4, 0x010030, 0x010037, 0x0015F7, + 0x0015E8, 0x0015F9, 0x0015FA, 0x0015FB, 0x0015FC, 0x010036, 0x0015FE, 0x0015FF, + 0x0015C0, 0x0015C1, 0x0015BF, 0x0015C3, 0x0015B9, 0x0015B4, 0x00158C, 0x0015C5, + 0x0015C2, 0x001513, 0x0015BB, 0x0015BA, 0x010032, 0x0015C7, 0x0015C4, 0x010041, + 0x0015DE, 0x0015D0, 0x0015B6, 0x0015DF, 0x0015D7, 0x0015DD, 0x0015B5, 0x0015D4, + 0x0015D9, 0x0015CB, 0x0015DB, 0x0015D8, 0x0015DC, 0x0015C6, 0x0015DA, 0x010051, + 0x0015CF, 0x010059, 0x010052, 0x0015B7, 0x010050, 0x010055, 0x0015B0, 0x010056, + 0x01005B, 0x010043, 0x0015CA, 0x0011FC, 0x0015C8, 0x0015C9, 0x010042, 0x010020, + 0x0015B3, 0x010022, 0x010023, 0x010026, 0x001501, 0x010054, 0x010021, 0x010029, + 0x01002B, 0x01005A, 0x010058, 0x0015B2, 0x010025, 0x010024, 0x01002F, 0x0011F6, + 0x010040, 0x0015F3, 0x0011C1, 0x0011F8, 0x01004B, 0x001515, 0x0015F2, 0x010038, + 0x0015A8, 0x010028, 0x0015F6, 0x0015FD, 0x01003D, 0x0011C6, 0x0015AE, 0x0015AF, + 0x001512, 0x010081, 0x0015E3, 0x010080, 0x010087, 0x001511, 0x010082, 0x01008B, + 0x010088, 0x01008F, 0x0011CC, 0x010085, 0x010084, 0x0015F5, 0x010086, 0x0011F7, + 0x001500, 0x010093, 0x001502, 0x001503, 0x0015CC, 0x0015A2, 0x001484, 0x001507, + 0x0015A0, 0x0011F1, 0x0015CD, 0x0015A3, 0x0011CA, 0x0015AB, 0x0015A6, 0x0015A7, + 0x001510, 0x0015A9, 0x0100A0, 0x001516, 0x0015AA, 0x0100A7, 0x0011C4, 0x001514, + 0x0015BC, 0x0015BE, 0x00151D, 0x0015AD, 0x0015B8, 0x0015BD, 0x0015A4, 0x0015A5, + 0x0100B0, 0x0100B1, 0x0100B2, 0x0100B7, 0x0100B4, 0x0100B5, 0x0100B6, 0x0100BB, + 0x0100B8, 0x001641, 0x001602, 0x001603, 0x001605, 0x0100BF, 0x00168E, 0x001606, + 0x0100C0, 0x0100C3, 0x001610, 0x010045, 0x010047, 0x0100C7, 0x010046, 0x010048, + 0x010049, 0x01004A, 0x01004D, 0x01005C, 0x010044, 0x00168D, 0x01004C, 0x0100D1, + 0x0100D0, 0x001613, 0x0100D2, 0x0100D5, 0x0100D4, 0x0100D7, 0x0100D6, 0x0100D9, + 0x0100D8, 0x0100DB, 0x0100DA, 0x0100DD, 0x01005D, 0x0100DF, 0x0100DE, 0x001633, + 0x0100E0, 0x0100E3, 0x0016B0, 0x001631, 0x001632, 0x0100E7, 0x0016B7, 0x0016B6, + 0x0016BE, 0x0016B9, 0x0016BA, 0x0016BB, 0x0016B5, 0x001618, 0x0016BD, 0x0100F1, + 0x0100F0, 0x00161D, 0x0100F2, 0x0100F5, 0x0100F4, 0x0100F7, 0x0100F6, 0x0100F9, + 0x0100F8, 0x00161A, 0x0100FA, 0x001643, 0x00165C, 0x001646, 0x00161F, 0x001642, + 0x01010B, 0x001611, 0x001612, 0x01011C, 0x01011D, 0x001615, 0x010131, 0x001617, + 0x010118, 0x001619, 0x01011F, 0x00161B, 0x001614, 0x001616, 0x01011E, 0x010111, + 0x00163A, 0x010113, 0x010112, 0x010110, 0x00161C, 0x010117, 0x010116, 0x01011B, + 0x010109, 0x01010A, 0x01010D, 0x010114, 0x010115, 0x01011A, 0x010119, 0x010108, + 0x010120, 0x01010C, 0x010122, 0x010121, 0x01010F, 0x01010E, 0x010107, 0x010129, + 0x00163B, 0x01012B, 0x01012A, 0x010124, 0x010125, 0x010126, 0x010127, 0x00161E, + 0x0016B1, 0x00168A, 0x001683, 0x001682, 0x001681, 0x001686, 0x001684, 0x010132, + 0x010128, 0x001687, 0x0016B4, 0x01012D, 0x01012C, 0x01012F, 0x01012E, 0x01015D, + 0x010140, 0x010141, 0x010142, 0x010147, 0x01015C, 0x00168C, 0x01015E, 0x01E915, + 0x001640, 0x001645, 0x01015F, 0x001647, 0x00160C, 0x00164E, 0x001644, 0x010151, + 0x010150, 0x010157, 0x010152, 0x010155, 0x010154, 0x010153, 0x010156, 0x010159, + 0x001672, 0x001677, 0x01015A, 0x010158, 0x001676, 0x01015B, 0x0016B3, 0x010130, + 0x001648, 0x010163, 0x010143, 0x0016B2, 0x001634, 0x001660, 0x00163E, 0x001685, + 0x001638, 0x001639, 0x001689, 0x00168B, 0x00163D, 0x00163F, 0x0016EF, 0x010172, + 0x010123, 0x010170, 0x010133, 0x010176, 0x010171, 0x010174, 0x010175, 0x0016C3, + 0x0016C2, 0x010178, 0x0016C0, 0x001699, 0x0016C6, 0x0016C1, 0x010177, 0x0016C7, + 0x0016C5, 0x001691, 0x0016C4, 0x001693, 0x001692, 0x001697, 0x001694, 0x01018B, + 0x001698, 0x0016CB, 0x01018A, 0x00169A, 0x0016CA, 0x0016DC, 0x001696, 0x001695, + 0x0016E1, 0x0016E0, 0x0016E3, 0x0016E2, 0x0016E7, 0x0016CD, 0x001673, 0x0016F4, + 0x0016C9, 0x0016CE, 0x0012C8, 0x001671, 0x0016CC, 0x001485, 0x001674, 0x00164C, + 0x0016E5, 0x0016F2, 0x0016F3, 0x0016E4, 0x0016E6, 0x0016F1, 0x0016F7, 0x0016F5, + 0x0016E8, 0x0016F0, 0x0016EA, 0x0016E9, 0x0016F8, 0x00164A, 0x0016EE, 0x0016F6, + 0x001701, 0x001700, 0x001703, 0x001702, 0x001705, 0x001704, 0x001707, 0x001706, + 0x001709, 0x001708, 0x00170B, 0x00170A, 0x001486, 0x00170C, 0x00170F, 0x00170E, + 0x001487, 0x001710, 0x001711, 0x001480, 0x001481, 0x001482, 0x001483, 0x00149C, + 0x00149D, 0x00125D, 0x00149E, 0x00149F, 0x001498, 0x00167D, 0x00167E, 0x01E92D, + 0x001721, 0x001720, 0x001723, 0x001722, 0x001725, 0x001661, 0x001727, 0x001726, + 0x001729, 0x001769, 0x00172B, 0x00172A, 0x00176C, 0x00172C, 0x00176E, 0x001667, + 0x001731, 0x001730, 0x001499, 0x00167F, 0x001665, 0x001664, 0x00149A, 0x00149B, + 0x001494, 0x001669, 0x00166B, 0x001495, 0x00166C, 0x001496, 0x001497, 0x00166F, + 0x001741, 0x000F5D, 0x001743, 0x001742, 0x001745, 0x001747, 0x00164F, 0x001744, + 0x001649, 0x001740, 0x00174B, 0x00164B, 0x00166A, 0x00174C, 0x001746, 0x00174A, + 0x001751, 0x001750, 0x001765, 0x01031C, 0x001766, 0x00164D, 0x010304, 0x01030A, + 0x001748, 0x001749, 0x00176A, 0x00176B, 0x001768, 0x00174D, 0x00174E, 0x00174F, + 0x000F5C, 0x001670, 0x001678, 0x0012CF, 0x01030F, 0x010307, 0x01031E, 0x010309, + 0x010318, 0x01031A, 0x00167C, 0x00167A, 0x001763, 0x010308, 0x010339, 0x001679, + 0x001760, 0x001668, 0x001770, 0x001762, 0x010333, 0x01033F, 0x001675, 0x001761, + 0x010331, 0x00167B, 0x001662, 0x010332, 0x010335, 0x001663, 0x001666, 0x001767, + 0x001781, 0x001784, 0x001783, 0x001782, 0x001785, 0x001780, 0x001787, 0x001786, + 0x001799, 0x001798, 0x00178B, 0x00178A, 0x00179D, 0x001789, 0x00179F, 0x00179E, + 0x001791, 0x01030E, 0x001793, 0x00178E, 0x00178D, 0x001794, 0x00178F, 0x001792, + 0x001790, 0x00179C, 0x00179B, 0x00179A, 0x001788, 0x001795, 0x001796, 0x001797, + 0x001490, 0x0017A3, 0x001491, 0x0017A1, 0x0017A6, 0x0017A7, 0x0017A2, 0x0017A5, + 0x0017A0, 0x001492, 0x01E92E, 0x0017A9, 0x00178C, 0x0017AC, 0x01E897, 0x00122D, + 0x0017B1, 0x0017B2, 0x0017B3, 0x0017B0, 0x010334, 0x0010C0, 0x001231, 0x010338, + 0x00122C, 0x01033B, 0x01033A, 0x01030C, 0x01030D, 0x01033E, 0x001493, 0x0010E2, + 0x00158D, 0x00156C, 0x010323, 0x010330, 0x01E8B2, 0x0010F3, 0x00123C, 0x01E8B1, + 0x001250, 0x00156D, 0x01E8B0, 0x001253, 0x01E8B6, 0x010336, 0x001252, 0x01E8B3, + 0x00156E, 0x00156F, 0x0102A7, 0x001255, 0x010295, 0x001225, 0x01E8B7, 0x010298, + 0x0102A0, 0x0102A4, 0x01029B, 0x01E8BB, 0x0102A6, 0x0017DC, 0x001251, 0x010292, + 0x0017E1, 0x0017E2, 0x0017E3, 0x0017E0, 0x0017E5, 0x0017E6, 0x0017E7, 0x0017E4, + 0x0017E9, 0x0017E8, 0x010291, 0x010290, 0x010294, 0x010297, 0x010296, 0x001100, + 0x001239, 0x0017F2, 0x0017F0, 0x001568, 0x01E89F, 0x0017F1, 0x0017F3, 0x0017F4, + 0x0017F9, 0x001569, 0x0102A2, 0x0102A1, 0x0017F5, 0x0017F8, 0x0017F7, 0x0017F6, + 0x000F5E, 0x00186E, 0x001853, 0x001866, 0x001864, 0x001865, 0x001867, 0x00183C, + 0x001868, 0x001869, 0x00186A, 0x00186B, 0x000F5F, 0x00186D, 0x000EDD, 0x00186F, + 0x001835, 0x000F58, 0x000ED8, 0x000ED9, 0x000EDE, 0x000EDF, 0x01E882, 0x0102E8, + 0x0102ED, 0x01E88B, 0x0102EB, 0x0102EC, 0x0102D0, 0x0102EE, 0x0102EF, 0x00156A, + 0x001833, 0x001831, 0x00183D, 0x001830, 0x001837, 0x001850, 0x001832, 0x001875, + 0x001862, 0x001863, 0x001836, 0x001857, 0x001874, 0x001861, 0x001860, 0x0102E1, + 0x0102E4, 0x001852, 0x0102E2, 0x0102E6, 0x0102A5, 0x0102E7, 0x001851, 0x0102A8, + 0x0102A9, 0x0102AA, 0x0102AB, 0x0102AC, 0x0102AD, 0x0102C3, 0x0102AF, 0x0102E5, + 0x001841, 0x001840, 0x0102E9, 0x001842, 0x001845, 0x001844, 0x001847, 0x001846, + 0x001849, 0x001848, 0x00184B, 0x00184A, 0x00182D, 0x0102EA, 0x00184F, 0x00184E, + 0x001871, 0x00182C, 0x010313, 0x001872, 0x010364, 0x001870, 0x001877, 0x010348, + 0x010349, 0x010368, 0x010369, 0x001876, 0x01036F, 0x00185C, 0x01036B, 0x00184D, + 0x001822, 0x001821, 0x001820, 0x001823, 0x001826, 0x001825, 0x00184C, 0x001827, + 0x00182A, 0x010312, 0x00182B, 0x010311, 0x00182E, 0x010315, 0x00182F, 0x010321, + 0x010320, 0x001829, 0x010322, 0x001828, 0x010360, 0x010361, 0x010362, 0x001834, + 0x010366, 0x001873, 0x010367, 0x01032D, 0x00183A, 0x01032F, 0x01032E, 0x00183B, + 0x000ED2, 0x014624, 0x000ED3, 0x010374, 0x010375, 0x01E8A3, 0x000ED6, 0x00156B, + 0x01462A, 0x001564, 0x000EAE, 0x000EAD, 0x01462B, 0x000EAF, 0x010365, 0x010341, + 0x010343, 0x010347, 0x010342, 0x01035D, 0x0103CD, 0x01035F, 0x010340, 0x0103C8, + 0x010359, 0x01035C, 0x0103CB, 0x0103CE, 0x0103CC, 0x010346, 0x0103CF, 0x010352, + 0x01EE03, 0x010353, 0x0103C3, 0x010350, 0x010351, 0x010354, 0x010355, 0x010310, + 0x010358, 0x01035E, 0x01035A, 0x010356, 0x01035B, 0x010357, 0x01EE11, 0x01EE10, + 0x01EE13, 0x01EE12, 0x01EE15, 0x01EE14, 0x01EE17, 0x01EE16, 0x01EE19, 0x01EE18, + 0x01EE1B, 0x01EE1A, 0x01EE1D, 0x01EE1C, 0x01EE1F, 0x01EE1E, 0x01EE21, 0x010345, + 0x010344, 0x01EE22, 0x010372, 0x01EE24, 0x01EE27, 0x010373, 0x01EE29, 0x010371, + 0x01EE2B, 0x01EE2A, 0x010370, 0x01EE2C, 0x01EE2F, 0x01034A, 0x01EE31, 0x01EE30, + 0x010394, 0x010381, 0x010382, 0x010380, 0x01EE37, 0x010384, 0x010386, 0x01039A, + 0x0103CA, 0x0103AF, 0x01038F, 0x010385, 0x01039B, 0x010387, 0x010399, 0x0103A2, + 0x01030B, 0x010393, 0x0103C9, 0x01EEA1, 0x01EE47, 0x010392, 0x010302, 0x01038B, + 0x01EE4B, 0x010300, 0x010391, 0x010390, 0x010397, 0x010396, 0x010395, 0x010303, + 0x0103B4, 0x01EE52, 0x010383, 0x01EE06, 0x0103A7, 0x01EE02, 0x0103B5, 0x00186C, + 0x0103B9, 0x0103B8, 0x0103D3, 0x0103BB, 0x0103BD, 0x010319, 0x0103BF, 0x0103B1, + 0x0103B0, 0x01EE62, 0x0103B2, 0x01039C, 0x0103B6, 0x0103B7, 0x01EE69, 0x01EE68, + 0x010398, 0x01039D, 0x01EE6D, 0x01EE6C, 0x01EE6F, 0x01EE6E, 0x01EE71, 0x01EE70, + 0x01031B, 0x0103C0, 0x01EE75, 0x01EE74, 0x01EE77, 0x01EE76, 0x0103C1, 0x010314, + 0x01EE7B, 0x010316, 0x001913, 0x0103AD, 0x001901, 0x01031D, 0x010317, 0x001912, + 0x01EE91, 0x00190C, 0x01EE90, 0x01EE96, 0x01EE95, 0x01EE97, 0x01EE94, 0x010306, + 0x0103D1, 0x0103D2, 0x010301, 0x0103D5, 0x0103D4, 0x0103C2, 0x010305, 0x0103A0, + 0x0103A1, 0x010337, 0x0103AB, 0x0103A4, 0x001910, 0x0103A6, 0x01031F, 0x0103A8, + 0x001911, 0x0103AA, 0x01EE83, 0x001915, 0x001917, 0x0103A5, 0x0103BE, 0x0103AC, + 0x00195A, 0x01EEA2, 0x01EEA5, 0x001956, 0x01EEA7, 0x01EEA6, 0x01EEA9, 0x01EEA8, + 0x01EEAB, 0x0103A9, 0x01EEAD, 0x01EEAC, 0x01EEAF, 0x01EEAE, 0x0103AE, 0x00195B, + 0x001955, 0x001950, 0x001953, 0x001952, 0x001914, 0x001957, 0x001916, 0x01EE82, + 0x001918, 0x001919, 0x00191A, 0x00191B, 0x01EE9B, 0x00191D, 0x00191E, 0x01EE81, + 0x01EE80, 0x01EEB6, 0x01EE86, 0x01EE85, 0x01EE84, 0x01EE87, 0x01EE89, 0x01EEB5, + 0x01EE88, 0x01EE8B, 0x01EE8D, 0x00185D, 0x01EE8C, 0x01EEB2, 0x01EEB7, 0x001854, + 0x01EEB3, 0x01EEB0, 0x001855, 0x01EE8E, 0x001954, 0x01EE8F, 0x001856, 0x01EE9A, + 0x001958, 0x001959, 0x00195E, 0x01EE99, 0x01EE98, 0x00195D, 0x01EEB1, 0x00195F, + 0x0019B5, 0x001983, 0x001984, 0x0019B6, 0x001986, 0x001981, 0x001982, 0x001985, + 0x001989, 0x001980, 0x00198B, 0x00198F, 0x0019D6, 0x001987, 0x00198C, 0x0019BB, + 0x001991, 0x001988, 0x001993, 0x001992, 0x0019D1, 0x0019D2, 0x0019D3, 0x00198E, + 0x0019D7, 0x001998, 0x00198A, 0x00198D, 0x0019D0, 0x00199C, 0x00199F, 0x00199E, + 0x010415, 0x01041A, 0x0019A3, 0x010422, 0x010414, 0x01041F, 0x010416, 0x010420, + 0x010421, 0x010424, 0x0019A1, 0x0019A2, 0x010426, 0x010419, 0x01042B, 0x010563, + 0x0019D4, 0x010427, 0x0019B3, 0x0019B2, 0x0019D5, 0x0019B0, 0x0019B1, 0x01042F, + 0x0019DA, 0x0019BC, 0x0019D8, 0x0019D9, 0x01EE0C, 0x01EE0D, 0x010418, 0x0019B7, + 0x010474, 0x0019C3, 0x01EE2D, 0x014601, 0x014600, 0x014606, 0x014607, 0x01EE2E, + 0x0019C2, 0x0019C0, 0x010473, 0x01044C, 0x0019C5, 0x0019C1, 0x0019C7, 0x01EE32, + 0x010450, 0x010483, 0x01EE34, 0x01EE35, 0x0019C4, 0x01EE36, 0x0019C6, 0x01EEB9, + 0x01EE3B, 0x0019C9, 0x01EEB8, 0x00185B, 0x010456, 0x01EE39, 0x00185A, 0x010491, + 0x010490, 0x010493, 0x010492, 0x010495, 0x010494, 0x0019A5, 0x0019A6, 0x010499, + 0x010498, 0x01049B, 0x01049A, 0x01049D, 0x01049C, 0x010497, 0x010496, 0x0104A1, + 0x0104A0, 0x01EE57, 0x0104A2, 0x0104A5, 0x0104A4, 0x0104A7, 0x0104A6, 0x01EE51, + 0x01EE59, 0x0019B9, 0x0019BA, 0x01EE54, 0x01EE5B, 0x01EE49, 0x0104A9, 0x0104B1, + 0x0104B0, 0x01EE42, 0x0104B2, 0x0104A8, 0x0104B4, 0x0104B7, 0x01EE6A, 0x01EE61, + 0x010475, 0x0104BB, 0x01EE67, 0x01EE4D, 0x01EE4E, 0x01EE4F, 0x01EE64, 0x0104C2, + 0x01EE72, 0x001B18, 0x001B06, 0x01EE7C, 0x001B14, 0x01EE7E, 0x01EE79, 0x001B1E, + 0x01EE7A, 0x0104C1, 0x001B1B, 0x01EE5D, 0x0104C0, 0x01EE5F, 0x0104C3, 0x01EEBA, + 0x010470, 0x0104D3, 0x001A82, 0x001A83, 0x001A84, 0x010477, 0x0104C7, 0x0104D9, + 0x0104D8, 0x010476, 0x0104DA, 0x0104DD, 0x0104DC, 0x0104DF, 0x0104DE, 0x0104E2, + 0x0104E0, 0x0104E3, 0x01EEB4, 0x01EEA3, 0x0104E1, 0x0104E4, 0x0104E5, 0x010428, + 0x010425, 0x0104EB, 0x01EEBB, 0x0104E8, 0x0104EF, 0x0104E6, 0x0104E7, 0x0104F1, + 0x010451, 0x010452, 0x0104F2, 0x0104F0, 0x0104F4, 0x0104F7, 0x0104F6, 0x0104FB, + 0x010472, 0x0104F8, 0x01045B, 0x010471, 0x0104F5, 0x0104FA, 0x0104F9, 0x001A43, + 0x001A81, 0x001A41, 0x001A42, 0x001A40, 0x010455, 0x001A46, 0x001A47, 0x010502, + 0x010458, 0x001A99, 0x001A96, 0x01045F, 0x001A87, 0x01051C, 0x001A45, 0x010511, + 0x010510, 0x010513, 0x001A44, 0x010515, 0x010514, 0x010517, 0x010516, 0x010519, + 0x010518, 0x01051B, 0x01051A, 0x01051D, 0x001A4A, 0x01051F, 0x01051E, 0x010501, + 0x010500, 0x010507, 0x010522, 0x010520, 0x010521, 0x010527, 0x010506, 0x010505, + 0x010503, 0x001A49, 0x001A4B, 0x010524, 0x010525, 0x010526, 0x001A48, 0x001A4F, + 0x000AA4, 0x000A21, 0x000A22, 0x000A23, 0x000A15, 0x000AA5, 0x000AA6, 0x000AA7, + 0x01047D, 0x000A09, 0x000A08, 0x000A39, 0x000A20, 0x000A27, 0x000A0F, 0x010541, + 0x010540, 0x010543, 0x010542, 0x010545, 0x010544, 0x010547, 0x010546, 0x010549, + 0x010548, 0x01054B, 0x01054A, 0x01054D, 0x01054C, 0x01054F, 0x01054E, 0x010535, + 0x010552, 0x01053D, 0x01050B, 0x010534, 0x010553, 0x010504, 0x010536, 0x010538, + 0x010539, 0x01053A, 0x01053B, 0x01053C, 0x01055C, 0x01053E, 0x01053F, 0x010561, + 0x010560, 0x000AA1, 0x010562, 0x01F109, 0x01F108, 0x01047A, 0x010479, 0x000AA0, + 0x01F10A, 0x010457, 0x01047B, 0x000AB8, 0x001BAE, 0x001BAF, 0x000ABD, 0x010454, + 0x01055D, 0x01055E, 0x01055F, 0x010554, 0x010555, 0x010556, 0x001BCF, 0x010532, + 0x010537, 0x01055A, 0x010531, 0x010530, 0x010559, 0x010558, 0x01055B, 0x001BC8, + 0x010484, 0x001BD0, 0x000E9D, 0x010480, 0x001BD5, 0x001A90, 0x001BD6, 0x001BD7, + 0x01048A, 0x010482, 0x001A4D, 0x010485, 0x001A4C, 0x001BDB, 0x001A4E, 0x001A98, + 0x001A94, 0x0104B3, 0x014644, 0x000AE1, 0x000E84, 0x001A93, 0x01F10C, 0x0104B8, + 0x000AE0, 0x001A91, 0x001A92, 0x001A95, 0x001A97, 0x0104BE, 0x0104BF, 0x000A72, + 0x000E9C, 0x000A25, 0x0104A3, 0x000A26, 0x000A73, 0x000AE6, 0x000AE7, 0x010488, + 0x000AEA, 0x000AF9, 0x000AEB, 0x0104BA, 0x000A24, 0x01048E, 0x000A74, 0x000A6C, + 0x001B0C, 0x001B48, 0x001B46, 0x001B4B, 0x001B45, 0x001B19, 0x001B47, 0x010523, + 0x001B09, 0x001B08, 0x001B0B, 0x001B0A, 0x001B0D, 0x001B4A, 0x001B0F, 0x001B0E, + 0x001B11, 0x001B10, 0x001B13, 0x001B12, 0x001B15, 0x01442F, 0x001B17, 0x001B16, + 0x000E8D, 0x014442, 0x014447, 0x01440F, 0x001B1A, 0x001B1C, 0x014441, 0x014409, + 0x001B30, 0x001B20, 0x001B23, 0x001B22, 0x001B25, 0x001B21, 0x001B27, 0x001B24, + 0x0104DB, 0x0104D2, 0x0104D0, 0x001B29, 0x001B2A, 0x001B2C, 0x001B26, 0x001B2B, + 0x01440D, 0x001B33, 0x01440E, 0x01441B, 0x014432, 0x014536, 0x0144EC, 0x014537, + 0x014460, 0x001B32, 0x0144ED, 0x014431, 0x001B31, 0x000A2A, 0x001B49, 0x000A2B, + 0x0144AC, 0x014430, 0x000EB3, 0x01447B, 0x014433, 0x010512, 0x000EB2, 0x014437, + 0x000F68, 0x000F6C, 0x000F4A, 0x000EB0, 0x01441A, 0x01447C, 0x000F4E, 0x010601, + 0x001B51, 0x001B53, 0x010602, 0x010600, 0x001B56, 0x001B54, 0x001B52, 0x001B55, + 0x001B50, 0x010604, 0x001B58, 0x010606, 0x010605, 0x001B59, 0x010607, 0x001B57, + 0x01440A, 0x01440B, 0x014462, 0x014461, 0x0144D0, 0x014473, 0x014436, 0x010608, + 0x010609, 0x01060A, 0x01060B, 0x01060C, 0x01060D, 0x01060E, 0x01447E, 0x014475, + 0x014472, 0x014466, 0x01445A, 0x014476, 0x01445C, 0x01444C, 0x000F69, 0x014463, + 0x010623, 0x01445D, 0x01443E, 0x01445E, 0x014467, 0x01443C, 0x01445F, 0x010633, + 0x001B83, 0x01440C, 0x01443D, 0x01063C, 0x000E8A, 0x01063E, 0x000E87, 0x014423, + 0x01063A, 0x01447F, 0x014443, 0x014453, 0x001B8D, 0x001B8C, 0x01063D, 0x010655, + 0x010654, 0x001B90, 0x001B93, 0x010656, 0x010657, 0x001B91, 0x001B92, 0x0144AD, + 0x01065B, 0x00A804, 0x001B9C, 0x0144AE, 0x01065F, 0x001B95, 0x001B96, 0x001B97, + 0x001B84, 0x001A85, 0x001B8E, 0x001B8F, 0x001B88, 0x001B85, 0x001B86, 0x001B87, + 0x01F102, 0x010652, 0x010651, 0x001B8B, 0x01F10B, 0x010650, 0x001B8A, 0x001B89, + 0x001BB1, 0x001BB0, 0x001BB3, 0x001BB2, 0x001BB5, 0x001BB4, 0x001BB7, 0x001BB6, + 0x001BB9, 0x001BB8, 0x001BBB, 0x001BBA, 0x001BBD, 0x001A80, 0x001BBF, 0x001BBE, + 0x001BC1, 0x00A832, 0x001BC3, 0x001BC2, 0x001BC5, 0x001BC4, 0x0144AF, 0x001BC6, + 0x001BC9, 0x001BC0, 0x001BCB, 0x001BCA, 0x001BCD, 0x001BCC, 0x001BC7, 0x001BCE, + 0x001BD1, 0x01F103, 0x001BD3, 0x001BD2, 0x0144D2, 0x0144D1, 0x001A86, 0x014440, + 0x001A89, 0x01444B, 0x00A89B, 0x001A88, 0x0144B8, 0x001BDC, 0x00A89A, 0x00A822, + 0x001BE1, 0x001BE0, 0x001BE3, 0x001BE2, 0x001BE5, 0x001BE4, 0x00A8D8, 0x00AA9C, + 0x014445, 0x001BBC, 0x014452, 0x014616, 0x00A8F3, 0x000E88, 0x01444A, 0x0106A1, + 0x0106A0, 0x014446, 0x0106A2, 0x001BA0, 0x0106A4, 0x0106A7, 0x0106A6, 0x0106A9, + 0x0106A8, 0x0106AB, 0x0106AA, 0x0106AE, 0x0106A5, 0x0106AF, 0x0106AD, 0x0144B9, + 0x001C0D, 0x001C00, 0x001C03, 0x001C06, 0x001C05, 0x001C04, 0x001C07, 0x001C0C, + 0x001C09, 0x001C18, 0x001C0B, 0x0106AC, 0x001C0A, 0x001C0F, 0x001C1E, 0x0106DF, + 0x001C11, 0x001C10, 0x001C13, 0x001C12, 0x001C16, 0x001C17, 0x0106C3, 0x001C14, + 0x001C19, 0x001C1A, 0x001C1B, 0x001C1C, 0x001C1D, 0x001C15, 0x001C1F, 0x0106D3, + 0x0106D0, 0x0106D1, 0x0106D2, 0x0106D7, 0x0106D4, 0x0106D5, 0x0106D6, 0x0106DB, + 0x01F101, 0x0106D9, 0x0106DA, 0x01F100, 0x0106D8, 0x0106DC, 0x0106DE, 0x001C08, + 0x001C20, 0x001C21, 0x001C22, 0x001C23, 0x001C74, 0x001C71, 0x001C76, 0x001C77, + 0x001C60, 0x001C61, 0x001C62, 0x001C63, 0x001C0E, 0x001C75, 0x0106FF, 0x0106F1, + 0x0106F0, 0x0106F7, 0x0106F2, 0x0106F5, 0x01F107, 0x01F106, 0x0106F6, 0x01F105, + 0x0106F8, 0x0106F9, 0x0106FA, 0x0106F4, 0x0106DD, 0x0106FB, 0x001C54, 0x010710, + 0x010711, 0x001C50, 0x001C53, 0x010717, 0x001C51, 0x010715, 0x010716, 0x001C52, + 0x001C5A, 0x001C5B, 0x001C56, 0x001C59, 0x001C5F, 0x001C55, 0x010714, 0x001C57, + 0x001C40, 0x001C41, 0x001C42, 0x001C43, 0x001C44, 0x001C45, 0x01F104, 0x001C47, + 0x001C70, 0x001C49, 0x001C72, 0x001C73, 0x001C5C, 0x010712, 0x001C46, 0x010721, + 0x010720, 0x001C5D, 0x010722, 0x010725, 0x010724, 0x010727, 0x010726, 0x010718, + 0x01071F, 0x01072B, 0x01071A, 0x010728, 0x010729, 0x01071E, 0x001C58, 0x001C5E, + 0x00A8B0, 0x00A8B1, 0x00A8AB, 0x00A8A9, 0x0145E1, 0x00A8D5, 0x00A8A4, 0x00A8D9, + 0x001C82, 0x00A8AA, 0x00AA86, 0x001C83, 0x01071B, 0x01072F, 0x010719, 0x001C81, + 0x001C85, 0x010743, 0x001C80, 0x001C86, 0x000C9B, 0x001C87, 0x001C84, 0x000C97, + 0x001565, 0x000C93, 0x001C88, 0x014584, 0x01444E, 0x001566, 0x014589, 0x010751, + 0x010750, 0x000C9A, 0x010752, 0x010755, 0x010754, 0x0145B1, 0x0145B2, 0x0145B3, + 0x0145B0, 0x014515, 0x014514, 0x00AA80, 0x000F25, 0x014533, 0x01451B, 0x01458C, + 0x000F24, 0x01458D, 0x014618, 0x00AA89, 0x01450C, 0x01462C, 0x000C92, 0x014603, + 0x014630, 0x000CB2, 0x000C96, 0x000C95, 0x00A8F4, 0x000CB8, 0x00AA88, 0x01462E, + 0x01442E, 0x01450D, 0x01450E, 0x01450F, 0x000D6D, 0x014610, 0x000F22, 0x000F42, + 0x000D68, 0x00AA9E, 0x000D6E, 0x014505, 0x014631, 0x000F40, 0x001567, 0x01461A, + 0x000C94, 0x001560, 0x014602, 0x000D6C, 0x001561, 0x000C90, 0x00A80F, 0x01455E, + 0x0145CC, 0x0145C5, 0x01071C, 0x014478, 0x01071D, 0x01444F, 0x014540, 0x000CA8, + 0x00A8D4, 0x001C6C, 0x010703, 0x0145CD, 0x014479, 0x001C65, 0x001C66, 0x001C67, + 0x014474, 0x001C69, 0x001C6A, 0x01446F, 0x01455F, 0x001CEC, 0x001CEF, 0x001CEE, + 0x001CF1, 0x001CF0, 0x01447A, 0x001562, 0x001CF5, 0x0145F2, 0x0145F3, 0x001CF6, + 0x0145F6, 0x014531, 0x0145F7, 0x014532, 0x014530, 0x00A8F5, 0x01460E, 0x014578, + 0x001D01, 0x001D02, 0x001D03, 0x001D00, 0x001D05, 0x001D06, 0x001D07, 0x001D04, + 0x001D0C, 0x001D0A, 0x001D0B, 0x000D0F, 0x001D09, 0x001D1D, 0x001D0F, 0x001D0D, + 0x001D11, 0x001D10, 0x001D13, 0x001D12, 0x001D15, 0x001D14, 0x001D17, 0x001D08, + 0x001D19, 0x001D18, 0x001D1B, 0x001D1A, 0x001D1E, 0x001D1F, 0x001D16, 0x001D1C, + 0x001D21, 0x001D24, 0x001D23, 0x001D22, 0x000D27, 0x001D20, 0x001D27, 0x001D26, + 0x001D29, 0x001D2A, 0x001D2B, 0x000D23, 0x000D0E, 0x001D25, 0x001D0E, 0x000D2B, + 0x000D21, 0x000D76, 0x000D22, 0x000D25, 0x000D26, 0x01446E, 0x001563, 0x00A815, + 0x001D28, 0x000D24, 0x000D7B, 0x000D6F, 0x01462F, 0x00157C, 0x000D75, 0x000D3D, + 0x000DC0, 0x000D20, 0x000D77, 0x000D6A, 0x000DC4, 0x000D67, 0x000D73, 0x000D69, + 0x000D66, 0x000D71, 0x000D4E, 0x000D72, 0x000D70, 0x000D60, 0x000D2A, 0x010801, + 0x010803, 0x010820, 0x010802, 0x010800, 0x010826, 0x010804, 0x010805, 0x010818, + 0x01080B, 0x01081A, 0x01080A, 0x010814, 0x010808, 0x01081C, 0x01080C, 0x010811, + 0x010817, 0x01081B, 0x010812, 0x010810, 0x001D74, 0x001D6D, 0x001D6C, 0x001D6F, + 0x001D6B, 0x001D79, 0x001D7A, 0x001D7B, 0x001D6E, 0x001D7D, 0x001D7E, 0x001D7F, + 0x010834, 0x010835, 0x001D73, 0x001D72, 0x010827, 0x001D71, 0x010822, 0x010838, + 0x001D70, 0x01083C, 0x010821, 0x001D75, 0x010823, 0x001D77, 0x001D76, 0x001D7C, + 0x001D81, 0x010833, 0x001D83, 0x001D82, 0x001D85, 0x010832, 0x010831, 0x001D86, + 0x010819, 0x001D98, 0x010837, 0x010830, 0x01080F, 0x001D8C, 0x01081F, 0x01085B, + 0x001D91, 0x001D90, 0x001D93, 0x001D92, 0x001D95, 0x001D94, 0x001D97, 0x001D96, + 0x01085F, 0x01085D, 0x01083F, 0x010842, 0x01085A, 0x001D99, 0x001D9A, 0x010840, + 0x010841, 0x010853, 0x010852, 0x010847, 0x010845, 0x010846, 0x010851, 0x010850, + 0x010854, 0x01084A, 0x01084B, 0x010855, 0x010844, 0x010859, 0x010843, 0x01084F, + 0x010875, 0x010849, 0x01082C, 0x01087B, 0x010825, 0x010824, 0x01087F, 0x010828, + 0x010829, 0x01082A, 0x01087A, 0x01082E, 0x01082D, 0x01082B, 0x01082F, 0x010873, + 0x010872, 0x010862, 0x010863, 0x010860, 0x010861, 0x010871, 0x010867, 0x010858, + 0x010870, 0x010865, 0x010874, 0x01085C, 0x010866, 0x01085E, 0x010876, 0x010881, + 0x014632, 0x010883, 0x010882, 0x010885, 0x000DC6, 0x000DC5, 0x010886, 0x010889, + 0x010888, 0x01088B, 0x01088A, 0x00A821, 0x000DAC, 0x01088F, 0x000DC3, 0x010891, + 0x00AA99, 0x000D7A, 0x010892, 0x010895, 0x00AA9A, 0x00A814, 0x010896, 0x010899, + 0x010898, 0x01089B, 0x01089A, 0x000DC2, 0x00AA9F, 0x00AA83, 0x000D7E, 0x000DC1, + 0x014613, 0x000D7F, 0x00AA87, 0x014625, 0x0108AC, 0x0108A7, 0x000CB5, 0x000D74, + 0x00AA81, 0x0108AB, 0x0108AA, 0x0108A8, 0x0108A9, 0x0108AF, 0x00A835, 0x000DAD, + 0x014611, 0x001E61, 0x001E62, 0x001E63, 0x00A834, 0x001E65, 0x001E66, 0x00AA98, + 0x01461B, 0x014615, 0x014619, 0x014612, 0x001E7C, 0x001E7D, 0x001E6C, 0x01086A, + 0x001E1D, 0x01084D, 0x001E7E, 0x001E7F, 0x001E1F, 0x01084E, 0x001E14, 0x01086D, + 0x001E78, 0x010848, 0x001E1B, 0x001E1A, 0x001E1E, 0x001E18, 0x0108E3, 0x0108FC, + 0x0108FD, 0x010868, 0x001E74, 0x001EAD, 0x01086C, 0x01086E, 0x001EAE, 0x01084C, + 0x0108FB, 0x001EBD, 0x0108FE, 0x001EAA, 0x001EAF, 0x0108FF, 0x001E79, 0x0108E1, + 0x0108E0, 0x001EBE, 0x0108E2, 0x0108E5, 0x0108E4, 0x0108E7, 0x0108E6, 0x001EBF, + 0x0108E8, 0x0108EB, 0x0108EA, 0x001EB9, 0x0108EC, 0x0108F4, 0x0108EE, 0x0108F2, + 0x001ED8, 0x01087C, 0x001E43, 0x0108F1, 0x01087D, 0x001ED4, 0x01086F, 0x010879, + 0x010869, 0x01086B, 0x001EDA, 0x0108F0, 0x01087E, 0x010864, 0x0108F5, 0x001ED5, + 0x001E40, 0x001E41, 0x001E42, 0x001E4D, 0x001E44, 0x001E45, 0x001E46, 0x001E47, + 0x001E48, 0x001E49, 0x001E4A, 0x001E4B, 0x001E7A, 0x001E5C, 0x001E4E, 0x001E4F, + 0x001E70, 0x001E73, 0x001E72, 0x001ED9, 0x001EDD, 0x001E71, 0x001E76, 0x001EDF, + 0x010901, 0x010902, 0x001E7B, 0x001E75, 0x001E4C, 0x001E77, 0x010907, 0x010922, + 0x010920, 0x001EDB, 0x010913, 0x010927, 0x010921, 0x010924, 0x010925, 0x010929, + 0x010928, 0x01092B, 0x01092A, 0x001EDE, 0x01092C, 0x010926, 0x01092E, 0x010910, + 0x010911, 0x010912, 0x001E83, 0x010914, 0x001E82, 0x010916, 0x010917, 0x010918, + 0x001E85, 0x001E81, 0x01091B, 0x01092D, 0x010915, 0x001E8A, 0x01092F, 0x001E86, + 0x001E8C, 0x001EBA, 0x001E90, 0x010900, 0x010905, 0x010906, 0x001E93, 0x001EB8, + 0x001E92, 0x001E8E, 0x01090B, 0x010904, 0x001E8B, 0x001E9C, 0x001E88, 0x001E84, + 0x001EA3, 0x001EB1, 0x001EB2, 0x001EB0, 0x001EB4, 0x001EA2, 0x001EB6, 0x001EB7, + 0x001EA1, 0x001E89, 0x001EA5, 0x001EBB, 0x001EB5, 0x001E8D, 0x001EA7, 0x001E8F, + 0x001EA8, 0x00A820, 0x001EA6, 0x001E91, 0x001E97, 0x00AA11, 0x00AA82, 0x010930, + 0x010931, 0x010932, 0x001EAB, 0x001EA4, 0x001EAC, 0x001EB3, 0x010937, 0x001EBC, + 0x001ED0, 0x001EC2, 0x001EC1, 0x001ED3, 0x00AA13, 0x001ED1, 0x001ED2, 0x00AA9D, + 0x01446D, 0x001ED6, 0x00AAB6, 0x014617, 0x001ED7, 0x001ECC, 0x014614, 0x00AAB1, + 0x010980, 0x001E94, 0x001E9D, 0x010985, 0x010984, 0x010987, 0x001E96, 0x001E95, + 0x001E98, 0x001E99, 0x001E9A, 0x001E9B, 0x001EFD, 0x001E9F, 0x001E9E, 0x000CAF, + 0x001EF0, 0x001EF1, 0x000CA3, 0x00A850, 0x001EF4, 0x001EF5, 0x001EF6, 0x001EF7, + 0x001EF8, 0x001EF9, 0x001EFA, 0x001EFB, 0x000CA2, 0x001EFF, 0x001EFE, 0x0109A1, + 0x0109A0, 0x0109A3, 0x0109A2, 0x0109A6, 0x001EF3, 0x0109A7, 0x0109A5, 0x0109AB, + 0x0109A8, 0x0109A9, 0x0109AA, 0x0109A4, 0x0109AC, 0x010923, 0x0109AE, 0x001EF2, + 0x001F2C, 0x001F2D, 0x001F2E, 0x010934, 0x010935, 0x010936, 0x001F24, 0x010938, + 0x010939, 0x001F28, 0x001F2F, 0x0109BD, 0x0109AD, 0x0109AF, 0x0109BE, 0x0109EC, + 0x000E52, 0x001F10, 0x014608, 0x01460B, 0x001F1D, 0x001F14, 0x000E50, 0x0109C3, + 0x0109EF, 0x001F18, 0x001F1B, 0x0109ED, 0x001F68, 0x001F19, 0x001F1A, 0x0109D5, + 0x0109DC, 0x001F23, 0x0109D2, 0x0109D3, 0x0109D4, 0x0109D7, 0x0109D6, 0x001F22, + 0x0109D8, 0x0109DB, 0x0109DA, 0x0109DE, 0x001F26, 0x001F21, 0x0109D9, 0x0109F0, + 0x0109F1, 0x0109F2, 0x0109E2, 0x0109E1, 0x0109E0, 0x0109E7, 0x0109F7, 0x0109EA, + 0x0109E5, 0x0109E8, 0x0109E9, 0x0109E4, 0x0109EE, 0x0109E6, 0x0109DD, 0x001F25, + 0x0109EB, 0x000E81, 0x001F43, 0x001F42, 0x000F43, 0x001F41, 0x001F40, 0x0109DF, + 0x000E09, 0x000E82, 0x001F78, 0x00AAE9, 0x00A81B, 0x001F44, 0x001F4C, 0x00AAE8, + 0x001F51, 0x001F50, 0x001F53, 0x001F52, 0x001F55, 0x001F54, 0x001F57, 0x001F56, + 0x001F59, 0x001F49, 0x001F5B, 0x001F4B, 0x001F5D, 0x001F45, 0x001F5F, 0x001F4D, + 0x010A00, 0x010A13, 0x001F6C, 0x010A15, 0x001F62, 0x00AA1B, 0x010A16, 0x001F63, + 0x001F48, 0x00AA14, 0x001F4A, 0x010A1F, 0x001F60, 0x001F61, 0x010A1D, 0x010A23, + 0x001F65, 0x001F66, 0x001F73, 0x001F72, 0x001F76, 0x001F71, 0x001F74, 0x001F75, + 0x000E9E, 0x001F69, 0x001F7B, 0x001F6D, 0x001F79, 0x001F7C, 0x001F7D, 0x010A31, + 0x00AA10, 0x010A33, 0x010A32, 0x010A30, 0x00157D, 0x000E0D, 0x000E0E, 0x00157E, + 0x001F98, 0x000E08, 0x000E0A, 0x00AA27, 0x000E0F, 0x00AA21, 0x00AA20, 0x001F9E, + 0x001F91, 0x001F93, 0x00157F, 0x001F90, 0x001F96, 0x001F94, 0x001F92, 0x001F95, + 0x001F99, 0x000F8B, 0x001F9B, 0x001F9A, 0x001F9D, 0x000F8A, 0x001F9F, 0x001F97, + 0x000E21, 0x000E22, 0x000E23, 0x000F59, 0x000E25, 0x000E9F, 0x000E27, 0x000E20, + 0x000F26, 0x000CAE, 0x000E2A, 0x000E2B, 0x000E28, 0x000E29, 0x000E26, 0x000E2F, + 0x000E99, 0x001578, 0x001579, 0x00157A, 0x00157B, 0x001574, 0x001575, 0x001576, + 0x001577, 0x001570, 0x001571, 0x000E96, 0x001572, 0x000E2D, 0x000E2E, 0x000E97, + 0x000F00, 0x001573, 0x001FC3, 0x001FC2, 0x00154C, 0x001FC4, 0x001FC7, 0x001FC6, + 0x001FC9, 0x00154D, 0x001FCB, 0x001FCA, 0x00154E, 0x001FCC, 0x00154F, 0x001548, + 0x000E54, 0x001549, 0x00154A, 0x00154B, 0x000E55, 0x000E56, 0x000E57, 0x000CDE, + 0x001544, 0x000E59, 0x001545, 0x001546, 0x000E58, 0x001547, 0x001540, 0x001541, + 0x001542, 0x001543, 0x00155C, 0x00152E, 0x00152F, 0x001528, 0x00158E, 0x00158F, + 0x001588, 0x001584, 0x001591, 0x00126D, 0x00127E, 0x00127F, 0x001278, 0x001279, + 0x00127A, 0x00127B, 0x001FF3, 0x001FF2, 0x001274, 0x001FF4, 0x001FF7, 0x001FF6, + 0x001FF9, 0x001FF8, 0x001FFB, 0x001FFA, 0x001275, 0x001276, 0x00AA25, 0x001277, + 0x00AA24, 0x001270, 0x00AA28, 0x001271, 0x001272, 0x001273, 0x00124C, 0x00124D, + 0x01E8AC, 0x01E8AD, 0x01E8BC, 0x01E8BD, 0x01E8BF, 0x01E8B5, 0x00AA57, 0x010AC1, + 0x010AC0, 0x010AC3, 0x010AC2, 0x010AC5, 0x010AC4, 0x010AC7, 0x010AC6, 0x00120E, + 0x00120F, 0x010ACB, 0x001208, 0x010ACD, 0x010ACC, 0x010ACF, 0x010ACE, 0x010AD1, + 0x001209, 0x010AD3, 0x00AA52, 0x00AA53, 0x00AA50, 0x00AA51, 0x010AD6, 0x010AD9, + 0x00120A, 0x001201, 0x010ADA, 0x010ADD, 0x010ADC, 0x001202, 0x010ADE, 0x010AE1, + 0x010AE0, 0x010AE3, 0x010AE2, 0x0012E8, 0x010AE4, 0x00FC5D, 0x00FC5E, 0x00FC58, + 0x00FC3F, 0x010AEB, 0x00FC3B, 0x010AED, 0x010AEC, 0x010AEF, 0x010AEE, 0x00FC34, + 0x00FC35, 0x00FC36, 0x00FC37, 0x00FC30, 0x00FC31, 0x00FC32, 0x00FC0C, 0x00FC0D, + 0x00FC0E, 0x00FC13, 0x00FCEC, 0x00FCED, 0x00FCEE, 0x00FCEA, 0x00FCA5, 0x010B10, + 0x010B11, 0x010B1C, 0x00FCA6, 0x010B14, 0x010B15, 0x010B16, 0x010B17, 0x010B18, + 0x010B19, 0x010B1A, 0x010B1B, 0x00FCA0, 0x010B1D, 0x010B1E, 0x010B1F, 0x010B02, + 0x010B01, 0x010B13, 0x010B12, 0x010B00, 0x010B05, 0x00FC8D, 0x010B07, 0x00FC8E, + 0x00FC85, 0x010B04, 0x010B0A, 0x010B06, 0x00FC86, 0x0013BD, 0x0013BE, 0x0013BF, + 0x0013B8, 0x0013B9, 0x010B03, 0x0013BA, 0x0013BB, 0x0013B4, 0x0013B5, 0x0013B6, + 0x0013B7, 0x0013B0, 0x0013B1, 0x0013B2, 0x0013B3, 0x00138C, 0x010B09, 0x00FD53, + 0x00FD2C, 0x00FD2D, 0x00FD2E, 0x00FD2F, 0x00FD28, 0x00FD29, 0x00FD2A, 0x00FD2B, + 0x00FD24, 0x00FD25, 0x00FD26, 0x00FD27, 0x00FD20, 0x00FD21, 0x00FD22, 0x00FD23, + 0x010B23, 0x00FD3C, 0x010B33, 0x00106F, 0x00FD38, 0x00FD39, 0x00FD3A, 0x00FD3B, + 0x00FD36, 0x00FD37, 0x00FD31, 0x00FD32, 0x00FD0B, 0x00FD00, 0x00FD01, 0x010B30, + 0x010B31, 0x010B32, 0x010B52, 0x010B34, 0x010B35, 0x010B50, 0x010B51, 0x010B54, + 0x010B58, 0x010B5B, 0x010B5F, 0x010B55, 0x010B0B, 0x00FD02, 0x010B08, 0x00FD03, + 0x010B0D, 0x010B0E, 0x00FD1C, 0x00FD1D, 0x00FD1E, 0x00FD19, 0x00FD1A, 0x00105D, + 0x00105A, 0x00105B, 0x001054, 0x001055, 0x001050, 0x001051, 0x010B0F, 0x001052, + 0x001053, 0x001028, 0x00FDFA, 0x00FDF3, 0x00103F, 0x00FDC4, 0x00FDC5, 0x00FDC6, + 0x00FDC7, 0x00FDC0, 0x00FDC1, 0x010B0C, 0x00FDC2, 0x00100D, 0x00100E, 0x00100F, + 0x001008, 0x010B83, 0x001009, 0x00100A, 0x010B82, 0x00100B, 0x001004, 0x001005, + 0x001006, 0x001007, 0x001000, 0x010B81, 0x001001, 0x001002, 0x001003, 0x010B80, + 0x00101C, 0x010B91, 0x010B90, 0x010B84, 0x010B85, 0x010B86, 0x010B87, 0x010B88, + 0x010B89, 0x010B8A, 0x010B8B, 0x010B8E, 0x010B8D, 0x00FDB3, 0x010B8F, 0x00FD8A, + 0x010BAC, 0x00FD83, 0x00FD9D, 0x00FD9E, 0x010BAE, 0x00FD9F, 0x00FD98, 0x010BA9, + 0x010BAB, 0x010BAF, 0x010BAA, 0x00FD99, 0x010B8C, 0x00FD9A, 0x010BAD, 0x00FD95, + 0x0010C1, 0x0010C2, 0x0010DF, 0x002102, 0x0010D8, 0x00FA43, 0x002107, 0x00FA5C, + 0x00FA5E, 0x00FA5F, 0x00210B, 0x00210A, 0x00210D, 0x00210C, 0x00210F, 0x00210E, + 0x00FA58, 0x00FA59, 0x00FA5A, 0x00FA5B, 0x00FA54, 0x00FA55, 0x00FA56, 0x00FA51, + 0x00FA52, 0x00FA53, 0x00FA2C, 0x00FA2D, 0x00FA2E, 0x00211C, 0x00FA29, 0x00FA2A, + 0x00115D, 0x00115E, 0x00115F, 0x001158, 0x001159, 0x00115A, 0x00115B, 0x001154, + 0x001155, 0x001156, 0x001157, 0x001150, 0x001151, 0x00212C, 0x001152, 0x001153, + 0x002131, 0x002130, 0x002133, 0x002132, 0x002135, 0x002134, 0x002137, 0x002136, + 0x00112C, 0x002138, 0x00112D, 0x00112E, 0x00213D, 0x00112F, 0x00213F, 0x00213E, + 0x001128, 0x001129, 0x00112A, 0x00112B, 0x001124, 0x001125, 0x002147, 0x002146, + 0x001126, 0x001127, 0x001120, 0x002148, 0x00214E, 0x001121, 0x001122, 0x001123, + 0x002151, 0x00113C, 0x002153, 0x002152, 0x002155, 0x002154, 0x00110D, 0x00110E, + 0x00110F, 0x002158, 0x001108, 0x00110B, 0x00215D, 0x00215C, 0x00215F, 0x00215E, + 0x002171, 0x001104, 0x002163, 0x002162, 0x0011B6, 0x002161, 0x0011B3, 0x00119A, + 0x00FB23, 0x00FB3C, 0x00FB3E, 0x00FB38, 0x00FB39, 0x00FB3A, 0x00FB3B, 0x00216C, + 0x00FB34, 0x00FB35, 0x00FB36, 0x00FB30, 0x00FB31, 0x00FB32, 0x00FB33, 0x00FB04, + 0x00FB05, 0x00FB06, 0x00FB00, 0x00FB01, 0x00FB02, 0x00217C, 0x00FB03, 0x00FB1D, + 0x00FB1F, 0x000E44, 0x002183, 0x00FB15, 0x002182, 0x002184, 0x00FB16, 0x002181, + 0x002189, 0x002185, 0x000E41, 0x000E42, 0x002188, 0x000E43, 0x00FB13, 0x002186, + 0x00FBEC, 0x00FBED, 0x00FBEE, 0x00FBE9, 0x00FBEA, 0x00FBF3, 0x000E30, 0x000E32, + 0x000E33, 0x000E0C, 0x00FBD7, 0x000E01, 0x000E02, 0x000E03, 0x00AA67, 0x00AA60, + 0x00AA61, 0x00AA62, 0x00AA63, 0x00AA7E, 0x00AA7F, 0x00AA7A, 0x00FBB0, 0x00AA75, + 0x00AA76, 0x00FB8C, 0x00FB8D, 0x00AA8F, 0x00FB89, 0x00FB8A, 0x00FB8B, 0x00FB84, + 0x00FB98, 0x00FB99, 0x00FB9A, 0x00FB94, 0x000ED4, 0x000ED5, 0x000ED7, 0x000ED0, + 0x000ED1, 0x00AA26, 0x00AA22, 0x00AA23, 0x000EAA, 0x000EAB, 0x000EA5, 0x000EA7, + 0x000EA1, 0x000EA2, 0x00AA8D, 0x000EA3, 0x000EBD, 0x00AA8C, 0x00AA0C, 0x00AA0D, + 0x00AA8E, 0x00AA0E, 0x00AA0F, 0x00AA08, 0x00AA09, 0x00AA0B, 0x00AA06, 0x00AA00, + 0x00AA01, 0x00AA03, 0x00AA1D, 0x00AA1F, 0x00AA18, 0x00AA1A, 0x00AA15, 0x00AA12, + 0x000E9A, 0x000E9B, 0x000E94, 0x000E95, 0x00AAEA, 0x00AAE4, 0x00AAE5, 0x00AAE7, + 0x00AAE0, 0x00AAE1, 0x00AA17, 0x000F6A, 0x000F6B, 0x000F64, 0x000F65, 0x000F66, + 0x000F67, 0x000F60, 0x000F61, 0x000F62, 0x000F63, 0x014645, 0x014646, 0x014640, + 0x014641, 0x014642, 0x014643, 0x000F4C, 0x000F4D, 0x000F4F, 0x00AAC2, 0x000F49, + 0x000F4B, 0x000F44, 0x000F45, 0x000F46, 0x000F47, 0x014609, 0x01460A, 0x014604, + 0x014605, 0x00AA9B, 0x00AA94, 0x00AA95, 0x00AA16, 0x00AA96, 0x00AA97, 0x00AA90, + 0x00AA1E, 0x00AA91, 0x00AA92, 0x00AA93, 0x00AB64, 0x00AB65, 0x00AB60, 0x00AB61, + 0x00AB62, 0x00AB63, 0x00AB7C, 0x00AB7D, 0x00AB7E, 0x00AB7F, 0x00AB78, 0x00AB79, + 0x00AB7A, 0x00AB7B, 0x00AB74, 0x00AB75, 0x00AB76, 0x00AB77, 0x00AB70, 0x00AB71, + 0x00AB72, 0x00AB73, 0x00AB4C, 0x00AB4D, 0x00AB4E, 0x00AB4F, 0x00AB48, 0x00AB49, + 0x00AB4A, 0x00AB4B, 0x00AB44, 0x00AB45, 0x00AB46, 0x00AB47, 0x00AB40, 0x00AB41, + 0x00AB42, 0x00AB43, 0x00AB58, 0x00AB59, 0x00AB5A, 0x00AB54, 0x00AB55, 0x00AB56, + 0x00F964, 0x00F97C, 0x00F944, 0x00F945, 0x00F95C, 0x00F95D, 0x00F95B, 0x00F954, + 0x00F955, 0x00F956, 0x00F957, 0x00F950, 0x00F92C, 0x00F92D, 0x00F929, 0x00F92A, + 0x00F92B, 0x00F924, 0x00AAC0, 0x00F925, 0x00AAE2, 0x00AAE6, 0x00F926, 0x00F927, + 0x00F920, 0x00F921, 0x00F922, 0x00F93B, 0x00F934, 0x00F9BB, 0x00F9B4, 0x00F9B1, + 0x00F9B2, 0x00F9B3, 0x00F98C, 0x00A857, 0x00A851, 0x00A852, 0x00A853, 0x000CAC, + 0x000CAD, 0x000CAA, 0x000CAB, 0x000CA4, 0x000CA5, 0x000CA6, 0x00AADC, 0x000CA7, + 0x000CA0, 0x000CA1, 0x000CBD, 0x00A830, 0x00A831, 0x00A80C, 0x00A80D, 0x00A80E, + 0x000CB1, 0x000C8C, 0x00A807, 0x000C88, 0x00A81E, 0x01447D, 0x014470, 0x014471, + 0x014458, 0x014459, 0x01445B, 0x014454, 0x014455, 0x014456, 0x014457, 0x014450, + 0x014451, 0x01442C, 0x01442D, 0x014408, 0x0144F0, 0x0144F1, 0x00AAE3, 0x0144C6, + 0x0144C7, 0x0144C0, 0x0144C1, 0x0144C2, 0x0144C3, 0x0144DC, 0x0144DD, 0x0144D9, + 0x0144D6, 0x0144D7, 0x0144D3, 0x0144A8, 0x0144A9, 0x0144AA, 0x0144AB, 0x0144A4, + 0x0144A5, 0x0144A6, 0x0144A7, 0x0144A0, 0x00AA1C, 0x0144A1, 0x0144A2, 0x0144A3, + 0x0144BC, 0x0144BD, 0x00AA19, 0x014571, 0x014546, 0x014547, 0x014541, 0x014542, + 0x014543, 0x01455C, 0x01455D, 0x014558, 0x014559, 0x01455A, 0x01455B, 0x014554, + 0x014555, 0x014556, 0x014557, 0x014550, 0x014551, 0x01452C, 0x01452D, 0x014508, + 0x014509, 0x01451A, 0x0145F0, 0x0145F1, 0x0145CE, 0x0145CF, 0x0145C8, 0x0145C9, + 0x0145CA, 0x0145CB, 0x0145C4, 0x0145A6, 0x0145A7, 0x0145A0, 0x0145A1, 0x014588, + 0x01458A, 0x01458B, 0x014586, 0x014587, 0x014580, 0x00A61A, 0x00A61B, 0x00A614, + 0x00A615, 0x00A6E4, 0x000B6A, 0x000B6B, 0x000B66, 0x000B67, 0x000B60, 0x000B61, + 0x00A6CC, 0x00A6CD, 0x00A6CA, 0x00A6C6, 0x00A6C7, 0x00A6C0, 0x00A6C1, 0x00A6C2, + 0x00A6C3, 0x00A6DC, 0x00A6DD, 0x00A6DE, 0x00A6DF, 0x00A6D8, 0x00A6D9, 0x00A6DA, + 0x00A6DB, 0x00A6D4, 0x00A6D5, 0x00A6D0, 0x00A6D2, 0x00A6D3, 0x00A6AC, 0x00A6AD, + 0x00A6AE, 0x00AA02, 0x00A6AF, 0x00A6A8, 0x00A6A9, 0x00A6AA, 0x00A6AB, 0x00A6A4, + 0x00A6A5, 0x00A6A3, 0x00A6B6, 0x00A6B0, 0x00A6B1, 0x00A68C, 0x00A68D, 0x00A68E, + 0x00A68B, 0x00A687, 0x00AAF2, 0x00A680, 0x000B0A, 0x000B0B, 0x000B05, 0x00A69A, + 0x00A69B, 0x00A694, 0x00A695, 0x00A76B, 0x00A764, 0x00A77E, 0x00A77F, 0x00A77A, + 0x00A77B, 0x00A774, 0x00A775, 0x00A776, 0x00A777, 0x00A771, 0x00A772, 0x00A773, + 0x00A74C, 0x00A74D, 0x00A74E, 0x00A74F, 0x00AA07, 0x00A748, 0x00A749, 0x00A745, + 0x00A746, 0x00A747, 0x00A740, 0x00A741, 0x00A742, 0x00A743, 0x00A75C, 0x00A75D, + 0x00A75E, 0x00A75F, 0x00A758, 0x00A759, 0x00A75A, 0x00A75B, 0x00A754, 0x00A755, + 0x00A756, 0x00A757, 0x00A750, 0x00A751, 0x00A752, 0x00A753, 0x00A72C, 0x00A72D, + 0x00A72E, 0x00A72F, 0x00A728, 0x00A729, 0x00A72B, 0x00A724, 0x00A725, 0x00A726, + 0x00A727, 0x000BAE, 0x000BAF, 0x00A73D, 0x00A73F, 0x00A738, 0x00A739, 0x00A73A, + 0x00A73B, 0x00A734, 0x00A736, 0x00A737, 0x00A730, 0x00A731, 0x000BB4, 0x000BB5, + 0x000BB6, 0x000BB7, 0x000BB0, 0x000BB1, 0x000BB2, 0x000BB3, 0x000B8E, 0x000B8F, + 0x000B88, 0x000B89, 0x000B8A, 0x000B85, 0x000B86, 0x000B87, 0x000B83, 0x000B9C, + 0x000B9E, 0x000B9F, 0x000B99, 0x000B9A, 0x000B94, 0x000B95, 0x000B90, 0x000B92, + 0x000B93, 0x000868, 0x000869, 0x00A7FD, 0x000866, 0x000867, 0x000862, 0x000863, + 0x00A7F7, 0x00084C, 0x00084D, 0x00084E, 0x00084F, 0x000848, 0x000849, 0x00084A, + 0x00084B, 0x000844, 0x00AA04, 0x00AA0A, 0x000845, 0x000846, 0x00AA05, 0x000847, + 0x000840, 0x000841, 0x000842, 0x000843, 0x000858, 0x00A7AC, 0x00A7AD, 0x000855, + 0x00A7A6, 0x00A7A7, 0x00A7A0, 0x00A7A1, 0x00A7A2, 0x00A7A3, 0x00A7B4, 0x00A7B5, + 0x00A7B6, 0x00A7B7, 0x00A7B0, 0x00A7B1, 0x00A7B2, 0x00A7B3, 0x00A78C, 0x00A78D, + 0x00A78E, 0x00A78F, 0x00A78B, 0x00A784, 0x00A785, 0x00A796, 0x00A797, 0x00A790, + 0x00A791, 0x00A792, 0x00A793, 0x00A46C, 0x00A46D, 0x00A468, 0x00A469, 0x00A466, + 0x00A467, 0x00A460, 0x00A461, 0x00A462, 0x00A463, 0x00A47C, 0x00A47D, 0x00A47E, + 0x00A47F, 0x00A478, 0x00A479, 0x00A47A, 0x00A47B, 0x00A474, 0x00A475, 0x00A476, + 0x00A477, 0x00A470, 0x00A471, 0x00A472, 0x00A473, 0x00A44C, 0x00A44D, 0x00A44E, + 0x00A44F, 0x00A448, 0x00A449, 0x00A44A, 0x00A44B, 0x00A444, 0x00A445, 0x00A446, + 0x00A447, 0x00A440, 0x00A441, 0x00A442, 0x00A443, 0x00A45C, 0x00A45D, 0x00A45E, + 0x00A45F, 0x00A458, 0x00A459, 0x00A45A, 0x00A45B, 0x00A454, 0x00A455, 0x00A456, + 0x00A457, 0x00A450, 0x00A451, 0x00A452, 0x00A453, 0x00A42C, 0x00A42D, 0x00A42E, + 0x00A42F, 0x00A428, 0x00A429, 0x00A42A, 0x00A42B, 0x00A424, 0x00A425, 0x00A430, + 0x00A431, 0x00A40F, 0x00A406, 0x00A407, 0x00A400, 0x00A401, 0x00A402, 0x00A403, + 0x00A41C, 0x00A41D, 0x00A41E, 0x00A41F, 0x00A418, 0x00A419, 0x00A41A, 0x00A41B, + 0x00A414, 0x00A415, 0x00A416, 0x00A417, 0x00A410, 0x00A411, 0x00A412, 0x00A413, + 0x00A4EC, 0x00A4ED, 0x00A4EE, 0x00A4EF, 0x00A4E8, 0x00A4E9, 0x00A4EA, 0x00A4EB, + 0x00A4E4, 0x00A4E5, 0x00096A, 0x00096B, 0x000966, 0x000967, 0x000960, 0x000961, + 0x00A4F4, 0x00A4F5, 0x00097A, 0x00097B, 0x000974, 0x000975, 0x000976, 0x000977, + 0x000972, 0x000973, 0x00A4DC, 0x00A4DD, 0x00A4DE, 0x00A4DF, 0x00A4D8, 0x00A4D9, + 0x00A4DA, 0x00A4DB, 0x00A4D4, 0x00A4D5, 0x00095A, 0x00095B, 0x000950, 0x00092C, + 0x00092D, 0x00092E, 0x00092F, 0x000928, 0x000929, 0x00092A, 0x00092B, 0x000924, + 0x000925, 0x000926, 0x000927, 0x000920, 0x000921, 0x000922, 0x000923, 0x00093D, + 0x000938, 0x000939, 0x00A48C, 0x000934, 0x000935, 0x00090A, 0x00090B, 0x000904, + 0x000905, 0x000906, 0x000907, 0x00091C, 0x00091D, 0x00091E, 0x00091F, 0x000918, + 0x000919, 0x00A57E, 0x00A57F, 0x00A574, 0x00A575, 0x00A577, 0x00A570, 0x00A571, + 0x00A54C, 0x00A54D, 0x00A544, 0x00A545, 0x00A546, 0x00A547, 0x00A541, 0x00A542, + 0x00A543, 0x00A55C, 0x00A55D, 0x00A55E, 0x00A55F, 0x00A558, 0x00A559, 0x00A55A, + 0x00A55B, 0x002460, 0x00A554, 0x00A555, 0x00A550, 0x002464, 0x002467, 0x00A552, + 0x002469, 0x002468, 0x00246B, 0x00246A, 0x00246D, 0x00246C, 0x00246F, 0x00246E, + 0x00A553, 0x002470, 0x00A52C, 0x00A52D, 0x002475, 0x002474, 0x002477, 0x002476, + 0x002479, 0x002478, 0x00247B, 0x00247A, 0x00247D, 0x00A52E, 0x00247F, 0x00247E, + 0x00A52F, 0x00A528, 0x00A529, 0x00A52A, 0x00A52B, 0x00A524, 0x00A525, 0x00A523, + 0x00A536, 0x00A530, 0x00A531, 0x00A50C, 0x00A50D, 0x00A50E, 0x00A50F, 0x00A50B, + 0x00A505, 0x00A507, 0x00A500, 0x00A51E, 0x00A51B, 0x00A514, 0x00A515, 0x00A5EB, + 0x00A5E4, 0x00A5E6, 0x00A5E7, 0x00A5FC, 0x00A5FD, 0x00A5CA, 0x00A5C6, 0x00A5C7, + 0x00A5C0, 0x00A5C1, 0x00A5DD, 0x00A5DA, 0x00A5D6, 0x00A5D7, 0x00A5D0, 0x00A5D1, + 0x00A5D2, 0x00A5D3, 0x00A5AC, 0x00A5AD, 0x00A5AE, 0x00A5AF, 0x00A5A8, 0x00A5A9, + 0x00A5AA, 0x00A5AB, 0x00A5A4, 0x00A5A5, 0x00A586, 0x00A587, 0x00A580, 0x00A581, + 0x00A582, 0x00A583, 0x00A59C, 0x00A59D, 0x00A59E, 0x00A59F, 0x00A598, 0x00A599, + 0x00A59A, 0x00A59B, 0x00A594, 0x00A595, 0x00A596, 0x00A597, 0x00A590, 0x00A591, + 0x00A592, 0x00A593, 0x00A26C, 0x00A26D, 0x00A26E, 0x00A26F, 0x00A268, 0x00A269, + 0x00A26A, 0x00A26B, 0x00A264, 0x00A265, 0x00A266, 0x00A267, 0x00A262, 0x00A263, + 0x00A27C, 0x00A27D, 0x00A27E, 0x00A27F, 0x00A278, 0x00A279, 0x00A27A, 0x00A27B, + 0x00A274, 0x00A275, 0x00A277, 0x00A270, 0x00A256, 0x00A257, 0x00A250, 0x00A251, + 0x00A252, 0x00A253, 0x00A22C, 0x00A22D, 0x00A22E, 0x0024EC, 0x00A228, 0x00A229, + 0x00A2C6, 0x0024F0, 0x00A2C2, 0x00A2C3, 0x0024F5, 0x0024F4, 0x0024F7, 0x0024F6, + 0x0024F9, 0x0024F8, 0x0024FB, 0x0024FA, 0x0024FD, 0x00A2DC, 0x0024FF, 0x0024FE, + 0x00A2DD, 0x00A2DE, 0x00A2DF, 0x00A2D8, 0x00A2D9, 0x00A2DA, 0x00A2DB, 0x00A2D4, + 0x00A2D5, 0x00A2B6, 0x00A2B7, 0x00A2B0, 0x00A2B1, 0x00A2B2, 0x00A2B3, 0x00A28C, + 0x00A28D, 0x00A28E, 0x00A28F, 0x00A288, 0x00A289, 0x00A28A, 0x00A28B, 0x00A284, + 0x00A285, 0x00A286, 0x00A287, 0x00A280, 0x00A281, 0x00A282, 0x00A283, 0x00A29C, + 0x00A29D, 0x00A29E, 0x00A29F, 0x00A298, 0x00A299, 0x00A29A, 0x00A29B, 0x00A294, + 0x014628, 0x00A295, 0x00A36B, 0x00A366, 0x00A367, 0x00A360, 0x00A361, 0x00A37D, + 0x00A376, 0x00A377, 0x00A370, 0x00A371, 0x00A372, 0x00A373, 0x00A34C, 0x00A34D, + 0x00A34E, 0x00A34F, 0x00A348, 0x00A349, 0x00A34A, 0x00A34B, 0x00A344, 0x00A345, + 0x00A326, 0x00A327, 0x00A320, 0x00A321, 0x00A322, 0x00A323, 0x00A33C, 0x00A33D, + 0x00A338, 0x014629, 0x00A339, 0x00A336, 0x00A337, 0x00A330, 0x00A331, 0x00A332, + 0x00A333, 0x00A30C, 0x00A30D, 0x011005, 0x00A30E, 0x00A30F, 0x011006, 0x011009, + 0x011008, 0x00A308, 0x01100A, 0x01100D, 0x01100C, 0x01100F, 0x01100E, 0x00A309, + 0x00A30A, 0x00A304, 0x00A305, 0x00A002, 0x00A003, 0x00A01E, 0x00A01F, 0x00A018, + 0x00A019, 0x00A014, 0x00A0FA, 0x00A0D6, 0x00A0D7, 0x00A0D0, 0x00A0D1, 0x00A0D2, + 0x00A0D3, 0x00A0AC, 0x00A0AD, 0x00A0A9, 0x00A08A, 0x00A166, 0x00A167, 0x00A160, + 0x00A161, 0x00A17D, 0x00A176, 0x00A177, 0x00A170, 0x00A171, 0x00A172, 0x00A173, + 0x00A14C, 0x011033, 0x00A14D, 0x00A14E, 0x00A14F, 0x00A148, 0x00A149, 0x00A145, + 0x00A146, 0x00A147, 0x00A140, 0x00A141, 0x00A142, 0x00A143, 0x00A15C, 0x00A15D, + 0x00A15E, 0x00A15F, 0x00A158, 0x00A159, 0x00A15A, 0x00A15B, 0x00A154, 0x00A155, + 0x00A126, 0x00A127, 0x00A120, 0x00A121, 0x00A122, 0x00A123, 0x00A13C, 0x00A13D, + 0x00A13E, 0x00A13F, 0x00A138, 0x00A139, 0x00A13A, 0x00A13B, 0x00A134, 0x00A135, + 0x00A136, 0x00A137, 0x00A130, 0x00A131, 0x00A132, 0x00A133, 0x00A10C, 0x00A10D, + 0x00A10E, 0x00A10F, 0x00A108, 0x00A109, 0x00A10A, 0x00A10B, 0x00A104, 0x00A105, + 0x00A106, 0x00A107, 0x00A100, 0x00A101, 0x00A102, 0x00A103, 0x00A11C, 0x00A11D, + 0x00A116, 0x00A117, 0x00A110, 0x00A111, 0x00A112, 0x00A113, 0x00A1EC, 0x00A1ED, + 0x00A1EE, 0x00A1EF, 0x00A1E8, 0x00A1E9, 0x00A1EA, 0x00A1EB, 0x00A1E4, 0x00A1E5, + 0x00021A, 0x00021B, 0x000214, 0x000215, 0x000216, 0x000217, 0x000210, 0x000211, + 0x000212, 0x000213, 0x0002AC, 0x0002AD, 0x0002AE, 0x0002AF, 0x0002A8, 0x0002A9, + 0x0002AA, 0x0002AB, 0x0002A4, 0x0002A5, 0x0002A6, 0x0002A7, 0x0002A0, 0x0002A1, + 0x0002A2, 0x0002A3, 0x00028C, 0x00028D, 0x00028E, 0x00028F, 0x000288, 0x000289, + 0x00028A, 0x00028B, 0x000284, 0x000285, 0x000286, 0x000287, 0x000280, 0x000281, + 0x000282, 0x000283, 0x00029C, 0x00029D, 0x00029E, 0x00029F, 0x000298, 0x000299, + 0x00029A, 0x00029B, 0x000294, 0x000295, 0x000296, 0x000297, 0x000290, 0x000291, + 0x000292, 0x000293, 0x00037C, 0x00037D, 0x00037F, 0x00037B, 0x000376, 0x000377, + 0x000370, 0x000371, 0x000372, 0x000373, 0x01D66C, 0x01D66D, 0x01D66E, 0x01D66F, + 0x01D668, 0x01D669, 0x01D66A, 0x01D66B, 0x01D664, 0x01D665, 0x01D666, 0x01D667, + 0x01D660, 0x01D661, 0x01D662, 0x01D663, 0x01D67C, 0x01D67D, 0x01D67E, 0x01D67F, + 0x01D678, 0x01D679, 0x01D67A, 0x01D67B, 0x01D674, 0x01D675, 0x01D676, 0x01D677, + 0x01D670, 0x01D671, 0x01D654, 0x01D600, 0x01D613, 0x01D6E9, 0x01D6EA, 0x01D6EB, + 0x01D6E5, 0x01D6E6, 0x01D6E7, 0x01D6E0, 0x01D6E1, 0x000395, 0x01D6C6, 0x000063, + 0x01D6C2, 0x01D6C3, 0x01D6DC, 0x01D6DD, 0x01D6D9, 0x000075, 0x000041, 0x01D6A2, + 0x01D6A3, 0x01D6BC, 0x01D6BD, 0x01D6B9, 0x01D6B2, 0x01D6B3, 0x01D68C, 0x01D68D, + 0x01D68E, 0x01D68F, 0x01D688, 0x011105, 0x011104, 0x011107, 0x011106, 0x011109, + 0x011108, 0x01110B, 0x01110A, 0x01110D, 0x01110C, 0x01110F, 0x01110E, 0x01D689, + 0x01D68A, 0x01D68B, 0x01D684, 0x01D685, 0x01D686, 0x01D687, 0x01D680, 0x01D681, + 0x01D682, 0x01D683, 0x01D69C, 0x01D69D, 0x01D698, 0x01D699, 0x01D692, 0x011121, + 0x011120, 0x011123, 0x011122, 0x01D693, 0x01D76C, 0x01D76D, 0x01D76E, 0x01D768, + 0x01D769, 0x01D76A, 0x01D76B, 0x01D764, 0x01D765, 0x01D766, 0x01D767, 0x01D760, + 0x01D761, 0x01D762, 0x01D763, 0x01D77C, 0x01D77D, 0x011137, 0x011136, 0x011139, + 0x011138, 0x01113B, 0x01113A, 0x01113D, 0x01113C, 0x01113F, 0x01113E, 0x01D77E, + 0x01D77F, 0x01D778, 0x01D779, 0x01D77A, 0x01D77B, 0x01D774, 0x01D775, 0x01D776, + 0x01D777, 0x01D770, 0x01D771, 0x0000E9, 0x01D755, 0x01D732, 0x01D733, 0x011151, + 0x011150, 0x01D70C, 0x011152, 0x011155, 0x011154, 0x011157, 0x011156, 0x011159, + 0x011158, 0x01115B, 0x01115A, 0x01115D, 0x01115C, 0x01115F, 0x01115E, 0x01D70D, + 0x01D70E, 0x01D70F, 0x01D709, 0x01D70A, 0x01D70B, 0x01D704, 0x01D705, 0x01D706, + 0x01D707, 0x01D700, 0x01D701, 0x01D71D, 0x01D71E, 0x01D719, 0x01D71A, 0x01D714, + 0x01D716, 0x01D717, 0x01E924, 0x01E925, 0x01D712, 0x01E927, 0x01D713, 0x01D7EC, + 0x01D7ED, 0x01D7EE, 0x01D7EF, 0x01D7E8, 0x01D7E9, 0x01D7EA, 0x01D7EB, 0x01D7E4, + 0x01D7E5, 0x01D7E6, 0x01D7E7, 0x011185, 0x011184, 0x011187, 0x011186, 0x011189, + 0x011188, 0x01118B, 0x01118A, 0x01118D, 0x01118C, 0x01118F, 0x01118E, 0x01D7E0, + 0x01D7E1, 0x01D7E2, 0x01D7E3, 0x01D7FC, 0x01D7FD, 0x01D7FE, 0x01D7FF, 0x01D7F8, + 0x01D7F9, 0x01D7FA, 0x01D7FB, 0x01D7F4, 0x01D7F5, 0x01D7F6, 0x01D7F7, 0x01D7F0, + 0x01D7F1, 0x0111A3, 0x00016E, 0x00016F, 0x00017D, 0x00014B, 0x00012B, 0x0001F7, + 0x01D4F2, 0x01D4F3, 0x01D4CC, 0x01D4CD, 0x01D4CE, 0x01D4CF, 0x01D4C8, 0x01D4C9, + 0x01D4CA, 0x01D4CB, 0x01D4C5, 0x01D4C6, 0x01D4C7, 0x01D4C0, 0x01D4C1, 0x01D4C2, + 0x01D4C3, 0x01D4DC, 0x01D4DD, 0x01D4DE, 0x01D4DF, 0x01D4D8, 0x01D4D9, 0x01D4DA, + 0x01D4DB, 0x01D4D4, 0x01D4D5, 0x01D4D6, 0x01D4D7, 0x01D4D0, 0x01D4D1, 0x01D4D2, + 0x01D4D3, 0x01D4AC, 0x01D4AE, 0x01D4AF, 0x01D4A9, 0x01D4AA, 0x01D4AB, 0x01D4A5, + 0x01D4A6, 0x01D4A2, 0x01D4BD, 0x01D4BE, 0x01D4BF, 0x01D4B8, 0x01D4B9, 0x01D4BB, + 0x01D4B4, 0x01D4B5, 0x01D4B6, 0x01D4B7, 0x01D4B0, 0x01D4B1, 0x01D4B2, 0x01D4B3, + 0x01D48C, 0x01D48D, 0x01D48E, 0x01D48F, 0x01D488, 0x01D489, 0x01D48A, 0x01D48B, + 0x01D484, 0x01D485, 0x01D486, 0x01D487, 0x01D480, 0x01D481, 0x01D482, 0x01D483, + 0x01D49C, 0x01D49E, 0x01D49F, 0x01D498, 0x01D499, 0x01D49A, 0x01D49B, 0x01D494, + 0x01D495, 0x01D496, 0x01D497, 0x01D490, 0x01D491, 0x01D492, 0x01D493, 0x01D56C, + 0x01D56D, 0x01D56E, 0x01D56F, 0x01D568, 0x01D569, 0x01D56A, 0x01D56B, 0x01D564, + 0x01D565, 0x01D566, 0x01D567, 0x01D560, 0x01D561, 0x01D562, 0x01D563, 0x01D57C, + 0x01D57D, 0x01D57E, 0x01D57F, 0x01D578, 0x01D579, 0x01D57A, 0x01D57B, 0x01D574, + 0x01D575, 0x01D576, 0x01D577, 0x01D570, 0x01D571, 0x01D572, 0x01D573, 0x01D54C, + 0x01D54D, 0x01D54E, 0x01D54F, 0x01D54A, 0x01D54B, 0x01D544, 0x002777, 0x002776, + 0x002779, 0x002778, 0x00277B, 0x00277A, 0x00277D, 0x00277C, 0x00277F, 0x00277E, + 0x002781, 0x002780, 0x002783, 0x002782, 0x002785, 0x002784, 0x002787, 0x002786, + 0x002789, 0x002788, 0x00278B, 0x00278A, 0x00278D, 0x01D546, 0x00278F, 0x00278E, + 0x002791, 0x01D540, 0x002793, 0x002792, 0x01D541, 0x01D542, 0x01D543, 0x01D55C, + 0x01D55D, 0x01D55E, 0x01D55F, 0x01D558, 0x01D559, 0x01D55A, 0x01D55B, 0x01D554, + 0x01D555, 0x01D556, 0x01D557, 0x01D550, 0x01D552, 0x01D553, 0x01D52C, 0x01D52D, + 0x01D52E, 0x01D52F, 0x01D528, 0x01D529, 0x01D52A, 0x01D52B, 0x01D524, 0x01D525, + 0x01D526, 0x01D527, 0x01E914, 0x01D520, 0x01D521, 0x01E917, 0x01D522, 0x01D523, + 0x01D53C, 0x01D53D, 0x01D53E, 0x01E91D, 0x01D538, 0x01D539, 0x01D53B, 0x01D534, + 0x01D535, 0x01D536, 0x01D537, 0x01D530, 0x01D531, 0x01D532, 0x01D533, 0x01D50D, + 0x01D50E, 0x01D50F, 0x01D508, 0x01D509, 0x01D50A, 0x01D504, 0x01D505, 0x01D507, + 0x01D500, 0x01D501, 0x01D502, 0x01E935, 0x01D503, 0x01D51C, 0x01D51E, 0x01D51F, + 0x01D518, 0x01D519, 0x01D51A, 0x01D51B, 0x01D514, 0x01D516, 0x01D517, 0x01D510, + 0x01D511, 0x01D512, 0x01D513, 0x01D5EC, 0x01D5ED, 0x01D5EE, 0x01D5EF, 0x01D5E8, + 0x01D5E9, 0x01D5EA, 0x01D5EB, 0x01D5E4, 0x01D5E5, 0x01D5E6, 0x01D5E7, 0x01D5E0, + 0x01D5E1, 0x01D5E2, 0x01D5E3, 0x01D5FC, 0x01D5FD, 0x01D5FE, 0x01D5FF, 0x01D5F8, + 0x01D5F9, 0x01D5FA, 0x01D5FB, 0x01D5F4, 0x01D5F5, 0x01D5F6, 0x01D5F7, 0x01D5F0, + 0x01D5F1, 0x01D5F2, 0x01D5F3, 0x01D5CC, 0x01D5CD, 0x01D5CE, 0x01D5CF, 0x01D5C8, + 0x01D5C9, 0x01D5CA, 0x01D5CB, 0x01D5C4, 0x01D5C5, 0x01D5C6, 0x01D5C7, 0x01D5C0, + 0x01D5C1, 0x01D5C2, 0x01D5C3, 0x01D5DC, 0x01D5DD, 0x01D5DE, 0x01D5DF, 0x01D5D8, + 0x01D5D9, 0x01D5DA, 0x01D5DB, 0x01D5D4, 0x01D5D5, 0x01D5D6, 0x01D5D7, 0x01D5D0, + 0x01D5D1, 0x01D5D2, 0x01D5D3, 0x01D5AC, 0x01D5AD, 0x01D5AE, 0x01D5AF, 0x01D5A8, + 0x01D5A9, 0x01D5AA, 0x01D5AB, 0x01D5A4, 0x01D5A5, 0x01D5A6, 0x01D5A7, 0x01D5A0, + 0x01D5A1, 0x01D5A2, 0x01D5A3, 0x01D5BC, 0x01D5BD, 0x01D5BE, 0x01D5BF, 0x01D5B8, + 0x01D5B9, 0x01D5BA, 0x01D5BB, 0x01D5B4, 0x01D5B5, 0x01D5B6, 0x01D5B7, 0x01D5B0, + 0x01D5B1, 0x01D5B2, 0x01D5B3, 0x01D58C, 0x01D58D, 0x01D58E, 0x01D58F, 0x01D588, + 0x01D589, 0x01D58A, 0x01D58B, 0x01D584, 0x01D585, 0x01E8AF, 0x01D586, 0x01D587, + 0x01D580, 0x01D581, 0x01D582, 0x01D583, 0x01D59C, 0x01D59D, 0x01D59E, 0x01D59F, + 0x01D598, 0x01D599, 0x01D59A, 0x01D59B, 0x01D594, 0x01D595, 0x01D596, 0x01D597, + 0x01D590, 0x01D591, 0x01D592, 0x01D593, 0x01D36C, 0x01D36D, 0x01D36E, 0x01D36F, + 0x01D368, 0x01D369, 0x01D36A, 0x01D36B, 0x01D364, 0x01D365, 0x01D366, 0x01D367, + 0x01D360, 0x01D361, 0x01D362, 0x01D363, 0x01D370, 0x01D371, 0x01342C, 0x01342D, + 0x01342E, 0x013428, 0x013429, 0x01342A, 0x01342B, 0x013424, 0x013425, 0x013426, + 0x013427, 0x013420, 0x013421, 0x013422, 0x013423, 0x01340C, 0x01340D, 0x01340E, + 0x01340F, 0x013408, 0x013409, 0x01340A, 0x01340B, 0x013404, 0x013405, 0x013406, + 0x013407, 0x013400, 0x013401, 0x013402, 0x013403, 0x01341C, 0x01341D, 0x01341E, + 0x01341F, 0x013418, 0x013419, 0x01341A, 0x01341B, 0x013414, 0x013415, 0x013416, + 0x013417, 0x013410, 0x013411, 0x013412, 0x013413, 0x01326C, 0x01326D, 0x01326E, + 0x01326F, 0x013268, 0x013269, 0x01326A, 0x01326B, 0x013264, 0x013265, 0x013266, + 0x013267, 0x013260, 0x013261, 0x013262, 0x013263, 0x01327C, 0x01327D, 0x01327E, + 0x01327F, 0x013278, 0x013279, 0x01327A, 0x01327B, 0x013274, 0x013275, 0x013276, + 0x013277, 0x013270, 0x013271, 0x013272, 0x013273, 0x01324C, 0x01324D, 0x01324E, + 0x01324F, 0x013248, 0x013249, 0x01324A, 0x01324B, 0x013244, 0x013245, 0x013246, + 0x013247, 0x013240, 0x013241, 0x013242, 0x013243, 0x01325C, 0x01325D, 0x01325E, + 0x01325F, 0x013258, 0x013259, 0x01B012, 0x01B013, 0x01325A, 0x01325B, 0x013254, + 0x013255, 0x01B010, 0x01B011, 0x013256, 0x013257, 0x013250, 0x013251, 0x01B016, + 0x01B017, 0x013252, 0x013253, 0x01322C, 0x01322D, 0x01322E, 0x01322F, 0x01B014, + 0x01B015, 0x013228, 0x013229, 0x01322A, 0x01322B, 0x013224, 0x013225, 0x013226, + 0x013227, 0x01B039, 0x01B03E, 0x01B038, 0x01B03F, 0x01B034, 0x01B035, 0x01B024, + 0x01B025, 0x01B02A, 0x01B02B, 0x01B03A, 0x01B03B, 0x01B01C, 0x01B02F, 0x01B03D, + 0x01B02E, 0x01B01A, 0x01B019, 0x01B01B, 0x01B018, 0x01B01E, 0x01B002, 0x01B01F, + 0x01B003, 0x01B000, 0x01B001, 0x01B028, 0x01B029, 0x013220, 0x01B01D, 0x01B006, + 0x01B007, 0x013221, 0x013222, 0x013223, 0x01323C, 0x01323D, 0x01323E, 0x01323F, + 0x013238, 0x013239, 0x01323A, 0x01323B, 0x013234, 0x013235, 0x013236, 0x013237, + 0x013230, 0x013231, 0x013232, 0x01B053, 0x01B052, 0x013233, 0x01320C, 0x01320D, + 0x01320E, 0x01B059, 0x01320F, 0x01B05E, 0x013208, 0x013209, 0x01B05F, 0x01320A, + 0x01320B, 0x01B020, 0x01B021, 0x01B022, 0x01B023, 0x01B065, 0x01B064, 0x01B026, + 0x01B027, 0x01B069, 0x01B068, 0x01B06B, 0x01B06A, 0x01B06D, 0x01B06C, 0x01B06F, + 0x01B06E, 0x013204, 0x013205, 0x013206, 0x013207, 0x013200, 0x013201, 0x013202, + 0x013203, 0x01321C, 0x01321D, 0x01321E, 0x01321F, 0x01B03C, 0x013218, 0x013219, + 0x01321A, 0x01321B, 0x013214, 0x013215, 0x013216, 0x013217, 0x013210, 0x011411, + 0x011410, 0x011413, 0x011412, 0x011415, 0x011414, 0x011417, 0x011416, 0x013211, + 0x013212, 0x01141B, 0x01141A, 0x013213, 0x0132EC, 0x0132ED, 0x0132EE, 0x0132EF, + 0x0132E8, 0x0132E9, 0x0132EA, 0x0132EB, 0x0132E4, 0x0132E5, 0x0132E6, 0x0132E7, + 0x0132E0, 0x0132E1, 0x0132E2, 0x0132E3, 0x0132FC, 0x0132FD, 0x0132FE, 0x0132FF, + 0x0132F8, 0x0132F9, 0x0132FA, 0x0132FB, 0x0132F4, 0x0132F5, 0x0132F6, 0x0132F7, + 0x0132F0, 0x0132F1, 0x0132F2, 0x0132F3, 0x0132CC, 0x0132CD, 0x0132CE, 0x0132CF, + 0x0132C8, 0x0132C9, 0x0132CA, 0x0132CB, 0x0132C4, 0x0132C5, 0x0132C6, 0x0132C7, + 0x0132C0, 0x0132C1, 0x0132C2, 0x0132C3, 0x0132DC, 0x0132DD, 0x0132DE, 0x0132DF, + 0x0132D8, 0x0132D9, 0x0132DA, 0x0132DB, 0x0132D4, 0x0132D5, 0x0132D6, 0x0132D7, + 0x0132D0, 0x0132D1, 0x0132D2, 0x0132D3, 0x0132AC, 0x0132AD, 0x0132AE, 0x0132AF, + 0x0132A8, 0x0132A9, 0x0132AA, 0x0132AB, 0x0132A4, 0x0132A5, 0x0132A6, 0x0132A7, + 0x0132A0, 0x0132A1, 0x0132A2, 0x01B0EE, 0x01B0EF, 0x01B0E5, 0x01B0E4, 0x0132A3, + 0x0132BC, 0x01B0E9, 0x01B0E8, 0x0132BD, 0x0132BE, 0x0132BF, 0x0132B8, 0x01B0EA, + 0x01B0EB, 0x0132B9, 0x0132BA, 0x0132BB, 0x0132B4, 0x0132B5, 0x0132B6, 0x011482, + 0x011483, 0x01B0EC, 0x01B0ED, 0x01149C, 0x01149D, 0x01149E, 0x01149F, 0x011498, + 0x011499, 0x01B101, 0x01B100, 0x01B103, 0x01B102, 0x01149A, 0x01149B, 0x01B107, + 0x01B106, 0x011493, 0x011492, 0x011490, 0x011491, 0x011497, 0x011496, 0x011494, + 0x011495, 0x01B111, 0x01B110, 0x01B113, 0x01B112, 0x01B115, 0x01B114, 0x01B117, + 0x01B116, 0x01B119, 0x01B118, 0x01B11B, 0x01B11A, 0x01B11D, 0x01B11C, 0x011481, + 0x01B11E, 0x011480, 0x01148B, 0x011485, 0x011486, 0x011484, 0x011487, 0x0114A0, + 0x0114A1, 0x0114A2, 0x0114A3, 0x01148C, 0x01148D, 0x01148E, 0x01148F, 0x0114AB, + 0x0114A5, 0x01148A, 0x0114A4, 0x0114A6, 0x011489, 0x0114A7, 0x011488, 0x0114C4, + 0x0132B7, 0x0132B0, 0x0132B1, 0x0114D6, 0x0114D7, 0x0114C7, 0x0114C5, 0x0132B2, + 0x0132B3, 0x01328C, 0x01328D, 0x01328E, 0x01328F, 0x013288, 0x013289, 0x0114D2, + 0x0114D3, 0x0114D0, 0x0114D1, 0x01328A, 0x0114D4, 0x01328B, 0x0114D5, 0x0114D9, + 0x0114D8, 0x013284, 0x013285, 0x013286, 0x013287, 0x013280, 0x013281, 0x013282, + 0x013283, 0x01329C, 0x01329D, 0x01329E, 0x01329F, 0x013298, 0x013299, 0x0114A8, + 0x0114A9, 0x0114AA, 0x01329A, 0x0114AC, 0x0114AD, 0x0114AE, 0x0114AF, 0x01329B, + 0x013294, 0x013295, 0x013296, 0x013297, 0x013290, 0x013291, 0x013292, 0x013293, + 0x01336C, 0x01336D, 0x01336E, 0x01336F, 0x013368, 0x013369, 0x01336A, 0x01336B, + 0x013364, 0x013365, 0x013366, 0x013367, 0x013360, 0x013361, 0x013362, 0x013363, + 0x01337C, 0x01337D, 0x01337E, 0x01337F, 0x013378, 0x013379, 0x01337A, 0x01337B, + 0x013374, 0x013375, 0x013376, 0x013377, 0x013370, 0x013371, 0x013372, 0x013373, + 0x01334C, 0x01334D, 0x01334E, 0x01334F, 0x013348, 0x013349, 0x01334A, 0x01334B, + 0x013344, 0x013345, 0x013346, 0x013347, 0x013340, 0x013341, 0x013342, 0x013343, + 0x01335C, 0x01335D, 0x01335E, 0x01335F, 0x013358, 0x013359, 0x01335A, 0x01335B, + 0x013354, 0x013355, 0x013356, 0x013357, 0x013350, 0x013351, 0x013352, 0x013353, + 0x01332C, 0x01332D, 0x01332E, 0x01332F, 0x013328, 0x013329, 0x01332A, 0x01332B, + 0x013324, 0x013325, 0x013326, 0x013327, 0x013320, 0x013321, 0x013322, 0x013323, + 0x01333C, 0x01333D, 0x01333E, 0x01333F, 0x013338, 0x013339, 0x01333A, 0x01333B, + 0x013334, 0x013335, 0x013336, 0x013337, 0x013330, 0x013331, 0x013332, 0x013333, + 0x01330C, 0x01330D, 0x01330E, 0x01330F, 0x013308, 0x013309, 0x01330A, 0x01330B, + 0x013304, 0x013305, 0x013306, 0x013307, 0x013300, 0x013301, 0x013302, 0x013303, + 0x01331C, 0x01331D, 0x01331E, 0x01331F, 0x013318, 0x013319, 0x01331A, 0x01331B, + 0x013314, 0x013315, 0x013316, 0x013317, 0x013310, 0x013311, 0x013312, 0x013313, + 0x0133EC, 0x0133ED, 0x0133EE, 0x0133EF, 0x0133E8, 0x0133E9, 0x0133EA, 0x011581, + 0x011580, 0x011583, 0x011582, 0x0133EB, 0x011584, 0x011587, 0x011586, 0x011589, + 0x011588, 0x01158B, 0x01158A, 0x01158D, 0x01158C, 0x01158F, 0x01158E, 0x0133E4, + 0x0133E5, 0x0133E6, 0x0133E7, 0x0133E0, 0x0133E1, 0x0133E2, 0x0133E3, 0x011599, + 0x011598, 0x0133FC, 0x0133FD, 0x01159D, 0x01159C, 0x01159F, 0x01159E, 0x0133FE, + 0x0133FF, 0x0133F8, 0x0133F9, 0x0133FA, 0x0133FB, 0x0133F4, 0x0133F5, 0x0133F6, + 0x0133F7, 0x0133F0, 0x0133F1, 0x0133F2, 0x0133F3, 0x0133CC, 0x0133CD, 0x0133CE, + 0x0133CF, 0x0133C8, 0x0133C9, 0x0133CA, 0x0133CB, 0x0133C4, 0x0133C5, 0x0133C6, + 0x0133C7, 0x0133C0, 0x0133C1, 0x0133C2, 0x0133C3, 0x0133DC, 0x0133DD, 0x0133DE, + 0x0133DF, 0x0133D8, 0x0133D9, 0x0133DA, 0x0133DB, 0x0133D4, 0x0133D5, 0x0133D6, + 0x0133D7, 0x0133D0, 0x0133D1, 0x0133D2, 0x0133D3, 0x0133AC, 0x0133AD, 0x0133AE, + 0x0133AF, 0x0133A8, 0x0133A9, 0x0133AA, 0x0133AB, 0x0133A4, 0x0133A5, 0x0133A6, + 0x0133A7, 0x0133A0, 0x0133A1, 0x0133A2, 0x0133A3, 0x0133BC, 0x0133BD, 0x0133BE, + 0x0133BF, 0x0133B8, 0x0133B9, 0x0133BA, 0x0133BB, 0x0133B4, 0x0133B5, 0x0133B6, + 0x0133B7, 0x0133B0, 0x0133B1, 0x0133B2, 0x0133B3, 0x01338C, 0x01338D, 0x01338E, + 0x01338F, 0x013388, 0x013389, 0x01338A, 0x01338B, 0x013384, 0x013385, 0x013386, + 0x013387, 0x013380, 0x013381, 0x013382, 0x013383, 0x01339C, 0x01339D, 0x01339E, + 0x01339F, 0x011603, 0x013398, 0x013399, 0x01339A, 0x01339B, 0x013394, 0x013395, + 0x013396, 0x013397, 0x013390, 0x013391, 0x013392, 0x013393, 0x01306C, 0x011611, + 0x011610, 0x011613, 0x011612, 0x011615, 0x011614, 0x011617, 0x011616, 0x011619, + 0x011618, 0x01161B, 0x01161A, 0x01161D, 0x01161C, 0x01161F, 0x01161E, 0x011621, + 0x011620, 0x01306D, 0x011622, 0x011625, 0x011624, 0x011627, 0x011626, 0x011629, + 0x011628, 0x01162B, 0x01162A, 0x01162D, 0x01162C, 0x01162F, 0x01162E, 0x01306E, + 0x01306F, 0x013068, 0x013069, 0x01306A, 0x01306B, 0x013064, 0x013065, 0x013066, + 0x013067, 0x013060, 0x013061, 0x013062, 0x013063, 0x01307C, 0x01307D, 0x01307E, + 0x01307F, 0x013078, 0x013079, 0x01307A, 0x011644, 0x01307B, 0x013074, 0x013075, + 0x013076, 0x013077, 0x013070, 0x013071, 0x013072, 0x013073, 0x01304C, 0x011651, + 0x011650, 0x011653, 0x011652, 0x011655, 0x011654, 0x011657, 0x011656, 0x011659, + 0x011658, 0x01304D, 0x01304E, 0x01304F, 0x013048, 0x013049, 0x01304A, 0x01304B, + 0x013044, 0x013045, 0x013046, 0x013047, 0x013040, 0x013041, 0x013042, 0x013043, + 0x01305C, 0x01305D, 0x01305E, 0x01305F, 0x013058, 0x013059, 0x01305A, 0x01305B, + 0x013054, 0x013055, 0x013056, 0x013057, 0x013050, 0x013051, 0x013052, 0x013053, + 0x01302C, 0x01302D, 0x01302E, 0x01302F, 0x013028, 0x013029, 0x01302A, 0x01302B, + 0x013024, 0x011683, 0x013025, 0x013026, 0x013027, 0x013020, 0x013021, 0x013022, + 0x013023, 0x01303C, 0x01303D, 0x01303E, 0x01303F, 0x013038, 0x013039, 0x011691, + 0x011690, 0x011693, 0x011692, 0x011695, 0x011694, 0x011697, 0x01303A, 0x011699, + 0x011698, 0x01169B, 0x01169A, 0x01169D, 0x01169C, 0x01169F, 0x01303B, 0x0116A1, + 0x0116A0, 0x013034, 0x0116A2, 0x0116A5, 0x0116A4, 0x0116A7, 0x0116A6, 0x0116A9, + 0x0116A8, 0x013035, 0x0116AA, 0x013036, 0x013037, 0x013030, 0x013031, 0x013032, + 0x013033, 0x01300C, 0x01300D, 0x01300E, 0x01300F, 0x013008, 0x013009, 0x01300A, + 0x01300B, 0x013004, 0x013005, 0x013006, 0x013007, 0x013000, 0x013001, 0x0116C1, + 0x0116C0, 0x0116C3, 0x0116C2, 0x0116C5, 0x0116C4, 0x0116C7, 0x0116C6, 0x0116C9, + 0x0116C8, 0x013002, 0x013003, 0x01301C, 0x01301D, 0x01301E, 0x01301F, 0x013018, + 0x013019, 0x01301A, 0x01301B, 0x013014, 0x013015, 0x013016, 0x013017, 0x013010, + 0x013011, 0x013012, 0x013013, 0x0130EC, 0x0130ED, 0x0130EE, 0x0130EF, 0x0130E8, + 0x0130E9, 0x0130EA, 0x0130EB, 0x0130E4, 0x0130E5, 0x0130E6, 0x0130E7, 0x0130E0, + 0x0130E1, 0x0130E2, 0x0130E3, 0x0130FC, 0x0130FD, 0x0130FE, 0x0130FF, 0x0130F8, + 0x0130F9, 0x0130FA, 0x0130FB, 0x0130F4, 0x0130F5, 0x0130F6, 0x0130F7, 0x0130F0, + 0x0130F1, 0x0130F2, 0x0130F3, 0x0130CC, 0x0130CD, 0x0130CE, 0x0130CF, 0x0130C8, + 0x0130C9, 0x0130CA, 0x0130CB, 0x0130C4, 0x0130C5, 0x0130C6, 0x0130C7, 0x0130C0, + 0x0130C1, 0x0130C2, 0x0130C3, 0x0130DC, 0x0130DD, 0x0130DE, 0x0130DF, 0x0130D8, + 0x0130D9, 0x0130DA, 0x0130DB, 0x0130D4, 0x0130D5, 0x0130D6, 0x0130D7, 0x0130D0, + 0x0130D1, 0x0130D2, 0x0130D3, 0x0130AC, 0x0130AD, 0x0130AE, 0x0130AF, 0x0130A8, + 0x0130A9, 0x0130AA, 0x0130AB, 0x0130A4, 0x0130A5, 0x0130A6, 0x0130A7, 0x0130A0, + 0x0130A1, 0x0130A2, 0x0130A3, 0x0130BC, 0x0130BD, 0x0130BE, 0x0130BF, 0x0130B8, + 0x002C81, 0x002C80, 0x002C83, 0x002C82, 0x002C85, 0x0130B9, 0x002C87, 0x002C86, + 0x002C89, 0x0130BA, 0x0130BB, 0x002C8A, 0x0130B4, 0x0130B5, 0x0130B6, 0x0130B7, + 0x002C91, 0x002C90, 0x002C93, 0x002C92, 0x002C95, 0x002C94, 0x002C97, 0x002C96, + 0x002C99, 0x002C98, 0x002C9B, 0x002C9A, 0x002C9D, 0x002C9C, 0x002C9F, 0x002C9E, + 0x0130B0, 0x0130B1, 0x0130B2, 0x0130B3, 0x01308C, 0x01308D, 0x01308E, 0x01308F, + 0x013088, 0x013089, 0x01308A, 0x01308B, 0x013084, 0x013085, 0x013086, 0x013087, + 0x013080, 0x013081, 0x013082, 0x013083, 0x002CB5, 0x01309C, 0x01309D, 0x01309E, + 0x01309F, 0x013098, 0x013099, 0x01309A, 0x01309B, 0x013094, 0x013095, 0x013096, + 0x013097, 0x013090, 0x013091, 0x013092, 0x013093, 0x01316C, 0x01316D, 0x01316E, + 0x01316F, 0x013168, 0x013169, 0x01316A, 0x01316B, 0x013164, 0x013165, 0x013166, + 0x013167, 0x013160, 0x013161, 0x013162, 0x013163, 0x01317C, 0x01317D, 0x01317E, + 0x01317F, 0x013178, 0x013179, 0x01317A, 0x01317B, 0x013174, 0x013175, 0x013176, + 0x013177, 0x013170, 0x013171, 0x013172, 0x013173, 0x01314C, 0x01314D, 0x01314E, + 0x01314F, 0x013148, 0x013149, 0x01314A, 0x01314B, 0x013144, 0x013145, 0x013146, + 0x013147, 0x013140, 0x013141, 0x013142, 0x013143, 0x01315C, 0x01315D, 0x01315E, + 0x01315F, 0x013158, 0x013159, 0x01315A, 0x01315B, 0x013154, 0x013155, 0x013156, + 0x013157, 0x013150, 0x013151, 0x013152, 0x013153, 0x01312C, 0x01312D, 0x01312E, + 0x01312F, 0x013128, 0x013129, 0x01312A, 0x01312B, 0x002D0C, 0x013124, 0x013125, + 0x002D11, 0x002D10, 0x002D13, 0x002D12, 0x002D15, 0x013126, 0x002D17, 0x002D16, + 0x002D19, 0x013127, 0x002D1B, 0x002D1A, 0x013120, 0x013121, 0x013122, 0x013123, + 0x01313C, 0x01313D, 0x01313E, 0x01313F, 0x013138, 0x013139, 0x01313A, 0x01313B, + 0x013134, 0x013135, 0x013136, 0x013137, 0x013130, 0x013131, 0x013132, 0x013133, + 0x002D31, 0x002D30, 0x002D33, 0x002D32, 0x002D35, 0x01310C, 0x002D37, 0x002D36, + 0x002D39, 0x01310D, 0x01310E, 0x002D3A, 0x01310F, 0x013108, 0x013109, 0x01310A, + 0x002D41, 0x002D40, 0x002D43, 0x002D42, 0x002D45, 0x002D44, 0x002D47, 0x002D46, + 0x002D49, 0x002D48, 0x002D4B, 0x002D4A, 0x002D4D, 0x002D4C, 0x002D4F, 0x002D4E, + 0x01310B, 0x013104, 0x013105, 0x013106, 0x013107, 0x013100, 0x013101, 0x013102, + 0x013103, 0x01311C, 0x01311D, 0x01311E, 0x01311F, 0x002D5C, 0x013118, 0x013119, + 0x01311A, 0x01311B, 0x013114, 0x013115, 0x013116, 0x013117, 0x013110, 0x013111, + 0x013112, 0x013113, 0x0131EC, 0x0131ED, 0x0131EE, 0x0131EF, 0x0131E8, 0x0131E9, + 0x0131EA, 0x0131EB, 0x0131E4, 0x0131E5, 0x0131E6, 0x0131E7, 0x0131E0, 0x0131E1, + 0x0131E2, 0x0131E3, 0x0131FC, 0x0131FD, 0x0131FE, 0x0131FF, 0x0131F8, 0x0131F9, + 0x0131FA, 0x0131FB, 0x0131F4, 0x0131F5, 0x0131F6, 0x0131F7, 0x0131F0, 0x0131F1, + 0x0131F2, 0x0131F3, 0x0131CC, 0x0131CD, 0x0131CE, 0x0131CF, 0x0131C8, 0x0131C9, + 0x0131CA, 0x0131CB, 0x0131C4, 0x0131C5, 0x0131C6, 0x0131C7, 0x0131C0, 0x0131C1, + 0x0131C2, 0x0131C3, 0x0131DC, 0x0131DD, 0x0131DE, 0x0131DF, 0x0131D8, 0x0131D9, + 0x0131DA, 0x0131DB, 0x0131D4, 0x0131D5, 0x0131D6, 0x0131D7, 0x0131D0, 0x0131D1, + 0x0131D2, 0x0131D3, 0x0131AC, 0x0131AD, 0x0131AE, 0x0131AF, 0x0131A8, 0x0131A9, + 0x0131AA, 0x0131AB, 0x0131A4, 0x0131A5, 0x0131A6, 0x0131A7, 0x0131A0, 0x0131A1, + 0x0131A2, 0x0131A3, 0x0131BC, 0x0131BD, 0x0131BE, 0x0131BF, 0x0131B8, 0x0131B9, + 0x002DC1, 0x002DC0, 0x002DC3, 0x002DC2, 0x002DC5, 0x002DC4, 0x0131BA, 0x002DC6, + 0x002DC9, 0x002DC8, 0x002DCB, 0x002DCA, 0x002DCD, 0x002DCC, 0x0131BB, 0x002DCE, + 0x0131B4, 0x0131B5, 0x0131B6, 0x0131B7, 0x0131B0, 0x0131B1, 0x0131B2, 0x0131B3, + 0x01318C, 0x01318D, 0x01318E, 0x01318F, 0x013188, 0x002DDC, 0x013189, 0x01318A, + 0x01318B, 0x013184, 0x013185, 0x013186, 0x013187, 0x013180, 0x013181, 0x013182, + 0x013183, 0x01319C, 0x01319D, 0x01319E, 0x01319F, 0x013198, 0x013199, 0x01319A, + 0x01319B, 0x013194, 0x013195, 0x013196, 0x013197, 0x013190, 0x013191, 0x013192, + 0x013193, 0x02FA0C, 0x02FA0D, 0x02FA0E, 0x02FA0F, 0x02FA08, 0x02FA09, 0x02FA0A, + 0x02FA0B, 0x02FA04, 0x02FA05, 0x02FA06, 0x02FA07, 0x02FA00, 0x02FA01, 0x02FA02, + 0x02FA03, 0x02FA1C, 0x02FA1D, 0x02FA18, 0x02FA19, 0x02FA1A, 0x02FA1B, 0x02FA14, + 0x02FA15, 0x02FA16, 0x02FA17, 0x02FA10, 0x02FA11, 0x02FA12, 0x02FA13, 0x01246C, + 0x01246D, 0x01246E, 0x012468, 0x012469, 0x01246A, 0x01246B, 0x012464, 0x012465, + 0x012466, 0x012467, 0x012460, 0x012461, 0x012462, 0x012463, 0x01244C, 0x01244D, + 0x01244E, 0x01244F, 0x012448, 0x012449, 0x01244A, 0x01244B, 0x012444, 0x012445, + 0x012446, 0x012447, 0x012440, 0x012441, 0x012442, 0x012443, 0x01245C, 0x01245D, + 0x01245E, 0x01245F, 0x012458, 0x012459, 0x01245A, 0x01245B, 0x012454, 0x012455, + 0x012456, 0x012457, 0x012450, 0x012451, 0x012452, 0x012453, 0x01242C, 0x01242D, + 0x01242E, 0x01242F, 0x012428, 0x012429, 0x01242A, 0x01242B, 0x012424, 0x012425, + 0x012426, 0x012427, 0x012420, 0x012421, 0x012422, 0x012423, 0x01243C, 0x01243D, + 0x01243E, 0x01243F, 0x012438, 0x012439, 0x01243A, 0x01243B, 0x012434, 0x012435, + 0x012436, 0x012437, 0x012430, 0x012431, 0x012432, 0x012433, 0x01240C, 0x01240D, + 0x01240E, 0x01240F, 0x012408, 0x012409, 0x01240A, 0x01240B, 0x012404, 0x012405, + 0x012406, 0x012407, 0x012400, 0x012401, 0x012402, 0x012403, 0x01241C, 0x01241D, + 0x01241E, 0x01241F, 0x012418, 0x012419, 0x01241A, 0x01241B, 0x012414, 0x012415, + 0x012416, 0x012417, 0x012410, 0x012411, 0x012412, 0x012413, 0x0124EC, 0x0124ED, + 0x0124EE, 0x0124EF, 0x0124E8, 0x0124E9, 0x0124EA, 0x0124EB, 0x0124E4, 0x0124E5, + 0x0124E6, 0x0124E7, 0x0124E0, 0x0124E1, 0x0124E2, 0x0124E3, 0x0124FC, 0x0124FD, + 0x0124FE, 0x0124FF, 0x0124F8, 0x0124F9, 0x0124FA, 0x0124FB, 0x0124F4, 0x0124F5, + 0x0124F6, 0x0124F7, 0x0124F0, 0x0124F1, 0x0124F2, 0x0124F3, 0x0124CC, 0x0124CD, + 0x0124CE, 0x0124CF, 0x0124C8, 0x0124C9, 0x0124CA, 0x0124CB, 0x0124C4, 0x0124C5, + 0x0124C6, 0x0124C7, 0x0124C0, 0x0124C1, 0x0124C2, 0x0124C3, 0x0124DC, 0x0124DD, + 0x0124DE, 0x0124DF, 0x0124D8, 0x0124D9, 0x0124DA, 0x0124DB, 0x0124D4, 0x0124D5, + 0x0124D6, 0x0124D7, 0x0124D0, 0x0124D1, 0x0124D2, 0x0124D3, 0x0124AC, 0x0124AD, + 0x0124AE, 0x0124AF, 0x0124A8, 0x0124A9, 0x0124AA, 0x0124AB, 0x0124A4, 0x0124A5, + 0x0124A6, 0x0124A7, 0x0124A0, 0x0124A1, 0x0124A2, 0x0124A3, 0x0124BC, 0x0124BD, + 0x0124BE, 0x0124BF, 0x0124B8, 0x0124B9, 0x0124BA, 0x0124BB, 0x0124B4, 0x0124B5, + 0x0124B6, 0x0124B7, 0x0124B0, 0x0124B1, 0x0124B2, 0x0124B3, 0x01248C, 0x01248D, + 0x01248E, 0x01248F, 0x012488, 0x012489, 0x01248A, 0x01248B, 0x012484, 0x012485, + 0x012486, 0x012487, 0x012480, 0x012481, 0x012482, 0x012483, 0x01249C, 0x01249D, + 0x01249E, 0x01249F, 0x012498, 0x012499, 0x01249A, 0x01249B, 0x012494, 0x012495, + 0x012496, 0x012497, 0x012490, 0x012491, 0x012492, 0x012493, 0x012540, 0x012541, + 0x012542, 0x012543, 0x01252C, 0x01252D, 0x01252E, 0x01252F, 0x012528, 0x012539, + 0x01253A, 0x01253B, 0x012534, 0x02F84F, 0x016801, 0x016800, 0x016803, 0x016802, + 0x016805, 0x016804, 0x016807, 0x016806, 0x016809, 0x016808, 0x01680B, 0x01680A, + 0x01680D, 0x01680C, 0x01680F, 0x01680E, 0x016811, 0x016810, 0x016813, 0x016812, + 0x016815, 0x016814, 0x016817, 0x016816, 0x016819, 0x016818, 0x01681B, 0x01681A, + 0x01681D, 0x016849, 0x01681F, 0x01681E, 0x016821, 0x016820, 0x016823, 0x016822, + 0x016825, 0x016824, 0x016827, 0x016826, 0x016829, 0x016828, 0x01682B, 0x01682A, + 0x01682D, 0x01682C, 0x01682F, 0x01682E, 0x016831, 0x016862, 0x016833, 0x016832, + 0x016835, 0x016842, 0x016837, 0x01686B, 0x01687D, 0x016838, 0x01684E, 0x01684D, + 0x01683D, 0x01683C, 0x01683F, 0x01683E, 0x011A00, 0x016840, 0x01681C, 0x01685E, + 0x016843, 0x011A0B, 0x016844, 0x011A0E, 0x011A0F, 0x01684B, 0x01685F, 0x011A11, + 0x011A10, 0x011A13, 0x011A12, 0x011A15, 0x011A1B, 0x011A17, 0x016857, 0x016852, + 0x011A14, 0x011A18, 0x01686F, 0x016855, 0x01685D, 0x011A16, 0x011A1A, 0x016853, + 0x016851, 0x011A32, 0x016850, 0x01684F, 0x01685C, 0x011A22, 0x011A23, 0x01683A, + 0x01686D, 0x016834, 0x016860, 0x011A24, 0x011A2B, 0x016861, 0x01687C, 0x011A21, + 0x011A27, 0x011A1C, 0x011A3A, 0x01687E, 0x011A0D, 0x011A1E, 0x01684A, 0x01685B, + 0x011A19, 0x016854, 0x016856, 0x016859, 0x011A1D, 0x011A1F, 0x01685A, 0x01687F, + 0x016878, 0x016836, 0x016877, 0x016830, 0x011A31, 0x011A30, 0x016883, 0x016882, + 0x016881, 0x016886, 0x016885, 0x016880, 0x016884, 0x01688D, 0x01687A, 0x01687B, + 0x01689C, 0x01688C, 0x01688F, 0x01688E, 0x016892, 0x016895, 0x016893, 0x011A0C, + 0x011A50, 0x016896, 0x016897, 0x016891, 0x016890, 0x01689D, 0x016899, 0x016894, + 0x016898, 0x01689E, 0x01689F, 0x01689A, 0x011A20, 0x01686E, 0x011A5D, 0x011A5C, + 0x016875, 0x011A5E, 0x011A5F, 0x016874, 0x0168B8, 0x0168B9, 0x016839, 0x011A71, + 0x011A73, 0x011A2E, 0x011A72, 0x011A70, 0x0168B1, 0x011A25, 0x0168B3, 0x0168B2, + 0x0168B5, 0x0168B4, 0x0168B7, 0x0168B6, 0x0168B0, 0x0168BA, 0x0168BB, 0x011A81, + 0x011A80, 0x011A83, 0x011A82, 0x01686C, 0x0168C5, 0x011A87, 0x0168C1, 0x011A89, + 0x016871, 0x0168C4, 0x0168C7, 0x0168C6, 0x011A88, 0x011A86, 0x0168C2, 0x0168C3, + 0x0168C0, 0x0168E4, 0x01684C, 0x016870, 0x0168C8, 0x016858, 0x016848, 0x016841, + 0x011AC7, 0x016845, 0x016846, 0x016847, 0x0168C9, 0x0168D8, 0x0168CA, 0x0168CB, + 0x0168DD, 0x0168DC, 0x0168DF, 0x0168DE, 0x0168E5, 0x016872, 0x0168E6, 0x0168E7, + 0x0168E0, 0x0168E1, 0x0168E2, 0x0168E3, 0x016876, 0x0168E8, 0x0168EC, 0x0168ED, + 0x0168EE, 0x0168EF, 0x0168EA, 0x0168EB, 0x016864, 0x0168E9, 0x016867, 0x011A76, + 0x0168FC, 0x0168FD, 0x011A2F, 0x016873, 0x0168FE, 0x0168FF, 0x011A2A, 0x011AC1, + 0x011AC0, 0x011AC3, 0x011AC2, 0x011AC5, 0x011AC4, 0x011A77, 0x011AC6, 0x011AC9, + 0x011AC8, 0x011ACB, 0x011ACA, 0x011ACD, 0x011ACC, 0x011ACF, 0x011ACE, 0x011AD2, + 0x011AD7, 0x011AD3, 0x011AD1, 0x011AD5, 0x011AD4, 0x011AD0, 0x011AD6, 0x011AD9, + 0x011AD8, 0x011ADB, 0x011ADA, 0x011ADD, 0x011ADC, 0x011ADF, 0x011ADE, 0x011AE1, + 0x011AE0, 0x011AE3, 0x011AE2, 0x011AE5, 0x011AE4, 0x011AE7, 0x011AE6, 0x011AE9, + 0x011AE8, 0x011AEB, 0x011AEA, 0x011AED, 0x011AEC, 0x011AEF, 0x011AEE, 0x011AF1, + 0x011AF0, 0x011AF3, 0x011AF2, 0x011AF5, 0x011AF4, 0x011AF7, 0x011AF6, 0x003043, + 0x011AF8, 0x003041, 0x003042, 0x003045, 0x003048, 0x003082, 0x003046, 0x003047, + 0x003022, 0x003021, 0x003023, 0x003080, 0x003044, 0x00304D, 0x003057, 0x003056, + 0x00304F, 0x003038, 0x003007, 0x00304B, 0x003055, 0x00305C, 0x00304A, 0x003049, + 0x003066, 0x003065, 0x00304E, 0x003061, 0x003067, 0x00305D, 0x003006, 0x00305E, + 0x003059, 0x0030A7, 0x003058, 0x003039, 0x00304C, 0x00316D, 0x00305F, 0x011A2C, + 0x003072, 0x003073, 0x011A26, 0x00303A, 0x016961, 0x016960, 0x003054, 0x011A29, + 0x00305B, 0x016869, 0x016863, 0x016866, 0x00305A, 0x01696D, 0x003071, 0x00303C, + 0x01696E, 0x01696C, 0x01696F, 0x003092, 0x00111E, 0x00111F, 0x003090, 0x011A28, + 0x003081, 0x016865, 0x001118, 0x001119, 0x011A2D, 0x016879, 0x01686A, 0x011A6F, + 0x00111A, 0x01697F, 0x003094, 0x01697E, 0x011A7D, 0x011A7C, 0x001115, 0x003093, + 0x011A79, 0x011A7A, 0x00111B, 0x011A78, 0x011A7E, 0x003095, 0x011A7F, 0x011A7B, + 0x011A6C, 0x001101, 0x0030A3, 0x0030A2, 0x001133, 0x0030A1, 0x001106, 0x001107, + 0x0030B8, 0x0030B9, 0x00110A, 0x011A6E, 0x001105, 0x00111D, 0x011A63, 0x011A62, + 0x0030BA, 0x0030B5, 0x0030BD, 0x0030BF, 0x00308E, 0x0030B4, 0x0030B7, 0x0030B6, + 0x0030BB, 0x00308D, 0x003083, 0x00308F, 0x003088, 0x011A74, 0x0030BC, 0x0030BE, + 0x011A61, 0x011A60, 0x001142, 0x00309F, 0x011A66, 0x003096, 0x011A67, 0x011A68, + 0x011A6B, 0x011A6A, 0x011A69, 0x011A75, 0x011A65, 0x011A64, 0x011A6D, 0x001109, + 0x001140, 0x001141, 0x001144, 0x001143, 0x003091, 0x001145, 0x001146, 0x001147, + 0x001138, 0x001149, 0x00113A, 0x00114B, 0x00115C, 0x00113D, 0x00113E, 0x00113F, + 0x0011EC, 0x001139, 0x001134, 0x00113B, 0x003064, 0x0011ED, 0x0011EE, 0x0011EF, + 0x003068, 0x003069, 0x00306A, 0x00306B, 0x00306C, 0x0011E9, 0x0011EA, 0x0011E8, + 0x003070, 0x001131, 0x001132, 0x001137, 0x003074, 0x003075, 0x003076, 0x003077, + 0x003078, 0x003079, 0x00307A, 0x001135, 0x001136, 0x00307D, 0x00307E, 0x00307F, + 0x0011E5, 0x003176, 0x0011E4, 0x0011EB, 0x003105, 0x00311D, 0x003107, 0x003106, + 0x003109, 0x003108, 0x00310B, 0x00310A, 0x00310D, 0x00310C, 0x00310F, 0x00310E, + 0x003114, 0x003115, 0x003116, 0x003117, 0x003112, 0x003113, 0x003162, 0x003161, + 0x003110, 0x003111, 0x00311E, 0x00311F, 0x003119, 0x00311C, 0x00311A, 0x00311B, + 0x003121, 0x003120, 0x003123, 0x003122, 0x003125, 0x016A2D, 0x003127, 0x003126, + 0x003129, 0x00317D, 0x00312B, 0x0011E6, 0x016A28, 0x00312C, 0x016A2F, 0x0011E7, + 0x003131, 0x003118, 0x003133, 0x003132, 0x003135, 0x003134, 0x003137, 0x003136, + 0x003139, 0x003138, 0x00313B, 0x00313A, 0x00313D, 0x00313C, 0x00313F, 0x00313E, + 0x003141, 0x003140, 0x003143, 0x003142, 0x016A54, 0x0011E2, 0x00317E, 0x003146, + 0x003145, 0x016A55, 0x003144, 0x003149, 0x003170, 0x0011E1, 0x00314B, 0x003147, + 0x003151, 0x003150, 0x003153, 0x003152, 0x003155, 0x003154, 0x003157, 0x003156, + 0x003159, 0x003158, 0x00315B, 0x00315A, 0x00315D, 0x00315C, 0x00315F, 0x00315E, + 0x011C52, 0x00312A, 0x00316B, 0x00314D, 0x016A57, 0x011C1B, 0x003173, 0x00314F, + 0x00316C, 0x003148, 0x00314A, 0x003124, 0x011C1A, 0x011C51, 0x00314E, 0x003172, + 0x003177, 0x016A50, 0x011C13, 0x003163, 0x003171, 0x003174, 0x011C12, 0x00312E, + 0x011C57, 0x003128, 0x003178, 0x011C10, 0x011C15, 0x00317F, 0x016A52, 0x011C50, + 0x003182, 0x003180, 0x003183, 0x003185, 0x003186, 0x003181, 0x003187, 0x003188, + 0x00318C, 0x00318A, 0x00318B, 0x00318E, 0x003184, 0x003189, 0x00318D, 0x0030A4, + 0x0030AC, 0x003193, 0x011C40, 0x003192, 0x003195, 0x003194, 0x0030AE, 0x0030AD, + 0x0030A8, 0x016A58, 0x0030AA, 0x0030AB, 0x0030AF, 0x0030A9, 0x00316E, 0x00316F, + 0x0031B0, 0x0031A0, 0x0031A3, 0x0031A2, 0x0031A5, 0x0031A1, 0x0031A7, 0x0031A6, + 0x0031A9, 0x0031A8, 0x0031AB, 0x0031AA, 0x0031A4, 0x0031AE, 0x0031AF, 0x0030A6, + 0x0031B5, 0x0031B2, 0x0031B3, 0x0031B4, 0x0031B8, 0x0031B1, 0x0031B7, 0x0031B6, + 0x003169, 0x0031BA, 0x0031B9, 0x003168, 0x0031AC, 0x0031AD, 0x00312D, 0x0030A5, + 0x0030D0, 0x016A5C, 0x0030D2, 0x0030D1, 0x0030D7, 0x00314C, 0x0030D4, 0x011C18, + 0x0030DA, 0x0030D9, 0x011C1F, 0x0030DB, 0x0030DE, 0x016A2E, 0x0030D6, 0x0030D5, + 0x003165, 0x0030D3, 0x016A2C, 0x011C1D, 0x011C17, 0x011C11, 0x016A56, 0x016A5A, + 0x011C82, 0x011C83, 0x011C73, 0x003164, 0x011C19, 0x0011FD, 0x0011E3, 0x011C80, + 0x0030DD, 0x016ADD, 0x003160, 0x003167, 0x0031FC, 0x016AD8, 0x00317C, 0x003175, + 0x016ADF, 0x003179, 0x00317A, 0x00317B, 0x0031FD, 0x0030DF, 0x0031FE, 0x0031FF, + 0x0031F1, 0x0031F0, 0x0031F3, 0x0031F2, 0x00316A, 0x003166, 0x0031F5, 0x0030D8, + 0x0031F4, 0x0031F8, 0x0031FB, 0x0031FA, 0x0031F9, 0x011C81, 0x0031F6, 0x0031F7, + 0x016ADC, 0x011C16, 0x011C14, 0x016A68, 0x011C0B, 0x016ADE, 0x011C87, 0x011C1C, + 0x011C04, 0x011C06, 0x016A51, 0x016A53, 0x011C05, 0x011C1E, 0x016A42, 0x016A5B, + 0x016A41, 0x016A59, 0x016A40, 0x016A43, 0x016B26, 0x016B6F, 0x016B20, 0x011C54, + 0x016B27, 0x003285, 0x016A44, 0x0010B5, 0x011C55, 0x011C56, 0x003286, 0x003287, + 0x003288, 0x0010B7, 0x003284, 0x011C53, 0x016A45, 0x016B29, 0x016A49, 0x016B2A, + 0x016B25, 0x016A47, 0x016B24, 0x0010B6, 0x016A5D, 0x011C03, 0x016B2B, 0x016A5E, + 0x0010B0, 0x011C58, 0x016A4B, 0x003289, 0x016A62, 0x016A63, 0x016B23, 0x016B22, + 0x016B65, 0x016B2D, 0x016B2E, 0x016B64, 0x016B21, 0x016B28, 0x016B6B, 0x016B2F, + 0x016A4A, 0x016B69, 0x016A60, 0x016A61, 0x0032BC, 0x011C07, 0x011C5F, 0x0010BA, + 0x0010BB, 0x016A65, 0x016A66, 0x016A67, 0x011C5B, 0x016A69, 0x016B2C, 0x011D02, + 0x011D17, 0x016B8C, 0x011D01, 0x011D1C, 0x016B50, 0x016B59, 0x016B56, 0x016B55, + 0x011D1E, 0x011D1A, 0x011D1B, 0x016B57, 0x011D19, 0x011D18, 0x011D00, 0x016B08, + 0x016B5B, 0x011D13, 0x016B13, 0x016B06, 0x016B54, 0x011D12, 0x016B5D, 0x011D10, + 0x011D11, 0x011D14, 0x011D1F, 0x016B05, 0x011D15, 0x011D16, 0x016B52, 0x016B53, + 0x016B5E, 0x016B5F, 0x011D03, 0x016B51, 0x011D21, 0x011D22, 0x016B60, 0x011D29, + 0x011D2B, 0x016B04, 0x011D20, 0x016B66, 0x016B6A, 0x011D26, 0x011D2D, 0x016B63, + 0x011D1D, 0x011D30, 0x016B68, 0x011D24, 0x016B73, 0x016B61, 0x016B12, 0x016B67, + 0x016B72, 0x016B71, 0x016B7D, 0x011D52, 0x016B58, 0x011D2A, 0x016B7E, 0x016B7F, + 0x016B0E, 0x016B0D, 0x016B0F, 0x011C01, 0x011C00, 0x016B80, 0x016B83, 0x016B82, + 0x016B87, 0x016B81, 0x016B89, 0x016B8B, 0x011C0F, 0x016B8D, 0x016B88, 0x016B8A, + 0x016B86, 0x001080, 0x016B8F, 0x016B8E, 0x011D53, 0x001011, 0x011C0C, 0x011C0A, + 0x016B84, 0x016B85, 0x011C0E, 0x0010A3, 0x011C08, 0x0010EC, 0x0010B4, 0x0010A0, + 0x0010A4, 0x0010A2, 0x0032B1, 0x011C26, 0x011C2B, 0x001013, 0x011C25, 0x011D2C, + 0x011D28, 0x011C24, 0x011C0D, 0x011D2F, 0x001012, 0x0010BC, 0x011D2E, 0x0010A6, + 0x003283, 0x0010C4, 0x001010, 0x0010C3, 0x0010C5, 0x0010C7, 0x0010D3, 0x011C28, + 0x011C29, 0x011C2A, 0x0010ED, 0x011C2C, 0x0010CD, 0x003282, 0x001098, 0x001017, + 0x001096, 0x001095, 0x001094, 0x011D04, 0x011D05, 0x011D06, 0x001097, 0x011D08, + 0x011D09, 0x001099, 0x011D0B, 0x011D0C, 0x011D0D, 0x011D0E, 0x011D0F, 0x0010DC, + 0x0010D2, 0x003281, 0x0010E1, 0x0010E3, 0x0010E6, 0x0010E7, 0x0010D1, 0x0010E0, + 0x0010E8, 0x0010E9, 0x0010EA, 0x0010EB, 0x0010E5, 0x0010FD, 0x0010E4, 0x0010EF, + 0x016B5C, 0x0010F0, 0x011D23, 0x0010F2, 0x0010F5, 0x0010F1, 0x0010F7, 0x0010F4, + 0x0010F8, 0x0010EE, 0x0010FA, 0x0010F9, 0x0010FF, 0x0010FE, 0x003280, 0x0010F6, + 0x016B6C, 0x016B6D, 0x016B6E, 0x001022, 0x016B70, 0x001020, 0x001026, 0x001027, + 0x016B74, 0x016B75, 0x016B76, 0x016B77, 0x00100C, 0x001025, 0x001024, 0x001029, + 0x001310, 0x001315, 0x001312, 0x001313, 0x001014, 0x001015, 0x001016, 0x00101D, + 0x001018, 0x001019, 0x00101A, 0x00101B, 0x00102A, 0x00101F, 0x00101E, 0x011D50, + 0x011D51, 0x001163, 0x001162, 0x00117D, 0x001167, 0x001161, 0x011D57, 0x00117E, + 0x001178, 0x001160, 0x001179, 0x00117A, 0x001168, 0x00117F, 0x001166, 0x00116A, + 0x00116C, 0x001021, 0x00116E, 0x001023, 0x001174, 0x001165, 0x001164, 0x00116D, + 0x00117B, 0x001170, 0x001169, 0x00116B, 0x00117C, 0x001175, 0x001176, 0x00116F, + 0x001040, 0x001041, 0x001042, 0x001043, 0x001047, 0x00114D, 0x00114E, 0x00114F, + 0x001049, 0x001044, 0x00114A, 0x001302, 0x001045, 0x001148, 0x00114C, 0x001046, + 0x001318, 0x001304, 0x001303, 0x001334, 0x001314, 0x00131C, 0x001306, 0x001301, + 0x001048, 0x001319, 0x00131A, 0x00131B, 0x00105C, 0x00131D, 0x00131E, 0x00131F, + 0x001172, 0x001061, 0x00133C, 0x001332, 0x001065, 0x001333, 0x001177, 0x001066, + 0x001331, 0x00130C, 0x001352, 0x001353, 0x001330, 0x001351, 0x00106E, 0x001337, + 0x001070, 0x001171, 0x001300, 0x001173, 0x001324, 0x001075, 0x001076, 0x001077, + 0x00107C, 0x001079, 0x00107A, 0x00107B, 0x001078, 0x00107D, 0x00107E, 0x00107F, + 0x001380, 0x001381, 0x001382, 0x001383, 0x001384, 0x001385, 0x001386, 0x001387, + 0x001388, 0x001389, 0x00138A, 0x00138B, 0x0013E9, 0x00138D, 0x00138E, 0x00138F, + 0x001308, 0x001309, 0x00130E, 0x00130D, 0x00130F, 0x001305, 0x001336, 0x001307, + 0x0013E8, 0x0013ED, 0x00130A, 0x00130B, 0x0013EC, 0x0013AD, 0x0013EE, 0x0013EF, + 0x0013A0, 0x0010A1, 0x0013A2, 0x0013A3, 0x0013A1, 0x0010A5, 0x0013A4, 0x0010A7, + 0x0010A8, 0x0010A9, 0x0010AA, 0x0010AB, 0x0010AC, 0x0010AD, 0x0010AE, 0x0010AF, + 0x0013A8, 0x0013A9, 0x0013AE, 0x0013AF, 0x0013AC, 0x0013A5, 0x0013A6, 0x0013A7, + 0x0010B8, 0x0010B9, 0x0013AA, 0x0013AB, 0x0013BC, 0x0010BD, 0x0010BE, 0x0010BF, + 0x0013C1, 0x0013C2, 0x0013C3, 0x0013D6, 0x0013C5, 0x0013D5, 0x0013C7, 0x0013D7, + 0x0013D8, 0x0013D9, 0x0013C0, 0x0013DB, 0x0013C6, 0x0013DD, 0x0013DA, 0x0013DF, + 0x0010D0, 0x0013D4, 0x0013D3, 0x0013DC, 0x0010D4, 0x0010D5, 0x0010D6, 0x0010D7, + 0x0013D2, 0x0010D9, 0x0010DA, 0x0010DB, 0x0013D1, 0x0010DD, 0x0010DE, 0x0013D0, + 0x0013E0, 0x0013E1, 0x0013E2, 0x0013E3, 0x0013C4, 0x0013E5, 0x0013E6, 0x0013E7, + 0x0013C8, 0x0013C9, 0x0013CA, 0x0013CB, 0x0013CC, 0x0013CD, 0x0013CE, 0x0013CF, + 0x0013F0, 0x0013F1, 0x0013F2, 0x0013F3, 0x0013F4, 0x0013F5, 0x0013E4, 0x0013EA, + 0x0013F8, 0x0013F9, 0x0013FA, 0x0013FB, 0x0013FC, 0x0013FD, 0x0013DE, 0x0013EB, + 0x02F848, 0x02F849, 0x02F84A, 0x02F84B, 0x02F844, 0x02F845, 0x02F846, 0x02F847, + 0x02F840, 0x02F841, 0x02F842, 0x02F843, 0x02F85C, 0x02F85D, 0x02F85E, 0x02F82F, + 0x02F828, 0x02F829, 0x02F82A, 0x02F82B, 0x02F824, 0x02F825, 0x02F826, 0x02F827, + 0x02F820, 0x02F821, 0x02F822, 0x02F823, 0x02F83C, 0x02F83D, 0x02F83E, 0x02F83F, + 0x001524, 0x001520, 0x02F838, 0x001523, 0x02F839, 0x001521, 0x001522, 0x02F83A, + 0x00152B, 0x02F83B, 0x02F834, 0x02F835, 0x00152C, 0x001525, 0x001526, 0x001527, + 0x02F836, 0x001529, 0x02F837, 0x02F830, 0x001534, 0x00153D, 0x02F831, 0x00152D, + 0x001538, 0x00153B, 0x00153A, 0x00152A, 0x00153C, 0x001539, 0x00153E, 0x00153F, + 0x02F832, 0x02F833, 0x02F80C, 0x02F80D, 0x02F80E, 0x02F80F, 0x02F808, 0x02F809, + 0x02F80A, 0x02F80B, 0x02F804, 0x02F805, 0x02F806, 0x02F807, 0x02F800, 0x02F801, + 0x001553, 0x02F802, 0x001554, 0x02F803, 0x001556, 0x001551, 0x001552, 0x02F81C, + 0x001550, 0x02F81D, 0x00155A, 0x00155B, 0x001558, 0x001555, 0x02F81E, 0x001557, + 0x02F81F, 0x001260, 0x02F818, 0x02F819, 0x02F81A, 0x001267, 0x02F81B, 0x02F814, + 0x001268, 0x02F815, 0x02F816, 0x02F817, 0x00126C, 0x02F810, 0x00126E, 0x00126F, + 0x00155D, 0x001559, 0x02F811, 0x02F812, 0x02F813, 0x02F8EC, 0x00155E, 0x00155F, + 0x02F8ED, 0x02F8EE, 0x02F8EF, 0x02F8E8, 0x02F8E9, 0x02F8EA, 0x02F8EB, 0x02F8E4, + 0x02F8E5, 0x02F8E6, 0x02F8E7, 0x02F8E0, 0x001284, 0x02F8E1, 0x02F8E2, 0x02F8E3, + 0x001288, 0x02F8FC, 0x00128A, 0x00128B, 0x02F8FD, 0x02F8FE, 0x02F8FF, 0x02F8F8, + 0x02F8F9, 0x02F8FA, 0x02F8FB, 0x02F8F4, 0x02F8F5, 0x02F8F6, 0x02F8F7, 0x02F8F0, + 0x001298, 0x001299, 0x02F8F1, 0x01230E, 0x01230F, 0x00129D, 0x00129E, 0x00129F, + 0x012308, 0x012309, 0x01230A, 0x01230B, 0x012304, 0x012305, 0x012306, 0x012307, + 0x012300, 0x012301, 0x012302, 0x012303, 0x01231C, 0x01231D, 0x01231E, 0x01231F, + 0x012318, 0x012319, 0x01231A, 0x01231B, 0x012314, 0x012315, 0x012316, 0x012317, + 0x012310, 0x012311, 0x012312, 0x012313, 0x01238C, 0x01238D, 0x01238E, 0x01238F, + 0x012388, 0x012389, 0x01238A, 0x01238B, 0x012384, 0x012385, 0x012386, 0x012387, + 0x012380, 0x012381, 0x012382, 0x012383, 0x012398, 0x012399, 0x012394, 0x012395, + 0x012396, 0x012397, 0x012390, 0x012391, 0x012392, 0x012393, 0x01206C, 0x01206D, + 0x01206E, 0x01BC01, 0x01BC00, 0x01BC03, 0x01BC02, 0x01BC05, 0x01BC04, 0x01BC07, + 0x01BC06, 0x01BC09, 0x01BC08, 0x01BC0B, 0x01BC0A, 0x01BC0D, 0x01BC0C, 0x01BC0F, + 0x01BC0E, 0x01BC11, 0x01BC10, 0x01BC13, 0x01BC12, 0x01BC15, 0x01BC14, 0x01BC17, + 0x01BC16, 0x01BC19, 0x01BC18, 0x01BC1B, 0x01BC1A, 0x01BC1D, 0x01BC1C, 0x01BC1F, + 0x01BC1E, 0x01BC21, 0x01BC20, 0x01BC23, 0x01BC22, 0x01206F, 0x012068, 0x01BC27, + 0x01BC26, 0x001581, 0x001582, 0x001583, 0x001599, 0x00159C, 0x001587, 0x00159B, + 0x00159A, 0x01BC31, 0x01BC30, 0x01BC33, 0x01BC32, 0x01BC35, 0x01BC34, 0x01BC37, + 0x01BC36, 0x01BC39, 0x01BC38, 0x01BC3B, 0x01BC3A, 0x01BC3D, 0x01BC3C, 0x01BC3F, + 0x01BC3E, 0x001590, 0x001593, 0x001592, 0x001595, 0x001594, 0x001597, 0x001596, + 0x001580, 0x001585, 0x001586, 0x01BC52, 0x01BC53, 0x01BC50, 0x01BC51, 0x01BC57, + 0x00158A, 0x001589, 0x01BC69, 0x00158B, 0x01BC68, 0x0015A1, 0x00159D, 0x0015AC, + 0x001533, 0x0015B1, 0x00159E, 0x00159F, 0x001536, 0x001531, 0x001532, 0x001530, + 0x00150C, 0x01BC64, 0x001537, 0x01BC6A, 0x001598, 0x01BC24, 0x01BC25, 0x00150D, + 0x01BC65, 0x01BC28, 0x01BC29, 0x01BC2A, 0x01BC2B, 0x01BC2C, 0x01BC2D, 0x01BC2E, + 0x01BC2F, 0x0015D1, 0x0015D2, 0x0015D3, 0x001535, 0x0015D5, 0x0015D6, 0x012228, + 0x01222C, 0x0120E0, 0x01225B, 0x0120EE, 0x0120ED, 0x0120EF, 0x0120EC, 0x0120E8, + 0x0120E9, 0x01BC81, 0x0120E6, 0x01BC62, 0x01BC63, 0x01BC85, 0x01BC84, 0x01BC83, + 0x012013, 0x01BC61, 0x01BC88, 0x01BC60, 0x012254, 0x012012, 0x01BC66, 0x012010, + 0x01BC67, 0x01BC92, 0x01BC90, 0x01BC93, 0x01BC91, 0x01BC96, 0x01BC78, 0x01BC97, + 0x0120FC, 0x01BC7A, 0x0120E3, 0x01BC98, 0x01BC99, 0x0120FD, 0x01BC95, 0x01BC94, + 0x01BC82, 0x01BC80, 0x0120E1, 0x01BC7C, 0x012016, 0x01BC74, 0x012017, 0x01BC86, + 0x01BC87, 0x0120E2, 0x01BC79, 0x0120EA, 0x01BC76, 0x01BC77, 0x0120E7, 0x0120F8, + 0x0120F9, 0x01BC70, 0x01BC7B, 0x01BC72, 0x01BC73, 0x0120FE, 0x01BC75, 0x0120C0, + 0x0120C1, 0x0120C2, 0x0120C3, 0x0120C4, 0x0120C5, 0x0120C6, 0x0120C7, 0x0120C8, + 0x0120C9, 0x0120CA, 0x0120CB, 0x01BC42, 0x01BC43, 0x01BC44, 0x01BC45, 0x01BC4E, + 0x01BC4F, 0x01BC4C, 0x01BC49, 0x012253, 0x01BC48, 0x01BC4A, 0x01BC4D, 0x01BC4B, + 0x0120CF, 0x012252, 0x012251, 0x0120DC, 0x012250, 0x01BC54, 0x01BC55, 0x01BC56, + 0x01BC41, 0x01BC58, 0x01BC59, 0x01BC5A, 0x01BC5B, 0x01BC5C, 0x01BC5D, 0x01BC5E, + 0x01BC5F, 0x01BC40, 0x01BC71, 0x0120CC, 0x0120CD, 0x0120CE, 0x0120FF, 0x01BC46, + 0x01BC47, 0x0120F2, 0x0120F3, 0x0120F1, 0x0120F6, 0x0120F0, 0x0120F7, 0x012256, + 0x012255, 0x012257, 0x0120FB, 0x0120F4, 0x0120F5, 0x0120FA, 0x0122ED, 0x012081, + 0x012080, 0x012083, 0x012082, 0x012085, 0x012084, 0x012087, 0x012086, 0x012089, + 0x012088, 0x01208B, 0x01208A, 0x01208D, 0x01208C, 0x01208F, 0x01208E, 0x0120D0, + 0x0120D1, 0x0120D2, 0x0120D3, 0x0120D4, 0x0120D5, 0x0120D6, 0x0120D7, 0x012099, + 0x012098, 0x0120DA, 0x0120DB, 0x01209D, 0x01209C, 0x01209F, 0x01209E, 0x0120A1, + 0x0120A0, 0x0120A3, 0x0120A2, 0x0120A5, 0x0120A4, 0x0120A7, 0x0120A6, 0x0120A9, + 0x0120A8, 0x0120AB, 0x0120AA, 0x0120AD, 0x0120AC, 0x0120AF, 0x0120AE, 0x0120B1, + 0x0120B0, 0x0120B3, 0x0120B2, 0x0120B5, 0x0120B4, 0x0120B7, 0x0120B6, 0x0120B9, + 0x0120B8, 0x0120BB, 0x0120BA, 0x0120BD, 0x0120BC, 0x0120BF, 0x0120BE, 0x0120D8, + 0x0120D9, 0x0120DE, 0x0120DF, 0x0120DD, 0x016F01, 0x016F00, 0x016F03, 0x016F02, + 0x016F05, 0x016F04, 0x016F07, 0x016F06, 0x016F09, 0x016F08, 0x016F0B, 0x016F0A, + 0x016F0D, 0x016F0C, 0x016F0F, 0x016F0E, 0x016F11, 0x016F10, 0x016F13, 0x016F12, + 0x016F15, 0x016F14, 0x016F17, 0x016F16, 0x016F19, 0x016F18, 0x016F1B, 0x016F1A, + 0x016F1D, 0x016F1C, 0x016F1F, 0x016F1E, 0x016F21, 0x016F20, 0x016F23, 0x016F22, + 0x016F25, 0x016F24, 0x016F27, 0x016F26, 0x016F29, 0x016F28, 0x016F2B, 0x016F2A, + 0x016F2D, 0x016F2C, 0x016F2F, 0x016F2E, 0x016F31, 0x016F30, 0x016F33, 0x016F32, + 0x016F35, 0x016F34, 0x016F37, 0x016F36, 0x016F39, 0x016F38, 0x016F3B, 0x016F3A, + 0x016F3D, 0x016F3C, 0x016F3F, 0x012106, 0x012107, 0x016F43, 0x016F40, 0x012102, + 0x01210B, 0x016F44, 0x012103, 0x012109, 0x012105, 0x01210F, 0x016F42, 0x012111, + 0x012110, 0x012113, 0x012112, 0x001369, 0x012108, 0x012117, 0x016F50, 0x012119, + 0x01211B, 0x012118, 0x012104, 0x01211D, 0x01211F, 0x01211C, 0x01211E, 0x00136A, + 0x001282, 0x001281, 0x016F41, 0x001283, 0x001286, 0x001285, 0x001280, 0x001287, + 0x00136C, 0x00136D, 0x00129C, 0x01210C, 0x01210D, 0x01210E, 0x00136E, 0x00136F, + 0x001212, 0x012133, 0x012132, 0x001213, 0x001211, 0x00121C, 0x012136, 0x001217, + 0x001219, 0x001218, 0x00121B, 0x00121A, 0x001216, 0x001215, 0x001214, 0x012240, + 0x012241, 0x012243, 0x016F3E, 0x012244, 0x012245, 0x012242, 0x012247, 0x012248, + 0x012249, 0x01224A, 0x01224B, 0x01224C, 0x01224D, 0x012246, 0x01224F, 0x001210, + 0x001200, 0x001204, 0x001207, 0x001203, 0x00121D, 0x00121E, 0x00121F, 0x012258, + 0x012259, 0x01225A, 0x01224E, 0x01225C, 0x01225D, 0x01225E, 0x01225F, 0x012260, + 0x012261, 0x012262, 0x012263, 0x012264, 0x012265, 0x012266, 0x012267, 0x012268, + 0x012269, 0x01226A, 0x01226B, 0x01226C, 0x01226D, 0x01226E, 0x01226F, 0x012270, + 0x012271, 0x012272, 0x012273, 0x012274, 0x012275, 0x012276, 0x012277, 0x012278, + 0x012279, 0x01227A, 0x01227B, 0x01227C, 0x01227D, 0x01227E, 0x01227F, 0x001229, + 0x001254, 0x001244, 0x001248, 0x001264, 0x001293, 0x001205, 0x001206, 0x001256, + 0x001228, 0x00125A, 0x00120B, 0x00125B, 0x001258, 0x00127D, 0x00122E, 0x00124B, + 0x0012E0, 0x0012E1, 0x0012E6, 0x0012E7, 0x0012E4, 0x001221, 0x001222, 0x001223, + 0x001220, 0x001226, 0x0012EA, 0x0012EB, 0x0012EC, 0x001227, 0x0012E9, 0x0012E5, + 0x0121E1, 0x00122B, 0x0012F5, 0x001232, 0x0012F4, 0x001224, 0x00122A, 0x00122F, + 0x0012F9, 0x0012F8, 0x0012EE, 0x00123A, 0x0012ED, 0x0012EF, 0x0012FF, 0x0012FE, + 0x001320, 0x001291, 0x001296, 0x001295, 0x00132C, 0x001297, 0x001322, 0x001323, + 0x001321, 0x001328, 0x001325, 0x001327, 0x00133D, 0x00133E, 0x00133F, 0x0121C1, + 0x0121C0, 0x0121C3, 0x0121C2, 0x0121C5, 0x0121C4, 0x0121C7, 0x0121C6, 0x0121C9, + 0x0121C8, 0x0121CB, 0x0121CA, 0x0121CD, 0x0121CC, 0x0121CF, 0x0121CE, 0x001338, + 0x001339, 0x00133A, 0x00133B, 0x0121D5, 0x0121D4, 0x001335, 0x0121D6, 0x0121D9, + 0x0121D8, 0x0121DB, 0x0121DA, 0x0121DD, 0x0121DC, 0x0121DF, 0x0121DE, 0x00D7BE, + 0x0121E0, 0x0121E3, 0x0121E2, 0x0121E5, 0x0121E4, 0x0121E7, 0x0121E6, 0x0121E9, + 0x0121E8, 0x0121EB, 0x0121EA, 0x0121ED, 0x0121EC, 0x0121EF, 0x0121EE, 0x0121F1, + 0x0121F0, 0x0121F3, 0x0121F2, 0x0121F5, 0x0121F4, 0x0121F7, 0x0121F6, 0x0121F9, + 0x0121F8, 0x0121FB, 0x0121FA, 0x0121FD, 0x0121FC, 0x0121FF, 0x0121FE, 0x012201, + 0x012200, 0x001350, 0x001356, 0x012205, 0x012204, 0x012202, 0x012203, 0x012209, + 0x012208, 0x01220B, 0x01220A, 0x001354, 0x001357, 0x012206, 0x012207, 0x012211, + 0x012210, 0x012213, 0x012212, 0x012215, 0x012214, 0x012217, 0x012216, 0x012219, + 0x012218, 0x01221B, 0x01221A, 0x01221D, 0x01221C, 0x01221F, 0x01221E, 0x001326, + 0x00129B, 0x012232, 0x00135A, 0x001359, 0x001294, 0x001355, 0x012231, 0x00129A, + 0x001358, 0x001329, 0x00132A, 0x00132B, 0x00132E, 0x00132D, 0x01220F, 0x00132F, + 0x001379, 0x001371, 0x001378, 0x00137B, 0x001290, 0x001375, 0x001292, 0x001377, + 0x012233, 0x00134C, 0x00D7B8, 0x00D7B9, 0x00D7BA, 0x01220E, 0x00D7BC, 0x012220, + 0x012221, 0x00D7BF, 0x00D7BB, 0x012224, 0x012225, 0x012222, 0x012223, 0x012238, + 0x012229, 0x01222A, 0x01222B, 0x00D7B6, 0x00D7B7, 0x012226, 0x012227, 0x012230, + 0x012234, 0x01222E, 0x01222F, 0x00D7B4, 0x012235, 0x012236, 0x012237, 0x012239, + 0x00D7B5, 0x01223A, 0x01223B, 0x01223C, 0x01223D, 0x01223E, 0x01223F, 0x00134E, + 0x00D7D1, 0x00D7D3, 0x001373, 0x001372, 0x00D7D2, 0x001374, 0x001376, 0x00137C, + 0x01222D, 0x001370, 0x00136B, 0x01220C, 0x01220D, 0x00134D, 0x00137A, 0x00134F, + 0x001340, 0x001341, 0x001342, 0x001343, 0x001344, 0x001345, 0x001346, 0x001347, + 0x001348, 0x00134B, 0x00134A, 0x00D7D7, 0x001349, 0x00D7D0, 0x00D7BD, 0x012281, + 0x012280, 0x0122A8, 0x0122CE, 0x012285, 0x012284, 0x012282, 0x012283, 0x012289, + 0x012288, 0x01228B, 0x01228A, 0x01228D, 0x01228C, 0x012286, 0x012287, 0x012291, + 0x012290, 0x012293, 0x012292, 0x012295, 0x012294, 0x012297, 0x012296, 0x012299, + 0x012298, 0x01229B, 0x01229A, 0x01229D, 0x01229C, 0x01229F, 0x01229E, 0x0122A1, + 0x0122A0, 0x0122A3, 0x0122A2, 0x0122A5, 0x0122A4, 0x0122A7, 0x0122A6, 0x0122A9, + 0x0122B9, 0x0122AB, 0x0122AA, 0x0122AD, 0x0122AC, 0x0122AF, 0x0122AE, 0x0122B1, + 0x0122B0, 0x0122B3, 0x0122B2, 0x0122B5, 0x0122B4, 0x0122B7, 0x0122B6, 0x01228F, + 0x0122B8, 0x0122BB, 0x0122BA, 0x0122BD, 0x0122BC, 0x0122BF, 0x0122BE, 0x0122C1, + 0x0122C0, 0x0122C3, 0x0122C2, 0x0122C5, 0x0122C4, 0x0122E8, 0x0122C6, 0x0122C9, + 0x0122D9, 0x0122CB, 0x0122CA, 0x0122CD, 0x0122CC, 0x0122CF, 0x0122C7, 0x0122D1, + 0x01228E, 0x0122D3, 0x0122D2, 0x0122D5, 0x0122D4, 0x0122D7, 0x0122D6, 0x0122D0, + 0x0122D8, 0x0122DB, 0x0122DA, 0x0122DD, 0x0122DC, 0x0122DF, 0x0122DE, 0x0122E2, + 0x0122E0, 0x0122E3, 0x0122FD, 0x0122E6, 0x0122E4, 0x0122E7, 0x0122E1, 0x0122EA, + 0x0122F9, 0x0122EB, 0x0122E5, 0x0122EF, 0x0122EC, 0x0122FE, 0x0122E9, 0x0122F1, + 0x0122F0, 0x0122F3, 0x0122F2, 0x0122F5, 0x0122F4, 0x0122F7, 0x0122F6, 0x0122C8, + 0x0122F8, 0x0122FB, 0x0122FA, 0x0122FF, 0x0122FC, 0x02F861, 0x02F860, 0x02F863, + 0x01230C, 0x012324, 0x01234F, 0x02F867, 0x02F866, 0x02F869, 0x02F868, 0x01230D, + 0x02F86A, 0x02F86D, 0x02F86C, 0x02F86F, 0x02F86E, 0x02F871, 0x02F870, 0x02F82E, + 0x02F82D, 0x02F875, 0x02F874, 0x02F877, 0x02F876, 0x02F879, 0x02F878, 0x02F87B, + 0x02F87A, 0x02F87D, 0x02F87C, 0x02F87F, 0x02F87E, 0x02F890, 0x02F897, 0x01232C, + 0x012320, 0x012323, 0x012322, 0x012325, 0x012321, 0x012327, 0x012326, 0x012338, + 0x012328, 0x01232B, 0x01232A, 0x01232D, 0x012329, 0x01232F, 0x01232E, 0x012334, + 0x012330, 0x012333, 0x012332, 0x012335, 0x012331, 0x012337, 0x012336, 0x01233C, + 0x02F891, 0x01233B, 0x01233A, 0x01233D, 0x012339, 0x01233F, 0x01233E, 0x012341, + 0x012340, 0x012343, 0x012342, 0x012345, 0x012344, 0x012347, 0x012346, 0x012349, + 0x012359, 0x01234B, 0x01234A, 0x01234D, 0x01234C, 0x012364, 0x01234E, 0x012351, + 0x012350, 0x012353, 0x012352, 0x012355, 0x012354, 0x012357, 0x012356, 0x0122EE, + 0x012358, 0x01235B, 0x01235A, 0x01235D, 0x01235C, 0x01235F, 0x01235E, 0x012361, + 0x012360, 0x012363, 0x012362, 0x012365, 0x012375, 0x012367, 0x012366, 0x012369, + 0x012368, 0x01236B, 0x01236A, 0x01236D, 0x01236C, 0x01236F, 0x01236E, 0x012371, + 0x012370, 0x012373, 0x012372, 0x012348, 0x012374, 0x012377, 0x012376, 0x012379, + 0x012378, 0x01237B, 0x01237A, 0x01237D, 0x01237C, 0x01237F, 0x01237E, 0x02F882, + 0x02F883, 0x02F880, 0x02F881, 0x02F886, 0x02F887, 0x02F888, 0x02F889, 0x02F88A, + 0x02F88B, 0x02F884, 0x02F885, 0x02F89E, 0x02F88F, 0x02F88C, 0x02F88D, 0x02F892, + 0x02F893, 0x02F894, 0x02F895, 0x02F896, 0x02F8B3, 0x02F898, 0x02F899, 0x02F94C, + 0x02F89B, 0x02F89C, 0x02F89D, 0x02F89F, 0x02F89A, 0x02F901, 0x02F900, 0x02F903, + 0x02F902, 0x02F905, 0x02F904, 0x02F907, 0x02F906, 0x02F909, 0x02F908, 0x02F90B, + 0x02F90A, 0x02F90D, 0x02F90C, 0x02F90F, 0x02F91F, 0x02F911, 0x02F910, 0x02F913, + 0x02F912, 0x02F915, 0x02F914, 0x02F917, 0x02F916, 0x02F919, 0x02F918, 0x02F91B, + 0x02F91A, 0x02F91D, 0x02F91C, 0x02F92E, 0x02F91E, 0x02F921, 0x02F920, 0x02F923, + 0x02F922, 0x02F90E, 0x02F924, 0x02F927, 0x02F926, 0x02F929, 0x02F928, 0x02F92B, + 0x02F92A, 0x02F92D, 0x02F925, 0x02F92F, 0x02F93F, 0x02F931, 0x02F930, 0x02F933, + 0x02F932, 0x02F935, 0x02F934, 0x02F937, 0x02F82C, 0x02F939, 0x02F938, 0x02F93B, + 0x02F93A, 0x02F93D, 0x02F93C, 0x02F936, 0x02F93E, 0x02F941, 0x02F947, 0x02F940, + 0x02F942, 0x02F945, 0x02F94B, 0x02F944, 0x02F946, 0x02F949, 0x02F94F, 0x02F948, + 0x02F94A, 0x02F95C, 0x02F96D, 0x02F94D, 0x02F95F, 0x02F951, 0x02F950, 0x02F953, + 0x02F952, 0x02F955, 0x02F954, 0x02F957, 0x02F956, 0x02F959, 0x02F958, 0x02F95B, + 0x02F95A, 0x02F96C, 0x02F943, 0x02F95D, 0x02F95E, 0x02F94E, 0x02F92C, 0x02F963, + 0x02F962, 0x02F960, 0x02F961, 0x02F967, 0x02F966, 0x02F969, 0x02F968, 0x02F96B, + 0x02F96A, 0x02F964, 0x02F965, 0x02F96F, 0x02F96E, 0x02F971, 0x02F970, 0x02F853, + 0x02F972, 0x02F975, 0x02F974, 0x02F977, 0x02F976, 0x02F979, 0x02F978, 0x02F97B, + 0x02F97A, 0x02F97D, 0x02F97C, 0x02F97F, 0x02F97E, 0x02F981, 0x02F980, 0x02F983, + 0x02F987, 0x02F985, 0x02F984, 0x02F982, 0x02F986, 0x02F989, 0x02F988, 0x02F98B, + 0x02F98F, 0x02F98D, 0x02F98C, 0x02F99E, 0x02F98E, 0x02F991, 0x02F990, 0x02F9AE, + 0x02F997, 0x02F995, 0x02F994, 0x02F993, 0x02F996, 0x02F999, 0x02F998, 0x02F99B, + 0x02F99F, 0x02F99D, 0x02F99C, 0x02F99A, 0x02F992, 0x02F9A1, 0x02F9A0, 0x02F9A3, + 0x02F9A2, 0x02F9A5, 0x02F9A4, 0x02F9A7, 0x02F9A6, 0x02F9A9, 0x02F9A8, 0x02F9AB, + 0x02F9AA, 0x02F98A, 0x02F9AC, 0x02F9AF, 0x02F9BF, 0x02F9B1, 0x02F9B0, 0x02F9B3, + 0x02F9EC, 0x02F9B5, 0x02F9B4, 0x02F9B7, 0x02F9B6, 0x02F9B9, 0x02F9B8, 0x02F9BB, + 0x02F9BA, 0x02F9BD, 0x02F9BC, 0x02F9B2, 0x02F9BE, 0x02F9C1, 0x02F9C0, 0x02F9C3, + 0x02F9C2, 0x02F9C5, 0x02F9C4, 0x02F9C7, 0x02F9C6, 0x02F9C9, 0x02F9C8, 0x02F9CB, + 0x02F9DB, 0x02F9CD, 0x02F9CC, 0x02F9CF, 0x02F9CE, 0x02F9D1, 0x02F9D0, 0x02F9D3, + 0x02F9D2, 0x02F9D5, 0x02F9D4, 0x02F9D7, 0x02F9D6, 0x02F9D9, 0x02F9D8, 0x02F9ED, + 0x02F9DA, 0x02F9DD, 0x02F9DC, 0x02F9DF, 0x02F9DE, 0x02F9CA, 0x02F9AD, 0x02F9E3, + 0x02F9E2, 0x02F9E0, 0x02F9E1, 0x02F9E7, 0x02F9E6, 0x02F9E9, 0x02F9E8, 0x02F9EB, + 0x02F9EA, 0x02F9E4, 0x02F9E5, 0x02F9EF, 0x02F9EE, 0x02F9F1, 0x02F9F0, 0x02F9F3, + 0x02F9F2, 0x02F9F5, 0x02F9F4, 0x02F9F7, 0x02F9F6, 0x02F9F9, 0x02F9F8, 0x02F9FB, + 0x02F9FA, 0x02F9FD, 0x02F9FC, 0x02F9FF, 0x02F9FE, 0x012069, 0x01206A, 0x01206B, + 0x012064, 0x012065, 0x012066, 0x012067, 0x012060, 0x012061, 0x012062, 0x012063, + 0x01207C, 0x01207D, 0x01207E, 0x01207F, 0x012078, 0x012079, 0x01207A, 0x01207B, + 0x012074, 0x012075, 0x012076, 0x012077, 0x012070, 0x012071, 0x012072, 0x012073, + 0x01204C, 0x01204D, 0x01204E, 0x01204F, 0x012048, 0x012049, 0x01204A, 0x01204B, + 0x012044, 0x012045, 0x012046, 0x012047, 0x012040, 0x012041, 0x012042, 0x012043, + 0x01205C, 0x01205D, 0x01205E, 0x00D7B0, 0x01205F, 0x012058, 0x012059, 0x01205A, + 0x01205B, 0x012054, 0x012055, 0x012056, 0x012057, 0x012050, 0x012051, 0x012052, + 0x012053, 0x01202C, 0x01202D, 0x01202E, 0x01202F, 0x012028, 0x012029, 0x01202A, + 0x01202B, 0x012024, 0x012025, 0x012026, 0x00D7B1, 0x012027, 0x012020, 0x012021, + 0x012022, 0x012023, 0x01203C, 0x01203D, 0x01203E, 0x01203F, 0x012038, 0x012039, + 0x01203A, 0x01203B, 0x012034, 0x012035, 0x012036, 0x012037, 0x012030, 0x012031, + 0x012032, 0x012033, 0x01200C, 0x01200D, 0x01200E, 0x02F862, 0x02F864, 0x012501, + 0x012500, 0x012503, 0x012502, 0x02F865, 0x012504, 0x012525, 0x02F86B, 0x012509, + 0x012508, 0x01250B, 0x01250A, 0x01250D, 0x01250C, 0x01250F, 0x01250E, 0x012511, + 0x012510, 0x012513, 0x012512, 0x012515, 0x012514, 0x012517, 0x012516, 0x012519, + 0x012518, 0x01251B, 0x01251A, 0x01251D, 0x012524, 0x01251F, 0x01251E, 0x012521, + 0x012520, 0x012523, 0x012522, 0x01253C, 0x012535, 0x012527, 0x01200F, 0x01252B, + 0x012526, 0x012008, 0x012529, 0x012009, 0x01200A, 0x01252A, 0x01200B, 0x012531, + 0x012530, 0x012533, 0x012532, 0x012537, 0x02F8BB, 0x02F8B5, 0x012536, 0x02F8B4, + 0x012538, 0x012004, 0x012005, 0x01253D, 0x02F8B2, 0x01253F, 0x01253E, 0x012006, + 0x012007, 0x012000, 0x012001, 0x02F88E, 0x012002, 0x012003, 0x01201C, 0x01201D, + 0x01201E, 0x01201F, 0x012018, 0x012019, 0x01201A, 0x01201B, 0x012014, 0x012015, + 0x012011, 0x0120EB, 0x0120E4, 0x02F8B1, 0x0120E5, 0x02F8B0, 0x01209A, 0x01209B, + 0x02F8B6, 0x012094, 0x02F8B7, 0x012095, 0x012096, 0x012097, 0x012090, 0x012091, + 0x012092, 0x012093, 0x01216C, 0x01216D, 0x01216E, 0x01216F, 0x012168, 0x012169, + 0x01216A, 0x01216B, 0x012164, 0x012165, 0x012166, 0x012167, 0x012160, 0x012161, + 0x012162, 0x012163, 0x01217C, 0x01217D, 0x01217E, 0x01217F, 0x012178, 0x012179, + 0x01217A, 0x01217B, 0x012174, 0x012175, 0x012176, 0x012177, 0x02F8B9, 0x012170, + 0x012171, 0x012172, 0x012173, 0x01214C, 0x01214D, 0x01214E, 0x01214F, 0x012148, + 0x012149, 0x01214A, 0x01214B, 0x012144, 0x012145, 0x012146, 0x012147, 0x012140, + 0x012141, 0x012142, 0x012143, 0x01215C, 0x01215D, 0x01215E, 0x01215F, 0x012158, + 0x02F8BA, 0x012159, 0x01215A, 0x01215B, 0x012154, 0x012155, 0x012156, 0x012157, + 0x012150, 0x012151, 0x012152, 0x012153, 0x01212C, 0x01212D, 0x01212E, 0x01212F, + 0x012128, 0x012129, 0x01212A, 0x01212B, 0x012124, 0x012125, 0x012126, 0x012127, + 0x012120, 0x012121, 0x012122, 0x012123, 0x01213C, 0x01213D, 0x01213E, 0x01213F, + 0x012138, 0x012139, 0x01213A, 0x01213B, 0x012134, 0x012135, 0x012137, 0x012130, + 0x012131, 0x01210A, 0x012100, 0x012101, 0x01211A, 0x012114, 0x012115, 0x012116, + 0x0121D7, 0x0121D0, 0x0121D1, 0x0121D2, 0x0121D3, 0x0121AC, 0x0121AD, 0x0121AE, + 0x0121AF, 0x0121A8, 0x0121A9, 0x0121AA, 0x0121AB, 0x0121A4, 0x0121A5, 0x0121A6, + 0x0121A7, 0x0121A0, 0x0121A1, 0x0121A2, 0x0121A3, 0x0121BC, 0x0121BD, 0x0121BE, + 0x0121BF, 0x0121B8, 0x0121B9, 0x0121BA, 0x0121BB, 0x0121B4, 0x0121B5, 0x0121B6, + 0x0121B7, 0x0121B0, 0x0121B1, 0x0121B2, 0x0121B3, 0x01218C, 0x01218D, 0x01218E, + 0x01218F, 0x012188, 0x012189, 0x01218A, 0x01218B, 0x012184, 0x012185, 0x012186, + 0x012187, 0x012180, 0x00D7C1, 0x00D7C0, 0x00D7C3, 0x00D7C2, 0x00D7C5, 0x00D7C4, + 0x012181, 0x00D7C6, 0x012182, 0x012183, 0x00D7CB, 0x00D7E8, 0x00D7CD, 0x00D7CC, + 0x00D7CF, 0x00D7CE, 0x01219C, 0x01219D, 0x01219E, 0x01219F, 0x00D7D5, 0x00D7D4, + 0x00D7EF, 0x00D7D6, 0x00D7D9, 0x00D7D8, 0x00D7DB, 0x00D7DA, 0x00D7DD, 0x00D7DC, + 0x00D7DF, 0x00D7DE, 0x00D7E1, 0x00D7E0, 0x00D7E3, 0x00D7E2, 0x00D7E5, 0x00D7E4, + 0x00D7E9, 0x00D7E6, 0x00D7F8, 0x00D7ED, 0x00D7EB, 0x00D7EA, 0x00D7B2, 0x00D7EE, + 0x00D7EC, 0x00D7B3, 0x00D7F1, 0x00D7F0, 0x00D7F3, 0x00D7F2, 0x00D7F5, 0x00D7F4, + 0x00D7F7, 0x00D7F6, 0x00D7F9, 0x00D7FA, 0x00D7FB, 0x012198, 0x012199, 0x01219A, + 0x01219B, 0x00D7E7, 0x00FA00, 0x00FA03, 0x00FA02, 0x02F8A1, 0x02F858, 0x02F8A2, + 0x02F8A3, 0x02F8A0, 0x02F8A5, 0x02F8A6, 0x02F8A7, 0x02F8A8, 0x02F8A9, 0x02F8AA, + 0x02F8AB, 0x02F8A4, 0x02F8AD, 0x02F8AE, 0x02F8AF, 0x00FA01, 0x00FA1C, 0x00FA1D, + 0x00FA1E, 0x00FA06, 0x02F84D, 0x00FA19, 0x00FA1F, 0x02F8B8, 0x02F8AC, 0x02F84E, + 0x02F84C, 0x02F8BC, 0x02F8BD, 0x02F8BE, 0x02F8BF, 0x02F8C0, 0x02F8C1, 0x02F8C2, + 0x02F8C3, 0x02F8C4, 0x02F8C5, 0x02F8C6, 0x02F8C7, 0x02F8C8, 0x02F8C9, 0x02F8CA, + 0x02F8CB, 0x02F8CC, 0x02F8CD, 0x02F8CE, 0x02F8CF, 0x02F8D0, 0x02F8D1, 0x02F8D2, + 0x02F8D3, 0x02F8D4, 0x02F8D5, 0x02F8D6, 0x02F8D7, 0x02F8D8, 0x02F8D9, 0x02F8DA, + 0x02F8DB, 0x02F8DC, 0x02F8DD, 0x02F8DE, 0x02F8DF, 0x02F873, 0x02F973, 0x02F85A, + 0x02F85B, 0x02F872, 0x02F856, 0x00FA0A, 0x02F85F, 0x00FA0B, 0x00FA04, 0x00FA05, + 0x00FA07, 0x02F854, 0x02F855, 0x00FA4B, 0x00FA0C, 0x00FA61, 0x00FA0D, 0x02F8F2, + 0x02F8F3, 0x00FA60, 0x00FA09, 0x02F851, 0x02F852, 0x00FA08, 0x00FA0E, 0x02F857, + 0x02F850, 0x00FA0F, 0x00FA24, 0x00FA3D, 0x00FA71, 0x00FA25, 0x00FA34, 0x00FC22, + 0x00FA3C, 0x00FA26, 0x00FA28, 0x00FA3B, 0x00FA3A, 0x00FA38, 0x00FA75, 0x00FA2B, + 0x00FA3E, 0x00FA7B, 0x00FA32, 0x00FA31, 0x00FA73, 0x00FA33, 0x00FA30, 0x00FA36, + 0x00FA57, 0x00FA62, 0x00FA77, 0x00FA2F, 0x00FA72, 0x00FA3F, 0x00FA39, 0x00FA35, + 0x00FA37, 0x00FA23, 0x012194, 0x012195, 0x012196, 0x012197, 0x012190, 0x012191, + 0x012192, 0x012193, 0x00324C, 0x00324D, 0x00324E, 0x00324F, 0x003248, 0x003249, + 0x00324A, 0x00324B, 0x00FC10, 0x00FC11, 0x00FC12, 0x00325C, 0x00FC14, 0x00FC15, + 0x00FC16, 0x00FC17, 0x00FC1A, 0x00FC19, 0x00325D, 0x00FC1B, 0x00325E, 0x00FC18, + 0x00325F, 0x00FC1F, 0x00FC50, 0x00FC57, 0x00FC52, 0x00FC51, 0x00FC54, 0x02F859, + 0x00FC56, 0x00FC55, 0x00FCF8, 0x00FCF9, 0x00FCFA, 0x003258, 0x00FCFC, 0x003259, + 0x00FCFE, 0x00FCFD, 0x00325A, 0x00325B, 0x003254, 0x003255, 0x00FA49, 0x00FC53, + 0x003256, 0x003257, 0x003251, 0x00FA4A, 0x003252, 0x003253, 0x00FCF5, 0x003228, + 0x003229, 0x003224, 0x00FC01, 0x00FCE9, 0x00FCE8, 0x00FC02, 0x00FCE4, 0x00FC05, + 0x00FC03, 0x00FA47, 0x012506, 0x012507, 0x00FC0B, 0x00FCE3, 0x012505, 0x00FC09, + 0x00FC07, 0x00FCEF, 0x00FA46, 0x00FCC8, 0x00FCC9, 0x00FCCA, 0x00FCC4, 0x00FCF1, + 0x00FCF2, 0x00FCF7, 0x00FA45, 0x00FCF0, 0x00FCF6, 0x00FCF4, 0x003225, 0x003226, + 0x00FCFF, 0x003227, 0x003220, 0x00FCE5, 0x003221, 0x01251C, 0x00FCEB, 0x003222, + 0x00FCE7, 0x003223, 0x00FCCF, 0x011C6C, 0x00FA44, 0x00FC3A, 0x00FC1C, 0x00FCE6, + 0x00FC1E, 0x011C68, 0x00FC00, 0x00FC08, 0x00FC0A, 0x011C69, 0x00FC04, 0x00FC0F, + 0x00FC06, 0x011C6A, 0x00FC33, 0x011C6B, 0x011C64, 0x011C65, 0x00FC1D, 0x00FCCC, + 0x00FCCD, 0x00FCCE, 0x011C66, 0x011C67, 0x011C60, 0x011C61, 0x011C62, 0x011C63, + 0x011C7C, 0x011C7D, 0x011C7E, 0x011C7F, 0x011C78, 0x011C79, 0x011C7A, 0x011C7B, + 0x011C74, 0x011C75, 0x011C76, 0x011C77, 0x011C72, 0x0032BD, 0x0032BE, 0x0032BF, + 0x0032B8, 0x0032B9, 0x0032BA, 0x0032BB, 0x0032B4, 0x0032B5, 0x0032B6, 0x0032B7, + 0x0032B2, 0x0032B3, 0x011C5C, 0x011C5D, 0x011C5E, 0x00FF23, 0x011C59, 0x011C5A, + 0x011C2D, 0x011C2E, 0x00FC3C, 0x016A64, 0x011C27, 0x011C20, 0x011C21, 0x00FC3D, + 0x00FC3E, 0x011C22, 0x011C23, 0x016A4C, 0x00FC38, 0x00FC27, 0x00FF36, 0x00FC21, + 0x00FF37, 0x00FC23, 0x016A4D, 0x016A4E, 0x016A4F, 0x016A48, 0x00FC39, 0x016A46, + 0x011C02, 0x016A29, 0x016A2A, 0x016A2B, 0x016A24, 0x016A25, 0x016A26, 0x016A27, + 0x016A20, 0x016A21, 0x00FA48, 0x016A22, 0x016A23, 0x016A38, 0x00FA4C, 0x00FA4D, + 0x00FA4E, 0x00FA4F, 0x016A34, 0x016A35, 0x016A36, 0x016A37, 0x016A30, 0x016A31, + 0x016A32, 0x016A33, 0x016A0C, 0x016A0D, 0x016A0E, 0x016A0F, 0x016A08, 0x016A09, + 0x016A0A, 0x016A0B, 0x016A04, 0x016A05, 0x016A06, 0x00FA63, 0x00FA64, 0x00FA65, + 0x00FA66, 0x00FA67, 0x00FA68, 0x00FA69, 0x00FA6A, 0x00FA6B, 0x00FA6C, 0x00FA6D, + 0x016A07, 0x016A00, 0x00FA70, 0x016A01, 0x016A02, 0x016A03, 0x00FA74, 0x016A1C, + 0x00FA76, 0x016A1D, 0x00FA78, 0x00FA79, 0x00FA7A, 0x016A1E, 0x00FA7C, 0x00FA7D, + 0x00FA7E, 0x00FA7F, 0x016A1F, 0x016A18, 0x016A19, 0x016A1A, 0x016A1B, 0x016A14, + 0x016A15, 0x016A16, 0x016A17, 0x016A10, 0x016A11, 0x016A12, 0x016A13, 0x016AEC, + 0x016AED, 0x016AE8, 0x016AE9, 0x016AEA, 0x016AEB, 0x016AE4, 0x016AE5, 0x016AE6, + 0x016AE7, 0x016AE0, 0x016AE1, 0x016AE2, 0x016AE3, 0x011C8C, 0x011C8D, 0x011C8E, + 0x011C8F, 0x011C88, 0x011C89, 0x011C8A, 0x011C8B, 0x011C84, 0x011C85, 0x011C86, + 0x016AD9, 0x016ADA, 0x016ADB, 0x016AD4, 0x016AD5, 0x016AD6, 0x016AD7, 0x016AD0, + 0x016AD1, 0x016AD2, 0x00FC20, 0x00FC25, 0x00FC24, 0x016AD3, 0x00FC26, 0x011D46, + 0x011D58, 0x011D59, 0x011D54, 0x011D55, 0x011D56, 0x011D25, 0x011D27, 0x00306D, + 0x00306E, 0x00306F, 0x003060, 0x00FC2A, 0x003062, 0x003063, 0x00FC29, 0x00307C, + 0x00307B, 0x003050, 0x003051, 0x003052, 0x003053, 0x00FC2B, 0x003028, 0x003029, + 0x003024, 0x003025, 0x003026, 0x003027, 0x016B0C, 0x016B09, 0x016B0A, 0x016B0B, + 0x016B07, 0x016B00, 0x016B01, 0x016B02, 0x016B03, 0x016B1C, 0x016B1D, 0x016B1E, + 0x016B1F, 0x016B18, 0x016B19, 0x016B1A, 0x016B1B, 0x016B14, 0x016B15, 0x016B16, + 0x016B17, 0x016B10, 0x016B11, 0x0030EC, 0x0030ED, 0x0030EE, 0x0030EF, 0x0030E8, + 0x0030E9, 0x0030EA, 0x0030EB, 0x0030E4, 0x0030E5, 0x0030E6, 0x0030E7, 0x0030E0, + 0x0030E1, 0x0030E2, 0x0030E3, 0x0030FF, 0x0030F8, 0x0030F9, 0x0030FA, 0x0030F4, + 0x0030F5, 0x0030F6, 0x0030F7, 0x0030F0, 0x0030F1, 0x0030F2, 0x0030F3, 0x0030CC, + 0x0030CD, 0x0030CE, 0x0030CF, 0x0030C8, 0x0030C9, 0x0030CA, 0x0030CB, 0x0030C4, + 0x0030C5, 0x0030C6, 0x0030C7, 0x0030C0, 0x0030C1, 0x0030C2, 0x0030C3, 0x0030DC, + 0x00FAB1, 0x0030B0, 0x0030B1, 0x0030B2, 0x0030B3, 0x00308C, 0x00FAB0, 0x003089, + 0x00308A, 0x00308B, 0x003084, 0x003085, 0x003086, 0x003087, 0x016868, 0x01683B, + 0x0168F8, 0x0168F9, 0x00FC28, 0x0168FA, 0x0168FB, 0x0168F4, 0x00FC2C, 0x00FC2D, + 0x00FC2E, 0x00FC2F, 0x0168F5, 0x0168F6, 0x0168F7, 0x0168F0, 0x0168F1, 0x0168F2, + 0x0168F3, 0x0168CC, 0x0168CD, 0x0168CE, 0x0168CF, 0x0168D9, 0x0168DA, 0x0168DB, + 0x0168D4, 0x0168D5, 0x0168D6, 0x0168D7, 0x0168D0, 0x0168D1, 0x0168D2, 0x0168D3, + 0x0168AC, 0x0168AD, 0x0168AE, 0x0168AF, 0x0168A8, 0x0168A9, 0x0168AA, 0x0168AB, + 0x0168A4, 0x0168A5, 0x0168A6, 0x00FAB4, 0x00FABA, 0x0168A7, 0x0168A0, 0x0168A1, + 0x0168A2, 0x0168A3, 0x0168BC, 0x00FC59, 0x00FC5A, 0x00FC5B, 0x0168BD, 0x00FABB, + 0x0168BE, 0x00FC5F, 0x0168BF, 0x016888, 0x016889, 0x01688A, 0x01688B, 0x016887, + 0x01689B, 0x016968, 0x016969, 0x01696A, 0x01696B, 0x016964, 0x016965, 0x016966, + 0x016967, 0x016962, 0x016963, 0x01697C, 0x01697D, 0x016978, 0x016979, 0x01697A, + 0x01697B, 0x016974, 0x00FAB5, 0x016975, 0x016976, 0x016977, 0x016970, 0x016971, + 0x00FAB6, 0x016972, 0x016973, 0x01694C, 0x01694D, 0x01694E, 0x01694F, 0x016948, + 0x016949, 0x01694A, 0x01694B, 0x016944, 0x016945, 0x016946, 0x016947, 0x016940, + 0x016941, 0x00FAB2, 0x016942, 0x016943, 0x01695C, 0x01695D, 0x01695E, 0x01695F, + 0x016958, 0x016959, 0x01695A, 0x01695B, 0x016954, 0x016955, 0x016956, 0x016957, + 0x016950, 0x016951, 0x016952, 0x016953, 0x01692C, 0x01692D, 0x01692E, 0x01692F, + 0x016928, 0x016929, 0x01692A, 0x01692B, 0x016924, 0x016925, 0x00FA8C, 0x016926, + 0x016927, 0x016920, 0x016921, 0x016922, 0x016923, 0x01693C, 0x01693D, 0x01693E, + 0x01693F, 0x016938, 0x016939, 0x01693A, 0x01693B, 0x016934, 0x016935, 0x016936, + 0x016937, 0x016930, 0x016931, 0x016932, 0x016933, 0x01690C, 0x01690D, 0x01690E, + 0x01690F, 0x016908, 0x016909, 0x01690A, 0x01690B, 0x016904, 0x016905, 0x016906, + 0x016907, 0x016900, 0x016901, 0x016902, 0x016903, 0x01691C, 0x01691D, 0x01691E, + 0x01691F, 0x016918, 0x016919, 0x01691A, 0x01691B, 0x016914, 0x016915, 0x016916, + 0x016917, 0x016910, 0x016911, 0x016912, 0x016913, 0x0169EC, 0x0169ED, 0x0169EE, + 0x0169EF, 0x0169E8, 0x0169E9, 0x0169EA, 0x0169EB, 0x0169E4, 0x0169E5, 0x0169E6, + 0x0169E7, 0x0169E0, 0x0169E1, 0x0169E2, 0x0169E3, 0x0169FC, 0x0169FD, 0x0169FE, + 0x0169FF, 0x0169F8, 0x0169F9, 0x0169FA, 0x0169FB, 0x0169F4, 0x0169F5, 0x0169F6, + 0x0169F7, 0x0169F0, 0x00FAC0, 0x00FAC1, 0x00FAC6, 0x0169F1, 0x00FFD4, 0x00FFD5, + 0x0169F2, 0x0169F3, 0x0169CC, 0x0169CD, 0x00FAC4, 0x00FFDA, 0x0169CE, 0x0169CF, + 0x0169C8, 0x00FAC5, 0x00FAC8, 0x0169C9, 0x00FACA, 0x0169CA, 0x0169CB, 0x00FFAC, + 0x00FFAD, 0x00FFAE, 0x0169C4, 0x0169C5, 0x0169C6, 0x0169C7, 0x00FAAC, 0x00FACB, + 0x00FAD8, 0x0169C0, 0x0169C1, 0x0169C2, 0x0169C3, 0x00FAA9, 0x0169DC, 0x0169DD, + 0x0169DE, 0x00FAA4, 0x00FFA7, 0x00FAC9, 0x0169DF, 0x00FAAA, 0x00FACC, 0x00FACD, + 0x00FACE, 0x00FACF, 0x0169D8, 0x00FFAB, 0x00FFA2, 0x00FFA1, 0x00FAAE, 0x00FFA0, + 0x00FFA6, 0x00FAAD, 0x00FFA9, 0x00FFA8, 0x00FAA8, 0x00FFAA, 0x00FFA4, 0x00FAAF, + 0x00FFAF, 0x00FFA5, 0x0169D9, 0x0169DA, 0x0169DB, 0x0169D4, 0x0169D5, 0x0169D6, + 0x0169D7, 0x0169D0, 0x0169D1, 0x0169D2, 0x00FFD3, 0x0169D3, 0x0169AC, 0x0169AD, + 0x0169AE, 0x0169AF, 0x0169A8, 0x0169A9, 0x0169AA, 0x0169AB, 0x0169A4, 0x00FAC2, + 0x0169A5, 0x0169A6, 0x0169A7, 0x0169A0, 0x0169A1, 0x0169A2, 0x0169A3, 0x0169BC, + 0x0169BD, 0x0169BE, 0x0169BF, 0x0169B8, 0x0169B9, 0x0169BA, 0x0169BB, 0x0169B4, + 0x0169B5, 0x0169B6, 0x0169B7, 0x0169B0, 0x0169B1, 0x0169B2, 0x0169B3, 0x01698C, + 0x01698D, 0x01698E, 0x00FAD0, 0x01698F, 0x00FFD2, 0x00FFD6, 0x016988, 0x00FAD5, + 0x00FAD6, 0x00FFD7, 0x016989, 0x00FAD9, 0x01698A, 0x01698B, 0x016984, 0x00FAD4, + 0x00FFDB, 0x016985, 0x00FA10, 0x016986, 0x00FA12, 0x00FF84, 0x00FA14, 0x00FA15, + 0x00FA16, 0x00FA17, 0x00FA18, 0x00FF88, 0x00FA1A, 0x00FF8B, 0x00FF8D, 0x00FA1B, + 0x00FF8F, 0x00FF8E, 0x016987, 0x00FA11, 0x016980, 0x00FA13, 0x016981, 0x016982, + 0x016983, 0x01699C, 0x01699D, 0x01699E, 0x01699F, 0x016998, 0x016999, 0x01699A, + 0x01699B, 0x016994, 0x016995, 0x016996, 0x016997, 0x00FFA3, 0x016990, 0x016991, + 0x016992, 0x016993, 0x0118EC, 0x00FFBD, 0x0118ED, 0x0118EE, 0x00FFBE, 0x00FFBC, + 0x0118EF, 0x00FAA3, 0x00FFB0, 0x00FFB5, 0x00FFB6, 0x0118E8, 0x00FABC, 0x00FABD, + 0x00FABE, 0x00FFB7, 0x00FABF, 0x00FFB9, 0x00FFBA, 0x00FFBB, 0x00FAB8, 0x00FAB9, + 0x00FFB4, 0x00FFB8, 0x0118E9, 0x0118EA, 0x0118EB, 0x0118E4, 0x0118E5, 0x0118E6, + 0x0118E7, 0x0118E0, 0x0118E1, 0x0118E2, 0x0118E3, 0x0118FF, 0x0118F0, 0x0118F1, + 0x0118F2, 0x0118CC, 0x0118CD, 0x0118CE, 0x0118CF, 0x0118C8, 0x0118C9, 0x0118CA, + 0x0118CB, 0x0118C4, 0x0118C5, 0x0118C6, 0x0118C7, 0x0118C0, 0x0118C1, 0x0118C2, + 0x0118C3, 0x0118DC, 0x0118DD, 0x0118DE, 0x0118DF, 0x0118D8, 0x0118D9, 0x0118DA, + 0x0118DB, 0x0118D4, 0x0118D5, 0x0118D6, 0x0118D7, 0x0118D0, 0x0118D1, 0x0118D2, + 0x0118D3, 0x0118AC, 0x0118AD, 0x0118AE, 0x0118AF, 0x0118A8, 0x0118A9, 0x0118AA, + 0x0118AB, 0x0118A4, 0x0118A5, 0x0118A6, 0x0118A7, 0x0118A0, 0x0118A1, 0x0118A2, + 0x0118A3, 0x0118BC, 0x0118BD, 0x0118BE, 0x0118BF, 0x0118B8, 0x0118B9, 0x0118BA, + 0x0118BB, 0x0118B4, 0x0118B5, 0x0118B6, 0x0118B7, 0x0118B0, 0x0118B1, 0x0118B2, + 0x0118B3, 0x002C6C, 0x002C6D, 0x002C6E, 0x002C6F, 0x002C68, 0x002C69, 0x002C6A, + 0x002C6B, 0x002C64, 0x002C65, 0x002C66, 0x002C67, 0x002C60, 0x002C61, 0x002C62, + 0x002C63, 0x002C7E, 0x002C7F, 0x002C78, 0x002C79, 0x002C7A, 0x002C7B, 0x002C74, + 0x002C75, 0x002C76, 0x002C77, 0x002C70, 0x002C71, 0x002C72, 0x002C73, 0x002C4C, + 0x002C4D, 0x002C4E, 0x002C4F, 0x002C48, 0x002C49, 0x002C4A, 0x002C4B, 0x002C44, + 0x002C45, 0x002C46, 0x002C47, 0x002C40, 0x002C41, 0x002C42, 0x002C43, 0x002C5C, + 0x002C5D, 0x002C5E, 0x00FCD8, 0x00FCDD, 0x00FCDC, 0x002C58, 0x00FCD4, 0x00FCDE, + 0x00FCD6, 0x00FCDF, 0x002C59, 0x00FCD9, 0x00FCDA, 0x002C5A, 0x002C5B, 0x002C54, + 0x002C55, 0x002C56, 0x002C57, 0x002C50, 0x002C51, 0x002C52, 0x002C53, 0x002C2C, + 0x002C2D, 0x002C2E, 0x002C28, 0x002C29, 0x002C2A, 0x002C2B, 0x002C24, 0x002C25, + 0x002C26, 0x002C27, 0x002C20, 0x002C21, 0x002C22, 0x002C23, 0x002C3C, 0x00FCC5, + 0x002C3D, 0x002C3E, 0x002C3F, 0x002C38, 0x002C39, 0x002C3A, 0x002C3B, 0x002C34, + 0x002C35, 0x002C36, 0x002C37, 0x002C30, 0x002C31, 0x002C32, 0x002C33, 0x002C0C, + 0x002C0D, 0x002C0E, 0x002C0F, 0x002C08, 0x002C09, 0x002C0A, 0x002C0B, 0x002C04, + 0x002C05, 0x002C06, 0x00FC80, 0x00FC81, 0x00FC82, 0x00FCD2, 0x00FC84, 0x00FCD5, + 0x00FCD0, 0x00FC87, 0x00FC88, 0x00FC89, 0x00FC8A, 0x00FC8B, 0x00FC8C, 0x002C07, + 0x00FCDB, 0x00FC8F, 0x00FCC1, 0x00FC90, 0x00FC91, 0x00FC92, 0x00FCC2, 0x00FC94, + 0x002C00, 0x00FC96, 0x00FCD1, 0x00FCC0, 0x00FCD3, 0x00FCC7, 0x00FC93, 0x00FC97, + 0x00FCC6, 0x00FC95, 0x00FCA4, 0x00FCA1, 0x00FCA2, 0x00FC83, 0x00FCB9, 0x00FCD7, + 0x00FCC3, 0x00FCA7, 0x002C01, 0x00FCBB, 0x002C02, 0x00FCFB, 0x00FCCB, 0x00FCF3, + 0x00FCBA, 0x002C03, 0x00FCB0, 0x00FCB1, 0x00FCB2, 0x00FCB3, 0x00FCB4, 0x00FCB5, + 0x00FCB6, 0x00FCB7, 0x00FC98, 0x00FC99, 0x00FC9A, 0x00FC9B, 0x00FC9C, 0x00FC9D, + 0x00FC9E, 0x00FC9F, 0x002C1C, 0x002C1D, 0x002C1E, 0x002C1F, 0x002C18, 0x002C19, + 0x002C1A, 0x002C1B, 0x00FCBC, 0x002C14, 0x002C15, 0x002C16, 0x002C17, 0x00FCBD, + 0x00FCBE, 0x00FCBF, 0x002C10, 0x002C11, 0x002C12, 0x00FCA3, 0x002C13, 0x002CEC, + 0x002CED, 0x002CEE, 0x002CEB, 0x00FCE1, 0x00FCE2, 0x002CE4, 0x00FCE0, 0x00FCB8, + 0x002CE0, 0x002CE1, 0x002CE2, 0x002CE3, 0x002CFD, 0x002CF2, 0x002CF3, 0x002CCC, + 0x002CCD, 0x00FCAF, 0x00FCA8, 0x00FCA9, 0x00FCAA, 0x00FCAB, 0x00FCAC, 0x00FCAD, + 0x00FCAE, 0x002CCE, 0x002CCF, 0x002CC8, 0x002CC9, 0x002CCA, 0x002CCB, 0x002CC4, + 0x002CC5, 0x002CC6, 0x002CC7, 0x002CC0, 0x002CC1, 0x002CC2, 0x002CC3, 0x002CDC, + 0x002CDD, 0x002CDE, 0x002CDF, 0x002CD8, 0x002CD9, 0x002CDA, 0x002CDB, 0x002CD4, + 0x002CD5, 0x002CD6, 0x002CD7, 0x002CD0, 0x002CD1, 0x002CD2, 0x002CD3, 0x002CAC, + 0x002CAD, 0x002CAE, 0x002CAF, 0x002CA8, 0x002CA9, 0x002CAA, 0x002CAB, 0x002CA4, + 0x002CA5, 0x002CA6, 0x002CA7, 0x002CA0, 0x002CA1, 0x002CA2, 0x002CA3, 0x002CBC, + 0x002CBD, 0x002CBE, 0x002CBF, 0x002CB8, 0x002CB9, 0x002CBA, 0x002CBB, 0x002CB4, + 0x002CB6, 0x002CB7, 0x002CB0, 0x002CB1, 0x002CB2, 0x002CB3, 0x002C8C, 0x002C8D, + 0x002C8E, 0x002C8F, 0x002C88, 0x002C8B, 0x002C84, 0x011623, 0x002D64, 0x002D65, + 0x002D66, 0x002D67, 0x002D60, 0x002D61, 0x002D62, 0x002D63, 0x01160C, 0x01160D, + 0x01160E, 0x01160F, 0x011608, 0x011609, 0x01160A, 0x01160B, 0x011604, 0x011605, + 0x011606, 0x011607, 0x011600, 0x011601, 0x011602, 0x002D5D, 0x00FD7C, 0x00FD6D, + 0x002D5E, 0x002D5F, 0x00FD50, 0x00FD51, 0x00FD52, 0x002D58, 0x00FD54, 0x00FD55, + 0x00FD56, 0x00FD57, 0x00FD58, 0x00FD59, 0x00FD5A, 0x00FD5B, 0x00FD5C, 0x00FD5D, + 0x00FD5E, 0x00FD5F, 0x00FD78, 0x00FD7D, 0x00FD7E, 0x00FD62, 0x00FD74, 0x00FD75, + 0x00FD76, 0x00FD7F, 0x00FD67, 0x00FD79, 0x00FD7A, 0x00FD61, 0x002D59, 0x00FD60, + 0x00FD6B, 0x002D5A, 0x00FD65, 0x00FD71, 0x00FD72, 0x00FD73, 0x00FD64, 0x00FD70, + 0x00FD66, 0x00FD77, 0x00FD68, 0x00FD7B, 0x00FD6A, 0x00FD63, 0x00FD6C, 0x00FD69, + 0x00FD6E, 0x00FD6F, 0x002D5B, 0x002D54, 0x002D55, 0x002D56, 0x002D57, 0x002D50, + 0x002D51, 0x002D52, 0x002D53, 0x002D2D, 0x002D24, 0x002D25, 0x002D27, 0x002D20, + 0x002D21, 0x002D22, 0x002D23, 0x002D3C, 0x002D3D, 0x002D3E, 0x002D3F, 0x002D38, + 0x002D3B, 0x002D34, 0x002D0D, 0x002D0E, 0x002D0F, 0x002D08, 0x002D09, 0x002D0A, + 0x002D0B, 0x002D04, 0x002D05, 0x002D06, 0x002D07, 0x002D00, 0x002D01, 0x002D02, + 0x002D03, 0x002D1C, 0x002D1D, 0x002D1E, 0x002D1F, 0x002D18, 0x002D14, 0x0116A3, + 0x01168C, 0x01168D, 0x01168E, 0x01168F, 0x011688, 0x011689, 0x01168A, 0x01168B, + 0x011684, 0x011685, 0x011686, 0x011687, 0x011680, 0x011681, 0x011682, 0x01169E, + 0x011696, 0x002DDD, 0x002DDE, 0x002DD8, 0x002DD9, 0x002DDA, 0x002DDB, 0x002DD4, + 0x002DD5, 0x002DD6, 0x002DD0, 0x002DD1, 0x002DD2, 0x002DD3, 0x002DAC, 0x002DAD, + 0x002DAE, 0x002DA8, 0x002DA9, 0x002DAA, 0x002DAB, 0x002DA4, 0x002DA5, 0x002DA6, + 0x002DA0, 0x002DA1, 0x002DA2, 0x002DA3, 0x01E807, 0x002DBC, 0x002DBD, 0x002DBE, + 0x002DB8, 0x002DB9, 0x002DBA, 0x002DBB, 0x002DB4, 0x002DB5, 0x002DB6, 0x002DB0, + 0x01E817, 0x002DB1, 0x002DB2, 0x002DB3, 0x002D8C, 0x002D8D, 0x002D8E, 0x002D8F, + 0x002D88, 0x002D89, 0x002D8A, 0x002D8B, 0x01E83B, 0x002D84, 0x002D85, 0x002D86, + 0x002D87, 0x01E830, 0x01E831, 0x002D80, 0x002D81, 0x01E834, 0x002D82, 0x002D83, + 0x01E837, 0x002D94, 0x01E832, 0x002D95, 0x002D96, 0x002D90, 0x00FD04, 0x00FD05, + 0x00FD06, 0x00FD07, 0x00FD08, 0x00FD09, 0x00FD0A, 0x00FD0F, 0x00FD0C, 0x00FD0D, + 0x00FD0E, 0x00FD1F, 0x00FD10, 0x00FD11, 0x00FD12, 0x00FD13, 0x002D91, 0x00FD16, + 0x00FD1B, 0x00FD17, 0x002D92, 0x00FD18, 0x002D93, 0x011738, 0x00FD15, 0x00FD14, + 0x011739, 0x01173A, 0x01173B, 0x011734, 0x011735, 0x011736, 0x011737, 0x011730, + 0x011731, 0x011732, 0x011733, 0x01170C, 0x01170D, 0x01170E, 0x01170F, 0x011708, + 0x011709, 0x01170A, 0x00FD30, 0x01170B, 0x011704, 0x011705, 0x00FD35, 0x00FD34, + 0x011706, 0x00FD33, 0x011707, 0x011700, 0x011701, 0x011702, 0x011703, 0x00FD3D, + 0x011718, 0x011719, 0x011714, 0x011715, 0x011716, 0x011717, 0x011710, 0x011711, + 0x011712, 0x011713, 0x011448, 0x011449, 0x01144A, 0x011447, 0x011458, 0x011459, + 0x011454, 0x011455, 0x011456, 0x011457, 0x011450, 0x011451, 0x011452, 0x011453, + 0x01142C, 0x01142D, 0x01142E, 0x01142F, 0x011428, 0x011429, 0x01142A, 0x01142B, + 0x011424, 0x011425, 0x011426, 0x011427, 0x011420, 0x011421, 0x011422, 0x011423, + 0x011434, 0x011430, 0x011431, 0x011432, 0x011433, 0x01140C, 0x01140D, 0x01140E, + 0x01140F, 0x011408, 0x011409, 0x01140A, 0x01140B, 0x011404, 0x011405, 0x011406, + 0x011407, 0x011400, 0x011401, 0x011402, 0x011403, 0x01141C, 0x01141D, 0x01141E, + 0x01141F, 0x011418, 0x011419, 0x01B066, 0x01B067, 0x01B060, 0x01B061, 0x01B062, + 0x01B063, 0x01B07C, 0x01B07D, 0x01B07E, 0x01B07F, 0x01B078, 0x01B079, 0x01B07A, + 0x01B07B, 0x01B074, 0x01B075, 0x01B076, 0x01B077, 0x01B070, 0x01B071, 0x01B072, + 0x01B073, 0x01B04C, 0x01B04D, 0x01B04E, 0x01B04F, 0x01B048, 0x01B049, 0x01B04A, + 0x01B04B, 0x01B044, 0x01B045, 0x01B046, 0x01B047, 0x01B040, 0x00FDA4, 0x00FDA5, + 0x00FDAC, 0x01B041, 0x00FDA8, 0x00FDA9, 0x00FDAA, 0x00FDAB, 0x00FDAE, 0x00FDAD, + 0x01B042, 0x00FDAF, 0x01B043, 0x01B05C, 0x01B05D, 0x01B058, 0x01B05A, 0x01B05B, + 0x01B054, 0x01B055, 0x01B056, 0x01B057, 0x01B050, 0x01B051, 0x01B02C, 0x00FEC4, + 0x01B02D, 0x01B036, 0x00FEC7, 0x00FEC2, 0x01B037, 0x00FDC3, 0x00FEC0, 0x00FEC1, + 0x01B030, 0x00FEC5, 0x01B031, 0x01B032, 0x01B033, 0x00FEC6, 0x01B00C, 0x01B00D, + 0x01B00E, 0x00FDF9, 0x00FDF1, 0x00FDFB, 0x00FDF7, 0x01B00F, 0x01B008, 0x00FDF5, + 0x00FDF6, 0x01B009, 0x01B00A, 0x01B00B, 0x01B004, 0x01B005, 0x00FDF4, 0x01B0E6, + 0x00FDF8, 0x01B0E7, 0x00FDF0, 0x01B0E0, 0x00FDF2, 0x01B0E1, 0x01B0E2, 0x01B0E3, + 0x01B0FC, 0x01B0FD, 0x01B0FE, 0x01B0FF, 0x01B0F8, 0x01B0F9, 0x01B0FA, 0x01B0FB, + 0x00FEDC, 0x01B0F4, 0x01B0F5, 0x01B0F6, 0x01B0F7, 0x01B0F0, 0x01B0F1, 0x01B0F2, + 0x01B0F3, 0x00FEC3, 0x01B0CC, 0x01B0CD, 0x01B0CE, 0x01B0CF, 0x01B0C8, 0x01B0C9, + 0x01B0CA, 0x01B0CB, 0x01B0C4, 0x01B0C5, 0x01B0C6, 0x01B0C7, 0x00FDA2, 0x01B0C0, + 0x01B0C1, 0x01B0C2, 0x01B0C3, 0x01B0DC, 0x01B0DD, 0x01B0DE, 0x01B0DF, 0x01B0D8, + 0x01B0D9, 0x00FDA1, 0x01B0DA, 0x01B0DB, 0x01B0D4, 0x01B0D5, 0x00FDA0, 0x01B0D6, + 0x01B0D7, 0x01B0D0, 0x01B0D1, 0x01B0D2, 0x01B0D3, 0x01B0AC, 0x01B0AD, 0x01B0AE, + 0x01B0AF, 0x01B0A8, 0x01B0A9, 0x01B0AA, 0x01B0AB, 0x01B0A4, 0x01B0A5, 0x01B0A6, + 0x01B0A7, 0x01B0A0, 0x01B0A1, 0x01B0A2, 0x01B0A3, 0x01B0BC, 0x01B0BD, 0x01B0BE, + 0x01B0BF, 0x01B0B8, 0x01B0B9, 0x01B0BA, 0x01B0BB, 0x01B0B4, 0x01B0B5, 0x01B0B6, + 0x01B0B7, 0x01B0B0, 0x01B0B1, 0x01B0B2, 0x01B0B3, 0x01B08C, 0x01B08D, 0x01B08E, + 0x01B08F, 0x01B088, 0x01B089, 0x01B08A, 0x01B08B, 0x01B084, 0x01B085, 0x01B086, + 0x01B087, 0x01B080, 0x01B081, 0x01B082, 0x01B083, 0x01B09C, 0x01B09D, 0x01B09E, + 0x01B09F, 0x01B098, 0x01B099, 0x01B09A, 0x01B09B, 0x01B094, 0x01B095, 0x01B096, + 0x01B097, 0x01B090, 0x01B091, 0x01B092, 0x01B093, 0x0115D8, 0x0115D9, 0x0115DA, + 0x0115DB, 0x0115AC, 0x0115AD, 0x0115AE, 0x0115A8, 0x0115A9, 0x0115AA, 0x0115AB, + 0x0115A4, 0x0115A5, 0x0115A6, 0x0115A7, 0x0115A0, 0x0115A1, 0x0115A2, 0x0115A3, + 0x01B10C, 0x01B10D, 0x01B10E, 0x01B10F, 0x01B108, 0x01B109, 0x01B10A, 0x00FDA7, + 0x01B10B, 0x01B104, 0x01B105, 0x011585, 0x01159A, 0x01159B, 0x011594, 0x011595, + 0x00FDA6, 0x011596, 0x00FD81, 0x00FF2D, 0x00FF2E, 0x011597, 0x00FD80, 0x00FD84, + 0x00FD87, 0x00FD86, 0x00FD8B, 0x00FD89, 0x00FD88, 0x00FF2F, 0x00FD85, 0x00FD8E, + 0x00FD8D, 0x00FD8F, 0x00FD93, 0x011590, 0x00FD92, 0x011591, 0x00FD96, 0x00FD94, + 0x011592, 0x011593, 0x011228, 0x011229, 0x01122A, 0x00FDBC, 0x00FD8C, 0x00FD9C, + 0x00FD9B, 0x00FF2C, 0x01122B, 0x011224, 0x00FF2B, 0x011225, 0x011226, 0x011227, + 0x011220, 0x011221, 0x00FF21, 0x011222, 0x00FDBD, 0x00FF22, 0x00FF25, 0x00FF24, + 0x00FF27, 0x00FF26, 0x00FDB7, 0x00FDBB, 0x00FDB2, 0x00FDB0, 0x00FDB6, 0x00FF28, + 0x00FF2A, 0x00FDB5, 0x00FDB8, 0x00FDB9, 0x00FDBA, 0x00FF29, 0x011223, 0x00FDB4, + 0x00FDBE, 0x00FDBF, 0x00FEE8, 0x00FEEC, 0x01120C, 0x01120D, 0x00FECC, 0x00FEED, + 0x00FEEE, 0x01120E, 0x00FECA, 0x00FEC9, 0x00FF53, 0x00FECB, 0x00FEC8, 0x00FECD, + 0x00FECE, 0x00FECF, 0x00FF50, 0x00FF51, 0x00FF52, 0x01120F, 0x011208, 0x011209, + 0x01120A, 0x00FF56, 0x01120B, 0x011204, 0x011205, 0x011206, 0x011207, 0x011200, + 0x011201, 0x011202, 0x00FEF8, 0x00FEE2, 0x00FDA3, 0x00FEE3, 0x00FEE0, 0x00FEE1, + 0x00FEFC, 0x00FEE5, 0x00FEF9, 0x00FEE9, 0x00FEEA, 0x00FEEF, 0x00FEE4, 0x00FEEB, + 0x00FEE6, 0x00FEE7, 0x00FF54, 0x00FF55, 0x00FEF2, 0x00FEF3, 0x00FEF0, 0x00FEF1, + 0x00FEF7, 0x00FF57, 0x00FF58, 0x00FEFA, 0x00FF5A, 0x00FF59, 0x00FEF4, 0x00FEF5, + 0x00FEF6, 0x00FEFB, 0x011203, 0x01121C, 0x01121D, 0x01121E, 0x01121F, 0x011218, + 0x011219, 0x01121A, 0x01121B, 0x011214, 0x011215, 0x011216, 0x011217, 0x011210, + 0x011211, 0x011213, 0x0112F8, 0x0112F9, 0x0112F4, 0x0112F5, 0x0112F6, 0x0112F7, + 0x0112F0, 0x0112F1, 0x0112F2, 0x0112F3, 0x0112CC, 0x0112CD, 0x0112CE, 0x0112CF, + 0x0112C8, 0x0112C9, 0x0112CA, 0x0112CB, 0x0112C4, 0x0112C5, 0x0112C6, 0x0112C7, + 0x0112C0, 0x0112C1, 0x0112C2, 0x0112C3, 0x0112DC, 0x0112DD, 0x0112DE, 0x0112D8, + 0x0112D9, 0x0112DA, 0x0112DB, 0x0112D4, 0x0112D5, 0x0112D6, 0x0112D7, 0x0112D0, + 0x0112D1, 0x0112D2, 0x0112D3, 0x0112A8, 0x0112A4, 0x0112A5, 0x0112A6, 0x0112A7, + 0x0112A0, 0x0112A1, 0x0112A2, 0x0112A3, 0x0112BC, 0x0112BD, 0x0112BE, 0x0112BF, + 0x0112B8, 0x0112B9, 0x0112BA, 0x0112BB, 0x0112B4, 0x0112B5, 0x0112B6, 0x0112B7, + 0x0112B0, 0x0112B1, 0x0112B2, 0x0112B3, 0x01128C, 0x01128D, 0x01128F, 0x011288, + 0x01128A, 0x01128B, 0x011284, 0x011285, 0x011286, 0x011280, 0x011281, 0x011282, + 0x011283, 0x01129C, 0x01129D, 0x01129F, 0x011298, 0x011299, 0x01129A, 0x01129B, + 0x011294, 0x011295, 0x011296, 0x011297, 0x011290, 0x011291, 0x011292, 0x011293, + 0x011360, 0x011361, 0x01135D, 0x01135E, 0x01135F, 0x011350, 0x01132C, 0x01132D, + 0x01132E, 0x01132F, 0x011328, 0x01132A, 0x01132B, 0x011324, 0x011325, 0x011326, + 0x011327, 0x011320, 0x011321, 0x011322, 0x011323, 0x01133D, 0x011338, 0x011339, + 0x011335, 0x011336, 0x011337, 0x011330, 0x011332, 0x011333, 0x01130C, 0x01130F, + 0x011308, 0x011309, 0x01130A, 0x01130B, 0x011305, 0x011306, 0x011307, 0x01131C, + 0x01131D, 0x01131E, 0x01131F, 0x011318, 0x011319, 0x01131A, 0x01131B, 0x011314, + 0x011315, 0x011316, 0x011317, 0x011310, 0x011313, 0x01106C, 0x01106D, 0x01106E, + 0x01106F, 0x011068, 0x011069, 0x01106A, 0x01106B, 0x011064, 0x011065, 0x011066, + 0x011067, 0x011060, 0x011061, 0x011062, 0x011063, 0x01105C, 0x01105D, 0x01105E, + 0x01105F, 0x011058, 0x011059, 0x01105A, 0x01105B, 0x011054, 0x011055, 0x011056, + 0x011057, 0x011052, 0x011053, 0x01102C, 0x01102D, 0x01102E, 0x01102F, 0x011028, + 0x011029, 0x01102A, 0x01102B, 0x011024, 0x011025, 0x011026, 0x011027, 0x011020, + 0x011021, 0x011022, 0x011023, 0x011034, 0x011035, 0x011036, 0x011037, 0x011030, + 0x011031, 0x011032, 0x01100B, 0x011004, 0x011007, 0x011003, 0x01101C, 0x01101D, + 0x01101E, 0x01101F, 0x011018, 0x011019, 0x01101A, 0x01101B, 0x011014, 0x011015, + 0x011016, 0x011017, 0x011010, 0x011011, 0x011012, 0x011013, 0x0110E8, 0x0110E4, + 0x0110E5, 0x0110E6, 0x0110E7, 0x0110E0, 0x0110E1, 0x0110E2, 0x0110E3, 0x0110F8, + 0x0110F9, 0x0110F4, 0x0110F5, 0x0110F6, 0x0110F7, 0x0110F0, 0x0110F1, 0x0110F2, + 0x0110F3, 0x0110DC, 0x0110DD, 0x0110DE, 0x0110DF, 0x0110D8, 0x0110D9, 0x0110DA, + 0x0110DB, 0x0110D4, 0x0110D5, 0x0110D6, 0x0110D7, 0x0110D0, 0x0110D1, 0x0110D2, + 0x0110D3, 0x0110AC, 0x0110AD, 0x0110AE, 0x0110AF, 0x0110A8, 0x0110A9, 0x0110AA, + 0x0110AB, 0x0110A4, 0x0110A5, 0x0110A6, 0x0110A7, 0x0110A0, 0x0110A1, 0x0110A2, + 0x0110A3, 0x01108C, 0x01108D, 0x01108E, 0x01108F, 0x011088, 0x011089, 0x01108A, + 0x01108B, 0x011084, 0x011085, 0x011086, 0x011087, 0x011083, 0x01109C, 0x01109D, + 0x01109E, 0x01109F, 0x011098, 0x011099, 0x01109A, 0x01109B, 0x011094, 0x011095, + 0x011096, 0x011097, 0x011090, 0x011091, 0x011092, 0x011093, 0x01116C, 0x01116D, + 0x01116E, 0x01116F, 0x011168, 0x011169, 0x01116A, 0x01116B, 0x011164, 0x011165, + 0x011166, 0x011167, 0x011160, 0x011161, 0x011162, 0x011163, 0x011176, 0x011170, + 0x011171, 0x011172, 0x00278C, 0x011153, 0x011124, 0x011125, 0x011126, 0x002790, + 0x002465, 0x002466, 0x002461, 0x002462, 0x002463, 0x00247C, 0x002471, 0x002472, + 0x002473, 0x011103, 0x01111C, 0x01111D, 0x01111E, 0x01111F, 0x011118, 0x011119, + 0x01111A, 0x01111B, 0x011114, 0x011115, 0x011116, 0x011117, 0x011110, 0x011111, + 0x011112, 0x011113, 0x0111EC, 0x0111ED, 0x0111EE, 0x0111EF, 0x0111E8, 0x0111E9, + 0x0111EA, 0x0111EB, 0x0111E4, 0x0111E5, 0x0111E6, 0x0111E7, 0x0111E1, 0x0111E2, + 0x0111E3, 0x0111F4, 0x0111F0, 0x0111F1, 0x0111F2, 0x01E8AE, 0x01E8B4, 0x0111F3, + 0x0111C4, 0x0111C1, 0x01E8B9, 0x01E8BE, 0x01E8B8, 0x0111C2, 0x01E8A9, 0x01E8BA, + 0x01E8AA, 0x0111C3, 0x0111DC, 0x0111D8, 0x01E887, 0x01E880, 0x01E881, 0x0111D9, + 0x0111DA, 0x0111D4, 0x0111D5, 0x0111D6, 0x01E884, 0x0111D7, 0x0111D0, 0x01E886, + 0x01E885, 0x0111D1, 0x01E890, 0x0111D2, 0x01E889, 0x01E888, 0x01E88D, 0x0111D3, + 0x0111AC, 0x0111AD, 0x01E898, 0x0111AE, 0x01E88A, 0x0111AF, 0x0111A8, 0x0111A9, + 0x0111AA, 0x0111AB, 0x0111A4, 0x0111A5, 0x01E8C3, 0x0111A6, 0x0111A7, 0x0111A0, + 0x0111A1, 0x0111A2, 0x01E88F, 0x0024ED, 0x0024EE, 0x0024EF, 0x0024EA, 0x0024EB, + 0x0111B0, 0x0111B1, 0x0111B2, 0x0024FC, 0x0024F1, 0x0024F2, 0x0024F3, 0x011183, + 0x01119C, 0x01119D, 0x01119E, 0x01119F, 0x011198, 0x01E88C, 0x01E8CA, 0x01E88E, + 0x011199, 0x01119A, 0x01119B, 0x011194, 0x011195, 0x011196, 0x011197, 0x011190, + 0x011191, 0x011192, 0x011193, 0x010E6C, 0x010E6D, 0x010E6E, 0x010E6F, 0x010E68, + 0x010E69, 0x010E6A, 0x010E6B, 0x010E64, 0x010E65, 0x010E66, 0x010E67, 0x010E60, + 0x010E61, 0x010E62, 0x010E63, 0x010E7C, 0x010E7D, 0x010E7E, 0x010E78, 0x010E79, + 0x010E7A, 0x010E7B, 0x010E74, 0x010E75, 0x010E76, 0x010E77, 0x010E70, 0x010E71, + 0x010E72, 0x010E73, 0x00248C, 0x00248D, 0x00248E, 0x00248F, 0x002488, 0x002489, + 0x00248A, 0x00248B, 0x002484, 0x002485, 0x002486, 0x002487, 0x002480, 0x002481, + 0x002482, 0x002483, 0x002498, 0x002499, 0x00249A, 0x00249B, 0x002494, 0x002495, + 0x002496, 0x002497, 0x002490, 0x002491, 0x002492, 0x002493, 0x010C48, 0x010C44, + 0x010C45, 0x010C46, 0x010C47, 0x010C40, 0x010C41, 0x010C42, 0x010C43, 0x010C2C, + 0x010C2D, 0x010C2E, 0x010C2F, 0x010C28, 0x010C29, 0x010C2A, 0x010C2B, 0x010C24, + 0x010C25, 0x010C26, 0x010C27, 0x010C20, 0x010C21, 0x010C22, 0x010C23, 0x010C3C, + 0x010C3D, 0x010C3E, 0x010C3F, 0x010C38, 0x010C39, 0x010C3A, 0x010C3B, 0x010C34, + 0x010C35, 0x010C36, 0x010C37, 0x010C30, 0x010C31, 0x010C32, 0x010C33, 0x010C0C, + 0x010C0D, 0x010C0E, 0x010C0F, 0x010C08, 0x010C09, 0x010C0A, 0x010C0B, 0x010C04, + 0x010C05, 0x010C06, 0x010C07, 0x010C00, 0x010C01, 0x010C02, 0x010C03, 0x010C1C, + 0x010C1D, 0x010C1E, 0x010C1F, 0x010C18, 0x010C19, 0x010C1A, 0x010C1B, 0x010C14, + 0x010C15, 0x010C16, 0x010C17, 0x010C10, 0x010C11, 0x010C12, 0x010C13, 0x010CEC, + 0x010CED, 0x010CEE, 0x010CEF, 0x010CE8, 0x010CE9, 0x010CEA, 0x010CEB, 0x010CE4, + 0x010CE5, 0x010CE6, 0x010CE7, 0x010CE0, 0x010CE1, 0x010CE2, 0x010CE3, 0x010CFC, + 0x010CFD, 0x010CFE, 0x010CFF, 0x010CFA, 0x010CFB, 0x010CF0, 0x010CF1, 0x010CF2, + 0x010CCC, 0x010CCD, 0x010CCE, 0x010CCF, 0x010CC8, 0x010CC9, 0x010CCA, 0x010CCB, + 0x010CC4, 0x010CC5, 0x010CC6, 0x010CC7, 0x010CC0, 0x010CC1, 0x010CC2, 0x010CC3, + 0x010CDC, 0x010CDD, 0x010CDE, 0x010CDF, 0x010CD8, 0x010CD9, 0x010CDA, 0x010CDB, + 0x010CD4, 0x010CD5, 0x010CD6, 0x010CD7, 0x010CD0, 0x010CD1, 0x010CD2, 0x010CD3, + 0x010CAC, 0x010CAD, 0x010CAE, 0x010CAF, 0x010CA8, 0x010CA9, 0x010CAA, 0x010CAB, + 0x010CA4, 0x010CA5, 0x010CA6, 0x010CA7, 0x010CA0, 0x010CA1, 0x010CA2, 0x010CA3, + 0x010CB0, 0x010CB1, 0x010CB2, 0x010C8C, 0x010C8D, 0x010C8E, 0x010C8F, 0x010C88, + 0x010C89, 0x010C8A, 0x010C8B, 0x010C84, 0x010C85, 0x010C86, 0x010C87, 0x010C80, + 0x010C81, 0x010C82, 0x010C83, 0x010C9C, 0x010C9D, 0x010C9E, 0x010C9F, 0x010C98, + 0x010C99, 0x010C9A, 0x010C9B, 0x010C94, 0x010C95, 0x010C96, 0x010C97, 0x010C90, + 0x010C91, 0x010C92, 0x010C93, 0x002078, 0x002079, 0x002074, 0x002075, 0x002076, + 0x002077, 0x002070, 0x010A6C, 0x010A6D, 0x010A6E, 0x010A6F, 0x010A68, 0x010A69, + 0x010A6A, 0x010A6B, 0x010A64, 0x010A65, 0x010A66, 0x010A67, 0x010A60, 0x010A61, + 0x010A62, 0x010A63, 0x010A7C, 0x010A7D, 0x010A7E, 0x010A78, 0x010A79, 0x010A7A, + 0x010A7B, 0x010A74, 0x010A75, 0x010A76, 0x010A77, 0x010A70, 0x010A71, 0x010A72, + 0x010A73, 0x010A44, 0x010A45, 0x010A46, 0x010A47, 0x010A40, 0x010A41, 0x010A42, + 0x010A43, 0x002088, 0x002089, 0x002084, 0x002085, 0x002086, 0x002087, 0x002080, + 0x002081, 0x002082, 0x002083, 0x010A2C, 0x010A2D, 0x010A2E, 0x010A2F, 0x010A28, + 0x010A29, 0x010A2A, 0x010A2B, 0x010A24, 0x010A25, 0x010A26, 0x010A27, 0x010A20, + 0x010A21, 0x010A22, 0x00216D, 0x00216E, 0x00216F, 0x002168, 0x002169, 0x00216A, + 0x00216B, 0x002164, 0x002165, 0x002166, 0x002167, 0x002160, 0x00217D, 0x00217E, + 0x00217F, 0x002178, 0x002179, 0x00217A, 0x00217B, 0x002174, 0x002175, 0x002176, + 0x002177, 0x002170, 0x002172, 0x002173, 0x010A1C, 0x010A1E, 0x002149, 0x010A19, + 0x010A1A, 0x010A1B, 0x002145, 0x010A17, 0x010A10, 0x010A11, 0x010A12, 0x002159, + 0x00215A, 0x00215B, 0x002156, 0x002157, 0x002150, 0x00212D, 0x00212F, 0x002128, + 0x00212A, 0x00212B, 0x002124, 0x002126, 0x00213C, 0x002139, 0x010AC9, 0x010ACA, + 0x010ADF, 0x010AD8, 0x010ADB, 0x010AD4, 0x010AD5, 0x010AD7, 0x010AD0, 0x010AD2, + 0x00211D, 0x002119, 0x00211A, 0x00211B, 0x002115, 0x002110, 0x002111, 0x002112, + 0x002113, 0x010A8C, 0x010A8D, 0x010A8E, 0x010A8F, 0x010A88, 0x010A89, 0x010A8A, + 0x010A8B, 0x010A84, 0x010A85, 0x010A86, 0x010A87, 0x010A80, 0x010A81, 0x010A82, + 0x010A83, 0x010A9C, 0x010A9D, 0x010A9E, 0x010A9F, 0x010A98, 0x010A99, 0x010A9A, + 0x010A9B, 0x010A94, 0x010A95, 0x010A96, 0x010A97, 0x010A90, 0x010A91, 0x010A92, + 0x010A93, 0x010B6C, 0x010B6D, 0x010B6E, 0x010B6F, 0x010B68, 0x010B69, 0x010B6A, + 0x010B6B, 0x010B64, 0x010B65, 0x010B66, 0x010B67, 0x010B60, 0x010B61, 0x010B62, + 0x010B63, 0x010B7C, 0x010B7D, 0x010B7E, 0x010B7F, 0x010B78, 0x010B79, 0x010B7A, + 0x010B7B, 0x010B70, 0x010B71, 0x010B72, 0x010B4C, 0x010B4D, 0x010B4E, 0x010B4F, + 0x010B48, 0x010B49, 0x010B4A, 0x010B4B, 0x010B44, 0x010B45, 0x010B46, 0x010B47, + 0x010B40, 0x010B41, 0x010B42, 0x010B43, 0x010B5C, 0x010B5D, 0x010B5E, 0x010B59, + 0x010B5A, 0x002187, 0x002180, 0x010B53, 0x010B2C, 0x010B2D, 0x010B2E, 0x010B2F, + 0x010B28, 0x010B29, 0x010B2A, 0x010B2B, 0x010B24, 0x010B25, 0x010B26, 0x010B27, + 0x010B20, 0x010B21, 0x010B22, 0x001E6D, 0x001E6E, 0x001E6F, 0x001E68, 0x001E69, + 0x001E6A, 0x001E6B, 0x001E64, 0x001E67, 0x001E60, 0x001E5D, 0x001E5E, 0x001E5F, + 0x001E58, 0x001E59, 0x001E5A, 0x001E5B, 0x001E54, 0x001E55, 0x001E56, 0x001E57, + 0x001E50, 0x001E51, 0x001E52, 0x001E53, 0x001E2C, 0x001E2D, 0x001E2E, 0x001E2F, + 0x001E28, 0x001E29, 0x001E2A, 0x001E2B, 0x001E24, 0x001E25, 0x001E26, 0x001E27, + 0x001E20, 0x001E21, 0x001E22, 0x001E23, 0x001E3C, 0x001E3D, 0x001E3E, 0x001E3F, + 0x001E38, 0x001E39, 0x001E3A, 0x001E3B, 0x001E34, 0x001E35, 0x001E36, 0x001E37, + 0x001E30, 0x001E31, 0x001E32, 0x001E33, 0x001E0C, 0x001E0D, 0x001E0E, 0x001E0F, + 0x001E08, 0x001E09, 0x001E0A, 0x001E0B, 0x001E04, 0x001E05, 0x001E06, 0x001E07, + 0x001E00, 0x001E01, 0x001E02, 0x001E03, 0x001E1C, 0x001E19, 0x001E15, 0x001E16, + 0x001E17, 0x001E10, 0x001E11, 0x001E12, 0x001E13, 0x001EEC, 0x001EED, 0x001EEE, + 0x001EEF, 0x001EE8, 0x001EE9, 0x001EEA, 0x001EEB, 0x001EE4, 0x001EE5, 0x001EE6, + 0x001EE7, 0x001EE0, 0x001EE1, 0x001EE2, 0x001EE3, 0x01E8CC, 0x01E8CD, 0x01E8CE, + 0x001EFC, 0x001ECD, 0x001ECE, 0x001ECF, 0x001EC8, 0x001EC9, 0x001ECA, 0x001ECB, + 0x001EC4, 0x001EC5, 0x001EC6, 0x001EC7, 0x001EC0, 0x001EC3, 0x001EDC, 0x001EA9, + 0x001EA0, 0x001E87, 0x001E80, 0x001F6E, 0x001F6F, 0x001F6A, 0x001F6B, 0x001F64, + 0x001F67, 0x01080D, 0x01080E, 0x001F7A, 0x001F77, 0x001F70, 0x01081D, 0x01081E, + 0x010815, 0x010816, 0x010813, 0x0108ED, 0x0108EF, 0x0108E9, 0x001F29, 0x001F2A, + 0x001F2B, 0x001F27, 0x001F20, 0x001F3C, 0x001F3D, 0x001F3E, 0x001F3F, 0x001F38, + 0x001F39, 0x001F3A, 0x001F3B, 0x001F34, 0x001F35, 0x001F36, 0x001F37, 0x001F30, + 0x001F31, 0x001F32, 0x001F33, 0x001F0C, 0x001F0D, 0x001F0E, 0x001F0F, 0x001F08, + 0x001F09, 0x001F0A, 0x001F0B, 0x001F04, 0x001F05, 0x001F06, 0x001F07, 0x001F00, + 0x001F01, 0x001F02, 0x001F03, 0x001F1C, 0x0108AD, 0x0108AE, 0x001F15, 0x001F11, + 0x001F12, 0x001F13, 0x001FEC, 0x001FE8, 0x001FE9, 0x001FEA, 0x001FEB, 0x001FE4, + 0x001FE5, 0x001FE6, 0x001FE7, 0x001FE0, 0x001FE1, 0x001FE2, 0x001FE3, 0x001FFC, + 0x01088C, 0x01088D, 0x01088E, 0x010884, 0x00FA88, 0x00FA8E, 0x010887, 0x010880, + 0x01089C, 0x00FA9C, 0x01089D, 0x00FA89, 0x00FA98, 0x00FA8B, 0x00FA8A, 0x00FA9E, + 0x01089E, 0x00FA8D, 0x001FC8, 0x010894, 0x010897, 0x010890, 0x010893, 0x001FD8, + 0x001FD9, 0x001FDA, 0x001FDB, 0x001FD6, 0x001FD7, 0x001FD0, 0x001FD1, 0x001FD2, + 0x001FD3, 0x001FAC, 0x001FAD, 0x001FAE, 0x001FAF, 0x001FA8, 0x001FA9, 0x001FAA, + 0x001FAB, 0x001FA4, 0x001FA5, 0x001FA6, 0x001FA7, 0x001FA0, 0x001FA1, 0x001FA2, + 0x001FA3, 0x001FBC, 0x001FBE, 0x001FB8, 0x001FB9, 0x001FBA, 0x001FBB, 0x001FB4, + 0x001FB6, 0x001FB7, 0x001FB0, 0x001FB1, 0x001FB2, 0x001FB3, 0x001F8C, 0x001F8D, + 0x001F8E, 0x001F8F, 0x001F88, 0x001F89, 0x001F8A, 0x001F8B, 0x001F84, 0x001F85, + 0x001F86, 0x001F87, 0x001F80, 0x001F81, 0x001F82, 0x001F83, 0x001F9C, 0x001C6D, + 0x001C6E, 0x001C6F, 0x001C68, 0x001C6B, 0x001C64, 0x010933, 0x01090C, 0x01090D, + 0x01090E, 0x01090F, 0x010908, 0x010909, 0x01090A, 0x010903, 0x001C4D, 0x001C4E, + 0x001C4F, 0x001C48, 0x010919, 0x01091A, 0x0109E3, 0x0109FC, 0x0109FD, 0x0109FE, + 0x0109FF, 0x0109F8, 0x0109F9, 0x0109FA, 0x0109FB, 0x0109F4, 0x0109F5, 0x0109F6, + 0x0109F3, 0x0109CC, 0x0109CD, 0x0109CE, 0x0109CF, 0x0109C8, 0x0109C9, 0x0109CA, + 0x0109CB, 0x0109C4, 0x0109C5, 0x0109C6, 0x0109C7, 0x0109C0, 0x0109C1, 0x0109C2, + 0x001C01, 0x001C02, 0x0109BC, 0x0109BF, 0x001CE9, 0x001CEA, 0x001CEB, 0x0109B4, + 0x0109B5, 0x0109B6, 0x0109B7, 0x0109B0, 0x0109B1, 0x0109B2, 0x0109B3, 0x01098C, + 0x01098D, 0x01098E, 0x01098F, 0x010988, 0x010989, 0x01098A, 0x01098B, 0x010986, + 0x010981, 0x010982, 0x010983, 0x01099C, 0x01099D, 0x01099E, 0x01099F, 0x010998, + 0x010999, 0x01099A, 0x01099B, 0x010994, 0x010995, 0x010996, 0x010997, 0x010990, + 0x010991, 0x010992, 0x010993, 0x01066C, 0x01066D, 0x01066E, 0x01066F, 0x010668, + 0x010669, 0x01066A, 0x01066B, 0x010664, 0x010665, 0x010666, 0x010667, 0x010660, + 0x010661, 0x010662, 0x010663, 0x01067C, 0x01067D, 0x01067E, 0x01067F, 0x010678, + 0x010679, 0x01067A, 0x01067B, 0x010674, 0x010675, 0x010676, 0x010677, 0x010670, + 0x010671, 0x010672, 0x010673, 0x01064C, 0x01064D, 0x01064E, 0x01064F, 0x010648, + 0x010649, 0x01064A, 0x01064B, 0x010644, 0x010645, 0x010646, 0x010647, 0x010640, + 0x010641, 0x010642, 0x010643, 0x01065C, 0x01065D, 0x01065E, 0x010658, 0x010659, + 0x01065A, 0x010653, 0x01062C, 0x01062D, 0x01062E, 0x01062F, 0x010628, 0x010629, + 0x01062A, 0x01062B, 0x010624, 0x010625, 0x010626, 0x010627, 0x010620, 0x010621, + 0x010622, 0x01063F, 0x010638, 0x010639, 0x01063B, 0x010634, 0x010635, 0x010636, + 0x010637, 0x010630, 0x010631, 0x010632, 0x01060F, 0x010603, 0x01061C, 0x01061D, + 0x01061E, 0x01061F, 0x010618, 0x010619, 0x01061A, 0x01061B, 0x010614, 0x010615, + 0x010616, 0x010617, 0x010610, 0x010611, 0x010612, 0x010613, 0x0106EC, 0x0106ED, + 0x0106EE, 0x0106EF, 0x0106E8, 0x0106E9, 0x0106EA, 0x0106EB, 0x0106E4, 0x0106E5, + 0x0106E6, 0x0106E7, 0x0106E0, 0x0106E1, 0x0106E2, 0x0106E3, 0x0106FC, 0x0106FD, + 0x0106FE, 0x0106F3, 0x0106CC, 0x0106CD, 0x0106CE, 0x0106CF, 0x0106C8, 0x0106C9, + 0x0106CA, 0x0106CB, 0x0106C4, 0x0106C5, 0x0106C6, 0x0106C7, 0x0106C0, 0x0106C1, + 0x0106C2, 0x0106A3, 0x0106BC, 0x0106BD, 0x0106BE, 0x0106BF, 0x0106B8, 0x0106B9, + 0x0106BA, 0x0106BB, 0x0106B4, 0x0106B5, 0x0106B6, 0x0106B7, 0x0106B0, 0x0106B1, + 0x0106B2, 0x0106B3, 0x01068C, 0x01068D, 0x01068E, 0x01068F, 0x010688, 0x010689, + 0x01068A, 0x01068B, 0x010684, 0x010685, 0x010686, 0x010687, 0x010680, 0x010681, + 0x010682, 0x010683, 0x01069C, 0x01069D, 0x01069E, 0x01069F, 0x010698, 0x010699, + 0x01069A, 0x01069B, 0x010694, 0x010695, 0x010696, 0x010697, 0x010690, 0x010691, + 0x010692, 0x010693, 0x010764, 0x010765, 0x010766, 0x010767, 0x010760, 0x010761, + 0x010762, 0x010763, 0x01074C, 0x01074D, 0x01074E, 0x01074F, 0x010748, 0x010749, + 0x01074A, 0x01074B, 0x010744, 0x010745, 0x010746, 0x010747, 0x010740, 0x010741, + 0x010742, 0x001D8D, 0x001D8E, 0x001D8F, 0x001D88, 0x001D89, 0x001D8A, 0x001D8B, + 0x001D84, 0x001D87, 0x001D80, 0x010753, 0x01072C, 0x01072D, 0x01072E, 0x01072A, + 0x010723, 0x010734, 0x010735, 0x010736, 0x010730, 0x010731, 0x010732, 0x010733, + 0x01070C, 0x01070D, 0x01070E, 0x01070F, 0x010708, 0x010709, 0x01070A, 0x01070B, + 0x010704, 0x010705, 0x010706, 0x010707, 0x010700, 0x010701, 0x010702, 0x010713, + 0x001A54, 0x001A50, 0x001A51, 0x001A52, 0x001A53, 0x001A2C, 0x001A2D, 0x001A2E, + 0x001A2F, 0x001A28, 0x001A29, 0x001A2A, 0x001A2B, 0x001A24, 0x001A25, 0x001A26, + 0x001A27, 0x001A20, 0x001A21, 0x001A22, 0x001A23, 0x001A3C, 0x001A3D, 0x001A3E, + 0x001A3F, 0x001A38, 0x001A39, 0x001A3A, 0x001A3B, 0x001A34, 0x001A35, 0x001A36, + 0x001A37, 0x001A30, 0x001A31, 0x001A32, 0x001A33, 0x001A0C, 0x001A0D, 0x001A0E, + 0x001A0F, 0x001A08, 0x001A09, 0x001A0A, 0x001A0B, 0x001A04, 0x001A05, 0x001A06, + 0x001A07, 0x001A00, 0x001A01, 0x001A02, 0x001A03, 0x001A14, 0x001A15, 0x001A16, + 0x001A10, 0x001A11, 0x001A12, 0x001A13, 0x01046C, 0x01046D, 0x01046E, 0x01046F, + 0x010468, 0x010469, 0x01046A, 0x01046B, 0x010464, 0x010465, 0x010466, 0x010467, + 0x010460, 0x010461, 0x010462, 0x010463, 0x01047C, 0x01047E, 0x01047F, 0x010478, + 0x01044D, 0x01044E, 0x01044F, 0x010448, 0x010449, 0x01044A, 0x01044B, 0x010444, + 0x010445, 0x010446, 0x010447, 0x010440, 0x010441, 0x010442, 0x010443, 0x01045C, + 0x01045D, 0x01045E, 0x010459, 0x01045A, 0x010453, 0x01042C, 0x01042D, 0x01042E, + 0x010429, 0x01042A, 0x010423, 0x01043C, 0x01043D, 0x01043E, 0x01043F, 0x010438, + 0x010439, 0x01043A, 0x01043B, 0x010434, 0x010435, 0x010436, 0x010437, 0x010430, + 0x010431, 0x010432, 0x010433, 0x01040C, 0x01040D, 0x01040E, 0x01040F, 0x010408, + 0x010409, 0x01040A, 0x01040B, 0x010404, 0x010405, 0x010406, 0x010407, 0x010400, + 0x010401, 0x010402, 0x010403, 0x01041C, 0x01041D, 0x01041E, 0x01041B, 0x010417, + 0x010410, 0x010411, 0x010412, 0x010413, 0x0104EC, 0x0104ED, 0x0104EE, 0x0104E9, + 0x0104EA, 0x001B2D, 0x001B2E, 0x001B2F, 0x001B28, 0x0104F3, 0x0104CC, 0x0104CD, + 0x0104CE, 0x0104CF, 0x0104C8, 0x0104C9, 0x0104CA, 0x0104CB, 0x0104C4, 0x0104C5, + 0x0104C6, 0x001B05, 0x001B07, 0x0104D1, 0x001B1D, 0x001B1F, 0x0104BC, 0x0104BD, + 0x0104B9, 0x0104B5, 0x0104B6, 0x01048C, 0x01048D, 0x01048F, 0x010489, 0x01048B, + 0x010486, 0x010487, 0x010481, 0x001BDD, 0x001BDE, 0x001BDF, 0x001BD8, 0x001BD9, + 0x001BDA, 0x001BD4, 0x01EE0E, 0x01EE0F, 0x01EE08, 0x01EE09, 0x01EE0A, 0x01EE0B, + 0x01EE05, 0x01EE07, 0x01EE00, 0x01EE01, 0x010557, 0x010550, 0x010551, 0x001B9D, + 0x001B9E, 0x001B9F, 0x001B98, 0x001B99, 0x001B9A, 0x001B9B, 0x001B94, 0x010533, + 0x01050C, 0x01050D, 0x01050E, 0x01050F, 0x010508, 0x010509, 0x01050A, 0x00185E, + 0x00185F, 0x001858, 0x001859, 0x001824, 0x00183E, 0x00183F, 0x001838, 0x001839, + 0x01EE92, 0x01EE93, 0x001818, 0x001819, 0x001814, 0x001815, 0x001816, 0x001817, + 0x001810, 0x001811, 0x001812, 0x001813, 0x0018EC, 0x0018ED, 0x0018EE, 0x0018EF, + 0x0018E8, 0x0018E9, 0x0018EA, 0x0018EB, 0x0018E4, 0x0018E5, 0x0018E6, 0x0018E7, + 0x0018E0, 0x0018E1, 0x0018E2, 0x0018E3, 0x0018F4, 0x0018F5, 0x0018F0, 0x0018F1, + 0x0018F2, 0x0018F3, 0x0018CC, 0x0018CD, 0x0018CE, 0x0018CF, 0x0018C8, 0x0018C9, + 0x0018CA, 0x0018CB, 0x0018C4, 0x0018C5, 0x0018C6, 0x0018C7, 0x0018C0, 0x0018C1, + 0x0018C2, 0x0018C3, 0x0018DC, 0x0018DD, 0x0018DE, 0x0018DF, 0x0018D8, 0x0018D9, + 0x0018DA, 0x0018DB, 0x0018D4, 0x0018D5, 0x0018D6, 0x0018D7, 0x0018D0, 0x0018D1, + 0x0018D2, 0x0018D3, 0x0018A8, 0x0018AA, 0x0018A4, 0x0018A5, 0x0018A6, 0x0018A7, + 0x0018A0, 0x0018A1, 0x0018A2, 0x0018A3, 0x0018BC, 0x0018BD, 0x0018BE, 0x0018BF, + 0x0018B8, 0x01D608, 0x0018B9, 0x0018BA, 0x0018BB, 0x01D60C, 0x01D60D, 0x01D60E, + 0x0018B4, 0x0018B5, 0x0018B6, 0x0018B7, 0x0018B0, 0x0018B1, 0x0018B2, 0x0018B3, + 0x00188C, 0x00188D, 0x00188E, 0x00188F, 0x001888, 0x001889, 0x00188A, 0x00188B, + 0x001884, 0x01D620, 0x01D621, 0x01D622, 0x01D623, 0x01D624, 0x01D625, 0x01D626, + 0x01D627, 0x01D628, 0x01D629, 0x01D62A, 0x01D62B, 0x01D62C, 0x01D62D, 0x01D62E, + 0x01D62F, 0x01D630, 0x01D631, 0x01D632, 0x001887, 0x01D634, 0x01D635, 0x01D636, + 0x01D637, 0x01D638, 0x01D639, 0x01D63A, 0x01D63B, 0x01D63C, 0x01D63D, 0x01D63E, + 0x01D63F, 0x01D640, 0x01D641, 0x01D642, 0x01D643, 0x01D644, 0x01D645, 0x01D646, + 0x01D647, 0x01D648, 0x01D649, 0x01D64A, 0x01D64B, 0x01D64C, 0x01D64D, 0x01D64E, + 0x01D64F, 0x01D650, 0x01D651, 0x01D652, 0x01D653, 0x001880, 0x01D655, 0x01D656, + 0x01D657, 0x01D658, 0x01D659, 0x01D65A, 0x001881, 0x01D65C, 0x01D65D, 0x01D65E, + 0x01D65F, 0x001882, 0x001883, 0x00189C, 0x00189D, 0x00189E, 0x00189F, 0x001898, + 0x001899, 0x00189A, 0x00189B, 0x001894, 0x001895, 0x001896, 0x001897, 0x001890, + 0x001891, 0x001892, 0x001893, 0x01D672, 0x01D673, 0x00196C, 0x00196D, 0x001968, + 0x001969, 0x00196A, 0x00196B, 0x001964, 0x001965, 0x001966, 0x001967, 0x001960, + 0x001961, 0x001962, 0x001963, 0x001974, 0x001970, 0x001971, 0x001972, 0x001973, + 0x00194C, 0x00194D, 0x00194E, 0x00194F, 0x001948, 0x001949, 0x00194A, 0x00194B, + 0x001946, 0x001947, 0x00195C, 0x001951, 0x0102E3, 0x0102F8, 0x0102F9, 0x0102FA, + 0x0102FB, 0x0102F4, 0x0102F5, 0x0102F6, 0x0102F7, 0x0102F0, 0x0102F1, 0x0102F2, + 0x0102F3, 0x0102CC, 0x0102CD, 0x0102CE, 0x0102CF, 0x0102C8, 0x0102C9, 0x0102CA, + 0x0102CB, 0x0102C4, 0x0102C5, 0x0102C6, 0x0102C7, 0x0102C0, 0x0102C1, 0x0102C2, + 0x00190D, 0x00190E, 0x00190F, 0x001908, 0x001909, 0x00190A, 0x00190B, 0x001904, + 0x001905, 0x001906, 0x001907, 0x001900, 0x001902, 0x001903, 0x00191C, 0x0102AE, + 0x0102A3, 0x0102BC, 0x0102BD, 0x0102BE, 0x0102BF, 0x0102B8, 0x0102B9, 0x0102BA, + 0x0102BB, 0x0102B4, 0x0102B5, 0x0102B6, 0x0102B7, 0x0102B0, 0x0102B1, 0x0102B2, + 0x0102B3, 0x01028C, 0x01028D, 0x01028E, 0x01028F, 0x010288, 0x010289, 0x01028A, + 0x01028B, 0x010284, 0x010285, 0x010286, 0x010287, 0x010280, 0x010281, 0x010282, + 0x010283, 0x01029C, 0x0019C8, 0x010299, 0x01029A, 0x010293, 0x01036C, 0x01036D, + 0x01036E, 0x01036A, 0x010363, 0x0019A8, 0x0019A9, 0x0019AA, 0x0019AB, 0x0019A4, + 0x0019A7, 0x0019A0, 0x00FC40, 0x0019BD, 0x0019BE, 0x0019BF, 0x0019B8, 0x00FC45, + 0x0019B4, 0x00199D, 0x001999, 0x00199A, 0x00199B, 0x001994, 0x001995, 0x001996, + 0x00FC4E, 0x001997, 0x001990, 0x01033C, 0x01033D, 0x00165D, 0x00165E, 0x00165F, + 0x001658, 0x001659, 0x00165A, 0x00165B, 0x001654, 0x001655, 0x001656, 0x001657, + 0x001650, 0x001651, 0x001652, 0x001653, 0x00162C, 0x00162D, 0x00162E, 0x00162F, + 0x00FC66, 0x001628, 0x001629, 0x00162A, 0x00162B, 0x001624, 0x001625, 0x001626, + 0x001627, 0x001620, 0x001621, 0x001622, 0x001623, 0x00163C, 0x001635, 0x001636, + 0x001637, 0x001630, 0x00160D, 0x00160E, 0x00160F, 0x001608, 0x001609, 0x00160A, + 0x00160B, 0x001604, 0x001607, 0x001600, 0x001601, 0x0103A3, 0x0103BC, 0x0103BA, + 0x0103B3, 0x01038C, 0x01038D, 0x01038E, 0x010388, 0x010389, 0x01038A, 0x0016CF, + 0x0016C8, 0x0016DD, 0x0016DE, 0x0016DF, 0x0016D8, 0x0016D9, 0x0016DA, 0x0016DB, + 0x0016D4, 0x0016D5, 0x0016D6, 0x0016D7, 0x0016D0, 0x0016D1, 0x0016D2, 0x0016D3, + 0x0016AC, 0x0016AD, 0x0016AE, 0x0016AF, 0x0016A8, 0x0016A9, 0x0016AA, 0x0016AB, + 0x0016A4, 0x0016A5, 0x0016A6, 0x0016A7, 0x0016A0, 0x0016A1, 0x0016A2, 0x0016A3, + 0x0016BC, 0x0016BF, 0x0016B8, 0x00168F, 0x001688, 0x010057, 0x010053, 0x01002C, + 0x01002D, 0x01002E, 0x01002A, 0x001690, 0x01003C, 0x00176F, 0x001764, 0x010033, + 0x01000D, 0x01000E, 0x01000F, 0x010008, 0x010009, 0x01000A, 0x01000B, 0x010004, + 0x010005, 0x010006, 0x010000, 0x010001, 0x010002, 0x010013, 0x0100EC, 0x0100ED, + 0x0100EE, 0x0100EF, 0x0100E8, 0x0100E9, 0x0100EA, 0x0100EB, 0x0100E4, 0x0100E5, + 0x0100E6, 0x0100E1, 0x0100E2, 0x00172D, 0x00172E, 0x00172F, 0x001728, 0x001724, + 0x0100F3, 0x0100CC, 0x0100CD, 0x0100CE, 0x0100CF, 0x0100C8, 0x0100C9, 0x0100CA, + 0x0100CB, 0x0100C4, 0x0100C5, 0x0100C6, 0x0100C1, 0x0100C2, 0x0100DC, 0x0100D3, + 0x0100AC, 0x0100AD, 0x0100AE, 0x0100AF, 0x0100A8, 0x0100A9, 0x0100AA, 0x0100AB, + 0x0100A4, 0x0100A5, 0x0100A6, 0x0100A1, 0x0100A2, 0x0100A3, 0x0100BC, 0x0100BD, + 0x0100BE, 0x0100B9, 0x0100BA, 0x0100B3, 0x01008C, 0x01008D, 0x01008E, 0x010089, + 0x01008A, 0x010083, 0x01009C, 0x01009D, 0x01009E, 0x01009F, 0x010098, 0x010099, + 0x01009A, 0x01009B, 0x010094, 0x010095, 0x010096, 0x010097, 0x010090, 0x010091, + 0x010092, 0x01016C, 0x01016D, 0x01016E, 0x01016F, 0x010168, 0x010169, 0x01016A, + 0x01016B, 0x010164, 0x010165, 0x010166, 0x010167, 0x010160, 0x010161, 0x010162, + 0x0017AD, 0x0017AE, 0x0017AF, 0x0017A8, 0x0017AA, 0x0017AB, 0x0017A4, 0x010173, + 0x01014C, 0x01014D, 0x01014E, 0x01014F, 0x010148, 0x010149, 0x01014A, 0x01014B, + 0x010144, 0x010145, 0x010146, 0x00146D, 0x00146E, 0x00146F, 0x001468, 0x001469, + 0x00146A, 0x00146B, 0x001464, 0x001465, 0x001466, 0x001467, 0x001460, 0x001475, + 0x001476, 0x001477, 0x00F95A, 0x001471, 0x001472, 0x001473, 0x00144C, 0x00145D, + 0x00F959, 0x01D401, 0x01D400, 0x01D403, 0x01D402, 0x01D405, 0x01D404, 0x01D407, + 0x01D406, 0x01D409, 0x01D408, 0x01D40B, 0x01D40A, 0x01D40D, 0x01D40C, 0x01D40F, + 0x01D40E, 0x01D411, 0x01D410, 0x01D413, 0x01D412, 0x01D415, 0x01D414, 0x01D417, + 0x01D416, 0x01D419, 0x01D418, 0x01D41B, 0x01D41A, 0x01D41D, 0x01D41C, 0x01D41F, + 0x01D41E, 0x01D421, 0x01D420, 0x01D423, 0x01D422, 0x01D425, 0x01D424, 0x01D427, + 0x01D426, 0x01D429, 0x01D428, 0x01D42B, 0x01D42A, 0x01D42D, 0x01D42C, 0x01D42F, + 0x01D42E, 0x01D431, 0x01D430, 0x01D433, 0x01D432, 0x01D435, 0x01D434, 0x01D437, + 0x01D436, 0x01D439, 0x01D438, 0x01D43B, 0x01D43A, 0x01D43D, 0x01D43C, 0x01D43F, + 0x01D43E, 0x01D441, 0x01D440, 0x01D443, 0x01D442, 0x01D445, 0x01D444, 0x01D447, + 0x01D446, 0x01D449, 0x01D448, 0x01D44B, 0x01D44A, 0x01D44D, 0x01D44C, 0x01D44F, + 0x01D44E, 0x01D451, 0x01D450, 0x01D453, 0x01D452, 0x01D6D8, 0x01D454, 0x01D457, + 0x01D456, 0x01D459, 0x01D458, 0x01D45B, 0x01D45A, 0x01D45D, 0x01D45C, 0x01D45F, + 0x01D45E, 0x01D461, 0x01D460, 0x01D463, 0x01D462, 0x01D465, 0x01D464, 0x01D467, + 0x01D466, 0x01D469, 0x01D468, 0x01D46B, 0x01D46A, 0x01D46D, 0x01D46C, 0x01D46F, + 0x01D46E, 0x01D471, 0x01D470, 0x01D473, 0x01D472, 0x01D475, 0x01D474, 0x01D477, + 0x01D476, 0x01D479, 0x01D478, 0x01D47B, 0x01D47A, 0x01D47D, 0x01D47C, 0x01D47F, + 0x01D47E, 0x00145E, 0x00145F, 0x001458, 0x001459, 0x00145A, 0x00145B, 0x001454, + 0x001455, 0x001456, 0x001457, 0x001450, 0x001451, 0x001452, 0x001453, 0x00142C, + 0x00142D, 0x00142E, 0x00142F, 0x001428, 0x001429, 0x00142A, 0x00142B, 0x001424, + 0x001425, 0x001426, 0x001427, 0x001420, 0x001421, 0x001422, 0x001423, 0x00143C, + 0x00143D, 0x00143E, 0x00143F, 0x001438, 0x001439, 0x00143A, 0x00143B, 0x001434, + 0x001435, 0x001436, 0x001437, 0x001430, 0x001431, 0x001432, 0x001433, 0x00140C, + 0x00140D, 0x00140E, 0x00140F, 0x001408, 0x001409, 0x00140A, 0x00140B, 0x001404, + 0x001405, 0x001406, 0x001407, 0x001401, 0x001402, 0x001403, 0x00141C, 0x00141D, + 0x00141E, 0x00141F, 0x001418, 0x001419, 0x00141A, 0x00141B, 0x001414, 0x001415, + 0x001416, 0x001417, 0x00FF18, 0x001410, 0x001411, 0x001412, 0x001413, 0x0014EC, + 0x0014ED, 0x0014EE, 0x0014EF, 0x0014E8, 0x0014E9, 0x0014EA, 0x0014EB, 0x0014E4, + 0x0014E5, 0x0014E6, 0x0014E7, 0x0014E0, 0x0014E1, 0x0014E2, 0x0014E3, 0x0014FC, + 0x0014FD, 0x01D4E1, 0x01D4E0, 0x01D4E3, 0x01D4E2, 0x01D4E5, 0x01D4E4, 0x01D4E7, + 0x01D4E6, 0x01D4E9, 0x01D4E8, 0x01D4EB, 0x01D4EA, 0x01D4ED, 0x01D4EC, 0x01D4EF, + 0x01D4EE, 0x01D4F1, 0x01D4F0, 0x0014FE, 0x0014FF, 0x01D4F5, 0x01D4F4, 0x01D4F7, + 0x01D4F6, 0x01D4F9, 0x01D4F8, 0x01D4FB, 0x01D4FA, 0x01D4FD, 0x01D4FC, 0x01D4FF, + 0x01D4FE, 0x0014F8, 0x0014F9, 0x0014FA, 0x0014F5, 0x0014F6, 0x00FBDC, 0x00FBDD, + 0x0014F7, 0x0014F0, 0x0014F1, 0x00FBD9, 0x0014F2, 0x0014F3, 0x0014CC, 0x00FBDE, + 0x00FBDF, 0x0014CD, 0x0014CE, 0x0014CF, 0x01D612, 0x0014C8, 0x0014C9, 0x00FBE4, + 0x00FBE5, 0x00FBE6, 0x00FBE8, 0x0014CA, 0x0014CB, 0x00FBEF, 0x00FBFC, 0x00FBFD, + 0x0014C4, 0x00FBEB, 0x00FBF7, 0x00FBF0, 0x00FBF1, 0x00FBF2, 0x0014C5, 0x00FBF4, + 0x0014C6, 0x00FBF6, 0x0014C7, 0x00FBF9, 0x00FBFA, 0x00FBFF, 0x00FBF8, 0x00FBF5, + 0x00FBFE, 0x0014C0, 0x0014C1, 0x0014C2, 0x0014C3, 0x01D611, 0x0014DC, 0x0014DD, + 0x0014DE, 0x0014DF, 0x0014D8, 0x0014D9, 0x0014DA, 0x0014DB, 0x0014D4, 0x01D610, + 0x0014D5, 0x0014D6, 0x00FF90, 0x0014D7, 0x0014D0, 0x0014D1, 0x0014D2, 0x00FF95, + 0x00FF96, 0x01D6E8, 0x01D6EC, 0x00FBD8, 0x0014D3, 0x01D74C, 0x01D74D, 0x01D74E, + 0x01D6ED, 0x0014AC, 0x0014A6, 0x00FBE7, 0x0014BD, 0x00FBE1, 0x0014BE, 0x0014BF, + 0x0014B8, 0x0014B9, 0x0014BA, 0x0014BB, 0x0014B4, 0x0014B5, 0x0014B6, 0x0014B7, + 0x0014B0, 0x0014B1, 0x01D6E4, }; + +/* indexes */ +const uint16_t NU_DUCET_VALUES_I[] = { + 0x0781, 0x07BC, 0x0209, 0x075B, 0x07FE, 0x0802, 0x0760, 0x0765, 0x032D, 0x032C, + 0x032F, 0x0335, 0x0866, 0x0830, 0x03E7, 0x03E9, 0x0767, 0x0A68, 0x081A, 0x07FF, + 0x07F6, 0x07FB, 0x07F9, 0x07FD, 0x07C3, 0x07D9, 0x0749, 0x0763, 0x0767, 0x076C, + 0x0801, 0x080D, 0x0851, 0x0828, 0x0554, 0x0669, 0x076B, 0x06D2, 0x07EA, 0x0803, + 0x05BC, 0x0A7D, 0x07E2, 0x0856, 0x0300, 0x0897, 0x01DF, 0x05E9, 0x084C, 0x072F, + 0x0485, 0x04AB, 0x0510, 0x053D, 0x078C, 0x0792, 0x07C0, 0x07C6, 0x0578, 0x09C6, + 0x0688, 0x069C, 0x07F1, 0x076F, 0x023F, 0x023E, 0x0245, 0x024F, 0x024D, 0x024B, + 0x025D, 0x02C2, 0x061A, 0x065F, 0x0288, 0x0776, 0x0694, 0x05DD, 0x0600, 0x063C, + 0x02E8, 0x0493, 0x06B2, 0x0319, 0x04C1, 0x04CA, 0x04C7, 0x0313, 0x04D0, 0x05FB, + 0x05FA, 0x05FD, 0x03E5, 0x06A7, 0x06F5, 0x06AB, 0x089A, 0x0A44, 0x0767, 0x076C, + 0x0867, 0x089A, 0x0278, 0x07C2, 0x07D8, 0x07ED, 0x07AA, 0x07F8, 0x07FC, 0x07F2, + 0x04BF, 0x04BE, 0x0886, 0x0778, 0x01C9, 0x056A, 0x03BD, 0x083C, 0x0A62, 0x01A2, + 0x0198, 0x02D0, 0x067F, 0x02AE, 0x03CC, 0x036D, 0x0862, 0x0859, 0x082A, 0x07C5, + 0x0656, 0x0676, 0x0270, 0x0276, 0x086B, 0x027A, 0x04FA, 0x0269, 0x07F3, 0x02CC, + 0x026A, 0x0814, 0x06F6, 0x05A7, 0x04E9, 0x04A1, 0x02FA, 0x04E8, 0x04F4, 0x03CB, + 0x0766, 0x04F1, 0x061D, 0x06B4, 0x0622, 0x061F, 0x0761, 0x04EB, 0x0694, 0x061C, + 0x067F, 0x023D, 0x03FD, 0x0414, 0x07EE, 0x078D, 0x0760, 0x0765, 0x07BF, 0x076D, + 0x0783, 0x078F, 0x0832, 0x07C5, 0x085E, 0x083D, 0x0863, 0x022A, 0x0424, 0x044C, + 0x01F5, 0x061A, 0x0215, 0x021F, 0x0551, 0x0234, 0x082A, 0x0867, 0x086B, 0x065F, + 0x082F, 0x083B, 0x02F0, 0x032B, 0x07FE, 0x0802, 0x05DE, 0x061B, 0x0660, 0x0680, + 0x0832, 0x083D, 0x0292, 0x047F, 0x0769, 0x076E, 0x0816, 0x07F0, 0x0552, 0x0800, + 0x01DB, 0x05AD, 0x081B, 0x07F7, 0x0539, 0x07E7, 0x044D, 0x01BD, 0x0511, 0x056B, + 0x01C3, 0x01C1, 0x01F2, 0x080C, 0x02A9, 0x05CD, 0x02C7, 0x055D, 0x0827, 0x0816, + 0x036E, 0x038A, 0x03E4, 0x03E3, 0x040F, 0x0425, 0x03B3, 0x0885, 0x049D, 0x04E7, + 0x0534, 0x054E, 0x0819, 0x082F, 0x0850, 0x0861, 0x059A, 0x07ED, 0x06B3, 0x06A6, + 0x01F0, 0x0695, 0x081B, 0x0861, 0x06D3, 0x068D, 0x0253, 0x027E, 0x0240, 0x026B, + 0x0252, 0x027D, 0x02BE, 0x02C8, 0x02BF, 0x02C9, 0x02C1, 0x02CB, 0x02C0, 0x02CA, + 0x02DF, 0x02F1, 0x02E2, 0x02F4, 0x031F, 0x033B, 0x0312, 0x032E, 0x031B, 0x0337, + 0x031E, 0x033A, 0x0318, 0x0334, 0x0381, 0x038D, 0x0380, 0x038C, 0x0383, 0x038F, + 0x0384, 0x0390, 0x03A8, 0x03B4, 0x03AD, 0x03B9, 0x03D3, 0x03EB, 0x03B2, 0x03EE, + 0x03CE, 0x03E6, 0x03D4, 0x03ED, 0x03FC, 0x03EC, 0x03DF, 0x03F8, 0x040B, 0x0410, + 0x041F, 0x0428, 0x044E, 0x055C, 0x0450, 0x043D, 0x044F, 0x043F, 0x0456, 0x043E, + 0x0451, 0x0445, 0x049E, 0x0440, 0x04A3, 0x0490, 0x04A0, 0x0495, 0x0719, 0x0492, + 0x056A, 0x04BB, 0x04D4, 0x04FE, 0x04C0, 0x04EA, 0x04C9, 0x04F3, 0x04E4, 0x050E, + 0x055E, 0x056C, 0x0561, 0x056F, 0x055F, 0x056D, 0x059B, 0x05AE, 0x059D, 0x05B0, + 0x05A1, 0x05B4, 0x059E, 0x05B1, 0x05D1, 0x05E1, 0x05CE, 0x05DF, 0x05EB, 0x05EC, + 0x0606, 0x0628, 0x0609, 0x062B, 0x05FC, 0x061E, 0x0389, 0x049C, 0x0605, 0x0627, + 0x0608, 0x062A, 0x0679, 0x0683, 0x06A9, 0x06B6, 0x06D4, 0x06B7, 0x06D7, 0x06CA, + 0x047E, 0x06CD, 0x05A8, 0x06CC, 0x02B8, 0x02B0, 0x02B9, 0x02BA, 0x0714, 0x0715, + 0x02D8, 0x051F, 0x0306, 0x02D7, 0x030B, 0x0308, 0x06D1, 0x030A, 0x0353, 0x0350, + 0x037A, 0x0356, 0x039E, 0x0379, 0x03BF, 0x03A4, 0x0404, 0x0408, 0x0430, 0x0431, + 0x0476, 0x0463, 0x04B0, 0x064F, 0x052B, 0x04B1, 0x04DA, 0x0504, 0x03A5, 0x03A6, + 0x0545, 0x0546, 0x0711, 0x057B, 0x05C6, 0x0710, 0x05F0, 0x05C9, 0x05F1, 0x05F2, + 0x0630, 0x05F4, 0x0654, 0x060E, 0x06C3, 0x066F, 0x06DE, 0x06C2, 0x06ED, 0x06DD, + 0x06F0, 0x06F1, 0x0709, 0x06F3, 0x0712, 0x0713, 0x06FB, 0x05DA, 0x0728, 0x0727, + 0x072A, 0x0729, 0x02FD, 0x02FF, 0x045A, 0x02EC, 0x0448, 0x0459, 0x04A9, 0x04AA, + 0x0275, 0x049B, 0x03E8, 0x024A, 0x04F0, 0x03D0, 0x0620, 0x04C6, 0x0626, 0x05FE, + 0x0623, 0x0604, 0x0625, 0x0601, 0x0624, 0x0603, 0x034F, 0x0602, 0x024E, 0x0279, + 0x0251, 0x027C, 0x025F, 0x028A, 0x039A, 0x039B, 0x0382, 0x038E, 0x041E, 0x0427, + 0x04D2, 0x04FC, 0x04D3, 0x04FD, 0x06EC, 0x06EE, 0x02FE, 0x040C, 0x02EB, 0x02FC, + 0x037F, 0x038B, 0x0861, 0x03C0, 0x0491, 0x049F, 0x024C, 0x0277, 0x025E, 0x0289, + 0x04D1, 0x04FB, 0x07AA, 0x07C2, 0x07BF, 0x078F, 0x0783, 0x07C5, 0x07FC, 0x07F0, + 0x07F4, 0x081B, 0x07AA, 0x07C2, 0x07D8, 0x07FA, 0x0850, 0x0863, 0x085E, 0x0779, + 0x0749, 0x089A, 0x0861, 0x0763, 0x07ED, 0x076C, 0x078D, 0x0819, 0x0760, 0x0767, + 0x07ED, 0x076E, 0x082F, 0x0827, 0x083B, 0x082F, 0x0861, 0x0850, 0x0869, 0x0865, + 0x0816, 0x0885, 0x07C2, 0x0779, 0x0861, 0x07ED, 0x0819, 0x0827, 0x0765, 0x0760, + 0x076E, 0x0769, 0x078F, 0x0783, 0x07C5, 0x07BF, 0x07F0, 0x07E7, 0x07FA, 0x07F4, + 0x0802, 0x07FE, 0x081B, 0x0816, 0x07C5, 0x082A, 0x083D, 0x0832, 0x0863, 0x085E, + 0x086B, 0x0867, 0x07E7, 0x089A, 0x0763, 0x0749, 0x076C, 0x0767, 0x078D, 0x0779, + 0x07C2, 0x07AA, 0x07ED, 0x07D8, 0x07F8, 0x07F2, 0x0800, 0x07FC, 0x0819, 0x080C, + 0x082F, 0x0827, 0x083B, 0x082F, 0x0861, 0x0850, 0x0869, 0x0865, 0x07ED, 0x0885, + 0x07C2, 0x0779, 0x0861, 0x07ED, 0x0819, 0x0827, 0x0785, 0x0787, 0x0779, 0x07C2, + 0x01B1, 0x019D, 0x01E4, 0x01CF, 0x020E, 0x01FA, 0x0224, 0x021A, 0x0239, 0x022F, + 0x01B1, 0x019D, 0x01E4, 0x01CF, 0x020E, 0x01FA, 0x0224, 0x021A, 0x07F2, 0x07F8, + 0x076C, 0x0800, 0x080C, 0x0819, 0x0827, 0x082F, 0x07FE, 0x0802, 0x0850, 0x0861, + 0x082A, 0x07C5, 0x0832, 0x083D, 0x07FC, 0x083B, 0x0224, 0x021A, 0x0827, 0x082F, + 0x0760, 0x0765, 0x0769, 0x076E, 0x0783, 0x078F, 0x07BF, 0x07C5, 0x07E7, 0x07F0, + 0x05B7, 0x05A4, 0x0280, 0x0255, 0x0281, 0x0256, 0x033F, 0x0323, 0x0340, 0x0324, + 0x03F0, 0x03D7, 0x03F1, 0x03D8, 0x0502, 0x04D8, 0x0503, 0x04D9, 0x04F9, 0x04CF, + 0x06BA, 0x06AE, 0x0471, 0x04B7, 0x05F5, 0x0413, 0x02EA, 0x0550, 0x0295, 0x02D3, + 0x06C8, 0x06C7, 0x03B5, 0x03A9, 0x06E5, 0x0718, 0x0717, 0x02B1, 0x0645, 0x0675, + 0x034B, 0x034A, 0x0417, 0x0416, 0x055B, 0x055A, 0x0581, 0x0580, 0x04F8, 0x04CE, + 0x029A, 0x029C, 0x02A0, 0x02B7, 0x051E, 0x02D9, 0x0305, 0x0307, 0x0359, 0x0352, + 0x035A, 0x0355, 0x035B, 0x035F, 0x0360, 0x041A, 0x04B2, 0x030C, 0x0532, 0x0531, + 0x06E2, 0x06E1, 0x027B, 0x0250, 0x0311, 0x031C, 0x04F2, 0x04C8, 0x03CD, 0x0338, + 0x03CF, 0x03D1, 0x0652, 0x0489, 0x04AF, 0x04B6, 0x04AC, 0x052A, 0x06C9, 0x052E, + 0x04F7, 0x04CD, 0x0585, 0x0587, 0x02D2, 0x0464, 0x05EE, 0x05C1, 0x103C, 0x0DB8, + 0x0D7D, 0x0C6F, 0x1037, 0x0E0C, 0x1014, 0x1027, 0x0A7A, 0x0A79, 0x103E, 0x103F, + 0x0A54, 0x0A5D, 0x0A61, 0x0A67, 0x1040, 0x1021, 0x0CD1, 0x0D9B, 0x0CD6, 0x0CD3, + 0x1024, 0x0CD8, 0x1030, 0x0EB6, 0x0D9C, 0x0DB5, 0x0CD5, 0x102E, 0x1015, 0x0EB5, + 0x0A1A, 0x0A19, 0x0A5A, 0x0A58, 0x0A6B, 0x0764, 0x0A6E, 0x0A6D, 0x0A76, 0x0A75, + 0x0A72, 0x0A71, 0x0A55, 0x0A5F, 0x0A7C, 0x0A7B, 0x1039, 0x1034, 0x1033, 0x1038, + 0x0A83, 0x0A20, 0x0A6C, 0x1035, 0x0A08, 0x0A07, 0x0A22, 0x103D, 0x0768, 0x0A1F, + 0x0A1C, 0x0A1B, 0x09DC, 0x09E2, 0x09E9, 0x09F6, 0x0A09, 0x0A0B, 0x0473, 0x0A2D, + 0x0403, 0x0407, 0x03FE, 0x064E, 0x046B, 0x046F, 0x06C1, 0x06C0, 0x0A7E, 0x0A21, + 0x0A47, 0x0A84, 0x0A81, 0x0A82, 0x0A23, 0x0A43, 0x0989, 0x09AA, 0x0A4B, 0x0A50, + 0x098E, 0x0978, 0x09F7, 0x0A41, 0x02A3, 0x0396, 0x0399, 0x03A3, 0x02DE, 0x030F, + 0x0363, 0x037E, 0x03A7, 0x03CA, 0x0467, 0x041C, 0x078E, 0x048F, 0x040A, 0x04BD, + 0x0589, 0x039D, 0x03C2, 0x07AB, 0x074A, 0x058A, 0x07D4, 0x0515, 0x054C, 0x0583, + 0x0362, 0x064A, 0x043C, 0x0478, 0x058D, 0x058F, 0x0DAA, 0x0DB0, 0x0E41, 0x0DAB, + 0x0DA7, 0x0E06, 0x0E07, 0x0DAF, 0x0D99, 0x0DAE, 0x3242, 0x3243, 0x3245, 0x3250, + 0x3246, 0x3247, 0x2FAE, 0x3244, 0x324A, 0x324B, 0x3249, 0x324D, 0x324E, 0x324F, + 0x324C, 0x3251, 0x3252, 0x3253, 0x3254, 0x3260, 0x3256, 0x3257, 0x3258, 0x3259, + 0x325A, 0x325B, 0x2F27, 0x325D, 0x325E, 0x325F, 0x325C, 0x3261, 0x0CCC, 0x0D50, + 0x2FB0, 0x3286, 0x0F99, 0x0F9A, 0x0DAC, 0x3248, 0x0D88, 0x0D8B, 0x3265, 0x0DB7, + 0x0DAD, 0x0E08, 0x0E0B, 0x2FAF, 0x3272, 0x3273, 0x3275, 0x3280, 0x3276, 0x3277, + 0x3274, 0x3279, 0x327A, 0x327B, 0x3278, 0x327D, 0x0D4A, 0x327F, 0x327C, 0x3281, + 0x0D7B, 0x0D7C, 0x102B, 0x3287, 0x1032, 0x103B, 0x2FA8, 0x0D7E, 0x2FB1, 0x2FAA, + 0x0D45, 0x0D78, 0x2F90, 0x0E0D, 0x0D7A, 0x0FD9, 0x0E0E, 0x0EF5, 0x0E0A, 0x0E8B, + 0x0E8C, 0x0E8D, 0x0FDA, 0x0F64, 0x0F10, 0x0F13, 0x0C70, 0x1013, 0x0F65, 0x0F98, + 0x0F44, 0x0DB6, 0x327E, 0x3270, 0x0F14, 0x2FA5, 0x3266, 0x3267, 0x2FA7, 0x2FA4, + 0x326A, 0x326B, 0x326C, 0x326D, 0x326F, 0x2FA3, 0x3271, 0x2FA2, 0x101E, 0x2FA9, + 0x101D, 0x2FAB, 0x2FB6, 0x2FA6, 0x2FB8, 0x2FB9, 0x0988, 0x0933, 0x0931, 0x092E, + 0x2FBE, 0x2FBF, 0x2FAC, 0x2FAD, 0x2F4A, 0x2FC0, 0x2F4E, 0x095D, 0x2F47, 0x2F46, + 0x0932, 0x2F4F, 0x2F5A, 0x2F5B, 0x2F4D, 0x2F4B, 0x2F50, 0x2F51, 0x2F60, 0x2F61, + 0x2F53, 0x2F52, 0x2F55, 0x2F54, 0x2F5C, 0x2F5D, 0x2F59, 0x2F58, 0x2F44, 0x2F45, + 0x2F5E, 0x2F5F, 0x2F56, 0x2F57, 0x2F42, 0x2F43, 0x2F66, 0x2F62, 0x2F65, 0x2F64, + 0x2F67, 0x2F63, 0x2F48, 0x2F49, 0x0936, 0x2F6A, 0x2F6D, 0x2F6C, 0x2FB7, 0x095E, + 0x2F71, 0x2F70, 0x2F76, 0x2F72, 0x2F75, 0x2F74, 0x2F77, 0x2F73, 0x2F79, 0x2F78, + 0x2F7E, 0x2F7A, 0x2F7D, 0x2F7C, 0x2F7F, 0x2F7B, 0x2F81, 0x2F80, 0x3082, 0x3083, + 0x30A4, 0x30A5, 0x2F85, 0x30A3, 0x30A8, 0x30A9, 0x30A2, 0x308A, 0x2F86, 0x2F8C, + 0x2F87, 0x2F9F, 0x0937, 0x0991, 0x2F82, 0x2F83, 0x2F84, 0x2FC1, 0x2F97, 0x2F96, + 0x2F88, 0x2F89, 0x2F9B, 0x2F9A, 0x2F9D, 0x2F9C, 0x30BE, 0x2F9E, 0x2FA1, 0x2FA0, + 0x30C0, 0x30C1, 0x092F, 0x2FBA, 0x2F8B, 0x2FB3, 0x0992, 0x2F8A, 0x2FB4, 0x2F8D, + 0x2FB5, 0x30BC, 0x30BA, 0x2FB2, 0x2F68, 0x2F69, 0x30B2, 0x30B3, 0x30B4, 0x30B5, + 0x30B6, 0x30B7, 0x2F91, 0x30BB, 0x2FBB, 0x2F8E, 0x30B8, 0x30BD, 0x30BF, 0x2FBD, + 0x2F8F, 0x30B9, 0x2FEA, 0x2FEB, 0x2FEC, 0x2FED, 0x3046, 0x3047, 0x2FE6, 0x2FE7, + 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050, 0x3051, 0x2FEE, 0x2FEF, + 0x303A, 0x303B, 0x3054, 0x3055, 0x2FD6, 0x2FD7, 0x2FDC, 0x2FDD, 0x2FDA, 0x2FDB, + 0x2FE0, 0x2FE1, 0x2FF0, 0x2FF1, 0x3042, 0x3043, 0x3044, 0x3045, 0x3066, 0x3067, + 0x3048, 0x3049, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070, 0x3071, + 0x3052, 0x3053, 0x3074, 0x3075, 0x3056, 0x3057, 0x3058, 0x3059, 0x305A, 0x305B, + 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, 0x3061, 0x3062, 0x3063, 0x3084, 0x3085, + 0x3086, 0x3087, 0x3088, 0x3089, 0x3015, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, + 0x3090, 0x3091, 0x3092, 0x3093, 0x3094, 0x3095, 0x3096, 0x3097, 0x3098, 0x3099, + 0x309A, 0x309B, 0x309C, 0x309D, 0x309E, 0x309F, 0x30A0, 0x30A1, 0x3012, 0x3013, + 0x3014, 0x3065, 0x3006, 0x3037, 0x3019, 0x3064, 0x303D, 0x300C, 0x3018, 0x300D, + 0x3036, 0x3040, 0x303C, 0x3041, 0x3072, 0x3073, 0x3068, 0x3069, 0x3076, 0x3077, + 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, 0x3080, 0x3081, + 0x0946, 0x0945, 0x09C9, 0x09C8, 0x093E, 0x093D, 0x09EF, 0x09EE, 0x09AF, 0x09AE, + 0x0966, 0x0965, 0x0974, 0x0973, 0x0A69, 0x0A6A, 0x2EED, 0x0B95, 0x0A89, 0x0A8A, + 0x099B, 0x099C, 0x09A8, 0x09A9, 0x09C2, 0x0A15, 0x09D6, 0x09D7, 0x09C3, 0x0A16, + 0x09BA, 0x09BB, 0x0959, 0x09A4, 0x09E6, 0x09E5, 0x095A, 0x09A5, 0x0B90, 0x0BA5, + 0x0B94, 0x0B92, 0x0BA3, 0x0B9D, 0x0B96, 0x0B99, 0x0BA1, 0x0B9F, 0x0B93, 0x0BAD, + 0x0BA9, 0x0BA7, 0x0B9B, 0x0BAB, 0x0BB1, 0x0BAF, 0x0BB5, 0x0BB3, 0x0BBD, 0x0BBB, + 0x0BC1, 0x0BBF, 0x0BC8, 0x0B97, 0x2ECC, 0x0BC7, 0x0BBC, 0x09DA, 0x0BC5, 0x0BC6, + 0x0BD6, 0x0BD4, 0x0BDA, 0x0BB0, 0x0BDE, 0x0BDC, 0x0BD8, 0x0BE0, 0x0BC3, 0x0BBE, + 0x0BC0, 0x0BC9, 0x0BCB, 0x0BCD, 0x0BD0, 0x0BD2, 0x0BC4, 0x2EDD, 0x0BC2, 0x0BCE, + 0x0A32, 0x0A31, 0x0B9C, 0x0B8F, 0x0C2C, 0x0C26, 0x091C, 0x0BD1, 0x0C23, 0x3025, + 0x3026, 0x3027, 0x3024, 0x0BAE, 0x302A, 0x302B, 0x302C, 0x302D, 0x302E, 0x302F, + 0x3030, 0x3031, 0x0BB4, 0x2ED4, 0x0BB2, 0x0B9A, 0x0A35, 0x0997, 0x0BD7, 0x0BD9, + 0x0BD3, 0x0BD5, 0x0BDF, 0x0B98, 0x0BDB, 0x0BDD, 0x303E, 0x0C61, 0x2EC3, 0x2EC4, + 0x0C1E, 0x0C21, 0x2EC7, 0x2EC8, 0x0968, 0x0967, 0x09A7, 0x09A6, 0x09B1, 0x09B0, + 0x09E1, 0x09E0, 0x2EC9, 0x2ECA, 0x099E, 0x099D, 0x2ED5, 0x2ED6, 0x2ED3, 0x2ED0, + 0x2ED8, 0x2ED9, 0x2ECD, 0x2ECB, 0x2EDC, 0x2ECE, 0x2EDE, 0x2EDF, 0x2ED1, 0x2ED2, + 0x2EEE, 0x2EEF, 0x2EF0, 0x2EF1, 0x2EE6, 0x2EE7, 0x2EE4, 0x2EE5, 0x2EFA, 0x2EFB, + 0x2EEC, 0x2EEB, 0x2EE9, 0x2ECF, 0x2F00, 0x2EEA, 0x2EF2, 0x2EF3, 0x2EF4, 0x2EF5, + 0x2EFC, 0x2F01, 0x2EF8, 0x2EF9, 0x0C00, 0x2F0B, 0x2EFD, 0x2EE3, 0x2EF6, 0x2EF7, + 0x2EFE, 0x2EFF, 0x2F04, 0x2F03, 0x0BA6, 0x2F05, 0x2F08, 0x2F02, 0x2F09, 0x0BFA, + 0x0C03, 0x0BF9, 0x2F0C, 0x2F0D, 0x2F06, 0x2F07, 0x2F1D, 0x2F11, 0x2F14, 0x2F15, + 0x2F12, 0x2F13, 0x2F18, 0x2F19, 0x0C0B, 0x0BAA, 0x0B91, 0x0BAC, 0x0BF3, 0x0BF6, + 0x0C09, 0x0C05, 0x0BFE, 0x0BA0, 0x0BA2, 0x0BA4, 0x0C11, 0x0B9E, 0x0C0E, 0x0C14, + 0x0BEC, 0x0BEF, 0x0C15, 0x0C1C, 0x0C12, 0x0C20, 0x0BB6, 0x0C19, 0x0BE1, 0x0BE8, + 0x0C17, 0x0BA8, 0x0BCA, 0x0BCC, 0x0BFB, 0x0BFD, 0x2EE2, 0x2EE8, 0x2F1A, 0x2F1B, + 0x2F1C, 0x2F1F, 0x2F16, 0x2F17, 0x2F20, 0x2F21, 0x108C, 0x3202, 0x108E, 0x108F, + 0x0D9D, 0x1090, 0x3208, 0x3209, 0x3226, 0x3227, 0x322F, 0x0F04, 0x30D7, 0x0DBC, + 0x0DA3, 0x0E43, 0x0D40, 0x30D3, 0x322B, 0x3230, 0x322E, 0x0E61, 0x322A, 0x30D2, + 0x10A8, 0x3231, 0x0DB3, 0x322C, 0x321E, 0x10A7, 0x10A9, 0x10AA, 0x0D76, 0x30DF, + 0x1099, 0x109B, 0x323E, 0x30D6, 0x3224, 0x3225, 0x109E, 0x0D77, 0x316D, 0x31F0, + 0x31EE, 0x0D8D, 0x30D5, 0x30CD, 0x30DD, 0x3236, 0x3240, 0x3241, 0x3237, 0x2F2E, + 0x09D2, 0x0A5E, 0x2F2D, 0x09CE, 0x0979, 0x09CB, 0x2F30, 0x2F31, 0x2F2C, 0x09D0, + 0x09BC, 0x2F22, 0x097D, 0x2F25, 0x10A5, 0x09FF, 0x2F2F, 0x1096, 0x2F0A, 0x321F, + 0x2F24, 0x2F29, 0x2F0E, 0x2F0F, 0x2F10, 0x2F2A, 0x109F, 0x3153, 0x102A, 0x0A60, + 0x323C, 0x108D, 0x2F40, 0x2F28, 0x097E, 0x097A, 0x096F, 0x2F3B, 0x2F1E, 0x2F3A, + 0x2F41, 0x09FA, 0x2F26, 0x2F2B, 0x0A0E, 0x0970, 0x09D1, 0x2F3E, 0x2F38, 0x2F23, + 0x0A10, 0x09D3, 0x0A30, 0x0A0D, 0x0939, 0x0A0F, 0x0A53, 0x0A51, 0x0935, 0x0934, + 0x2F34, 0x2F35, 0x2F36, 0x2F37, 0x09DB, 0x2F3C, 0x2F3F, 0x2F33, 0x0A57, 0x0A56, + 0x2F32, 0x0938, 0x2F3D, 0x2F39, 0x0980, 0x097F, 0x1029, 0x102F, 0x09DF, 0x09DE, + 0x3154, 0x3159, 0x3177, 0x317B, 0x0E29, 0x0E0F, 0x092B, 0x103A, 0x0948, 0x0947, + 0x0998, 0x0A14, 0x099A, 0x0999, 0x1036, 0x0961, 0x0995, 0x0A02, 0x0A03, 0x0A13, + 0x0A2A, 0x0A29, 0x09F0, 0x0A36, 0x09E8, 0x09E7, 0x09BF, 0x09BE, 0x0A88, 0x0A87, + 0x0996, 0x09C4, 0x09A0, 0x0956, 0x0A12, 0x0A11, 0x09C5, 0x0A00, 0x09D9, 0x09D8, + 0x0A3A, 0x0A39, 0x0D83, 0x0E45, 0x0A3E, 0x0A3D, 0x0A40, 0x0A3F, 0x0D79, 0x0DE0, + 0x0928, 0x098F, 0x091E, 0x3167, 0x093C, 0x094D, 0x316B, 0x09BD, 0x09C0, 0x09B4, + 0x09B5, 0x0CD4, 0x0A37, 0x0A8B, 0x091F, 0x094F, 0x0920, 0x091D, 0x0957, 0x094B, + 0x0924, 0x0922, 0x0926, 0x0925, 0x0923, 0x0921, 0x0962, 0x0960, 0x0958, 0x0955, + 0x0A8C, 0x101F, 0x102C, 0x1026, 0x0993, 0x09A3, 0x09A2, 0x09C1, 0x1025, 0x1023, + 0x0954, 0x0994, 0x1028, 0x0A38, 0x32B0, 0x32A6, 0x09FD, 0x09F8, 0x32AA, 0x32AE, + 0x32AD, 0x0A2E, 0x32AF, 0x32B1, 0x0A01, 0x32AC, 0x09FE, 0x09F9, 0x102D, 0x09F1, + 0x1020, 0x1022, 0x1069, 0x106A, 0x1065, 0x1068, 0x106D, 0x106F, 0x106C, 0x108B, + 0x106B, 0x1081, 0x31C3, 0x1076, 0x31D8, 0x31D9, 0x107F, 0x106E, 0x1084, 0x1082, + 0x3255, 0x1085, 0x1083, 0x1080, 0x1089, 0x1088, 0x1079, 0x1066, 0x1077, 0x31DA, + 0x31D4, 0x31D5, 0x1087, 0x1067, 0x31D6, 0x31D7, 0x31DC, 0x31DD, 0x31D3, 0x31DB, + 0x31E0, 0x31DF, 0x31E1, 0x31D2, 0x1075, 0x31C2, 0x1072, 0x1074, 0x1071, 0x107D, + 0x31C4, 0x31C5, 0x31E6, 0x31ED, 0x107A, 0x107B, 0x31F6, 0x31E7, 0x31FC, 0x31FD, + 0x1070, 0x31EB, 0x1078, 0x107C, 0x31EA, 0x31EF, 0x31C8, 0x31C9, 0x31F7, 0x10A0, + 0x1092, 0x1097, 0x31DE, 0x31CD, 0x31EC, 0x31F1, 0x1098, 0x01DF, 0x01C9, 0x01A2, + 0x021F, 0x109A, 0x0CD2, 0x0234, 0x1091, 0x1093, 0x10A1, 0x10A2, 0x10A3, 0x10A4, + 0x109C, 0x109D, 0x321B, 0x1095, 0x3214, 0x3215, 0x1094, 0x1031, 0x3155, 0x321D, + 0x3212, 0x3213, 0x3216, 0x3205, 0x3203, 0x3217, 0x3218, 0x3219, 0x0198, 0x0209, + 0x022A, 0x0215, 0x107E, 0x1073, 0x3204, 0x10A6, 0x323A, 0x323B, 0x01F5, 0x323D, + 0x10AB, 0x10AC, 0x3220, 0x32A7, 0x321C, 0x3221, 0x32AB, 0x321A, 0x3200, 0x3201, + 0x097C, 0x0950, 0x0942, 0x0930, 0x094E, 0x096C, 0x0983, 0x0984, 0x09AB, 0x0952, + 0x09C7, 0x09F5, 0x108A, 0x098A, 0x09FC, 0x0A42, 0x094A, 0x094C, 0x0941, 0x092D, + 0x096B, 0x0A80, 0x0981, 0x0982, 0x097B, 0x1086, 0x09F4, 0x0951, 0x09B3, 0x09B9, + 0x09CD, 0x09D5, 0x0A48, 0x09E4, 0x09EB, 0x09FB, 0x09DD, 0x0A0C, 0x0A24, 0x0A2F, + 0x086A, 0x0A0A, 0x07E5, 0x0A52, 0x0740, 0x0990, 0x07A3, 0x07CF, 0x09B2, 0x0927, + 0x0929, 0x092C, 0x091B, 0x0949, 0x0953, 0x095F, 0x0987, 0x093A, 0x098D, 0x099F, + 0x0977, 0x09B8, 0x09CA, 0x09D4, 0x0817, 0x0823, 0x0833, 0x082D, 0x083A, 0x083E, + 0x085F, 0x0864, 0x0868, 0x086D, 0x07D3, 0x084B, 0x080A, 0x0847, 0x087E, 0x07EF, + 0x0762, 0x07C1, 0x085B, 0x085C, 0x085D, 0x0860, 0x0818, 0x07EC, 0x0822, 0x0821, + 0x078B, 0x078A, 0x0786, 0x0784, 0x0820, 0x081F, 0x089D, 0x089C, 0x08E2, 0x08E1, + 0x08EC, 0x08EB, 0x08EE, 0x08ED, 0x08F4, 0x08F3, 0x0902, 0x0901, 0x0908, 0x0907, + 0x0910, 0x090F, 0x07EB, 0x0826, 0x082E, 0x07E8, 0x07C4, 0x0A7F, 0x0A4D, 0x08A1, + 0x08A0, 0x0831, 0x081E, 0x081D, 0x082C, 0x0837, 0x0835, 0x0839, 0x32F5, 0x32D0, + 0x32C6, 0x32C7, 0x32F7, 0x32F4, 0x32CA, 0x32CB, 0x32CC, 0x32CD, 0x3282, 0x3283, + 0x32A8, 0x32A9, 0x3344, 0x3345, 0x3288, 0x3289, 0x3342, 0x3343, 0x334D, 0x334C, + 0x328E, 0x3347, 0x3290, 0x3346, 0x32CE, 0x32CF, 0x0C47, 0x0C46, 0x0C48, 0x3348, + 0x0D55, 0x3349, 0x334A, 0x334B, 0x0ECD, 0x0F8F, 0x1016, 0x0EA7, 0x0C50, 0x105E, + 0x32A2, 0x32A3, 0x32A4, 0x32A5, 0x32FF, 0x3330, 0x3268, 0x3269, 0x0FDB, 0x32FB, + 0x0C4C, 0x105F, 0x32C0, 0x0F66, 0x32F8, 0x32F9, 0x32B2, 0x32B3, 0x32B4, 0x32B5, + 0x32B6, 0x32B7, 0x32F6, 0x32B9, 0x32BA, 0x32BB, 0x32BC, 0x32BD, 0x32BE, 0x32BF, + 0x32C1, 0x32B8, 0x334F, 0x3350, 0x3351, 0x0C4B, 0x3331, 0x0C45, 0x3355, 0x3356, + 0x329A, 0x332C, 0x0CD7, 0x0ECF, 0x329E, 0x329F, 0x32FC, 0x3301, 0x3292, 0x3293, + 0x3294, 0x3295, 0x3296, 0x3297, 0x3298, 0x3299, 0x3285, 0x329B, 0x329C, 0x329D, + 0x3352, 0x3284, 0x32A0, 0x32A1, 0x0F45, 0x0DB9, 0x0CD9, 0x3327, 0x3361, 0x3362, + 0x0C99, 0x328F, 0x3360, 0x3365, 0x328C, 0x328B, 0x335F, 0x328A, 0x3291, 0x3366, + 0x3370, 0x3372, 0x336F, 0x3371, 0x32FA, 0x3376, 0x32FD, 0x3375, 0x3326, 0x0C49, + 0x32E5, 0x0C56, 0x0C4A, 0x32FE, 0x0C4F, 0x332D, 0x2636, 0x25B6, 0x25B7, 0x0C4E, + 0x0C57, 0x2635, 0x0C52, 0x25B1, 0x25A9, 0x25A7, 0x25A2, 0x0C58, 0x25A3, 0x25A8, + 0x0C4D, 0x25A1, 0x0C54, 0x25B0, 0x25B3, 0x25B2, 0x25BC, 0x25BD, 0x4495, 0x4492, + 0x25B9, 0x25B8, 0x0C51, 0x25BA, 0x44A9, 0x0215, 0x25C0, 0x449D, 0x25DB, 0x25E1, + 0x25A0, 0x25DA, 0x0C53, 0x44AB, 0x44AA, 0x44AF, 0x44D1, 0x0C55, 0x2634, 0x449C, + 0x25DC, 0x2703, 0x25A5, 0x263B, 0x4499, 0x44BD, 0x25D4, 0x25D3, 0x0C5A, 0x25D9, + 0x25D6, 0x25D7, 0x0CDA, 0x0CDB, 0x0F02, 0x0FD7, 0x1060, 0x1045, 0x25C3, 0x25DD, + 0x25ED, 0x25EE, 0x25E2, 0x0EFC, 0x0DBA, 0x0E8E, 0x25EC, 0x2620, 0x138B, 0x44C7, + 0x1063, 0x105D, 0x4498, 0x260A, 0x260B, 0x021F, 0x2626, 0x105C, 0x25FB, 0x2704, + 0x44B4, 0x0C59, 0x1042, 0x25F4, 0x261C, 0x261D, 0x2624, 0x2625, 0x2622, 0x2623, + 0x2627, 0x25FA, 0x2610, 0x2616, 0x0E62, 0x2615, 0x260D, 0x260C, 0x2617, 0x0D2A, + 0x25C2, 0x25EB, 0x2614, 0x25F2, 0x2619, 0x25C1, 0x2612, 0x2611, 0x1041, 0x1062, + 0x0DBB, 0x1046, 0x25DE, 0x104B, 0x25C7, 0x25C8, 0x4580, 0x25DF, 0x1384, 0x263A, + 0x12BE, 0x12BF, 0x25E0, 0x25F1, 0x44CE, 0x44B5, 0x44D0, 0x44CF, 0x12B6, 0x12B7, + 0x12C1, 0x12C9, 0x12C3, 0x12C2, 0x12C0, 0x12CE, 0x12C5, 0x12CF, 0x25EA, 0x446D, + 0x4430, 0x1548, 0x12C4, 0x12BD, 0x12C7, 0x12BB, 0x44FE, 0x0C9A, 0x2B27, 0x4481, + 0x0D94, 0x0EAE, 0x12F5, 0x12F6, 0x0C98, 0x0C9C, 0x32E3, 0x262F, 0x32E4, 0x32E9, + 0x0E42, 0x2B23, 0x12F0, 0x12EF, 0x441A, 0x2B21, 0x32E2, 0x32E8, 0x1D57, 0x2B22, + 0x262E, 0x12F1, 0x4450, 0x12F2, 0x4451, 0x2B24, 0x2637, 0x2B1D, 0x2B18, 0x441D, + 0x44C0, 0x44C1, 0x4489, 0x43A2, 0x4500, 0x44F6, 0x12C6, 0x3300, 0x4501, 0x4511, + 0x12DA, 0x12DD, 0x12E7, 0x12ED, 0x446A, 0x2B1F, 0x2B1E, 0x44FF, 0x44E4, 0x2B28, + 0x12C8, 0x44E5, 0x44D7, 0x44E0, 0x44D6, 0x44E1, 0x44DE, 0x44DB, 0x44DA, 0x44DD, + 0x44DC, 0x44DF, 0x022A, 0x0215, 0x022A, 0x021F, 0x0234, 0x0234, 0x0215, 0x021F, + 0x2699, 0x2696, 0x260E, 0x260F, 0x01C9, 0x01DF, 0x269F, 0x26A0, 0x269A, 0x2609, + 0x2607, 0x4502, 0x269E, 0x269D, 0x269B, 0x12D8, 0x44F5, 0x12D2, 0x12DB, 0x12D3, + 0x12E9, 0x12FA, 0x1307, 0x1302, 0x1308, 0x1309, 0x1303, 0x1306, 0x1305, 0x1304, + 0x1319, 0x131B, 0x26B2, 0x1318, 0x26B4, 0x26B3, 0x26B6, 0x26B5, 0x26B8, 0x26B7, + 0x26BA, 0x26B9, 0x130E, 0x26BB, 0x1313, 0x130F, 0x1315, 0x1314, 0x1317, 0x1316, + 0x1310, 0x1311, 0x1312, 0x131A, 0x131F, 0x1321, 0x2601, 0x25FE, 0x130B, 0x131D, + 0x2679, 0x2661, 0x2689, 0x2662, 0x01A2, 0x0198, 0x130D, 0x01C9, 0x31A4, 0x31A5, + 0x021F, 0x0215, 0x132F, 0x1334, 0x1327, 0x2618, 0x131C, 0x1333, 0x1336, 0x1335, + 0x1331, 0x1324, 0x31A9, 0x1325, 0x1326, 0x1337, 0x130A, 0x130C, 0x0198, 0x01A2, + 0x01DF, 0x0037, 0x01F5, 0x01C9, 0x0209, 0x31A8, 0x3182, 0x3183, 0x1323, 0x1338, + 0x31A2, 0x31A3, 0x3189, 0x0038, 0x003B, 0x003C, 0x318E, 0x131E, 0x318F, 0x0039, + 0x1320, 0x132E, 0x3192, 0x3193, 0x3194, 0x31B4, 0x31B2, 0x31B3, 0x3198, 0x3199, + 0x1328, 0x132C, 0x1322, 0x31B8, 0x132D, 0x31B9, 0x3190, 0x3191, 0x0A25, 0x0A26, + 0x0943, 0x0944, 0x09AC, 0x1329, 0x09B6, 0x09B7, 0x09CC, 0x09CF, 0x31B5, 0x09CF, + 0x09CC, 0x09CF, 0x003A, 0x09CC, 0x1330, 0x1332, 0x132A, 0x132B, 0x31B6, 0x31B7, + 0x31C0, 0x0234, 0x31BA, 0x31BB, 0x133E, 0x31C1, 0x1343, 0x133F, 0x31BE, 0x31BF, + 0x0A34, 0x133C, 0x0A33, 0x31BD, 0x0A45, 0x31BC, 0x2707, 0x1340, 0x133D, 0x3163, + 0x3164, 0x1341, 0x134C, 0x134A, 0x134F, 0x134E, 0x1351, 0x1350, 0x1354, 0x1352, + 0x1356, 0x1355, 0x3152, 0x3158, 0x3162, 0x3195, 0x3168, 0x3169, 0x317E, 0x317F, + 0x3180, 0x135F, 0x318B, 0x3176, 0x1364, 0x1363, 0x1366, 0x1365, 0x1369, 0x1367, + 0x317C, 0x3181, 0x136A, 0x317D, 0x1368, 0x1347, 0x317A, 0x1346, 0x095B, 0x3165, + 0x26D8, 0x270A, 0x3186, 0x3187, 0x26D2, 0x09F3, 0x318A, 0x095C, 0x09CC, 0x318D, + 0x0A2B, 0x09CF, 0x0A2C, 0x318C, 0x0976, 0x0975, 0x2706, 0x1381, 0x26DA, 0x0A3C, + 0x26D9, 0x25AC, 0x0972, 0x0971, 0x26E8, 0x0A27, 0x26BD, 0x093F, 0x134B, 0x4471, + 0x1353, 0x134D, 0x26BF, 0x136B, 0x0A46, 0x1362, 0x2702, 0x1380, 0x2708, 0x26C3, + 0x13CB, 0x26C4, 0x01A2, 0x0198, 0x01DF, 0x01C9, 0x0209, 0x01F5, 0x021F, 0x3166, + 0x0234, 0x022A, 0x3170, 0x4467, 0x316C, 0x316A, 0x26BE, 0x2633, 0x316E, 0x316F, + 0x3171, 0x44BB, 0x26D5, 0x26D4, 0x26CF, 0x26D0, 0x26D1, 0x44B6, 0x26DB, 0x26DC, + 0x4466, 0x26D7, 0x136D, 0x26D6, 0x136F, 0x136E, 0x1371, 0x1370, 0x1373, 0x1372, + 0x1377, 0x1375, 0x1378, 0x05B9, 0x071B, 0x0569, 0x30D9, 0x44F7, 0x26EB, 0x30D4, + 0x26B1, 0x01C9, 0x44B3, 0x26EC, 0x25F6, 0x2681, 0x0577, 0x01DF, 0x0474, 0x44B2, + 0x137B, 0x2700, 0x137A, 0x063B, 0x05D8, 0x2613, 0x0619, 0x26FF, 0x050D, 0x1391, + 0x0475, 0x03C3, 0x1395, 0x1394, 0x1397, 0x1396, 0x003F, 0x1398, 0x139F, 0x1399, + 0x05A6, 0x0040, 0x139C, 0x139B, 0x05E7, 0x035C, 0x30DC, 0x25FD, 0x137F, 0x028C, + 0x02DD, 0x30DB, 0x0262, 0x0261, 0x30C4, 0x30C5, 0x070B, 0x1383, 0x03FF, 0x30D8, + 0x0290, 0x071A, 0x0209, 0x052C, 0x26E2, 0x06EA, 0x26E5, 0x06F9, 0x13BC, 0x136C, + 0x065E, 0x26E1, 0x1393, 0x26E6, 0x0439, 0x0668, 0x30E0, 0x30E1, 0x26FD, 0x14BA, + 0x13BE, 0x4457, 0x022A, 0x441C, 0x26F4, 0x06FA, 0x30DA, 0x052D, 0x26F3, 0x01F5, + 0x0A5B, 0x0400, 0x01DF, 0x01C9, 0x0650, 0x0706, 0x021F, 0x0215, 0x0234, 0x022A, + 0x06F7, 0x048D, 0x06FD, 0x054B, 0x003E, 0x0042, 0x0704, 0x06FE, 0x0705, 0x0703, + 0x0041, 0x446C, 0x1379, 0x139E, 0x0366, 0x003D, 0x0707, 0x06E9, 0x02FB, 0x2705, + 0x037D, 0x0708, 0x13CE, 0x137E, 0x13B3, 0x0394, 0x13B2, 0x01DF, 0x13AE, 0x13CC, + 0x13B7, 0x13CD, 0x13AD, 0x025C, 0x03C1, 0x13B0, 0x02D6, 0x13AC, 0x13B1, 0x26BC, + 0x13B4, 0x26FE, 0x13B5, 0x13AF, 0x43AF, 0x328D, 0x1559, 0x1541, 0x13BF, 0x153B, + 0x139A, 0x13A2, 0x13A3, 0x43A4, 0x43A5, 0x43B0, 0x13BB, 0x3263, 0x4513, 0x4547, + 0x0209, 0x43B1, 0x4395, 0x452F, 0x13B8, 0x43A9, 0x13B9, 0x43A3, 0x0375, 0x43B6, + 0x43F6, 0x43B4, 0x43B2, 0x43B3, 0x43B7, 0x43BA, 0x43B8, 0x43FA, 0x43B9, 0x43BC, + 0x43BD, 0x43BB, 0x13C9, 0x13AB, 0x43A8, 0x43AA, 0x43CD, 0x43A6, 0x04E3, 0x43A7, + 0x13A4, 0x13A5, 0x43FE, 0x049A, 0x43AE, 0x13A9, 0x13C5, 0x13C8, 0x13C6, 0x13C7, + 0x31B0, 0x4397, 0x31B1, 0x326E, 0x13C4, 0x4393, 0x4394, 0x4398, 0x4392, 0x0376, + 0x13B6, 0x0287, 0x43DF, 0x43FC, 0x13BD, 0x13BA, 0x13CA, 0x13C3, 0x43DB, 0x2709, + 0x4396, 0x04A8, 0x0963, 0x4409, 0x13C0, 0x13C1, 0x13C2, 0x270B, 0x13D0, 0x13CF, + 0x43D6, 0x270C, 0x26EE, 0x3264, 0x13D1, 0x13D2, 0x13D3, 0x13D4, 0x31AF, 0x13D5, + 0x31AC, 0x31AE, 0x43DA, 0x31A7, 0x31A6, 0x31AA, 0x3262, 0x31AB, 0x43CA, 0x43CB, + 0x43C6, 0x43CC, 0x31AD, 0x43C7, 0x43FB, 0x43FD, 0x13EB, 0x1464, 0x456D, 0x138C, + 0x43F7, 0x2017, 0x152A, 0x137D, 0x1526, 0x1388, 0x441F, 0x1524, 0x4428, 0x4416, + 0x1386, 0x4417, 0x441B, 0x44A2, 0x4421, 0x137C, 0x13E9, 0x442B, 0x4431, 0x4420, + 0x442D, 0x4425, 0x4429, 0x4415, 0x13EC, 0x4426, 0x452C, 0x1382, 0x4424, 0x442E, + 0x13EA, 0x4423, 0x441E, 0x4427, 0x442F, 0x4522, 0x4548, 0x13F5, 0x444D, 0x4521, + 0x4448, 0x13F9, 0x4414, 0x4444, 0x1392, 0x13FA, 0x4537, 0x1387, 0x13D6, 0x1523, + 0x211D, 0x022A, 0x4443, 0x4445, 0x0234, 0x4449, 0x4413, 0x01C9, 0x4418, 0x4419, + 0x442A, 0x4412, 0x1C95, 0x021F, 0x4442, 0x4447, 0x1D6E, 0x442C, 0x4472, 0x4550, + 0x4478, 0x1C98, 0x152D, 0x4479, 0x447A, 0x447B, 0x447D, 0x0215, 0x1525, 0x1C75, + 0x447C, 0x1529, 0x01F5, 0x0049, 0x1C80, 0x0198, 0x01A2, 0x1C79, 0x1C8E, 0x0209, + 0x4490, 0x4491, 0x1C9C, 0x1C9B, 0x4551, 0x1C7A, 0x1C9D, 0x1C9E, 0x1CA1, 0x1CA2, + 0x4475, 0x1C89, 0x4477, 0x4474, 0x1CA3, 0x4476, 0x004B, 0x004A, 0x1C7C, 0x01DF, + 0x1C8F, 0x4473, 0x448E, 0x1416, 0x1412, 0x1413, 0x1410, 0x4487, 0x4485, 0x4484, + 0x4446, 0x4486, 0x448A, 0x4488, 0x448B, 0x1539, 0x444C, 0x448C, 0x1408, 0x1409, + 0x448D, 0x1538, 0x4493, 0x140E, 0x1417, 0x4494, 0x140F, 0x4496, 0x153D, 0x1553, + 0x1415, 0x1546, 0x1547, 0x1407, 0x140C, 0x1551, 0x154D, 0x140D, 0x44A3, 0x154C, + 0x44A5, 0x44A4, 0x153F, 0x13FD, 0x1561, 0x44A8, 0x1560, 0x1537, 0x44B0, 0x1536, + 0x44B1, 0x44AE, 0x1555, 0x155C, 0x1562, 0x1563, 0x153E, 0x140B, 0x44B7, 0x153A, + 0x44B9, 0x44B8, 0x1545, 0x44BA, 0x140A, 0x44BC, 0x1544, 0x1414, 0x154A, 0x154B, + 0x1550, 0x13FB, 0x13FC, 0x13FF, 0x13FE, 0x44C6, 0x1400, 0x1401, 0x44CB, 0x44CA, + 0x44CD, 0x44CC, 0x1542, 0x1430, 0x141C, 0x1419, 0x1403, 0x1543, 0x153C, 0x1540, + 0x1431, 0x1421, 0x01DF, 0x0198, 0x1405, 0x021F, 0x1300, 0x1406, 0x01A2, 0x01C9, + 0x141A, 0x0215, 0x142B, 0x141B, 0x01A2, 0x12AB, 0x1418, 0x1428, 0x1427, 0x142D, + 0x1566, 0x1557, 0x1556, 0x142A, 0x1429, 0x142F, 0x12FF, 0x1554, 0x44F3, 0x44F2, + 0x1300, 0x44F4, 0x155A, 0x155B, 0x44F9, 0x44F8, 0x44FB, 0x44FA, 0x44FD, 0x44FC, + 0x1447, 0x1567, 0x144B, 0x144D, 0x1301, 0x142C, 0x4505, 0x4504, 0x4507, 0x4506, + 0x4509, 0x4508, 0x450B, 0x01C9, 0x450D, 0x450C, 0x450F, 0x450E, 0x1D5B, 0x4510, + 0x01A2, 0x01DF, 0x4515, 0x4514, 0x1D6C, 0x1D5A, 0x1D61, 0x1D60, 0x1D68, 0x021F, + 0x0209, 0x1D6F, 0x1D67, 0x1D66, 0x1D6D, 0x0234, 0x4523, 0x1D69, 0x4525, 0x4524, + 0x4527, 0x4526, 0x4529, 0x4528, 0x452B, 0x452A, 0x452D, 0x0198, 0x0215, 0x452E, + 0x4531, 0x4530, 0x1D4D, 0x1D73, 0x022A, 0x1D4B, 0x1D4F, 0x144C, 0x1D48, 0x1D46, + 0x1D51, 0x1D45, 0x1D4E, 0x1D47, 0x1D4A, 0x1D5E, 0x1D71, 0x1D50, 0x1D5F, 0x1D4C, + 0x1D5C, 0x1D5D, 0x1D52, 0x4546, 0x141D, 0x1420, 0x454B, 0x454A, 0x454D, 0x454C, + 0x141E, 0x454E, 0x2B19, 0x141F, 0x146A, 0x4517, 0x2B11, 0x2B12, 0x2B1B, 0x2B1A, + 0x4422, 0x1432, 0x4549, 0x144A, 0x1446, 0x01C9, 0x1468, 0x021F, 0x1422, 0x1469, + 0x0215, 0x142E, 0x022A, 0x0234, 0x01DF, 0x01C9, 0x1D70, 0x2B0D, 0x1D72, 0x2B0F, + 0x2B0E, 0x2B1C, 0x2B14, 0x2B10, 0x2B13, 0x2B15, 0x2B16, 0x4572, 0x4575, 0x4574, + 0x4577, 0x4576, 0x4579, 0x4578, 0x457B, 0x457A, 0x457D, 0x457C, 0x1478, 0x1472, + 0x2B26, 0x2B25, 0x2B17, 0x146C, 0x146D, 0x2B29, 0x4587, 0x4586, 0x1FFD, 0x146B, + 0x458B, 0x458A, 0x458D, 0x458C, 0x1FFE, 0x458E, 0x4591, 0x2001, 0x147F, 0x2003, + 0x149C, 0x147E, 0x2008, 0x1480, 0x200A, 0x2009, 0x200C, 0x200B, 0x1481, 0x147C, + 0x2010, 0x200F, 0x2012, 0x2011, 0x14A9, 0x1474, 0x149A, 0x2015, 0x2018, 0x1470, + 0x201A, 0x2019, 0x1471, 0x201B, 0x14A2, 0x146E, 0x2020, 0x201F, 0x1484, 0x1485, + 0x147B, 0x14A5, 0x2026, 0x2025, 0x1486, 0x1483, 0x1479, 0x147A, 0x1487, 0x202B, + 0x1482, 0x149E, 0x45D1, 0x45C7, 0x45C8, 0x45C9, 0x45C5, 0x45AE, 0x459E, 0x459F, + 0x01DF, 0x01A2, 0x45A1, 0x0209, 0x1423, 0x45AF, 0x45B0, 0x45B1, 0x1499, 0x149B, + 0x1411, 0x0050, 0x004E, 0x4783, 0x004F, 0x14A8, 0x146F, 0x0051, 0x004D, 0x0198, + 0x01DF, 0x004C, 0x149D, 0x0052, 0x1475, 0x0215, 0x005B, 0x1426, 0x1496, 0x1497, + 0x149F, 0x1498, 0x14A3, 0x1493, 0x1D87, 0x1D7F, 0x1DA7, 0x1D91, 0x1491, 0x1DBF, + 0x1D99, 0x14A0, 0x14A1, 0x1DBA, 0x1D8C, 0x1D80, 0x1DA1, 0x1D93, 0x1DA8, 0x1DA4, + 0x45CD, 0x14AA, 0x14A7, 0x14A4, 0x1425, 0x1424, 0x14D8, 0x14B0, 0x0234, 0x022A, + 0x14B6, 0x14AE, 0x1DBD, 0x1DB0, 0x4874, 0x14AF, 0x14DD, 0x14DE, 0x14AD, 0x14D7, + 0x14B2, 0x14AC, 0x14B8, 0x14B7, 0x14D9, 0x14B9, 0x14BC, 0x14BB, 0x30C7, 0x14BD, + 0x14B1, 0x14B4, 0x14BF, 0x14BE, 0x14C1, 0x14C0, 0x14C3, 0x14C2, 0x30C3, 0x14CD, + 0x14D6, 0x14C6, 0x14C9, 0x14CB, 0x14C7, 0x14DA, 0x14C8, 0x30DE, 0x1B37, 0x14B5, + 0x14B3, 0x1B43, 0x14C5, 0x14CF, 0x14C4, 0x1B61, 0x14D5, 0x14CA, 0x1B79, 0x14D4, + 0x14D3, 0x1B5B, 0x14CE, 0x14DB, 0x30C2, 0x14DC, 0x14DF, 0x1DD2, 0x1B4F, 0x1B8B, + 0x1B91, 0x45CE, 0x45D0, 0x022A, 0x0234, 0x1B73, 0x1B85, 0x45CA, 0x30C9, 0x45C6, + 0x45B9, 0x1DA3, 0x45B3, 0x45CB, 0x45CC, 0x45B2, 0x45CF, 0x45BF, 0x4724, 0x4665, + 0x1514, 0x1BA1, 0x47CD, 0x1513, 0x0215, 0x1DB8, 0x1DCE, 0x1DD1, 0x46C4, 0x1DA0, + 0x0209, 0x47C0, 0x01C9, 0x01F5, 0x0215, 0x0198, 0x4807, 0x01A2, 0x01A2, 0x0198, + 0x14CC, 0x01C9, 0x0234, 0x01F5, 0x021F, 0x01DF, 0x14D2, 0x022A, 0x0198, 0x1D98, + 0x1B67, 0x1B6D, 0x1515, 0x01C9, 0x45B4, 0x45B5, 0x1D92, 0x1DB3, 0x0198, 0x1DAF, + 0x45E3, 0x4848, 0x01DF, 0x4819, 0x1B7F, 0x4801, 0x30C6, 0x481E, 0x01C9, 0x0234, + 0x487B, 0x022A, 0x30C8, 0x021F, 0x30D0, 0x18EF, 0x30D1, 0x30FC, 0x1B9B, 0x1B9C, + 0x45B8, 0x1901, 0x30CA, 0x30CB, 0x30CC, 0x18F5, 0x1B98, 0x30CF, 0x18FB, 0x0E89, + 0x30F2, 0x30E3, 0x0F95, 0x0F96, 0x0FAA, 0x0EFD, 0x30F8, 0x30F9, 0x0EA8, 0x0EA4, + 0x30CE, 0x1017, 0x192B, 0x1931, 0x0EA6, 0x0F11, 0x1A8F, 0x1A95, 0x0F8B, 0x1913, + 0x1B9D, 0x1B9E, 0x0F03, 0x1AB3, 0x0F43, 0x0D4F, 0x4772, 0x190D, 0x0F41, 0x0F42, + 0x0F40, 0x1AB9, 0x0F0F, 0x0F90, 0x1018, 0x0F97, 0x30F7, 0x1919, 0x1B55, 0x30F5, + 0x30F4, 0x30FD, 0x1B9A, 0x1B49, 0x0EF4, 0x30F3, 0x30F6, 0x1907, 0x0FAF, 0x3116, + 0x0FC8, 0x0215, 0x0FB8, 0x3117, 0x2135, 0x47F0, 0x4730, 0x0FB5, 0x30E7, 0x0FC2, + 0x30E8, 0x0FB0, 0x0E58, 0x3121, 0x311D, 0x3103, 0x311B, 0x30E6, 0x311C, 0x0FD8, + 0x0ECE, 0x0EAF, 0x14FA, 0x46FF, 0x0EB0, 0x0EF3, 0x48BE, 0x0ECC, 0x0EFB, 0x0EED, + 0x4701, 0x4610, 0x0EA9, 0x30E5, 0x0E63, 0x0FC5, 0x30E2, 0x0FC1, 0x30FE, 0x1008, + 0x30E4, 0x3120, 0x0E78, 0x212B, 0x0EF6, 0x476A, 0x2129, 0x311A, 0x30E9, 0x30FF, + 0x0EF2, 0x2137, 0x3100, 0x0F9B, 0x475F, 0x30FB, 0x30FA, 0x3101, 0x1B3D, 0x3102, + 0x14F5, 0x0D8C, 0x0F67, 0x0F46, 0x1127, 0x1126, 0x112A, 0x0D67, 0x469F, 0x0C64, + 0x310A, 0x310B, 0x3110, 0x0F15, 0x310E, 0x310F, 0x0D98, 0x3111, 0x0FDC, 0x0C65, + 0x0FBB, 0x0D1E, 0x0CC2, 0x0C9D, 0x1012, 0x0C5B, 0x0C5E, 0x0D7F, 0x0C6B, 0x0D06, + 0x0C71, 0x0C9B, 0x480D, 0x0CDC, 0x0CA7, 0x3123, 0x3122, 0x4677, 0x0D56, 0x0C68, + 0x0CDF, 0x0C6E, 0x30EC, 0x30ED, 0x0D91, 0x100F, 0x0F12, 0x0D2B, 0x1010, 0x30F1, + 0x0F0A, 0x3133, 0x3134, 0x3135, 0x0D95, 0x1011, 0x3138, 0x1A74, 0x1A75, 0x4882, + 0x1A55, 0x20FB, 0x0E8F, 0x0ED0, 0x0EB9, 0x0FE3, 0x3107, 0x212D, 0x3104, 0x3105, + 0x0F09, 0x4814, 0x468C, 0x4818, 0x477F, 0x311E, 0x3109, 0x46D5, 0x311F, 0x215B, + 0x2159, 0x47B3, 0x2167, 0x2157, 0x474B, 0x4632, 0x460F, 0x4669, 0x4635, 0x47B0, + 0x471B, 0x45EE, 0x4685, 0x46A5, 0x46F0, 0x4753, 0x46B6, 0x4704, 0x4866, 0x47BB, + 0x4615, 0x48BC, 0x4681, 0x4698, 0x3108, 0x47CF, 0x483E, 0x14F4, 0x0D8E, 0x3106, + 0x476E, 0x4762, 0x45E5, 0x214F, 0x46AB, 0x4666, 0x46AE, 0x4737, 0x2163, 0x4678, + 0x4889, 0x4767, 0x4677, 0x48AA, 0x467D, 0x46E9, 0x464D, 0x310C, 0x488B, 0x310D, + 0x151A, 0x200E, 0x457E, 0x470F, 0x47AA, 0x4581, 0x457F, 0x145D, 0x4520, 0x2115, + 0x2014, 0x022C, 0x0236, 0x019A, 0x2013, 0x2109, 0x01DF, 0x4886, 0x210F, 0x0221, + 0x0198, 0x01A2, 0x2117, 0x445B, 0x210B, 0x445C, 0x021F, 0x1435, 0x1433, 0x4460, + 0x1439, 0x210D, 0x1517, 0x4461, 0x1434, 0x1C90, 0x143E, 0x445A, 0x1C9F, 0x0234, + 0x01A4, 0x01CB, 0x448F, 0x151E, 0x1465, 0x152F, 0x2141, 0x1437, 0x4872, 0x1438, + 0x152B, 0x1518, 0x1C96, 0x4834, 0x1BB7, 0x211B, 0x445E, 0x1462, 0x01F5, 0x152C, + 0x1532, 0x4732, 0x1530, 0x1461, 0x4470, 0x1516, 0x20ED, 0x1C91, 0x0CA5, 0x143D, + 0x20F1, 0x20F3, 0x2165, 0x215F, 0x1C8A, 0x14FB, 0x1C8C, 0x20EF, 0x4750, 0x2161, + 0x20FD, 0x20EB, 0x20E9, 0x20FF, 0x46E2, 0x2107, 0x01C9, 0x01A2, 0x2119, 0x01DF, + 0x20F9, 0x0198, 0x2121, 0x2123, 0x20F5, 0x2127, 0x0234, 0x214D, 0x022A, 0x0209, + 0x021F, 0x0EB7, 0x0D24, 0x0C5C, 0x0217, 0x0D23, 0x0FBC, 0x2105, 0x01DF, 0x0FC9, + 0x0FE4, 0x0D19, 0x0CC7, 0x0215, 0x215D, 0x2153, 0x2151, 0x0D25, 0x1BBE, 0x151C, + 0x1C94, 0x1C8B, 0x47E7, 0x4456, 0x445D, 0x151D, 0x1BD1, 0x1BD0, 0x191F, 0x4693, + 0x1019, 0x473F, 0x1BD2, 0x18A7, 0x0EF7, 0x445F, 0x18B3, 0x0EF8, 0x1967, 0x18B9, + 0x1BBA, 0x1BBB, 0x0FAB, 0x0FD2, 0x0C78, 0x1C93, 0x0FAC, 0x1937, 0x1997, 0x0FCF, + 0x0FD1, 0x0EFA, 0x0D49, 0x0FC4, 0x0C29, 0x18AD, 0x0EB1, 0x01E1, 0x0CCD, 0x022A, + 0x1C73, 0x1C72, 0x0D9A, 0x01F7, 0x020B, 0x0DB4, 0x01F5, 0x0FC6, 0x487C, 0x18D1, + 0x0FB1, 0x0209, 0x0215, 0x021F, 0x022A, 0x0234, 0x0E09, 0x0E44, 0x0E8A, 0x47A2, + 0x1CA0, 0x0FB6, 0x1007, 0x1BB4, 0x1BB6, 0x0EF9, 0x485C, 0x01A2, 0x1C9A, 0x0198, + 0x0FCD, 0x0FD0, 0x1BBF, 0x101B, 0x1BB9, 0x1949, 0x46C5, 0x1BB8, 0x1BB5, 0x1BA6, + 0x1009, 0x100E, 0x1925, 0x0FB7, 0x2BF8, 0x0EEE, 0x1A72, 0x1A73, 0x0FD4, 0x2BF3, + 0x2BFB, 0x01C9, 0x0F0D, 0x0FD3, 0x143A, 0x143C, 0x1A76, 0x1404, 0x1402, 0x01A2, + 0x0198, 0x01A2, 0x01F5, 0x0209, 0x01F5, 0x0209, 0x1002, 0x01DF, 0x0215, 0x021F, + 0x4817, 0x19AD, 0x2C32, 0x2C2C, 0x2C27, 0x0BB9, 0x01DF, 0x0BB7, 0x193D, 0x19B2, + 0x2C2D, 0x01DF, 0x2C31, 0x2C2E, 0x1943, 0x47E5, 0x488E, 0x46E4, 0x4857, 0x0F2D, + 0x45E9, 0x47A1, 0x4871, 0x48AE, 0x46B4, 0x45E1, 0x48A8, 0x4892, 0x0F07, 0x479D, + 0x2C24, 0x0D1F, 0x2BF1, 0x0D26, 0x0D1A, 0x476F, 0x0D27, 0x0D1D, 0x2BEA, 0x0C24, + 0x0EAD, 0x0D1B, 0x0EAC, 0x0BEA, 0x0C07, 0x0C1B, 0x0BE6, 0x0EAA, 0x2BA3, 0x2BCA, + 0x2BA1, 0x0EB4, 0x2BBE, 0x2BA4, 0x2BA5, 0x2BA6, 0x0EB3, 0x2BBF, 0x2BC0, 0x2BC3, + 0x2BC4, 0x2BCB, 0x0EAB, 0x2AA7, 0x2C0B, 0x0F77, 0x0D28, 0x0D4B, 0x47F6, 0x2BC7, + 0x1DB9, 0x0D20, 0x2BE0, 0x2BE1, 0x0D29, 0x0F5B, 0x2AAB, 0x2BE5, 0x2BE6, 0x2BE7, + 0x0EB2, 0x0D4C, 0x0D53, 0x0D46, 0x0D47, 0x0D44, 0x2BEB, 0x0D41, 0x0D42, 0x0D4E, + 0x2691, 0x0D54, 0x1C71, 0x1C84, 0x0D4D, 0x1C74, 0x1C77, 0x1C76, 0x1C7E, 0x2676, + 0x2675, 0x267C, 0x1C7D, 0x1C78, 0x1C83, 0x1C7F, 0x2BFF, 0x2BFE, 0x1C81, 0x1CA4, + 0x1C92, 0x1C82, 0x226E, 0x2C0C, 0x1C97, 0x1C99, 0x226F, 0x2C0F, 0x46F8, 0x469A, + 0x26AF, 0x2C26, 0x2694, 0x2692, 0x2C0E, 0x2248, 0x2C06, 0x26A9, 0x2693, 0x2BFD, + 0x2C07, 0x2C02, 0x2C01, 0x1C7B, 0x2C03, 0x2C04, 0x2C0A, 0x2C09, 0x26AA, 0x26A2, + 0x26A3, 0x26A4, 0x26A1, 0x26A6, 0x26A5, 0x26B0, 0x2BA2, 0x26A7, 0x26A8, 0x26AC, + 0x2B9F, 0x0BF2, 0x2B87, 0x26AB, 0x1230, 0x264C, 0x1FFF, 0x2007, 0x201E, 0x2000, + 0x2002, 0x2672, 0x0469, 0x1234, 0x46EF, 0x2004, 0x475E, 0x11F0, 0x11EF, 0x268F, + 0x2670, 0x2690, 0x0398, 0x046D, 0x2688, 0x046A, 0x266F, 0x0522, 0x2016, 0x048B, + 0x0514, 0x2029, 0x2BE2, 0x034D, 0x051D, 0x268A, 0x264E, 0x2678, 0x0349, 0x264F, + 0x2653, 0x267D, 0x2669, 0x2671, 0x267B, 0x201C, 0x0299, 0x267A, 0x2006, 0x264D, + 0x029E, 0x202A, 0x0374, 0x265D, 0x0348, 0x266A, 0x2660, 0x266B, 0x265C, 0x04B8, + 0x2665, 0x2666, 0x2667, 0x2668, 0x2663, 0x2652, 0x266C, 0x2664, 0x2021, 0x2BE8, + 0x4672, 0x0649, 0x46F9, 0x0C13, 0x0643, 0x0C1A, 0x2005, 0x0FBA, 0x46B9, 0x0642, + 0x0C1F, 0x0C2D, 0x0CCE, 0x0D1C, 0x0F00, 0x2685, 0x0D48, 0x0FB4, 0x477E, 0x4791, + 0x0D22, 0x0EEF, 0x0F01, 0x06A2, 0x0FB2, 0x0FAE, 0x268C, 0x01A2, 0x2684, 0x268D, + 0x2023, 0x472A, 0x201D, 0x0FB9, 0x0D43, 0x0F91, 0x0BE7, 0x0C18, 0x2C21, 0x0F94, + 0x0C0D, 0x0C10, 0x0C25, 0x0C28, 0x0C2E, 0x2024, 0x0F93, 0x0C08, 0x0BE3, 0x0C27, + 0x0234, 0x4480, 0x2B77, 0x2B7A, 0x2B79, 0x0C2B, 0x2B78, 0x2B9A, 0x2BD2, 0x2022, + 0x2B7D, 0x069F, 0x2B80, 0x0FB3, 0x0C2A, 0x0BE2, 0x2B9B, 0x2B9D, 0x2B8A, 0x2B90, + 0x2B8D, 0x2B8B, 0x0BF7, 0x0C22, 0x2B93, 0x2B94, 0x2B96, 0x2B98, 0x2B95, 0x2B86, + 0x2B99, 0x2B92, 0x200D, 0x0CC6, 0x0C66, 0x2B85, 0x0CC5, 0x0C1D, 0x0C67, 0x2249, + 0x0CCA, 0x2B7F, 0x0CC3, 0x2639, 0x0CCB, 0x1231, 0x1247, 0x2B7B, 0x1233, 0x2B81, + 0x1235, 0x2BCC, 0x122F, 0x124A, 0x1249, 0x1248, 0x124B, 0x124C, 0x124D, 0x0CC8, + 0x2BD8, 0x2B83, 0x0CC9, 0x2BFC, 0x2B84, 0x0CD0, 0x2B89, 0x0CCF, 0x2BE4, 0x0CC4, + 0x0C16, 0x0FAD, 0x2AD6, 0x0D21, 0x2B9E, 0x04BC, 0x2638, 0x1FBC, 0x1FBD, 0x1FBE, + 0x1FC6, 0x1FC0, 0x4829, 0x0D93, 0x4768, 0x481C, 0x0D8A, 0x0EF1, 0x1FBF, 0x461B, + 0x0D52, 0x1FC2, 0x2B88, 0x474E, 0x265E, 0x0EF0, 0x0D51, 0x0D8F, 0x0D97, 0x0D96, + 0x022A, 0x0F05, 0x0EFF, 0x4835, 0x4867, 0x1FC3, 0x1FC4, 0x1FC5, 0x1D9C, 0x0F06, + 0x0F8E, 0x0F8D, 0x265F, 0x4699, 0x1DE9, 0x2BCF, 0x101A, 0x2BDB, 0x0F92, 0x4606, + 0x2BDF, 0x2AA3, 0x4842, 0x2BE3, 0x461C, 0x48A4, 0x486F, 0x1D8E, 0x45E0, 0x465D, + 0x475B, 0x48B0, 0x4883, 0x1DD3, 0x467F, 0x4790, 0x4726, 0x4968, 0x1DC4, 0x2B8F, + 0x1125, 0x480E, 0x1232, 0x470F, 0x11D2, 0x0F3C, 0x47EA, 0x0F3E, 0x0F3D, 0x4714, + 0x0F3F, 0x0F60, 0x4628, 0x0F62, 0x0F61, 0x0F85, 0x0F63, 0x0F87, 0x0F86, 0x0F89, + 0x481B, 0x484B, 0x11CE, 0x4859, 0x4850, 0x11CD, 0x46F5, 0x11CF, 0x48BE, 0x462E, + 0x45FB, 0x4780, 0x022A, 0x0234, 0x0DA1, 0x4756, 0x45DD, 0x000F, 0x000B, 0x0016, + 0x0013, 0x0C80, 0x0C7F, 0x0C82, 0x2680, 0x0C89, 0x0C88, 0x0CB6, 0x0CB5, 0x0CB8, + 0x0CB7, 0x0CBA, 0x0CB9, 0x0CF8, 0x0CF7, 0x0CFC, 0x0CF9, 0x0CFE, 0x0CFD, 0x0D0F, + 0x0D0E, 0x0D11, 0x0D10, 0x0D13, 0x0D12, 0x0E9C, 0x0E9B, 0x0EC5, 0x0EC4, 0x1D62, + 0x0964, 0x0A49, 0x1D64, 0x1D6B, 0x0A86, 0x0969, 0x1D65, 0x0A78, 0x0A74, 0x11D1, + 0x0A70, 0x0A85, 0x0A4E, 0x0A5C, 0x0A77, 0x0A4F, 0x0A63, 0x0A65, 0x0A6F, 0x0A04, + 0x096A, 0x0A73, 0x0A06, 0x0A64, 0x0A66, 0x096D, 0x096E, 0x09AD, 0x0A4A, 0x0A1E, + 0x09CC, 0x0A1D, 0x0986, 0x0985, 0x45DB, 0x473B, 0x098B, 0x14F6, 0x1128, 0x098C, + 0x14F0, 0x14F7, 0x11F1, 0x1D43, 0x01F5, 0x4641, 0x0209, 0x1549, 0x11D0, 0x1129, + 0x4755, 0x11EE, 0x1D6A, 0x11ED, 0x4712, 0x1D53, 0x11EC, 0x2B20, 0x0F0E, 0x14E9, + 0x10F2, 0x10F1, 0x2131, 0x2133, 0x46FB, 0x470A, 0x4754, 0x4633, 0x2145, 0x4778, + 0x2101, 0x2103, 0x4702, 0x472A, 0x14EC, 0x478D, 0x14EA, 0x43AB, 0x4623, 0x14ED, + 0x14EE, 0x14F1, 0x43D1, 0x14E8, 0x14F2, 0x14F3, 0x14EF, 0x2143, 0x2125, 0x488D, + 0x4764, 0x213D, 0x4738, 0x1FC1, 0x2139, 0x01A2, 0x212F, 0x111C, 0x111F, 0x4399, + 0x1121, 0x1120, 0x1123, 0x1122, 0x477B, 0x112B, 0x112E, 0x4831, 0x1130, 0x214B, + 0x1132, 0x1131, 0x1135, 0x1134, 0x1137, 0x1136, 0x1139, 0x2149, 0x113B, 0x113A, + 0x2155, 0x1552, 0x48B2, 0x113D, 0x47AC, 0x1501, 0x14FC, 0x469D, 0x4793, 0x48A6, + 0x46EA, 0x0234, 0x022A, 0x1D56, 0x4880, 0x4743, 0x1502, 0x150E, 0x46F4, 0x14FD, + 0x14FE, 0x114B, 0x01F5, 0x0209, 0x114E, 0x4616, 0x1150, 0x114F, 0x1152, 0x460E, + 0x48B4, 0x1153, 0x115B, 0x1D58, 0x115D, 0x115C, 0x4811, 0x485B, 0x4617, 0x4830, + 0x14FF, 0x14EB, 0x150F, 0x485F, 0x1511, 0x1510, 0x1D7D, 0x48B1, 0x46BE, 0x1DC0, + 0x01C9, 0x01A2, 0x01DF, 0x116F, 0x0215, 0x1512, 0x0198, 0x021F, 0x1D55, 0x14F8, + 0x1500, 0x1DAD, 0x14F9, 0x0209, 0x1DD5, 0x01F5, 0x213F, 0x213B, 0x1180, 0x117F, + 0x2113, 0x2027, 0x2147, 0x0046, 0x46C8, 0x1D63, 0x2028, 0x489C, 0x2111, 0x211F, + 0x45FC, 0x4888, 0x46ED, 0x20F7, 0x4769, 0x47CB, 0x297A, 0x2979, 0x1194, 0x1193, + 0x1196, 0x1195, 0x1198, 0x1197, 0x119A, 0x1199, 0x119D, 0x119C, 0x119F, 0x119E, + 0x11A1, 0x11A0, 0x11A3, 0x11A2, 0x2975, 0x11A4, 0x11A6, 0x11A5, 0x11A8, 0x11A7, + 0x2976, 0x2974, 0x11AA, 0x11A9, 0x11AC, 0x11AB, 0x11AE, 0x11AD, 0x2981, 0x11AF, + 0x2983, 0x11B0, 0x11B2, 0x11B1, 0x11B4, 0x11B3, 0x297D, 0x297C, 0x11B6, 0x297E, + 0x11B8, 0x11B7, 0x11BA, 0x11B9, 0x2978, 0x11BB, 0x11BE, 0x11BD, 0x11C0, 0x11BF, + 0x11C2, 0x11C1, 0x297F, 0x11C3, 0x11C5, 0x11C4, 0x11C7, 0x11C6, 0x11C9, 0x11C8, + 0x11CB, 0x11CA, 0x2991, 0x2967, 0x11D6, 0x11D5, 0x2966, 0x2964, 0x298C, 0x2965, + 0x2992, 0x2993, 0x2968, 0x2969, 0x296A, 0x296D, 0x296E, 0x296F, 0x11E4, 0x11E3, + 0x11E6, 0x11E5, 0x296C, 0x2973, 0x11EA, 0x11E9, 0x2982, 0x2980, 0x11F5, 0x11F4, + 0x11F7, 0x11F6, 0x298E, 0x2985, 0x2986, 0x29B5, 0x29B4, 0x2997, 0x298A, 0x298B, + 0x29B8, 0x298F, 0x2984, 0x2987, 0x2970, 0x2971, 0x2972, 0x2989, 0x29A5, 0x29A1, + 0x29A0, 0x29BF, 0x29B7, 0x29A7, 0x2999, 0x299A, 0x299D, 0x299E, 0x29B6, 0x298D, + 0x299C, 0x29A2, 0x29A3, 0x2988, 0x29C4, 0x29C5, 0x29E7, 0x1D44, 0x29C7, 0x29C9, + 0x29CA, 0x021F, 0x01F5, 0x01C9, 0x29B0, 0x1D54, 0x1D49, 0x29B1, 0x1D59, 0x47C3, + 0x29F5, 0x29D8, 0x29F7, 0x29F6, 0x29F9, 0x29F8, 0x29DA, 0x29FA, 0x29FD, 0x29DE, + 0x29FF, 0x29FE, 0x2A01, 0x2A00, 0x1D75, 0x2A02, 0x2A05, 0x2A04, 0x29D6, 0x2A06, + 0x2A09, 0x2A08, 0x2A0B, 0x2A0A, 0x1D74, 0x2A0C, 0x2A0F, 0x29DF, 0x4863, 0x2990, + 0x474D, 0x463A, 0x4771, 0x0C5D, 0x29D4, 0x29DB, 0x0E1F, 0x0DEB, 0x0CBB, 0x0C69, + 0x0C6D, 0x0C6C, 0x0C8B, 0x0C7D, 0x0C72, 0x0E11, 0x0CA1, 0x0C9F, 0x2A25, 0x2A24, + 0x29A6, 0x2A26, 0x29A4, 0x2A28, 0x01A2, 0x29AB, 0x01DF, 0x01C9, 0x0209, 0x29AF, + 0x29A9, 0x0D3A, 0x0234, 0x29AA, 0x0DFE, 0x29AD, 0x29CB, 0x0E18, 0x29C2, 0x29B9, + 0x29BA, 0x29BB, 0x29BC, 0x29BD, 0x29BE, 0x000C, 0x29C0, 0x29C1, 0x29B2, 0x29C3, + 0x0E2B, 0x0DA5, 0x0E9D, 0x0E98, 0x0DBE, 0x0DC9, 0x0DD8, 0x0EC0, 0x0EBB, 0x0D5C, + 0x0E17, 0x29D5, 0x224A, 0x000E, 0x29A8, 0x0DE2, 0x0DF1, 0x0D70, 0x29AC, 0x29B3, + 0x0004, 0x0003, 0x29D7, 0x0008, 0x0D69, 0x0D86, 0x0010, 0x0012, 0x0D85, 0x29AE, + 0x0006, 0x000A, 0x2A2C, 0x2A2A, 0x2A30, 0x2A2E, 0x2A34, 0x2A32, 0x2A38, 0x2A36, + 0x2A3C, 0x2A3A, 0x2A40, 0x2A3E, 0x2A44, 0x2A42, 0x2A48, 0x2A46, 0x2A4C, 0x2A4A, + 0x2A50, 0x2A4E, 0x0D62, 0x0D31, 0x0E7D, 0x2A56, 0x2A5C, 0x2A5A, 0x2A60, 0x2A5E, + 0x0002, 0x2A62, 0x2A68, 0x2A66, 0x2A6C, 0x2A6A, 0x2A2B, 0x2A29, 0x0D58, 0x0D5B, + 0x0001, 0x2A31, 0x2A37, 0x2A35, 0x2A3B, 0x2A39, 0x0E39, 0x2A3D, 0x2A43, 0x0E32, + 0x2A47, 0x2A45, 0x2A4B, 0x2A49, 0x0DCF, 0x2A4D, 0x2A53, 0x2A51, 0x2A57, 0x2A55, + 0x2A5B, 0x2A59, 0x2A5F, 0x2A5D, 0x2A63, 0x2A61, 0x2A67, 0x2A65, 0x2A6B, 0x2A69, + 0x46E6, 0x29C8, 0x469C, 0x4774, 0x29D2, 0x466E, 0x29CC, 0x29CD, 0x4761, 0x29D1, + 0x29D0, 0x4719, 0x01A2, 0x0198, 0x01DF, 0x01C9, 0x0209, 0x01F5, 0x021F, 0x0215, + 0x0234, 0x022A, 0x4745, 0x0F5E, 0x0C63, 0x0C62, 0x224B, 0x46B3, 0x4782, 0x0C5F, + 0x22C0, 0x22C1, 0x29E0, 0x46DE, 0x0C60, 0x29C6, 0x22DA, 0x29E1, 0x0C6A, 0x0C7A, + 0x0D0A, 0x22DB, 0x29CE, 0x29CF, 0x473A, 0x29DC, 0x22C5, 0x22D4, 0x29D9, 0x22D6, + 0x29D3, 0x29E2, 0x22D3, 0x0D0D, 0x22D5, 0x22D8, 0x29DD, 0x46A8, 0x29E3, 0x0CFF, + 0x22D7, 0x0CB2, 0x0D08, 0x0CAF, 0x0CDE, 0x226A, 0x226B, 0x0CDD, 0x0CE1, 0x22C2, + 0x22C6, 0x22C7, 0x0CA9, 0x0CF1, 0x22CA, 0x2264, 0x22C4, 0x22CB, 0x2244, 0x221D, + 0x2BF5, 0x4802, 0x2AAC, 0x2BED, 0x492D, 0x2C11, 0x4865, 0x48E0, 0x48EA, 0x0015, + 0x2238, 0x2269, 0x2228, 0x0014, 0x0D32, 0x21FC, 0x21FF, 0x21FE, 0x0018, 0x21FD, + 0x2203, 0x2200, 0x0D14, 0x0017, 0x0D2D, 0x0CEE, 0x2206, 0x2201, 0x2202, 0x2207, + 0x222C, 0x2235, 0x2234, 0x2239, 0x221E, 0x2209, 0x220A, 0x223B, 0x2205, 0x047C, + 0x04E2, 0x0446, 0x2204, 0x2218, 0x220B, 0x01A3, 0x0199, 0x01E0, 0x01CA, 0x020A, + 0x01F6, 0x0220, 0x0216, 0x0235, 0x223A, 0x221F, 0x2236, 0x2237, 0x2CB5, 0x2CBA, + 0x2CBF, 0x2C96, 0x2CA8, 0x2D35, 0x2D2F, 0x2D29, 0x2D5C, 0x2C67, 0x2C9D, 0x2C82, + 0x2C6D, 0x2CAF, 0x2C7C, 0x2CCE, 0x2C74, 0x2C7E, 0x2230, 0x0553, 0x053C, 0x05B8, + 0x0575, 0x063A, 0x05E6, 0x2C69, 0x2C77, 0x06BD, 0x0698, 0x2C6F, 0x06DA, 0x2CA2, + 0x2C84, 0x2C8B, 0x2C90, 0x2BEF, 0x02A7, 0x225C, 0x225F, 0x4658, 0x46D7, 0x225D, + 0x2260, 0x025B, 0x02C4, 0x465C, 0x4890, 0x2267, 0x2261, 0x477A, 0x47BD, 0x2263, + 0x0386, 0x0365, 0x4731, 0x45E2, 0x473D, 0x2BF9, 0x46D1, 0x4861, 0x484F, 0x4779, + 0x47B8, 0x47FD, 0x4707, 0x2C28, 0x4873, 0x483A, 0x0329, 0x4722, 0x473E, 0x46FD, + 0x453A, 0x0D92, 0x02E6, 0x4710, 0x225E, 0x4536, 0x2278, 0x4540, 0x453D, 0x453B, + 0x4534, 0x4535, 0x4541, 0x453F, 0x0499, 0x453C, 0x03B1, 0x4785, 0x4720, 0x03DB, + 0x480F, 0x0422, 0x040D, 0x471C, 0x453E, 0x483E, 0x454F, 0x2CC9, 0x2CC4, 0x2CD6, + 0x2CD1, 0x2CDF, 0x4781, 0x2CE6, 0x2CE2, 0x2CEC, 0x4562, 0x4571, 0x2CF4, 0x4568, + 0x2D04, 0x4553, 0x456E, 0x2D1F, 0x4566, 0x2D25, 0x2D22, 0x456F, 0x2D2B, 0x2D3C, + 0x4565, 0x2D44, 0x2D40, 0x2D4C, 0x2D48, 0x2D5F, 0x2D52, 0x2265, 0x4564, 0x0D82, + 0x456C, 0x4567, 0x4569, 0x4563, 0x4555, 0x0DA6, 0x0D6D, 0x22B0, 0x0D6C, 0x2266, + 0x22B7, 0x4554, 0x2977, 0x4558, 0x0D81, 0x2A81, 0x4552, 0x2A87, 0x2A84, 0x4559, + 0x0DA0, 0x4844, 0x458F, 0x01DF, 0x48C5, 0x0D9F, 0x01C9, 0x1DD0, 0x456A, 0x456B, + 0x4570, 0x4590, 0x0EBF, 0x2B33, 0x2B30, 0x2B39, 0x2B36, 0x2B3F, 0x2B3C, 0x0B4C, + 0x2A9D, 0x2B45, 0x2B42, 0x2B4B, 0x2B48, 0x2B51, 0x2B4E, 0x0E97, 0x46E5, 0x46EB, + 0x0B4F, 0x0B55, 0x2AB3, 0x0E91, 0x2A91, 0x2AA6, 0x23B2, 0x4799, 0x2AA0, 0x46A3, + 0x2B6C, 0x471C, 0x0ED2, 0x23B3, 0x4764, 0x46AD, 0x4622, 0x46A7, 0x2A73, 0x46C3, + 0x45D9, 0x2245, 0x46E8, 0x47BC, 0x462B, 0x2A76, 0x23B0, 0x2246, 0x45EC, 0x481A, + 0x0198, 0x01A2, 0x2247, 0x0EC6, 0x4841, 0x478B, 0x48C8, 0x0EDC, 0x0F17, 0x4607, + 0x0EE4, 0x461E, 0x23AA, 0x0F24, 0x0F35, 0x2392, 0x23AE, 0x36F5, 0x3724, 0x23A8, + 0x36F9, 0x23AD, 0x3725, 0x3709, 0x3729, 0x372A, 0x372D, 0x370D, 0x370E, 0x370F, + 0x3710, 0x3702, 0x3701, 0x23A5, 0x3703, 0x3707, 0x3705, 0x23A9, 0x23A6, 0x370C, + 0x23B1, 0x23A4, 0x370B, 0x370A, 0x3706, 0x3708, 0x23AB, 0x3721, 0x23B4, 0x23B5, + 0x23BC, 0x23AF, 0x23B8, 0x3720, 0x3727, 0x23BB, 0x23AC, 0x23BD, 0x23BE, 0x23BF, + 0x23C0, 0x3726, 0x23C2, 0x23C3, 0x2384, 0x2385, 0x2383, 0x2387, 0x237D, 0x2378, + 0x2348, 0x2389, 0x2386, 0x22CF, 0x237F, 0x237E, 0x3722, 0x238B, 0x2388, 0x372F, + 0x23A2, 0x2394, 0x237A, 0x23A3, 0x239B, 0x23A1, 0x2379, 0x2398, 0x239D, 0x238F, + 0x239F, 0x239C, 0x23A0, 0x238A, 0x239E, 0x373D, 0x2393, 0x3745, 0x373E, 0x237B, + 0x373C, 0x3741, 0x2374, 0x3742, 0x3747, 0x3731, 0x238E, 0x2C2F, 0x238C, 0x238D, + 0x3730, 0x3711, 0x2377, 0x3713, 0x3714, 0x3717, 0x22BD, 0x3740, 0x3712, 0x3719, + 0x371B, 0x3746, 0x3744, 0x2376, 0x3716, 0x3715, 0x371F, 0x2C29, 0x372E, 0x23B7, + 0x2BE9, 0x2C2B, 0x3739, 0x22D1, 0x23B6, 0x3728, 0x236C, 0x3718, 0x23BA, 0x23C1, + 0x372C, 0x2BEE, 0x2372, 0x2373, 0x22CE, 0x374B, 0x23A7, 0x374A, 0x3751, 0x22CD, + 0x374C, 0x3755, 0x3752, 0x3759, 0x2BF6, 0x374F, 0x374E, 0x23B9, 0x3750, 0x2C2A, + 0x22BC, 0x375D, 0x22BE, 0x22BF, 0x2390, 0x2365, 0x2240, 0x22C3, 0x2363, 0x2C22, + 0x2391, 0x2366, 0x2BF4, 0x236F, 0x2369, 0x236B, 0x22CC, 0x236D, 0x376A, 0x22D2, + 0x236E, 0x3771, 0x2BEC, 0x22D0, 0x2380, 0x2382, 0x22D9, 0x2371, 0x237C, 0x2381, + 0x2367, 0x2368, 0x377A, 0x377B, 0x377C, 0x3781, 0x377E, 0x377F, 0x3780, 0x3785, + 0x3782, 0x2405, 0x23C6, 0x23C7, 0x23C9, 0x3789, 0x248D, 0x23CA, 0x378A, 0x378D, + 0x23D4, 0x3733, 0x3735, 0x3791, 0x3734, 0x3736, 0x3737, 0x3738, 0x373B, 0x3748, + 0x3732, 0x248C, 0x373A, 0x379B, 0x379A, 0x23D7, 0x379C, 0x379F, 0x379E, 0x37A1, + 0x37A0, 0x37A3, 0x37A2, 0x37A5, 0x37A4, 0x37A7, 0x3749, 0x37A9, 0x37A8, 0x23F7, + 0x37AA, 0x37AD, 0x24A9, 0x23F5, 0x23F6, 0x37B1, 0x24B1, 0x24AF, 0x24B8, 0x24B2, + 0x24B4, 0x24B5, 0x24AE, 0x23DC, 0x24B7, 0x37BB, 0x37BA, 0x23E1, 0x37BC, 0x37BF, + 0x37BE, 0x37C1, 0x37C0, 0x37C3, 0x37C2, 0x23DE, 0x37C4, 0x2407, 0x2420, 0x240A, + 0x23E3, 0x2406, 0x0209, 0x23D5, 0x23D6, 0x0096, 0x0097, 0x23D9, 0x00AB, 0x23DB, + 0x0092, 0x23DD, 0x0099, 0x23DF, 0x23D8, 0x23DA, 0x0098, 0x008B, 0x23FE, 0x008D, + 0x008C, 0x008A, 0x23E0, 0x0091, 0x0090, 0x0095, 0x01DF, 0x01F5, 0x021F, 0x008E, + 0x008F, 0x0094, 0x0093, 0x01C9, 0x009A, 0x0215, 0x009C, 0x009B, 0x0234, 0x022A, + 0x01A2, 0x00A3, 0x23FF, 0x00A5, 0x00A4, 0x009E, 0x009F, 0x00A0, 0x00A1, 0x23E2, + 0x24AA, 0x2489, 0x2482, 0x2481, 0x2480, 0x2485, 0x2483, 0x00AC, 0x00A2, 0x2486, + 0x24AD, 0x00A7, 0x00A6, 0x00A9, 0x00A8, 0x01C9, 0x00AE, 0x00AF, 0x01A2, 0x00B3, + 0x01C9, 0x248B, 0x01C9, 0x2A54, 0x2404, 0x2409, 0x0209, 0x240B, 0x23D0, 0x2412, + 0x2408, 0x00BB, 0x00BA, 0x00C1, 0x00BC, 0x00BF, 0x00BE, 0x00BD, 0x00C0, 0x01A2, + 0x2354, 0x2431, 0x01A2, 0x01A2, 0x2358, 0x01C9, 0x24AC, 0x00AA, 0x240C, 0x00C5, + 0x0209, 0x24AB, 0x23F8, 0x2424, 0x2402, 0x2484, 0x23FC, 0x23FD, 0x2488, 0x248A, + 0x2401, 0x2403, 0x24D8, 0x00D4, 0x009D, 0x00D2, 0x00AD, 0x00D7, 0x00D3, 0x00D5, + 0x00D6, 0x24BE, 0x24BC, 0x00D9, 0x24BA, 0x2498, 0x24C1, 0x24BB, 0x00D8, 0x24C3, + 0x24C0, 0x2490, 0x24BF, 0x2492, 0x2491, 0x2496, 0x2493, 0x00DA, 0x2497, 0x24C8, + 0x0198, 0x2499, 0x24C7, 0x24DC, 0x2495, 0x2494, 0x24EA, 0x24E6, 0x24E7, 0x24EB, + 0x24EE, 0x24CB, 0x2355, 0x24A7, 0x24C6, 0x24CC, 0x11B5, 0x2353, 0x24CA, 0x2241, + 0x2356, 0x2410, 0x24EC, 0x24CD, 0x24E0, 0x24E9, 0x24ED, 0x24B0, 0x24E2, 0x24BD, + 0x24EF, 0x24A1, 0x24C9, 0x24B3, 0x24E4, 0x240E, 0x24C2, 0x24D5, 0x1CC5, 0x1CC4, + 0x1CC7, 0x1CC6, 0x1CC9, 0x1CC8, 0x1CCB, 0x1CCA, 0x1CCD, 0x1CCC, 0x1CCF, 0x1CCE, + 0x2242, 0x1CD0, 0x1CD2, 0x1CD1, 0x2243, 0x1CD3, 0x1CD4, 0x223C, 0x223D, 0x223E, + 0x223F, 0x2258, 0x2259, 0x114C, 0x225A, 0x225B, 0x2254, 0x2437, 0x2438, 0x2A3F, + 0x1CD6, 0x1CD5, 0x1CD8, 0x1CD7, 0x1CDA, 0x2425, 0x1CDC, 0x1CDB, 0x1CDE, 0x1D02, + 0x1CE0, 0x1CDF, 0x1D05, 0x1CE1, 0x1D06, 0x242B, 0x1CE6, 0x1CE5, 0x2255, 0x2439, + 0x2429, 0x2428, 0x2256, 0x2257, 0x2250, 0x242D, 0x242F, 0x2251, 0x2430, 0x2252, + 0x2253, 0x2339, 0x1CE8, 0x1BC1, 0x1CEA, 0x1CE9, 0x1CEC, 0x1CEE, 0x2413, 0x1CEB, + 0x240D, 0x1CE7, 0x1CF2, 0x240F, 0x242E, 0x1CF3, 0x1CED, 0x1CF1, 0x1CF8, 0x1CF7, + 0x1CFE, 0x3514, 0x1CFF, 0x2411, 0x34FB, 0x3501, 0x1CEF, 0x1CF0, 0x1D03, 0x1D04, + 0x1D01, 0x1CF4, 0x1CF5, 0x1CF6, 0x1BC0, 0x234A, 0x2432, 0x11BC, 0x3507, 0x34FE, + 0x3516, 0x3500, 0x3510, 0x3512, 0x2436, 0x2434, 0x1CFC, 0x34FF, 0x3523, 0x2433, + 0x1CF9, 0x242C, 0x1D08, 0x1CFB, 0x351D, 0x3529, 0x2357, 0x1CFA, 0x351B, 0x2435, + 0x2426, 0x351C, 0x351F, 0x2427, 0x242A, 0x1D00, 0x1E11, 0x1E14, 0x1E13, 0x1E12, + 0x1E15, 0x1E10, 0x1E17, 0x1E16, 0x1E29, 0x1E28, 0x1E1B, 0x1E1A, 0x1E2D, 0x1E19, + 0x1E2F, 0x1E2E, 0x1E21, 0x3505, 0x1E23, 0x1E1E, 0x1E1D, 0x1E24, 0x1E1F, 0x1E22, + 0x1E20, 0x1E2C, 0x1E2B, 0x1E2A, 0x1E18, 0x1E25, 0x1E26, 0x1E27, 0x224C, 0x1E34, + 0x224D, 0x1E31, 0x1E37, 0x1E38, 0x1E32, 0x1E36, 0x1E30, 0x224E, 0x2A41, 0x1E3A, + 0x1E1C, 0x1E3D, 0x29FB, 0x1118, 0x1E42, 0x1E43, 0x1E44, 0x1E41, 0x351E, 0x0B7F, + 0x111D, 0x3522, 0x1117, 0x3525, 0x3524, 0x3503, 0x3504, 0x3528, 0x224F, 0x0B4D, + 0x2349, 0x2328, 0x0085, 0x351A, 0x2A16, 0x0B50, 0x112F, 0x2A15, 0x1141, 0x2329, + 0x2A14, 0x1144, 0x2A1A, 0x3520, 0x1143, 0x2A17, 0x232A, 0x232B, 0x34B3, 0x1146, + 0x34A4, 0x1110, 0x2A1B, 0x34A7, 0x34AC, 0x34B0, 0x34AA, 0x2A1F, 0x34B2, 0x1E33, + 0x1142, 0x34A1, 0x01A2, 0x01C9, 0x01DF, 0x0198, 0x0209, 0x0215, 0x021F, 0x01F5, + 0x0234, 0x022A, 0x34A0, 0x349F, 0x34A3, 0x34A6, 0x34A5, 0x2A6D, 0x112C, 0x01C9, + 0x0198, 0x2324, 0x2A03, 0x01A2, 0x01DF, 0x01F5, 0x0234, 0x2325, 0x34AE, 0x34AD, + 0x0209, 0x022A, 0x021F, 0x0215, 0x1BC2, 0x2085, 0x2070, 0x2051, 0x2056, 0x2058, + 0x205E, 0x2083, 0x2066, 0x2069, 0x2071, 0x207B, 0x1BC3, 0x208C, 0x1A5B, 0x2087, + 0x206F, 0x1BBC, 0x022A, 0x0234, 0x19B3, 0x19E3, 0x29E6, 0x022A, 0x00DE, 0x29EF, + 0x00DC, 0x00DD, 0x34DC, 0x00DF, 0x00E0, 0x2326, 0x2067, 0x205D, 0x2086, 0x205C, + 0x2076, 0x2065, 0x2064, 0x2077, 0x204A, 0x207F, 0x2073, 0x207E, 0x2080, 0x2040, + 0x2045, 0x01A2, 0x01F5, 0x206B, 0x01C9, 0x0215, 0x34B1, 0x021F, 0x2068, 0x34B4, + 0x34B5, 0x34B6, 0x34B7, 0x34B8, 0x34B9, 0x34CF, 0x34BB, 0x0209, 0x208F, 0x208E, + 0x0234, 0x2090, 0x2037, 0x2034, 0x203F, 0x203D, 0x2044, 0x2042, 0x204E, 0x2049, + 0x2054, 0x00DB, 0x205A, 0x2055, 0x206C, 0x2052, 0x350B, 0x2075, 0x0AFF, 0x2093, + 0x2072, 0x3532, 0x3533, 0x0B03, 0x0B04, 0x207C, 0x0B0A, 0x206D, 0x0B06, 0x2053, + 0x2036, 0x2033, 0x2031, 0x203C, 0x2043, 0x2041, 0x2050, 0x2046, 0x204D, 0x350A, + 0x204F, 0x3509, 0x2059, 0x350D, 0x205B, 0x0209, 0x01A2, 0x2048, 0x0084, 0x2047, + 0x0AFB, 0x0AFC, 0x0AFD, 0x206A, 0x0B01, 0x2039, 0x0B02, 0x3517, 0x207D, 0x3519, + 0x3518, 0x2082, 0x01C9, 0x45B6, 0x01DF, 0x0B0F, 0x0B10, 0x2A07, 0x0215, 0x2327, + 0x45BC, 0x2320, 0x1A67, 0x1A61, 0x45BD, 0x1A6D, 0x0B00, 0x352B, 0x352D, 0x3531, + 0x352C, 0x0AF8, 0x3AC8, 0x0AFA, 0x352A, 0x3AC3, 0x0AF4, 0x0AF7, 0x3AC6, 0x3AC9, + 0x3AC7, 0x3530, 0x3ACA, 0x0AED, 0x0D80, 0x0AEE, 0x3AC2, 0x0AEB, 0x0AEC, 0x0AEF, + 0x0AF0, 0x3508, 0x0AF3, 0x0AF9, 0x0AF5, 0x0AF1, 0x0AF6, 0x0AF2, 0x0E10, 0x0E90, + 0x0D9E, 0x0EBA, 0x0CE0, 0x0DE1, 0x0D68, 0x0D07, 0x0E2A, 0x0D84, 0x0E79, 0x0E59, + 0x0F8C, 0x0CA6, 0x0EB8, 0x0EA5, 0x0CA8, 0x352F, 0x352E, 0x0D2C, 0x0B0D, 0x0F9C, + 0x0D57, 0x0B0E, 0x0FE5, 0x0B0C, 0x0F16, 0x0ED1, 0x0B0B, 0x0F47, 0x0E64, 0x3534, + 0x0E10, 0x0E90, 0x3A95, 0x3A82, 0x3A83, 0x3A81, 0x0D68, 0x3A85, 0x3A87, 0x3A9B, + 0x3AC5, 0x3AAE, 0x3A90, 0x3A86, 0x3A9C, 0x3A88, 0x3A9A, 0x3AA1, 0x3502, 0x3A94, + 0x3AC4, 0x0CA8, 0x0D57, 0x3A93, 0x34F9, 0x3A8C, 0x0F16, 0x34F7, 0x3A92, 0x3A91, + 0x3A98, 0x3A97, 0x3A96, 0x34FA, 0x3AB3, 0x0EBA, 0x3A84, 0x0DA4, 0x3AA6, 0x0D2C, + 0x3AB4, 0x2089, 0x3AB8, 0x3AB7, 0x00ED, 0x3ABA, 0x3ABC, 0x3511, 0x3ABE, 0x3AB0, + 0x3AAF, 0x0D2C, 0x3AB1, 0x3A9D, 0x3AB5, 0x3AB6, 0x0FE5, 0x0E46, 0x3A99, 0x3A9E, + 0x0F68, 0x0F47, 0x0E64, 0x0DBD, 0x0E10, 0x0E90, 0x3513, 0x3ABF, 0x0CE0, 0x0DE1, + 0x0D68, 0x0D07, 0x3AC0, 0x350C, 0x0E79, 0x350E, 0x1CBA, 0x3AAC, 0x1CA6, 0x3515, + 0x350F, 0x1CB9, 0x0E10, 0x1CB3, 0x0E90, 0x0D07, 0x0CE0, 0x0D68, 0x0DE1, 0x34FD, + 0x01A2, 0x01C9, 0x34F8, 0x00EF, 0x00EE, 0x3AC1, 0x34FC, 0x3A9F, 0x3AA0, 0x3521, + 0x3AAA, 0x3AA3, 0x1CB7, 0x3AA5, 0x3506, 0x3AA7, 0x1CB8, 0x3AA9, 0x0D80, 0x1CBC, + 0x1CBE, 0x3AA4, 0x3ABD, 0x3AAB, 0x1E4F, 0x0D2C, 0x0FBD, 0x1E4B, 0x0D57, 0x0DA4, + 0x0FE5, 0x0E46, 0x0F16, 0x3AA8, 0x0F68, 0x0F47, 0x0E64, 0x0DBD, 0x3AAD, 0x1E50, + 0x1E4A, 0x1E45, 0x1E48, 0x1E47, 0x1CBB, 0x1E4C, 0x1CBD, 0x0D2C, 0x1CBF, 0x1CC0, + 0x1CC1, 0x1CC2, 0x0E79, 0x1CAE, 0x1CB2, 0x0CA8, 0x0C9E, 0x0D07, 0x0DA4, 0x0FBD, + 0x0F9C, 0x0D57, 0x0FE5, 0x0CE0, 0x0E46, 0x0F16, 0x0F68, 0x2035, 0x0F47, 0x0EBA, + 0x0D68, 0x2084, 0x0D9E, 0x0E90, 0x2074, 0x0DBD, 0x1E49, 0x0E64, 0x2079, 0x0E59, + 0x1E4D, 0x1E4E, 0x1E53, 0x0E2A, 0x0D84, 0x1E52, 0x0E10, 0x1E54, 0x1F49, 0x1E77, + 0x1E7C, 0x1F4A, 0x1E86, 0x1E6D, 0x1E72, 0x1E81, 0x1E95, 0x1E68, 0x1E9F, 0x1EB3, + 0x0215, 0x1E8B, 0x1EA4, 0x1F4F, 0x1EBD, 0x1E90, 0x1EC7, 0x1EC2, 0x01A2, 0x01C9, + 0x01DF, 0x1EAE, 0x021F, 0x1EE0, 0x1E9A, 0x1EA9, 0x0198, 0x1EF4, 0x1F03, 0x1EFE, + 0x3560, 0x356A, 0x1F17, 0x357A, 0x355E, 0x3574, 0x3562, 0x3576, 0x3578, 0x357E, + 0x1F0D, 0x1F12, 0x3582, 0x3568, 0x353B, 0x36B9, 0x01F5, 0x3584, 0x1F47, 0x1F46, + 0x0209, 0x1F44, 0x1F45, 0x3543, 0x01A2, 0x1F50, 0x022A, 0x0234, 0x0F47, 0x0F68, + 0x3566, 0x1F4B, 0x35A9, 0x1F57, 0x0F68, 0x4593, 0x4592, 0x4598, 0x4599, 0x0DBD, + 0x1F56, 0x1F54, 0x35A8, 0x357D, 0x1F59, 0x1F55, 0x1F5B, 0x0EBA, 0x3585, 0x3643, + 0x0DE1, 0x0CE0, 0x1F58, 0x0D07, 0x1F5A, 0x0E2A, 0x0E79, 0x1F5D, 0x0D84, 0x2092, + 0x358B, 0x0E2A, 0x2091, 0x3651, 0x3650, 0x3653, 0x3652, 0x3655, 0x3654, 0x1F21, + 0x1F26, 0x3659, 0x3658, 0x365B, 0x365A, 0x365D, 0x365C, 0x3657, 0x3656, 0x01A2, + 0x0198, 0x0D68, 0x01C9, 0x0209, 0x01F5, 0x021F, 0x0215, 0x0E10, 0x0E2A, 0x1F4D, + 0x1F4E, 0x0DE1, 0x0E79, 0x0FE5, 0x0234, 0x2178, 0x2176, 0x0D2C, 0x217A, 0x022A, + 0x217E, 0x2184, 0x0ED1, 0x0CA8, 0x35AA, 0x218C, 0x0D57, 0x0F68, 0x0DBD, 0x0E64, + 0x0F9C, 0x219A, 0x0EBA, 0x1FDC, 0x1FC8, 0x0CA6, 0x1FD8, 0x0EA5, 0x0E2A, 0x1FE2, + 0x0E59, 0x2198, 0x1FDF, 0x0F8C, 0x2196, 0x0EB8, 0x219C, 0x0E59, 0x35A5, 0x21BC, + 0x01C9, 0x01DF, 0x01F5, 0x35AC, 0x21A4, 0x2177, 0x2175, 0x35AB, 0x2179, 0x217F, + 0x217D, 0x2183, 0x2181, 0x2189, 0x2185, 0x218B, 0x0DE1, 0x0D80, 0x2187, 0x218D, + 0x218F, 0x3535, 0x3580, 0x219B, 0x0E79, 0x2195, 0x21A3, 0x2191, 0x2193, 0x21A7, + 0x3586, 0x3587, 0x21A9, 0x21A5, 0x21AD, 0x21B3, 0x21B1, 0x21BB, 0x35A7, 0x21B5, + 0x3590, 0x35A6, 0x21AF, 0x21B9, 0x21B7, 0x1F81, 0x01A2, 0x1F7F, 0x1F80, 0x1F7E, + 0x358A, 0x1F84, 0x1F86, 0x3660, 0x358D, 0x0234, 0x0215, 0x3594, 0x021F, 0x367A, + 0x1F83, 0x366F, 0x366E, 0x3671, 0x1F82, 0x3673, 0x3672, 0x3675, 0x3674, 0x3677, + 0x3676, 0x3679, 0x3678, 0x367B, 0x1F89, 0x367D, 0x367C, 0x365F, 0x365E, 0x3665, + 0x3680, 0x367E, 0x367F, 0x3685, 0x3664, 0x3663, 0x3661, 0x1F88, 0x1F8A, 0x3682, + 0x3683, 0x3684, 0x1F87, 0x1F8F, 0x138D, 0x1358, 0x1359, 0x135A, 0x1349, 0x138E, + 0x138F, 0x1390, 0x35B2, 0x133B, 0x1344, 0x1348, 0x1357, 0x135E, 0x1345, 0x3697, + 0x3696, 0x3699, 0x3698, 0x369B, 0x369A, 0x369D, 0x369C, 0x369F, 0x369E, 0x36A1, + 0x36A0, 0x36A3, 0x36A2, 0x36A5, 0x36A4, 0x368B, 0x36A8, 0x3693, 0x3669, 0x368A, + 0x36A9, 0x3662, 0x368C, 0x368E, 0x368F, 0x3690, 0x3691, 0x3692, 0x36B2, 0x3694, + 0x3695, 0x36B7, 0x36B6, 0x138A, 0x36B8, 0x022D, 0x0222, 0x35AF, 0x35AE, 0x1389, + 0x0237, 0x358C, 0x35B0, 0x139D, 0x17F2, 0x180C, 0x13A0, 0x3589, 0x36B3, 0x36B4, + 0x36B5, 0x36AA, 0x36AB, 0x36AC, 0x1D2D, 0x3688, 0x368D, 0x36B0, 0x3687, 0x3686, + 0x36AF, 0x36AE, 0x36B1, 0x1D27, 0x3644, 0x1D2E, 0x1A1F, 0x3640, 0x1D33, 0x0198, + 0x1D34, 0x1D35, 0x364A, 0x3642, 0x1F8D, 0x3645, 0x1F8B, 0x1D38, 0x1F8E, 0x022A, + 0x01F5, 0x217C, 0x45D6, 0x1376, 0x19C5, 0x01DF, 0x019E, 0x2186, 0x1374, 0x01A2, + 0x01C9, 0x0209, 0x021F, 0x2192, 0x2194, 0x1342, 0x1A19, 0x135C, 0x01DF, 0x135D, + 0x133A, 0x0198, 0x01A2, 0x3648, 0x01F5, 0x1385, 0x0209, 0x218A, 0x135B, 0x364E, + 0x1339, 0x0215, 0x1FCE, 0x1FED, 0x1FD7, 0x1FFB, 0x1FD6, 0x1FDD, 0x1FE7, 0x3681, + 0x1FCB, 0x1FCA, 0x1FCD, 0x1FCC, 0x1FCF, 0x1FFA, 0x1FD1, 0x1FD0, 0x1FD3, 0x1FD2, + 0x1FD5, 0x1FD4, 0x1FD9, 0x43C1, 0x1FDB, 0x1FDA, 0x19E9, 0x43D4, 0x43D9, 0x43A1, + 0x1FDE, 0x1FE0, 0x43D3, 0x439B, 0x1FF7, 0x1FE4, 0x1FE8, 0x1FE6, 0x1FEA, 0x1FE5, + 0x1FEC, 0x1FE9, 0x217B, 0x21BA, 0x21B6, 0x1FEF, 0x1FF0, 0x1FF2, 0x1FEB, 0x1FF1, + 0x439F, 0x1FFC, 0x43A0, 0x43AD, 0x43C4, 0x44C8, 0x447E, 0x44C9, 0x43F2, 0x1FF9, + 0x447F, 0x43C3, 0x1FF8, 0x1360, 0x1FF6, 0x1361, 0x443E, 0x43C2, 0x1A70, 0x440D, + 0x43C5, 0x3670, 0x1A6F, 0x43C9, 0x1BCE, 0x1BC8, 0x1BAE, 0x1A6E, 0x43AC, 0x440E, + 0x1BB2, 0x37C6, 0x01A2, 0x01DF, 0x37C7, 0x37C5, 0x0215, 0x01F5, 0x01C9, 0x0209, + 0x0198, 0x37C9, 0x022A, 0x37CB, 0x37CA, 0x0234, 0x37CC, 0x021F, 0x439C, 0x439D, + 0x43F4, 0x43F3, 0x4462, 0x4405, 0x43C8, 0x37CD, 0x37CE, 0x37CF, 0x37D0, 0x37D1, + 0x37D2, 0x37D3, 0x4410, 0x4407, 0x4404, 0x43F8, 0x43EC, 0x4408, 0x43EE, 0x43DE, + 0x1BA4, 0x43F5, 0x37E8, 0x43EF, 0x43D0, 0x43F0, 0x43F9, 0x43CE, 0x43F1, 0x37F8, + 0x17E8, 0x439E, 0x43CF, 0x3801, 0x19DD, 0x3803, 0x19CB, 0x43B5, 0x37FF, 0x4411, + 0x43D5, 0x43E5, 0x17F5, 0x17F4, 0x3802, 0x381A, 0x3819, 0x17F8, 0x17FB, 0x381B, + 0x381C, 0x17F9, 0x17FA, 0x443F, 0x3820, 0x1519, 0x1807, 0x4440, 0x3824, 0x17FD, + 0x17FE, 0x17FF, 0x17EA, 0x0209, 0x17F6, 0x17F7, 0x17EE, 0x17EB, 0x17EC, 0x17ED, + 0x01A5, 0x3817, 0x3816, 0x17F3, 0x019E, 0x3815, 0x17F0, 0x17EF, 0x01A2, 0x0198, + 0x01DF, 0x01C9, 0x0209, 0x01F5, 0x021F, 0x0215, 0x0234, 0x022A, 0x1806, 0x17E9, + 0x1801, 0x0198, 0x1803, 0x17F1, 0x1D21, 0x0045, 0x1D23, 0x1D22, 0x1D24, 0x1D23, + 0x4441, 0x1D25, 0x1D28, 0x1D20, 0x1D2A, 0x1D29, 0x1D2B, 0x1D2B, 0x1D26, 0x1D2C, + 0x1D2F, 0x01CC, 0x1D31, 0x1D30, 0x4464, 0x4463, 0x0215, 0x43D2, 0x0234, 0x43DD, + 0x154F, 0x022A, 0x444A, 0x1D39, 0x154E, 0x1535, 0x1D3E, 0x1D3D, 0x1D40, 0x1D3F, + 0x1D42, 0x1D41, 0x022A, 0x1B1F, 0x43D7, 0x1808, 0x43E4, 0x45A8, 0x1300, 0x19D1, + 0x43DC, 0x3866, 0x3865, 0x43D8, 0x3867, 0x180D, 0x3869, 0x386C, 0x386B, 0x386E, + 0x386D, 0x3870, 0x386F, 0x3873, 0x386A, 0x3874, 0x3872, 0x444B, 0x1C5A, 0x1C4A, + 0x1C4D, 0x1C50, 0x1C4F, 0x1C4E, 0x1C51, 0x1C59, 0x1C53, 0x1C65, 0x1C58, 0x3871, + 0x1C57, 0x1C5C, 0x1C6B, 0x38A4, 0x1C5E, 0x1C5D, 0x1C60, 0x1C5F, 0x1C63, 0x1C64, + 0x3888, 0x1C61, 0x1C66, 0x1C67, 0x1C68, 0x1C69, 0x1C6A, 0x1C62, 0x1C6C, 0x3898, + 0x3895, 0x3896, 0x3897, 0x389C, 0x3899, 0x389A, 0x389B, 0x38A0, 0x019B, 0x389E, + 0x389F, 0x019C, 0x389D, 0x38A1, 0x38A3, 0x1C52, 0x1C6D, 0x1C6E, 0x1C6F, 0x1C70, + 0x20C5, 0x20C2, 0x20C7, 0x20C8, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x1C5B, 0x20C6, + 0x38C4, 0x38B6, 0x38B5, 0x38BC, 0x38B7, 0x38BA, 0x0218, 0x020C, 0x38BB, 0x01F8, + 0x38BD, 0x38BE, 0x38BF, 0x38B9, 0x38A2, 0x38C0, 0x01F5, 0x38D5, 0x38D6, 0x0198, + 0x01DF, 0x38DC, 0x01A2, 0x38DA, 0x38DB, 0x01C9, 0x20AB, 0x20AC, 0x0215, 0x0234, + 0x20B0, 0x0209, 0x38D9, 0x021F, 0x0198, 0x01A2, 0x01C9, 0x01DF, 0x01F5, 0x0209, + 0x01E2, 0x021F, 0x20C1, 0x0234, 0x20C3, 0x20C4, 0x20AD, 0x38D7, 0x0215, 0x38E6, + 0x38E5, 0x20AE, 0x38E7, 0x38EA, 0x38E9, 0x38EC, 0x38EB, 0x38DD, 0x38E4, 0x38F0, + 0x38DF, 0x38ED, 0x38EE, 0x38E3, 0x022A, 0x20AF, 0x1564, 0x1565, 0x155F, 0x155D, + 0x4573, 0x0209, 0x1558, 0x0234, 0x09CC, 0x155E, 0x1A9B, 0x09E3, 0x38E0, 0x38F4, + 0x38DE, 0x093B, 0x09EA, 0x38FF, 0x092A, 0x0A4C, 0x1449, 0x0A59, 0x09EA, 0x1445, + 0x2321, 0x1441, 0x0A05, 0x4516, 0x43E0, 0x2322, 0x451B, 0x390D, 0x390C, 0x1448, + 0x390E, 0x3911, 0x3910, 0x4543, 0x4544, 0x4545, 0x4542, 0x44A7, 0x44A6, 0x1A77, + 0x0209, 0x44C5, 0x44AD, 0x451E, 0x01F5, 0x451F, 0x45AA, 0x1AAD, 0x449E, 0x45BE, + 0x1440, 0x4595, 0x45C2, 0x145F, 0x1444, 0x1443, 0x1300, 0x1463, 0x1AA7, 0x45C0, + 0x43C0, 0x449F, 0x44A0, 0x44A1, 0x021F, 0x45A2, 0x01C9, 0x1BA7, 0x01C9, 0x1B2B, + 0x022A, 0x4497, 0x45C3, 0x1BA3, 0x2323, 0x45AC, 0x1442, 0x231C, 0x4594, 0x0215, + 0x231D, 0x143F, 0x1522, 0x44F0, 0x455E, 0x4557, 0x38E1, 0x440A, 0x38E2, 0x43E1, + 0x44D2, 0x1456, 0x01F5, 0x20BD, 0x38C8, 0x455F, 0x440B, 0x20B6, 0x20B7, 0x20B8, + 0x4406, 0x20BA, 0x20BB, 0x4401, 0x44F1, 0x12FC, 0x12FC, 0x12FC, 0x12FC, 0x12FC, + 0x440C, 0x231E, 0x12FD, 0x4584, 0x4585, 0x12FE, 0x4588, 0x44C3, 0x4589, 0x44C4, + 0x44C2, 0x1300, 0x45A0, 0x450A, 0x0297, 0x0298, 0x02B2, 0x0293, 0x0301, 0x0302, + 0x0347, 0x02D1, 0x0460, 0x0415, 0x042E, 0x1477, 0x0402, 0x063F, 0x0512, 0x0486, + 0x0513, 0x0520, 0x051C, 0x0521, 0x0533, 0x0516, 0x0528, 0x035E, 0x057F, 0x053E, + 0x05EA, 0x0584, 0x0640, 0x0651, 0x0527, 0x063D, 0x0689, 0x0720, 0x06EF, 0x06DC, + 0x1490, 0x066A, 0x07F5, 0x076A, 0x082B, 0x086C, 0x09A1, 0x148B, 0x1476, 0x0721, + 0x04AD, 0x1495, 0x1489, 0x0059, 0x148A, 0x148E, 0x148F, 0x4400, 0x231F, 0x1528, + 0x081C, 0x148D, 0x1492, 0x0234, 0x45C1, 0x236A, 0x0058, 0x14AB, 0x14E0, 0x1488, + 0x005A, 0x01F5, 0x14E4, 0x01A2, 0x0056, 0x01DF, 0x0198, 0x0054, 0x149D, 0x0055, + 0x0053, 0x1473, 0x1494, 0x391B, 0x391D, 0x3937, 0x391C, 0x391A, 0x393D, 0x391E, + 0x391F, 0x392F, 0x3922, 0x3931, 0x3921, 0x392B, 0x3920, 0x3933, 0x3923, 0x3928, + 0x392E, 0x3932, 0x3929, 0x3927, 0x05BE, 0x0303, 0x02B3, 0x0487, 0x0641, 0x0388, + 0x05D7, 0x0405, 0x0377, 0x053F, 0x0647, 0x0655, 0x394B, 0x394C, 0x058E, 0x0582, + 0x393E, 0x0543, 0x3939, 0x394E, 0x04AE, 0x394F, 0x3938, 0x05EF, 0x393A, 0x03A0, + 0x06DF, 0x0409, 0x0304, 0x394A, 0x039C, 0x0378, 0x046E, 0x3949, 0x3948, 0x0488, + 0x3930, 0x05CB, 0x394D, 0x3947, 0x3926, 0x066D, 0x3936, 0x00FE, 0x0309, 0x029F, + 0x0358, 0x034C, 0x0354, 0x035D, 0x0523, 0x0406, 0x0102, 0x0100, 0x3950, 0x3A0E, + 0x01DF, 0x0648, 0x06F2, 0x3A0C, 0x3A0D, 0x3A1F, 0x3A1E, 0x3A13, 0x3A11, 0x3A12, + 0x3A1D, 0x3A1C, 0x3A20, 0x3A16, 0x3A17, 0x3A21, 0x3A10, 0x01C9, 0x3A0F, 0x3A1B, + 0x39D6, 0x3A15, 0x3943, 0x01DF, 0x393C, 0x393B, 0x00F1, 0x393F, 0x3940, 0x3941, + 0x01C9, 0x3945, 0x3944, 0x3942, 0x3946, 0x39D4, 0x39D3, 0x39C3, 0x39C4, 0x39C1, + 0x39C2, 0x39D2, 0x39C8, 0x01A2, 0x39D1, 0x39C6, 0x39D5, 0x00FF, 0x39C7, 0x0101, + 0x39D7, 0x39D8, 0x45C4, 0x39DA, 0x39DB, 0x39DD, 0x14E6, 0x14E5, 0x39DF, 0x39E1, + 0x39E0, 0x39E3, 0x39E2, 0x1534, 0x14D0, 0x39E6, 0x14E3, 0x39E8, 0x1B0D, 0x148C, + 0x39EB, 0x39EC, 0x1B13, 0x1527, 0x39EE, 0x39F1, 0x39F0, 0x39F3, 0x39F2, 0x14E2, + 0x1B31, 0x1A89, 0x14A6, 0x14E1, 0x45A5, 0x147D, 0x1AA1, 0x45B7, 0x0209, 0x01A2, + 0x1460, 0x0057, 0x1A7D, 0x01F5, 0x01F5, 0x01C9, 0x01DF, 0x00F4, 0x0048, 0x14D1, + 0x45A3, 0x05A0, 0x05B5, 0x05A2, 0x0047, 0x059C, 0x05B2, 0x1B07, 0x45AD, 0x45A7, + 0x45AB, 0x45A4, 0x0661, 0x0657, 0x05E2, 0x39CB, 0x031D, 0x3A19, 0x0662, 0x0658, + 0x0364, 0x3A1A, 0x033D, 0x39CF, 0x0629, 0x3A14, 0x0328, 0x0344, 0x036F, 0x0343, + 0x39FA, 0x0209, 0x00F5, 0x39C9, 0x0639, 0x0259, 0x39CD, 0x39CE, 0x026C, 0x3A18, + 0x01A2, 0x031A, 0x00F6, 0x0273, 0x0241, 0x00F7, 0x0607, 0x39F8, 0x39F7, 0x0330, + 0x39F9, 0x39FC, 0x39FB, 0x39FE, 0x39FD, 0x0314, 0x39FF, 0x3A02, 0x3A01, 0x0325, + 0x3A03, 0x3A0A, 0x3A05, 0x3A09, 0x050B, 0x01F5, 0x047B, 0x3A08, 0x0209, 0x04EF, + 0x39D0, 0x01A2, 0x39CA, 0x39CC, 0x0505, 0x3A07, 0x00F0, 0x39C5, 0x3A0B, 0x04C5, + 0x0481, 0x047A, 0x0482, 0x04CB, 0x04A2, 0x0494, 0x04A4, 0x0496, 0x04A6, 0x0498, + 0x04A5, 0x0497, 0x062C, 0x0573, 0x04F6, 0x04CC, 0x05E4, 0x0615, 0x0637, 0x04E1, + 0x04DC, 0x05D4, 0x0638, 0x04DE, 0x0C30, 0x0C31, 0x060A, 0x0617, 0x04F5, 0x0616, + 0x0C36, 0x34DF, 0x34DD, 0x04DB, 0x0C42, 0x34E4, 0x34DE, 0x34E1, 0x34E2, 0x34E6, + 0x34E5, 0x34E8, 0x34E7, 0x0508, 0x34E9, 0x34E3, 0x34EB, 0x0C3F, 0x0C40, 0x0C41, + 0x0677, 0x0C43, 0x0681, 0x01A2, 0x00FB, 0x00FC, 0x067B, 0x0678, 0x01DF, 0x34EA, + 0x0C44, 0x0697, 0x34EC, 0x0685, 0x0696, 0x033E, 0x06D5, 0x0C2F, 0x0C34, 0x0C35, + 0x06CE, 0x0341, 0x06D8, 0x06B9, 0x0C3A, 0x0C33, 0x068F, 0x05C3, 0x0686, 0x0684, + 0x0254, 0x0242, 0x026F, 0x026D, 0x026E, 0x027F, 0x0283, 0x0258, 0x0257, 0x067D, + 0x0246, 0x0322, 0x0243, 0x068E, 0x0247, 0x06AD, 0x0274, 0x1533, 0x0272, 0x06CB, + 0x05CF, 0x1FA4, 0x1A83, 0x34ED, 0x34EE, 0x34EF, 0x0248, 0x0271, 0x0284, 0x0244, + 0x34F4, 0x0336, 0x04EC, 0x0333, 0x0315, 0x04C3, 0x1FA6, 0x04C2, 0x04ED, 0x1B25, + 0x43FF, 0x04EE, 0x1B99, 0x45A9, 0x04C4, 0x050A, 0x45A6, 0x1B97, 0x4359, 0x06D9, + 0x05C4, 0x4363, 0x4361, 0x4366, 0x03B0, 0x06CF, 0x067A, 0x06AA, 0x0266, 0x05A9, + 0x0672, 0x030E, 0x05BA, 0x145C, 0x0635, 0x0613, 0x1451, 0x1C85, 0x06BC, 0x06B0, + 0x06BB, 0x06AF, 0x06B8, 0x06AC, 0x045B, 0x0449, 0x1450, 0x06C4, 0x06C5, 0x435A, + 0x4358, 0x435E, 0x435C, 0x4364, 0x06A8, 0x4367, 0x4362, 0x4371, 0x4369, 0x436B, + 0x436E, 0x4360, 0x4374, 0x34E0, 0x4378, 0x06B5, 0x07AD, 0x07B5, 0x07B1, 0x34F1, + 0x34F2, 0x34F3, 0x0794, 0x34F5, 0x34F6, 0x07AC, 0x07B9, 0x0172, 0x4376, 0x437A, + 0x438E, 0x0168, 0x01C9, 0x0770, 0x459A, 0x459D, 0x077F, 0x0771, 0x0198, 0x01F5, + 0x016B, 0x077B, 0x0780, 0x0169, 0x0887, 0x077E, 0x077D, 0x0151, 0x0158, 0x079E, + 0x014E, 0x014F, 0x0150, 0x0153, 0x0152, 0x0796, 0x0154, 0x0157, 0x0156, 0x015A, + 0x0798, 0x079B, 0x0155, 0x016C, 0x016D, 0x016E, 0x015E, 0x015D, 0x015C, 0x0163, + 0x0174, 0x0166, 0x0161, 0x0164, 0x0165, 0x0160, 0x016A, 0x0162, 0x0159, 0x079C, + 0x0167, 0x19B9, 0x0809, 0x0806, 0x1BA8, 0x0807, 0x0804, 0x015B, 0x18C5, 0x19BF, + 0x080B, 0x150C, 0x152E, 0x0805, 0x080F, 0x150B, 0x0843, 0x083F, 0x0845, 0x0841, + 0x0844, 0x0840, 0x0846, 0x0842, 0x0852, 0x0811, 0x0854, 0x0813, 0x0853, 0x0808, + 0x0855, 0x0812, 0x1843, 0x1847, 0x0888, 0x1848, 0x0871, 0x1FAE, 0x1849, 0x0879, + 0x080E, 0x1FA7, 0x0810, 0x1851, 0x086E, 0x0876, 0x184F, 0x1855, 0x0877, 0x0873, + 0x0776, 0x0777, 0x07D0, 0x0740, 0x07A5, 0x07A3, 0x1A25, 0x088F, 0x0847, 0x0890, + 0x080A, 0x0880, 0x087E, 0x1863, 0x1FA3, 0x1865, 0x1864, 0x1862, 0x2338, 0x18DD, + 0x18E3, 0x233A, 0x07B3, 0x18BF, 0x18CB, 0x1FBA, 0x18E9, 0x1FB4, 0x1FB3, 0x07B2, + 0x07A2, 0x079F, 0x233B, 0x079A, 0x0799, 0x0795, 0x0797, 0x079D, 0x07BB, 0x1BD4, + 0x07B8, 0x07B0, 0x07B6, 0x1BD3, 0x07BA, 0x07A1, 0x1955, 0x195B, 0x1961, 0x1BBD, + 0x196D, 0x1A2B, 0x1979, 0x194F, 0x0215, 0x145B, 0x198B, 0x1991, 0x197F, 0x1985, + 0x1973, 0x19A9, 0x1A07, 0x2334, 0x2335, 0x2336, 0x2337, 0x2330, 0x2331, 0x2332, + 0x2333, 0x232C, 0x232D, 0x19FB, 0x232E, 0x199D, 0x19A3, 0x1A01, 0x1BCF, 0x232F, + 0x07A9, 0x07A6, 0x2308, 0x07A4, 0x07A8, 0x07A7, 0x0781, 0x2309, 0x07BC, 0x07BD, + 0x230A, 0x07BE, 0x230B, 0x2304, 0x01F5, 0x2305, 0x2306, 0x2307, 0x0209, 0x0215, + 0x021F, 0x1466, 0x2300, 0x0234, 0x2301, 0x2302, 0x022A, 0x2303, 0x22FC, 0x22FD, + 0x22FE, 0x22FF, 0x2318, 0x22EA, 0x22EB, 0x22E4, 0x234B, 0x234C, 0x2344, 0x2340, + 0x234E, 0x115F, 0x1171, 0x1172, 0x116B, 0x116C, 0x116D, 0x116E, 0x0884, 0x0881, + 0x1166, 0x087F, 0x0883, 0x0882, 0x0814, 0x0815, 0x0897, 0x0898, 0x1167, 0x1168, + 0x1FB8, 0x1169, 0x1FB7, 0x1162, 0x1FBB, 0x1163, 0x1164, 0x1165, 0x113F, 0x1140, + 0x2A10, 0x2A11, 0x2A20, 0x2A21, 0x2A23, 0x2A19, 0x021F, 0x3A5E, 0x3A5D, 0x3A60, + 0x3A5F, 0x3A62, 0x3A61, 0x3A64, 0x3A63, 0x10F3, 0x10F4, 0x3A67, 0x10ED, 0x3A69, + 0x3A68, 0x3A6B, 0x3A6A, 0x3A6D, 0x10EE, 0x3A6F, 0x01C9, 0x01DF, 0x0198, 0x01A2, + 0x3A72, 0x3A75, 0x10EF, 0x10E6, 0x3A76, 0x3A79, 0x3A78, 0x10E7, 0x3A7A, 0x3A7D, + 0x3A7C, 0x3A7F, 0x3A7E, 0x11DB, 0x3A80, 0x0FE2, 0x0005, 0x0FFF, 0x0F3A, 0x01A2, + 0x0EE9, 0x0103, 0x0209, 0x0105, 0x0104, 0x0EC9, 0x0ECA, 0x0ECB, 0x0EE5, 0x0EA1, + 0x0EA2, 0x0EA3, 0x0D01, 0x0D02, 0x0D03, 0x0D17, 0x0EDB, 0x0F23, 0x0F73, 0x0DF0, + 0x0CED, 0x399B, 0x399C, 0x39A7, 0x0D09, 0x399F, 0x39A0, 0x39A1, 0x39A2, 0x39A3, + 0x39A4, 0x39A5, 0x39A6, 0x0CAE, 0x39A8, 0x39A9, 0x39AA, 0x398D, 0x398C, 0x399E, + 0x399D, 0x398B, 0x3990, 0x0F81, 0x3992, 0x0F82, 0x0F30, 0x398F, 0x3995, 0x3991, + 0x0F33, 0x2104, 0x2106, 0x2108, 0x20FA, 0x20FC, 0x398E, 0x20FE, 0x2100, 0x20F2, + 0x20F4, 0x20F6, 0x20F8, 0x20EA, 0x20EC, 0x20EE, 0x20F0, 0x126A, 0x3994, 0x0CE6, + 0x0E36, 0x0DE3, 0x0DE4, 0x0DE6, 0x0DF9, 0x0DF8, 0x0DD3, 0x0E1B, 0x0E38, 0x0DF2, + 0x0DF4, 0x0DF7, 0x0D6F, 0x0E1D, 0x0E1E, 0x0E37, 0x39AE, 0x0CA0, 0x39BE, 0x1DD8, + 0x0DED, 0x0DEE, 0x0E4D, 0x0E5D, 0x0DCC, 0x0DEC, 0x0DC8, 0x0DEA, 0x0E01, 0x0D66, + 0x0D3E, 0x39BB, 0x39BC, 0x39BD, 0x3A34, 0x39BF, 0x39C0, 0x3A32, 0x3A33, 0x3A36, + 0x01A2, 0x01F5, 0x0109, 0x3A37, 0x3996, 0x0D3F, 0x3993, 0x0D74, 0x3998, 0x3999, + 0x0D61, 0x0D38, 0x0D39, 0x0DFC, 0x0DFD, 0x1DD7, 0x1D82, 0x1D90, 0x1DE3, 0x1DE4, + 0x1DC9, 0x1DCA, 0x399A, 0x1DE1, 0x1DE2, 0x1DE6, 0x0E24, 0x0CA3, 0x1DCD, 0x0E67, + 0x0E16, 0x0DD2, 0x0F79, 0x0F57, 0x0E9A, 0x3997, 0x0CB3, 0x1D9F, 0x1DA2, 0x1DA5, + 0x1D8F, 0x3A4E, 0x1D96, 0x1D9A, 0x3A4D, 0x1D9B, 0x1D81, 0x1D83, 0x1D86, 0x1D8A, + 0x1D76, 0x3A4C, 0x1D78, 0x1D7A, 0x1D7E, 0x3A4B, 0x1DC6, 0x3A5C, 0x3A5B, 0x3A4F, + 0x3A50, 0x3A51, 0x3A52, 0x3A53, 0x3A54, 0x3A55, 0x3A56, 0x3A59, 0x3A58, 0x0F7B, + 0x3A5A, 0x0F4F, 0x01F5, 0x0F19, 0x0FEB, 0x0CB4, 0x010F, 0x0CF3, 0x0F6C, 0x01A2, + 0x01DF, 0x0110, 0x01C9, 0x0F78, 0x3A57, 0x0F80, 0x010E, 0x0F6E, 0x0B28, 0x0B3D, + 0x0B44, 0x02D0, 0x0B2C, 0x46F1, 0x0357, 0x47F1, 0x47F6, 0x4810, 0x03BD, 0x0389, + 0x03BD, 0x03BD, 0x03AD, 0x03B2, 0x47C5, 0x47C7, 0x47CA, 0x47E4, 0x47A5, 0x47A8, + 0x47AD, 0x479A, 0x479E, 0x479F, 0x48A0, 0x48AD, 0x486A, 0x0578, 0x48CA, 0x489E, + 0x2B0B, 0x2B0C, 0x2B2A, 0x2B04, 0x2B06, 0x2B08, 0x2B09, 0x2AFF, 0x2B00, 0x2B01, + 0x2B02, 0x2AFB, 0x2AFC, 0x02AE, 0x2AFD, 0x2AFE, 0x0372, 0x0346, 0x0485, 0x037C, + 0x0BE5, 0x04E6, 0x0BEE, 0x0BEB, 0x2ACE, 0x0BF1, 0x2AD0, 0x2AD2, 0x0767, 0x2AD4, + 0x081B, 0x0769, 0x2AC8, 0x2AC9, 0x2ACB, 0x2ACC, 0x2AC3, 0x2AC4, 0x032A, 0x02EF, + 0x2AC5, 0x2AC6, 0x2ABA, 0x03E2, 0x037B, 0x2ABC, 0x2ABF, 0x2AC1, 0x01C8, 0x2AE4, + 0x01C2, 0x01C0, 0x01C4, 0x01DD, 0x2A94, 0x2A97, 0x2A9A, 0x0208, 0x2A85, 0x2A8E, + 0x0214, 0x01F4, 0x01BF, 0x0229, 0x03DD, 0x2A79, 0x03F9, 0x03F7, 0x2BDE, 0x03F6, + 0x2BD5, 0x2B97, 0x0BF5, 0x0C0C, 0x0C0F, 0x0BFF, 0x0C02, 0x0C0A, 0x0C06, 0x0458, + 0x0BF4, 0x0BF8, 0x0BFC, 0x0BE4, 0x0BE9, 0x0BED, 0x0BF0, 0x0369, 0x05AA, 0x05AB, + 0x0367, 0x036A, 0x036B, 0x0447, 0x0368, 0x0C01, 0x0C04, 0x19B1, 0x02DB, 0x0BB8, + 0x0069, 0x02DA, 0x0BCF, 0x0068, 0x01A1, 0x0215, 0x19AE, 0x19AF, 0x006C, 0x19B0, + 0x0BBA, 0x006A, 0x0C90, 0x0C83, 0x0C91, 0x0FDE, 0x0C8C, 0x0C85, 0x19AA, 0x19AB, + 0x19AC, 0x18D7, 0x0FCB, 0x1895, 0x189B, 0x18A1, 0x1D9E, 0x1D7C, 0x1D85, 0x1D88, + 0x1D8B, 0x1D89, 0x1D95, 0x1DC5, 0x101C, 0x1DEA, 0x1DEB, 0x0DA9, 0x0DA8, 0x1AD1, + 0x0D89, 0x0DB2, 0x0DB1, 0x0D90, 0x0F0B, 0x0F0C, 0x0F08, 0x0EFE, 0x01F5, 0x0209, + 0x021F, 0x0198, 0x01A2, 0x1FB9, 0x1FB5, 0x1FB6, 0x19D7, 0x1A4F, 0x1A43, 0x1A49, + 0x1A31, 0x1A37, 0x1AC5, 0x1A3D, 0x1A71, 0x1ABF, 0x1F9F, 0x1FA0, 0x1ACB, 0x1FA1, + 0x1FA2, 0x1F9B, 0x1F9C, 0x1F9E, 0x1F99, 0x1F93, 0x1F94, 0x1F96, 0x1FB0, 0x1FB2, + 0x1FAB, 0x1FAD, 0x1FA8, 0x1FA5, 0x1A0D, 0x1A13, 0x19EF, 0x19F5, 0x150D, 0x1507, + 0x1508, 0x150A, 0x1503, 0x1504, 0x1FAA, 0x1BC7, 0x1BA5, 0x1BCA, 0x1BCB, 0x1BCC, + 0x1BCD, 0x1BC4, 0x1BC5, 0x1BC6, 0x1BC9, 0x45D7, 0x45D8, 0x45D2, 0x45D3, 0x45D4, + 0x45D5, 0x1BB0, 0x1BB1, 0x1BB3, 0x1BA0, 0x1BAD, 0x1BAF, 0x1BA9, 0x1BAA, 0x1BAB, + 0x1BAC, 0x459B, 0x459C, 0x4596, 0x4597, 0x1B19, 0x1AEF, 0x1AF5, 0x1FA9, 0x1AFB, + 0x1B01, 0x1AD7, 0x1FB1, 0x1ADD, 0x1AE3, 0x1AE9, 0x02A2, 0x089B, 0x06FF, 0x0700, + 0x0524, 0x0701, 0x20E1, 0x20E3, 0x20E5, 0x20E7, 0x20D9, 0x20DB, 0x20DD, 0x20DF, + 0x20D1, 0x20D3, 0x20D5, 0x20D7, 0x20C9, 0x20CB, 0x20CD, 0x20CF, 0x0594, 0x05C7, + 0x063E, 0x0646, 0x0591, 0x058C, 0x0592, 0x0593, 0x051B, 0x0579, 0x057C, 0x0590, + 0x0519, 0x0517, 0x0518, 0x051A, 0x06A0, 0x06A1, 0x06C6, 0x06A4, 0x06A5, 0x069E, + 0x4792, 0x47F5, 0x47B1, 0x47E9, 0x470F, 0x4845, 0x46CD, 0x4609, 0x4608, 0x47A4, + 0x47C1, 0x47C6, 0x4869, 0x45E8, 0x46F8, 0x472C, 0x4760, 0x4839, 0x1B9F, 0x46CC, + 0x1505, 0x1509, 0x47EF, 0x482C, 0x48AF, 0x4687, 0x4742, 0x478E, 0x47E3, 0x45F2, + 0x4899, 0x4875, 0x488F, 0x4893, 0x4718, 0x1C8D, 0x1C86, 0x1C87, 0x1C88, 0x1459, + 0x145A, 0x1457, 0x1458, 0x1452, 0x1453, 0x1454, 0x1BA2, 0x1455, 0x144E, 0x144F, + 0x1467, 0x0043, 0x0044, 0x151F, 0x1520, 0x1521, 0x145E, 0x143B, 0x151B, 0x1436, + 0x1531, 0x440F, 0x4402, 0x4403, 0x43EA, 0x43EB, 0x43ED, 0x43E6, 0x43E7, 0x43E8, + 0x43E9, 0x43E2, 0x43E3, 0x43BE, 0x43BF, 0x439A, 0x4482, 0x4483, 0x1506, 0x4458, + 0x4459, 0x4452, 0x4453, 0x4454, 0x4455, 0x446E, 0x446F, 0x446B, 0x4468, 0x4469, + 0x4465, 0x443A, 0x443B, 0x443C, 0x443D, 0x4436, 0x4437, 0x4438, 0x4439, 0x4432, + 0x1FAF, 0x4433, 0x4434, 0x4435, 0x444E, 0x444F, 0x1FAC, 0x4503, 0x44D8, 0x44D9, + 0x44D3, 0x44D4, 0x44D5, 0x44EE, 0x44EF, 0x44EA, 0x44EB, 0x44EC, 0x44ED, 0x44E6, + 0x44E7, 0x44E8, 0x44E9, 0x44E2, 0x44E3, 0x44BE, 0x44BF, 0x449A, 0x449B, 0x44AC, + 0x4582, 0x4583, 0x4560, 0x4561, 0x455A, 0x455B, 0x455C, 0x455D, 0x4556, 0x4538, + 0x4539, 0x4532, 0x4533, 0x451A, 0x451C, 0x451D, 0x4518, 0x4519, 0x4512, 0x2608, + 0x2630, 0x25BF, 0x25D5, 0x2701, 0x01F5, 0x0209, 0x0198, 0x01A2, 0x13A8, 0x13AA, + 0x26E9, 0x26EA, 0x26E7, 0x26E3, 0x26E4, 0x26DD, 0x26DE, 0x26DF, 0x26E0, 0x26F9, + 0x26FA, 0x26FB, 0x26FC, 0x26F5, 0x26F6, 0x26F7, 0x26F8, 0x26F1, 0x26F2, 0x26ED, + 0x26EF, 0x26F0, 0x26C9, 0x26CA, 0x26CB, 0x1F95, 0x26CC, 0x26C5, 0x26C6, 0x26C7, + 0x26C8, 0x26C1, 0x26C2, 0x26C0, 0x26D3, 0x26CD, 0x26CE, 0x09ED, 0x09EC, 0x0A28, + 0x09F2, 0x0A3B, 0x14E7, 0x0940, 0x13A6, 0x13A7, 0x13A1, 0x09CF, 0x09CC, 0x0A18, + 0x0A17, 0x0702, 0x06F8, 0x03A2, 0x03A1, 0x02E9, 0x0371, 0x04B9, 0x0596, 0x0597, + 0x05F6, 0x030D, 0x0472, 0x048E, 0x0526, 0x0525, 0x050F, 0x04E5, 0x1F9A, 0x0462, + 0x0461, 0x0438, 0x045F, 0x045E, 0x0435, 0x0434, 0x0437, 0x0436, 0x0599, 0x0598, + 0x066C, 0x066B, 0x0558, 0x0557, 0x057E, 0x057D, 0x054A, 0x0549, 0x0556, 0x0555, + 0x0542, 0x0541, 0x0548, 0x0547, 0x070D, 0x070C, 0x070F, 0x070E, 0x05E8, 0x05DC, + 0x070A, 0x0723, 0x0722, 0x03C9, 0x03C8, 0x13ED, 0x13EE, 0x0265, 0x02DC, 0x028F, + 0x0264, 0x028B, 0x0260, 0x028D, 0x028E, 0x0263, 0x0373, 0x05BD, 0x13F2, 0x13F1, + 0x13F7, 0x13F8, 0x13EF, 0x13F4, 0x13F0, 0x13F3, 0x13DD, 0x13DE, 0x13DA, 0x13DB, + 0x13DC, 0x13D7, 0x13D8, 0x13D9, 0x13E3, 0x13F6, 0x13E7, 0x13E8, 0x13E5, 0x13E6, + 0x13E2, 0x13E4, 0x13DF, 0x13E0, 0x13E1, 0x1049, 0x104A, 0x048C, 0x1047, 0x1048, + 0x1043, 0x1044, 0x0401, 0x1058, 0x1059, 0x105A, 0x105B, 0x1054, 0x1055, 0x1056, + 0x1057, 0x1050, 0x1F97, 0x1F9D, 0x1051, 0x1052, 0x1F98, 0x1053, 0x104C, 0x104D, + 0x104E, 0x104F, 0x1064, 0x0397, 0x046C, 0x1061, 0x0576, 0x0568, 0x0393, 0x0387, + 0x042C, 0x0423, 0x02BC, 0x02BB, 0x0530, 0x052F, 0x043B, 0x05F8, 0x0419, 0x06A3, + 0x071C, 0x064B, 0x0470, 0x071E, 0x071D, 0x05BB, 0x05A8, 0x02B5, 0x02B4, 0x04B4, + 0x04B3, 0x02D5, 0x02D4, 0x332E, 0x332F, 0x332A, 0x332B, 0x3328, 0x3329, 0x3322, + 0x3323, 0x3324, 0x3325, 0x333E, 0x333F, 0x3340, 0x3341, 0x333A, 0x333B, 0x333C, + 0x333D, 0x3336, 0x3337, 0x3338, 0x3339, 0x3332, 0x3333, 0x3334, 0x3335, 0x330E, + 0x330F, 0x3310, 0x3311, 0x330A, 0x330B, 0x330C, 0x330D, 0x3306, 0x3307, 0x3308, + 0x3309, 0x3302, 0x3303, 0x3304, 0x3305, 0x331E, 0x331F, 0x3320, 0x3321, 0x331A, + 0x331B, 0x331C, 0x331D, 0x3316, 0x3317, 0x3318, 0x3319, 0x3312, 0x3313, 0x3314, + 0x3315, 0x32EE, 0x32EF, 0x32F0, 0x32F1, 0x32EA, 0x32EB, 0x32EC, 0x32ED, 0x32E6, + 0x32E7, 0x32F2, 0x32F3, 0x32D1, 0x32C8, 0x32C9, 0x32C2, 0x32C3, 0x32C4, 0x32C5, + 0x32DE, 0x32DF, 0x32E0, 0x32E1, 0x32DA, 0x32DB, 0x32DC, 0x32DD, 0x32D6, 0x32D7, + 0x32D8, 0x32D9, 0x32D2, 0x32D3, 0x32D4, 0x32D5, 0x336C, 0x336A, 0x336D, 0x336E, + 0x3367, 0x3368, 0x336B, 0x3369, 0x3363, 0x3364, 0x01F5, 0x0209, 0x0198, 0x01A2, + 0x12BA, 0x12BC, 0x3373, 0x3374, 0x12EE, 0x12CB, 0x12B1, 0x12B2, 0x12B3, 0x12B4, + 0x12AC, 0x12B0, 0x335B, 0x335C, 0x335D, 0x335E, 0x3357, 0x3358, 0x3359, 0x335A, + 0x3353, 0x3354, 0x12CA, 0x12D1, 0x12AA, 0x12E8, 0x12EA, 0x12EB, 0x12EC, 0x12E3, + 0x12E4, 0x12E5, 0x12E6, 0x12DF, 0x12E0, 0x12E1, 0x12E2, 0x12D7, 0x12D9, 0x12DC, + 0x12DE, 0x12F9, 0x12F7, 0x12F8, 0x334E, 0x12F3, 0x12F4, 0x12B8, 0x12B9, 0x12AD, + 0x12AE, 0x12AF, 0x12B5, 0x12D0, 0x12D4, 0x12D5, 0x12D6, 0x12CC, 0x12CD, 0x2628, + 0x2629, 0x261E, 0x261F, 0x2621, 0x261A, 0x261B, 0x25EF, 0x25F0, 0x25E6, 0x25E7, + 0x25E8, 0x25E9, 0x25E3, 0x25E4, 0x25E5, 0x2603, 0x2604, 0x2605, 0x2606, 0x25FC, + 0x25FF, 0x2600, 0x2602, 0x01B2, 0x25F8, 0x25F9, 0x25F3, 0x020F, 0x0230, 0x25F5, + 0x01B3, 0x023A, 0x01B5, 0x01B4, 0x01B7, 0x01B6, 0x01B9, 0x01B8, 0x25F7, 0x01BA, + 0x25CD, 0x25CE, 0x0024, 0x0019, 0x0027, 0x0026, 0x0029, 0x0028, 0x002B, 0x002A, + 0x001A, 0x25CF, 0x001C, 0x001B, 0x25D0, 0x25C9, 0x25CA, 0x25CB, 0x25CC, 0x25C5, + 0x25C6, 0x25C4, 0x25D8, 0x25D1, 0x25D2, 0x25AB, 0x25AD, 0x25AE, 0x25AF, 0x25AA, + 0x25A4, 0x25A6, 0x259F, 0x25BE, 0x25BB, 0x25B4, 0x25B5, 0x269C, 0x2695, 0x2697, + 0x2698, 0x26AD, 0x26AE, 0x2677, 0x2673, 0x2674, 0x266D, 0x266E, 0x268E, 0x268B, + 0x2686, 0x2687, 0x267E, 0x267F, 0x2682, 0x2683, 0x2658, 0x2659, 0x265A, 0x265B, + 0x2654, 0x2655, 0x2656, 0x2657, 0x2650, 0x2651, 0x2631, 0x2632, 0x262A, 0x262B, + 0x262C, 0x262D, 0x2648, 0x2649, 0x264A, 0x264B, 0x2644, 0x2645, 0x2646, 0x2647, + 0x2640, 0x2641, 0x2642, 0x2643, 0x263C, 0x263D, 0x263E, 0x263F, 0x312E, 0x312F, + 0x3130, 0x3131, 0x312A, 0x312B, 0x312C, 0x312D, 0x3126, 0x3127, 0x3128, 0x3129, + 0x3124, 0x3125, 0x313E, 0x313F, 0x3140, 0x3141, 0x313A, 0x313B, 0x313C, 0x313D, + 0x3136, 0x3137, 0x3139, 0x3132, 0x3118, 0x3119, 0x3112, 0x3113, 0x3114, 0x3115, + 0x30EE, 0x30EF, 0x30F0, 0x01B5, 0x30EA, 0x30EB, 0x3188, 0x01B9, 0x3184, 0x3185, + 0x01B2, 0x01D1, 0x01E5, 0x01D0, 0x020F, 0x01FB, 0x0225, 0x021B, 0x023A, 0x319E, + 0x019E, 0x01B3, 0x319F, 0x31A0, 0x31A1, 0x319A, 0x319B, 0x319C, 0x319D, 0x3196, + 0x3197, 0x3178, 0x3179, 0x3172, 0x3173, 0x3174, 0x3175, 0x314E, 0x314F, 0x3150, + 0x3151, 0x314A, 0x314B, 0x314C, 0x314D, 0x3146, 0x3147, 0x3148, 0x3149, 0x3142, + 0x3143, 0x3144, 0x3145, 0x315E, 0x315F, 0x3160, 0x3161, 0x315A, 0x315B, 0x315C, + 0x315D, 0x3156, 0x45BA, 0x3157, 0x322D, 0x3228, 0x3229, 0x3222, 0x3223, 0x323F, + 0x3238, 0x3239, 0x3232, 0x3233, 0x3234, 0x3235, 0x320E, 0x320F, 0x3210, 0x3211, + 0x320A, 0x320B, 0x320C, 0x320D, 0x3206, 0x3207, 0x31E8, 0x31E9, 0x31E2, 0x31E3, + 0x31E4, 0x31E5, 0x31FE, 0x31FF, 0x31FA, 0x45BB, 0x31FB, 0x31F8, 0x31F9, 0x31F2, + 0x31F3, 0x31F4, 0x31F5, 0x31CE, 0x31CF, 0x180E, 0x31D0, 0x31D1, 0x180F, 0x1812, + 0x1811, 0x31CA, 0x1813, 0x1816, 0x1815, 0x1818, 0x1817, 0x31CB, 0x31CC, 0x31C6, + 0x31C7, 0x2EC5, 0x2EC6, 0x2EE0, 0x2EE1, 0x2EDA, 0x2EDB, 0x2ED7, 0x2FBC, 0x2F98, + 0x2F99, 0x2F92, 0x2F93, 0x2F94, 0x2F95, 0x2F6E, 0x2F6F, 0x2F6B, 0x2F4C, 0x3028, + 0x3029, 0x3022, 0x3023, 0x303F, 0x3038, 0x3039, 0x3032, 0x3033, 0x3034, 0x3035, + 0x300E, 0x183C, 0x300F, 0x3010, 0x3011, 0x300A, 0x300B, 0x3007, 0x3008, 0x3009, + 0x3002, 0x3003, 0x3004, 0x3005, 0x301E, 0x301F, 0x3020, 0x3021, 0x301A, 0x301B, + 0x301C, 0x301D, 0x3016, 0x3017, 0x2FE8, 0x2FE9, 0x2FE2, 0x2FE3, 0x2FE4, 0x2FE5, + 0x2FFE, 0x2FFF, 0x3000, 0x3001, 0x2FFA, 0x2FFB, 0x2FFC, 0x2FFD, 0x2FF6, 0x2FF7, + 0x2FF8, 0x2FF9, 0x2FF2, 0x2FF3, 0x2FF4, 0x2FF5, 0x2FCE, 0x2FCF, 0x2FD0, 0x2FD1, + 0x2FCA, 0x2FCB, 0x2FCC, 0x2FCD, 0x2FC6, 0x2FC7, 0x2FC8, 0x2FC9, 0x2FC2, 0x2FC3, + 0x2FC4, 0x2FC5, 0x2FDE, 0x2FDF, 0x2FD8, 0x2FD9, 0x2FD2, 0x2FD3, 0x2FD4, 0x2FD5, + 0x30AE, 0x30AF, 0x30B0, 0x30B1, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30A6, 0x30A7, + 0x05E3, 0x05D3, 0x062E, 0x060C, 0x062F, 0x060D, 0x0570, 0x0562, 0x0571, 0x0563, + 0x072D, 0x072E, 0x064C, 0x064D, 0x05D9, 0x036C, 0x044A, 0x044B, 0x02EE, 0x02ED, + 0x05DA, 0x05DB, 0x0559, 0x0724, 0x0725, 0x02EB, 0x0674, 0x068C, 0x0477, 0x06BF, + 0x05F3, 0x0644, 0x0653, 0x066E, 0x041B, 0x05CA, 0x05CC, 0x05F7, 0x057A, 0x0595, + 0x05C0, 0x05C5, 0x03BE, 0x0418, 0x043A, 0x045D, 0x072C, 0x02AF, 0x0361, 0x039F, + 0x0716, 0x071F, 0x0726, 0x072B, 0x06E3, 0x06E4, 0x06EB, 0x06F4, 0x0834, 0x0838, + 0x07E9, 0x0836, 0x0789, 0x0788, 0x0791, 0x0790, 0x089F, 0x089E, 0x067F, 0x0694, + 0x06B2, 0x06D2, 0x05AC, 0x05DD, 0x061A, 0x065F, 0x04E6, 0x0538, 0x0551, 0x056A, + 0x0424, 0x044C, 0x047E, 0x049C, 0x0485, 0x04AB, 0x0510, 0x053D, 0x03FB, 0x0412, + 0x042D, 0x045C, 0x0346, 0x0372, 0x0395, 0x03BD, 0x0291, 0x02AE, 0x06BE, 0x05AC, + 0x045C, 0x07C5, 0x07E7, 0x07F0, 0x076E, 0x0783, 0x078F, 0x0827, 0x0819, 0x077A, + 0x0779, 0x02BD, 0x0749, 0x0763, 0x0779, 0x07C2, 0x0869, 0x05F9, 0x0268, 0x06B2, + 0x06D2, 0x085E, 0x0863, 0x07C5, 0x07F4, 0x07FA, 0x02C6, 0x02EF, 0x032A, 0x036D, + 0x06BE, 0x1DEE, 0x1DED, 0x1DF0, 0x1DEF, 0x1DF2, 0x1DF1, 0x1DF4, 0x1DF3, 0x1DF6, + 0x1DF5, 0x1DF8, 0x1DF7, 0x06DB, 0x0267, 0x02A8, 0x063C, 0x0669, 0x0688, 0x069C, + 0x0554, 0x0578, 0x05BC, 0x05E9, 0x05AC, 0x05DD, 0x04E6, 0x0538, 0x03E2, 0x1E0A, + 0x1E09, 0x1E0C, 0x1E0B, 0x040E, 0x0867, 0x086B, 0x089A, 0x0832, 0x083D, 0x085E, + 0x0863, 0x0816, 0x081B, 0x082A, 0x07C5, 0x07F4, 0x07FA, 0x07FE, 0x0802, 0x07FC, + 0x0800, 0x01A2, 0x0198, 0x01DF, 0x01C9, 0x0209, 0x01F5, 0x021F, 0x0215, 0x0234, + 0x022A, 0x080C, 0x0819, 0x07D8, 0x07ED, 0x07F2, 0x07F8, 0x0779, 0x078D, 0x07AA, + 0x07C2, 0x0749, 0x0763, 0x0310, 0x0819, 0x0867, 0x086B, 0x1596, 0x1595, 0x0827, + 0x1597, 0x159A, 0x1599, 0x159C, 0x159B, 0x159E, 0x159D, 0x15A0, 0x159F, 0x15A2, + 0x15A1, 0x15A4, 0x15A3, 0x082F, 0x082F, 0x083B, 0x0800, 0x080C, 0x0819, 0x07D8, + 0x07ED, 0x07F2, 0x07F8, 0x0779, 0x078D, 0x0765, 0x0769, 0x0861, 0x0827, 0x0885, + 0x0779, 0x07C2, 0x2A2D, 0x2A2F, 0x0865, 0x2A33, 0x0869, 0x019D, 0x01B1, 0x01CF, + 0x01E4, 0x021A, 0x0224, 0x022F, 0x0239, 0x01CF, 0x01E4, 0x01FA, 0x020E, 0x15BD, + 0x15BC, 0x15BF, 0x15BE, 0x15C1, 0x15C0, 0x15C3, 0x15C2, 0x15C5, 0x15C4, 0x15C7, + 0x15C6, 0x022F, 0x0239, 0x019D, 0x01B1, 0x021A, 0x0224, 0x022F, 0x0239, 0x01CF, + 0x01E4, 0x01FA, 0x020E, 0x022F, 0x0239, 0x019D, 0x01B1, 0x01FA, 0x020E, 0x15DB, + 0x0621, 0x05FF, 0x06D6, 0x04BA, 0x03D5, 0x06FC, 0x03E2, 0x040E, 0x067F, 0x0694, + 0x06B2, 0x06D2, 0x05AC, 0x05DD, 0x061A, 0x065F, 0x0538, 0x0551, 0x056A, 0x0424, + 0x044C, 0x047E, 0x049C, 0x0485, 0x04AB, 0x0510, 0x053D, 0x03FB, 0x0412, 0x042D, + 0x045C, 0x0346, 0x0372, 0x0395, 0x03BD, 0x0291, 0x02AE, 0x02D0, 0x0300, 0x0554, + 0x05BC, 0x05E9, 0x04AB, 0x0510, 0x053D, 0x0412, 0x042D, 0x0395, 0x03B2, 0x03E2, + 0x040E, 0x02C6, 0x02EF, 0x036D, 0x06BE, 0x06DB, 0x0267, 0x02A8, 0x063C, 0x0669, + 0x0688, 0x069C, 0x0424, 0x044C, 0x047E, 0x049C, 0x0389, 0x03B2, 0x03E2, 0x040E, + 0x02C6, 0x02EF, 0x032A, 0x036D, 0x06BE, 0x06DB, 0x0267, 0x02A8, 0x0291, 0x02D0, + 0x0300, 0x067F, 0x0694, 0x06B2, 0x06D2, 0x05AC, 0x05DD, 0x061A, 0x065F, 0x04E6, + 0x0538, 0x0551, 0x056A, 0x0291, 0x02AE, 0x02D0, 0x0300, 0x067F, 0x0694, 0x06B2, + 0x06D2, 0x05AC, 0x05DD, 0x061A, 0x065F, 0x04E6, 0x0538, 0x0551, 0x056A, 0x0554, + 0x0578, 0x05BC, 0x05E9, 0x0485, 0x04AB, 0x0510, 0x053D, 0x03FB, 0x0412, 0x042D, + 0x045C, 0x0346, 0x0372, 0x0395, 0x03BD, 0x063C, 0x0669, 0x0688, 0x069C, 0x05BC, + 0x05E9, 0x0485, 0x01D0, 0x01B2, 0x01FB, 0x01E5, 0x021B, 0x020F, 0x0230, 0x0225, + 0x01B3, 0x023A, 0x01D0, 0x01B2, 0x01FB, 0x01E5, 0x021B, 0x020F, 0x0230, 0x0225, + 0x01B3, 0x023A, 0x01D0, 0x01B2, 0x01FB, 0x0510, 0x021B, 0x020F, 0x0230, 0x03FB, + 0x01B3, 0x023A, 0x0412, 0x042D, 0x045C, 0x0424, 0x044C, 0x047E, 0x049C, 0x0389, + 0x03B2, 0x03E2, 0x040E, 0x02C6, 0x02EF, 0x032A, 0x036D, 0x06BE, 0x0267, 0x02A8, + 0x04E6, 0x0538, 0x0551, 0x056A, 0x0424, 0x044C, 0x047E, 0x049C, 0x0389, 0x03B2, + 0x03E2, 0x040E, 0x2A52, 0x02C6, 0x02EF, 0x2A58, 0x032A, 0x036D, 0x0346, 0x0372, + 0x0395, 0x2A64, 0x0291, 0x02AE, 0x0300, 0x067F, 0x0694, 0x06B2, 0x06D2, 0x05AC, + 0x05DD, 0x061A, 0x065F, 0x0412, 0x042D, 0x045C, 0x0346, 0x0372, 0x0395, 0x0291, + 0x02AE, 0x0300, 0x067F, 0x0694, 0x06B2, 0x2A4F, 0x06D2, 0x06BE, 0x0267, 0x02A8, + 0x063C, 0x0669, 0x0688, 0x069C, 0x0554, 0x05BC, 0x05E9, 0x0485, 0x04AB, 0x0510, + 0x053D, 0x06BE, 0x06DB, 0x0267, 0x02A8, 0x063C, 0x0669, 0x0688, 0x069C, 0x0554, + 0x0578, 0x05BC, 0x05E9, 0x0485, 0x04AB, 0x0510, 0x053D, 0x04E6, 0x0538, 0x0551, + 0x056A, 0x0424, 0x044C, 0x047E, 0x049C, 0x0389, 0x03B2, 0x03E2, 0x040E, 0x02C6, + 0x02EF, 0x032A, 0x036D, 0x05AC, 0x05DD, 0x061A, 0x065F, 0x04E6, 0x0538, 0x0551, + 0x056A, 0x0424, 0x044C, 0x047E, 0x049C, 0x0389, 0x03B2, 0x03E2, 0x040E, 0x03FB, + 0x0412, 0x042D, 0x045C, 0x0346, 0x0372, 0x0395, 0x03BD, 0x0291, 0x02AE, 0x02D0, + 0x0300, 0x067F, 0x0694, 0x06B2, 0x06D2, 0x0485, 0x04AB, 0x0510, 0x053D, 0x03FB, + 0x0412, 0x042D, 0x045C, 0x0346, 0x0372, 0x0395, 0x03BD, 0x0291, 0x02AE, 0x02D0, + 0x0300, 0x02C6, 0x02EF, 0x032A, 0x036D, 0x06BE, 0x06DB, 0x0267, 0x02A8, 0x063C, + 0x0669, 0x0688, 0x069C, 0x0554, 0x0578, 0x05BC, 0x05E9, 0x0389, 0x03B2, 0x03E2, + 0x040E, 0x02C6, 0x02EF, 0x032A, 0x036D, 0x06BE, 0x06DB, 0x2A13, 0x0267, 0x02A8, + 0x063C, 0x0669, 0x0688, 0x069C, 0x067F, 0x0694, 0x06B2, 0x06D2, 0x05AC, 0x05DD, + 0x061A, 0x065F, 0x04E6, 0x0538, 0x0551, 0x056A, 0x0424, 0x044C, 0x047E, 0x049C, + 0x0192, 0x0193, 0x0194, 0x0195, 0x0234, 0x018F, 0x0190, 0x0191, 0x0209, 0x0215, + 0x021F, 0x022A, 0x01A2, 0x01C9, 0x01DF, 0x01F5, 0x0196, 0x0197, 0x4355, 0x4356, + 0x4357, 0x4351, 0x4352, 0x4353, 0x4354, 0x434D, 0x434E, 0x434F, 0x4350, 0x4349, + 0x434A, 0x434B, 0x434C, 0x4335, 0x4336, 0x4337, 0x4338, 0x4331, 0x4332, 0x4333, + 0x4334, 0x432D, 0x432E, 0x432F, 0x4330, 0x4329, 0x432A, 0x432B, 0x432C, 0x4345, + 0x4346, 0x4347, 0x4348, 0x4341, 0x4342, 0x4343, 0x4344, 0x433D, 0x433E, 0x433F, + 0x4340, 0x4339, 0x433A, 0x433B, 0x433C, 0x4195, 0x4196, 0x4197, 0x4198, 0x4191, + 0x4192, 0x4193, 0x4194, 0x418D, 0x418E, 0x418F, 0x4190, 0x4189, 0x418A, 0x418B, + 0x418C, 0x41A5, 0x41A6, 0x41A7, 0x41A8, 0x41A1, 0x41A2, 0x41A3, 0x41A4, 0x419D, + 0x419E, 0x419F, 0x41A0, 0x4199, 0x419A, 0x419B, 0x419C, 0x4175, 0x4176, 0x4177, + 0x4178, 0x4171, 0x4172, 0x4173, 0x4174, 0x416D, 0x416E, 0x416F, 0x4170, 0x4169, + 0x416A, 0x416B, 0x416C, 0x4185, 0x4186, 0x4187, 0x4188, 0x4181, 0x4182, 0x2D71, + 0x2D72, 0x4183, 0x4184, 0x417D, 0x417E, 0x2D6F, 0x2D70, 0x417F, 0x4180, 0x4179, + 0x417A, 0x2D75, 0x2D76, 0x417B, 0x417C, 0x4155, 0x4156, 0x4157, 0x4158, 0x2D73, + 0x2D74, 0x4151, 0x4152, 0x4153, 0x4154, 0x414D, 0x414E, 0x414F, 0x4150, 0x2D98, + 0x2D9D, 0x2D97, 0x2D9E, 0x2D93, 0x2D94, 0x2D83, 0x2D84, 0x2D89, 0x2D8A, 0x2D99, + 0x2D9A, 0x2D7B, 0x2D8E, 0x2D9C, 0x2D8D, 0x2D79, 0x2D78, 0x2D7A, 0x2D77, 0x2D7D, + 0x2D60, 0x2D7E, 0x2D61, 0x2C78, 0x2D6D, 0x2D87, 0x2D88, 0x4149, 0x2D7C, 0x2D64, + 0x2D65, 0x414A, 0x414B, 0x414C, 0x4165, 0x4166, 0x4167, 0x4168, 0x4161, 0x4162, + 0x4163, 0x4164, 0x415D, 0x415E, 0x415F, 0x4160, 0x4159, 0x415A, 0x415B, 0x2DB2, + 0x2DB1, 0x415C, 0x4135, 0x4136, 0x4137, 0x2DB8, 0x4138, 0x2DBD, 0x4131, 0x4132, + 0x2DBE, 0x4133, 0x4134, 0x2D7F, 0x2D80, 0x2D81, 0x2D82, 0x2DC4, 0x2DC3, 0x2D85, + 0x2D86, 0x2DC8, 0x2DC7, 0x2DCA, 0x2DC9, 0x2DCC, 0x2DCB, 0x2DCE, 0x2DCD, 0x412D, + 0x412E, 0x412F, 0x4130, 0x4129, 0x412A, 0x412B, 0x412C, 0x4145, 0x4146, 0x4147, + 0x4148, 0x2D9B, 0x4141, 0x4142, 0x4143, 0x4144, 0x413D, 0x413E, 0x413F, 0x4140, + 0x4139, 0x16B6, 0x16B5, 0x16B8, 0x16B7, 0x16BA, 0x16B9, 0x16BC, 0x16BB, 0x413A, + 0x413B, 0x16C0, 0x16BF, 0x413C, 0x4215, 0x4216, 0x4217, 0x4218, 0x4211, 0x4212, + 0x4213, 0x4214, 0x420D, 0x420E, 0x420F, 0x4210, 0x4209, 0x420A, 0x420B, 0x420C, + 0x4225, 0x4226, 0x4227, 0x4228, 0x4221, 0x4222, 0x4223, 0x4224, 0x421D, 0x421E, + 0x421F, 0x4220, 0x4219, 0x421A, 0x421B, 0x421C, 0x41F5, 0x41F6, 0x41F7, 0x41F8, + 0x41F1, 0x41F2, 0x41F3, 0x41F4, 0x41ED, 0x41EE, 0x41EF, 0x41F0, 0x41E9, 0x41EA, + 0x41EB, 0x41EC, 0x4205, 0x4206, 0x4207, 0x4208, 0x4201, 0x4202, 0x4203, 0x4204, + 0x41FD, 0x41FE, 0x41FF, 0x4200, 0x41F9, 0x41FA, 0x41FB, 0x41FC, 0x41D5, 0x41D6, + 0x41D7, 0x41D8, 0x41D1, 0x41D2, 0x41D3, 0x41D4, 0x41CD, 0x41CE, 0x41CF, 0x41D0, + 0x41C9, 0x41CA, 0x41CB, 0x2E4D, 0x2E4E, 0x2E44, 0x2E43, 0x41CC, 0x41E5, 0x2E48, + 0x2E47, 0x41E6, 0x41E7, 0x41E8, 0x41E1, 0x2E49, 0x2E4A, 0x41E2, 0x41E3, 0x41E4, + 0x41DD, 0x41DE, 0x41DF, 0x16DF, 0x16E0, 0x2E4B, 0x2E4C, 0x16F9, 0x16FA, 0x16FB, + 0x16FC, 0x16F5, 0x16F6, 0x2E60, 0x2E5F, 0x2E62, 0x2E61, 0x16F7, 0x16F8, 0x2E66, + 0x2E65, 0x16F0, 0x16EF, 0x16ED, 0x16EE, 0x16F4, 0x16F3, 0x16F1, 0x16F2, 0x2E70, + 0x2E6F, 0x2E72, 0x2E71, 0x2E74, 0x2E73, 0x2E76, 0x2E75, 0x2E78, 0x2E77, 0x2E7A, + 0x2E79, 0x2E7C, 0x2E7B, 0x16DE, 0x2E7D, 0x16DD, 0x16E8, 0x16E2, 0x16E3, 0x16E1, + 0x16E4, 0x16FD, 0x16FE, 0x16FF, 0x1700, 0x16E9, 0x16EA, 0x16EB, 0x16EC, 0x1708, + 0x1702, 0x16E7, 0x1701, 0x1703, 0x16E6, 0x1704, 0x16E5, 0x170D, 0x41E0, 0x41D9, + 0x41DA, 0x0215, 0x021F, 0x16DC, 0x170E, 0x41DB, 0x41DC, 0x41B5, 0x41B6, 0x41B7, + 0x41B8, 0x41B1, 0x41B2, 0x01C9, 0x01DF, 0x0198, 0x01A2, 0x41B3, 0x01F5, 0x41B4, + 0x0209, 0x0234, 0x022A, 0x41AD, 0x41AE, 0x41AF, 0x41B0, 0x41A9, 0x41AA, 0x41AB, + 0x41AC, 0x41C5, 0x41C6, 0x41C7, 0x41C8, 0x41C1, 0x41C2, 0x1705, 0x1706, 0x1707, + 0x41C3, 0x1709, 0x170A, 0x170B, 0x170C, 0x41C4, 0x41BD, 0x41BE, 0x41BF, 0x41C0, + 0x41B9, 0x41BA, 0x41BB, 0x41BC, 0x4295, 0x4296, 0x4297, 0x4298, 0x4291, 0x4292, + 0x4293, 0x4294, 0x428D, 0x428E, 0x428F, 0x4290, 0x4289, 0x428A, 0x428B, 0x428C, + 0x42A5, 0x42A6, 0x42A7, 0x42A8, 0x42A1, 0x42A2, 0x42A3, 0x42A4, 0x429D, 0x429E, + 0x429F, 0x42A0, 0x4299, 0x429A, 0x429B, 0x429C, 0x4275, 0x4276, 0x4277, 0x4278, + 0x4271, 0x4272, 0x4273, 0x4274, 0x426D, 0x426E, 0x426F, 0x4270, 0x4269, 0x426A, + 0x426B, 0x426C, 0x4285, 0x4286, 0x4287, 0x4288, 0x4281, 0x4282, 0x4283, 0x4284, + 0x427D, 0x427E, 0x427F, 0x4280, 0x4279, 0x427A, 0x427B, 0x427C, 0x4255, 0x4256, + 0x4257, 0x4258, 0x4251, 0x4252, 0x4253, 0x4254, 0x424D, 0x424E, 0x424F, 0x4250, + 0x4249, 0x424A, 0x424B, 0x424C, 0x4265, 0x4266, 0x4267, 0x4268, 0x4261, 0x4262, + 0x4263, 0x4264, 0x425D, 0x425E, 0x425F, 0x4260, 0x4259, 0x425A, 0x425B, 0x425C, + 0x4235, 0x4236, 0x4237, 0x4238, 0x4231, 0x4232, 0x4233, 0x4234, 0x422D, 0x422E, + 0x422F, 0x4230, 0x4229, 0x422A, 0x422B, 0x422C, 0x4245, 0x4246, 0x4247, 0x4248, + 0x4241, 0x4242, 0x4243, 0x4244, 0x423D, 0x423E, 0x423F, 0x4240, 0x4239, 0x423A, + 0x423B, 0x423C, 0x4315, 0x4316, 0x4317, 0x4318, 0x4311, 0x4312, 0x4313, 0x1710, + 0x170F, 0x1714, 0x1711, 0x4314, 0x1716, 0x171A, 0x1719, 0x171C, 0x171B, 0x171E, + 0x171D, 0x1720, 0x171F, 0x1722, 0x1721, 0x430D, 0x430E, 0x430F, 0x4310, 0x4309, + 0x430A, 0x430B, 0x430C, 0x172C, 0x172B, 0x4325, 0x4326, 0x1730, 0x172F, 0x1732, + 0x1731, 0x4327, 0x4328, 0x4321, 0x4322, 0x4323, 0x4324, 0x431D, 0x431E, 0x431F, + 0x4320, 0x4319, 0x431A, 0x431B, 0x431C, 0x42F5, 0x42F6, 0x42F7, 0x42F8, 0x42F1, + 0x42F2, 0x42F3, 0x42F4, 0x42ED, 0x42EE, 0x42EF, 0x42F0, 0x42E9, 0x42EA, 0x42EB, + 0x42EC, 0x4305, 0x4306, 0x4307, 0x4308, 0x4301, 0x4302, 0x4303, 0x4304, 0x42FD, + 0x42FE, 0x42FF, 0x4300, 0x42F9, 0x42FA, 0x42FB, 0x42FC, 0x42D5, 0x42D6, 0x42D7, + 0x42D8, 0x42D1, 0x42D2, 0x42D3, 0x42D4, 0x42CD, 0x42CE, 0x42CF, 0x42D0, 0x42C9, + 0x42CA, 0x42CB, 0x42CC, 0x42E5, 0x42E6, 0x42E7, 0x42E8, 0x42E1, 0x42E2, 0x42E3, + 0x42E4, 0x42DD, 0x42DE, 0x42DF, 0x42E0, 0x42D9, 0x42DA, 0x42DB, 0x42DC, 0x42B5, + 0x42B6, 0x42B7, 0x42B8, 0x42B1, 0x42B2, 0x42B3, 0x42B4, 0x42AD, 0x42AE, 0x42AF, + 0x42B0, 0x42A9, 0x42AA, 0x42AB, 0x42AC, 0x42C5, 0x42C6, 0x42C7, 0x42C8, 0x1745, + 0x42C1, 0x42C2, 0x42C3, 0x42C4, 0x42BD, 0x42BE, 0x42BF, 0x42C0, 0x42B9, 0x42BA, + 0x42BB, 0x42BC, 0x3F95, 0x1753, 0x1752, 0x1755, 0x1754, 0x1757, 0x1756, 0x1759, + 0x1758, 0x175B, 0x175A, 0x175D, 0x175C, 0x175F, 0x175E, 0x1761, 0x1760, 0x1763, + 0x1762, 0x3F96, 0x1764, 0x1767, 0x1766, 0x1769, 0x1768, 0x176B, 0x176A, 0x176D, + 0x176C, 0x176F, 0x176E, 0x1771, 0x1770, 0x3F97, 0x3F98, 0x3F91, 0x3F92, 0x3F93, + 0x3F94, 0x3F8D, 0x3F8E, 0x3F8F, 0x3F90, 0x3F89, 0x3F8A, 0x3F8B, 0x3F8C, 0x3FA5, + 0x3FA6, 0x3FA7, 0x3FA8, 0x3FA1, 0x3FA2, 0x3FA3, 0x1772, 0x3FA4, 0x3F9D, 0x3F9E, + 0x3F9F, 0x3FA0, 0x3F99, 0x3F9A, 0x3F9B, 0x3F9C, 0x3F75, 0x01A2, 0x0198, 0x01DF, + 0x01C9, 0x0209, 0x01F5, 0x021F, 0x0215, 0x0234, 0x022A, 0x3F76, 0x3F77, 0x3F78, + 0x3F71, 0x3F72, 0x3F73, 0x3F74, 0x3F6D, 0x3F6E, 0x3F6F, 0x3F70, 0x3F69, 0x3F6A, + 0x3F6B, 0x3F6C, 0x3F85, 0x3F86, 0x3F87, 0x3F88, 0x3F81, 0x3F82, 0x3F83, 0x3F84, + 0x3F7D, 0x3F7E, 0x3F7F, 0x3F80, 0x3F79, 0x3F7A, 0x3F7B, 0x3F7C, 0x3F55, 0x3F56, + 0x3F57, 0x3F58, 0x3F51, 0x3F52, 0x3F53, 0x3F54, 0x3F4D, 0x1776, 0x3F4E, 0x3F4F, + 0x3F50, 0x3F49, 0x3F4A, 0x3F4B, 0x3F4C, 0x3F65, 0x3F66, 0x3F67, 0x3F68, 0x3F61, + 0x3F62, 0x1787, 0x1786, 0x1789, 0x1788, 0x178B, 0x178A, 0x178D, 0x3F63, 0x178F, + 0x178E, 0x1791, 0x1790, 0x1793, 0x1792, 0x1795, 0x3F64, 0x1797, 0x1796, 0x3F5D, + 0x1798, 0x179B, 0x179A, 0x177E, 0x179C, 0x177F, 0x177D, 0x3F5E, 0x179D, 0x3F5F, + 0x3F60, 0x3F59, 0x3F5A, 0x3F5B, 0x3F5C, 0x3F35, 0x3F36, 0x3F37, 0x3F38, 0x3F31, + 0x3F32, 0x3F33, 0x3F34, 0x3F2D, 0x3F2E, 0x3F2F, 0x3F30, 0x3F29, 0x3F2A, 0x01A2, + 0x0198, 0x01DF, 0x01C9, 0x0209, 0x01F5, 0x021F, 0x0215, 0x0234, 0x022A, 0x3F2B, + 0x3F2C, 0x3F45, 0x3F46, 0x3F47, 0x3F48, 0x3F41, 0x3F42, 0x3F43, 0x3F44, 0x3F3D, + 0x3F3E, 0x3F3F, 0x3F40, 0x3F39, 0x3F3A, 0x3F3B, 0x3F3C, 0x4015, 0x4016, 0x4017, + 0x4018, 0x4011, 0x4012, 0x4013, 0x4014, 0x400D, 0x400E, 0x400F, 0x4010, 0x4009, + 0x400A, 0x400B, 0x400C, 0x4025, 0x4026, 0x4027, 0x4028, 0x4021, 0x4022, 0x4023, + 0x4024, 0x401D, 0x401E, 0x401F, 0x4020, 0x4019, 0x401A, 0x401B, 0x401C, 0x3FF5, + 0x3FF6, 0x3FF7, 0x3FF8, 0x3FF1, 0x3FF2, 0x3FF3, 0x3FF4, 0x3FED, 0x3FEE, 0x3FEF, + 0x3FF0, 0x3FE9, 0x3FEA, 0x3FEB, 0x3FEC, 0x4005, 0x4006, 0x4007, 0x4008, 0x4001, + 0x4002, 0x4003, 0x4004, 0x3FFD, 0x3FFE, 0x3FFF, 0x4000, 0x3FF9, 0x3FFA, 0x3FFB, + 0x3FFC, 0x3FD5, 0x3FD6, 0x3FD7, 0x3FD8, 0x3FD1, 0x3FD2, 0x3FD3, 0x3FD4, 0x3FCD, + 0x3FCE, 0x3FCF, 0x3FD0, 0x3FC9, 0x3FCA, 0x3FCB, 0x3FCC, 0x3FE5, 0x3FE6, 0x3FE7, + 0x3FE8, 0x3FE1, 0x08A2, 0x08A3, 0x08A4, 0x08A5, 0x08A6, 0x3FE2, 0x08A8, 0x08A9, + 0x08AA, 0x3FE3, 0x3FE4, 0x08AF, 0x3FDD, 0x3FDE, 0x3FDF, 0x3FE0, 0x08B4, 0x08B5, + 0x08B6, 0x08B7, 0x08B8, 0x08BA, 0x08BD, 0x08BE, 0x08BF, 0x08C0, 0x08C1, 0x08C2, + 0x08C7, 0x08C8, 0x08C9, 0x08CA, 0x3FD9, 0x3FDA, 0x3FDB, 0x3FDC, 0x3FB5, 0x3FB6, + 0x3FB7, 0x3FB8, 0x3FB1, 0x3FB2, 0x3FB3, 0x3FB4, 0x3FAD, 0x3FAE, 0x3FAF, 0x3FB0, + 0x3FA9, 0x3FAA, 0x3FAB, 0x3FAC, 0x0913, 0x3FC5, 0x3FC6, 0x3FC7, 0x3FC8, 0x3FC1, + 0x3FC2, 0x3FC3, 0x3FC4, 0x3FBD, 0x3FBE, 0x3FBF, 0x3FC0, 0x3FB9, 0x3FBA, 0x3FBB, + 0x3FBC, 0x4095, 0x4096, 0x4097, 0x4098, 0x4091, 0x4092, 0x4093, 0x4094, 0x408D, + 0x408E, 0x408F, 0x4090, 0x4089, 0x408A, 0x408B, 0x408C, 0x40A5, 0x40A6, 0x40A7, + 0x40A8, 0x40A1, 0x40A2, 0x40A3, 0x40A4, 0x409D, 0x409E, 0x409F, 0x40A0, 0x4099, + 0x409A, 0x409B, 0x409C, 0x4075, 0x4076, 0x4077, 0x4078, 0x4071, 0x4072, 0x4073, + 0x4074, 0x406D, 0x406E, 0x406F, 0x4070, 0x4069, 0x406A, 0x406B, 0x406C, 0x4085, + 0x4086, 0x4087, 0x4088, 0x4081, 0x4082, 0x4083, 0x4084, 0x407D, 0x407E, 0x407F, + 0x4080, 0x4079, 0x407A, 0x407B, 0x407C, 0x4055, 0x4056, 0x4057, 0x4058, 0x4051, + 0x4052, 0x4053, 0x4054, 0x0B39, 0x404D, 0x404E, 0x0B4B, 0x0B48, 0x0B54, 0x0B4E, + 0x0B5A, 0x404F, 0x0B60, 0x0B5D, 0x0B66, 0x4050, 0x0B6C, 0x0B69, 0x4049, 0x404A, + 0x404B, 0x404C, 0x4065, 0x4066, 0x4067, 0x4068, 0x4061, 0x4062, 0x4063, 0x4064, + 0x405D, 0x405E, 0x405F, 0x4060, 0x4059, 0x405A, 0x405B, 0x405C, 0x10AE, 0x10AD, + 0x10B0, 0x10AF, 0x10B2, 0x4035, 0x10B4, 0x10B3, 0x10B6, 0x4036, 0x4037, 0x10B7, + 0x4038, 0x4031, 0x4032, 0x4033, 0x10BF, 0x10BE, 0x10C1, 0x10C0, 0x10C3, 0x10C2, + 0x10C5, 0x10C4, 0x10C7, 0x10C6, 0x10C9, 0x10C8, 0x10CB, 0x10CA, 0x10CD, 0x10CC, + 0x4034, 0x402D, 0x402E, 0x402F, 0x4030, 0x4029, 0x402A, 0x402B, 0x402C, 0x4045, + 0x4046, 0x4047, 0x4048, 0x10DB, 0x4041, 0x4042, 0x4043, 0x4044, 0x403D, 0x403E, + 0x403F, 0x4040, 0x4039, 0x403A, 0x403B, 0x403C, 0x4115, 0x4116, 0x4117, 0x4118, + 0x4111, 0x4112, 0x4113, 0x4114, 0x410D, 0x410E, 0x410F, 0x4110, 0x4109, 0x410A, + 0x410B, 0x410C, 0x4125, 0x4126, 0x4127, 0x4128, 0x4121, 0x4122, 0x4123, 0x4124, + 0x411D, 0x411E, 0x411F, 0x4120, 0x4119, 0x411A, 0x411B, 0x411C, 0x40F5, 0x40F6, + 0x40F7, 0x40F8, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40ED, 0x40EE, 0x40EF, 0x40F0, + 0x40E9, 0x40EA, 0x40EB, 0x40EC, 0x4105, 0x4106, 0x4107, 0x4108, 0x4101, 0x4102, + 0x4103, 0x4104, 0x40FD, 0x40FE, 0x40FF, 0x4100, 0x40F9, 0x40FA, 0x40FB, 0x40FC, + 0x40D5, 0x40D6, 0x40D7, 0x40D8, 0x40D1, 0x40D2, 0x40D3, 0x40D4, 0x40CD, 0x40CE, + 0x40CF, 0x40D0, 0x40C9, 0x40CA, 0x40CB, 0x40CC, 0x40E5, 0x40E6, 0x40E7, 0x40E8, + 0x40E1, 0x40E2, 0x128F, 0x128E, 0x1291, 0x1290, 0x1293, 0x1292, 0x40E3, 0x1294, + 0x1296, 0x1295, 0x1298, 0x1297, 0x129A, 0x1299, 0x40E4, 0x129B, 0x40DD, 0x40DE, + 0x40DF, 0x40E0, 0x40D9, 0x40DA, 0x40DB, 0x40DC, 0x40B5, 0x40B6, 0x40B7, 0x40B8, + 0x40B1, 0x12A7, 0x40B2, 0x40B3, 0x40B4, 0x40AD, 0x40AE, 0x40AF, 0x40B0, 0x40A9, + 0x40AA, 0x40AB, 0x40AC, 0x40C5, 0x40C6, 0x40C7, 0x40C8, 0x40C1, 0x40C2, 0x40C3, + 0x40C4, 0x40BD, 0x40BE, 0x40BF, 0x40C0, 0x40B9, 0x40BA, 0x40BB, 0x40BC, 0x48AB, + 0x490A, 0x490B, 0x48AC, 0x4909, 0x4975, 0x48A7, 0x48A9, 0x48A1, 0x48A2, 0x48A3, + 0x48A5, 0x489A, 0x4974, 0x489D, 0x4908, 0x48BA, 0x497B, 0x48B6, 0x48B7, 0x48B8, + 0x48B9, 0x4979, 0x48B3, 0x490D, 0x48B5, 0x4976, 0x490C, 0x4977, 0x4978, 0x021F, + 0x022A, 0x0234, 0x018E, 0x01F5, 0x0209, 0x0215, 0x018A, 0x018B, 0x018C, 0x018D, + 0x0186, 0x0187, 0x0188, 0x0189, 0x01F5, 0x0209, 0x0215, 0x01A2, 0x0234, 0x0234, + 0x01C9, 0x01DF, 0x022A, 0x022A, 0x0234, 0x0234, 0x0215, 0x021F, 0x021F, 0x021F, + 0x0182, 0x0183, 0x0184, 0x0185, 0x01A2, 0x01C9, 0x0180, 0x0181, 0x0209, 0x0209, + 0x01C9, 0x01DF, 0x01C9, 0x01DF, 0x01F5, 0x01F5, 0x01A2, 0x01C9, 0x01DF, 0x01DF, + 0x0215, 0x021F, 0x022A, 0x0234, 0x01DF, 0x01DF, 0x01F5, 0x0209, 0x01DF, 0x01F5, + 0x0209, 0x01C9, 0x01F5, 0x01F5, 0x01F5, 0x01F5, 0x01F5, 0x0209, 0x01DF, 0x01DF, + 0x01A2, 0x01C9, 0x01DF, 0x01DF, 0x01F5, 0x0209, 0x017E, 0x017F, 0x021F, 0x022A, + 0x0234, 0x01F5, 0x01DF, 0x01F5, 0x0209, 0x0215, 0x0215, 0x021F, 0x022A, 0x0234, + 0x01C9, 0x01DF, 0x01F5, 0x0209, 0x022A, 0x0234, 0x01A2, 0x01C9, 0x01F5, 0x0209, + 0x0215, 0x021F, 0x0234, 0x01A2, 0x01C9, 0x01DF, 0x0209, 0x0215, 0x021F, 0x022A, + 0x3ED1, 0x3ED2, 0x3ED3, 0x3ED4, 0x3ECD, 0x3ECE, 0x3ECF, 0x3ED0, 0x3EC9, 0x3ECA, + 0x3ECB, 0x3ECC, 0x3EC5, 0x3EC6, 0x3EC7, 0x3EC8, 0x3EE1, 0x3EE2, 0x3EE3, 0x3EE4, + 0x3EDD, 0x3EDE, 0x3EDF, 0x3EE0, 0x3ED9, 0x3EDA, 0x3EDB, 0x3EDC, 0x3ED5, 0x3ED6, + 0x3ED7, 0x3ED8, 0x3EB1, 0x3EB2, 0x3EB3, 0x3EB4, 0x3EAD, 0x3EAE, 0x3EAF, 0x3EB0, + 0x3EA9, 0x3EAA, 0x3EAB, 0x3EAC, 0x3EA5, 0x3EA6, 0x3EA7, 0x3EA8, 0x3EC1, 0x3EC2, + 0x3EC3, 0x3EC4, 0x3EBD, 0x3EBE, 0x3EBF, 0x3EC0, 0x3EB9, 0x3EBA, 0x3EBB, 0x3EBC, + 0x3EB5, 0x3EB6, 0x3EB7, 0x3EB8, 0x3E91, 0x3E92, 0x3E93, 0x3E94, 0x3E8D, 0x3E8E, + 0x3E8F, 0x3E90, 0x3E89, 0x3E8A, 0x3E8B, 0x3E8C, 0x3E85, 0x3E86, 0x3E87, 0x3E88, + 0x3EA1, 0x3EA2, 0x3EA3, 0x3EA4, 0x3E9D, 0x3E9E, 0x3E9F, 0x3EA0, 0x3E99, 0x3E9A, + 0x3E9B, 0x3E9C, 0x3E95, 0x3E96, 0x3E97, 0x3E98, 0x3E71, 0x3E72, 0x3E73, 0x3E74, + 0x3E6D, 0x3E6E, 0x3E6F, 0x3E70, 0x3E69, 0x3E6A, 0x3E6B, 0x3E6C, 0x3E65, 0x3E66, + 0x3E67, 0x3E68, 0x3E81, 0x3E82, 0x3E83, 0x3E84, 0x3E7D, 0x3E7E, 0x3E7F, 0x3E80, + 0x3E79, 0x3E7A, 0x3E7B, 0x3E7C, 0x3E75, 0x3E76, 0x3E77, 0x3E78, 0x3F25, 0x3F26, + 0x3F27, 0x3F28, 0x3F11, 0x3F12, 0x3F13, 0x3F14, 0x3F0D, 0x3F1E, 0x3F1F, 0x3F20, + 0x3F19, 0x464C, 0x270E, 0x270D, 0x2710, 0x270F, 0x2712, 0x2711, 0x2714, 0x2713, + 0x2716, 0x2715, 0x2718, 0x2717, 0x271A, 0x2719, 0x271C, 0x271B, 0x271E, 0x271D, + 0x2720, 0x271F, 0x2722, 0x2721, 0x2724, 0x2723, 0x2726, 0x2725, 0x2728, 0x2727, + 0x272A, 0x2756, 0x272C, 0x272B, 0x272E, 0x272D, 0x2730, 0x272F, 0x2732, 0x2731, + 0x2734, 0x2733, 0x2736, 0x2735, 0x2738, 0x2737, 0x273A, 0x2739, 0x273C, 0x273B, + 0x273E, 0x276F, 0x2740, 0x273F, 0x2742, 0x274F, 0x2744, 0x2778, 0x278A, 0x2745, + 0x275B, 0x275A, 0x274A, 0x2749, 0x274C, 0x274B, 0x1BFE, 0x274D, 0x2729, 0x276B, + 0x2750, 0x1BD5, 0x2751, 0x1BD9, 0x1BDA, 0x2758, 0x276C, 0x1BDC, 0x1BDB, 0x1BDE, + 0x1BDD, 0x1BE0, 0x1BE6, 0x1BE2, 0x2764, 0x275F, 0x1BDF, 0x1BE3, 0x277C, 0x2762, + 0x276A, 0x1BE1, 0x1BE5, 0x2760, 0x275E, 0x1BD6, 0x275D, 0x275C, 0x2769, 0x1BED, + 0x1BEE, 0x2747, 0x277A, 0x2741, 0x276D, 0x1BEF, 0x1BF6, 0x276E, 0x2789, 0x1BEC, + 0x1BF2, 0x1BE7, 0x1BF7, 0x278B, 0x1BD8, 0x1BE9, 0x2757, 0x2768, 0x1BE4, 0x2761, + 0x2763, 0x2766, 0x1BE8, 0x1BEA, 0x2767, 0x278C, 0x2785, 0x2743, 0x2784, 0x273D, + 0x1BFD, 0x1BFC, 0x2790, 0x278F, 0x278E, 0x2793, 0x2792, 0x278D, 0x2791, 0x279A, + 0x2787, 0x2788, 0x27A9, 0x2799, 0x279C, 0x279B, 0x279F, 0x27A2, 0x27A0, 0x1BD7, + 0x1BFF, 0x27A3, 0x27A4, 0x279E, 0x279D, 0x27AA, 0x27A6, 0x27A1, 0x27A5, 0x27AB, + 0x27AC, 0x27A7, 0x1BEB, 0x277B, 0x1C02, 0x1C00, 0x2782, 0x1C03, 0x1C04, 0x2781, + 0x27C5, 0x27C6, 0x2746, 0x1C16, 0x1C18, 0x1BFA, 0x1C17, 0x1C15, 0x27BE, 0x1BF0, + 0x27C0, 0x27BF, 0x27C2, 0x27C1, 0x27C4, 0x27C3, 0x27BD, 0x27C7, 0x27C8, 0x1C29, + 0x1C28, 0x1C01, 0x1C2B, 0x2779, 0x27D2, 0x1C24, 0x27CE, 0x1C2A, 0x277E, 0x27D1, + 0x27D4, 0x27D3, 0x1C27, 0x1C22, 0x27CF, 0x27D0, 0x27CD, 0x27F1, 0x2759, 0x277D, + 0x27D5, 0x2765, 0x2755, 0x274E, 0x340C, 0x2752, 0x2753, 0x2754, 0x27D6, 0x27E5, + 0x27D7, 0x27D8, 0x27EA, 0x27E9, 0x27EC, 0x27EB, 0x27F2, 0x277F, 0x27F3, 0x27F4, + 0x27ED, 0x27EE, 0x27EF, 0x27F0, 0x2783, 0x27F5, 0x27F9, 0x27FA, 0x27FB, 0x27FC, + 0x27F7, 0x27F8, 0x2771, 0x27F6, 0x2774, 0x1C1B, 0x2809, 0x280A, 0x1BFB, 0x2780, + 0x280B, 0x280C, 0x1BF5, 0x3406, 0x3405, 0x3408, 0x3407, 0x340A, 0x3409, 0x1C1C, + 0x340B, 0x340E, 0x340D, 0x3410, 0x340F, 0x3412, 0x3411, 0x3414, 0x3413, 0x3417, + 0x3400, 0x3418, 0x3416, 0x33FE, 0x3419, 0x3415, 0x33FF, 0x3402, 0x3401, 0x3404, + 0x3403, 0x341B, 0x341A, 0x341C, 0x3421, 0x341E, 0x341D, 0x3420, 0x341F, 0x3428, + 0x3422, 0x3434, 0x3426, 0x3427, 0x3429, 0x3430, 0x3435, 0x3431, 0x342E, 0x3423, + 0x342F, 0x3425, 0x3436, 0x342C, 0x3424, 0x3432, 0x342A, 0x342B, 0x342D, 0x2C6A, + 0x3433, 0x2C64, 0x2C65, 0x2C70, 0x2C7A, 0x2D23, 0x2C71, 0x2C79, 0x01C9, 0x01A2, + 0x01DF, 0x2D1C, 0x2C6B, 0x2C8C, 0x2CAA, 0x2CA5, 0x2C91, 0x47D2, 0x0198, 0x2C86, + 0x2CA4, 0x2CB7, 0x2C80, 0x2C7F, 0x2CD2, 0x2CCC, 0x2C8D, 0x2CC5, 0x2CD3, 0x2CBB, + 0x2CA9, 0x2CBC, 0x2CB0, 0x2C7B, 0x2CAB, 0x47D3, 0x2C87, 0x2C08, 0x2CC0, 0x1BF8, + 0x2CF5, 0x2CF6, 0x1BF1, 0x47D4, 0x286E, 0x286D, 0x2C9F, 0x1BF4, 0x2CB6, 0x2776, + 0x2770, 0x2773, 0x2CB1, 0x287A, 0x2CEF, 0x2D15, 0x287B, 0x2879, 0x287C, 0x2D59, + 0x2AB7, 0x2AB9, 0x2D53, 0x1BF3, 0x2D20, 0x2772, 0x2AAD, 0x2AAE, 0x1BF9, 0x2786, + 0x2777, 0x1C14, 0x2AAF, 0x288C, 0x2C72, 0x288B, 0x1C23, 0x1C21, 0x2AA9, 0x2D5D, + 0x1C1E, 0x1C1F, 0x2AB2, 0x1C1D, 0x1C25, 0x2C85, 0x1C26, 0x1C20, 0x1C11, 0x2A70, + 0x2C6C, 0x2C68, 0x2ADA, 0x2C66, 0x2A7F, 0x2A82, 0x2CAE, 0x2CB3, 0x2A8B, 0x1C13, + 0x2A7C, 0x2AB5, 0x1C08, 0x1C07, 0x2CB4, 0x2CA6, 0x2CBD, 0x2CC2, 0x2D4D, 0x2CA1, + 0x2CAD, 0x2CA7, 0x2CB8, 0x2D49, 0x2D26, 0x2D4E, 0x2D33, 0x1C19, 0x2CB9, 0x2CBE, + 0x1C06, 0x1C05, 0x2AEB, 0x2D38, 0x1C0B, 0x2C97, 0x1C0C, 0x1C0D, 0x1C10, 0x1C0F, + 0x1C0E, 0x1C1A, 0x1C0A, 0x1C09, 0x1C12, 0x2A88, 0x2AE8, 0x2AEA, 0x2AED, 0x2AEC, + 0x2D56, 0x2AEE, 0x2AEF, 0x2AF0, 0x2AE0, 0x2AF3, 0x2AE2, 0x2AF5, 0x2B0A, 0x2AE5, + 0x2AE6, 0x2AE7, 0x2C1D, 0x2AE1, 0x2ADB, 0x2AE3, 0x2CCB, 0x2C1E, 0x2C1F, 0x2C20, + 0x2CD7, 0x2CD8, 0x2CDD, 0x2CE0, 0x2CE3, 0x2C1A, 0x2C1B, 0x2C19, 0x2CEE, 0x2AD7, + 0x2AD8, 0x2ADF, 0x2CF7, 0x2CFD, 0x2CFE, 0x2CFF, 0x2D05, 0x2D06, 0x2D07, 0x2ADC, + 0x2ADD, 0x2D0F, 0x2D16, 0x2D19, 0x2C16, 0x2AC7, 0x2C15, 0x2C1C, 0x2E7E, 0x2EA9, + 0x2E82, 0x2E80, 0x2E85, 0x2E83, 0x2E88, 0x2E86, 0x2E8A, 0x2E89, 0x2E90, 0x2E8C, + 0x2E98, 0x2E99, 0x2E9A, 0x2E9B, 0x2E95, 0x2E97, 0x2B68, 0x2B65, 0x2E92, 0x2E94, + 0x2EAC, 0x2EAE, 0x2E9E, 0x2EA7, 0x2EA2, 0x2EA4, 0x2EB1, 0x2EAF, 0x2EB3, 0x2EB2, + 0x2EB6, 0x293A, 0x2EBB, 0x2EBA, 0x2EC1, 0x2AD9, 0x2E8E, 0x2C17, 0x2935, 0x2E96, + 0x293C, 0x2C18, 0x2A6E, 0x2E9D, 0x2BC1, 0x2A71, 0x2BC5, 0x2A74, 0x2A77, 0x2BC8, + 0x2A7D, 0x2A7A, 0x2BD0, 0x2BCD, 0x2BD6, 0x2BD3, 0x2BDC, 0x2BD9, 0x2A80, 0x2AB0, + 0x2A86, 0x2A83, 0x36E7, 0x2C13, 0x2ADE, 0x2A8C, 0x2A89, 0x36E8, 0x2ABD, 0x2A95, + 0x2C10, 0x2C12, 0x2A9B, 0x2A8F, 0x2B35, 0x2B32, 0x2B3B, 0x2B38, 0x2B41, 0x2B3E, + 0x2B47, 0x2B44, 0x2B4D, 0x2B4A, 0x2B53, 0x2B50, 0x2B59, 0x2B56, 0x2B5F, 0x2B5C, + 0x01C9, 0x2E84, 0x2C00, 0x2AA1, 0x36EA, 0x1880, 0x2ABB, 0x2B2F, 0x2C05, 0x2A92, + 0x2A98, 0x2EB4, 0x187F, 0x01A2, 0x2AA4, 0x2AB8, 0x2ACA, 0x36E3, 0x1878, 0x2B6B, + 0x2AB6, 0x2AC0, 0x1877, 0x2EA8, 0x021F, 0x2EBE, 0x2ACD, 0x1875, 0x187A, 0x2AE9, + 0x36E5, 0x0198, 0x2C23, 0x2AF1, 0x2C25, 0x2B05, 0x2B07, 0x2AF7, 0x2B7C, 0x2B7E, + 0x2B91, 0x2B8C, 0x2B8E, 0x2BA0, 0x2B03, 0x2B82, 0x2B9C, 0x2C6E, 0x2C8A, 0x47E1, + 0x1894, 0x47DF, 0x47E2, 0x47E0, 0x2C8F, 0x2C8E, 0x2C7D, 0x36EB, 0x2C83, 0x2C89, + 0x2C94, 0x2C81, 0x2AB4, 0x2C0D, 0x2EB7, 0x2E7F, 0x2E8B, 0x2E93, 0x2EAB, 0x2E9C, + 0x2EA5, 0x2EA6, 0x2EA3, 0x2EC0, 0x2EBF, 0x2EBC, 0x2EAA, 0x2EAD, 0x2EB0, 0x2C75, + 0x2E87, 0x2EB5, 0x2EBD, 0x2E81, 0x2E9F, 0x2EB8, 0x2E91, 0x2E8D, 0x2BF7, 0x2EA1, + 0x2EA0, 0x2BF2, 0x2EB9, 0x2E8F, 0x2EC2, 0x2C73, 0x2CF2, 0x36EF, 0x2CF9, 0x2CF3, + 0x2D03, 0x2A9E, 0x2CFB, 0x187D, 0x2D0B, 0x2D0A, 0x1884, 0x2D11, 0x2D17, 0x293B, + 0x2D02, 0x2D01, 0x2AA8, 0x2CFA, 0x2939, 0x1882, 0x187C, 0x1876, 0x36E9, 0x36ED, + 0x1C3C, 0x1C3D, 0x1C2D, 0x2B2C, 0x187E, 0x2C30, 0x2C14, 0x1C3A, 0x2D13, 0x2953, + 0x2B62, 0x2BF0, 0x2D3E, 0x294E, 0x2AD5, 0x2AC2, 0x2955, 0x2ACF, 0x2AD1, 0x2AD3, + 0x2D42, 0x2D1A, 0x2D46, 0x2D4A, 0x2CAC, 0x2C93, 0x2CD9, 0x2CB2, 0x2BFA, 0x2AAA, + 0x2CF0, 0x2D09, 0x2CE4, 0x2D08, 0x2D3A, 0x2D1D, 0x2D10, 0x1C3B, 0x2CF8, 0x2D00, + 0x2952, 0x187B, 0x1879, 0x022A, 0x1870, 0x2954, 0x1C41, 0x1881, 0x186A, 0x186C, + 0x36E4, 0x36E6, 0x186B, 0x1883, 0x36D5, 0x36EE, 0x36D4, 0x36EC, 0x36D3, 0x36D6, + 0x345D, 0x3473, 0x3457, 0x01F5, 0x345E, 0x47DC, 0x36D7, 0x0B5B, 0x0209, 0x0215, + 0x47D6, 0x47DB, 0x47D8, 0x0B61, 0x47DA, 0x01DF, 0x36D8, 0x3460, 0x36DC, 0x3461, + 0x345C, 0x36DA, 0x345B, 0x0B5E, 0x36F0, 0x1869, 0x3462, 0x36F1, 0x0B49, 0x022A, + 0x36DE, 0x47DD, 0x01C9, 0x01DF, 0x345A, 0x3459, 0x3469, 0x3464, 0x3465, 0x3468, + 0x3458, 0x345F, 0x346F, 0x3466, 0x36DD, 0x346D, 0x0198, 0x01A2, 0x0203, 0x186D, + 0x0215, 0x0B6A, 0x0B6D, 0x0209, 0x0215, 0x021F, 0x01C9, 0x0234, 0x3463, 0x17BA, + 0x17CD, 0x348B, 0x17B9, 0x17D2, 0x0198, 0x0234, 0x0215, 0x0209, 0x17D4, 0x17D0, + 0x17D1, 0x021F, 0x17CF, 0x17CE, 0x17B8, 0x343F, 0x0140, 0x17C9, 0x344A, 0x343D, + 0x01F5, 0x17C8, 0x0142, 0x17C6, 0x17C7, 0x17CA, 0x17D5, 0x343C, 0x17CB, 0x17CC, + 0x01C9, 0x01DF, 0x0143, 0x0144, 0x17BB, 0x01A2, 0x17D7, 0x17D8, 0x0145, 0x17E0, + 0x17E2, 0x343B, 0x17D6, 0x346A, 0x346E, 0x17DC, 0x17E4, 0x3467, 0x17D3, 0x17E7, + 0x346C, 0x17DA, 0x3477, 0x0146, 0x3449, 0x346B, 0x3476, 0x3475, 0x347C, 0x01C9, + 0x022A, 0x17E1, 0x347D, 0x347E, 0x3445, 0x3444, 0x3446, 0x1867, 0x1866, 0x347F, + 0x3482, 0x3481, 0x3486, 0x3480, 0x3488, 0x348A, 0x1874, 0x348C, 0x3487, 0x3489, + 0x3485, 0x1DC8, 0x348E, 0x348D, 0x01DF, 0x1DAA, 0x1871, 0x186F, 0x3483, 0x3484, + 0x1873, 0x0B1C, 0x186E, 0x0B6E, 0x0B58, 0x0B13, 0x0B1F, 0x0B19, 0x01EC, 0x188B, + 0x1890, 0x1DAE, 0x188A, 0x17E3, 0x17DF, 0x1889, 0x1872, 0x17E6, 0x1DAB, 0x0B70, + 0x17E5, 0x0B25, 0x47DE, 0x0B79, 0x1DA9, 0x0B52, 0x0B82, 0x0B86, 0x0B1A, 0x188D, + 0x188E, 0x188F, 0x0B71, 0x1891, 0x0B8C, 0x47D7, 0x022A, 0x1DBB, 0x0215, 0x0209, + 0x01F5, 0x17BC, 0x17BD, 0x17BE, 0x021F, 0x17BF, 0x17C0, 0x0234, 0x17C1, 0x17C2, + 0x17C3, 0x17C4, 0x17C5, 0x0B38, 0x0B17, 0x47D9, 0x0B4A, 0x0B53, 0x0B5C, 0x0B5F, + 0x0B14, 0x0B47, 0x0B62, 0x0B65, 0x0B68, 0x0B6B, 0x0B59, 0x0B8A, 0x0B56, 0x0B7A, + 0x0141, 0x0B7D, 0x17D9, 0x0B3B, 0x0B80, 0x0B26, 0x0B84, 0x0B77, 0x0B87, 0x0B74, + 0x0B89, 0x0B88, 0x0B8E, 0x0B8D, 0x47D5, 0x0B83, 0x3470, 0x3471, 0x3472, 0x1DDC, + 0x3474, 0x1DD4, 0x1DE0, 0x1DE5, 0x3478, 0x3479, 0x347A, 0x347B, 0x1D9D, 0x1DDF, + 0x1DDE, 0x1DE7, 0x120C, 0x1210, 0x120D, 0x120E, 0x1DB1, 0x1DB4, 0x1DB5, 0x1DC7, + 0x1DBE, 0x1DC1, 0x1DC2, 0x1DC3, 0x1DE8, 0x1DCF, 0x1DCC, 0x0198, 0x01A2, 0x2B34, + 0x2B31, 0x2B74, 0x2B40, 0x2B2E, 0x021F, 0x2B75, 0x2B6F, 0x2B2B, 0x2B70, 0x2B71, + 0x2B43, 0x2B76, 0x2B3D, 0x2B49, 0x2B4F, 0x1DDB, 0x2B55, 0x1DDD, 0x2B67, 0x2B3A, + 0x2B37, 0x2B52, 0x2B72, 0x2B5B, 0x2B46, 0x2B4C, 0x2B73, 0x2B6A, 0x2B6D, 0x2B58, + 0x0198, 0x01A2, 0x01C9, 0x01DF, 0x021F, 0x2AF8, 0x2AF9, 0x2AFA, 0x0234, 0x01F5, + 0x2AF4, 0x11FD, 0x0209, 0x2AF2, 0x2AF6, 0x0215, 0x1211, 0x11FF, 0x11FE, 0x123A, + 0x120F, 0x1215, 0x1201, 0x11FC, 0x022A, 0x1212, 0x1213, 0x1214, 0x1DD6, 0x1216, + 0x1217, 0x1218, 0x2B61, 0x1D94, 0x1243, 0x1238, 0x1DCB, 0x1239, 0x2B6E, 0x1DDA, + 0x1237, 0x1208, 0x1264, 0x1265, 0x1236, 0x1263, 0x1DA6, 0x123D, 0x1DD9, 0x2B5E, + 0x11FB, 0x2B64, 0x1221, 0x1D77, 0x1D79, 0x1D7B, 0x1DB2, 0x1D8D, 0x1D97, 0x1DAC, + 0x1D84, 0x1DB6, 0x1DB7, 0x1DBC, 0x1106, 0x1107, 0x1108, 0x1109, 0x1155, 0x1156, + 0x1157, 0x1158, 0x125E, 0x125F, 0x1260, 0x1261, 0x215C, 0x126B, 0x126C, 0x126D, + 0x1204, 0x1205, 0x120A, 0x1209, 0x120B, 0x1200, 0x123C, 0x1202, 0x215A, 0x2164, + 0x1206, 0x1207, 0x2162, 0x20E4, 0x2166, 0x2168, 0x20CA, 0x0B16, 0x20CE, 0x20D0, + 0x20CC, 0x0B22, 0x20D2, 0x0B2B, 0x0B2E, 0x0B31, 0x0B34, 0x0B37, 0x0B3A, 0x0B40, + 0x0B43, 0x0B46, 0x20DA, 0x20DC, 0x20E6, 0x20E8, 0x20E2, 0x20D4, 0x20D6, 0x20D8, + 0x0B64, 0x0B67, 0x20DE, 0x20E0, 0x2102, 0x0B73, 0x0B76, 0x0B7C, 0x210C, 0x210E, + 0x2110, 0x2136, 0x2114, 0x2134, 0x2118, 0x2138, 0x213A, 0x213C, 0x210A, 0x2140, + 0x2116, 0x2144, 0x213E, 0x2148, 0x0B11, 0x2132, 0x2130, 0x2142, 0x0B1D, 0x0B20, + 0x0B23, 0x0B29, 0x212E, 0x0B2F, 0x0B32, 0x0B35, 0x212C, 0x0B3E, 0x0B41, 0x212A, + 0x214A, 0x214C, 0x214E, 0x2150, 0x2112, 0x2154, 0x2156, 0x2158, 0x211A, 0x211C, + 0x211E, 0x2120, 0x2122, 0x2124, 0x2126, 0x2128, 0x216A, 0x216C, 0x216E, 0x2170, + 0x2172, 0x2174, 0x2152, 0x215E, 0x2169, 0x216B, 0x216D, 0x216F, 0x2171, 0x2173, + 0x2146, 0x2160, 0x4644, 0x4645, 0x4647, 0x464E, 0x463F, 0x4640, 0x4640, 0x4642, + 0x4639, 0x463B, 0x463C, 0x463D, 0x4661, 0x4662, 0x4663, 0x4627, 0x461F, 0x4620, + 0x4621, 0x4622, 0x48CF, 0x4619, 0x461A, 0x461D, 0x4611, 0x4612, 0x4613, 0x4614, + 0x4638, 0x4634, 0x4636, 0x4637, 0x22E0, 0x22DC, 0x4916, 0x22DF, 0x462F, 0x22DD, + 0x22DE, 0x4630, 0x22E7, 0x4631, 0x4915, 0x4748, 0x22E8, 0x22E1, 0x22E2, 0x22E3, + 0x462C, 0x22E5, 0x462D, 0x4629, 0x22F0, 0x22F9, 0x462A, 0x22E9, 0x22F4, 0x22F7, + 0x22F6, 0x22E6, 0x22F8, 0x22F5, 0x22FA, 0x22FB, 0x462A, 0x462A, 0x48CB, 0x4912, + 0x45F6, 0x45F7, 0x45EF, 0x45F0, 0x45F3, 0x45F1, 0x45E6, 0x45EA, 0x45EB, 0x45ED, + 0x45DE, 0x45DC, 0x230F, 0x45DF, 0x2310, 0x490E, 0x2312, 0x230D, 0x230E, 0x4970, + 0x230C, 0x460B, 0x2316, 0x2317, 0x2314, 0x2311, 0x460C, 0x2313, 0x48CE, 0x114D, + 0x4603, 0x45E4, 0x4604, 0x1154, 0x4605, 0x45F9, 0x115A, 0x45FF, 0x4911, 0x4602, + 0x115E, 0x45F8, 0x1160, 0x1161, 0x2319, 0x2315, 0x45FD, 0x490F, 0x48CC, 0x492F, + 0x231A, 0x231B, 0x4713, 0x48E1, 0x4715, 0x470C, 0x470D, 0x470E, 0x4711, 0x4709, + 0x4705, 0x470B, 0x48E0, 0x4700, 0x1178, 0x4706, 0x4708, 0x492E, 0x117C, 0x4721, + 0x117D, 0x117E, 0x4723, 0x471F, 0x4725, 0x491C, 0x4932, 0x471E, 0x4933, 0x471A, + 0x471C, 0x471D, 0x4931, 0x4930, 0x118A, 0x118B, 0x4716, 0x3DD9, 0x3DDA, 0x118F, + 0x1190, 0x1191, 0x3DD3, 0x3DD4, 0x3DD5, 0x3DD6, 0x3DCF, 0x3DD0, 0x3DD1, 0x3DD2, + 0x3DCB, 0x3DCC, 0x3DCD, 0x3DCE, 0x3DE7, 0x3DE8, 0x3DE9, 0x3DEA, 0x3DE3, 0x3DE4, + 0x3DE5, 0x3DE6, 0x3DDF, 0x3DE0, 0x3DE1, 0x3DE2, 0x3DDB, 0x3DDC, 0x3DDD, 0x3DDE, + 0x3E57, 0x3E58, 0x3E59, 0x3E5A, 0x3E53, 0x3E54, 0x3E55, 0x3E56, 0x3E4F, 0x3E50, + 0x3E51, 0x3E52, 0x3E4B, 0x3E4C, 0x3E4D, 0x3E4E, 0x3E63, 0x3E64, 0x3E5F, 0x3E60, + 0x3E61, 0x3E62, 0x3E5B, 0x3E5C, 0x3E5D, 0x3E5E, 0x3B37, 0x3B38, 0x3B39, 0x35B6, + 0x35B5, 0x35B8, 0x35B7, 0x35BA, 0x35B9, 0x35BC, 0x35BB, 0x35BE, 0x35BD, 0x35C0, + 0x35BF, 0x35C2, 0x35C1, 0x35C4, 0x35C3, 0x35C6, 0x35C5, 0x35C8, 0x35C7, 0x35CA, + 0x35C9, 0x35CC, 0x35CB, 0x35CE, 0x35CD, 0x35D0, 0x35CF, 0x35D2, 0x35D1, 0x35D4, + 0x35D3, 0x35D6, 0x35D5, 0x35D8, 0x35D7, 0x3B3A, 0x3B33, 0x35DC, 0x35DB, 0x233D, + 0x233E, 0x233F, 0x235C, 0x235F, 0x2343, 0x235E, 0x235D, 0x35E6, 0x35E5, 0x35E8, + 0x35E7, 0x35EA, 0x35E9, 0x35EC, 0x35EB, 0x35EE, 0x35ED, 0x35F0, 0x35EF, 0x35F2, + 0x35F1, 0x35F4, 0x35F3, 0x234D, 0x2350, 0x234F, 0x2352, 0x2351, 0x235A, 0x2359, + 0x233C, 0x2341, 0x2342, 0x3607, 0x3608, 0x3605, 0x3606, 0x360C, 0x2346, 0x2345, + 0x361E, 0x2347, 0x361D, 0x2364, 0x2360, 0x2370, 0x22EF, 0x2375, 0x2361, 0x2362, + 0x22F2, 0x22ED, 0x22EE, 0x22EC, 0x22C8, 0x3619, 0x22F3, 0x361F, 0x235B, 0x35D9, + 0x35DA, 0x22C9, 0x361A, 0x35DD, 0x35DE, 0x35DF, 0x35E0, 0x35E1, 0x35E2, 0x35E3, + 0x35E4, 0x2395, 0x2396, 0x2397, 0x22F1, 0x2399, 0x239A, 0x3CF3, 0x3CF7, 0x3BAB, + 0x3D26, 0x3BB9, 0x3BB8, 0x3BBA, 0x3BB7, 0x3BB3, 0x3BB4, 0x362E, 0x3BB1, 0x3617, + 0x3618, 0x3632, 0x3631, 0x3630, 0x3ADE, 0x3616, 0x3635, 0x3615, 0x3D1F, 0x3ADD, + 0x361B, 0x3ADB, 0x361C, 0x3638, 0x3636, 0x3639, 0x3637, 0x363C, 0x3628, 0x363D, + 0x3BC7, 0x362A, 0x3BAE, 0x363E, 0x363F, 0x3BC8, 0x363B, 0x363A, 0x362F, 0x362D, + 0x3BAC, 0x362C, 0x3AE1, 0x3624, 0x3AE2, 0x3633, 0x3634, 0x3BAD, 0x3629, 0x3BB5, + 0x3626, 0x3627, 0x3BB2, 0x3BC3, 0x3BC4, 0x3620, 0x362B, 0x3622, 0x3623, 0x3BC9, + 0x3625, 0x3B8B, 0x3B8C, 0x3B8D, 0x3B8E, 0x3B8F, 0x3B90, 0x3B91, 0x3B92, 0x3B93, + 0x3B94, 0x3B95, 0x3B96, 0x35F7, 0x35F8, 0x35F9, 0x35FA, 0x3603, 0x3604, 0x3601, + 0x35FE, 0x3D1E, 0x35FD, 0x35FF, 0x3602, 0x3600, 0x3B9A, 0x3D1D, 0x3D1C, 0x3BA7, + 0x3D1B, 0x3609, 0x360A, 0x360B, 0x35F6, 0x360D, 0x360E, 0x360F, 0x3610, 0x3611, + 0x3612, 0x3613, 0x3614, 0x35F5, 0x3621, 0x3B97, 0x3B98, 0x3B99, 0x3BCA, 0x35FB, + 0x35FC, 0x3BBD, 0x3BBE, 0x3BBC, 0x3BC1, 0x3BBB, 0x3BC2, 0x3D21, 0x3D20, 0x3D22, + 0x3BC6, 0x3BBF, 0x3BC0, 0x3BC5, 0x3DB8, 0x3B4C, 0x3B4B, 0x3B4E, 0x3B4D, 0x3B50, + 0x3B4F, 0x3B52, 0x3B51, 0x3B54, 0x3B53, 0x3B56, 0x3B55, 0x3B58, 0x3B57, 0x3B5A, + 0x3B59, 0x3B9B, 0x3B9C, 0x3B9D, 0x3B9E, 0x3B9F, 0x3BA0, 0x3BA1, 0x3BA2, 0x3B64, + 0x3B63, 0x3BA5, 0x3BA6, 0x3B68, 0x3B67, 0x3B6A, 0x3B69, 0x3B6C, 0x3B6B, 0x3B6E, + 0x3B6D, 0x3B70, 0x3B6F, 0x3B72, 0x3B71, 0x3B74, 0x3B73, 0x3B76, 0x3B75, 0x3B78, + 0x3B77, 0x3B7A, 0x3B79, 0x3B7C, 0x3B7B, 0x3B7E, 0x3B7D, 0x3B80, 0x3B7F, 0x3B82, + 0x3B81, 0x3B84, 0x3B83, 0x3B86, 0x3B85, 0x3B88, 0x3B87, 0x3B8A, 0x3B89, 0x3BA3, + 0x3BA4, 0x3BA9, 0x3BAA, 0x3BA8, 0x3378, 0x3377, 0x337A, 0x3379, 0x337D, 0x337B, + 0x337E, 0x337C, 0x3380, 0x337F, 0x3382, 0x3381, 0x3384, 0x3383, 0x3386, 0x3385, + 0x3389, 0x3387, 0x3388, 0x338A, 0x338C, 0x338B, 0x338E, 0x338D, 0x3390, 0x338F, + 0x3392, 0x3391, 0x3394, 0x3393, 0x3396, 0x3395, 0x3398, 0x3397, 0x339A, 0x3399, + 0x339B, 0x339C, 0x339E, 0x339D, 0x33A0, 0x339F, 0x33A2, 0x33A1, 0x33A4, 0x33A3, + 0x33A6, 0x33A5, 0x33A8, 0x33A7, 0x33AA, 0x33A9, 0x33AC, 0x33AB, 0x33AE, 0x33AD, + 0x33B0, 0x33AF, 0x33B2, 0x33B1, 0x33B4, 0x33B3, 0x33B5, 0x3BD1, 0x3BD2, 0x33BA, + 0x33B7, 0x3BCD, 0x3BD6, 0x33BB, 0x3BCE, 0x3BD4, 0x3BD0, 0x3BDA, 0x33B9, 0x3BDC, + 0x3BDB, 0x3BDE, 0x3BDD, 0x01A2, 0x3BD3, 0x3BE2, 0x33BC, 0x3BE4, 0x3BE6, 0x3BE3, + 0x3BCF, 0x3BE8, 0x3BEA, 0x3BE7, 0x3BE9, 0x01C9, 0x1176, 0x1175, 0x33B8, 0x1177, + 0x117A, 0x1179, 0x1174, 0x117B, 0x01F5, 0x0209, 0x118E, 0x3BD7, 0x3BD8, 0x3BD9, + 0x0215, 0x021F, 0x10F8, 0x3BFE, 0x3BFD, 0x10F9, 0x10F7, 0x1102, 0x3C01, 0x10FD, + 0x10FF, 0x10FE, 0x1101, 0x1100, 0x10FC, 0x10FB, 0x10FA, 0x3D0B, 0x3D0C, 0x3D0E, + 0x33B6, 0x3D0F, 0x3D10, 0x3D0D, 0x3D12, 0x3D13, 0x3D14, 0x3D15, 0x3D16, 0x3D17, + 0x3D18, 0x3D11, 0x3D1A, 0x10F6, 0x10E5, 0x10E9, 0x10EC, 0x10E8, 0x1103, 0x1104, + 0x1105, 0x3D23, 0x3D24, 0x3D25, 0x3D19, 0x3D27, 0x3D28, 0x3D29, 0x3D2A, 0x3D2B, + 0x3D2C, 0x3D2D, 0x3D30, 0x3D31, 0x3D32, 0x3D33, 0x3D34, 0x3D35, 0x3D36, 0x3D37, + 0x3D38, 0x3D39, 0x3D3A, 0x3D3B, 0x3D3C, 0x3D3D, 0x3D3E, 0x3D3F, 0x3D40, 0x3D41, + 0x3D42, 0x3D43, 0x3D44, 0x3D45, 0x3D46, 0x3D47, 0x3D48, 0x3D49, 0x3D4A, 0x3D4B, + 0x3D4C, 0x1114, 0x1145, 0x1138, 0x113C, 0x1151, 0x1184, 0x10EA, 0x10EB, 0x1147, + 0x1113, 0x1149, 0x10F0, 0x114A, 0x1148, 0x1170, 0x1119, 0x113E, 0x11D3, 0x11D4, + 0x11D9, 0x11DA, 0x11D7, 0x110C, 0x110D, 0x110E, 0x110B, 0x1111, 0x11DD, 0x11DE, + 0x11DF, 0x1112, 0x11DC, 0x11D8, 0x3CAC, 0x1116, 0x11E8, 0x111E, 0x11E7, 0x110F, + 0x1115, 0x111A, 0x11F3, 0x11F2, 0x11E1, 0x112D, 0x11E0, 0x11E2, 0x11F9, 0x11F8, + 0x121D, 0x1182, 0x1187, 0x1186, 0x122A, 0x1188, 0x121F, 0x1220, 0x121E, 0x1226, + 0x1222, 0x1224, 0x1244, 0x1245, 0x1246, 0x3C8C, 0x3C8B, 0x3C8E, 0x3C8D, 0x3C90, + 0x3C8F, 0x3C92, 0x3C91, 0x3C94, 0x3C93, 0x3C96, 0x3C95, 0x3C98, 0x3C97, 0x3C9A, + 0x3C99, 0x123F, 0x1240, 0x1241, 0x1242, 0x3CA0, 0x3C9F, 0x123B, 0x3CA1, 0x3CA4, + 0x3CA3, 0x3CA6, 0x3CA5, 0x3CA8, 0x3CA7, 0x3CAA, 0x3CA9, 0x2BB5, 0x3CAB, 0x3CAE, + 0x3CAD, 0x3CB0, 0x3CAF, 0x3CB2, 0x3CB1, 0x3CB4, 0x3CB3, 0x3CB6, 0x3CB5, 0x3CB8, + 0x3CB7, 0x3CBA, 0x3CB9, 0x3CBC, 0x3CBB, 0x3CBE, 0x3CBD, 0x3CC0, 0x3CBF, 0x3CC2, + 0x3CC1, 0x3CC4, 0x3CC3, 0x3CC6, 0x3CC5, 0x3CC8, 0x3CC7, 0x3CCA, 0x3CC9, 0x3CCC, + 0x3CCB, 0x1262, 0x1268, 0x3CD0, 0x3CCF, 0x3CCD, 0x3CCE, 0x3CD4, 0x3CD3, 0x3CD6, + 0x3CD5, 0x1266, 0x1269, 0x3CD1, 0x3CD2, 0x3CDC, 0x3CDB, 0x3CDE, 0x3CDD, 0x3CE0, + 0x3CDF, 0x3CE2, 0x3CE1, 0x3CE4, 0x3CE3, 0x3CE6, 0x3CE5, 0x3CE8, 0x3CE7, 0x3CEA, + 0x3CE9, 0x1223, 0x118D, 0x3CFD, 0x1271, 0x1270, 0x1185, 0x1267, 0x3CFC, 0x118C, + 0x126F, 0x1227, 0x1228, 0x1229, 0x122C, 0x122B, 0x3CDA, 0x122D, 0x0063, 0x0234, + 0x0062, 0x0065, 0x1181, 0x005F, 0x1183, 0x0061, 0x3CFE, 0x125A, 0x2BAF, 0x2BB0, + 0x2BB1, 0x3CD9, 0x2BB3, 0x3CEB, 0x3CEC, 0x2BB6, 0x2BB2, 0x3CEF, 0x3CF0, 0x3CED, + 0x3CEE, 0x3D03, 0x3CF4, 0x3CF5, 0x3CF6, 0x2BAD, 0x2BAE, 0x3CF1, 0x3CF2, 0x3CFB, + 0x3CFF, 0x3CF9, 0x3CFA, 0x2BAB, 0x3D00, 0x3D01, 0x3D02, 0x3D04, 0x2BAC, 0x3D05, + 0x3D06, 0x3D07, 0x3D08, 0x3D09, 0x3D0A, 0x125C, 0x2C39, 0x2C3B, 0x005D, 0x005C, + 0x2C3A, 0x005E, 0x0060, 0x0066, 0x3CF8, 0x022A, 0x01DF, 0x3CD7, 0x3CD8, 0x125B, + 0x0064, 0x125D, 0x124E, 0x124F, 0x1250, 0x1251, 0x1252, 0x1253, 0x1254, 0x1255, + 0x1256, 0x1259, 0x1258, 0x2C3F, 0x1257, 0x2C38, 0x2BB4, 0x3D4E, 0x3D4D, 0x3D75, + 0x3D9B, 0x3D52, 0x3D51, 0x3D4F, 0x3D50, 0x3D56, 0x3D55, 0x3D58, 0x3D57, 0x3D5A, + 0x3D59, 0x3D53, 0x3D54, 0x3D5E, 0x3D5D, 0x3D60, 0x3D5F, 0x3D62, 0x3D61, 0x3D64, + 0x3D63, 0x3D66, 0x3D65, 0x3D68, 0x3D67, 0x3D6A, 0x3D69, 0x3D6C, 0x3D6B, 0x3D6E, + 0x3D6D, 0x3D70, 0x3D6F, 0x3D72, 0x3D71, 0x3D74, 0x3D73, 0x3D76, 0x3D86, 0x3D78, + 0x3D77, 0x3D7A, 0x3D79, 0x3D7C, 0x3D7B, 0x3D7E, 0x3D7D, 0x3D80, 0x3D7F, 0x3D82, + 0x3D81, 0x3D84, 0x3D83, 0x3D5C, 0x3D85, 0x3D88, 0x3D87, 0x3D8A, 0x3D89, 0x3D8C, + 0x3D8B, 0x3D8E, 0x3D8D, 0x3D90, 0x3D8F, 0x3D92, 0x3D91, 0x3DB3, 0x3D93, 0x3D96, + 0x3DA4, 0x3D98, 0x3D97, 0x3D9A, 0x3D99, 0x3D9C, 0x3D94, 0x3D9E, 0x3D5B, 0x3DA0, + 0x3D9F, 0x3D2F, 0x3D2E, 0x3DA2, 0x3DA1, 0x3D9D, 0x3DA3, 0x3DA6, 0x3DA5, 0x3DA8, + 0x3DA7, 0x3DAA, 0x3DA9, 0x3DAD, 0x3DAB, 0x3DAE, 0x3DC8, 0x3DB1, 0x3DAF, 0x3DB2, + 0x3DAC, 0x3DB5, 0x3DC4, 0x3DB6, 0x3DB0, 0x3DBA, 0x3DB7, 0x3DC9, 0x3DB4, 0x3DBC, + 0x3DBB, 0x3DBE, 0x3DBD, 0x3DC0, 0x3DBF, 0x3DC2, 0x3DC1, 0x3D95, 0x3DC3, 0x3DC6, + 0x3DC5, 0x3DCA, 0x3DC7, 0x4919, 0x4918, 0x466C, 0x3DD7, 0x3DEF, 0x3E1A, 0x48D0, + 0x466F, 0x4671, 0x48D1, 0x3DD8, 0x4673, 0x4675, 0x491A, 0x4677, 0x4676, 0x491B, + 0x4679, 0x4626, 0x4625, 0x467C, 0x46A1, 0x467E, 0x48D2, 0x4684, 0x4682, 0x491D, + 0x4683, 0x491E, 0x4686, 0x4688, 0x4689, 0x469E, 0x4928, 0x3DF7, 0x3DEB, 0x3DEE, + 0x3DED, 0x3DF0, 0x3DEC, 0x3DF2, 0x3DF1, 0x3E03, 0x3DF3, 0x3DF6, 0x3DF5, 0x3DF8, + 0x3DF4, 0x3DFA, 0x3DF9, 0x3DFF, 0x3DFB, 0x3DFE, 0x3DFD, 0x3E00, 0x3DFC, 0x3E02, + 0x3E01, 0x3E07, 0x4921, 0x3E06, 0x3E05, 0x3E08, 0x3E04, 0x3E0A, 0x3E09, 0x3E0C, + 0x3E0B, 0x3E0E, 0x3E0D, 0x3E10, 0x3E0F, 0x3E12, 0x3E11, 0x3E14, 0x3E24, 0x3E16, + 0x3E15, 0x3E18, 0x3E17, 0x3E2F, 0x3E19, 0x3E1C, 0x3E1B, 0x3E1E, 0x3E1D, 0x3E20, + 0x3E1F, 0x3E22, 0x3E21, 0x3DB9, 0x3E23, 0x3E26, 0x3E25, 0x3E28, 0x3E27, 0x3E2A, + 0x3E29, 0x3E2C, 0x3E2B, 0x3E2E, 0x3E2D, 0x3E30, 0x3E40, 0x3E32, 0x3E31, 0x3E34, + 0x3E33, 0x3E36, 0x3E35, 0x3E38, 0x3E37, 0x3E3A, 0x3E39, 0x3E3C, 0x3E3B, 0x3E3E, + 0x3E3D, 0x3E13, 0x3E3F, 0x3E42, 0x3E41, 0x3E44, 0x3E43, 0x3E46, 0x3E45, 0x3E48, + 0x3E47, 0x3E4A, 0x3E49, 0x468E, 0x48D3, 0x468A, 0x468D, 0x4691, 0x4692, 0x48D4, + 0x491F, 0x48D5, 0x4695, 0x468F, 0x4690, 0x46AA, 0x497A, 0x4696, 0x4697, 0x4921, + 0x47F2, 0x46A0, 0x46A0, 0x48D6, 0x46C7, 0x4952, 0x46A2, 0x48ED, 0x48D7, 0x46A6, + 0x46A9, 0x46AC, 0x46A4, 0x472D, 0x4729, 0x472B, 0x472A, 0x472F, 0x472E, 0x4728, + 0x4934, 0x4736, 0x4735, 0x473A, 0x48E3, 0x4935, 0x4739, 0x4740, 0x493A, 0x4937, + 0x4936, 0x4746, 0x4741, 0x4744, 0x4745, 0x4747, 0x48E4, 0x4749, 0x474A, 0x4910, + 0x474C, 0x4938, 0x474F, 0x476C, 0x4752, 0x4759, 0x4757, 0x493B, 0x475A, 0x4733, + 0x475C, 0x493D, 0x493C, 0x4765, 0x4763, 0x4766, 0x48E5, 0x48E6, 0x475D, 0x476D, + 0x48E9, 0x4770, 0x476F, 0x48E7, 0x4773, 0x493E, 0x4775, 0x493F, 0x4624, 0x4920, + 0x477A, 0x4940, 0x477C, 0x4942, 0x4941, 0x4777, 0x48E8, 0x4944, 0x4787, 0x4784, + 0x4943, 0x4786, 0x48EC, 0x4946, 0x4787, 0x48EB, 0x478E, 0x4789, 0x478A, 0x494C, + 0x48F3, 0x4948, 0x47AB, 0x48EE, 0x4791, 0x4799, 0x4949, 0x494B, 0x494A, 0x47A3, + 0x47A0, 0x47A5, 0x48EF, 0x47A7, 0x47A6, 0x47BF, 0x4945, 0x494D, 0x494D, 0x478C, + 0x48E6, 0x47AF, 0x47AE, 0x48F0, 0x494E, 0x48F2, 0x47B5, 0x47B7, 0x47B9, 0x4951, + 0x47BA, 0x48F1, 0x494F, 0x47C4, 0x47C2, 0x48F4, 0x47C8, 0x4652, 0x4953, 0x4955, + 0x48F5, 0x4956, 0x47CC, 0x47D1, 0x47CE, 0x4957, 0x47E4, 0x47E6, 0x4958, 0x47E8, + 0x4959, 0x48F6, 0x4929, 0x47ED, 0x495A, 0x47EE, 0x48F8, 0x47EC, 0x4670, 0x492A, + 0x495B, 0x47F2, 0x47F8, 0x4860, 0x47F3, 0x480B, 0x48F9, 0x47F9, 0x47F7, 0x48FB, + 0x495C, 0x47FC, 0x47FB, 0x47FA, 0x47FE, 0x47FF, 0x47FD, 0x4805, 0x4810, 0x4806, + 0x4800, 0x4804, 0x4618, 0x4808, 0x4803, 0x480A, 0x4809, 0x495F, 0x495D, 0x48FA, + 0x495E, 0x4813, 0x4812, 0x4963, 0x4815, 0x492B, 0x4816, 0x48FC, 0x48FE, 0x4962, + 0x4961, 0x481D, 0x487E, 0x481F, 0x481E, 0x4822, 0x4820, 0x4824, 0x4821, 0x4827, + 0x4823, 0x4826, 0x4825, 0x48FD, 0x4828, 0x482B, 0x482A, 0x482E, 0x48FF, 0x4964, + 0x482F, 0x4833, 0x4832, 0x4836, 0x4900, 0x4965, 0x4855, 0x4901, 0x4966, 0x483D, + 0x4902, 0x484A, 0x4843, 0x4967, 0x484C, 0x484E, 0x484D, 0x4854, 0x4853, 0x4913, + 0x4969, 0x496D, 0x4856, 0x4914, 0x4858, 0x485D, 0x485A, 0x48CD, 0x4960, 0x486B, + 0x4868, 0x496A, 0x496B, 0x4876, 0x486E, 0x487A, 0x4879, 0x487D, 0x4878, 0x486D, + 0x496C, 0x4903, 0x487F, 0x496E, 0x4881, 0x488C, 0x4904, 0x4891, 0x468B, 0x4971, + 0x496F, 0x4906, 0x4905, 0x4972, 0x4896, 0x4973, 0x4907, 0x4898, 0x4898, 0x3B34, + 0x3B35, 0x3B36, 0x3B2F, 0x3B30, 0x3B31, 0x3B32, 0x3B2B, 0x3B2C, 0x3B2D, 0x3B2E, + 0x3B47, 0x3B48, 0x3B49, 0x3B4A, 0x3B43, 0x3B44, 0x3B45, 0x3B46, 0x3B3F, 0x3B40, + 0x3B41, 0x3B42, 0x3B3B, 0x3B3C, 0x3B3D, 0x3B3E, 0x3B17, 0x3B18, 0x3B19, 0x3B1A, + 0x3B13, 0x3B14, 0x3B15, 0x3B16, 0x3B0F, 0x3B10, 0x3B11, 0x3B12, 0x3B0B, 0x3B0C, + 0x3B0D, 0x3B0E, 0x3B27, 0x3B28, 0x3B29, 0x2BA7, 0x3B2A, 0x3B23, 0x3B24, 0x3B25, + 0x3B26, 0x3B1F, 0x3B20, 0x3B21, 0x3B22, 0x3B1B, 0x3B1C, 0x3B1D, 0x3B1E, 0x3AF7, + 0x3AF8, 0x3AF9, 0x3AFA, 0x3AF3, 0x3AF4, 0x3AF5, 0x3AF6, 0x3AEF, 0x3AF0, 0x3AF1, + 0x2BA8, 0x3AF2, 0x3AEB, 0x3AEC, 0x3AED, 0x3AEE, 0x3B07, 0x3B08, 0x3B09, 0x3B0A, + 0x3B03, 0x3B04, 0x3B05, 0x3B06, 0x3AFF, 0x3B00, 0x3B01, 0x3B02, 0x3AFB, 0x3AFC, + 0x3AFD, 0x3AFE, 0x3AD7, 0x3AD8, 0x3AD9, 0x466B, 0x466D, 0x3EE6, 0x3EE5, 0x3EE8, + 0x3EE7, 0x466A, 0x3EE9, 0x3F0A, 0x4673, 0x3EEE, 0x3EED, 0x3EF0, 0x3EEF, 0x3EF2, + 0x3EF1, 0x3EF4, 0x3EF3, 0x3EF6, 0x3EF5, 0x3EF8, 0x3EF7, 0x3EFA, 0x3EF9, 0x3EFC, + 0x3EFB, 0x3EFE, 0x3EFD, 0x3F00, 0x3EFF, 0x3F02, 0x3F09, 0x3F04, 0x3F03, 0x3F06, + 0x3F05, 0x3F08, 0x3F07, 0x3F21, 0x3F1A, 0x3F0C, 0x3ADA, 0x3F10, 0x3F0B, 0x3AD3, + 0x3F0E, 0x3AD4, 0x3AD5, 0x3F0F, 0x3AD6, 0x3F16, 0x3F15, 0x3F18, 0x3F17, 0x3F1C, + 0x46D4, 0x46CB, 0x3F1B, 0x46CA, 0x3F1D, 0x3ACF, 0x3AD0, 0x3F22, 0x46C6, 0x3F24, + 0x3F23, 0x3AD1, 0x3AD2, 0x3ACB, 0x3ACC, 0x4699, 0x3ACD, 0x3ACE, 0x3AE7, 0x3AE8, + 0x3AE9, 0x3AEA, 0x3AE3, 0x3AE4, 0x3AE5, 0x3AE6, 0x3ADF, 0x3AE0, 0x3ADC, 0x3BB6, + 0x3BAF, 0x46C4, 0x3BB0, 0x46C3, 0x3B65, 0x3B66, 0x46CF, 0x3B5F, 0x46D3, 0x3B60, + 0x3B61, 0x3B62, 0x3B5B, 0x3B5C, 0x3B5D, 0x3B5E, 0x3C37, 0x3C38, 0x3C39, 0x3C3A, + 0x3C33, 0x3C34, 0x3C35, 0x3C36, 0x3C2F, 0x3C30, 0x3C31, 0x3C32, 0x3C2B, 0x3C2C, + 0x3C2D, 0x3C2E, 0x3C47, 0x3C48, 0x3C49, 0x3C4A, 0x3C43, 0x3C44, 0x3C45, 0x3C46, + 0x3C3F, 0x3C40, 0x3C41, 0x3C42, 0x46D2, 0x3C3B, 0x3C3C, 0x3C3D, 0x3C3E, 0x3C17, + 0x3C18, 0x3C19, 0x3C1A, 0x3C13, 0x3C14, 0x3C15, 0x3C16, 0x3C0F, 0x3C10, 0x3C11, + 0x3C12, 0x3C0B, 0x3C0C, 0x3C0D, 0x3C0E, 0x3C27, 0x3C28, 0x3C29, 0x3C2A, 0x3C23, + 0x46D0, 0x3C24, 0x3C25, 0x3C26, 0x3C1F, 0x3C20, 0x3C21, 0x3C22, 0x3C1B, 0x3C1C, + 0x3C1D, 0x3C1E, 0x3BF7, 0x3BF8, 0x3BF9, 0x3BFA, 0x3BF3, 0x3BF4, 0x3BF5, 0x3BF6, + 0x3BEF, 0x3BF0, 0x3BF1, 0x3BF2, 0x3BEB, 0x3BEC, 0x3BED, 0x3BEE, 0x3C07, 0x3C08, + 0x3C09, 0x3C0A, 0x3C03, 0x3C04, 0x3C05, 0x3C06, 0x3BFF, 0x3C00, 0x3C02, 0x3BFB, + 0x3BFC, 0x3BD5, 0x3BCB, 0x3BCC, 0x3BE5, 0x3BDF, 0x3BE0, 0x3BE1, 0x3CA2, 0x3C9B, + 0x3C9C, 0x3C9D, 0x3C9E, 0x3C77, 0x3C78, 0x3C79, 0x3C7A, 0x3C73, 0x3C74, 0x3C75, + 0x3C76, 0x3C6F, 0x3C70, 0x3C71, 0x3C72, 0x3C6B, 0x3C6C, 0x3C6D, 0x3C6E, 0x3C87, + 0x3C88, 0x3C89, 0x3C8A, 0x3C83, 0x3C84, 0x3C85, 0x3C86, 0x3C7F, 0x3C80, 0x3C81, + 0x3C82, 0x3C7B, 0x3C7C, 0x3C7D, 0x3C7E, 0x3C57, 0x3C58, 0x3C59, 0x3C5A, 0x3C53, + 0x3C54, 0x3C55, 0x3C56, 0x3C4F, 0x3C50, 0x3C51, 0x3C52, 0x3C4B, 0x2BB8, 0x2BB7, + 0x2BBA, 0x2BB9, 0x2BBC, 0x2BBB, 0x3C4C, 0x2BBD, 0x3C4D, 0x3C4E, 0x2C33, 0x2C50, + 0x2C35, 0x2C34, 0x2C37, 0x2C36, 0x3C67, 0x3C68, 0x3C69, 0x3C6A, 0x2C3D, 0x2C3C, + 0x2C57, 0x2C3E, 0x2C41, 0x2C40, 0x2C43, 0x2C42, 0x2C45, 0x2C44, 0x2C47, 0x2C46, + 0x2C49, 0x2C48, 0x2C4B, 0x2C4A, 0x2C4D, 0x2C4C, 0x2C51, 0x2C4E, 0x2C60, 0x2C55, + 0x2C53, 0x2C52, 0x2BA9, 0x2C56, 0x2C54, 0x2BAA, 0x2C59, 0x2C58, 0x2C5B, 0x2C5A, + 0x2C5D, 0x2C5C, 0x2C5F, 0x2C5E, 0x2C61, 0x2C62, 0x2C63, 0x3C63, 0x3C64, 0x3C65, + 0x3C66, 0x2C4F, 0x460D, 0x47B6, 0x46CE, 0x48D9, 0x465A, 0x48D8, 0x46B1, 0x46B0, + 0x46B2, 0x46B7, 0x46B8, 0x46B9, 0x46B8, 0x46BC, 0x46BD, 0x4922, 0x46BF, 0x46C0, + 0x46C2, 0x4694, 0x4894, 0x47B4, 0x47D0, 0x46F3, 0x464F, 0x479B, 0x48C4, 0x4925, + 0x46C1, 0x464A, 0x4649, 0x46D6, 0x46DB, 0x4926, 0x46DD, 0x46DA, 0x46D8, 0x48DA, + 0x46DF, 0x46E1, 0x46E3, 0x46E0, 0x48DB, 0x46E5, 0x46E7, 0x4927, 0x46EC, 0x46F6, + 0x46EE, 0x48DE, 0x46F1, 0x48DD, 0x48DC, 0x4600, 0x4601, 0x46F7, 0x46F2, 0x47EB, + 0x48F7, 0x46F8, 0x46F9, 0x46FA, 0x46FE, 0x46FC, 0x492C, 0x48DF, 0x4703, 0x467B, + 0x4954, 0x465F, 0x4660, 0x467A, 0x4655, 0x483B, 0x4668, 0x469B, 0x4674, 0x4727, + 0x485E, 0x4653, 0x4650, 0x478F, 0x45F4, 0x483C, 0x4646, 0x48E2, 0x4717, 0x4837, + 0x4884, 0x465E, 0x4651, 0x482D, 0x48BF, 0x4654, 0x460D, 0x48C0, 0x48C7, 0x46B1, + 0x4605, 0x4864, 0x461D, 0x0E3A, 0x4682, 0x486C, 0x48C9, 0x4680, 0x4659, 0x464B, + 0x45FE, 0x489F, 0x46BB, 0x4648, 0x45F6, 0x45F3, 0x45E7, 0x461A, 0x45EA, 0x4643, + 0x47C3, 0x4846, 0x461F, 0x488A, 0x45FA, 0x46BD, 0x4656, 0x4625, 0x4649, 0x48C6, + 0x3C5F, 0x3C60, 0x3C61, 0x3C62, 0x3C5B, 0x3C5C, 0x3C5D, 0x3C5E, 0x0210, 0x021C, + 0x0226, 0x0231, 0x01B3, 0x01D1, 0x01E6, 0x01FC, 0x0D05, 0x0D15, 0x0D16, 0x01E8, + 0x0D18, 0x0D3B, 0x0D3D, 0x0D63, 0x0D72, 0x0D71, 0x01E9, 0x0D73, 0x01EA, 0x0D64, + 0x01EB, 0x0DDD, 0x0F8A, 0x0FFE, 0x0FA7, 0x0FA6, 0x0FA9, 0x4917, 0x0FFD, 0x0FFC, + 0x0E77, 0x0E87, 0x0E88, 0x01D9, 0x0DDF, 0x01DA, 0x0E05, 0x0E04, 0x01E6, 0x01E7, + 0x01D5, 0x01D6, 0x4758, 0x0FA8, 0x01D7, 0x01D8, 0x01D2, 0x476B, 0x01D3, 0x01D4, + 0x0E56, 0x0030, 0x0035, 0x0032, 0x0C8E, 0x0DEF, 0x0DCE, 0x0C8F, 0x0CF0, 0x0CBC, + 0x0C95, 0x473E, 0x3EEB, 0x3EEC, 0x0D00, 0x0CEF, 0x3EEA, 0x0CC0, 0x0CBE, 0x0F74, + 0x4734, 0x0ED7, 0x0F18, 0x0F1B, 0x0ED3, 0x0FEF, 0x0009, 0x0E76, 0x472D, 0x0FEE, + 0x0E57, 0x0011, 0x0034, 0x002E, 0x0D65, 0x0033, 0x002D, 0x0D0B, 0x0031, 0x3F01, + 0x0EDA, 0x002F, 0x0DCD, 0x0036, 0x0F4D, 0x012B, 0x4708, 0x0EE8, 0x0DD9, 0x0D0C, + 0x0DDB, 0x0127, 0x0C8D, 0x0CBF, 0x0CC1, 0x0128, 0x0C96, 0x0D04, 0x0CBD, 0x0129, + 0x0EC7, 0x012A, 0x0123, 0x0124, 0x0DDA, 0x0F1F, 0x0F21, 0x0F49, 0x0125, 0x0126, + 0x021F, 0x022A, 0x0234, 0x0122, 0x1C36, 0x1C37, 0x1C38, 0x1C39, 0x1C32, 0x1C33, + 0x1C34, 0x1C35, 0x1C2E, 0x1C2F, 0x1C30, 0x1C31, 0x1C2C, 0x0204, 0x0205, 0x0210, + 0x01FF, 0x0200, 0x0201, 0x0202, 0x01EF, 0x01FC, 0x01FD, 0x01FE, 0x01ED, 0x01EE, + 0x01DF, 0x01F5, 0x0209, 0x02CE, 0x0234, 0x01A2, 0x1892, 0x1893, 0x0EEA, 0x01F5, + 0x188C, 0x1885, 0x1886, 0x0EEB, 0x0EEC, 0x1887, 0x1888, 0x36DF, 0x0EE6, 0x0E55, + 0x0663, 0x0E26, 0x0687, 0x0E3B, 0x36E0, 0x36E1, 0x36E2, 0x36DB, 0x0EE7, 0x36D9, + 0x1868, 0x2936, 0x2937, 0x2938, 0x2931, 0x2932, 0x2933, 0x2934, 0x292D, 0x292E, + 0x4751, 0x292F, 0x2930, 0x2945, 0x4795, 0x4797, 0x4796, 0x4798, 0x2941, 0x2942, + 0x2943, 0x2944, 0x293D, 0x293E, 0x293F, 0x2940, 0x2919, 0x291A, 0x291B, 0x291C, + 0x2915, 0x2916, 0x2917, 0x2918, 0x2911, 0x2912, 0x2913, 0x4847, 0x4851, 0x4852, + 0x4862, 0x4864, 0x488E, 0x4897, 0x489B, 0x46AF, 0x4939, 0x47F4, 0x2914, 0x290D, + 0x45DA, 0x290E, 0x290F, 0x2910, 0x45F5, 0x2929, 0x4619, 0x292A, 0x4643, 0x463E, + 0x4642, 0x292B, 0x4657, 0x465B, 0x4664, 0x4667, 0x292C, 0x2925, 0x2926, 0x2927, + 0x2928, 0x2921, 0x2922, 0x2923, 0x2924, 0x291D, 0x291E, 0x291F, 0x2920, 0x2962, + 0x2963, 0x295E, 0x295F, 0x2960, 0x2961, 0x295A, 0x295B, 0x295C, 0x295D, 0x2956, + 0x2957, 0x2958, 0x2959, 0x1C46, 0x1C47, 0x1C48, 0x1C49, 0x1C42, 0x1C43, 0x1C44, + 0x1C45, 0x1C3E, 0x1C3F, 0x1C40, 0x294F, 0x2950, 0x2951, 0x294A, 0x294B, 0x294C, + 0x294D, 0x2946, 0x2947, 0x2948, 0x0E20, 0x0E3E, 0x0E3C, 0x2949, 0x0E54, 0x17DD, + 0x022A, 0x0234, 0x01F5, 0x0209, 0x0215, 0x17DB, 0x17DE, 0x2CE7, 0x2CEA, 0x2CED, + 0x2CC1, 0x0E75, 0x2CC6, 0x2CCA, 0x0E73, 0x2D0E, 0x2D0D, 0x2C92, 0x2C98, 0x2C99, + 0x2C9E, 0x0E85, 0x022A, 0x0234, 0x01F5, 0x0209, 0x0215, 0x021F, 0x3443, 0x3440, + 0x3441, 0x3442, 0x343E, 0x3437, 0x3438, 0x3439, 0x343A, 0x3453, 0x3454, 0x3455, + 0x3456, 0x344F, 0x3450, 0x3451, 0x3452, 0x344B, 0x344C, 0x344D, 0x344E, 0x3447, + 0x3448, 0x2D47, 0x2D4B, 0x2D4F, 0x2D50, 0x2D36, 0x2D3B, 0x2D3F, 0x2D43, 0x2D2A, + 0x2D2E, 0x2D30, 0x2D34, 0x2D1E, 0x2D21, 0x2D24, 0x2D28, 0x2CA3, 0x2D55, 0x2D58, + 0x2D5B, 0x2C76, 0x2C88, 0x2C9A, 0x2D51, 0x2D54, 0x2D57, 0x2D5A, 0x2D5E, 0x2CE5, + 0x2CE8, 0x2CEB, 0x2CF1, 0x2CDA, 0x2CDB, 0x2CDE, 0x2CE1, 0x2CCF, 0x2CD0, 0x2CD4, + 0x2CD5, 0x2CC3, 0x2CC7, 0x2CC8, 0x2CCD, 0x2D12, 0x47C9, 0x2C95, 0x2C9B, 0x2C9C, + 0x2CA0, 0x2D45, 0x47C3, 0x2D39, 0x2D3D, 0x2D41, 0x2D27, 0x2D2C, 0x2D2D, 0x2D32, + 0x2775, 0x2748, 0x2805, 0x2806, 0x0E60, 0x2807, 0x2808, 0x2801, 0x0E86, 0x0E9E, + 0x0E9F, 0x0EA0, 0x2802, 0x2803, 0x2804, 0x27FD, 0x27FE, 0x27FF, 0x2800, 0x27D9, + 0x27DA, 0x27DB, 0x27DC, 0x27E6, 0x27E7, 0x27E8, 0x27E1, 0x27E2, 0x27E3, 0x27E4, + 0x27DD, 0x27DE, 0x27DF, 0x27E0, 0x27B9, 0x27BA, 0x27BB, 0x27BC, 0x27B5, 0x27B6, + 0x27B7, 0x27B8, 0x27B1, 0x27B2, 0x27B3, 0x480C, 0x4844, 0x27B4, 0x27AD, 0x27AE, + 0x27AF, 0x27B0, 0x27C9, 0x1000, 0x1001, 0x0D87, 0x27CA, 0x4840, 0x27CB, 0x0007, + 0x27CC, 0x2795, 0x2796, 0x2797, 0x2798, 0x2794, 0x27A8, 0x2875, 0x2876, 0x2877, + 0x2878, 0x2871, 0x2872, 0x2873, 0x2874, 0x286F, 0x2870, 0x2889, 0x288A, 0x2885, + 0x2886, 0x2887, 0x2888, 0x2881, 0x4827, 0x2882, 0x2883, 0x2884, 0x287D, 0x287E, + 0x4838, 0x287F, 0x2880, 0x2859, 0x285A, 0x285B, 0x285C, 0x2855, 0x2856, 0x2857, + 0x2858, 0x2851, 0x2852, 0x2853, 0x2854, 0x284D, 0x284E, 0x47E4, 0x284F, 0x2850, + 0x2869, 0x286A, 0x286B, 0x286C, 0x2865, 0x2866, 0x2867, 0x2868, 0x2861, 0x2862, + 0x2863, 0x2864, 0x285D, 0x285E, 0x285F, 0x2860, 0x2839, 0x283A, 0x283B, 0x283C, + 0x2835, 0x2836, 0x2837, 0x2838, 0x2831, 0x2832, 0x46C9, 0x2833, 0x2834, 0x282D, + 0x282E, 0x282F, 0x2830, 0x2849, 0x284A, 0x284B, 0x284C, 0x2845, 0x2846, 0x2847, + 0x2848, 0x2841, 0x2842, 0x2843, 0x2844, 0x283D, 0x283E, 0x283F, 0x2840, 0x2819, + 0x281A, 0x281B, 0x281C, 0x2815, 0x2816, 0x2817, 0x2818, 0x2811, 0x2812, 0x2813, + 0x2814, 0x280D, 0x280E, 0x280F, 0x2810, 0x2829, 0x282A, 0x282B, 0x282C, 0x2825, + 0x2826, 0x2827, 0x2828, 0x2821, 0x2822, 0x2823, 0x2824, 0x281D, 0x281E, 0x281F, + 0x2820, 0x28F9, 0x28FA, 0x28FB, 0x28FC, 0x28F5, 0x28F6, 0x28F7, 0x28F8, 0x28F1, + 0x28F2, 0x28F3, 0x28F4, 0x28ED, 0x28EE, 0x28EF, 0x28F0, 0x2909, 0x290A, 0x290B, + 0x290C, 0x2905, 0x2906, 0x2907, 0x2908, 0x2901, 0x2902, 0x2903, 0x2904, 0x28FD, + 0x484A, 0x4852, 0x4887, 0x28FE, 0x2B5A, 0x2B5D, 0x28FF, 0x2900, 0x28D9, 0x28DA, + 0x4870, 0x2B66, 0x28DB, 0x28DC, 0x28D5, 0x4877, 0x4894, 0x28D6, 0x4897, 0x28D7, + 0x28D8, 0x2BD4, 0x2BD7, 0x2BDA, 0x28D1, 0x28D2, 0x28D3, 0x28D4, 0x47A9, 0x4898, + 0x48BB, 0x28CD, 0x28CE, 0x28CF, 0x28D0, 0x4789, 0x28E9, 0x28EA, 0x28EB, 0x477D, + 0x2A78, 0x4895, 0x28EC, 0x4788, 0x489B, 0x48A7, 0x48BE, 0x4924, 0x28E5, 0x2BD1, + 0x2A72, 0x2A6F, 0x47B2, 0x2B2D, 0x2BC9, 0x47AD, 0x2A7E, 0x2A7B, 0x4784, 0x2BCE, + 0x2A75, 0x47BE, 0x2BDD, 0x2BC6, 0x28E6, 0x28E7, 0x28E8, 0x28E1, 0x28E2, 0x28E3, + 0x28E4, 0x28DD, 0x28DE, 0x28DF, 0x2B57, 0x28E0, 0x28B9, 0x28BA, 0x28BB, 0x28BC, + 0x28B5, 0x28B6, 0x28B7, 0x28B8, 0x28B1, 0x485D, 0x28B2, 0x28B3, 0x28B4, 0x28AD, + 0x28AE, 0x28AF, 0x28B0, 0x28C9, 0x28CA, 0x28CB, 0x28CC, 0x28C5, 0x28C6, 0x28C7, + 0x28C8, 0x28C1, 0x28C2, 0x28C3, 0x28C4, 0x28BD, 0x28BE, 0x28BF, 0x28C0, 0x2899, + 0x289A, 0x289B, 0x4923, 0x289C, 0x2B54, 0x2B60, 0x2895, 0x4947, 0x4950, 0x2B63, + 0x2896, 0x48BD, 0x2897, 0x2898, 0x2891, 0x48EB, 0x2B69, 0x2892, 0x4657, 0x2893, + 0x46EF, 0x2CDC, 0x48C3, 0x460A, 0x4761, 0x4781, 0x4794, 0x2CE9, 0x479C, 0x2CFC, + 0x2D0C, 0x47A0, 0x2D18, 0x2D14, 0x2894, 0x48C1, 0x288D, 0x48C2, 0x288E, 0x288F, + 0x2890, 0x28A9, 0x28AA, 0x28AB, 0x28AC, 0x28A5, 0x28A6, 0x28A7, 0x28A8, 0x28A1, + 0x28A2, 0x28A3, 0x28A4, 0x2BC2, 0x289D, 0x289E, 0x289F, 0x28A0, 0x0139, 0x2AA2, + 0x013A, 0x013B, 0x2AA5, 0x2A9F, 0x013C, 0x4776, 0x2AB1, 0x2A8A, 0x2A8D, 0x022A, + 0x4846, 0x4845, 0x4843, 0x2A90, 0x4847, 0x2A96, 0x2A99, 0x2A9C, 0x483C, 0x483F, + 0x2ABE, 0x2A93, 0x0234, 0x0137, 0x0138, 0x01F5, 0x0209, 0x0215, 0x021F, 0x0198, + 0x01A2, 0x01C9, 0x01DF, 0x33BD, 0x013D, 0x013E, 0x013F, 0x33D6, 0x33D8, 0x33DA, + 0x33DC, 0x33CE, 0x33D0, 0x33D2, 0x33D4, 0x33C6, 0x33C8, 0x33CA, 0x33CC, 0x33BE, + 0x33C0, 0x33C2, 0x33C4, 0x33F6, 0x33F8, 0x33FA, 0x33FC, 0x33EE, 0x33F0, 0x33F2, + 0x33F4, 0x33E6, 0x33E8, 0x33EA, 0x33EC, 0x33DE, 0x33E0, 0x33E2, 0x33E4, 0x33D7, + 0x33D9, 0x33DB, 0x33DD, 0x33CF, 0x33D1, 0x33D3, 0x33D5, 0x33C7, 0x33C9, 0x33CB, + 0x33CD, 0x33BF, 0x33C1, 0x33C3, 0x33C5, 0x33F7, 0x33F9, 0x33FB, 0x33FD, 0x33EF, + 0x33F1, 0x33F3, 0x33F5, 0x33E7, 0x33E9, 0x33EB, 0x33ED, 0x33DF, 0x33E1, 0x33E3, + 0x33E5, 0x06E7, 0x029D, 0x048A, 0x029B, 0x03C4, 0x0433, 0x0432, 0x06E8, 0x058B, + 0x0294, 0x05ED, 0x03C5, 0x0466, 0x0465, 0x0468, 0x0540, 0x05C2, 0x06E6, 0x034E, + 0x0588, 0x0529, 0x0351, 0x0671, 0x03C7, 0x03C6, 0x054D, 0x02A1, 0x0670, 0x068B, + 0x068A, 0x0AC5, 0x0AC7, 0x0AC9, 0x0ACB, 0x0ABD, 0x0ABF, 0x0AC1, 0x0AC3, 0x0AB5, + 0x0AB7, 0x0AB9, 0x0ABB, 0x0AAD, 0x0AAF, 0x0AB1, 0x0AB3, 0x0AE5, 0x0AE7, 0x0AE9, + 0x0FA0, 0x0FEA, 0x0FE9, 0x0ADD, 0x0F6F, 0x0FEC, 0x0F71, 0x0C7B, 0x0ADF, 0x0F9E, + 0x0FE7, 0x0AE1, 0x0AE3, 0x0AD5, 0x0AD7, 0x0AD9, 0x0ADB, 0x0ACD, 0x0ACF, 0x0AD1, + 0x0AD3, 0x0AE6, 0x0AE8, 0x0AEA, 0x0ADE, 0x0AE0, 0x0AE2, 0x0AE4, 0x0AD6, 0x0AD8, + 0x0ADA, 0x0ADC, 0x0ACE, 0x0AD0, 0x0AD2, 0x0AD4, 0x0AA5, 0x0ED4, 0x0AA7, 0x0AA9, + 0x0AAB, 0x0A9D, 0x0A9F, 0x0AA1, 0x0AA3, 0x0A95, 0x0A97, 0x0A99, 0x0A9B, 0x0A8D, + 0x0A8F, 0x0A91, 0x0A93, 0x0AA6, 0x0AA8, 0x0AAA, 0x0AAC, 0x0A9E, 0x0AA0, 0x0AA2, + 0x0AA4, 0x0A96, 0x0A98, 0x0A9A, 0x0EDD, 0x0EDE, 0x0EDF, 0x0F6A, 0x0EE3, 0x0F70, + 0x0F50, 0x0F34, 0x0F56, 0x0F5A, 0x0F7C, 0x0F7D, 0x0F7E, 0x0A9C, 0x0FE8, 0x0F83, + 0x0E96, 0x0FE0, 0x0FF3, 0x0FF4, 0x0EBC, 0x0FF8, 0x0A8E, 0x0FFA, 0x0F53, 0x0E94, + 0x0F6D, 0x0ED6, 0x0FF5, 0x0C73, 0x0ED5, 0x0FF9, 0x0CE9, 0x0CE2, 0x0CE4, 0x0EE2, + 0x0E5B, 0x0F9F, 0x0EBD, 0x0D2E, 0x0A90, 0x0E68, 0x0A92, 0x0DDE, 0x0F1D, 0x000D, + 0x0E66, 0x0A94, 0x0DC4, 0x0E12, 0x0E14, 0x0E15, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E30, + 0x0C74, 0x0C75, 0x0C76, 0x0C77, 0x0CAA, 0x0CAB, 0x0CAC, 0x0CAD, 0x0AC6, 0x0AC8, + 0x0ACA, 0x0ACC, 0x0ABE, 0x0AC0, 0x0AC2, 0x0AC4, 0x0E7B, 0x0AB6, 0x0AB8, 0x0ABA, + 0x0ABC, 0x0E7C, 0x0E92, 0x0E93, 0x0AAE, 0x0AB0, 0x0AB2, 0x0CE7, 0x0AB4, 0x08E3, + 0x0904, 0x0903, 0x08E4, 0x0CB0, 0x0CB1, 0x08B9, 0x0C7C, 0x0E48, 0x0918, 0x0917, + 0x091A, 0x0919, 0x0083, 0x08F0, 0x08EF, 0x08F8, 0x08F7, 0x0DC3, 0x0D2F, 0x0D59, + 0x0D5A, 0x0D6A, 0x0D6B, 0x0DBF, 0x0DC1, 0x08FA, 0x08F9, 0x08F2, 0x08F1, 0x08F6, + 0x08F5, 0x08E8, 0x08E7, 0x08EA, 0x08E9, 0x08E0, 0x08DF, 0x08E6, 0x08E5, 0x090E, + 0x090D, 0x0916, 0x0915, 0x090A, 0x0909, 0x090C, 0x090B, 0x0900, 0x08FF, 0x0906, + 0x0905, 0x08FC, 0x08FB, 0x08FE, 0x08FD, 0x08D8, 0x08D7, 0x08DA, 0x08D9, 0x08D4, + 0x08D3, 0x08D6, 0x08D5, 0x08D0, 0x08CF, 0x08D2, 0x08D1, 0x08CC, 0x08CB, 0x08CE, + 0x08CD, 0x08C6, 0x08C5, 0x08DE, 0x08DD, 0x08BC, 0x08BB, 0x08C4, 0x08C3, 0x0914, + 0x08AD, 0x08AC, 0x08DC, 0x08DB, 0x0912, 0x0911, 0x08B1, 0x08B0, 0x08B3, 0x08B2, + 0x08AB, 0x08AE, 0x08A7, 0x1765, 0x10E3, 0x10E4, 0x10B9, 0x10D2, 0x10DF, 0x10E0, + 0x10E1, 0x10E2, 0x174E, 0x174F, 0x1750, 0x1751, 0x174A, 0x174B, 0x174C, 0x174D, + 0x1746, 0x1747, 0x1748, 0x1749, 0x1742, 0x1743, 0x1744, 0x10DC, 0x0E99, 0x0DE9, + 0x10DD, 0x10DE, 0x0CE3, 0x0CF4, 0x0CE5, 0x10D7, 0x0CE8, 0x0CEA, 0x0CEB, 0x0CEC, + 0x0D35, 0x0D30, 0x0D5F, 0x0D5E, 0x0DC2, 0x0DC0, 0x0DD0, 0x0DD4, 0x0E6E, 0x0E95, + 0x0EC1, 0x0DD5, 0x0E50, 0x0E6C, 0x0E6D, 0x0EC2, 0x0DF5, 0x0E7F, 0x0E81, 0x0DC5, + 0x10D8, 0x0DC6, 0x0DE8, 0x10D9, 0x0E13, 0x0E4F, 0x0E4A, 0x0E4B, 0x0E19, 0x0E2F, + 0x0E1C, 0x0E69, 0x0DE5, 0x0E80, 0x0DFA, 0x0DC7, 0x0DFB, 0x0DF3, 0x0E33, 0x0E35, + 0x10DA, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10CE, 0x10CF, 0x10D0, 0x10D1, 0x0B8B, + 0x0B78, 0x0B81, 0x0B85, 0x0B7E, 0x0B27, 0x0B3C, 0x0B51, 0x10BA, 0x10BB, 0x10BC, + 0x10BD, 0x10B5, 0x10B8, 0x10B1, 0x0B3F, 0x0B42, 0x0B45, 0x0B2D, 0x0B30, 0x0B33, + 0x0B36, 0x0B1E, 0x0B21, 0x0B24, 0x0B2A, 0x0B12, 0x0B15, 0x0B18, 0x0B1B, 0x0B6F, + 0x0B72, 0x0B75, 0x0B7B, 0x0B63, 0x0B57, 0x1799, 0x1782, 0x1783, 0x1784, 0x1785, + 0x177B, 0x177C, 0x1780, 0x1781, 0x1777, 0x1778, 0x1779, 0x177A, 0x1773, 0x1774, + 0x1775, 0x1794, 0x178C, 0x12A8, 0x12A9, 0x12A3, 0x12A4, 0x12A5, 0x12A6, 0x12A0, + 0x12A1, 0x12A2, 0x129C, 0x129D, 0x129E, 0x129F, 0x127D, 0x127E, 0x127F, 0x1279, + 0x127A, 0x127B, 0x127C, 0x1276, 0x1277, 0x1278, 0x1272, 0x1273, 0x1274, 0x1275, + 0x296B, 0x128B, 0x128C, 0x128D, 0x1287, 0x1288, 0x1289, 0x128A, 0x1284, 0x1285, + 0x1286, 0x1280, 0x297B, 0x1281, 0x1282, 0x1283, 0x11EB, 0x11FA, 0x1203, 0x1225, + 0x1189, 0x1192, 0x119B, 0x11CC, 0x299F, 0x1133, 0x1159, 0x116A, 0x1173, 0x2994, + 0x2995, 0x10F5, 0x110A, 0x2998, 0x111B, 0x1124, 0x299B, 0x121A, 0x2996, 0x121B, + 0x121C, 0x122E, 0x0D75, 0x0E27, 0x0E28, 0x0E3F, 0x0E40, 0x0DFF, 0x0E00, 0x0E21, + 0x0E03, 0x0E02, 0x0DDC, 0x0D6E, 0x0E3D, 0x0E51, 0x0E52, 0x0E70, 0x123E, 0x0E83, + 0x0D60, 0x0DD6, 0x126E, 0x0DD7, 0x1219, 0x022A, 0x0E82, 0x0E71, 0x0234, 0x0111, + 0x0112, 0x01F5, 0x0209, 0x0215, 0x021F, 0x0198, 0x01A2, 0x01C9, 0x01DF, 0x17AA, + 0x17AB, 0x17AC, 0x17AD, 0x17A6, 0x17A7, 0x17A8, 0x0DE7, 0x17A9, 0x17A2, 0x17A3, + 0x0DCB, 0x0DCA, 0x17A4, 0x0E49, 0x17A5, 0x179E, 0x179F, 0x17A0, 0x17A1, 0x0CA2, + 0x17B6, 0x17B7, 0x17B2, 0x17B3, 0x17B4, 0x17B5, 0x17AE, 0x17AF, 0x17B0, 0x17B1, + 0x16DB, 0x16A3, 0x16A4, 0x16DA, 0x022A, 0x0234, 0x01F5, 0x0209, 0x0215, 0x021F, + 0x0198, 0x01A2, 0x01C9, 0x01DF, 0x16D1, 0x16D2, 0x16D3, 0x16D4, 0x16CD, 0x16CE, + 0x16CF, 0x16D0, 0x16C9, 0x16CA, 0x16CB, 0x16CC, 0x16C5, 0x16C6, 0x16C7, 0x16C8, + 0x16D9, 0x16D5, 0x16D6, 0x16D7, 0x16D8, 0x16B1, 0x16B2, 0x16B3, 0x16B4, 0x16AD, + 0x16AE, 0x16AF, 0x16B0, 0x16A9, 0x16AA, 0x16AB, 0x16AC, 0x16A5, 0x16A6, 0x16A7, + 0x16A8, 0x16C1, 0x16C2, 0x16C3, 0x16C4, 0x16BD, 0x16BE, 0x2DC5, 0x2DC6, 0x2DBF, + 0x2DC0, 0x2DC1, 0x2DC2, 0x2DDB, 0x2DDC, 0x2DDD, 0x2DDE, 0x2DD7, 0x2DD8, 0x2DD9, + 0x2DDA, 0x2DD3, 0x2DD4, 0x2DD5, 0x2DD6, 0x2DCF, 0x2DD0, 0x2DD1, 0x2DD2, 0x2DAB, + 0x2DAC, 0x2DAD, 0x2DAE, 0x2DA7, 0x2DA8, 0x2DA9, 0x2DAA, 0x2DA3, 0x2DA4, 0x2DA5, + 0x2DA6, 0x2D9F, 0x0CFA, 0x0D37, 0x0F2B, 0x2DA0, 0x0DD1, 0x0E1A, 0x0DF6, 0x0E34, + 0x0FF2, 0x0F32, 0x2DA1, 0x0FF1, 0x2DA2, 0x2DBB, 0x2DBC, 0x2DB7, 0x2DB9, 0x2DBA, + 0x2DB3, 0x2DB4, 0x2DB5, 0x2DB6, 0x2DAF, 0x2DB0, 0x2D8B, 0x0E4C, 0x2D8C, 0x2D95, + 0x0E5A, 0x0E4E, 0x2D96, 0x0ED8, 0x0E31, 0x0E53, 0x2D8F, 0x0E5F, 0x2D90, 0x2D91, + 0x2D92, 0x0E5E, 0x2D6A, 0x2D6B, 0x2D6C, 0x0E23, 0x0EC8, 0x0D3C, 0x0E74, 0x2D6E, + 0x2D66, 0x0E22, 0x0DA2, 0x2D67, 0x2D68, 0x2D69, 0x2D62, 0x2D63, 0x0F5F, 0x2E45, + 0x0FC0, 0x2E46, 0x0E25, 0x2E3F, 0x0CA4, 0x2E40, 0x2E41, 0x2E42, 0x2E5B, 0x2E5C, + 0x2E5D, 0x2E5E, 0x2E57, 0x2E58, 0x2E59, 0x2E5A, 0x0ED9, 0x2E53, 0x2E54, 0x2E55, + 0x2E56, 0x2E4F, 0x2E50, 0x2E51, 0x2E52, 0x0E47, 0x2E2B, 0x2E2C, 0x2E2D, 0x2E2E, + 0x2E27, 0x2E28, 0x2E29, 0x2E2A, 0x2E23, 0x2E24, 0x2E25, 0x2E26, 0x0CF5, 0x2E1F, + 0x2E20, 0x2E21, 0x2E22, 0x2E3B, 0x2E3C, 0x2E3D, 0x2E3E, 0x2E37, 0x2E38, 0x0CF6, + 0x2E39, 0x2E3A, 0x2E33, 0x2E34, 0x0CF2, 0x2E35, 0x2E36, 0x2E2F, 0x2E30, 0x2E31, + 0x2E32, 0x2E0B, 0x2E0C, 0x2E0D, 0x2E0E, 0x2E07, 0x2E08, 0x2E09, 0x2E0A, 0x2E03, + 0x2E04, 0x2E05, 0x2E06, 0x2DFF, 0x2E00, 0x2E01, 0x2E02, 0x2E1B, 0x2E1C, 0x2E1D, + 0x2E1E, 0x2E17, 0x2E18, 0x2E19, 0x2E1A, 0x2E13, 0x2E14, 0x2E15, 0x2E16, 0x2E0F, + 0x2E10, 0x2E11, 0x2E12, 0x2DEB, 0x2DEC, 0x2DED, 0x2DEE, 0x2DE7, 0x2DE8, 0x2DE9, + 0x2DEA, 0x2DE3, 0x2DE4, 0x2DE5, 0x2DE6, 0x2DDF, 0x2DE0, 0x2DE1, 0x2DE2, 0x2DFB, + 0x2DFC, 0x2DFD, 0x2DFE, 0x2DF7, 0x2DF8, 0x2DF9, 0x2DFA, 0x2DF3, 0x2DF4, 0x2DF5, + 0x2DF6, 0x2DEF, 0x2DF0, 0x2DF1, 0x2DF2, 0x1712, 0x1713, 0x1715, 0x1717, 0x173F, + 0x1740, 0x1741, 0x173B, 0x173C, 0x173D, 0x173E, 0x1737, 0x1738, 0x1739, 0x173A, + 0x1733, 0x1734, 0x1735, 0x1736, 0x2E6B, 0x2E6C, 0x2E6D, 0x2E6E, 0x2E67, 0x2E68, + 0x2E69, 0x0D36, 0x2E6A, 0x2E63, 0x2E64, 0x1718, 0x172D, 0x172E, 0x1727, 0x1728, + 0x0D33, 0x1729, 0x0F2E, 0x0483, 0x04A7, 0x172A, 0x0F2C, 0x0F29, 0x0F31, 0x0F1E, + 0x0F58, 0x0F4E, 0x0F20, 0x050C, 0x0F2F, 0x0F51, 0x0F4C, 0x0F52, 0x0FA1, 0x1723, + 0x0F4B, 0x1724, 0x0F7A, 0x0FA2, 0x1725, 0x1726, 0x1616, 0x1617, 0x1618, 0x0F2A, + 0x0F4A, 0x0FF6, 0x0F7F, 0x0457, 0x1619, 0x1612, 0x042B, 0x1613, 0x1614, 0x1615, + 0x160E, 0x160F, 0x0286, 0x1610, 0x0F76, 0x02AD, 0x0345, 0x02F8, 0x0392, 0x0370, + 0x0EE1, 0x0EE0, 0x0EC3, 0x0FF7, 0x0E6F, 0x03BC, 0x0411, 0x0F1C, 0x0F6B, 0x0F59, + 0x0F1A, 0x03F4, 0x1611, 0x0EBE, 0x0D34, 0x0D5D, 0x0F72, 0x0FA3, 0x15FB, 0x15FC, + 0x0E6A, 0x0FBF, 0x0FBE, 0x15FD, 0x0E6B, 0x0E72, 0x05A5, 0x0E65, 0x0E5C, 0x0E84, + 0x0E7E, 0x0E7A, 0x0537, 0x054F, 0x0567, 0x15FE, 0x15F7, 0x15F8, 0x15F9, 0x0659, + 0x15FA, 0x15F3, 0x15F4, 0x15F5, 0x15F6, 0x15EF, 0x15F0, 0x15F1, 0x0F26, 0x0F55, + 0x0CFB, 0x0F48, 0x0F22, 0x0F5C, 0x0F28, 0x0F84, 0x0F38, 0x0FA5, 0x0FA4, 0x0FE1, + 0x0F54, 0x0F9D, 0x0F75, 0x0F69, 0x05D6, 0x0618, 0x0FF0, 0x0FE6, 0x0FDF, 0x0FFB, + 0x0F37, 0x067E, 0x0690, 0x0F27, 0x06D0, 0x06B1, 0x0FED, 0x0F36, 0x0F25, 0x0F39, + 0x15F2, 0x160A, 0x160B, 0x160C, 0x160D, 0x1606, 0x1607, 0x1608, 0x1609, 0x1602, + 0x1603, 0x1604, 0x1605, 0x15FF, 0x1600, 0x1601, 0x022A, 0x0234, 0x01F5, 0x0209, + 0x0215, 0x021F, 0x0198, 0x01A2, 0x01C9, 0x01DF, 0x1636, 0x1637, 0x1638, 0x1639, + 0x1632, 0x1633, 0x1634, 0x1635, 0x162E, 0x162F, 0x1630, 0x1631, 0x162A, 0x162B, + 0x162C, 0x162D, 0x1646, 0x1647, 0x1648, 0x1642, 0x1643, 0x1644, 0x1645, 0x163E, + 0x163F, 0x1640, 0x1641, 0x163A, 0x163B, 0x163C, 0x163D, 0x166D, 0x166B, 0x164D, + 0x164E, 0x166C, 0x1667, 0x1668, 0x1669, 0x166A, 0x1626, 0x1627, 0x1628, 0x1629, + 0x1622, 0x1623, 0x1624, 0x1625, 0x161E, 0x161F, 0x1620, 0x1621, 0x161A, 0x161B, + 0x161C, 0x161D, 0x1655, 0x1656, 0x1657, 0x1652, 0x1653, 0x1654, 0x164F, 0x1650, + 0x1651, 0x1649, 0x164A, 0x164B, 0x164C, 0x1664, 0x1665, 0x1666, 0x1660, 0x1661, + 0x1662, 0x1663, 0x165C, 0x165D, 0x165E, 0x165F, 0x1658, 0x1659, 0x165A, 0x165B, + 0x1676, 0x1678, 0x16A2, 0x16A0, 0x16A1, 0x166E, 0x1693, 0x1694, 0x1695, 0x1696, + 0x1690, 0x1691, 0x1692, 0x168C, 0x168D, 0x168E, 0x168F, 0x1688, 0x1689, 0x168A, + 0x168B, 0x169F, 0x169D, 0x169E, 0x169A, 0x169B, 0x169C, 0x1697, 0x1698, 0x1699, + 0x1677, 0x1679, 0x1672, 0x1673, 0x1674, 0x1675, 0x166F, 0x1670, 0x1671, 0x1684, + 0x1685, 0x1686, 0x1687, 0x1680, 0x1681, 0x1682, 0x1683, 0x167C, 0x167D, 0x167E, + 0x167F, 0x167A, 0x167B, 0x0215, 0x021F, 0x022A, 0x0234, 0x01C9, 0x01DF, 0x01F5, + 0x0209, 0x011C, 0x011D, 0x0198, 0x01A2, 0x0118, 0x0119, 0x011A, 0x011B, 0x0114, + 0x0115, 0x0116, 0x0117, 0x021F, 0x022A, 0x0234, 0x0113, 0x01DF, 0x01F5, 0x0209, + 0x0215, 0x01A2, 0x01C9, 0x1835, 0x1836, 0x1837, 0x1838, 0x1831, 0x1832, 0x1833, + 0x1834, 0x182D, 0x182E, 0x182F, 0x1830, 0x1829, 0x182A, 0x182B, 0x182C, 0x183F, + 0x1840, 0x1841, 0x1842, 0x1839, 0x183A, 0x183B, 0x1814, 0x183E, 0x1810, 0x183D, + 0x1825, 0x1826, 0x1827, 0x1828, 0x1821, 0x1822, 0x1823, 0x1824, 0x181D, 0x181E, + 0x181F, 0x1820, 0x1819, 0x181A, 0x181B, 0x181C, 0x36D2, 0x36CE, 0x36CF, 0x36D0, + 0x36D1, 0x36CA, 0x36CB, 0x36CC, 0x36CD, 0x022A, 0x0234, 0x01F5, 0x0209, 0x0215, + 0x021F, 0x0198, 0x01A2, 0x01C9, 0x01DF, 0x36C6, 0x36C7, 0x36C8, 0x36C9, 0x36C2, + 0x36C3, 0x36C4, 0x36C5, 0x36BE, 0x36BF, 0x36C0, 0x36C1, 0x36BA, 0x36BB, 0x36BC, + 0x36BD, 0x1591, 0x1592, 0x1593, 0x1594, 0x158E, 0x158F, 0x1590, 0x158B, 0x1589, + 0x158A, 0x158C, 0x158D, 0x1585, 0x1586, 0x1587, 0x1588, 0x1571, 0x1572, 0x1573, + 0x1574, 0x156D, 0x156E, 0x156F, 0x1570, 0x1569, 0x156A, 0x156B, 0x156C, 0x1568, + 0x1581, 0x1582, 0x1583, 0x1584, 0x157D, 0x157E, 0x157F, 0x1580, 0x1579, 0x157A, + 0x157B, 0x157C, 0x1575, 0x1576, 0x1577, 0x1578, 0x15B1, 0x15B2, 0x15B3, 0x15B4, + 0x15AD, 0x15AE, 0x15AF, 0x15B0, 0x15A9, 0x15AA, 0x15AB, 0x15AC, 0x15A5, 0x15A6, + 0x15A7, 0x15A8, 0x15B5, 0x15B6, 0x15B7, 0x15B8, 0x01E5, 0x1598, 0x1E0D, 0x1E0E, + 0x1E0F, 0x0225, 0x021B, 0x0225, 0x01D0, 0x01E5, 0x01FB, 0x002C, 0x01BB, 0x01BC, + 0x01D1, 0x1DEC, 0x1E05, 0x1E06, 0x1E07, 0x1E08, 0x1E01, 0x1E02, 0x1E03, 0x1E04, + 0x1DFD, 0x1DFE, 0x1DFF, 0x1E00, 0x1DF9, 0x1DFA, 0x1DFB, 0x1DFC, 0x012E, 0x012F, + 0x0130, 0x0131, 0x022A, 0x0234, 0x012C, 0x012D, 0x01F5, 0x0209, 0x0215, 0x021F, + 0x01A2, 0x01C9, 0x01DF, 0x0136, 0x0132, 0x0133, 0x0134, 0x2A12, 0x2A18, 0x0135, + 0x15B9, 0x15EB, 0x2A1D, 0x2A22, 0x2A1C, 0x15EC, 0x2A0D, 0x2A1E, 0x2A0E, 0x15ED, + 0x15EE, 0x022A, 0x29EB, 0x29E4, 0x29E5, 0x0234, 0x15BA, 0x01F5, 0x0209, 0x0215, + 0x29E8, 0x021F, 0x0198, 0x29EA, 0x29E9, 0x01A2, 0x29F4, 0x01C9, 0x29ED, 0x29EC, + 0x29F1, 0x01DF, 0x15E4, 0x15E5, 0x29FC, 0x15E6, 0x29EE, 0x15E7, 0x15E0, 0x15E1, + 0x15E2, 0x15E3, 0x15DC, 0x15DD, 0x2A27, 0x15DE, 0x15DF, 0x15D8, 0x15D9, 0x15DA, + 0x29F3, 0x01B6, 0x01B7, 0x01B8, 0x019E, 0x01B4, 0x15E8, 0x15E9, 0x15EA, 0x0230, + 0x01BA, 0x01BB, 0x01BC, 0x15BB, 0x15D4, 0x15D5, 0x15D6, 0x15D7, 0x15D0, 0x29F0, + 0x01F5, 0x29F2, 0x15D1, 0x15D2, 0x15D3, 0x15CC, 0x15CD, 0x15CE, 0x15CF, 0x15C8, + 0x15C9, 0x15CA, 0x15CB, 0x0070, 0x0071, 0x0072, 0x0073, 0x0234, 0x006D, 0x006E, + 0x006F, 0x0209, 0x0215, 0x021F, 0x022A, 0x01A2, 0x01C9, 0x01DF, 0x01F5, 0x0080, + 0x0081, 0x0082, 0x007C, 0x007D, 0x007E, 0x007F, 0x0078, 0x0079, 0x007A, 0x007B, + 0x0074, 0x0075, 0x0076, 0x0077, 0x020D, 0x0219, 0x0223, 0x022E, 0x01A6, 0x01CD, + 0x01E3, 0x01F9, 0x0021, 0x0022, 0x0023, 0x0025, 0x001D, 0x001E, 0x001F, 0x0020, + 0x01AE, 0x01AF, 0x01B0, 0x01CE, 0x01AA, 0x01AB, 0x01AC, 0x01AD, 0x0238, 0x01A7, + 0x01A8, 0x01A9, 0x259E, 0x259A, 0x259B, 0x259C, 0x259D, 0x2596, 0x2597, 0x2598, + 0x2599, 0x2582, 0x2583, 0x2584, 0x2585, 0x257E, 0x257F, 0x2580, 0x2581, 0x257A, + 0x257B, 0x257C, 0x257D, 0x2576, 0x2577, 0x2578, 0x2579, 0x2592, 0x2593, 0x2594, + 0x2595, 0x258E, 0x258F, 0x2590, 0x2591, 0x258A, 0x258B, 0x258C, 0x258D, 0x2586, + 0x2587, 0x2588, 0x2589, 0x2562, 0x2563, 0x2564, 0x2565, 0x255E, 0x255F, 0x2560, + 0x2561, 0x255A, 0x255B, 0x255C, 0x255D, 0x2556, 0x2557, 0x2558, 0x2559, 0x2572, + 0x2573, 0x2574, 0x2575, 0x256E, 0x256F, 0x2570, 0x2571, 0x256A, 0x256B, 0x256C, + 0x256D, 0x2566, 0x2567, 0x2568, 0x2569, 0x2548, 0x2549, 0x254C, 0x254E, 0x2540, + 0x2542, 0x2544, 0x2545, 0x2538, 0x253A, 0x253C, 0x253E, 0x2530, 0x2532, 0x2534, + 0x2535, 0x0086, 0x0087, 0x0088, 0x0089, 0x01A2, 0x0209, 0x2550, 0x2552, 0x2554, + 0x2508, 0x250A, 0x250C, 0x250E, 0x2500, 0x2502, 0x2503, 0x2504, 0x24F8, 0x24FA, + 0x24FC, 0x24FE, 0x24F0, 0x24F1, 0x24F4, 0x24F6, 0x2527, 0x252A, 0x252B, 0x252C, + 0x2520, 0x2522, 0x2524, 0x2526, 0x2518, 0x251A, 0x251C, 0x251E, 0x2510, 0x2511, + 0x2514, 0x2516, 0x254A, 0x254B, 0x254D, 0x254F, 0x2541, 0x2543, 0x2546, 0x2547, + 0x2539, 0x253B, 0x253D, 0x253F, 0x2531, 0x2533, 0x2536, 0x2537, 0x2551, 0x2553, + 0x2555, 0x2509, 0x250B, 0x250D, 0x250F, 0x2501, 0x2505, 0x2506, 0x2507, 0x24F9, + 0x24FB, 0x24FD, 0x24FF, 0x24F2, 0x24F3, 0x24F5, 0x24F7, 0x2529, 0x252D, 0x252E, + 0x252F, 0x2521, 0x2523, 0x2525, 0x2528, 0x2519, 0x251B, 0x251D, 0x251F, 0x2512, + 0x2513, 0x2515, 0x2517, 0x0232, 0x023B, 0x0206, 0x0211, 0x021D, 0x0227, 0x019F, + 0x395D, 0x395E, 0x395F, 0x3960, 0x3959, 0x395A, 0x395B, 0x395C, 0x3955, 0x3956, + 0x3957, 0x3958, 0x3951, 0x3952, 0x3953, 0x3954, 0x396D, 0x01A2, 0x00F8, 0x3969, + 0x396A, 0x396B, 0x396C, 0x3965, 0x3966, 0x3967, 0x3968, 0x3961, 0x3962, 0x3963, + 0x3964, 0x011E, 0x011F, 0x0120, 0x0121, 0x01A2, 0x01C9, 0x01DF, 0x01F5, 0x0233, + 0x023C, 0x0207, 0x0212, 0x021E, 0x0228, 0x01A0, 0x01BE, 0x01DC, 0x01F1, 0x185E, + 0x185F, 0x1860, 0x1861, 0x185A, 0x185B, 0x185C, 0x185D, 0x1856, 0x1857, 0x1858, + 0x1859, 0x1852, 0x1853, 0x1854, 0x02CF, 0x02F9, 0x0484, 0x03FA, 0x0699, 0x069A, + 0x069B, 0x0664, 0x0665, 0x0666, 0x0667, 0x03F5, 0x02C5, 0x02E7, 0x047D, 0x03E1, + 0x0691, 0x0692, 0x0693, 0x065A, 0x065B, 0x065C, 0x065D, 0x03DC, 0x03DE, 0x03E0, + 0x184E, 0x1850, 0x040E, 0x184B, 0x184C, 0x184D, 0x0300, 0x184A, 0x1844, 0x1845, + 0x1846, 0x01C5, 0x0213, 0x01C7, 0x01DE, 0x01F3, 0x01C6, 0x02D0, 0x032A, 0x06DB, + 0x0425, 0x0276, 0x06DB, 0x0886, 0x0819, 0x03E2, 0x3A65, 0x3A66, 0x3A7B, 0x3A74, + 0x3A77, 0x3A70, 0x3A71, 0x3A73, 0x3A6C, 0x3A6E, 0x0578, 0x053D, 0x0554, 0x0578, + 0x04AB, 0x03FB, 0x03FB, 0x045C, 0x044C, 0x397A, 0x397B, 0x397C, 0x397D, 0x3976, + 0x3977, 0x3978, 0x3979, 0x3972, 0x3973, 0x3974, 0x3975, 0x396E, 0x396F, 0x3970, + 0x3971, 0x398A, 0x01A2, 0x00F9, 0x00FA, 0x3986, 0x3987, 0x3988, 0x3989, 0x3982, + 0x3983, 0x3984, 0x3985, 0x397E, 0x397F, 0x3980, 0x3981, 0x3A44, 0x3A45, 0x3A46, + 0x3A47, 0x3A40, 0x3A41, 0x3A42, 0x3A43, 0x3A3C, 0x3A3D, 0x3A3E, 0x3A3F, 0x3A38, + 0x3A39, 0x3A3A, 0x3A3B, 0x010A, 0x010B, 0x010C, 0x010D, 0x01A2, 0x01C9, 0x01DF, + 0x01F5, 0x3A48, 0x3A49, 0x3A4A, 0x3A2E, 0x3A2F, 0x3A30, 0x3A31, 0x3A2A, 0x3A2B, + 0x3A2C, 0x3A2D, 0x3A26, 0x3A27, 0x3A28, 0x3A29, 0x3A22, 0x3A23, 0x3A24, 0x3A25, + 0x0106, 0x0107, 0x0108, 0x01C9, 0x01DF, 0x006B, 0x0067, 0x3A35, 0x39B7, 0x39B8, + 0x39B9, 0x39BA, 0x39B3, 0x39B4, 0x39B5, 0x39B6, 0x39AF, 0x39B0, 0x39B1, 0x39B2, + 0x39AB, 0x39AC, 0x39AD, 0x05D2, 0x05E5, 0x05D5, 0x05B6, 0x05A3, 0x05E0, 0x05D0, + 0x05AF, 0x059F, 0x05B3, 0x0565, 0x0574, 0x0566, 0x056E, 0x0560, 0x0572, 0x0564, + 0x053A, 0x0535, 0x053B, 0x0536, 0x0500, 0x04D6, 0x04FF, 0x04D5, 0x03F3, 0x03DA, + 0x03EA, 0x03D2, 0x03B8, 0x03AC, 0x03BB, 0x03AF, 0x03BA, 0x03AE, 0x03B6, 0x03AA, + 0x0391, 0x0385, 0x03B7, 0x03AB, 0x0454, 0x0443, 0x0480, 0x0479, 0x0453, 0x0442, + 0x0455, 0x0444, 0x042A, 0x0421, 0x0452, 0x0441, 0x0426, 0x041D, 0x0429, 0x0420, + 0x02F5, 0x02E3, 0x02F7, 0x02E5, 0x02CD, 0x02C3, 0x02F2, 0x02E0, 0x02AB, 0x02A5, + 0x02AC, 0x02A6, 0x0285, 0x025A, 0x02AA, 0x02A4, 0x0339, 0x0327, 0x0321, 0x033C, + 0x0320, 0x02F3, 0x02E1, 0x02F6, 0x02E4, 0x0634, 0x0612, 0x0633, 0x0611, 0x0631, + 0x060F, 0x0632, 0x0610, 0x0636, 0x0614, 0x062D, 0x060B, 0x0507, 0x04DD, 0x0509, + 0x04DF, 0x0215, 0x021F, 0x022A, 0x0673, 0x04E0, 0x0501, 0x04D7, 0x03EF, 0x03D6, + 0x03F2, 0x03D9, 0x0332, 0x0316, 0x0342, 0x0326, 0x0331, 0x0317, 0x0506, 0x0249, + 0x0282, 0x067C, 0x0682, 0x088C, 0x0894, 0x088A, 0x0892, 0x086F, 0x087B, 0x3924, + 0x3925, 0x0848, 0x07CF, 0x0742, 0x3934, 0x3935, 0x392C, 0x392D, 0x392A, 0x3A04, + 0x3A06, 0x3A00, 0x07B4, 0x07AF, 0x07B7, 0x07A0, 0x0793, 0x07DB, 0x07DF, 0x07DD, + 0x07E1, 0x07DA, 0x07DE, 0x07DC, 0x07E0, 0x07C8, 0x07CC, 0x07CA, 0x07CE, 0x07C7, + 0x07CB, 0x07C9, 0x07CD, 0x074C, 0x0754, 0x0750, 0x0758, 0x074B, 0x0753, 0x074E, + 0x0756, 0x0731, 0x0739, 0x0735, 0x073D, 0x0730, 0x0738, 0x0733, 0x073B, 0x077C, + 0x00F2, 0x00F3, 0x0774, 0x0773, 0x0772, 0x0775, 0x0829, 0x0858, 0x085A, 0x0857, + 0x0856, 0x0824, 0x0825, 0x084A, 0x084E, 0x0849, 0x084F, 0x084D, 0x084C, 0x0899, + 0x39E5, 0x39E4, 0x39E7, 0x39DC, 0x46B5, 0x46DC, 0x39DE, 0x39D9, 0x39F5, 0x4751, + 0x39F4, 0x46BD, 0x473C, 0x46C3, 0x46BA, 0x4759, 0x39F6, 0x46D9, 0x0782, 0x39ED, + 0x39EF, 0x39E9, 0x39EA, 0x07E4, 0x07E6, 0x07E3, 0x07E2, 0x07D2, 0x07D6, 0x07D1, + 0x07D7, 0x07D5, 0x07D4, 0x0889, 0x0891, 0x088D, 0x0895, 0x088E, 0x0896, 0x088B, + 0x0893, 0x0870, 0x0878, 0x0874, 0x087C, 0x0875, 0x087D, 0x0872, 0x087A, 0x075F, + 0x07C6, 0x075D, 0x075E, 0x075C, 0x075B, 0x0741, 0x0745, 0x0746, 0x0744, 0x0747, + 0x0743, 0x0748, 0x074D, 0x0755, 0x0751, 0x0759, 0x0752, 0x075A, 0x074F, 0x0757, + 0x0732, 0x073A, 0x0736, 0x073E, 0x0737, 0x073F, 0x0734, 0x073C, 0x07AE, 0x20BE, + 0x20BF, 0x20C0, 0x20B9, 0x20BC, 0x20B5, 0x34F0, 0x0C3B, 0x0C3C, 0x0C3D, 0x0C3E, + 0x0C37, 0x0C38, 0x0C39, 0x0C32, 0x1C54, 0x1C55, 0x1C56, 0x022A, 0x00FD, 0x01C9, + 0x015F, 0x0179, 0x017A, 0x017B, 0x017C, 0x0175, 0x0176, 0x0177, 0x0178, 0x0170, + 0x0171, 0x0173, 0x016F, 0x014A, 0x014B, 0x014C, 0x014D, 0x0234, 0x0147, 0x0148, + 0x0149, 0x0209, 0x0215, 0x021F, 0x022A, 0x01A2, 0x01C9, 0x01DF, 0x1C4B, 0x1C4C, + 0x017D, 0x438F, 0x12FB, 0x12FC, 0x12FC, 0x4384, 0x4387, 0x438A, 0x438C, 0x437B, + 0x437E, 0x4380, 0x4382, 0x436F, 0x4370, 0x4372, 0x4373, 0x4368, 0x436A, 0x436C, + 0x436D, 0x4365, 0x435B, 0x435D, 0x435F, 0x438B, 0x438D, 0x4390, 0x4391, 0x4385, + 0x4386, 0x4388, 0x4389, 0x437D, 0x437F, 0x4381, 0x4383, 0x4375, 0x4377, 0x4379, + 0x437C, 0x3831, 0x3832, 0x3833, 0x3834, 0x382D, 0x382E, 0x382F, 0x3830, 0x3829, + 0x382A, 0x382B, 0x382C, 0x3825, 0x3826, 0x3827, 0x3828, 0x3841, 0x3842, 0x3843, + 0x3844, 0x383D, 0x383E, 0x383F, 0x3840, 0x3839, 0x383A, 0x383B, 0x383C, 0x3835, + 0x3836, 0x3837, 0x3838, 0x3811, 0x3812, 0x3813, 0x3814, 0x380D, 0x380E, 0x380F, + 0x3810, 0x3809, 0x380A, 0x380B, 0x380C, 0x3805, 0x3806, 0x3807, 0x3808, 0x3821, + 0x3822, 0x3823, 0x381D, 0x381E, 0x381F, 0x3818, 0x37F1, 0x37F2, 0x37F3, 0x37F4, + 0x37ED, 0x37EE, 0x37EF, 0x37F0, 0x37E9, 0x37EA, 0x37EB, 0x37EC, 0x37E5, 0x37E6, + 0x37E7, 0x3804, 0x37FD, 0x37FE, 0x3800, 0x37F9, 0x37FA, 0x37FB, 0x37FC, 0x37F5, + 0x37F6, 0x37F7, 0x37D4, 0x37C8, 0x37E1, 0x37E2, 0x37E3, 0x37E4, 0x37DD, 0x37DE, + 0x37DF, 0x37E0, 0x37D9, 0x37DA, 0x37DB, 0x37DC, 0x37D5, 0x37D6, 0x37D7, 0x37D8, + 0x38B1, 0x38B2, 0x38B3, 0x38B4, 0x38AD, 0x38AE, 0x38AF, 0x38B0, 0x38A9, 0x38AA, + 0x38AB, 0x38AC, 0x38A5, 0x38A6, 0x38A7, 0x38A8, 0x38C1, 0x38C2, 0x38C3, 0x38B8, + 0x3891, 0x3892, 0x3893, 0x3894, 0x388D, 0x388E, 0x388F, 0x3890, 0x3889, 0x388A, + 0x388B, 0x388C, 0x3885, 0x3886, 0x3887, 0x3868, 0x3881, 0x3882, 0x3883, 0x3884, + 0x387D, 0x387E, 0x387F, 0x3880, 0x3879, 0x387A, 0x387B, 0x387C, 0x3875, 0x3876, + 0x3877, 0x3878, 0x3851, 0x3852, 0x3853, 0x3854, 0x384D, 0x384E, 0x384F, 0x3850, + 0x3849, 0x384A, 0x384B, 0x384C, 0x3845, 0x3846, 0x3847, 0x3848, 0x3861, 0x3862, + 0x3863, 0x3864, 0x385D, 0x385E, 0x385F, 0x3860, 0x3859, 0x385A, 0x385B, 0x385C, + 0x3855, 0x3856, 0x3857, 0x3858, 0x3916, 0x3917, 0x3918, 0x3919, 0x3912, 0x3913, + 0x3914, 0x3915, 0x3908, 0x3909, 0x390A, 0x390B, 0x3904, 0x3905, 0x3906, 0x3907, + 0x3900, 0x3901, 0x3902, 0x3903, 0x38FC, 0x38FD, 0x38FE, 0x069D, 0x06E0, 0x0296, + 0x0544, 0x0586, 0x05BF, 0x05C8, 0x042F, 0x04B5, 0x02B6, 0x390F, 0x38F1, 0x38F2, + 0x38F3, 0x38EF, 0x38E8, 0x38F9, 0x38FA, 0x38FB, 0x38F5, 0x38F6, 0x38F7, 0x38F8, + 0x38D1, 0x38D2, 0x38D3, 0x38D4, 0x38CD, 0x38CE, 0x38CF, 0x38D0, 0x38C9, 0x38CA, + 0x38CB, 0x38CC, 0x38C5, 0x38C6, 0x38C7, 0x38D8, 0x1F85, 0x1F90, 0x1F91, 0x1F92, + 0x1F8C, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F66, 0x1F67, 0x1F68, 0x1F69, 0x1F62, + 0x1F63, 0x1F64, 0x1F65, 0x1F5E, 0x1F5F, 0x1F60, 0x1F61, 0x1F7A, 0x1F7B, 0x1F7C, + 0x1F7D, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F6E, + 0x1F6F, 0x1F70, 0x1F71, 0x1D15, 0x1D16, 0x1D17, 0x1D18, 0x1D11, 0x1D12, 0x1D13, + 0x1D14, 0x1D0D, 0x1D0E, 0x1D0F, 0x1D10, 0x1D09, 0x1D0A, 0x1D0B, 0x1D0C, 0x1D1D, + 0x1D1E, 0x1D1F, 0x1D19, 0x1D1A, 0x1D1B, 0x1D1C, 0x35A1, 0x35A2, 0x35A3, 0x35A4, + 0x359D, 0x359E, 0x359F, 0x35A0, 0x3599, 0x359A, 0x359B, 0x359C, 0x3595, 0x3596, + 0x3597, 0x3598, 0x35B1, 0x35B3, 0x35B4, 0x35AD, 0x357F, 0x3581, 0x3583, 0x3575, + 0x3577, 0x3579, 0x357B, 0x356D, 0x356F, 0x3571, 0x3573, 0x3565, 0x3567, 0x3569, + 0x356B, 0x3591, 0x3592, 0x3593, 0x358E, 0x358F, 0x3588, 0x353D, 0x353F, 0x3541, + 0x3537, 0x3539, 0x357C, 0x355D, 0x355F, 0x3561, 0x3563, 0x3555, 0x3557, 0x3559, + 0x355B, 0x354D, 0x354F, 0x3551, 0x3553, 0x3545, 0x3547, 0x3549, 0x354B, 0x354E, + 0x3550, 0x3552, 0x3554, 0x3546, 0x3548, 0x354A, 0x354C, 0x353E, 0x3540, 0x3542, + 0x3544, 0x3536, 0x3538, 0x353A, 0x353C, 0x356E, 0x3570, 0x3572, 0x356C, 0x3564, + 0x3556, 0x3558, 0x355A, 0x355C, 0x219D, 0x219F, 0x21A1, 0x2197, 0x2199, 0x1FF3, + 0x1FF4, 0x1FF5, 0x1FEE, 0x21AB, 0x21AE, 0x21B0, 0x21B2, 0x21B4, 0x21A6, 0x21A8, + 0x21AA, 0x21AC, 0x219E, 0x21A0, 0x21A2, 0x1FC7, 0x1FC9, 0x21B8, 0x1FE1, 0x1FE3, + 0x218E, 0x2190, 0x2188, 0x2180, 0x2182, 0x364C, 0x364D, 0x364F, 0x3649, 0x364B, + 0x3646, 0x3647, 0x3641, 0x1D3A, 0x1D3B, 0x1D3C, 0x1D36, 0x1D37, 0x1D37, 0x1D32, + 0x0DBD, 0x0E64, 0x0E46, 0x0FE5, 0x0ED1, 0x0F16, 0x0FBD, 0x0D57, 0x0C9E, 0x0CA8, + 0x36AD, 0x36A6, 0x36A7, 0x1809, 0x180A, 0x180B, 0x1800, 0x1802, 0x1804, 0x1805, + 0x17FC, 0x3689, 0x366A, 0x366B, 0x366C, 0x366D, 0x3666, 0x3667, 0x3668, 0x2038, + 0x203B, 0x2088, 0x208B, 0x203E, 0x208A, 0x208D, 0x2078, 0x207A, 0x0EBA, 0x0D9E, + 0x022A, 0x0234, 0x01F5, 0x0209, 0x0215, 0x021F, 0x0198, 0x01A2, 0x01C9, 0x01DF, + 0x2476, 0x2477, 0x2478, 0x2479, 0x2472, 0x2473, 0x2474, 0x2475, 0x246E, 0x246F, + 0x2470, 0x2471, 0x246A, 0x246B, 0x246C, 0x246D, 0x247E, 0x247F, 0x247A, 0x247B, + 0x247C, 0x247D, 0x2456, 0x2457, 0x2458, 0x2459, 0x2452, 0x2453, 0x2454, 0x2455, + 0x244E, 0x244F, 0x2450, 0x2451, 0x244A, 0x244B, 0x244C, 0x244D, 0x2466, 0x2467, + 0x2468, 0x2469, 0x2462, 0x2463, 0x2464, 0x2465, 0x245E, 0x245F, 0x2460, 0x2461, + 0x245A, 0x245B, 0x245C, 0x245D, 0x20A1, 0x20AA, 0x2062, 0x2063, 0x20A8, 0x20A9, + 0x209C, 0x209E, 0x2061, 0x20A3, 0x2446, 0x2447, 0x2448, 0x2449, 0x2442, 0x0291, + 0x2443, 0x2444, 0x2445, 0x0346, 0x0372, 0x0395, 0x243E, 0x243F, 0x2440, 0x2441, + 0x243A, 0x243B, 0x243C, 0x243D, 0x2094, 0x2096, 0x2097, 0x2099, 0x203A, 0x2081, + 0x204B, 0x206E, 0x2030, 0x06BE, 0x06DB, 0x0267, 0x02A8, 0x02C6, 0x02EF, 0x032A, + 0x036D, 0x0389, 0x03B2, 0x03E2, 0x040E, 0x0424, 0x044C, 0x047E, 0x049C, 0x04E6, + 0x0538, 0x0551, 0x2032, 0x05AC, 0x05DD, 0x061A, 0x065F, 0x067F, 0x0694, 0x06B2, + 0x06D2, 0x0291, 0x02AE, 0x02D0, 0x0300, 0x0346, 0x0372, 0x0395, 0x03BD, 0x03FB, + 0x0412, 0x042D, 0x045C, 0x0485, 0x04AB, 0x0510, 0x053D, 0x0554, 0x0578, 0x05BC, + 0x05E9, 0x063C, 0x0669, 0x0688, 0x069C, 0x202C, 0x06DB, 0x0267, 0x02A8, 0x02C6, + 0x02EF, 0x032A, 0x202D, 0x0389, 0x03B2, 0x03E2, 0x040E, 0x202E, 0x202F, 0x205F, + 0x2060, 0x2095, 0x2098, 0x209B, 0x20A5, 0x2057, 0x204C, 0x20A2, 0x20A4, 0x20A6, + 0x20A7, 0x209A, 0x209D, 0x209F, 0x20A0, 0x02D0, 0x0300, 0x1E61, 0x1E62, 0x1E5D, + 0x1E5E, 0x1E5F, 0x1E60, 0x1E59, 0x1E5A, 0x1E5B, 0x1E5C, 0x1E55, 0x1E56, 0x1E57, + 0x1E58, 0x1E67, 0x1E63, 0x1E64, 0x1E65, 0x1E66, 0x0215, 0x021F, 0x022A, 0x0234, + 0x01C9, 0x01DF, 0x01F5, 0x0209, 0x0198, 0x01A2, 0x1E51, 0x1E46, 0x01DF, 0x00E9, + 0x00EA, 0x00EB, 0x00EC, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E1, 0x00E2, 0x00E3, + 0x00E4, 0x34D8, 0x34D9, 0x34DA, 0x34DB, 0x34D4, 0x34D5, 0x34D6, 0x34D7, 0x34D0, + 0x34D1, 0x34D2, 0x34D3, 0x34CC, 0x34CD, 0x34CE, 0x1CB4, 0x1CB5, 0x1CB6, 0x1CAD, + 0x1CAF, 0x1CB0, 0x1CB1, 0x1CA9, 0x1CAA, 0x1CAB, 0x1CAC, 0x1CA5, 0x1CA7, 0x1CA8, + 0x1CC3, 0x34BA, 0x34AF, 0x34C8, 0x34C9, 0x34CA, 0x34CB, 0x34C4, 0x34C5, 0x34C6, + 0x34C7, 0x34C0, 0x34C1, 0x34C2, 0x34C3, 0x34BC, 0x34BD, 0x34BE, 0x34BF, 0x349B, + 0x349C, 0x349D, 0x349E, 0x3497, 0x3498, 0x3499, 0x349A, 0x3493, 0x3494, 0x3495, + 0x3496, 0x348F, 0x3490, 0x3491, 0x3492, 0x34AB, 0x1F5C, 0x34A8, 0x34A9, 0x34A2, + 0x0B07, 0x0B08, 0x0B09, 0x0B05, 0x0AFE, 0x1F30, 0x1F35, 0x1F3A, 0x1F3F, 0x1F1C, + 0x1F2B, 0x1F08, 0x0F3B, 0x1F51, 0x1F52, 0x1F53, 0x1F4C, 0x0F5D, 0x1F48, 0x1EF9, + 0x1EE5, 0x1EEA, 0x1EEF, 0x1ECC, 0x1ED1, 0x1ED6, 0x0F88, 0x1EDB, 0x1EB8, 0x3526, + 0x3527, 0x2421, 0x2422, 0x2423, 0x241C, 0x241D, 0x241E, 0x241F, 0x2418, 0x2419, + 0x241A, 0x241B, 0x2414, 0x2415, 0x2416, 0x2417, 0x23F0, 0x23F1, 0x23F2, 0x23F3, + 0x0C81, 0x23EC, 0x23ED, 0x23EE, 0x23EF, 0x23E8, 0x23E9, 0x23EA, 0x23EB, 0x23E4, + 0x23E5, 0x23E6, 0x23E7, 0x2400, 0x23F9, 0x23FA, 0x23FB, 0x23F4, 0x23D1, 0x23D2, + 0x23D3, 0x23CC, 0x23CD, 0x23CE, 0x23CF, 0x23C8, 0x23CB, 0x23C4, 0x23C5, 0x3AA2, + 0x3ABB, 0x3AB9, 0x3AB2, 0x3A8D, 0x3A8E, 0x3A8F, 0x3A89, 0x3A8A, 0x3A8B, 0x24CE, + 0x24C4, 0x24DD, 0x24DE, 0x24DF, 0x24D7, 0x24D9, 0x24DA, 0x24DB, 0x24D3, 0x24C5, + 0x24D4, 0x24D6, 0x24CF, 0x24D0, 0x24D1, 0x24D2, 0x24A4, 0x24A5, 0x24A6, 0x24A8, + 0x24A2, 0x24A3, 0x24E1, 0x24E3, 0x249D, 0x249E, 0x249F, 0x24A0, 0x249A, 0x249B, + 0x249C, 0x24E5, 0x24B6, 0x24B9, 0x24E8, 0x248E, 0x2487, 0x3743, 0x373F, 0x371C, + 0x371D, 0x371E, 0x371A, 0x248F, 0x372B, 0x1D07, 0x1CFD, 0x3723, 0x36FE, 0x36FF, + 0x3700, 0x36FA, 0x36FB, 0x36FC, 0x36FD, 0x36F6, 0x36F7, 0x36F8, 0x36F2, 0x36F3, + 0x36F4, 0x3704, 0x37B6, 0x37B7, 0x37B8, 0x37B9, 0x37B2, 0x37B3, 0x37B4, 0x37B5, + 0x37AE, 0x37AF, 0x37B0, 0x37AB, 0x37AC, 0x1CE2, 0x1CE3, 0x1CE4, 0x1CDD, 0x1CD9, + 0x37BD, 0x3796, 0x3797, 0x3798, 0x3799, 0x3792, 0x3793, 0x3794, 0x3795, 0x378E, + 0x378F, 0x3790, 0x378B, 0x378C, 0x37A6, 0x379D, 0x3776, 0x3777, 0x3778, 0x3779, + 0x3772, 0x3773, 0x3774, 0x3775, 0x376E, 0x376F, 0x3770, 0x376B, 0x376C, 0x376D, + 0x3786, 0x3787, 0x3788, 0x3783, 0x3784, 0x377D, 0x3756, 0x3757, 0x3758, 0x3753, + 0x3754, 0x374D, 0x3766, 0x3767, 0x3768, 0x3769, 0x3762, 0x3763, 0x3764, 0x3765, + 0x375E, 0x375F, 0x3760, 0x3761, 0x375A, 0x375B, 0x375C, 0x00CE, 0x00CF, 0x00D0, + 0x00D1, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00C2, + 0x00C3, 0x00C4, 0x1E3E, 0x1E3F, 0x1E40, 0x1E39, 0x1E3B, 0x1E3C, 0x1E35, 0x0209, + 0x00B7, 0x00B8, 0x00B9, 0x0209, 0x0209, 0x00B4, 0x00B5, 0x00B6, 0x00B0, 0x00B1, + 0x00B2, 0x2229, 0x222A, 0x222B, 0x2224, 0x2225, 0x2226, 0x2227, 0x2220, 0x2221, + 0x2222, 0x2223, 0x221C, 0x2231, 0x2232, 0x2233, 0x4849, 0x222D, 0x222E, 0x222F, + 0x2208, 0x2219, 0x4885, 0x02AE, 0x0291, 0x0300, 0x02D0, 0x0372, 0x0346, 0x03BD, + 0x0395, 0x0412, 0x03FB, 0x045C, 0x042D, 0x04AB, 0x0485, 0x053D, 0x0510, 0x0578, + 0x0554, 0x05E9, 0x05BC, 0x0669, 0x063C, 0x069C, 0x0688, 0x06DB, 0x06BE, 0x02A8, + 0x0267, 0x02EF, 0x02C6, 0x036D, 0x032A, 0x03B2, 0x0389, 0x040E, 0x03E2, 0x044C, + 0x0424, 0x049C, 0x047E, 0x0538, 0x04E6, 0x056A, 0x0551, 0x05DD, 0x05AC, 0x065F, + 0x061A, 0x0694, 0x067F, 0x06D2, 0x06B2, 0x02AE, 0x0291, 0x0300, 0x02D0, 0x0372, + 0x0346, 0x03BD, 0x0395, 0x0412, 0x03FB, 0x045C, 0x042D, 0x04AB, 0x0485, 0x053D, + 0x0510, 0x0578, 0x0554, 0x05E9, 0x05BC, 0x0669, 0x063C, 0x069C, 0x0688, 0x06DB, + 0x06BE, 0x02A8, 0x0267, 0x02EF, 0x02C6, 0x036D, 0x032A, 0x0865, 0x0389, 0x040E, + 0x03E2, 0x044C, 0x0424, 0x049C, 0x047E, 0x0538, 0x04E6, 0x056A, 0x0551, 0x05DD, + 0x05AC, 0x065F, 0x061A, 0x0694, 0x067F, 0x06D2, 0x06B2, 0x02AE, 0x0291, 0x0300, + 0x02D0, 0x0372, 0x0346, 0x03BD, 0x0395, 0x0412, 0x03FB, 0x045C, 0x042D, 0x04AB, + 0x0485, 0x053D, 0x0510, 0x0578, 0x0554, 0x05E9, 0x05BC, 0x0669, 0x063C, 0x069C, + 0x0688, 0x221A, 0x221B, 0x2214, 0x2215, 0x2216, 0x2217, 0x2210, 0x2211, 0x2212, + 0x2213, 0x220C, 0x220D, 0x220E, 0x220F, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21E4, + 0x21E5, 0x21E6, 0x21E7, 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21DC, 0x21DD, 0x21DE, + 0x21DF, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F0, + 0x21F1, 0x21F2, 0x21F3, 0x21EC, 0x21ED, 0x21EE, 0x21EF, 0x21C8, 0x21C9, 0x21CA, + 0x21CB, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21BD, + 0x21BE, 0x21BF, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21D4, 0x21D5, 0x21D6, 0x21D7, + 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x022B, 0x21CC, 0x21CD, 0x21CE, 0x21CF, 0x22A8, + 0x22A9, 0x22AA, 0x22AB, 0x22A4, 0x22A5, 0x22A6, 0x22A7, 0x22A0, 0x22A1, 0x22A2, + 0x22A3, 0x229C, 0x229D, 0x229E, 0x229F, 0x22B8, 0x22B9, 0x0578, 0x0554, 0x05E9, + 0x05BC, 0x0669, 0x063C, 0x069C, 0x0688, 0x06DB, 0x06BE, 0x02A8, 0x0267, 0x02EF, + 0x02C6, 0x036D, 0x032A, 0x03B2, 0x0389, 0x22BA, 0x22BB, 0x044C, 0x0424, 0x049C, + 0x047E, 0x0538, 0x04E6, 0x056A, 0x0551, 0x05DD, 0x05AC, 0x065F, 0x061A, 0x22B4, + 0x22B5, 0x22B6, 0x22B1, 0x22B2, 0x0FCE, 0x0FCC, 0x22B3, 0x22AC, 0x22AD, 0x0FC7, + 0x22AE, 0x22AF, 0x2288, 0x0FD6, 0x0FD5, 0x2289, 0x228A, 0x228B, 0x042D, 0x2284, + 0x2285, 0x100D, 0x100C, 0x100A, 0x0FDD, 0x2286, 0x2287, 0x0C84, 0x1006, 0x1005, + 0x2280, 0x0C7E, 0x0C8A, 0x0C93, 0x0C86, 0x0C92, 0x2281, 0x0C94, 0x2282, 0x0C97, + 0x2283, 0x0C95, 0x0C88, 0x1004, 0x0C79, 0x0C87, 0x1003, 0x227C, 0x227D, 0x227E, + 0x227F, 0x0412, 0x2298, 0x2299, 0x229A, 0x229B, 0x2294, 0x2295, 0x2296, 0x2297, + 0x2290, 0x03FB, 0x2291, 0x2292, 0x2D1B, 0x2293, 0x228C, 0x228D, 0x228E, 0x2D31, + 0x2D37, 0x07BF, 0x07F4, 0x0FCA, 0x228F, 0x0865, 0x0869, 0x0885, 0x07FA, 0x2268, + 0x2262, 0x100B, 0x2279, 0x0FC3, 0x227A, 0x227B, 0x2274, 0x2275, 0x2276, 0x2277, + 0x2270, 0x2271, 0x2272, 0x2273, 0x226C, 0x226D, 0x0769, }; + diff --git a/vendor/nunicode/src/libnu/gen/_ducet_switch.c b/vendor/nunicode/src/libnu/gen/_ducet_switch.c new file mode 100644 index 0000000000..005ac1f259 --- /dev/null +++ b/vendor/nunicode/src/libnu/gen/_ducet_switch.c @@ -0,0 +1,1216 @@ +/* Automatically generated file (contractions-toc), 1490539886 + * + * Tag : _nu_ducet + * Contractions : 820 + */ + +#include <stdint.h> + +#include <libnu/udb.h> + +const size_t _NU_DUCET_CONTRACTIONS = 820; /* contractions included in switch */ +const size_t _NU_DUCET_CODEPOINTS = 20027; /* complementary codepoints number */ + +#define state_00AAB9 -838 +#define state_000438 -826 +#define state_0019B5 -749 +#define state_001B09 -745 +#define state_0019B7 -744 +#define state_0019BA -737 +#define state_00006C -712 +#define state_0019B6 -686 +#define state_00064A -684 +#define state_000648 -674 +#define state_00AABB -667 +#define state_000418 -500 +#define state_001B07 -482 +#define state_001B05 -454 +#define state_00AABC -394 +#define state_000627 -391 +#define state_000B92 -381 +#define state_00004C -343 +#define state_001B0D -252 +#define state_001025 -217 +#define state_000E40 -198 +#define state_000E41 -197 +#define state_000E42 -196 +#define state_000E43 -195 +#define state_000E44 -194 +#define state_00AAB5 -171 +#define state_00AAB6 -161 +#define state_000EC1 -114 +#define state_000EC0 -113 +#define state_000EC3 -112 +#define state_000EC2 -111 +#define state_000EC4 -109 +#define state_001B0B -59 +#define state_001B11 -24 + +const int16_t _NU_DUCET_ROOTS_G[] = { + 0, -34, 0, 0, -33, -32, -31, -30, -29, -28, 2, -26, + -15, 0, 0, 3, 0, 0, -14, -13, -12, 8, 1, 8, + -10, 0, -7, -6, 5, 20, 4, -4, -2, 0, }; + +const size_t _NU_DUCET_ROOTS_G_SIZE = sizeof(_NU_DUCET_ROOTS_G) / sizeof(*_NU_DUCET_ROOTS_G); + +/* codepoints */ +const uint32_t _NU_DUCET_ROOTS_VALUES_C[] = { + 0x00004C, 0x001B0D, 0x000648, 0x000EC0, 0x00064A, 0x000E44, 0x001B0B, 0x000EC1, + 0x000EC3, 0x001B05, 0x000E41, 0x000E43, 0x00006C, 0x000627, 0x0019B5, 0x001025, + 0x001B07, 0x00AAB9, 0x000E40, 0x0019B7, 0x000E42, 0x00AABC, 0x001B09, 0x0019BA, + 0x000EC2, 0x0019B6, 0x000B92, 0x000418, 0x00AABB, 0x000438, 0x00AAB5, 0x00AAB6, + 0x001B11, 0x000EC4, }; + +/* indexes */ +const uint16_t _NU_DUCET_ROOTS_VALUES_I[] = { + 0x0157, 0x00FC, 0x02A2, 0x0071, 0x02AC, 0x00C2, 0x003B, 0x0072, 0x0070, 0x01C6, + 0x00C5, 0x00C3, 0x02C8, 0x0187, 0x02ED, 0x00D9, 0x01E2, 0x0346, 0x00C6, 0x02E8, + 0x00C4, 0x018A, 0x02E9, 0x02E1, 0x006F, 0x02AE, 0x017D, 0x01F4, 0x029B, 0x033A, + 0x00AB, 0x00A1, 0x0018, 0x006D, }; + +/* MPH lookup for root codepoints + binary search on balanced tree + * for intermediate states */ +int32_t _nu_ducet_weight_switch(uint32_t u, int32_t *w, void *context) { + (void)(context); + + if (w == 0) { /* first entry, root states */ + uint32_t state = nu_udb_lookup_value(u, _NU_DUCET_ROOTS_G, _NU_DUCET_ROOTS_G_SIZE, + _NU_DUCET_ROOTS_VALUES_C, _NU_DUCET_ROOTS_VALUES_I); + + if (state != 0) { + return -state; /* VALUES_I store negated (positive) states */ + } + } + + if (w != 0) { /* re-entry, intermediate states */ + int32_t weight = *w; + *w = 0; + + if (weight == state_00004C) { + switch (u) { + case 0x000387: return 0x000456; + case 0x0000B7: return 0x000456; + } + + *w = 1; + return 0x00044D; + } + else if (weight < state_00004C) { + if (weight == state_00064A) { + switch (u) { + case 0x000654: return 0x000C71; + } + + *w = 1; + return 0x000FE3; + } + else if (weight < state_00064A) { + if (weight == state_0019B7) { + switch (u) { + case 0x0019A2: return 0x001F15; + case 0x001999: return 0x001EE8; + case 0x001981: return 0x001E70; + case 0x00198E: return 0x001EB1; + case 0x001988: return 0x001E93; + case 0x001994: return 0x001ECF; + case 0x0019A6: return 0x001F29; + case 0x00198A: return 0x001E9D; + case 0x001984: return 0x001E7F; + case 0x00199D: return 0x001EFC; + case 0x001991: return 0x001EC0; + case 0x0019A3: return 0x001F1A; + case 0x001980: return 0x001E6B; + case 0x00198D: return 0x001EAC; + case 0x001995: return 0x001ED4; + case 0x0019A7: return 0x001F2E; + case 0x00199A: return 0x001EED; + case 0x0019AA: return 0x001F3D; + case 0x00199E: return 0x001F01; + case 0x001992: return 0x001EC5; + case 0x001987: return 0x001E8E; + case 0x001996: return 0x001ED9; + case 0x0019A0: return 0x001F0B; + case 0x00199B: return 0x001EF2; + case 0x001983: return 0x001E7A; + case 0x0019AB: return 0x001F42; + case 0x0019A4: return 0x001F1F; + case 0x00199F: return 0x001F06; + case 0x001993: return 0x001ECA; + case 0x00198C: return 0x001EA7; + case 0x001986: return 0x001E89; + case 0x0019A8: return 0x001F33; + case 0x001997: return 0x001EDE; + case 0x0019A1: return 0x001F10; + case 0x00199C: return 0x001EF7; + case 0x001998: return 0x001EE3; + case 0x001982: return 0x001E75; + case 0x00198F: return 0x001EB6; + case 0x001989: return 0x001E98; + case 0x0019A5: return 0x001F24; + case 0x00198B: return 0x001EA2; + case 0x001985: return 0x001E84; + case 0x0019A9: return 0x001F38; + case 0x001990: return 0x001EBB; + } + + *w = 1; + return 0x001F4B; + } + else if (weight < state_0019B7) { + if (weight == state_0019B5) { + switch (u) { + case 0x0019A8: return 0x001F31; + case 0x00199F: return 0x001F04; + case 0x001993: return 0x001EC8; + case 0x0019AA: return 0x001F3B; + case 0x0019A7: return 0x001F2C; + case 0x001982: return 0x001E73; + case 0x00198F: return 0x001EB4; + case 0x001997: return 0x001EDC; + case 0x00199C: return 0x001EF5; + case 0x0019A0: return 0x001F09; + case 0x00198B: return 0x001EA0; + case 0x0019A9: return 0x001F36; + case 0x001990: return 0x001EB9; + case 0x0019A4: return 0x001F1D; + case 0x001985: return 0x001E82; + case 0x001994: return 0x001ECD; + case 0x0019AB: return 0x001F40; + case 0x001981: return 0x001E6E; + case 0x0019A1: return 0x001F0E; + case 0x00198E: return 0x001EAF; + case 0x001998: return 0x001EE1; + case 0x00199D: return 0x001EFA; + case 0x001991: return 0x001EBE; + case 0x0019A5: return 0x001F22; + case 0x00198A: return 0x001E9B; + case 0x001984: return 0x001E7D; + case 0x001995: return 0x001ED2; + case 0x001989: return 0x001E96; + case 0x00199A: return 0x001EEB; + case 0x001980: return 0x001E69; + case 0x00198D: return 0x001EAA; + case 0x001999: return 0x001EE6; + case 0x00199E: return 0x001EFF; + case 0x0019A2: return 0x001F13; + case 0x001987: return 0x001E8C; + case 0x001992: return 0x001EC3; + case 0x001988: return 0x001E91; + case 0x0019A6: return 0x001F27; + case 0x001983: return 0x001E78; + case 0x001996: return 0x001ED7; + case 0x00199B: return 0x001EF0; + case 0x0019A3: return 0x001F18; + case 0x00198C: return 0x001EA5; + case 0x001986: return 0x001E87; + } + + *w = 1; + return 0x001F49; + } + else if (weight < state_0019B5) { + if (weight == state_000438) { + switch (u) { + case 0x000306: return 0x000987; + } + + *w = 1; + return 0x000977; + } + else if (weight < state_000438) { + if (weight == state_00AAB9) { + switch (u) { + case 0x00AA92: return 0x001AE6; + case 0x00AAA5: return 0x001B58; + case 0x00AAAC: return 0x001B82; + case 0x00AA8F: return 0x001AD4; + case 0x00AA82: return 0x001A86; + case 0x00AA9C: return 0x001B22; + case 0x00AAA1: return 0x001B40; + case 0x00AA97: return 0x001B04; + case 0x00AAAD: return 0x001B88; + case 0x00AA86: return 0x001A9E; + case 0x00AA93: return 0x001AEC; + case 0x00AA9D: return 0x001B28; + case 0x00AA8A: return 0x001AB6; + case 0x00AAA6: return 0x001B5E; + case 0x00AA94: return 0x001AF2; + case 0x00AA8E: return 0x001ACE; + case 0x00AAAE: return 0x001B8E; + case 0x00AA81: return 0x001A80; + case 0x00AAA2: return 0x001B46; + case 0x00AA90: return 0x001ADA; + case 0x00AA9E: return 0x001B2E; + case 0x00AAAA: return 0x001B76; + case 0x00AA85: return 0x001A98; + case 0x00AA9A: return 0x001B16; + case 0x00AAA7: return 0x001B64; + case 0x00AA95: return 0x001AF8; + case 0x00AA89: return 0x001AB0; + case 0x00AA8D: return 0x001AC8; + case 0x00AA80: return 0x001A7A; + case 0x00AA98: return 0x001B0A; + case 0x00AAA3: return 0x001B4C; + case 0x00AA91: return 0x001AE0; + case 0x00AAA8: return 0x001B6A; + case 0x00AAAF: return 0x001B94; + case 0x00AA84: return 0x001A92; + case 0x00AA8C: return 0x001AC2; + case 0x00AA9F: return 0x001B34; + case 0x00AAA4: return 0x001B52; + case 0x00AAAB: return 0x001B7C; + case 0x00AA88: return 0x001AAA; + case 0x00AA83: return 0x001A8C; + case 0x00AA99: return 0x001B10; + case 0x00AA9B: return 0x001B1C; + case 0x00AAA0: return 0x001B3A; + case 0x00AA96: return 0x001AFE; + case 0x00AAA9: return 0x001B70; + case 0x00AA87: return 0x001AA4; + case 0x00AA8B: return 0x001ABC; + } + + *w = 1; + return 0x001B9A; + } + } + } + else { /* weight > state_0019B5 */ + if (weight == state_001B09) { + switch (u) { + case 0x001B35: return 0x001FCC; + } + + *w = 1; + return 0x001FCB; + } + } + } + else { /* weight > state_0019B7 */ + if (weight == state_00006C) { + switch (u) { + case 0x0000B7: return 0x000445; + case 0x000387: return 0x000445; + } + + *w = 1; + return 0x00043C; + } + else if (weight < state_00006C) { + if (weight == state_0019BA) { + switch (u) { + case 0x00198F: return 0x001EB7; + case 0x0019A2: return 0x001F16; + case 0x001995: return 0x001ED5; + case 0x00199C: return 0x001EF8; + case 0x001980: return 0x001E6C; + case 0x001991: return 0x001EC1; + case 0x0019A7: return 0x001F2F; + case 0x001984: return 0x001E80; + case 0x00199D: return 0x001EFD; + case 0x00198A: return 0x001E9E; + case 0x0019A3: return 0x001F1B; + case 0x001983: return 0x001E7B; + case 0x00198E: return 0x001EB2; + case 0x001996: return 0x001EDA; + case 0x0019A4: return 0x001F20; + case 0x001987: return 0x001E8F; + case 0x00199E: return 0x001F02; + case 0x001992: return 0x001EC6; + case 0x0019A0: return 0x001F0C; + case 0x00199A: return 0x001EEE; + case 0x001982: return 0x001E76; + case 0x00198D: return 0x001EAD; + case 0x0019AA: return 0x001F3E; + case 0x001997: return 0x001EDF; + case 0x0019A5: return 0x001F25; + case 0x001986: return 0x001E8A; + case 0x0019A8: return 0x001F34; + case 0x001989: return 0x001E99; + case 0x001993: return 0x001ECB; + case 0x00198C: return 0x001EA8; + case 0x0019A1: return 0x001F11; + case 0x001998: return 0x001EE4; + case 0x00199F: return 0x001F07; + case 0x001994: return 0x001ED0; + case 0x00199B: return 0x001EF3; + case 0x001981: return 0x001E71; + case 0x0019A9: return 0x001F39; + case 0x0019AB: return 0x001F43; + case 0x001988: return 0x001E94; + case 0x001990: return 0x001EBC; + case 0x00198B: return 0x001EA3; + case 0x0019A6: return 0x001F2A; + case 0x001999: return 0x001EE9; + case 0x001985: return 0x001E85; + } + + *w = 1; + return 0x001F4E; + } + } + else { /* weight > state_00006C */ + if (weight == state_0019B6) { + switch (u) { + case 0x001995: return 0x001ED3; + case 0x0019A3: return 0x001F19; + case 0x00199A: return 0x001EEC; + case 0x001980: return 0x001E6A; + case 0x00198D: return 0x001EAB; + case 0x001989: return 0x001E97; + case 0x0019AA: return 0x001F3C; + case 0x0019A7: return 0x001F2D; + case 0x00199E: return 0x001F00; + case 0x001990: return 0x001EBA; + case 0x001985: return 0x001E83; + case 0x001994: return 0x001ECE; + case 0x0019A2: return 0x001F14; + case 0x001981: return 0x001E6F; + case 0x00198E: return 0x001EB0; + case 0x0019A6: return 0x001F28; + case 0x00199D: return 0x001EFB; + case 0x00198A: return 0x001E9C; + case 0x001986: return 0x001E88; + case 0x001993: return 0x001EC9; + case 0x0019A1: return 0x001F0F; + case 0x001982: return 0x001E74; + case 0x00198F: return 0x001EB5; + case 0x001997: return 0x001EDD; + case 0x0019A5: return 0x001F23; + case 0x00199C: return 0x001EF6; + case 0x00198B: return 0x001EA1; + case 0x001987: return 0x001E8D; + case 0x0019A9: return 0x001F37; + case 0x001992: return 0x001EC4; + case 0x0019A0: return 0x001F0A; + case 0x001999: return 0x001EE7; + case 0x001983: return 0x001E79; + case 0x001996: return 0x001ED8; + case 0x0019A4: return 0x001F1E; + case 0x00199B: return 0x001EF1; + case 0x00198C: return 0x001EA6; + case 0x001988: return 0x001E92; + case 0x0019AB: return 0x001F41; + case 0x0019A8: return 0x001F32; + case 0x00199F: return 0x001F05; + case 0x001991: return 0x001EBF; + case 0x001998: return 0x001EE2; + case 0x001984: return 0x001E7E; + } + + *w = 1; + return 0x001F4A; + } + } + } + } + else { /* weight > state_00064A */ + if (weight == state_001B05) { + switch (u) { + case 0x001B35: return 0x001FC8; + } + + *w = 1; + return 0x001FC7; + } + else if (weight < state_001B05) { + if (weight == state_000418) { + switch (u) { + case 0x000306: return 0x000988; + } + + *w = 1; + return 0x00097B; + } + else if (weight < state_000418) { + if (weight == state_00AABB) { + switch (u) { + case 0x00AAA0: return 0x001B3B; + case 0x00AA8D: return 0x001AC9; + case 0x00AA81: return 0x001A81; + case 0x00AA99: return 0x001B11; + case 0x00AA90: return 0x001ADB; + case 0x00AAAF: return 0x001B95; + case 0x00AA9D: return 0x001B29; + case 0x00AA85: return 0x001A99; + case 0x00AA8A: return 0x001AB7; + case 0x00AAAB: return 0x001B7D; + case 0x00AA89: return 0x001AB1; + case 0x00AAA7: return 0x001B65; + case 0x00AA8E: return 0x001ACF; + case 0x00AA82: return 0x001A87; + case 0x00AA98: return 0x001B0B; + case 0x00AA97: return 0x001B05; + case 0x00AAAE: return 0x001B8F; + case 0x00AAA3: return 0x001B4D; + case 0x00AA86: return 0x001A9F; + case 0x00AA8B: return 0x001ABD; + case 0x00AA93: return 0x001AED; + case 0x00AAAA: return 0x001B77; + case 0x00AAA6: return 0x001B5F; + case 0x00AA8F: return 0x001AD5; + case 0x00AA83: return 0x001A8D; + case 0x00AA9C: return 0x001B23; + case 0x00AA96: return 0x001AFF; + case 0x00AAAD: return 0x001B89; + case 0x00AAA2: return 0x001B47; + case 0x00AA87: return 0x001AA5; + case 0x00AAA9: return 0x001B71; + case 0x00AA8C: return 0x001AC3; + case 0x00AA92: return 0x001AE7; + case 0x00AA9F: return 0x001B35; + case 0x00AAA5: return 0x001B59; + case 0x00AA9B: return 0x001B1D; + case 0x00AA95: return 0x001AF9; + case 0x00AAA1: return 0x001B41; + case 0x00AA80: return 0x001A7B; + case 0x00AAA8: return 0x001B6B; + case 0x00AA91: return 0x001AE1; + case 0x00AA9E: return 0x001B2F; + case 0x00AA84: return 0x001A93; + case 0x00AAA4: return 0x001B53; + case 0x00AAAC: return 0x001B83; + case 0x00AA9A: return 0x001B17; + case 0x00AA94: return 0x001AF3; + case 0x00AA88: return 0x001AAB; + } + + *w = 1; + return 0x001B9C; + } + else if (weight < state_00AABB) { + if (weight == state_000648) { + switch (u) { + case 0x000654: return 0x000C68; + } + + *w = 1; + return 0x000FBB; + } + } + } + else { /* weight > state_000418 */ + if (weight == state_001B07) { + switch (u) { + case 0x001B35: return 0x001FCA; + } + + *w = 1; + return 0x001FC9; + } + } + } + else { /* weight > state_001B05 */ + if (weight == state_000627) { + switch (u) { + case 0x000653: return 0x000C5E; + case 0x000655: return 0x000C6B; + case 0x000654: return 0x000C61; + } + + *w = 1; + return 0x000C9B; + } + else if (weight < state_000627) { + if (weight == state_00AABC) { + switch (u) { + case 0x00AA95: return 0x001AFA; + case 0x00AAA1: return 0x001B42; + case 0x00AA84: return 0x001A94; + case 0x00AA98: return 0x001B0C; + case 0x00AA91: return 0x001AE2; + case 0x00AAAC: return 0x001B84; + case 0x00AA9E: return 0x001B30; + case 0x00AA88: return 0x001AAC; + case 0x00AAA6: return 0x001B60; + case 0x00AA8D: return 0x001ACA; + case 0x00AA9A: return 0x001B18; + case 0x00AA96: return 0x001B00; + case 0x00AAA2: return 0x001B48; + case 0x00AA83: return 0x001A8E; + case 0x00AA99: return 0x001B12; + case 0x00AA92: return 0x001AE8; + case 0x00AAAD: return 0x001B8A; + case 0x00AA9F: return 0x001B36; + case 0x00AA87: return 0x001AA6; + case 0x00AAA7: return 0x001B66; + case 0x00AA8C: return 0x001AC4; + case 0x00AA9B: return 0x001B1E; + case 0x00AA97: return 0x001B06; + case 0x00AAA3: return 0x001B4E; + case 0x00AA82: return 0x001A88; + case 0x00AA93: return 0x001AEE; + case 0x00AAAE: return 0x001B90; + case 0x00AA86: return 0x001AA0; + case 0x00AAA8: return 0x001B6C; + case 0x00AA8B: return 0x001ABE; + case 0x00AAAA: return 0x001B78; + case 0x00AA9C: return 0x001B24; + case 0x00AAA4: return 0x001B54; + case 0x00AA8F: return 0x001AD6; + case 0x00AA81: return 0x001A82; + case 0x00AA94: return 0x001AF4; + case 0x00AAAF: return 0x001B96; + case 0x00AAA0: return 0x001B3C; + case 0x00AA85: return 0x001A9A; + case 0x00AAA9: return 0x001B72; + case 0x00AA8A: return 0x001AB8; + case 0x00AA90: return 0x001ADC; + case 0x00AAAB: return 0x001B7E; + case 0x00AA9D: return 0x001B2A; + case 0x00AA89: return 0x001AB2; + case 0x00AAA5: return 0x001B5A; + case 0x00AA8E: return 0x001AD0; + case 0x00AA80: return 0x001A7C; + } + + *w = 1; + return 0x001B9D; + } + } + else { /* weight > state_000627 */ + if (weight == state_000B92) { + switch (u) { + case 0x000BD7: return 0x0013E2; + } + + *w = 1; + return 0x0013E0; + } + } + } + } + } + else { /* weight > state_00004C */ + if (weight == state_00AAB6) { + switch (u) { + case 0x00AA9D: return 0x001B27; + case 0x00AA87: return 0x001AA3; + case 0x00AA8A: return 0x001AB5; + case 0x00AAA9: return 0x001B6F; + case 0x00AAAD: return 0x001B87; + case 0x00AA92: return 0x001AE5; + case 0x00AAA0: return 0x001B39; + case 0x00AA99: return 0x001B0F; + case 0x00AA83: return 0x001A8B; + case 0x00AA96: return 0x001AFD; + case 0x00AA8F: return 0x001AD3; + case 0x00AAA4: return 0x001B51; + case 0x00AA9C: return 0x001B21; + case 0x00AA88: return 0x001AA9; + case 0x00AA8B: return 0x001ABB; + case 0x00AAA8: return 0x001B69; + case 0x00AAAC: return 0x001B81; + case 0x00AA91: return 0x001ADF; + case 0x00AA98: return 0x001B09; + case 0x00AA84: return 0x001A91; + case 0x00AA95: return 0x001AF7; + case 0x00AAA3: return 0x001B4B; + case 0x00AA80: return 0x001A79; + case 0x00AA9B: return 0x001B1B; + case 0x00AA89: return 0x001AAF; + case 0x00AA8C: return 0x001AC1; + case 0x00AAA7: return 0x001B63; + case 0x00AAAB: return 0x001B7B; + case 0x00AA90: return 0x001AD9; + case 0x00AA9F: return 0x001B33; + case 0x00AA85: return 0x001A97; + case 0x00AAAF: return 0x001B93; + case 0x00AA94: return 0x001AF1; + case 0x00AAA2: return 0x001B45; + case 0x00AA81: return 0x001A7F; + case 0x00AA9A: return 0x001B15; + case 0x00AA8D: return 0x001AC7; + case 0x00AAA6: return 0x001B5D; + case 0x00AAAA: return 0x001B75; + case 0x00AA9E: return 0x001B2D; + case 0x00AA86: return 0x001A9D; + case 0x00AAAE: return 0x001B8D; + case 0x00AA93: return 0x001AEB; + case 0x00AAA1: return 0x001B3F; + case 0x00AA82: return 0x001A85; + case 0x00AA97: return 0x001B03; + case 0x00AA8E: return 0x001ACD; + case 0x00AAA5: return 0x001B57; + } + + *w = 1; + return 0x001B99; + } + else if (weight < state_00AAB6) { + if (weight == state_000E42) { + switch (u) { + case 0x000E1C: return 0x00193A; + case 0x000E16: return 0x001916; + case 0x000E24: return 0x00196A; + case 0x000E07: return 0x0018BC; + case 0x000E0C: return 0x0018DA; + case 0x000E12: return 0x0018FE; + case 0x000E1F: return 0x00194C; + case 0x000E2D: return 0x0019A0; + case 0x000E21: return 0x001958; + case 0x000E1B: return 0x001934; + case 0x000E15: return 0x001910; + case 0x000E25: return 0x001970; + case 0x000E2A: return 0x00198E; + case 0x000E23: return 0x001964; + case 0x000E11: return 0x0018F8; + case 0x000E1E: return 0x001946; + case 0x000E2E: return 0x0019A6; + case 0x000E04: return 0x0018AA; + case 0x000E1A: return 0x00192E; + case 0x000E14: return 0x00190A; + case 0x000E08: return 0x0018C2; + case 0x000E0D: return 0x0018E0; + case 0x000E01: return 0x001898; + case 0x000E19: return 0x001928; + case 0x000E28: return 0x001982; + case 0x000E10: return 0x0018F2; + case 0x000E26: return 0x001976; + case 0x000E1D: return 0x001940; + case 0x000E2B: return 0x001994; + case 0x000E05: return 0x0018B0; + case 0x000E0A: return 0x0018CE; + case 0x000E09: return 0x0018C8; + case 0x000E0E: return 0x0018E6; + case 0x000E02: return 0x00189E; + case 0x000E18: return 0x001922; + case 0x000E17: return 0x00191C; + case 0x000E27: return 0x00197C; + case 0x000E2C: return 0x00199A; + case 0x000E06: return 0x0018B6; + case 0x000E0B: return 0x0018D4; + case 0x000E13: return 0x001904; + case 0x000E29: return 0x001988; + case 0x000E20: return 0x001952; + case 0x000E22: return 0x00195E; + case 0x000E0F: return 0x0018EC; + case 0x000E03: return 0x0018A4; + } + + *w = 1; + return 0x0019AF; + } + else if (weight < state_000E42) { + if (weight == state_000E40) { + switch (u) { + case 0x000E04: return 0x0018A8; + case 0x000E27: return 0x00197A; + case 0x000E11: return 0x0018F6; + case 0x000E2C: return 0x001998; + case 0x000E1E: return 0x001944; + case 0x000E18: return 0x001920; + case 0x000E0D: return 0x0018DE; + case 0x000E01: return 0x001896; + case 0x000E1A: return 0x00192C; + case 0x000E14: return 0x001908; + case 0x000E05: return 0x0018AE; + case 0x000E0A: return 0x0018CC; + case 0x000E20: return 0x001950; + case 0x000E10: return 0x0018F0; + case 0x000E29: return 0x001986; + case 0x000E1D: return 0x00193E; + case 0x000E0E: return 0x0018E4; + case 0x000E24: return 0x001968; + case 0x000E17: return 0x00191A; + case 0x000E02: return 0x00189C; + case 0x000E2D: return 0x00199E; + case 0x000E21: return 0x001956; + case 0x000E13: return 0x001902; + case 0x000E22: return 0x00195C; + case 0x000E06: return 0x0018B4; + case 0x000E0B: return 0x0018D2; + case 0x000E25: return 0x00196E; + case 0x000E2A: return 0x00198C; + case 0x000E1C: return 0x001938; + case 0x000E16: return 0x001914; + case 0x000E0F: return 0x0018EA; + case 0x000E03: return 0x0018A2; + case 0x000E2E: return 0x0019A4; + case 0x000E08: return 0x0018C0; + case 0x000E12: return 0x0018FC; + case 0x000E1F: return 0x00194A; + case 0x000E07: return 0x0018BA; + case 0x000E0C: return 0x0018D8; + case 0x000E26: return 0x001974; + case 0x000E2B: return 0x001992; + case 0x000E1B: return 0x001932; + case 0x000E19: return 0x001926; + case 0x000E23: return 0x001962; + case 0x000E28: return 0x001980; + case 0x000E09: return 0x0018C6; + case 0x000E15: return 0x00190E; + } + + *w = 1; + return 0x0019AD; + } + else if (weight < state_000E40) { + if (weight == state_001025) { + switch (u) { + case 0x00102E: return 0x001DE0; + } + + *w = 1; + return 0x001DDF; + } + else if (weight < state_001025) { + if (weight == state_001B0D) { + switch (u) { + case 0x001B35: return 0x001FD0; + } + + *w = 1; + return 0x001FCF; + } + } + } + else { /* weight > state_000E40 */ + if (weight == state_000E41) { + switch (u) { + case 0x000E2C: return 0x001999; + case 0x000E26: return 0x001975; + case 0x000E14: return 0x001909; + case 0x000E01: return 0x001897; + case 0x000E0E: return 0x0018E5; + case 0x000E08: return 0x0018C1; + case 0x000E1D: return 0x00193F; + case 0x000E11: return 0x0018F7; + case 0x000E0A: return 0x0018CD; + case 0x000E04: return 0x0018A9; + case 0x000E29: return 0x001987; + case 0x000E2B: return 0x001993; + case 0x000E25: return 0x00196F; + case 0x000E15: return 0x00190F; + case 0x000E1A: return 0x00192D; + case 0x000E0D: return 0x0018DF; + case 0x000E21: return 0x001957; + case 0x000E2E: return 0x0019A5; + case 0x000E1E: return 0x001945; + case 0x000E23: return 0x001963; + case 0x000E07: return 0x0018BB; + case 0x000E2A: return 0x00198D; + case 0x000E24: return 0x001969; + case 0x000E12: return 0x0018FD; + case 0x000E03: return 0x0018A3; + case 0x000E20: return 0x001951; + case 0x000E16: return 0x001915; + case 0x000E28: return 0x001981; + case 0x000E2D: return 0x00199F; + case 0x000E1B: return 0x001933; + case 0x000E0C: return 0x0018D9; + case 0x000E06: return 0x0018B5; + case 0x000E1F: return 0x00194B; + case 0x000E13: return 0x001903; + case 0x000E18: return 0x001921; + case 0x000E02: return 0x00189D; + case 0x000E0F: return 0x0018EB; + case 0x000E27: return 0x00197B; + case 0x000E17: return 0x00191B; + case 0x000E1C: return 0x001939; + case 0x000E0B: return 0x0018D3; + case 0x000E09: return 0x0018C7; + case 0x000E22: return 0x00195D; + case 0x000E10: return 0x0018F1; + case 0x000E19: return 0x001927; + case 0x000E05: return 0x0018AF; + } + + *w = 1; + return 0x0019AE; + } + } + } + else { /* weight > state_000E42 */ + if (weight == state_000E44) { + switch (u) { + case 0x000E1E: return 0x001948; + case 0x000E10: return 0x0018F4; + case 0x000E08: return 0x0018C4; + case 0x000E01: return 0x00189A; + case 0x000E28: return 0x001984; + case 0x000E0E: return 0x0018E8; + case 0x000E14: return 0x00190C; + case 0x000E2B: return 0x001996; + case 0x000E27: return 0x00197E; + case 0x000E29: return 0x00198A; + case 0x000E0A: return 0x0018D0; + case 0x000E18: return 0x001924; + case 0x000E22: return 0x001960; + case 0x000E1D: return 0x001942; + case 0x000E13: return 0x001906; + case 0x000E09: return 0x0018CA; + case 0x000E06: return 0x0018B8; + case 0x000E17: return 0x00191E; + case 0x000E1C: return 0x00193C; + case 0x000E2C: return 0x00199C; + case 0x000E02: return 0x0018A0; + case 0x000E0F: return 0x0018EE; + case 0x000E12: return 0x001900; + case 0x000E24: return 0x00196C; + case 0x000E0B: return 0x0018D6; + case 0x000E07: return 0x0018BE; + case 0x000E16: return 0x001918; + case 0x000E20: return 0x001954; + case 0x000E23: return 0x001966; + case 0x000E1B: return 0x001936; + case 0x000E2D: return 0x0019A2; + case 0x000E03: return 0x0018A6; + case 0x000E1F: return 0x00194E; + case 0x000E25: return 0x001972; + case 0x000E0C: return 0x0018DC; + case 0x000E04: return 0x0018AC; + case 0x000E11: return 0x0018FA; + case 0x000E21: return 0x00195A; + case 0x000E2E: return 0x0019A8; + case 0x000E0D: return 0x0018E2; + case 0x000E15: return 0x001912; + case 0x000E1A: return 0x001930; + case 0x000E2A: return 0x001990; + case 0x000E26: return 0x001978; + case 0x000E05: return 0x0018B2; + case 0x000E19: return 0x00192A; + } + + *w = 1; + return 0x0019B1; + } + else if (weight < state_000E44) { + if (weight == state_000E43) { + switch (u) { + case 0x000E02: return 0x00189F; + case 0x000E22: return 0x00195F; + case 0x000E13: return 0x001905; + case 0x000E25: return 0x001971; + case 0x000E2A: return 0x00198F; + case 0x000E06: return 0x0018B7; + case 0x000E0B: return 0x0018D5; + case 0x000E28: return 0x001983; + case 0x000E1C: return 0x00193B; + case 0x000E2E: return 0x0019A7; + case 0x000E20: return 0x001953; + case 0x000E0F: return 0x0018ED; + case 0x000E01: return 0x001899; + case 0x000E14: return 0x00190B; + case 0x000E24: return 0x00196B; + case 0x000E05: return 0x0018B1; + case 0x000E0A: return 0x0018CF; + case 0x000E10: return 0x0018F3; + case 0x000E1D: return 0x001941; + case 0x000E2D: return 0x0019A1; + case 0x000E09: return 0x0018C9; + case 0x000E0E: return 0x0018E7; + case 0x000E15: return 0x001911; + case 0x000E27: return 0x00197D; + case 0x000E2C: return 0x00199B; + case 0x000E04: return 0x0018AB; + case 0x000E18: return 0x001923; + case 0x000E11: return 0x0018F9; + case 0x000E1E: return 0x001947; + case 0x000E08: return 0x0018C3; + case 0x000E23: return 0x001965; + case 0x000E0D: return 0x0018E1; + case 0x000E1A: return 0x00192F; + case 0x000E16: return 0x001917; + case 0x000E26: return 0x001977; + case 0x000E2B: return 0x001995; + case 0x000E03: return 0x0018A5; + case 0x000E19: return 0x001929; + case 0x000E29: return 0x001989; + case 0x000E12: return 0x0018FF; + case 0x000E1F: return 0x00194D; + case 0x000E07: return 0x0018BD; + case 0x000E0C: return 0x0018DB; + case 0x000E1B: return 0x001935; + case 0x000E17: return 0x00191D; + case 0x000E21: return 0x001959; + } + + *w = 1; + return 0x0019B0; + } + } + else { /* weight > state_000E44 */ + if (weight == state_00AAB5) { + switch (u) { + case 0x00AAA8: return 0x001B68; + case 0x00AA9F: return 0x001B32; + case 0x00AA93: return 0x001AEA; + case 0x00AAAA: return 0x001B74; + case 0x00AAA7: return 0x001B62; + case 0x00AA82: return 0x001A84; + case 0x00AA8F: return 0x001AD2; + case 0x00AA97: return 0x001B02; + case 0x00AAAE: return 0x001B8C; + case 0x00AA9C: return 0x001B20; + case 0x00AAA0: return 0x001B38; + case 0x00AA8B: return 0x001ABA; + case 0x00AAA9: return 0x001B6E; + case 0x00AA90: return 0x001AD8; + case 0x00AAA4: return 0x001B50; + case 0x00AA85: return 0x001A96; + case 0x00AA94: return 0x001AF0; + case 0x00AAAB: return 0x001B7A; + case 0x00AA81: return 0x001A7E; + case 0x00AAA1: return 0x001B3E; + case 0x00AA8E: return 0x001ACC; + case 0x00AA98: return 0x001B08; + case 0x00AAAF: return 0x001B92; + case 0x00AA9D: return 0x001B26; + case 0x00AA91: return 0x001ADE; + case 0x00AAA5: return 0x001B56; + case 0x00AA8A: return 0x001AB4; + case 0x00AA84: return 0x001A90; + case 0x00AA95: return 0x001AF6; + case 0x00AA89: return 0x001AAE; + case 0x00AAAC: return 0x001B80; + case 0x00AA9A: return 0x001B14; + case 0x00AA80: return 0x001A78; + case 0x00AA8D: return 0x001AC6; + case 0x00AA99: return 0x001B0E; + case 0x00AA9E: return 0x001B2C; + case 0x00AAA2: return 0x001B44; + case 0x00AA87: return 0x001AA2; + case 0x00AA92: return 0x001AE4; + case 0x00AA88: return 0x001AA8; + case 0x00AAA6: return 0x001B5C; + case 0x00AA83: return 0x001A8A; + case 0x00AA96: return 0x001AFC; + case 0x00AAAD: return 0x001B86; + case 0x00AA9B: return 0x001B1A; + case 0x00AAA3: return 0x001B4A; + case 0x00AA8C: return 0x001AC0; + case 0x00AA86: return 0x001A9C; + } + + *w = 1; + return 0x001B98; + } + } + } + } + else { /* weight > state_00AAB6 */ + if (weight == state_000EC2) { + switch (u) { + case 0x000E82: return 0x0019C2; + case 0x000E9B: return 0x001A16; + case 0x000EDD: return 0x001A5E; + case 0x000EAD: return 0x001A64; + case 0x000E9F: return 0x001A2E; + case 0x000EAA: return 0x0019DA; + case 0x000E81: return 0x0019BC; + case 0x000E9C: return 0x001A1C; + case 0x000E94: return 0x0019F2; + case 0x000EDC: return 0x001A58; + case 0x000EAE: return 0x001A6A; + case 0x000EA1: return 0x001A34; + case 0x000E84: return 0x0019C8; + case 0x000EA5: return 0x001A46; + case 0x000EAB: return 0x001A52; + case 0x000E95: return 0x0019F8; + case 0x000EA2: return 0x001A3A; + case 0x000E99: return 0x001A0A; + case 0x000E8A: return 0x0019E0; + case 0x000EDF: return 0x0019E6; + case 0x000E88: return 0x0019D4; + case 0x000E9D: return 0x001A22; + case 0x000E87: return 0x0019CE; + case 0x000E96: return 0x0019FE; + case 0x000E8D: return 0x0019EC; + case 0x000E9A: return 0x001A10; + case 0x000EA3: return 0x001A40; + case 0x000EDE: return 0x0019B6; + case 0x000E9E: return 0x001A28; + case 0x000EA7: return 0x001A4C; + case 0x000E97: return 0x001A04; + } + + *w = 1; + return 0x001A74; + } + else if (weight < state_000EC2) { + if (weight == state_000EC0) { + switch (u) { + case 0x000E84: return 0x0019C6; + case 0x000E9D: return 0x001A20; + case 0x000E8A: return 0x0019DE; + case 0x000EAB: return 0x001A50; + case 0x000E88: return 0x0019D2; + case 0x000E99: return 0x001A08; + case 0x000E96: return 0x0019FC; + case 0x000EA2: return 0x001A38; + case 0x000E87: return 0x0019CC; + case 0x000E9E: return 0x001A26; + case 0x000EDE: return 0x0019B4; + case 0x000E9A: return 0x001A0E; + case 0x000EA7: return 0x001A4A; + case 0x000E82: return 0x0019C0; + case 0x000E8D: return 0x0019EA; + case 0x000E97: return 0x001A02; + case 0x000EA3: return 0x001A3E; + case 0x000EAD: return 0x001A62; + case 0x000EDD: return 0x001A5C; + case 0x000E9F: return 0x001A2C; + case 0x000E94: return 0x0019F0; + case 0x000E9B: return 0x001A14; + case 0x000EAE: return 0x001A68; + case 0x000E81: return 0x0019BA; + case 0x000EAA: return 0x0019D8; + case 0x000EA5: return 0x001A44; + case 0x000EDC: return 0x001A56; + case 0x000E95: return 0x0019F6; + case 0x000E9C: return 0x001A1A; + case 0x000EA1: return 0x001A32; + case 0x000EDF: return 0x0019E4; + } + + *w = 1; + return 0x001A72; + } + else if (weight < state_000EC0) { + if (weight == state_000EC1) { + switch (u) { + case 0x000EAD: return 0x001A63; + case 0x000E97: return 0x001A03; + case 0x000EA1: return 0x001A33; + case 0x000E9C: return 0x001A1B; + case 0x000E82: return 0x0019C1; + case 0x000EDE: return 0x0019B5; + case 0x000EA5: return 0x001A45; + case 0x000E87: return 0x0019CD; + case 0x000E96: return 0x0019FD; + case 0x000E9B: return 0x001A15; + case 0x000E99: return 0x001A09; + case 0x000E88: return 0x0019D3; + case 0x000EAB: return 0x001A51; + case 0x000E9F: return 0x001A2D; + case 0x000E84: return 0x0019C7; + case 0x000EDF: return 0x0019E5; + case 0x000EA3: return 0x001A3F; + case 0x000E8D: return 0x0019EB; + case 0x000E95: return 0x0019F7; + case 0x000EDC: return 0x001A57; + case 0x000EA7: return 0x001A4B; + case 0x000E9A: return 0x001A0F; + case 0x000EAA: return 0x0019D9; + case 0x000E9E: return 0x001A27; + case 0x000EA2: return 0x001A39; + case 0x000E81: return 0x0019BB; + case 0x000EAE: return 0x001A69; + case 0x000E94: return 0x0019F1; + case 0x000E8A: return 0x0019DF; + case 0x000EDD: return 0x001A5D; + case 0x000E9D: return 0x001A21; + } + + *w = 1; + return 0x001A73; + } + } + else { /* weight > state_000EC0 */ + if (weight == state_000EC3) { + switch (u) { + case 0x000E96: return 0x0019FF; + case 0x000EAE: return 0x001A6B; + case 0x000E9C: return 0x001A1D; + case 0x000EA1: return 0x001A35; + case 0x000EDE: return 0x0019B7; + case 0x000EA5: return 0x001A47; + case 0x000E84: return 0x0019C9; + case 0x000E95: return 0x0019F9; + case 0x000EAD: return 0x001A65; + case 0x000E9B: return 0x001A17; + case 0x000E99: return 0x001A0B; + case 0x000EDF: return 0x0019E7; + case 0x000E9F: return 0x001A2F; + case 0x000E94: return 0x0019F3; + case 0x000E88: return 0x0019D5; + case 0x000EDC: return 0x001A59; + case 0x000E81: return 0x0019BD; + case 0x000E9A: return 0x001A11; + case 0x000E8D: return 0x0019ED; + case 0x000E9E: return 0x001A29; + case 0x000EA3: return 0x001A41; + case 0x000EA7: return 0x001A4D; + case 0x000EAB: return 0x001A53; + case 0x000E82: return 0x0019C3; + case 0x000E97: return 0x001A05; + case 0x000E9D: return 0x001A23; + case 0x000EA2: return 0x001A3B; + case 0x000E87: return 0x0019CF; + case 0x000E8A: return 0x0019E1; + case 0x000EDD: return 0x001A5F; + case 0x000EAA: return 0x0019DB; + } + + *w = 1; + return 0x001A75; + } + } + } + else { /* weight > state_000EC2 */ + if (weight == state_001B0B) { + switch (u) { + case 0x001B35: return 0x001FCE; + } + + *w = 1; + return 0x001FCD; + } + else if (weight < state_001B0B) { + if (weight == state_000EC4) { + switch (u) { + case 0x000EDD: return 0x001A60; + case 0x000E9F: return 0x001A30; + case 0x000EAA: return 0x0019DC; + case 0x000EA7: return 0x001A4E; + case 0x000E82: return 0x0019C4; + case 0x000E97: return 0x001A06; + case 0x000EDC: return 0x001A5A; + case 0x000EAE: return 0x001A6C; + case 0x000E9C: return 0x001A1E; + case 0x000E94: return 0x0019F4; + case 0x000EAB: return 0x001A54; + case 0x000E81: return 0x0019BE; + case 0x000EA1: return 0x001A36; + case 0x000EDF: return 0x0019E8; + case 0x000E9D: return 0x001A24; + case 0x000EA5: return 0x001A48; + case 0x000E8A: return 0x0019E2; + case 0x000E84: return 0x0019CA; + case 0x000E95: return 0x0019FA; + case 0x000E9A: return 0x001A12; + case 0x000E8D: return 0x0019EE; + case 0x000E99: return 0x001A0C; + case 0x000E9E: return 0x001A2A; + case 0x000EA2: return 0x001A3C; + case 0x000E87: return 0x0019D0; + case 0x000EDE: return 0x0019B8; + case 0x000E88: return 0x0019D6; + case 0x000E96: return 0x001A00; + case 0x000EAD: return 0x001A66; + case 0x000E9B: return 0x001A18; + case 0x000EA3: return 0x001A42; + } + + *w = 1; + return 0x001A76; + } + } + else { /* weight > state_001B0B */ + if (weight == state_001B11) { + switch (u) { + case 0x001B35: return 0x001FD4; + } + + *w = 1; + return 0x001FD3; + } + } + } + } + } + } + + return 0; +} diff --git a/vendor/nunicode/src/libnu/gen/_tolower.c b/vendor/nunicode/src/libnu/gen/_tolower.c new file mode 100644 index 0000000000..0e267f5386 --- /dev/null +++ b/vendor/nunicode/src/libnu/gen/_tolower.c @@ -0,0 +1,846 @@ +/* Automatically generated file (mph.py), 1490539881 + * + * Tag : NU_TOLOWER + * Prime : 01000193, + * G size : 1304, + * Combined length : 5006, + * Encoding : UTF-8 + */ + +#include <stdint.h> + +const int16_t NU_TOLOWER_G[] = { + 0, 1, 0, 1, -1279, 1, 0, 1, 1, 0, 1, -1277, + 1, -1271, 1, -1269, 1, 0, 1, 0, -1267, 0, 1, 0, + 1, 1, 1, 1, 0, 1, -1265, 1, 0, -1256, 0, -1254, + -1238, -1236, -1220, 1, -1194, 1, 0, 1, -1160, -1153, -1147, -1143, + 0, 1, -1135, -1133, -1131, 1, 0, 1, 1, 1, 5, 1, + 1, 1, 9, 1, -1129, 3, -1117, 2, -1116, 1, -1115, 1, + -1112, 1, -1111, 1, -1110, 1, -1108, 1, -1106, 1, -1103, 1, + -1101, 1, -1090, 1, 0, 1, 0, 5, 0, 32, 0, 32, + 0, 1, 0, 1, 0, 1, 0, 1, -1052, 1, -1049, 1, + -1019, 1, -1016, 1, -1013, 3, -1012, 4, -1010, 1, -1007, 1, + -1005, -1000, -999, -998, -997, -996, -995, -994, 0, 3, 0, 2, + 0, 1, 0, 2, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 4, 0, 1, 0, 5, + 0, 1, 0, 4, -992, 1, -991, 4, -990, 1, -989, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, -985, -984, -982, 1, 0, -981, -980, -979, + 0, 1, 0, 1, 0, 1, 0, 1, -978, 2, -977, 1, + -976, 1, -975, 1, -974, 1, -973, 1, -972, 2, -971, 1, + -970, 3, -969, 2, -968, 1, -966, 1, -964, 1, -963, 1, + -962, 2, -961, 1, 0, -949, 0, -904, 0, -902, 0, -900, + 0, -898, 0, -896, 0, -894, 0, -893, 0, -892, 0, -891, + 0, -890, 0, -889, 0, -888, 0, -887, 0, -881, 0, -879, + 0, -878, 0, -877, 0, -876, 0, -875, -874, 1, -873, 1, + 0, 1, -872, 1, -871, 2, -870, 14, 0, 24, -869, 24, + -866, 1, -865, 1, -864, 1, -863, 4, 14, 1, 25, 1, + 29, 1, 49, 1, -862, 2, -861, 1, -860, 2, -859, 2, + 0, -858, 0, -856, 0, -854, 0, -853, 0, 0, 0, 0, + 0, 0, 0, 0, -852, -849, -848, -847, -846, -845, 0, 0, + 1, -844, -843, -842, -841, -840, -839, -838, -837, -836, -834, -832, + -831, -830, -828, -826, -824, -822, -821, -820, -819, -818, -817, -816, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -815, -814, -813, -812, -811, -810, -809, -808, + -807, -804, -798, -797, -796, -795, -793, -790, -788, -785, -783, -782, + -778, -777, -776, -775, 9, 42, 45, 46, 76, 76, 94, 97, + -774, 104, 125, 126, -773, -772, -770, -768, 185, 186, 191, -767, + 197, 208, 224, 236, 5, 6, 56, 56, 60, 60, 71, 81, + -766, -765, -764, -763, -762, -761, -760, -759, 31, 74, 80, 85, + 88, 92, 92, 92, -758, -757, -756, -754, -753, -752, -751, -750, + 0, 0, 0, 0, 0, 0, 0, 0, -749, -748, -747, 0, + -746, -745, -744, -743, 1, 1, 1, 4, 2, -742, 16, 18, + 0, -741, 0, 0, 0, -740, -739, 0, 0, -738, -737, -734, + -731, -730, 0, -728, 0, 0, 0, 0, 0, -725, 0, 0, + -724, -723, 0, 0, 0, 0, 0, 0, -722, 0, -721, -720, + -719, -718, -717, -716, -715, -714, -713, -712, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -711, 0, -710, + 0, -709, 0, -708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -707, 0, 0, 0, -706, -705, -704, -703, + 1, -702, -701, 1, -700, 1, 1, -699, 1, 1, 1, -698, + 0, -697, 0, -696, 0, -695, 0, -694, 0, -693, 0, -692, + 0, -691, 0, -690, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -689, -688, -687, -686, + -685, -684, -683, -682, -681, 3, -680, 2, -679, 2, -678, -677, + -676, -675, -674, -673, 1, -672, -671, -670, -669, -668, -667, -666, + -665, -664, -663, -662, -661, -660, -659, -658, -657, -656, -655, -654, + -653, 8, -652, 8, -651, 40, -650, -649, -648, 4, -647, 64, + -646, 72, -645, 72, -644, 56, -643, 56, -642, 65, -641, 65, + 8, -640, -639, -638, 0, 0, 8, -637, -636, -635, -634, -633, + 0, -632, 0, -631, -630, -629, -628, -627, -626, -625, -624, -623, + -622, 64, -621, 64, -620, 64, -619, 64, -618, -617, 0, -616, + 0, -615, -614, -613, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -612, 0, -611, + 0, -610, 0, -609, 0, -608, 0, -607, 0, -606, 0, -605, + 0, -604, 0, -603, 0, -602, 0, -601, 0, -600, 0, -599, + 0, -598, 0, -597, 0, 1, 0, -596, 0, -595, 0, -594, + -593, 1, 0, -591, 0, 1, -589, -587, 0, 2, 0, -585, + 0, 4, 0, 14, 0, 19, 0, 20, 0, 16, 0, 17, + 0, -584, 0, -583, 0, -582, 0, -581, 0, -580, 0, -578, + 0, -571, 0, -569, -568, -567, -566, -565, 0, 4, -563, 4, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, -562, 0, -561, 0, 0, -560, -559, 0, + 0, -558, 0, -557, 0, -556, 0, -554, 0, -553, 0, -552, + 0, -551, 0, -550, 0, -549, 0, -548, 0, -546, 0, -544, + 0, -543, 0, -542, 0, 0, 0, 0, 0, -541, 0, -540, + 0, -539, 0, -538, 0, -537, 0, -536, 0, -535, 0, -534, + -533, -532, -531, -530, -529, -528, -527, -526, -525, -524, -523, -522, + -521, -520, -519, -518, -517, -516, -515, -514, -513, -511, -509, -507, + -505, -503, -501, -499, -498, -497, -495, -493, 0, 32, -491, 32, + 0, -489, 0, -487, 0, -485, 0, -484, 0, -481, 0, -479, + -478, 40, -477, 40, -476, 41, -474, 41, -472, 33, -471, 33, + -470, 51, -468, 53, 0, -466, 0, -464, 0, -463, 0, -462, + 0, -461, 0, -459, 0, -457, 0, -456, 0, -455, 0, -453, + 0, -452, 0, -451, 0, -450, 0, -449, 0, -447, 0, -444, + 0, 34, 0, 33, 0, 33, 0, 79, 0, 92, 0, 92, + 0, 126, 0, 167, -439, 4, -438, 4, -437, 8, -436, 8, + -432, 26, -428, 38, -421, 40, -419, 40, 47, 8, 73, 423, + 73, 76, 89, 105, 132, 241, 305, 306, 317, 318, 324, 324, + 244, 9, 459, 8, -416, 142, -415, 44, -412, -410, 0, -409, + 0, -405, -403, -395, 1, 64, 9, 65, 1, 64, 4, 64, + -393, 81, 128, 65, -390, 81, -389, 80, 1, 64, 1, 64, + 145, 76, 159, 83, 213, 84, 379, 87, 377, 107, 377, 109, + -388, -387, -386, -385, 0, 0, 0, -383, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, 2, 64, -375, 80, -371, 64, + -369, 80, -359, 80, 0, -357, -355, 80, -353, 14, -343, 32, + 0, -339, 0, 37, -335, 112, -330, 197, -327, 193, -320, 200, + -315, 174, 288, 34, 0, 0, -308, -303, 236, 201, 358, -285, + 544, 1, -254, 2, 544, 33, 548, 32, 32, 32, 32, 32, + 0, 17, -252, -250, 14, 1, 0, 17, 4, 1, 37, 6, + 9, 2, -232, 8, 21, 40, 32, -231, 39, 40, 41, -230, + -228, 86, -226, 1, -152, 227, -143, 6, }; + +const size_t NU_TOLOWER_G_SIZE = sizeof(NU_TOLOWER_G) / sizeof(*NU_TOLOWER_G); + +/* codepoints */ +const uint32_t NU_TOLOWER_VALUES_C[] = { + 0x01E908, 0x001E92, 0x001E90, 0x01E90A, 0x000533, 0x001E94, 0x00054A, 0x000548, + 0x01E912, 0x00054C, 0x00004D, 0x000055, 0x00050C, 0x00054E, 0x00050E, 0x001E9E, + 0x000520, 0x001EA2, 0x01E91A, 0x000522, 0x001EA0, 0x001EA4, 0x000508, 0x001EA6, + 0x000512, 0x000510, 0x000056, 0x000057, 0x001E8C, 0x00004C, 0x001E8E, 0x000516, + 0x01E90C, 0x001EB0, 0x000532, 0x001EB2, 0x000059, 0x001EB4, 0x000058, 0x001EB6, + 0x000541, 0x001EB8, 0x000543, 0x001EBA, 0x000518, 0x001EBC, 0x00051A, 0x001EBE, + 0x001EC4, 0x001EC0, 0x00005A, 0x001EC2, 0x01E91B, 0x000054, 0x01E910, 0x001EC6, + 0x001ECC, 0x000555, 0x000553, 0x001ECA, 0x01E914, 0x001EC8, 0x01E916, 0x001ECE, + 0x000551, 0x001ED2, 0x001ED0, 0x000514, 0x01E91D, 0x000534, 0x001ED4, 0x001ED6, + 0x00051E, 0x001ED8, 0x01041B, 0x001EDA, 0x00004A, 0x001EDC, 0x00004B, 0x001EDE, + 0x01E919, 0x001EE0, 0x01E91E, 0x001EE2, 0x000535, 0x001EE4, 0x01E91F, 0x001EE6, + 0x00FF28, 0x001EE8, 0x000053, 0x00FF2A, 0x00FF2C, 0x00FF2D, 0x00FF2E, 0x00FF2F, + 0x000531, 0x01E920, 0x000536, 0x001EF2, 0x001EF0, 0x001EF4, 0x000537, 0x001EF6, + 0x01041A, 0x001EF8, 0x00FF38, 0x001EFA, 0x010419, 0x001EFC, 0x010418, 0x001EFE, + 0x000048, 0x000049, 0x00004E, 0x00004F, 0x010423, 0x01E91C, 0x00FF24, 0x00FF26, + 0x000052, 0x0118A2, 0x0118A0, 0x01041D, 0x000051, 0x0118A4, 0x000050, 0x0118A6, + 0x01E90E, 0x0118A8, 0x000047, 0x0118AA, 0x0118AE, 0x0118AC, 0x00054B, 0x01E903, + 0x0118B2, 0x0118B0, 0x01041E, 0x01041F, 0x001F39, 0x0118B4, 0x001F2D, 0x0118B6, + 0x000526, 0x0118B8, 0x00FF32, 0x0118BA, 0x0118BE, 0x0118BC, 0x000046, 0x001F2F, + 0x001F08, 0x001F28, 0x001F2C, 0x001F0A, 0x001F0C, 0x001F0D, 0x001F0E, 0x001F0F, + 0x010422, 0x01E921, 0x010402, 0x00051C, 0x001F3C, 0x000045, 0x001F3F, 0x00053B, + 0x000044, 0x010421, 0x001F18, 0x001F3A, 0x001F3E, 0x010420, 0x001F38, 0x001F3B, + 0x010424, 0x010425, 0x010426, 0x00053A, 0x010401, 0x01041C, 0x010400, 0x010427, + 0x001F49, 0x001F48, 0x001F4B, 0x001F4A, 0x0104B5, 0x001F4C, 0x000547, 0x001FBB, + 0x0000C4, 0x0000C0, 0x000545, 0x0000C2, 0x0000DC, 0x0000CB, 0x0000DE, 0x0000C6, + 0x001F59, 0x0000C8, 0x001F5B, 0x0000CA, 0x001F5D, 0x0000CC, 0x001F5F, 0x0000CE, + 0x0000C9, 0x0000D0, 0x0000CF, 0x0000D2, 0x001F6D, 0x0000D4, 0x0000D8, 0x0000D6, + 0x0000DA, 0x001F68, 0x001F6B, 0x001F6A, 0x001F69, 0x001F6C, 0x001F6F, 0x001F6E, + 0x0104B1, 0x001F29, 0x0104B7, 0x001F2B, 0x00FF3A, 0x0004AC, 0x0004A8, 0x001F3D, + 0x01040A, 0x0104B0, 0x01040B, 0x0104B2, 0x001F2A, 0x0104B4, 0x010409, 0x0104B6, + 0x0104BA, 0x0104B8, 0x001F8A, 0x01E902, 0x0104BE, 0x0104B3, 0x0104BC, 0x000191, + 0x000042, 0x0004B8, 0x000043, 0x000181, 0x0000CD, 0x00FF25, 0x000041, 0x01E90B, + 0x001FBC, 0x000100, 0x01040F, 0x000102, 0x001F9C, 0x000104, 0x001F9E, 0x000106, + 0x001FD8, 0x000108, 0x001FDA, 0x00010A, 0x001F98, 0x00010C, 0x001F9A, 0x00010E, + 0x001FA9, 0x000110, 0x0024BB, 0x000112, 0x001F8B, 0x000114, 0x01040E, 0x000116, + 0x01040C, 0x001FAD, 0x001FAB, 0x00011A, 0x000190, 0x000118, 0x001FAF, 0x00FF23, + 0x001FB8, 0x000122, 0x000120, 0x001FBA, 0x001F1A, 0x01040D, 0x000124, 0x000126, + 0x001FF8, 0x000128, 0x001FFA, 0x00012A, 0x001FFC, 0x00012C, 0x001F1C, 0x00012E, + 0x001F89, 0x000132, 0x001F8E, 0x001F1D, 0x000130, 0x000134, 0x001F8F, 0x000136, + 0x001FE8, 0x001FEC, 0x001F1B, 0x00FF22, 0x00011C, 0x001F2E, 0x00011E, 0x00FF35, + 0x0010B0, 0x0010B1, 0x0010B6, 0x0010B7, 0x001F8D, 0x00FF30, 0x00FF37, 0x00FF36, + 0x001FD9, 0x00FF31, 0x001FDB, 0x00014A, 0x00FF34, 0x00014C, 0x00FF33, 0x00014E, + 0x000154, 0x000150, 0x000496, 0x000152, 0x001FEA, 0x001F8C, 0x001FE9, 0x000156, + 0x00015C, 0x001FA8, 0x001FAA, 0x00015A, 0x001FAC, 0x000158, 0x001FAE, 0x00015E, + 0x001FEB, 0x000160, 0x002C2D, 0x000162, 0x002C2E, 0x000164, 0x002C29, 0x000166, + 0x00016A, 0x000168, 0x001FFB, 0x001FF9, 0x0010B2, 0x00016C, 0x0010B3, 0x00016E, + 0x002C2B, 0x000170, 0x002C25, 0x000172, 0x0010A3, 0x000174, 0x002C27, 0x000176, + 0x0010C1, 0x000178, 0x0010C3, 0x0010C2, 0x0010C0, 0x0010C7, 0x001FCC, 0x000193, + 0x001FC8, 0x001FC9, 0x001FCA, 0x001FCB, 0x002C1D, 0x002C1F, 0x00018F, 0x000186, + 0x002C1B, 0x000187, 0x00052C, 0x00018A, 0x00018E, 0x0010C5, 0x0010C4, 0x00018B, + 0x0001B7, 0x0001B1, 0x002CED, 0x000182, 0x00052E, 0x000184, 0x000194, 0x000196, + 0x000528, 0x00052A, 0x0001B2, 0x002CEB, 0x0001B5, 0x0010B4, 0x01E90D, 0x01E90F, + 0x0010A2, 0x0001A0, 0x01E915, 0x0001A2, 0x01E917, 0x0001A4, 0x0001B3, 0x0001A6, + 0x0001A9, 0x0010A1, 0x0010B5, 0x01E911, 0x000189, 0x0010A0, 0x0001AF, 0x01E913, + 0x0010A4, 0x0010A5, 0x0010A6, 0x001F9D, 0x001F9F, 0x001F99, 0x001F9B, 0x0010A7, + 0x000198, 0x0001B8, 0x0001BC, 0x002CAC, 0x00019C, 0x00019D, 0x002CAE, 0x00019F, + 0x002CA8, 0x002CAA, 0x002CA4, 0x002CA6, 0x002CA0, 0x0001C4, 0x002CA2, 0x002CBC, + 0x002CBE, 0x0001C8, 0x002CB8, 0x0001CA, 0x002CBA, 0x002CB4, 0x002CB6, 0x002CB0, + 0x0001D1, 0x002CB2, 0x0001D3, 0x010CAD, 0x0001D5, 0x010CAF, 0x010CA9, 0x010CAB, + 0x0001D9, 0x010CA5, 0x0001DB, 0x010CA7, 0x010CA1, 0x010CA3, 0x002C9C, 0x0001DE, + 0x002C9E, 0x0001E2, 0x0001E0, 0x002C98, 0x002C9A, 0x0001E4, 0x002C94, 0x0001E6, + 0x002C96, 0x0001E8, 0x010CB1, 0x0001EA, 0x010C8C, 0x0001EC, 0x010C8D, 0x0001EE, + 0x010C8E, 0x010C8F, 0x010C88, 0x0001F2, 0x010C89, 0x0001F4, 0x010C8A, 0x0001F6, + 0x010C8B, 0x0001F8, 0x010C84, 0x0001FA, 0x010C85, 0x0001FC, 0x010C86, 0x0001FE, + 0x010C87, 0x010C80, 0x010C81, 0x010C82, 0x010C83, 0x010C9C, 0x010C9D, 0x010C9E, + 0x010C9F, 0x010C98, 0x010C99, 0x010C9A, 0x010C9B, 0x010C94, 0x010C95, 0x010C96, + 0x010C97, 0x010C90, 0x010C91, 0x010C92, 0x010C93, 0x00A68C, 0x00A68E, 0x00A688, + 0x00A68A, 0x00A684, 0x00A686, 0x00A680, 0x00A682, 0x00A698, 0x00A69A, 0x00A694, + 0x000222, 0x00A696, 0x000226, 0x00A690, 0x00A692, 0x00A76C, 0x00A76E, 0x00A768, + 0x00A76A, 0x00A764, 0x000224, 0x00A766, 0x00A760, 0x00A762, 0x00A77D, 0x00A77E, + 0x00A779, 0x00A77B, 0x000245, 0x000232, 0x00A740, 0x000241, 0x00A742, 0x000243, + 0x00A75C, 0x00022A, 0x00A75E, 0x00023A, 0x000228, 0x00022C, 0x00022E, 0x00023E, + 0x000244, 0x00A758, 0x000246, 0x00A75A, 0x00A754, 0x00A756, 0x00A750, 0x00A752, + 0x000220, 0x000248, 0x00A73C, 0x00024A, 0x00023D, 0x00024C, 0x00A738, 0x00024E, + 0x00023B, 0x00A734, 0x00A736, 0x000230, 0x00020C, 0x00020E, 0x000208, 0x00020A, + 0x000204, 0x000206, 0x000200, 0x000202, 0x00021C, 0x00021E, 0x000218, 0x00021A, + 0x000214, 0x000216, 0x000210, 0x000212, 0x00A7AC, 0x00A7AD, 0x00A7AE, 0x00A7A8, + 0x00A7AA, 0x00A7AB, 0x0013ED, 0x0013EF, 0x0013E9, 0x0013EB, 0x0013E4, 0x0013E5, + 0x0013E6, 0x0013E7, 0x0013E0, 0x0013E1, 0x0013E2, 0x0013E3, 0x00A7B4, 0x00A7B6, + 0x00A7B0, 0x00A7B1, 0x00A7B2, 0x00A7B3, 0x0013F4, 0x0013F0, 0x0013F1, 0x0013F2, + 0x0013CD, 0x0013CF, 0x0013C9, 0x0013CB, 0x0013C5, 0x0013C7, 0x0013C1, 0x0013C3, + 0x0013DC, 0x0013DD, 0x0013DF, 0x0013D9, 0x0013DB, 0x0013D4, 0x0013D5, 0x0013D6, + 0x0013D7, 0x0013D0, 0x0013D1, 0x0013D2, 0x0013D3, 0x0013AC, 0x0013AD, 0x0013AE, + 0x0013AF, 0x0013A8, 0x0013A9, 0x0013AA, 0x0013AB, 0x0013A4, 0x0013A5, 0x0013A6, + 0x0013A0, 0x0013A1, 0x0013A2, 0x0013A3, 0x0013BC, 0x0013BD, 0x0013BF, 0x0013B9, + 0x0013BB, 0x0013B4, 0x0013B5, 0x0013B6, 0x0013B7, 0x0013B0, 0x0013B1, 0x0013B2, + 0x0013B3, 0x0003EC, 0x0003EE, 0x0003E8, 0x0003EA, 0x0003E4, 0x0003E6, 0x0003E0, + 0x0003E2, 0x00216C, 0x002168, 0x00216B, 0x002165, 0x002166, 0x002160, 0x002161, + 0x002162, 0x002163, 0x0003CF, 0x0003DC, 0x0003DE, 0x0003D8, 0x0003DA, 0x0003A8, + 0x0003A9, 0x0003AA, 0x0003AB, 0x0003A4, 0x0003A5, 0x0003A6, 0x0003A7, 0x0003A0, + 0x0003A1, 0x0003A3, 0x00212A, 0x00212B, 0x002126, 0x002164, 0x002167, 0x00038C, + 0x002169, 0x00038E, 0x00038F, 0x00216A, 0x00216D, 0x000388, 0x00216F, 0x00216E, + 0x000389, 0x00038A, 0x0010CD, 0x000386, 0x002132, 0x00039E, 0x000394, 0x000395, + 0x000396, 0x000397, 0x000391, 0x000392, 0x000393, 0x0010AC, 0x0010AD, 0x0010AE, + 0x0010AF, 0x0010A8, 0x002183, 0x0010A9, 0x0010AA, 0x0010AB, 0x0010BC, 0x0010BD, + 0x0010BE, 0x0010BF, 0x0010B8, 0x0010B9, 0x0010BA, 0x0010BB, 0x010408, 0x010404, + 0x00A640, 0x010405, 0x00A642, 0x010406, 0x010407, 0x010403, 0x010414, 0x010415, + 0x010416, 0x010417, 0x00A646, 0x00A65A, 0x00A65C, 0x010410, 0x010411, 0x00A65E, + 0x010412, 0x00A650, 0x00A652, 0x010413, 0x00A654, 0x0024CC, 0x00A656, 0x00A644, + 0x0024CD, 0x00A658, 0x0024CE, 0x0024CF, 0x0024C8, 0x0024C9, 0x00A64A, 0x00A648, + 0x00A660, 0x00A64C, 0x00A662, 0x0024CA, 0x00A664, 0x00A64E, 0x0024CB, 0x0024C4, + 0x0024C5, 0x0024C6, 0x0024C7, 0x0024C0, 0x0024C1, 0x0024C2, 0x0024C3, 0x0104CC, + 0x0104CD, 0x0104CE, 0x0104CF, 0x0104C8, 0x0104C9, 0x0104CA, 0x00A666, 0x0104CB, + 0x00A668, 0x0104C4, 0x00A66A, 0x0104C5, 0x00A66C, 0x0104C6, 0x0104C7, 0x0104C0, + 0x002C01, 0x0104C1, 0x002C03, 0x0104C2, 0x0104C3, 0x0024BC, 0x0024BD, 0x0024BE, + 0x0024BF, 0x0024B8, 0x0024B9, 0x0024BA, 0x0024B6, 0x0024B7, 0x0104D0, 0x0104D1, + 0x0104D2, 0x002C15, 0x002C13, 0x0104D3, 0x001E6C, 0x001E6E, 0x002C17, 0x001E68, + 0x002C11, 0x001E6A, 0x0104BD, 0x0104BF, 0x0104B9, 0x0104BB, 0x0000C5, 0x0000C7, + 0x0000C1, 0x0000C3, 0x002C23, 0x002C21, 0x0000DD, 0x0000D9, 0x0000DB, 0x0000D5, + 0x0000D1, 0x0000D3, 0x001E5C, 0x001E5E, 0x001E58, 0x001E5A, 0x001E54, 0x00FF27, + 0x001E56, 0x000372, 0x000370, 0x00FF2B, 0x000376, 0x00FF29, 0x001E50, 0x001E52, + 0x001E2C, 0x001E2E, 0x001E28, 0x001E2A, 0x001E24, 0x001E26, 0x00037F, 0x001E20, + 0x002C00, 0x001E22, 0x002C02, 0x001E3C, 0x002C6D, 0x001E3E, 0x002C6E, 0x001E38, + 0x002C6F, 0x002C69, 0x002C06, 0x002C1A, 0x002C1C, 0x00039D, 0x00039C, 0x002C1E, + 0x002C70, 0x002C10, 0x002C12, 0x002C72, 0x002C14, 0x002C75, 0x002C16, 0x002C04, + 0x000399, 0x002C18, 0x00039B, 0x00039A, 0x000398, 0x00039F, 0x002C0A, 0x002C08, + 0x002C20, 0x002C0C, 0x002C22, 0x002C62, 0x002C24, 0x002C0E, 0x002C60, 0x002C63, + 0x010CA0, 0x010CA8, 0x010CA2, 0x010CAA, 0x002C64, 0x010CA4, 0x002C67, 0x010CA6, + 0x010CB0, 0x002C7F, 0x010CB2, 0x001F0B, 0x001E3A, 0x001F09, 0x002C26, 0x000197, + 0x002C28, 0x010CAC, 0x002C2A, 0x002CDC, 0x002C2C, 0x010CAE, 0x002C6B, 0x002C7E, + 0x0118AD, 0x0118AF, 0x0118A9, 0x0118AB, 0x002CD8, 0x0118A5, 0x002CDA, 0x0118A7, + 0x0118A1, 0x0118A3, 0x0118BD, 0x0118BF, 0x0118B9, 0x0118BB, 0x0118B5, 0x0118B7, + 0x0118B1, 0x0118B3, 0x001EEC, 0x00017D, 0x001EEE, 0x000179, 0x002C07, 0x001EEA, + 0x00017B, 0x002C19, 0x002C05, 0x002CD4, 0x000145, 0x000147, 0x000141, 0x000143, + 0x002CDE, 0x001EAC, 0x00013D, 0x001EAE, 0x00013F, 0x001EA8, 0x000139, 0x001EAA, + 0x002C80, 0x002C88, 0x002C82, 0x002C8A, 0x00013B, 0x002C84, 0x00042D, 0x002C86, + 0x002C90, 0x00042F, 0x002C92, 0x000429, 0x00042B, 0x0003F4, 0x0003F7, 0x000425, + 0x0003F9, 0x002C8C, 0x000427, 0x0003FA, 0x0003FD, 0x002C8E, 0x0003FF, 0x0003FE, + 0x00053E, 0x000400, 0x00053F, 0x000402, 0x002CC0, 0x000404, 0x002CC2, 0x000406, + 0x000539, 0x000408, 0x000538, 0x00040A, 0x002CC4, 0x00040C, 0x002CC6, 0x00040E, + 0x002CCA, 0x000410, 0x000413, 0x000412, 0x000411, 0x000414, 0x000417, 0x000416, + 0x000421, 0x00041A, 0x000418, 0x000423, 0x000415, 0x00041C, 0x002C0B, 0x00041E, + 0x00A722, 0x000420, 0x00A726, 0x000422, 0x002CCC, 0x000424, 0x002CCE, 0x000426, + 0x002CE0, 0x00042A, 0x00A724, 0x002CE2, 0x000428, 0x00042C, 0x002CC8, 0x00042E, + 0x002CD2, 0x002CD0, 0x000549, 0x00A732, 0x00054D, 0x0004D6, 0x00054F, 0x002CD6, + 0x0013C0, 0x00A72A, 0x002CF2, 0x00A73A, 0x00A728, 0x00A72C, 0x00A72E, 0x00A73E, + 0x00A744, 0x00040D, 0x00A746, 0x00048A, 0x0013C4, 0x0013CC, 0x0013C6, 0x0013CE, + 0x01E901, 0x00A748, 0x01E900, 0x00A74A, 0x00040F, 0x00A74C, 0x000409, 0x00A74E, + 0x01E906, 0x00040B, 0x01E907, 0x000405, 0x00049C, 0x000407, 0x000401, 0x000403, + 0x01E904, 0x01E905, 0x00041D, 0x00041F, 0x000419, 0x000498, 0x0013A7, 0x00049E, + 0x0013E8, 0x000460, 0x0013EA, 0x000462, 0x0013EC, 0x000464, 0x0013EE, 0x000466, + 0x00041B, 0x000468, 0x0001F7, 0x00046A, 0x0004E8, 0x00046C, 0x0001F1, 0x00046E, + 0x000474, 0x0013BA, 0x0013B8, 0x000472, 0x0013BE, 0x000470, 0x0004E4, 0x000476, + 0x00053C, 0x00053D, 0x0001CD, 0x00047A, 0x000478, 0x00047C, 0x0013C2, 0x00047E, + 0x0004E6, 0x00FF39, 0x0004AA, 0x00A78B, 0x0004D2, 0x00A78D, 0x0004AE, 0x0001CF, + 0x0013D8, 0x001E00, 0x0013DA, 0x001E02, 0x001E06, 0x001E04, 0x00048C, 0x00048E, + 0x0004B0, 0x001E0A, 0x001E08, 0x0004B2, 0x0004B4, 0x001E0C, 0x0004B6, 0x001E0E, + 0x00A790, 0x001E10, 0x00A792, 0x001E12, 0x000492, 0x001E14, 0x00A79A, 0x001E16, + 0x001E1A, 0x001E18, 0x000480, 0x0004A2, 0x0004A6, 0x001E1C, 0x0004A0, 0x001E1E, + 0x0013C8, 0x0001CB, 0x0013CA, 0x0004BA, 0x0004A4, 0x0004BC, 0x0013DE, 0x00FF21, + 0x000490, 0x000494, 0x002C09, 0x0013F3, 0x002C0D, 0x0013F5, 0x002C0F, 0x001F88, + 0x00A780, 0x001E30, 0x00A782, 0x001E32, 0x001E36, 0x001E34, 0x00A796, 0x0004BE, + 0x0004C1, 0x001F19, 0x0004C3, 0x0001C5, 0x0004C5, 0x00A784, 0x0004C7, 0x00A786, + 0x0004C9, 0x001E40, 0x0004CB, 0x001E42, 0x0004CD, 0x001E44, 0x001E48, 0x001E46, + 0x001E4A, 0x0004D0, 0x0004D4, 0x0004FE, 0x00A79C, 0x0001C7, 0x00A79E, 0x01E918, + 0x00A798, 0x0004D8, 0x01E909, 0x0004DA, 0x001E4C, 0x0004DC, 0x001E4E, 0x0004DE, + 0x00A7A0, 0x0004E0, 0x00A7A2, 0x0004E2, 0x00A7A4, 0x0004F8, 0x00A7A6, 0x0004FA, + 0x001E62, 0x001E60, 0x00049A, 0x0004EA, 0x001E66, 0x0004EC, 0x001E64, 0x0004EE, + 0x001F4D, 0x0004F0, 0x0001D7, 0x0004F2, 0x0001AC, 0x0004F4, 0x0001AE, 0x0004F6, + 0x001E74, 0x001E70, 0x001FB9, 0x001E72, 0x0004C0, 0x0004FC, 0x0001A7, 0x001E76, + 0x000540, 0x001E78, 0x000542, 0x001E7A, 0x000500, 0x001E7C, 0x000502, 0x001E7E, + 0x000524, 0x001E80, 0x000546, 0x001E82, 0x000504, 0x001E84, 0x000506, 0x001E86, + 0x00050A, 0x000550, 0x000552, 0x001E8A, 0x000554, 0x001E88, 0x000556, 0x000544, +}; + +/* indexes */ +const uint16_t NU_TOLOWER_VALUES_I[] = { + 0x0BC6, 0x0C3E, 0x0B9A, 0x0BD0, 0x04FB, 0x0C4C, 0x0540, 0x053A, 0x0BF8, 0x0546, + 0x0019, 0x0029, 0x04BF, 0x054C, 0x04C2, 0x0C50, 0x04DD, 0x0C57, 0x0C20, 0x04E0, + 0x0C53, 0x0C5B, 0x04B9, 0x0C5F, 0x04C8, 0x04C5, 0x002B, 0x002D, 0x0B92, 0x0017, + 0x0B96, 0x04CE, 0x0BDA, 0x0C73, 0x04F8, 0x0C77, 0x0031, 0x0C7B, 0x002F, 0x0C7F, + 0x0525, 0x0C83, 0x052B, 0x0C87, 0x04D1, 0x0C8B, 0x04D4, 0x0C8F, 0x0C9B, 0x0C93, + 0x0033, 0x0C97, 0x0C25, 0x0027, 0x0BEE, 0x0C9F, 0x0CAB, 0x0561, 0x055B, 0x0CA7, + 0x0C02, 0x0CA3, 0x0C0C, 0x0CAF, 0x0555, 0x0CB7, 0x0CB3, 0x04CB, 0x0C2F, 0x04FE, + 0x0CBB, 0x0CBF, 0x04DA, 0x0CC3, 0x05EE, 0x0CC7, 0x0013, 0x0CCB, 0x0015, 0x0CCF, + 0x0C1B, 0x0CD3, 0x0C34, 0x0CD7, 0x0501, 0x0CDB, 0x0C39, 0x0CDF, 0x12D2, 0x0CE3, + 0x0025, 0x12DA, 0x12E2, 0x12E6, 0x12EA, 0x12EE, 0x04F5, 0x0C42, 0x0504, 0x0CF7, + 0x0CF3, 0x0CFB, 0x0507, 0x0CFF, 0x05E9, 0x0D03, 0x1312, 0x0D07, 0x05E4, 0x0D0B, + 0x05DF, 0x0D0F, 0x000F, 0x0011, 0x001B, 0x001D, 0x0616, 0x0C2A, 0x12C2, 0x12CA, + 0x0023, 0x088C, 0x0882, 0x05F8, 0x0021, 0x0896, 0x001F, 0x08A0, 0x0BE4, 0x08AA, + 0x000D, 0x08B4, 0x08C8, 0x08BE, 0x0543, 0x0BAD, 0x08DC, 0x08D2, 0x05FD, 0x0602, + 0x0D6F, 0x08E6, 0x0D5F, 0x08F0, 0x04E6, 0x08FA, 0x12FA, 0x0904, 0x0918, 0x090E, + 0x000B, 0x0D67, 0x0D13, 0x0D4B, 0x0D5B, 0x0D1B, 0x0D23, 0x0D27, 0x0D2B, 0x0D2F, + 0x0611, 0x0C47, 0x0571, 0x04D7, 0x0D7B, 0x0009, 0x0D87, 0x0513, 0x0007, 0x060C, + 0x0D33, 0x0D73, 0x0D83, 0x0607, 0x0D6B, 0x0D77, 0x061B, 0x0620, 0x0625, 0x0510, + 0x056C, 0x05F3, 0x0567, 0x062A, 0x0D8F, 0x0D8B, 0x0D97, 0x0D93, 0x0648, 0x0D9B, + 0x0537, 0x0E3F, 0x0041, 0x0035, 0x0531, 0x003B, 0x0086, 0x0056, 0x008C, 0x0047, + 0x0DA3, 0x004D, 0x0DA7, 0x0053, 0x0DAB, 0x0059, 0x0DAF, 0x005F, 0x0050, 0x0065, + 0x0062, 0x006B, 0x0DC7, 0x0071, 0x007A, 0x0077, 0x0080, 0x0DB3, 0x0DBF, 0x0DBB, + 0x0DB7, 0x0DC3, 0x0DCF, 0x0DCB, 0x0634, 0x0D4F, 0x0652, 0x0D57, 0x131A, 0x042F, + 0x0429, 0x0D7F, 0x0599, 0x062F, 0x059E, 0x0639, 0x0D53, 0x0643, 0x0594, 0x064D, + 0x0661, 0x0657, 0x132A, 0x0BA8, 0x0675, 0x063E, 0x066B, 0x016C, 0x0003, 0x0441, + 0x0005, 0x014B, 0x005C, 0x12C6, 0x0001, 0x0BD5, 0x1382, 0x008F, 0x05B2, 0x0092, + 0x1352, 0x0095, 0x135A, 0x0098, 0x0E5B, 0x009B, 0x0E63, 0x009E, 0x1342, 0x00A1, + 0x134A, 0x00A4, 0x1366, 0x00A7, 0x0EF7, 0x00AA, 0x132E, 0x00AD, 0x05AD, 0x00B0, + 0x05A3, 0x1376, 0x136E, 0x00B6, 0x0169, 0x00B3, 0x137E, 0x12BE, 0x0E33, 0x00C2, + 0x00BF, 0x0E3B, 0x0D3B, 0x05A8, 0x00C5, 0x00C8, 0x0E7F, 0x00CB, 0x0E87, 0x00CE, + 0x138A, 0x00D1, 0x0D43, 0x00D4, 0x1326, 0x00D9, 0x133A, 0x0D47, 0x131E, 0x00DC, + 0x133E, 0x00DF, 0x0E6B, 0x0E7B, 0x0D3F, 0x12BA, 0x00B9, 0x0D63, 0x00BC, 0x1306, + 0x0723, 0x0727, 0x073B, 0x073F, 0x1336, 0x12F2, 0x130E, 0x130A, 0x0E5F, 0x12F6, + 0x0E67, 0x00FA, 0x1302, 0x00FD, 0x12FE, 0x0100, 0x0109, 0x0103, 0x040E, 0x0106, + 0x0E73, 0x1332, 0x0E6F, 0x010C, 0x0115, 0x1362, 0x136A, 0x0112, 0x1372, 0x010F, + 0x137A, 0x0118, 0x0E77, 0x011B, 0x0FFF, 0x011E, 0x1003, 0x0121, 0x0FEF, 0x0124, + 0x012A, 0x0127, 0x0E8B, 0x0E83, 0x072B, 0x012D, 0x072F, 0x0130, 0x0FF7, 0x0133, + 0x0FDF, 0x0136, 0x06EF, 0x0139, 0x0FE7, 0x013C, 0x0767, 0x013F, 0x076F, 0x076B, + 0x0763, 0x077B, 0x1386, 0x016F, 0x0E47, 0x0E4B, 0x0E4F, 0x0E53, 0x0FBF, 0x0FC7, + 0x0166, 0x0154, 0x0FB7, 0x0157, 0x04EF, 0x015D, 0x0163, 0x0777, 0x0773, 0x0160, + 0x01AE, 0x01A2, 0x1107, 0x014E, 0x04F2, 0x0151, 0x0172, 0x0175, 0x04E9, 0x04EC, + 0x01A5, 0x1103, 0x01AB, 0x0733, 0x0BDF, 0x0BE9, 0x06EB, 0x0187, 0x0C07, 0x018A, + 0x0C11, 0x018D, 0x01A8, 0x0190, 0x0196, 0x06E7, 0x0737, 0x0BF3, 0x015A, 0x06E3, + 0x019F, 0x0BFD, 0x06F3, 0x06F7, 0x06FB, 0x1356, 0x135E, 0x1346, 0x134E, 0x06FF, + 0x017B, 0x01B1, 0x01B4, 0x1093, 0x017E, 0x0181, 0x1097, 0x0184, 0x108B, 0x108F, + 0x1083, 0x1087, 0x107B, 0x01B7, 0x107F, 0x10B3, 0x10B7, 0x01C0, 0x10AB, 0x01C3, + 0x10AF, 0x10A3, 0x10A7, 0x109B, 0x01CF, 0x109F, 0x01D2, 0x0860, 0x01D5, 0x086A, + 0x084C, 0x0856, 0x01DB, 0x0838, 0x01DE, 0x0842, 0x0824, 0x082E, 0x1073, 0x01E1, + 0x1077, 0x01E7, 0x01E4, 0x106B, 0x106F, 0x01EA, 0x1063, 0x01ED, 0x1067, 0x01F0, + 0x0874, 0x01F3, 0x07BB, 0x01F6, 0x07C0, 0x01F9, 0x07C5, 0x07CA, 0x07A7, 0x01FF, + 0x07AC, 0x0202, 0x07B1, 0x0205, 0x07B6, 0x020B, 0x0793, 0x020E, 0x0798, 0x0211, + 0x079D, 0x0214, 0x07A2, 0x077F, 0x0784, 0x0789, 0x078E, 0x080B, 0x0810, 0x0815, + 0x081A, 0x07F7, 0x07FC, 0x0801, 0x0806, 0x07E3, 0x07E8, 0x07ED, 0x07F2, 0x07CF, + 0x07D4, 0x07D9, 0x07DE, 0x1183, 0x1187, 0x117B, 0x117F, 0x1173, 0x1177, 0x116B, + 0x116F, 0x119B, 0x119F, 0x1193, 0x024A, 0x1197, 0x0250, 0x118B, 0x118F, 0x1233, + 0x1237, 0x122B, 0x122F, 0x1223, 0x024D, 0x1227, 0x121B, 0x121F, 0x1243, 0x1247, + 0x123B, 0x123F, 0x027C, 0x0262, 0x11DB, 0x0273, 0x11DF, 0x0276, 0x1213, 0x0256, + 0x1217, 0x0265, 0x0253, 0x0259, 0x025C, 0x026F, 0x0279, 0x120B, 0x027F, 0x120F, + 0x1203, 0x1207, 0x11FB, 0x11FF, 0x0247, 0x0282, 0x11D3, 0x0285, 0x026C, 0x0288, + 0x11CB, 0x028B, 0x0269, 0x11C3, 0x11C7, 0x025F, 0x0229, 0x022C, 0x0223, 0x0226, + 0x021D, 0x0220, 0x0217, 0x021A, 0x0241, 0x0244, 0x023B, 0x023E, 0x0235, 0x0238, + 0x022F, 0x0232, 0x1298, 0x129B, 0x129E, 0x128E, 0x1292, 0x1295, 0x0A56, 0x0A5E, + 0x0A46, 0x0A4E, 0x0A32, 0x0A36, 0x0A3A, 0x0A3E, 0x0A22, 0x0A26, 0x0A2A, 0x0A2E, + 0x12AE, 0x12B2, 0x12A1, 0x12A4, 0x12A7, 0x12AA, 0x0A72, 0x0A62, 0x0A66, 0x0A6A, + 0x09D6, 0x09DE, 0x09C6, 0x09CE, 0x09B6, 0x09BE, 0x09A6, 0x09AE, 0x0A12, 0x0A16, + 0x0A1E, 0x0A06, 0x0A0E, 0x09F2, 0x09F6, 0x09FA, 0x09FE, 0x09E2, 0x09E6, 0x09EA, + 0x09EE, 0x0952, 0x0956, 0x095A, 0x095E, 0x0942, 0x0946, 0x094A, 0x094E, 0x0932, + 0x0936, 0x093A, 0x0922, 0x0926, 0x092A, 0x092E, 0x0992, 0x0996, 0x099E, 0x0986, + 0x098E, 0x0972, 0x0976, 0x097A, 0x097E, 0x0962, 0x0966, 0x096A, 0x096E, 0x031E, + 0x0321, 0x0318, 0x031B, 0x0312, 0x0315, 0x030C, 0x030F, 0x0ECF, 0x0EBF, 0x0ECB, + 0x0EB3, 0x0EB7, 0x0E9F, 0x0EA3, 0x0EA7, 0x0EAB, 0x02FD, 0x0306, 0x0309, 0x0300, + 0x0303, 0x02F1, 0x02F4, 0x02F7, 0x02FA, 0x02E5, 0x02E8, 0x02EB, 0x02EE, 0x02DC, + 0x02DF, 0x02E2, 0x0E96, 0x0E98, 0x0E93, 0x0EAF, 0x0EBB, 0x02A6, 0x0EC3, 0x02A9, + 0x02AC, 0x0EC7, 0x0ED3, 0x029D, 0x0EDB, 0x0ED7, 0x02A0, 0x02A3, 0x087E, 0x029A, + 0x0E9B, 0x02D6, 0x02B8, 0x02BB, 0x02BE, 0x02C1, 0x02AF, 0x02B2, 0x02B5, 0x0713, + 0x0717, 0x071B, 0x071F, 0x0703, 0x0EDF, 0x0707, 0x070B, 0x070F, 0x0753, 0x0757, + 0x075B, 0x075F, 0x0743, 0x0747, 0x074B, 0x074F, 0x058F, 0x057B, 0x110F, 0x0580, + 0x1113, 0x0585, 0x058A, 0x0576, 0x05CB, 0x05D0, 0x05D5, 0x05DA, 0x111B, 0x1143, + 0x1147, 0x05B7, 0x05BC, 0x114B, 0x05C1, 0x112F, 0x1133, 0x05C6, 0x1137, 0x0F3B, + 0x113B, 0x1117, 0x0F3F, 0x113F, 0x0F43, 0x0F47, 0x0F2B, 0x0F2F, 0x1123, 0x111F, + 0x114F, 0x1127, 0x1153, 0x0F33, 0x1157, 0x112B, 0x0F37, 0x0F1B, 0x0F1F, 0x0F23, + 0x0F27, 0x0F0B, 0x0F0F, 0x0F13, 0x0F17, 0x06BB, 0x06C0, 0x06C5, 0x06CA, 0x06A7, + 0x06AC, 0x06B1, 0x115B, 0x06B6, 0x115F, 0x0693, 0x1163, 0x0698, 0x1167, 0x069D, + 0x06A2, 0x067F, 0x0F4F, 0x0684, 0x0F57, 0x0689, 0x068E, 0x0EFB, 0x0EFF, 0x0F03, + 0x0F07, 0x0EEB, 0x0EEF, 0x0EF3, 0x0EE3, 0x0EE7, 0x06CF, 0x06D4, 0x06D9, 0x0F9F, + 0x0F97, 0x06DE, 0x0B52, 0x0B56, 0x0FA7, 0x0B4A, 0x0F8F, 0x0B4E, 0x0670, 0x067A, + 0x065C, 0x0666, 0x0044, 0x004A, 0x0038, 0x003E, 0x0FD7, 0x0FCF, 0x0089, 0x007D, + 0x0083, 0x0074, 0x0068, 0x006E, 0x0B32, 0x0B36, 0x0B2A, 0x0B2E, 0x0B22, 0x12CE, + 0x0B26, 0x0291, 0x028E, 0x12DE, 0x0294, 0x12D6, 0x0B1A, 0x0B1E, 0x0AD2, 0x0AD6, + 0x0ACA, 0x0ACE, 0x0AC2, 0x0AC6, 0x0297, 0x0ABA, 0x0F4B, 0x0ABE, 0x0F53, 0x0AF2, + 0x1021, 0x0AF6, 0x1024, 0x0AEA, 0x1027, 0x1019, 0x0F63, 0x0FB3, 0x0FBB, 0x02D3, + 0x02D0, 0x0FC3, 0x102A, 0x0F8B, 0x0F93, 0x102D, 0x0F9B, 0x1031, 0x0FA3, 0x0F5B, + 0x02C7, 0x0FAB, 0x02CD, 0x02CA, 0x02C4, 0x02D9, 0x0F73, 0x0F6B, 0x0FCB, 0x0F7B, + 0x0FD3, 0x100B, 0x0FDB, 0x0F83, 0x1007, 0x100E, 0x081F, 0x0847, 0x0829, 0x0851, + 0x1012, 0x0833, 0x1015, 0x083D, 0x086F, 0x1038, 0x0879, 0x0D1F, 0x0AEE, 0x0D17, + 0x0FE3, 0x0178, 0x0FEB, 0x085B, 0x0FF3, 0x10F3, 0x0FFB, 0x0865, 0x101D, 0x1035, + 0x08C3, 0x08CD, 0x08AF, 0x08B9, 0x10EB, 0x089B, 0x10EF, 0x08A5, 0x0887, 0x0891, + 0x0913, 0x091D, 0x08FF, 0x0909, 0x08EB, 0x08F5, 0x08D7, 0x08E1, 0x0CEB, 0x0148, + 0x0CEF, 0x0142, 0x0F67, 0x0CE7, 0x0145, 0x0FAF, 0x0F5F, 0x10E3, 0x00F4, 0x00F7, + 0x00EE, 0x00F1, 0x10F7, 0x0C6B, 0x00E8, 0x0C6F, 0x00EB, 0x0C63, 0x00E2, 0x0C67, + 0x103B, 0x104B, 0x103F, 0x104F, 0x00E5, 0x1043, 0x03C0, 0x1047, 0x105B, 0x03C6, + 0x105F, 0x03B4, 0x03BA, 0x0324, 0x0327, 0x03A8, 0x032A, 0x1053, 0x03AE, 0x032D, + 0x0330, 0x1057, 0x0336, 0x0333, 0x051C, 0x0339, 0x051F, 0x033F, 0x10BB, 0x0345, + 0x10BF, 0x034B, 0x050D, 0x0351, 0x050A, 0x0357, 0x10C3, 0x035D, 0x10C7, 0x0363, + 0x10CF, 0x0369, 0x0372, 0x036F, 0x036C, 0x0375, 0x037E, 0x037B, 0x039C, 0x0387, + 0x0381, 0x03A2, 0x0378, 0x038D, 0x0F77, 0x0393, 0x11A3, 0x0399, 0x11AB, 0x039F, + 0x10D3, 0x03A5, 0x10D7, 0x03AB, 0x10FB, 0x03B7, 0x11A7, 0x10FF, 0x03B1, 0x03BD, + 0x10CB, 0x03C3, 0x10DF, 0x10DB, 0x053D, 0x11BF, 0x0549, 0x046E, 0x054F, 0x10E7, + 0x09A2, 0x11B3, 0x110B, 0x11CF, 0x11AF, 0x11B7, 0x11BB, 0x11D7, 0x11E3, 0x0360, + 0x11E7, 0x03FC, 0x09B2, 0x09D2, 0x09BA, 0x09DA, 0x0BA3, 0x11EB, 0x0B9E, 0x11EF, + 0x0366, 0x11F3, 0x0354, 0x11F7, 0x0BBC, 0x035A, 0x0BC1, 0x0348, 0x0417, 0x034E, + 0x033C, 0x0342, 0x0BB2, 0x0BB7, 0x0390, 0x0396, 0x0384, 0x0411, 0x093E, 0x041A, + 0x0A42, 0x03C9, 0x0A4A, 0x03CC, 0x0A52, 0x03CF, 0x0A5A, 0x03D2, 0x038A, 0x03D5, + 0x0208, 0x03D8, 0x0489, 0x03DB, 0x01FC, 0x03DE, 0x03E7, 0x098A, 0x0982, 0x03E4, + 0x099A, 0x03E1, 0x0483, 0x03EA, 0x0516, 0x0519, 0x01C9, 0x03F0, 0x03ED, 0x03F3, + 0x09AA, 0x03F6, 0x0486, 0x1316, 0x042C, 0x125B, 0x0468, 0x125F, 0x0432, 0x01CC, + 0x0A02, 0x0A7A, 0x0A0A, 0x0A7E, 0x0A86, 0x0A82, 0x03FF, 0x0402, 0x0435, 0x0A8E, + 0x0A8A, 0x0438, 0x043B, 0x0A92, 0x043E, 0x0A96, 0x1262, 0x0A9A, 0x1266, 0x0A9E, + 0x0408, 0x0AA2, 0x1272, 0x0AA6, 0x0AAE, 0x0AAA, 0x03F9, 0x0420, 0x0426, 0x0AB2, + 0x041D, 0x0AB6, 0x09C2, 0x01C6, 0x09CA, 0x0444, 0x0423, 0x0447, 0x0A1A, 0x12B6, + 0x0405, 0x040B, 0x0F6F, 0x0A6E, 0x0F7F, 0x0A76, 0x0F87, 0x1322, 0x124B, 0x0ADA, + 0x124F, 0x0ADE, 0x0AE6, 0x0AE2, 0x126A, 0x044A, 0x0450, 0x0D37, 0x0453, 0x01BA, + 0x0456, 0x1253, 0x0459, 0x1257, 0x045C, 0x0AFA, 0x045F, 0x0AFE, 0x0462, 0x0B02, + 0x0B0A, 0x0B06, 0x0B0E, 0x0465, 0x046B, 0x04AA, 0x1276, 0x01BD, 0x127A, 0x0C16, + 0x126E, 0x0471, 0x0BCB, 0x0474, 0x0B12, 0x0477, 0x0B16, 0x047A, 0x127E, 0x047D, + 0x1282, 0x0480, 0x1286, 0x04A1, 0x128A, 0x04A4, 0x0B3E, 0x0B3A, 0x0414, 0x048C, + 0x0B46, 0x048F, 0x0B42, 0x0492, 0x0D9F, 0x0495, 0x01D8, 0x0498, 0x0199, 0x049B, + 0x019C, 0x049E, 0x0B62, 0x0B5A, 0x0E37, 0x0B5E, 0x044D, 0x04A7, 0x0193, 0x0B66, + 0x0522, 0x0B6A, 0x0528, 0x0B6E, 0x04AD, 0x0B72, 0x04B0, 0x0B76, 0x04E3, 0x0B7A, + 0x0534, 0x0B7E, 0x04B3, 0x0B82, 0x04B6, 0x0B86, 0x04BC, 0x0552, 0x0558, 0x0B8E, + 0x055E, 0x0B8A, 0x0564, 0x052E, }; + +const uint8_t NU_TOLOWER_COMBINED[] = { + 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, + 0x00, 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, 0x00, 0x6C, + 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, + 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, + 0x00, 0x79, 0x00, 0x7A, 0x00, 0xC3, 0xA0, 0x00, 0xC3, 0xA1, 0x00, 0xC3, + 0xA2, 0x00, 0xC3, 0xA3, 0x00, 0xC3, 0xA4, 0x00, 0xC3, 0xA5, 0x00, 0xC3, + 0xA6, 0x00, 0xC3, 0xA7, 0x00, 0xC3, 0xA8, 0x00, 0xC3, 0xA9, 0x00, 0xC3, + 0xAA, 0x00, 0xC3, 0xAB, 0x00, 0xC3, 0xAC, 0x00, 0xC3, 0xAD, 0x00, 0xC3, + 0xAE, 0x00, 0xC3, 0xAF, 0x00, 0xC3, 0xB0, 0x00, 0xC3, 0xB1, 0x00, 0xC3, + 0xB2, 0x00, 0xC3, 0xB3, 0x00, 0xC3, 0xB4, 0x00, 0xC3, 0xB5, 0x00, 0xC3, + 0xB6, 0x00, 0xC3, 0xB8, 0x00, 0xC3, 0xB9, 0x00, 0xC3, 0xBA, 0x00, 0xC3, + 0xBB, 0x00, 0xC3, 0xBC, 0x00, 0xC3, 0xBD, 0x00, 0xC3, 0xBE, 0x00, 0xC4, + 0x81, 0x00, 0xC4, 0x83, 0x00, 0xC4, 0x85, 0x00, 0xC4, 0x87, 0x00, 0xC4, + 0x89, 0x00, 0xC4, 0x8B, 0x00, 0xC4, 0x8D, 0x00, 0xC4, 0x8F, 0x00, 0xC4, + 0x91, 0x00, 0xC4, 0x93, 0x00, 0xC4, 0x95, 0x00, 0xC4, 0x97, 0x00, 0xC4, + 0x99, 0x00, 0xC4, 0x9B, 0x00, 0xC4, 0x9D, 0x00, 0xC4, 0x9F, 0x00, 0xC4, + 0xA1, 0x00, 0xC4, 0xA3, 0x00, 0xC4, 0xA5, 0x00, 0xC4, 0xA7, 0x00, 0xC4, + 0xA9, 0x00, 0xC4, 0xAB, 0x00, 0xC4, 0xAD, 0x00, 0xC4, 0xAF, 0x00, 0x69, + 0x00, 0xC4, 0xB3, 0x00, 0xC4, 0xB5, 0x00, 0xC4, 0xB7, 0x00, 0xC4, 0xBA, + 0x00, 0xC4, 0xBC, 0x00, 0xC4, 0xBE, 0x00, 0xC5, 0x80, 0x00, 0xC5, 0x82, + 0x00, 0xC5, 0x84, 0x00, 0xC5, 0x86, 0x00, 0xC5, 0x88, 0x00, 0xC5, 0x8B, + 0x00, 0xC5, 0x8D, 0x00, 0xC5, 0x8F, 0x00, 0xC5, 0x91, 0x00, 0xC5, 0x93, + 0x00, 0xC5, 0x95, 0x00, 0xC5, 0x97, 0x00, 0xC5, 0x99, 0x00, 0xC5, 0x9B, + 0x00, 0xC5, 0x9D, 0x00, 0xC5, 0x9F, 0x00, 0xC5, 0xA1, 0x00, 0xC5, 0xA3, + 0x00, 0xC5, 0xA5, 0x00, 0xC5, 0xA7, 0x00, 0xC5, 0xA9, 0x00, 0xC5, 0xAB, + 0x00, 0xC5, 0xAD, 0x00, 0xC5, 0xAF, 0x00, 0xC5, 0xB1, 0x00, 0xC5, 0xB3, + 0x00, 0xC5, 0xB5, 0x00, 0xC5, 0xB7, 0x00, 0xC3, 0xBF, 0x00, 0xC5, 0xBA, + 0x00, 0xC5, 0xBC, 0x00, 0xC5, 0xBE, 0x00, 0xC9, 0x93, 0x00, 0xC6, 0x83, + 0x00, 0xC6, 0x85, 0x00, 0xC9, 0x94, 0x00, 0xC6, 0x88, 0x00, 0xC9, 0x96, + 0x00, 0xC9, 0x97, 0x00, 0xC6, 0x8C, 0x00, 0xC7, 0x9D, 0x00, 0xC9, 0x99, + 0x00, 0xC9, 0x9B, 0x00, 0xC6, 0x92, 0x00, 0xC9, 0xA0, 0x00, 0xC9, 0xA3, + 0x00, 0xC9, 0xA9, 0x00, 0xC9, 0xA8, 0x00, 0xC6, 0x99, 0x00, 0xC9, 0xAF, + 0x00, 0xC9, 0xB2, 0x00, 0xC9, 0xB5, 0x00, 0xC6, 0xA1, 0x00, 0xC6, 0xA3, + 0x00, 0xC6, 0xA5, 0x00, 0xCA, 0x80, 0x00, 0xC6, 0xA8, 0x00, 0xCA, 0x83, + 0x00, 0xC6, 0xAD, 0x00, 0xCA, 0x88, 0x00, 0xC6, 0xB0, 0x00, 0xCA, 0x8A, + 0x00, 0xCA, 0x8B, 0x00, 0xC6, 0xB4, 0x00, 0xC6, 0xB6, 0x00, 0xCA, 0x92, + 0x00, 0xC6, 0xB9, 0x00, 0xC6, 0xBD, 0x00, 0xC7, 0x86, 0x00, 0xC7, 0x86, + 0x00, 0xC7, 0x89, 0x00, 0xC7, 0x89, 0x00, 0xC7, 0x8C, 0x00, 0xC7, 0x8C, + 0x00, 0xC7, 0x8E, 0x00, 0xC7, 0x90, 0x00, 0xC7, 0x92, 0x00, 0xC7, 0x94, + 0x00, 0xC7, 0x96, 0x00, 0xC7, 0x98, 0x00, 0xC7, 0x9A, 0x00, 0xC7, 0x9C, + 0x00, 0xC7, 0x9F, 0x00, 0xC7, 0xA1, 0x00, 0xC7, 0xA3, 0x00, 0xC7, 0xA5, + 0x00, 0xC7, 0xA7, 0x00, 0xC7, 0xA9, 0x00, 0xC7, 0xAB, 0x00, 0xC7, 0xAD, + 0x00, 0xC7, 0xAF, 0x00, 0xC7, 0xB3, 0x00, 0xC7, 0xB3, 0x00, 0xC7, 0xB5, + 0x00, 0xC6, 0x95, 0x00, 0xC6, 0xBF, 0x00, 0xC7, 0xB9, 0x00, 0xC7, 0xBB, + 0x00, 0xC7, 0xBD, 0x00, 0xC7, 0xBF, 0x00, 0xC8, 0x81, 0x00, 0xC8, 0x83, + 0x00, 0xC8, 0x85, 0x00, 0xC8, 0x87, 0x00, 0xC8, 0x89, 0x00, 0xC8, 0x8B, + 0x00, 0xC8, 0x8D, 0x00, 0xC8, 0x8F, 0x00, 0xC8, 0x91, 0x00, 0xC8, 0x93, + 0x00, 0xC8, 0x95, 0x00, 0xC8, 0x97, 0x00, 0xC8, 0x99, 0x00, 0xC8, 0x9B, + 0x00, 0xC8, 0x9D, 0x00, 0xC8, 0x9F, 0x00, 0xC6, 0x9E, 0x00, 0xC8, 0xA3, + 0x00, 0xC8, 0xA5, 0x00, 0xC8, 0xA7, 0x00, 0xC8, 0xA9, 0x00, 0xC8, 0xAB, + 0x00, 0xC8, 0xAD, 0x00, 0xC8, 0xAF, 0x00, 0xC8, 0xB1, 0x00, 0xC8, 0xB3, + 0x00, 0xE2, 0xB1, 0xA5, 0x00, 0xC8, 0xBC, 0x00, 0xC6, 0x9A, 0x00, 0xE2, + 0xB1, 0xA6, 0x00, 0xC9, 0x82, 0x00, 0xC6, 0x80, 0x00, 0xCA, 0x89, 0x00, + 0xCA, 0x8C, 0x00, 0xC9, 0x87, 0x00, 0xC9, 0x89, 0x00, 0xC9, 0x8B, 0x00, + 0xC9, 0x8D, 0x00, 0xC9, 0x8F, 0x00, 0xCD, 0xB1, 0x00, 0xCD, 0xB3, 0x00, + 0xCD, 0xB7, 0x00, 0xCF, 0xB3, 0x00, 0xCE, 0xAC, 0x00, 0xCE, 0xAD, 0x00, + 0xCE, 0xAE, 0x00, 0xCE, 0xAF, 0x00, 0xCF, 0x8C, 0x00, 0xCF, 0x8D, 0x00, + 0xCF, 0x8E, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB2, 0x00, 0xCE, 0xB3, 0x00, + 0xCE, 0xB4, 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0xB6, 0x00, 0xCE, 0xB7, 0x00, + 0xCE, 0xB8, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xBA, 0x00, 0xCE, 0xBB, 0x00, + 0xCE, 0xBC, 0x00, 0xCE, 0xBD, 0x00, 0xCE, 0xBE, 0x00, 0xCE, 0xBF, 0x00, + 0xCF, 0x80, 0x00, 0xCF, 0x81, 0x00, 0xCF, 0x83, 0x00, 0xCF, 0x84, 0x00, + 0xCF, 0x85, 0x00, 0xCF, 0x86, 0x00, 0xCF, 0x87, 0x00, 0xCF, 0x88, 0x00, + 0xCF, 0x89, 0x00, 0xCF, 0x8A, 0x00, 0xCF, 0x8B, 0x00, 0xCF, 0x97, 0x00, + 0xCF, 0x99, 0x00, 0xCF, 0x9B, 0x00, 0xCF, 0x9D, 0x00, 0xCF, 0x9F, 0x00, + 0xCF, 0xA1, 0x00, 0xCF, 0xA3, 0x00, 0xCF, 0xA5, 0x00, 0xCF, 0xA7, 0x00, + 0xCF, 0xA9, 0x00, 0xCF, 0xAB, 0x00, 0xCF, 0xAD, 0x00, 0xCF, 0xAF, 0x00, + 0xCE, 0xB8, 0x00, 0xCF, 0xB8, 0x00, 0xCF, 0xB2, 0x00, 0xCF, 0xBB, 0x00, + 0xCD, 0xBB, 0x00, 0xCD, 0xBC, 0x00, 0xCD, 0xBD, 0x00, 0xD1, 0x90, 0x00, + 0xD1, 0x91, 0x00, 0xD1, 0x92, 0x00, 0xD1, 0x93, 0x00, 0xD1, 0x94, 0x00, + 0xD1, 0x95, 0x00, 0xD1, 0x96, 0x00, 0xD1, 0x97, 0x00, 0xD1, 0x98, 0x00, + 0xD1, 0x99, 0x00, 0xD1, 0x9A, 0x00, 0xD1, 0x9B, 0x00, 0xD1, 0x9C, 0x00, + 0xD1, 0x9D, 0x00, 0xD1, 0x9E, 0x00, 0xD1, 0x9F, 0x00, 0xD0, 0xB0, 0x00, + 0xD0, 0xB1, 0x00, 0xD0, 0xB2, 0x00, 0xD0, 0xB3, 0x00, 0xD0, 0xB4, 0x00, + 0xD0, 0xB5, 0x00, 0xD0, 0xB6, 0x00, 0xD0, 0xB7, 0x00, 0xD0, 0xB8, 0x00, + 0xD0, 0xB9, 0x00, 0xD0, 0xBA, 0x00, 0xD0, 0xBB, 0x00, 0xD0, 0xBC, 0x00, + 0xD0, 0xBD, 0x00, 0xD0, 0xBE, 0x00, 0xD0, 0xBF, 0x00, 0xD1, 0x80, 0x00, + 0xD1, 0x81, 0x00, 0xD1, 0x82, 0x00, 0xD1, 0x83, 0x00, 0xD1, 0x84, 0x00, + 0xD1, 0x85, 0x00, 0xD1, 0x86, 0x00, 0xD1, 0x87, 0x00, 0xD1, 0x88, 0x00, + 0xD1, 0x89, 0x00, 0xD1, 0x8A, 0x00, 0xD1, 0x8B, 0x00, 0xD1, 0x8C, 0x00, + 0xD1, 0x8D, 0x00, 0xD1, 0x8E, 0x00, 0xD1, 0x8F, 0x00, 0xD1, 0xA1, 0x00, + 0xD1, 0xA3, 0x00, 0xD1, 0xA5, 0x00, 0xD1, 0xA7, 0x00, 0xD1, 0xA9, 0x00, + 0xD1, 0xAB, 0x00, 0xD1, 0xAD, 0x00, 0xD1, 0xAF, 0x00, 0xD1, 0xB1, 0x00, + 0xD1, 0xB3, 0x00, 0xD1, 0xB5, 0x00, 0xD1, 0xB7, 0x00, 0xD1, 0xB9, 0x00, + 0xD1, 0xBB, 0x00, 0xD1, 0xBD, 0x00, 0xD1, 0xBF, 0x00, 0xD2, 0x81, 0x00, + 0xD2, 0x8B, 0x00, 0xD2, 0x8D, 0x00, 0xD2, 0x8F, 0x00, 0xD2, 0x91, 0x00, + 0xD2, 0x93, 0x00, 0xD2, 0x95, 0x00, 0xD2, 0x97, 0x00, 0xD2, 0x99, 0x00, + 0xD2, 0x9B, 0x00, 0xD2, 0x9D, 0x00, 0xD2, 0x9F, 0x00, 0xD2, 0xA1, 0x00, + 0xD2, 0xA3, 0x00, 0xD2, 0xA5, 0x00, 0xD2, 0xA7, 0x00, 0xD2, 0xA9, 0x00, + 0xD2, 0xAB, 0x00, 0xD2, 0xAD, 0x00, 0xD2, 0xAF, 0x00, 0xD2, 0xB1, 0x00, + 0xD2, 0xB3, 0x00, 0xD2, 0xB5, 0x00, 0xD2, 0xB7, 0x00, 0xD2, 0xB9, 0x00, + 0xD2, 0xBB, 0x00, 0xD2, 0xBD, 0x00, 0xD2, 0xBF, 0x00, 0xD3, 0x8F, 0x00, + 0xD3, 0x82, 0x00, 0xD3, 0x84, 0x00, 0xD3, 0x86, 0x00, 0xD3, 0x88, 0x00, + 0xD3, 0x8A, 0x00, 0xD3, 0x8C, 0x00, 0xD3, 0x8E, 0x00, 0xD3, 0x91, 0x00, + 0xD3, 0x93, 0x00, 0xD3, 0x95, 0x00, 0xD3, 0x97, 0x00, 0xD3, 0x99, 0x00, + 0xD3, 0x9B, 0x00, 0xD3, 0x9D, 0x00, 0xD3, 0x9F, 0x00, 0xD3, 0xA1, 0x00, + 0xD3, 0xA3, 0x00, 0xD3, 0xA5, 0x00, 0xD3, 0xA7, 0x00, 0xD3, 0xA9, 0x00, + 0xD3, 0xAB, 0x00, 0xD3, 0xAD, 0x00, 0xD3, 0xAF, 0x00, 0xD3, 0xB1, 0x00, + 0xD3, 0xB3, 0x00, 0xD3, 0xB5, 0x00, 0xD3, 0xB7, 0x00, 0xD3, 0xB9, 0x00, + 0xD3, 0xBB, 0x00, 0xD3, 0xBD, 0x00, 0xD3, 0xBF, 0x00, 0xD4, 0x81, 0x00, + 0xD4, 0x83, 0x00, 0xD4, 0x85, 0x00, 0xD4, 0x87, 0x00, 0xD4, 0x89, 0x00, + 0xD4, 0x8B, 0x00, 0xD4, 0x8D, 0x00, 0xD4, 0x8F, 0x00, 0xD4, 0x91, 0x00, + 0xD4, 0x93, 0x00, 0xD4, 0x95, 0x00, 0xD4, 0x97, 0x00, 0xD4, 0x99, 0x00, + 0xD4, 0x9B, 0x00, 0xD4, 0x9D, 0x00, 0xD4, 0x9F, 0x00, 0xD4, 0xA1, 0x00, + 0xD4, 0xA3, 0x00, 0xD4, 0xA5, 0x00, 0xD4, 0xA7, 0x00, 0xD4, 0xA9, 0x00, + 0xD4, 0xAB, 0x00, 0xD4, 0xAD, 0x00, 0xD4, 0xAF, 0x00, 0xD5, 0xA1, 0x00, + 0xD5, 0xA2, 0x00, 0xD5, 0xA3, 0x00, 0xD5, 0xA4, 0x00, 0xD5, 0xA5, 0x00, + 0xD5, 0xA6, 0x00, 0xD5, 0xA7, 0x00, 0xD5, 0xA8, 0x00, 0xD5, 0xA9, 0x00, + 0xD5, 0xAA, 0x00, 0xD5, 0xAB, 0x00, 0xD5, 0xAC, 0x00, 0xD5, 0xAD, 0x00, + 0xD5, 0xAE, 0x00, 0xD5, 0xAF, 0x00, 0xD5, 0xB0, 0x00, 0xD5, 0xB1, 0x00, + 0xD5, 0xB2, 0x00, 0xD5, 0xB3, 0x00, 0xD5, 0xB4, 0x00, 0xD5, 0xB5, 0x00, + 0xD5, 0xB6, 0x00, 0xD5, 0xB7, 0x00, 0xD5, 0xB8, 0x00, 0xD5, 0xB9, 0x00, + 0xD5, 0xBA, 0x00, 0xD5, 0xBB, 0x00, 0xD5, 0xBC, 0x00, 0xD5, 0xBD, 0x00, + 0xD5, 0xBE, 0x00, 0xD5, 0xBF, 0x00, 0xD6, 0x80, 0x00, 0xD6, 0x81, 0x00, + 0xD6, 0x82, 0x00, 0xD6, 0x83, 0x00, 0xD6, 0x84, 0x00, 0xD6, 0x85, 0x00, + 0xD6, 0x86, 0x00, 0xF0, 0x90, 0x90, 0xA8, 0x00, 0xF0, 0x90, 0x90, 0xA9, + 0x00, 0xF0, 0x90, 0x90, 0xAA, 0x00, 0xF0, 0x90, 0x90, 0xAB, 0x00, 0xF0, + 0x90, 0x90, 0xAC, 0x00, 0xF0, 0x90, 0x90, 0xAD, 0x00, 0xF0, 0x90, 0x90, + 0xAE, 0x00, 0xF0, 0x90, 0x90, 0xAF, 0x00, 0xF0, 0x90, 0x90, 0xB0, 0x00, + 0xF0, 0x90, 0x90, 0xB1, 0x00, 0xF0, 0x90, 0x90, 0xB2, 0x00, 0xF0, 0x90, + 0x90, 0xB3, 0x00, 0xF0, 0x90, 0x90, 0xB4, 0x00, 0xF0, 0x90, 0x90, 0xB5, + 0x00, 0xF0, 0x90, 0x90, 0xB6, 0x00, 0xF0, 0x90, 0x90, 0xB7, 0x00, 0xF0, + 0x90, 0x90, 0xB8, 0x00, 0xF0, 0x90, 0x90, 0xB9, 0x00, 0xF0, 0x90, 0x90, + 0xBA, 0x00, 0xF0, 0x90, 0x90, 0xBB, 0x00, 0xF0, 0x90, 0x90, 0xBC, 0x00, + 0xF0, 0x90, 0x90, 0xBD, 0x00, 0xF0, 0x90, 0x90, 0xBE, 0x00, 0xF0, 0x90, + 0x90, 0xBF, 0x00, 0xF0, 0x90, 0x91, 0x80, 0x00, 0xF0, 0x90, 0x91, 0x81, + 0x00, 0xF0, 0x90, 0x91, 0x82, 0x00, 0xF0, 0x90, 0x91, 0x83, 0x00, 0xF0, + 0x90, 0x91, 0x84, 0x00, 0xF0, 0x90, 0x91, 0x85, 0x00, 0xF0, 0x90, 0x91, + 0x86, 0x00, 0xF0, 0x90, 0x91, 0x87, 0x00, 0xF0, 0x90, 0x91, 0x88, 0x00, + 0xF0, 0x90, 0x91, 0x89, 0x00, 0xF0, 0x90, 0x91, 0x8A, 0x00, 0xF0, 0x90, + 0x91, 0x8B, 0x00, 0xF0, 0x90, 0x91, 0x8C, 0x00, 0xF0, 0x90, 0x91, 0x8D, + 0x00, 0xF0, 0x90, 0x91, 0x8E, 0x00, 0xF0, 0x90, 0x91, 0x8F, 0x00, 0xF0, + 0x90, 0x93, 0x98, 0x00, 0xF0, 0x90, 0x93, 0x99, 0x00, 0xF0, 0x90, 0x93, + 0x9A, 0x00, 0xF0, 0x90, 0x93, 0x9B, 0x00, 0xF0, 0x90, 0x93, 0x9C, 0x00, + 0xF0, 0x90, 0x93, 0x9D, 0x00, 0xF0, 0x90, 0x93, 0x9E, 0x00, 0xF0, 0x90, + 0x93, 0x9F, 0x00, 0xF0, 0x90, 0x93, 0xA0, 0x00, 0xF0, 0x90, 0x93, 0xA1, + 0x00, 0xF0, 0x90, 0x93, 0xA2, 0x00, 0xF0, 0x90, 0x93, 0xA3, 0x00, 0xF0, + 0x90, 0x93, 0xA4, 0x00, 0xF0, 0x90, 0x93, 0xA5, 0x00, 0xF0, 0x90, 0x93, + 0xA6, 0x00, 0xF0, 0x90, 0x93, 0xA7, 0x00, 0xF0, 0x90, 0x93, 0xA8, 0x00, + 0xF0, 0x90, 0x93, 0xA9, 0x00, 0xF0, 0x90, 0x93, 0xAA, 0x00, 0xF0, 0x90, + 0x93, 0xAB, 0x00, 0xF0, 0x90, 0x93, 0xAC, 0x00, 0xF0, 0x90, 0x93, 0xAD, + 0x00, 0xF0, 0x90, 0x93, 0xAE, 0x00, 0xF0, 0x90, 0x93, 0xAF, 0x00, 0xF0, + 0x90, 0x93, 0xB0, 0x00, 0xF0, 0x90, 0x93, 0xB1, 0x00, 0xF0, 0x90, 0x93, + 0xB2, 0x00, 0xF0, 0x90, 0x93, 0xB3, 0x00, 0xF0, 0x90, 0x93, 0xB4, 0x00, + 0xF0, 0x90, 0x93, 0xB5, 0x00, 0xF0, 0x90, 0x93, 0xB6, 0x00, 0xF0, 0x90, + 0x93, 0xB7, 0x00, 0xF0, 0x90, 0x93, 0xB8, 0x00, 0xF0, 0x90, 0x93, 0xB9, + 0x00, 0xF0, 0x90, 0x93, 0xBA, 0x00, 0xF0, 0x90, 0x93, 0xBB, 0x00, 0xE2, + 0xB4, 0x80, 0x00, 0xE2, 0xB4, 0x81, 0x00, 0xE2, 0xB4, 0x82, 0x00, 0xE2, + 0xB4, 0x83, 0x00, 0xE2, 0xB4, 0x84, 0x00, 0xE2, 0xB4, 0x85, 0x00, 0xE2, + 0xB4, 0x86, 0x00, 0xE2, 0xB4, 0x87, 0x00, 0xE2, 0xB4, 0x88, 0x00, 0xE2, + 0xB4, 0x89, 0x00, 0xE2, 0xB4, 0x8A, 0x00, 0xE2, 0xB4, 0x8B, 0x00, 0xE2, + 0xB4, 0x8C, 0x00, 0xE2, 0xB4, 0x8D, 0x00, 0xE2, 0xB4, 0x8E, 0x00, 0xE2, + 0xB4, 0x8F, 0x00, 0xE2, 0xB4, 0x90, 0x00, 0xE2, 0xB4, 0x91, 0x00, 0xE2, + 0xB4, 0x92, 0x00, 0xE2, 0xB4, 0x93, 0x00, 0xE2, 0xB4, 0x94, 0x00, 0xE2, + 0xB4, 0x95, 0x00, 0xE2, 0xB4, 0x96, 0x00, 0xE2, 0xB4, 0x97, 0x00, 0xE2, + 0xB4, 0x98, 0x00, 0xE2, 0xB4, 0x99, 0x00, 0xE2, 0xB4, 0x9A, 0x00, 0xE2, + 0xB4, 0x9B, 0x00, 0xE2, 0xB4, 0x9C, 0x00, 0xE2, 0xB4, 0x9D, 0x00, 0xE2, + 0xB4, 0x9E, 0x00, 0xE2, 0xB4, 0x9F, 0x00, 0xE2, 0xB4, 0xA0, 0x00, 0xE2, + 0xB4, 0xA1, 0x00, 0xE2, 0xB4, 0xA2, 0x00, 0xE2, 0xB4, 0xA3, 0x00, 0xE2, + 0xB4, 0xA4, 0x00, 0xE2, 0xB4, 0xA5, 0x00, 0xE2, 0xB4, 0xA7, 0x00, 0xF0, + 0x90, 0xB3, 0x80, 0x00, 0xF0, 0x90, 0xB3, 0x81, 0x00, 0xF0, 0x90, 0xB3, + 0x82, 0x00, 0xF0, 0x90, 0xB3, 0x83, 0x00, 0xF0, 0x90, 0xB3, 0x84, 0x00, + 0xF0, 0x90, 0xB3, 0x85, 0x00, 0xF0, 0x90, 0xB3, 0x86, 0x00, 0xF0, 0x90, + 0xB3, 0x87, 0x00, 0xF0, 0x90, 0xB3, 0x88, 0x00, 0xF0, 0x90, 0xB3, 0x89, + 0x00, 0xF0, 0x90, 0xB3, 0x8A, 0x00, 0xF0, 0x90, 0xB3, 0x8B, 0x00, 0xF0, + 0x90, 0xB3, 0x8C, 0x00, 0xF0, 0x90, 0xB3, 0x8D, 0x00, 0xF0, 0x90, 0xB3, + 0x8E, 0x00, 0xF0, 0x90, 0xB3, 0x8F, 0x00, 0xF0, 0x90, 0xB3, 0x90, 0x00, + 0xF0, 0x90, 0xB3, 0x91, 0x00, 0xF0, 0x90, 0xB3, 0x92, 0x00, 0xF0, 0x90, + 0xB3, 0x93, 0x00, 0xF0, 0x90, 0xB3, 0x94, 0x00, 0xF0, 0x90, 0xB3, 0x95, + 0x00, 0xF0, 0x90, 0xB3, 0x96, 0x00, 0xF0, 0x90, 0xB3, 0x97, 0x00, 0xF0, + 0x90, 0xB3, 0x98, 0x00, 0xF0, 0x90, 0xB3, 0x99, 0x00, 0xF0, 0x90, 0xB3, + 0x9A, 0x00, 0xF0, 0x90, 0xB3, 0x9B, 0x00, 0xF0, 0x90, 0xB3, 0x9C, 0x00, + 0xF0, 0x90, 0xB3, 0x9D, 0x00, 0xF0, 0x90, 0xB3, 0x9E, 0x00, 0xF0, 0x90, + 0xB3, 0x9F, 0x00, 0xF0, 0x90, 0xB3, 0xA0, 0x00, 0xF0, 0x90, 0xB3, 0xA1, + 0x00, 0xF0, 0x90, 0xB3, 0xA2, 0x00, 0xF0, 0x90, 0xB3, 0xA3, 0x00, 0xF0, + 0x90, 0xB3, 0xA4, 0x00, 0xF0, 0x90, 0xB3, 0xA5, 0x00, 0xF0, 0x90, 0xB3, + 0xA6, 0x00, 0xF0, 0x90, 0xB3, 0xA7, 0x00, 0xF0, 0x90, 0xB3, 0xA8, 0x00, + 0xF0, 0x90, 0xB3, 0xA9, 0x00, 0xF0, 0x90, 0xB3, 0xAA, 0x00, 0xF0, 0x90, + 0xB3, 0xAB, 0x00, 0xF0, 0x90, 0xB3, 0xAC, 0x00, 0xF0, 0x90, 0xB3, 0xAD, + 0x00, 0xF0, 0x90, 0xB3, 0xAE, 0x00, 0xF0, 0x90, 0xB3, 0xAF, 0x00, 0xF0, + 0x90, 0xB3, 0xB0, 0x00, 0xF0, 0x90, 0xB3, 0xB1, 0x00, 0xF0, 0x90, 0xB3, + 0xB2, 0x00, 0xE2, 0xB4, 0xAD, 0x00, 0xF0, 0x91, 0xA3, 0x80, 0x00, 0xF0, + 0x91, 0xA3, 0x81, 0x00, 0xF0, 0x91, 0xA3, 0x82, 0x00, 0xF0, 0x91, 0xA3, + 0x83, 0x00, 0xF0, 0x91, 0xA3, 0x84, 0x00, 0xF0, 0x91, 0xA3, 0x85, 0x00, + 0xF0, 0x91, 0xA3, 0x86, 0x00, 0xF0, 0x91, 0xA3, 0x87, 0x00, 0xF0, 0x91, + 0xA3, 0x88, 0x00, 0xF0, 0x91, 0xA3, 0x89, 0x00, 0xF0, 0x91, 0xA3, 0x8A, + 0x00, 0xF0, 0x91, 0xA3, 0x8B, 0x00, 0xF0, 0x91, 0xA3, 0x8C, 0x00, 0xF0, + 0x91, 0xA3, 0x8D, 0x00, 0xF0, 0x91, 0xA3, 0x8E, 0x00, 0xF0, 0x91, 0xA3, + 0x8F, 0x00, 0xF0, 0x91, 0xA3, 0x90, 0x00, 0xF0, 0x91, 0xA3, 0x91, 0x00, + 0xF0, 0x91, 0xA3, 0x92, 0x00, 0xF0, 0x91, 0xA3, 0x93, 0x00, 0xF0, 0x91, + 0xA3, 0x94, 0x00, 0xF0, 0x91, 0xA3, 0x95, 0x00, 0xF0, 0x91, 0xA3, 0x96, + 0x00, 0xF0, 0x91, 0xA3, 0x97, 0x00, 0xF0, 0x91, 0xA3, 0x98, 0x00, 0xF0, + 0x91, 0xA3, 0x99, 0x00, 0xF0, 0x91, 0xA3, 0x9A, 0x00, 0xF0, 0x91, 0xA3, + 0x9B, 0x00, 0xF0, 0x91, 0xA3, 0x9C, 0x00, 0xF0, 0x91, 0xA3, 0x9D, 0x00, + 0xF0, 0x91, 0xA3, 0x9E, 0x00, 0xF0, 0x91, 0xA3, 0x9F, 0x00, 0xEA, 0xAD, + 0xB0, 0x00, 0xEA, 0xAD, 0xB1, 0x00, 0xEA, 0xAD, 0xB2, 0x00, 0xEA, 0xAD, + 0xB3, 0x00, 0xEA, 0xAD, 0xB4, 0x00, 0xEA, 0xAD, 0xB5, 0x00, 0xEA, 0xAD, + 0xB6, 0x00, 0xEA, 0xAD, 0xB7, 0x00, 0xEA, 0xAD, 0xB8, 0x00, 0xEA, 0xAD, + 0xB9, 0x00, 0xEA, 0xAD, 0xBA, 0x00, 0xEA, 0xAD, 0xBB, 0x00, 0xEA, 0xAD, + 0xBC, 0x00, 0xEA, 0xAD, 0xBD, 0x00, 0xEA, 0xAD, 0xBE, 0x00, 0xEA, 0xAD, + 0xBF, 0x00, 0xEA, 0xAE, 0x80, 0x00, 0xEA, 0xAE, 0x81, 0x00, 0xEA, 0xAE, + 0x82, 0x00, 0xEA, 0xAE, 0x83, 0x00, 0xEA, 0xAE, 0x84, 0x00, 0xEA, 0xAE, + 0x85, 0x00, 0xEA, 0xAE, 0x86, 0x00, 0xEA, 0xAE, 0x87, 0x00, 0xEA, 0xAE, + 0x88, 0x00, 0xEA, 0xAE, 0x89, 0x00, 0xEA, 0xAE, 0x8A, 0x00, 0xEA, 0xAE, + 0x8B, 0x00, 0xEA, 0xAE, 0x8C, 0x00, 0xEA, 0xAE, 0x8D, 0x00, 0xEA, 0xAE, + 0x8E, 0x00, 0xEA, 0xAE, 0x8F, 0x00, 0xEA, 0xAE, 0x90, 0x00, 0xEA, 0xAE, + 0x91, 0x00, 0xEA, 0xAE, 0x92, 0x00, 0xEA, 0xAE, 0x93, 0x00, 0xEA, 0xAE, + 0x94, 0x00, 0xEA, 0xAE, 0x95, 0x00, 0xEA, 0xAE, 0x96, 0x00, 0xEA, 0xAE, + 0x97, 0x00, 0xEA, 0xAE, 0x98, 0x00, 0xEA, 0xAE, 0x99, 0x00, 0xEA, 0xAE, + 0x9A, 0x00, 0xEA, 0xAE, 0x9B, 0x00, 0xEA, 0xAE, 0x9C, 0x00, 0xEA, 0xAE, + 0x9D, 0x00, 0xEA, 0xAE, 0x9E, 0x00, 0xEA, 0xAE, 0x9F, 0x00, 0xEA, 0xAE, + 0xA0, 0x00, 0xEA, 0xAE, 0xA1, 0x00, 0xEA, 0xAE, 0xA2, 0x00, 0xEA, 0xAE, + 0xA3, 0x00, 0xEA, 0xAE, 0xA4, 0x00, 0xEA, 0xAE, 0xA5, 0x00, 0xEA, 0xAE, + 0xA6, 0x00, 0xEA, 0xAE, 0xA7, 0x00, 0xEA, 0xAE, 0xA8, 0x00, 0xEA, 0xAE, + 0xA9, 0x00, 0xEA, 0xAE, 0xAA, 0x00, 0xEA, 0xAE, 0xAB, 0x00, 0xEA, 0xAE, + 0xAC, 0x00, 0xEA, 0xAE, 0xAD, 0x00, 0xEA, 0xAE, 0xAE, 0x00, 0xEA, 0xAE, + 0xAF, 0x00, 0xEA, 0xAE, 0xB0, 0x00, 0xEA, 0xAE, 0xB1, 0x00, 0xEA, 0xAE, + 0xB2, 0x00, 0xEA, 0xAE, 0xB3, 0x00, 0xEA, 0xAE, 0xB4, 0x00, 0xEA, 0xAE, + 0xB5, 0x00, 0xEA, 0xAE, 0xB6, 0x00, 0xEA, 0xAE, 0xB7, 0x00, 0xEA, 0xAE, + 0xB8, 0x00, 0xEA, 0xAE, 0xB9, 0x00, 0xEA, 0xAE, 0xBA, 0x00, 0xEA, 0xAE, + 0xBB, 0x00, 0xEA, 0xAE, 0xBC, 0x00, 0xEA, 0xAE, 0xBD, 0x00, 0xEA, 0xAE, + 0xBE, 0x00, 0xEA, 0xAE, 0xBF, 0x00, 0xE1, 0x8F, 0xB8, 0x00, 0xE1, 0x8F, + 0xB9, 0x00, 0xE1, 0x8F, 0xBA, 0x00, 0xE1, 0x8F, 0xBB, 0x00, 0xE1, 0x8F, + 0xBC, 0x00, 0xE1, 0x8F, 0xBD, 0x00, 0xE1, 0xB8, 0x81, 0x00, 0xE1, 0xB8, + 0x83, 0x00, 0xE1, 0xB8, 0x85, 0x00, 0xE1, 0xB8, 0x87, 0x00, 0xE1, 0xB8, + 0x89, 0x00, 0xE1, 0xB8, 0x8B, 0x00, 0xE1, 0xB8, 0x8D, 0x00, 0xE1, 0xB8, + 0x8F, 0x00, 0xE1, 0xB8, 0x91, 0x00, 0xE1, 0xB8, 0x93, 0x00, 0xE1, 0xB8, + 0x95, 0x00, 0xE1, 0xB8, 0x97, 0x00, 0xE1, 0xB8, 0x99, 0x00, 0xE1, 0xB8, + 0x9B, 0x00, 0xE1, 0xB8, 0x9D, 0x00, 0xE1, 0xB8, 0x9F, 0x00, 0xE1, 0xB8, + 0xA1, 0x00, 0xE1, 0xB8, 0xA3, 0x00, 0xE1, 0xB8, 0xA5, 0x00, 0xE1, 0xB8, + 0xA7, 0x00, 0xE1, 0xB8, 0xA9, 0x00, 0xE1, 0xB8, 0xAB, 0x00, 0xE1, 0xB8, + 0xAD, 0x00, 0xE1, 0xB8, 0xAF, 0x00, 0xE1, 0xB8, 0xB1, 0x00, 0xE1, 0xB8, + 0xB3, 0x00, 0xE1, 0xB8, 0xB5, 0x00, 0xE1, 0xB8, 0xB7, 0x00, 0xE1, 0xB8, + 0xB9, 0x00, 0xE1, 0xB8, 0xBB, 0x00, 0xE1, 0xB8, 0xBD, 0x00, 0xE1, 0xB8, + 0xBF, 0x00, 0xE1, 0xB9, 0x81, 0x00, 0xE1, 0xB9, 0x83, 0x00, 0xE1, 0xB9, + 0x85, 0x00, 0xE1, 0xB9, 0x87, 0x00, 0xE1, 0xB9, 0x89, 0x00, 0xE1, 0xB9, + 0x8B, 0x00, 0xE1, 0xB9, 0x8D, 0x00, 0xE1, 0xB9, 0x8F, 0x00, 0xE1, 0xB9, + 0x91, 0x00, 0xE1, 0xB9, 0x93, 0x00, 0xE1, 0xB9, 0x95, 0x00, 0xE1, 0xB9, + 0x97, 0x00, 0xE1, 0xB9, 0x99, 0x00, 0xE1, 0xB9, 0x9B, 0x00, 0xE1, 0xB9, + 0x9D, 0x00, 0xE1, 0xB9, 0x9F, 0x00, 0xE1, 0xB9, 0xA1, 0x00, 0xE1, 0xB9, + 0xA3, 0x00, 0xE1, 0xB9, 0xA5, 0x00, 0xE1, 0xB9, 0xA7, 0x00, 0xE1, 0xB9, + 0xA9, 0x00, 0xE1, 0xB9, 0xAB, 0x00, 0xE1, 0xB9, 0xAD, 0x00, 0xE1, 0xB9, + 0xAF, 0x00, 0xE1, 0xB9, 0xB1, 0x00, 0xE1, 0xB9, 0xB3, 0x00, 0xE1, 0xB9, + 0xB5, 0x00, 0xE1, 0xB9, 0xB7, 0x00, 0xE1, 0xB9, 0xB9, 0x00, 0xE1, 0xB9, + 0xBB, 0x00, 0xE1, 0xB9, 0xBD, 0x00, 0xE1, 0xB9, 0xBF, 0x00, 0xE1, 0xBA, + 0x81, 0x00, 0xE1, 0xBA, 0x83, 0x00, 0xE1, 0xBA, 0x85, 0x00, 0xE1, 0xBA, + 0x87, 0x00, 0xE1, 0xBA, 0x89, 0x00, 0xE1, 0xBA, 0x8B, 0x00, 0xE1, 0xBA, + 0x8D, 0x00, 0xE1, 0xBA, 0x8F, 0x00, 0xE1, 0xBA, 0x91, 0x00, 0xF0, 0x9E, + 0xA4, 0xA2, 0x00, 0xF0, 0x9E, 0xA4, 0xA3, 0x00, 0xF0, 0x9E, 0xA4, 0xA4, + 0x00, 0xF0, 0x9E, 0xA4, 0xA5, 0x00, 0xF0, 0x9E, 0xA4, 0xA6, 0x00, 0xF0, + 0x9E, 0xA4, 0xA7, 0x00, 0xF0, 0x9E, 0xA4, 0xA8, 0x00, 0xF0, 0x9E, 0xA4, + 0xA9, 0x00, 0xF0, 0x9E, 0xA4, 0xAA, 0x00, 0xF0, 0x9E, 0xA4, 0xAB, 0x00, + 0xF0, 0x9E, 0xA4, 0xAC, 0x00, 0xF0, 0x9E, 0xA4, 0xAD, 0x00, 0xF0, 0x9E, + 0xA4, 0xAE, 0x00, 0xF0, 0x9E, 0xA4, 0xAF, 0x00, 0xF0, 0x9E, 0xA4, 0xB0, + 0x00, 0xF0, 0x9E, 0xA4, 0xB1, 0x00, 0xF0, 0x9E, 0xA4, 0xB2, 0x00, 0xF0, + 0x9E, 0xA4, 0xB3, 0x00, 0xF0, 0x9E, 0xA4, 0xB4, 0x00, 0xF0, 0x9E, 0xA4, + 0xB5, 0x00, 0xF0, 0x9E, 0xA4, 0xB6, 0x00, 0xF0, 0x9E, 0xA4, 0xB7, 0x00, + 0xF0, 0x9E, 0xA4, 0xB8, 0x00, 0xF0, 0x9E, 0xA4, 0xB9, 0x00, 0xF0, 0x9E, + 0xA4, 0xBA, 0x00, 0xF0, 0x9E, 0xA4, 0xBB, 0x00, 0xF0, 0x9E, 0xA4, 0xBC, + 0x00, 0xF0, 0x9E, 0xA4, 0xBD, 0x00, 0xF0, 0x9E, 0xA4, 0xBE, 0x00, 0xF0, + 0x9E, 0xA4, 0xBF, 0x00, 0xF0, 0x9E, 0xA5, 0x80, 0x00, 0xF0, 0x9E, 0xA5, + 0x81, 0x00, 0xE1, 0xBA, 0x93, 0x00, 0xF0, 0x9E, 0xA5, 0x82, 0x00, 0xF0, + 0x9E, 0xA5, 0x83, 0x00, 0xE1, 0xBA, 0x95, 0x00, 0xC3, 0x9F, 0x00, 0xE1, + 0xBA, 0xA1, 0x00, 0xE1, 0xBA, 0xA3, 0x00, 0xE1, 0xBA, 0xA5, 0x00, 0xE1, + 0xBA, 0xA7, 0x00, 0xE1, 0xBA, 0xA9, 0x00, 0xE1, 0xBA, 0xAB, 0x00, 0xE1, + 0xBA, 0xAD, 0x00, 0xE1, 0xBA, 0xAF, 0x00, 0xE1, 0xBA, 0xB1, 0x00, 0xE1, + 0xBA, 0xB3, 0x00, 0xE1, 0xBA, 0xB5, 0x00, 0xE1, 0xBA, 0xB7, 0x00, 0xE1, + 0xBA, 0xB9, 0x00, 0xE1, 0xBA, 0xBB, 0x00, 0xE1, 0xBA, 0xBD, 0x00, 0xE1, + 0xBA, 0xBF, 0x00, 0xE1, 0xBB, 0x81, 0x00, 0xE1, 0xBB, 0x83, 0x00, 0xE1, + 0xBB, 0x85, 0x00, 0xE1, 0xBB, 0x87, 0x00, 0xE1, 0xBB, 0x89, 0x00, 0xE1, + 0xBB, 0x8B, 0x00, 0xE1, 0xBB, 0x8D, 0x00, 0xE1, 0xBB, 0x8F, 0x00, 0xE1, + 0xBB, 0x91, 0x00, 0xE1, 0xBB, 0x93, 0x00, 0xE1, 0xBB, 0x95, 0x00, 0xE1, + 0xBB, 0x97, 0x00, 0xE1, 0xBB, 0x99, 0x00, 0xE1, 0xBB, 0x9B, 0x00, 0xE1, + 0xBB, 0x9D, 0x00, 0xE1, 0xBB, 0x9F, 0x00, 0xE1, 0xBB, 0xA1, 0x00, 0xE1, + 0xBB, 0xA3, 0x00, 0xE1, 0xBB, 0xA5, 0x00, 0xE1, 0xBB, 0xA7, 0x00, 0xE1, + 0xBB, 0xA9, 0x00, 0xE1, 0xBB, 0xAB, 0x00, 0xE1, 0xBB, 0xAD, 0x00, 0xE1, + 0xBB, 0xAF, 0x00, 0xE1, 0xBB, 0xB1, 0x00, 0xE1, 0xBB, 0xB3, 0x00, 0xE1, + 0xBB, 0xB5, 0x00, 0xE1, 0xBB, 0xB7, 0x00, 0xE1, 0xBB, 0xB9, 0x00, 0xE1, + 0xBB, 0xBB, 0x00, 0xE1, 0xBB, 0xBD, 0x00, 0xE1, 0xBB, 0xBF, 0x00, 0xE1, + 0xBC, 0x80, 0x00, 0xE1, 0xBC, 0x81, 0x00, 0xE1, 0xBC, 0x82, 0x00, 0xE1, + 0xBC, 0x83, 0x00, 0xE1, 0xBC, 0x84, 0x00, 0xE1, 0xBC, 0x85, 0x00, 0xE1, + 0xBC, 0x86, 0x00, 0xE1, 0xBC, 0x87, 0x00, 0xE1, 0xBC, 0x90, 0x00, 0xE1, + 0xBC, 0x91, 0x00, 0xE1, 0xBC, 0x92, 0x00, 0xE1, 0xBC, 0x93, 0x00, 0xE1, + 0xBC, 0x94, 0x00, 0xE1, 0xBC, 0x95, 0x00, 0xE1, 0xBC, 0xA0, 0x00, 0xE1, + 0xBC, 0xA1, 0x00, 0xE1, 0xBC, 0xA2, 0x00, 0xE1, 0xBC, 0xA3, 0x00, 0xE1, + 0xBC, 0xA4, 0x00, 0xE1, 0xBC, 0xA5, 0x00, 0xE1, 0xBC, 0xA6, 0x00, 0xE1, + 0xBC, 0xA7, 0x00, 0xE1, 0xBC, 0xB0, 0x00, 0xE1, 0xBC, 0xB1, 0x00, 0xE1, + 0xBC, 0xB2, 0x00, 0xE1, 0xBC, 0xB3, 0x00, 0xE1, 0xBC, 0xB4, 0x00, 0xE1, + 0xBC, 0xB5, 0x00, 0xE1, 0xBC, 0xB6, 0x00, 0xE1, 0xBC, 0xB7, 0x00, 0xE1, + 0xBD, 0x80, 0x00, 0xE1, 0xBD, 0x81, 0x00, 0xE1, 0xBD, 0x82, 0x00, 0xE1, + 0xBD, 0x83, 0x00, 0xE1, 0xBD, 0x84, 0x00, 0xE1, 0xBD, 0x85, 0x00, 0xE1, + 0xBD, 0x91, 0x00, 0xE1, 0xBD, 0x93, 0x00, 0xE1, 0xBD, 0x95, 0x00, 0xE1, + 0xBD, 0x97, 0x00, 0xE1, 0xBD, 0xA0, 0x00, 0xE1, 0xBD, 0xA1, 0x00, 0xE1, + 0xBD, 0xA2, 0x00, 0xE1, 0xBD, 0xA3, 0x00, 0xE1, 0xBD, 0xA4, 0x00, 0xE1, + 0xBD, 0xA5, 0x00, 0xE1, 0xBD, 0xA6, 0x00, 0xE1, 0xBD, 0xA7, 0x00, 0xE1, + 0xBE, 0x80, 0x00, 0xE1, 0xBE, 0x81, 0x00, 0xE1, 0xBE, 0x82, 0x00, 0xE1, + 0xBE, 0x83, 0x00, 0xE1, 0xBE, 0x84, 0x00, 0xE1, 0xBE, 0x85, 0x00, 0xE1, + 0xBE, 0x86, 0x00, 0xE1, 0xBE, 0x87, 0x00, 0xE1, 0xBE, 0x90, 0x00, 0xE1, + 0xBE, 0x91, 0x00, 0xE1, 0xBE, 0x92, 0x00, 0xE1, 0xBE, 0x93, 0x00, 0xE1, + 0xBE, 0x94, 0x00, 0xE1, 0xBE, 0x95, 0x00, 0xE1, 0xBE, 0x96, 0x00, 0xE1, + 0xBE, 0x97, 0x00, 0xE1, 0xBE, 0xA0, 0x00, 0xE1, 0xBE, 0xA1, 0x00, 0xE1, + 0xBE, 0xA2, 0x00, 0xE1, 0xBE, 0xA3, 0x00, 0xE1, 0xBE, 0xA4, 0x00, 0xE1, + 0xBE, 0xA5, 0x00, 0xE1, 0xBE, 0xA6, 0x00, 0xE1, 0xBE, 0xA7, 0x00, 0xE1, + 0xBE, 0xB0, 0x00, 0xE1, 0xBE, 0xB1, 0x00, 0xE1, 0xBD, 0xB0, 0x00, 0xE1, + 0xBD, 0xB1, 0x00, 0xE1, 0xBE, 0xB3, 0x00, 0xE1, 0xBD, 0xB2, 0x00, 0xE1, + 0xBD, 0xB3, 0x00, 0xE1, 0xBD, 0xB4, 0x00, 0xE1, 0xBD, 0xB5, 0x00, 0xE1, + 0xBF, 0x83, 0x00, 0xE1, 0xBF, 0x90, 0x00, 0xE1, 0xBF, 0x91, 0x00, 0xE1, + 0xBD, 0xB6, 0x00, 0xE1, 0xBD, 0xB7, 0x00, 0xE1, 0xBF, 0xA0, 0x00, 0xE1, + 0xBF, 0xA1, 0x00, 0xE1, 0xBD, 0xBA, 0x00, 0xE1, 0xBD, 0xBB, 0x00, 0xE1, + 0xBF, 0xA5, 0x00, 0xE1, 0xBD, 0xB8, 0x00, 0xE1, 0xBD, 0xB9, 0x00, 0xE1, + 0xBD, 0xBC, 0x00, 0xE1, 0xBD, 0xBD, 0x00, 0xE1, 0xBF, 0xB3, 0x00, 0xCF, + 0x89, 0x00, 0x6B, 0x00, 0xC3, 0xA5, 0x00, 0xE2, 0x85, 0x8E, 0x00, 0xE2, + 0x85, 0xB0, 0x00, 0xE2, 0x85, 0xB1, 0x00, 0xE2, 0x85, 0xB2, 0x00, 0xE2, + 0x85, 0xB3, 0x00, 0xE2, 0x85, 0xB4, 0x00, 0xE2, 0x85, 0xB5, 0x00, 0xE2, + 0x85, 0xB6, 0x00, 0xE2, 0x85, 0xB7, 0x00, 0xE2, 0x85, 0xB8, 0x00, 0xE2, + 0x85, 0xB9, 0x00, 0xE2, 0x85, 0xBA, 0x00, 0xE2, 0x85, 0xBB, 0x00, 0xE2, + 0x85, 0xBC, 0x00, 0xE2, 0x85, 0xBD, 0x00, 0xE2, 0x85, 0xBE, 0x00, 0xE2, + 0x85, 0xBF, 0x00, 0xE2, 0x86, 0x84, 0x00, 0xE2, 0x93, 0x90, 0x00, 0xE2, + 0x93, 0x91, 0x00, 0xE2, 0x93, 0x92, 0x00, 0xE2, 0x93, 0x93, 0x00, 0xE2, + 0x93, 0x94, 0x00, 0xE2, 0x93, 0x95, 0x00, 0xE2, 0x93, 0x96, 0x00, 0xE2, + 0x93, 0x97, 0x00, 0xE2, 0x93, 0x98, 0x00, 0xE2, 0x93, 0x99, 0x00, 0xE2, + 0x93, 0x9A, 0x00, 0xE2, 0x93, 0x9B, 0x00, 0xE2, 0x93, 0x9C, 0x00, 0xE2, + 0x93, 0x9D, 0x00, 0xE2, 0x93, 0x9E, 0x00, 0xE2, 0x93, 0x9F, 0x00, 0xE2, + 0x93, 0xA0, 0x00, 0xE2, 0x93, 0xA1, 0x00, 0xE2, 0x93, 0xA2, 0x00, 0xE2, + 0x93, 0xA3, 0x00, 0xE2, 0x93, 0xA4, 0x00, 0xE2, 0x93, 0xA5, 0x00, 0xE2, + 0x93, 0xA6, 0x00, 0xE2, 0x93, 0xA7, 0x00, 0xE2, 0x93, 0xA8, 0x00, 0xE2, + 0x93, 0xA9, 0x00, 0xE2, 0xB0, 0xB0, 0x00, 0xE2, 0xB0, 0xB1, 0x00, 0xE2, + 0xB0, 0xB2, 0x00, 0xE2, 0xB0, 0xB3, 0x00, 0xE2, 0xB0, 0xB4, 0x00, 0xE2, + 0xB0, 0xB5, 0x00, 0xE2, 0xB0, 0xB6, 0x00, 0xE2, 0xB0, 0xB7, 0x00, 0xE2, + 0xB0, 0xB8, 0x00, 0xE2, 0xB0, 0xB9, 0x00, 0xE2, 0xB0, 0xBA, 0x00, 0xE2, + 0xB0, 0xBB, 0x00, 0xE2, 0xB0, 0xBC, 0x00, 0xE2, 0xB0, 0xBD, 0x00, 0xE2, + 0xB0, 0xBE, 0x00, 0xE2, 0xB0, 0xBF, 0x00, 0xE2, 0xB1, 0x80, 0x00, 0xE2, + 0xB1, 0x81, 0x00, 0xE2, 0xB1, 0x82, 0x00, 0xE2, 0xB1, 0x83, 0x00, 0xE2, + 0xB1, 0x84, 0x00, 0xE2, 0xB1, 0x85, 0x00, 0xE2, 0xB1, 0x86, 0x00, 0xE2, + 0xB1, 0x87, 0x00, 0xE2, 0xB1, 0x88, 0x00, 0xE2, 0xB1, 0x89, 0x00, 0xE2, + 0xB1, 0x8A, 0x00, 0xE2, 0xB1, 0x8B, 0x00, 0xE2, 0xB1, 0x8C, 0x00, 0xE2, + 0xB1, 0x8D, 0x00, 0xE2, 0xB1, 0x8E, 0x00, 0xE2, 0xB1, 0x8F, 0x00, 0xE2, + 0xB1, 0x90, 0x00, 0xE2, 0xB1, 0x91, 0x00, 0xE2, 0xB1, 0x92, 0x00, 0xE2, + 0xB1, 0x93, 0x00, 0xE2, 0xB1, 0x94, 0x00, 0xE2, 0xB1, 0x95, 0x00, 0xE2, + 0xB1, 0x96, 0x00, 0xE2, 0xB1, 0x97, 0x00, 0xE2, 0xB1, 0x98, 0x00, 0xE2, + 0xB1, 0x99, 0x00, 0xE2, 0xB1, 0x9A, 0x00, 0xE2, 0xB1, 0x9B, 0x00, 0xE2, + 0xB1, 0x9C, 0x00, 0xE2, 0xB1, 0x9D, 0x00, 0xE2, 0xB1, 0x9E, 0x00, 0xE2, + 0xB1, 0xA1, 0x00, 0xC9, 0xAB, 0x00, 0xE1, 0xB5, 0xBD, 0x00, 0xC9, 0xBD, + 0x00, 0xE2, 0xB1, 0xA8, 0x00, 0xE2, 0xB1, 0xAA, 0x00, 0xE2, 0xB1, 0xAC, + 0x00, 0xC9, 0x91, 0x00, 0xC9, 0xB1, 0x00, 0xC9, 0x90, 0x00, 0xC9, 0x92, + 0x00, 0xE2, 0xB1, 0xB3, 0x00, 0xE2, 0xB1, 0xB6, 0x00, 0xC8, 0xBF, 0x00, + 0xC9, 0x80, 0x00, 0xE2, 0xB2, 0x81, 0x00, 0xE2, 0xB2, 0x83, 0x00, 0xE2, + 0xB2, 0x85, 0x00, 0xE2, 0xB2, 0x87, 0x00, 0xE2, 0xB2, 0x89, 0x00, 0xE2, + 0xB2, 0x8B, 0x00, 0xE2, 0xB2, 0x8D, 0x00, 0xE2, 0xB2, 0x8F, 0x00, 0xE2, + 0xB2, 0x91, 0x00, 0xE2, 0xB2, 0x93, 0x00, 0xE2, 0xB2, 0x95, 0x00, 0xE2, + 0xB2, 0x97, 0x00, 0xE2, 0xB2, 0x99, 0x00, 0xE2, 0xB2, 0x9B, 0x00, 0xE2, + 0xB2, 0x9D, 0x00, 0xE2, 0xB2, 0x9F, 0x00, 0xE2, 0xB2, 0xA1, 0x00, 0xE2, + 0xB2, 0xA3, 0x00, 0xE2, 0xB2, 0xA5, 0x00, 0xE2, 0xB2, 0xA7, 0x00, 0xE2, + 0xB2, 0xA9, 0x00, 0xE2, 0xB2, 0xAB, 0x00, 0xE2, 0xB2, 0xAD, 0x00, 0xE2, + 0xB2, 0xAF, 0x00, 0xE2, 0xB2, 0xB1, 0x00, 0xE2, 0xB2, 0xB3, 0x00, 0xE2, + 0xB2, 0xB5, 0x00, 0xE2, 0xB2, 0xB7, 0x00, 0xE2, 0xB2, 0xB9, 0x00, 0xE2, + 0xB2, 0xBB, 0x00, 0xE2, 0xB2, 0xBD, 0x00, 0xE2, 0xB2, 0xBF, 0x00, 0xE2, + 0xB3, 0x81, 0x00, 0xE2, 0xB3, 0x83, 0x00, 0xE2, 0xB3, 0x85, 0x00, 0xE2, + 0xB3, 0x87, 0x00, 0xE2, 0xB3, 0x89, 0x00, 0xE2, 0xB3, 0x8B, 0x00, 0xE2, + 0xB3, 0x8D, 0x00, 0xE2, 0xB3, 0x8F, 0x00, 0xE2, 0xB3, 0x91, 0x00, 0xE2, + 0xB3, 0x93, 0x00, 0xE2, 0xB3, 0x95, 0x00, 0xE2, 0xB3, 0x97, 0x00, 0xE2, + 0xB3, 0x99, 0x00, 0xE2, 0xB3, 0x9B, 0x00, 0xE2, 0xB3, 0x9D, 0x00, 0xE2, + 0xB3, 0x9F, 0x00, 0xE2, 0xB3, 0xA1, 0x00, 0xE2, 0xB3, 0xA3, 0x00, 0xE2, + 0xB3, 0xAC, 0x00, 0xE2, 0xB3, 0xAE, 0x00, 0xE2, 0xB3, 0xB3, 0x00, 0xEA, + 0x99, 0x81, 0x00, 0xEA, 0x99, 0x83, 0x00, 0xEA, 0x99, 0x85, 0x00, 0xEA, + 0x99, 0x87, 0x00, 0xEA, 0x99, 0x89, 0x00, 0xEA, 0x99, 0x8B, 0x00, 0xEA, + 0x99, 0x8D, 0x00, 0xEA, 0x99, 0x8F, 0x00, 0xEA, 0x99, 0x91, 0x00, 0xEA, + 0x99, 0x93, 0x00, 0xEA, 0x99, 0x95, 0x00, 0xEA, 0x99, 0x97, 0x00, 0xEA, + 0x99, 0x99, 0x00, 0xEA, 0x99, 0x9B, 0x00, 0xEA, 0x99, 0x9D, 0x00, 0xEA, + 0x99, 0x9F, 0x00, 0xEA, 0x99, 0xA1, 0x00, 0xEA, 0x99, 0xA3, 0x00, 0xEA, + 0x99, 0xA5, 0x00, 0xEA, 0x99, 0xA7, 0x00, 0xEA, 0x99, 0xA9, 0x00, 0xEA, + 0x99, 0xAB, 0x00, 0xEA, 0x99, 0xAD, 0x00, 0xEA, 0x9A, 0x81, 0x00, 0xEA, + 0x9A, 0x83, 0x00, 0xEA, 0x9A, 0x85, 0x00, 0xEA, 0x9A, 0x87, 0x00, 0xEA, + 0x9A, 0x89, 0x00, 0xEA, 0x9A, 0x8B, 0x00, 0xEA, 0x9A, 0x8D, 0x00, 0xEA, + 0x9A, 0x8F, 0x00, 0xEA, 0x9A, 0x91, 0x00, 0xEA, 0x9A, 0x93, 0x00, 0xEA, + 0x9A, 0x95, 0x00, 0xEA, 0x9A, 0x97, 0x00, 0xEA, 0x9A, 0x99, 0x00, 0xEA, + 0x9A, 0x9B, 0x00, 0xEA, 0x9C, 0xA3, 0x00, 0xEA, 0x9C, 0xA5, 0x00, 0xEA, + 0x9C, 0xA7, 0x00, 0xEA, 0x9C, 0xA9, 0x00, 0xEA, 0x9C, 0xAB, 0x00, 0xEA, + 0x9C, 0xAD, 0x00, 0xEA, 0x9C, 0xAF, 0x00, 0xEA, 0x9C, 0xB3, 0x00, 0xEA, + 0x9C, 0xB5, 0x00, 0xEA, 0x9C, 0xB7, 0x00, 0xEA, 0x9C, 0xB9, 0x00, 0xEA, + 0x9C, 0xBB, 0x00, 0xEA, 0x9C, 0xBD, 0x00, 0xEA, 0x9C, 0xBF, 0x00, 0xEA, + 0x9D, 0x81, 0x00, 0xEA, 0x9D, 0x83, 0x00, 0xEA, 0x9D, 0x85, 0x00, 0xEA, + 0x9D, 0x87, 0x00, 0xEA, 0x9D, 0x89, 0x00, 0xEA, 0x9D, 0x8B, 0x00, 0xEA, + 0x9D, 0x8D, 0x00, 0xEA, 0x9D, 0x8F, 0x00, 0xEA, 0x9D, 0x91, 0x00, 0xEA, + 0x9D, 0x93, 0x00, 0xEA, 0x9D, 0x95, 0x00, 0xEA, 0x9D, 0x97, 0x00, 0xEA, + 0x9D, 0x99, 0x00, 0xEA, 0x9D, 0x9B, 0x00, 0xEA, 0x9D, 0x9D, 0x00, 0xEA, + 0x9D, 0x9F, 0x00, 0xEA, 0x9D, 0xA1, 0x00, 0xEA, 0x9D, 0xA3, 0x00, 0xEA, + 0x9D, 0xA5, 0x00, 0xEA, 0x9D, 0xA7, 0x00, 0xEA, 0x9D, 0xA9, 0x00, 0xEA, + 0x9D, 0xAB, 0x00, 0xEA, 0x9D, 0xAD, 0x00, 0xEA, 0x9D, 0xAF, 0x00, 0xEA, + 0x9D, 0xBA, 0x00, 0xEA, 0x9D, 0xBC, 0x00, 0xE1, 0xB5, 0xB9, 0x00, 0xEA, + 0x9D, 0xBF, 0x00, 0xEA, 0x9E, 0x81, 0x00, 0xEA, 0x9E, 0x83, 0x00, 0xEA, + 0x9E, 0x85, 0x00, 0xEA, 0x9E, 0x87, 0x00, 0xEA, 0x9E, 0x8C, 0x00, 0xC9, + 0xA5, 0x00, 0xEA, 0x9E, 0x91, 0x00, 0xEA, 0x9E, 0x93, 0x00, 0xEA, 0x9E, + 0x97, 0x00, 0xEA, 0x9E, 0x99, 0x00, 0xEA, 0x9E, 0x9B, 0x00, 0xEA, 0x9E, + 0x9D, 0x00, 0xEA, 0x9E, 0x9F, 0x00, 0xEA, 0x9E, 0xA1, 0x00, 0xEA, 0x9E, + 0xA3, 0x00, 0xEA, 0x9E, 0xA5, 0x00, 0xEA, 0x9E, 0xA7, 0x00, 0xEA, 0x9E, + 0xA9, 0x00, 0xC9, 0xA6, 0x00, 0xC9, 0x9C, 0x00, 0xC9, 0xA1, 0x00, 0xC9, + 0xAC, 0x00, 0xC9, 0xAA, 0x00, 0xCA, 0x9E, 0x00, 0xCA, 0x87, 0x00, 0xCA, + 0x9D, 0x00, 0xEA, 0xAD, 0x93, 0x00, 0xEA, 0x9E, 0xB5, 0x00, 0xEA, 0x9E, + 0xB7, 0x00, 0xEF, 0xBD, 0x81, 0x00, 0xEF, 0xBD, 0x82, 0x00, 0xEF, 0xBD, + 0x83, 0x00, 0xEF, 0xBD, 0x84, 0x00, 0xEF, 0xBD, 0x85, 0x00, 0xEF, 0xBD, + 0x86, 0x00, 0xEF, 0xBD, 0x87, 0x00, 0xEF, 0xBD, 0x88, 0x00, 0xEF, 0xBD, + 0x89, 0x00, 0xEF, 0xBD, 0x8A, 0x00, 0xEF, 0xBD, 0x8B, 0x00, 0xEF, 0xBD, + 0x8C, 0x00, 0xEF, 0xBD, 0x8D, 0x00, 0xEF, 0xBD, 0x8E, 0x00, 0xEF, 0xBD, + 0x8F, 0x00, 0xEF, 0xBD, 0x90, 0x00, 0xEF, 0xBD, 0x91, 0x00, 0xEF, 0xBD, + 0x92, 0x00, 0xEF, 0xBD, 0x93, 0x00, 0xEF, 0xBD, 0x94, 0x00, 0xEF, 0xBD, + 0x95, 0x00, 0xEF, 0xBD, 0x96, 0x00, 0xEF, 0xBD, 0x97, 0x00, 0xEF, 0xBD, + 0x98, 0x00, 0xEF, 0xBD, 0x99, 0x00, 0xEF, 0xBD, 0x9A, 0x00, 0x69, 0xCC, + 0x87, 0x00, 0xE1, 0xBE, 0x80, 0x00, 0xE1, 0xBE, 0x81, 0x00, 0xE1, 0xBE, + 0x82, 0x00, 0xE1, 0xBE, 0x83, 0x00, 0xE1, 0xBE, 0x84, 0x00, 0xE1, 0xBE, + 0x85, 0x00, 0xE1, 0xBE, 0x86, 0x00, 0xE1, 0xBE, 0x87, 0x00, 0xE1, 0xBE, + 0x90, 0x00, 0xE1, 0xBE, 0x91, 0x00, 0xE1, 0xBE, 0x92, 0x00, 0xE1, 0xBE, + 0x93, 0x00, 0xE1, 0xBE, 0x94, 0x00, 0xE1, 0xBE, 0x95, 0x00, 0xE1, 0xBE, + 0x96, 0x00, 0xE1, 0xBE, 0x97, 0x00, 0xE1, 0xBE, 0xA0, 0x00, 0xE1, 0xBE, + 0xA1, 0x00, 0xE1, 0xBE, 0xA2, 0x00, 0xE1, 0xBE, 0xA3, 0x00, 0xE1, 0xBE, + 0xA4, 0x00, 0xE1, 0xBE, 0xA5, 0x00, 0xE1, 0xBE, 0xA6, 0x00, 0xE1, 0xBE, + 0xA7, 0x00, 0xE1, 0xBE, 0xB3, 0x00, 0xE1, 0xBF, 0x83, 0x00, 0xE1, 0xBF, + 0xB3, 0x00, +}; + diff --git a/vendor/nunicode/src/libnu/gen/_tounaccent.c b/vendor/nunicode/src/libnu/gen/_tounaccent.c new file mode 100644 index 0000000000..d672d6368b --- /dev/null +++ b/vendor/nunicode/src/libnu/gen/_tounaccent.c @@ -0,0 +1,460 @@ +/* Automatically generated file (mph.py), 1491062342 + * + * Tag : NU_TOUNACCENT + * Prime : 01000193, + * G size : 845, + * Combined length : 2082, + * Encoding : UTF-8 + */ + +#include <stdint.h> + +const int16_t NU_TOUNACCENT_G[] = { + -845, -844, -843, -842, -841, -840, -839, -838, -837, -836, -834, -833, + -832, -831, -830, -829, -828, 0, -827, 0, -826, 0, -825, 0, + -824, -823, -822, -821, 0, 0, -820, -819, -818, -817, -816, -815, + 0, 0, -814, -813, -812, -811, -810, -809, -808, -807, -806, -805, + -804, -803, -802, -801, 0, 0, -800, -799, -798, -797, -796, -795, + -794, 1, 1, 1, -793, -792, 1, 1, 1, 1, 1, 1, + 1, -791, -790, 11, 2, 1, 1, 5, -789, -788, -787, 2, + -786, -785, -784, -783, 1, 30, 2, 32, 32, 2, 24, 18, + -782, -781, 48, 48, 52, 49, 20, 49, 1, 4, -780, 5, + 6, 10, 17, 30, 16, 66, -779, 68, 68, 65, 20, 69, + 65, 24, 65, 79, 65, -778, -777, -776, -775, -774, -773, -772, + -771, -770, -769, -768, -767, -766, -765, -764, -763, -762, -761, -760, + -759, -758, -757, -756, -755, -754, -753, -752, -751, -750, -749, -748, + -747, -746, -745, -744, -743, -742, -741, -740, -739, -738, -737, -736, + -735, -734, -733, -732, -731, -730, -729, -728, 0, 0, -727, -726, + 0, 0, 0, 0, -725, -724, -723, -722, -721, -720, -719, -718, + -717, -716, -715, -714, -713, -712, -711, -710, -709, -708, -707, -706, + -705, -704, -703, -702, -701, -700, -699, -698, -697, -696, -695, -694, + -693, -692, -691, -690, -689, -688, -687, -686, -685, -684, -683, -682, + -681, -680, -679, -678, -677, -676, -675, -674, -673, -672, -671, -670, + 1, 1, 4, 1, 1, 1, -669, -668, 1, 1, -667, -666, + 1, 1, 1, 1, 1, 1, 1, -665, -664, -663, -662, -661, + -660, -659, -658, -657, -656, 2, 21, -655, 9, 1, 1, 1, + -654, 16, 1, 1, 1, 5, 2, 1, 1, -653, -652, -651, + 1, 1, -650, -649, 2, 1, 4, 8, 1, 1, -648, -647, + 1, 6, 4, 18, -646, -645, -644, -643, -642, 10, 18, 16, + 9, 1, 1, 5, 9, -641, -640, -639, 88, -638, 88, 88, + 88, -637, -636, -635, 0, 0, 0, 0, 0, -634, -633, -632, + -631, -630, 0, 0, 0, -629, -628, 0, 0, 0, 64, -627, + -626, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -625, -624, -623, -622, 0, -621, 0, -620, 6, + 11, 0, 0, 0, 0, -619, -618, 0, 0, -617, -616, -615, + 0, 0, 0, 0, 0, -614, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -613, 0, -612, 6, 0, 0, + 0, 0, -611, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -610, -609, -608, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -607, 0, -606, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -605, 0, -604, 0, 0, -603, 0, + 0, -602, 0, 0, 0, 0, 0, 0, 0, -601, -600, 0, + 0, -599, -598, 0, 0, -597, -596, 0, 0, 0, 0, 0, + -595, 0, -594, 0, 0, 0, 0, 0, 0, 0, 0, -593, + -592, -591, 0, 0, 0, 0, 0, 0, -590, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -589, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -588, 2, -379, -336, -297, -295, -293, -290, -289, -277, 6, -152, + -148, -145, 1, -136, -132, 1, 1, 5, 5, 16, 16, 13, + 16, 1, 4, 2, 7, 8, 8, 20, 22, 1, 1, 1, + 1, -97, -73, -72, -58, -57, 32, 32, 37, -54, -53, -52, + -50, 8, -48, -47, 2, 2, 1, 9, 56, 1, 4, 2, + 14, 16, 16, -46, 1, 39, 71, 80, -41, 0, -39, -34, + 82, 84, 80, 80, 88, 96, 12, 12, 64, 64, 64, 68, + 73, 64, 66, 81, 85, 1, 2, 2, 5, 9, 1, -32, + -31, 17, 23, 17, 34, 30, 33, 35, -30, 27, 20, 24, + -29, 49, -28, 0, -27, 9, 15, 20, 181, 254, 253, 249, + 252, -26, -25, -24, -23, 2, 6, -22, 15, 224, 229, 259, + 261, -21, -20, -19, 258, 260, 262, 260, 265, 267, -18, -17, + 200, 256, 256, 280, 256, -16, 280, 280, 284, 5, 5, 1, + 5, -15, -14, 12, 12, -13, 18, 4, 42, -12, 0, -11, + -10, 33, 36, 32, 42, 41, 260, 44, 261, 38, 266, 73, + 268, 273, 257, 261, 286, 274, -9, 288, 261, 298, 256, 16, + 339, 336, -6, -4, 291, 338, 365, 365, 365, 330, 293, 295, + 308, 335, -3, -2, -1, }; + +const size_t NU_TOUNACCENT_G_SIZE = sizeof(NU_TOUNACCENT_G) / sizeof(*NU_TOUNACCENT_G); + +/* codepoints */ +const uint32_t NU_TOUNACCENT_VALUES_C[] = { + 0x001F24, 0x001F25, 0x001F26, 0x001F39, 0x000169, 0x001F3A, 0x00016B, 0x00016A, + 0x001F32, 0x001F1C, 0x001F1D, 0x000144, 0x001F1B, 0x000143, 0x00015C, 0x000154, + 0x001FE5, 0x001FE6, 0x00012A, 0x00012B, 0x000124, 0x000122, 0x00013D, 0x00013E, + 0x001FF2, 0x001FF3, 0x001FC4, 0x001FC6, 0x00010D, 0x000109, 0x000101, 0x000102, + 0x000125, 0x0001EA, 0x000168, 0x00016C, 0x00012D, 0x000126, 0x0001EB, 0x00012C, + 0x001FB8, 0x00012F, 0x00012E, 0x000129, 0x000128, 0x00022D, 0x001F89, 0x001F8A, + 0x000160, 0x001F84, 0x000161, 0x001F85, 0x001F86, 0x001F87, 0x000164, 0x000385, + 0x001F83, 0x001F9C, 0x000386, 0x000389, 0x000388, 0x00038F, 0x00038A, 0x00038E, + 0x00038C, 0x0003CE, 0x00015A, 0x00015B, 0x000390, 0x000159, 0x000165, 0x001F9D, + 0x001F9E, 0x00016E, 0x00016F, 0x001F0A, 0x001F04, 0x001F06, 0x000156, 0x001F08, + 0x000150, 0x001F21, 0x001F22, 0x001F0D, 0x0003AB, 0x000155, 0x00017C, 0x000157, + 0x0003AC, 0x00016D, 0x001F0E, 0x0003AD, 0x001F31, 0x001F0C, 0x00017E, 0x001F20, + 0x001F9F, 0x0003AF, 0x0003AE, 0x000163, 0x0003B0, 0x000174, 0x001F38, 0x000179, + 0x001F37, 0x001F0F, 0x000178, 0x0003AA, 0x001F33, 0x001E23, 0x001E22, 0x001E25, + 0x001E24, 0x001E27, 0x001E26, 0x001E29, 0x000171, 0x001E2B, 0x001E2A, 0x000173, + 0x00017D, 0x000175, 0x00017B, 0x001E68, 0x001E69, 0x000177, 0x001E6B, 0x00017A, + 0x001F30, 0x001F36, 0x001E6F, 0x0001D1, 0x001E38, 0x001E3B, 0x001E3A, 0x0001D2, + 0x001E39, 0x001E3F, 0x001E3E, 0x001E55, 0x001E40, 0x001E43, 0x001E41, 0x001E4C, + 0x00021F, 0x001E47, 0x001E42, 0x000218, 0x001E4D, 0x001E4B, 0x001E4A, 0x000219, + 0x001E4F, 0x001E5E, 0x001E4E, 0x001F3D, 0x001F3C, 0x001E5B, 0x001F3E, 0x001E56, + 0x0000E4, 0x0000E5, 0x0000ED, 0x001E59, 0x001E58, 0x0000E7, 0x001E5A, 0x001E5D, + 0x001E5C, 0x0000E8, 0x0000EB, 0x001E61, 0x0000E9, 0x0000EC, 0x001E62, 0x0000EE, + 0x001E60, 0x001E74, 0x001F34, 0x001F27, 0x001F23, 0x001E63, 0x001F3B, 0x001E7C, + 0x001F3F, 0x001E67, 0x001E7D, 0x001E76, 0x001E75, 0x001E73, 0x001E72, 0x001E7E, + 0x0000F4, 0x001E77, 0x0000C3, 0x0000C2, 0x0000C1, 0x0000F5, 0x0000F6, 0x0000C5, + 0x0000F9, 0x0000C8, 0x0000FB, 0x000419, 0x0000CE, 0x001E83, 0x001E81, 0x001E86, + 0x0000D1, 0x0000CF, 0x0000D3, 0x0000D2, 0x0000D5, 0x0000D4, 0x0000DD, 0x0000D6, + 0x0000D9, 0x0000D8, 0x0000DB, 0x0000DA, 0x001E94, 0x001E93, 0x0000DC, 0x001E95, + 0x001E97, 0x001E84, 0x001E96, 0x0000F1, 0x001E8D, 0x001E98, 0x001E90, 0x001E82, + 0x001E85, 0x0000E3, 0x0000F2, 0x001E80, 0x0000CC, 0x0000CD, 0x0000FA, 0x001EB5, + 0x0000E0, 0x0000F3, 0x001E87, 0x0000E2, 0x001EBD, 0x001EB4, 0x001EBB, 0x0000EF, + 0x0000FD, 0x0000F8, 0x0000FC, 0x0000FF, 0x001EB7, 0x001EB3, 0x0000EA, 0x0000E1, + 0x001EB0, 0x001EB2, 0x000103, 0x001E88, 0x001E89, 0x001EA2, 0x001E8F, 0x001EB6, + 0x001E8C, 0x000450, 0x001E8E, 0x000400, 0x000401, 0x002209, 0x000403, 0x000457, + 0x000107, 0x000100, 0x000407, 0x000108, 0x00021B, 0x00011C, 0x00010E, 0x000106, + 0x00011D, 0x000118, 0x000104, 0x00010F, 0x00011E, 0x00011F, 0x000112, 0x000113, + 0x000214, 0x000215, 0x000136, 0x000476, 0x000216, 0x000123, 0x000217, 0x000105, + 0x000210, 0x00010A, 0x00010B, 0x001EA1, 0x000439, 0x001EA3, 0x000121, 0x001FE2, + 0x001FE1, 0x001EA7, 0x001FE3, 0x001FE8, 0x001FE0, 0x001FEA, 0x001FEB, 0x001FE7, + 0x000137, 0x000130, 0x001EA0, 0x001FEC, 0x001FE9, 0x00010C, 0x00013C, 0x000176, + 0x001FED, 0x001FEE, 0x000146, 0x001EBA, 0x001EBC, 0x001FF9, 0x001EBF, 0x001EB8, + 0x001FF8, 0x001FFC, 0x001EBE, 0x00011A, 0x000119, 0x000141, 0x000142, 0x000211, + 0x000110, 0x000111, 0x000116, 0x001F1A, 0x000114, 0x000147, 0x000170, 0x000117, + 0x00015D, 0x00011B, 0x00015F, 0x001F11, 0x000115, 0x000158, 0x000172, 0x00015E, + 0x001F10, 0x001F13, 0x001F12, 0x001F14, 0x001F15, 0x00014C, 0x001FFB, 0x00014D, + 0x001F19, 0x000148, 0x001FFA, 0x00014F, 0x001F01, 0x001F03, 0x00014E, 0x000145, + 0x001F35, 0x001F02, 0x000162, 0x0004C1, 0x001F05, 0x001F00, 0x0004C2, 0x001FE4, + 0x001F0B, 0x001F07, 0x000212, 0x001FCC, 0x001FCF, 0x001F18, 0x001FCE, 0x001FCD, + 0x000135, 0x002281, 0x002285, 0x002284, 0x0004D0, 0x0004D3, 0x0004D2, 0x002288, + 0x0004D1, 0x0004D7, 0x0004D6, 0x001F09, 0x0001EC, 0x0004DB, 0x0004DA, 0x0004DD, + 0x0004DC, 0x0004DF, 0x0004DE, 0x002280, 0x0004E5, 0x0004E3, 0x0004E2, 0x002289, + 0x0004E7, 0x000151, 0x0004E6, 0x0004EE, 0x0004ED, 0x0004EB, 0x0004EA, 0x0004E4, + 0x0001E7, 0x0004EF, 0x0001A0, 0x0004F1, 0x0004F0, 0x0022AE, 0x0004F2, 0x0004F5, + 0x0004F4, 0x0001AF, 0x0022AD, 0x0022AC, 0x0004F8, 0x0004F3, 0x0004F9, 0x001F65, + 0x001F64, 0x0004EC, 0x001F66, 0x001F69, 0x001F68, 0x0001ED, 0x0001E6, 0x001F6D, + 0x001F6C, 0x001F6F, 0x001F6E, 0x0001E9, 0x0001E8, 0x0022AF, 0x0001EE, 0x0001EF, + 0x000120, 0x0001F9, 0x000127, 0x00013A, 0x0001D4, 0x000139, 0x00013B, 0x0001E0, + 0x001FC8, 0x0001D9, 0x000134, 0x0001DB, 0x001F95, 0x001F94, 0x001F8B, 0x001F8D, + 0x0001D5, 0x0001D0, 0x0001D3, 0x0001D6, 0x0001DC, 0x001F88, 0x0001D7, 0x0001DA, + 0x001F8F, 0x0001D8, 0x001F8E, 0x0001DF, 0x0001DE, 0x001F93, 0x001F91, 0x0022EA, + 0x0001E1, 0x001F92, 0x001F90, 0x001F99, 0x001F98, 0x001F9B, 0x001F9A, 0x001FBB, + 0x0001CD, 0x001F96, 0x001F97, 0x0022EB, 0x001F81, 0x001F82, 0x0001CE, 0x0001CF, + 0x001F80, 0x001FB6, 0x001FB7, 0x0001FA, 0x001FA5, 0x001FA6, 0x0001F4, 0x0001F5, + 0x0001F0, 0x0001F8, 0x0001FB, 0x0001FF, 0x0001FE, 0x001FB3, 0x001FB1, 0x001F8C, + 0x001FB4, 0x001FB2, 0x000203, 0x000202, 0x000201, 0x000200, 0x00020E, 0x00020F, + 0x000205, 0x001FB0, 0x00020B, 0x000209, 0x001FDF, 0x001FCB, 0x00020A, 0x000208, + 0x001FCA, 0x000213, 0x001FA7, 0x001FD9, 0x000204, 0x001FDB, 0x000206, 0x000207, + 0x001FDA, 0x00020D, 0x00020C, 0x001FD2, 0x00021A, 0x001FD3, 0x001FD1, 0x00021E, + 0x001FD0, 0x001FC2, 0x001FD6, 0x001FC3, 0x001FC1, 0x000227, 0x000228, 0x000226, + 0x001FC9, 0x001FD7, 0x00022B, 0x000229, 0x001FA8, 0x00022C, 0x00022A, 0x001FA4, + 0x000231, 0x000230, 0x000233, 0x000232, 0x001FB9, 0x001FAA, 0x001FAB, 0x001FAE, + 0x001FA9, 0x001FBC, 0x001FAF, 0x001FF6, 0x001FA1, 0x001FA2, 0x00022E, 0x00022F, + 0x001FF7, 0x001FC7, 0x001FA3, 0x001FA0, 0x001FAC, 0x001FD8, 0x001FF4, 0x001FAD, + 0x001FBA, 0x001FDD, 0x001FDE, 0x0001A1, 0x0001B0, 0x00212B, 0x00226D, 0x00226E, + 0x00226F, 0x002260, 0x002262, 0x002278, 0x002279, 0x002274, 0x002275, 0x002270, + 0x002271, 0x002249, 0x002244, 0x002247, 0x002241, 0x002224, 0x002226, 0x0021CD, + 0x0021CE, 0x0021CF, 0x00220C, 0x000477, 0x002204, 0x0021AE, 0x00045C, 0x00045D, + 0x00045E, 0x0022EC, 0x0022ED, 0x000451, 0x000453, 0x0022E0, 0x0022E1, 0x0022E2, + 0x0022E3, 0x0003CC, 0x0003CD, 0x0003CA, 0x0003CB, 0x00219A, 0x00219B, 0x00040C, + 0x00040D, 0x00040E, 0x001E6C, 0x001E6D, 0x001E6E, 0x001E6A, 0x001E64, 0x001E65, + 0x001E66, 0x001E7F, 0x001E78, 0x001E79, 0x001E7A, 0x001E7B, 0x001E70, 0x001E71, + 0x001E48, 0x001E49, 0x001E44, 0x001E45, 0x001E46, 0x001E5F, 0x001E54, 0x001E57, + 0x001E50, 0x001E51, 0x001E52, 0x001E53, 0x001E2C, 0x001E2D, 0x001E2E, 0x001E2F, + 0x001E28, 0x001E20, 0x001E21, 0x001E3C, 0x001E3D, 0x001E34, 0x001E35, 0x001E36, + 0x001E37, 0x001E30, 0x001E31, 0x001E32, 0x001E33, 0x001E0C, 0x001E0D, 0x001E0E, + 0x001E0F, 0x001E08, 0x001E09, 0x001E0A, 0x001E0B, 0x001E04, 0x001E05, 0x001E06, + 0x001E07, 0x001E00, 0x001E01, 0x001E02, 0x001E03, 0x001E1C, 0x001E1D, 0x001E1E, + 0x001E1F, 0x001E18, 0x001E19, 0x001E1A, 0x001E1B, 0x001E14, 0x001E15, 0x001E16, + 0x001E17, 0x001E10, 0x001E11, 0x001E12, 0x001E13, 0x001EEC, 0x001EED, 0x001EEE, + 0x001EEF, 0x001EE8, 0x001EE9, 0x001EEA, 0x001EEB, 0x001EE4, 0x001EE5, 0x001EE6, + 0x001EE7, 0x001EE0, 0x001EE1, 0x001EE2, 0x001EE3, 0x001EF8, 0x001EF9, 0x001EF4, + 0x001EF5, 0x001EF6, 0x001EF7, 0x001EF0, 0x001EF1, 0x001EF2, 0x001EF3, 0x001ECC, + 0x001ECD, 0x001ECE, 0x001ECF, 0x001EC8, 0x001EC9, 0x001ECA, 0x001ECB, 0x001EC4, + 0x001EC5, 0x001EC6, 0x001EC7, 0x001EC0, 0x001EC1, 0x001EC2, 0x001EC3, 0x001EDC, + 0x001EDD, 0x001EDE, 0x001EDF, 0x001ED8, 0x001ED9, 0x001EDA, 0x001EDB, 0x001ED4, + 0x001ED5, 0x001ED6, 0x001ED7, 0x001ED0, 0x001ED1, 0x001ED2, 0x001ED3, 0x001EAC, + 0x001EAD, 0x001EAE, 0x001EAF, 0x001EA8, 0x001EA9, 0x001EAA, 0x001EAB, 0x001EA4, + 0x001EA5, 0x001EA6, 0x001EB9, 0x001EB1, 0x001E8A, 0x001E8B, 0x0000C9, 0x0000CA, + 0x0000CB, 0x0000C4, 0x001E99, 0x0000C7, 0x0000C0, 0x001E91, 0x001E92, 0x001F6A, + 0x001F6B, 0x001F67, 0x001F60, 0x001F61, 0x001F62, 0x001F63, 0x001F7C, 0x001F7D, + 0x001F78, 0x001F79, 0x001F7A, 0x001F7B, 0x001F74, 0x001F75, 0x001F76, 0x001F77, + 0x001F70, 0x001F71, 0x001F72, 0x001F73, 0x001F4C, 0x001F4D, 0x001F48, 0x001F49, + 0x001F4A, 0x001F4B, 0x001F44, 0x001F45, 0x001F40, 0x001F41, 0x001F42, 0x001F43, + 0x001F5D, 0x001F5F, 0x001F59, 0x001F5B, 0x001F54, 0x001F55, 0x001F56, 0x001F57, + 0x001F50, 0x001F51, 0x002ADC, 0x001F52, 0x001F53, 0x001F2C, 0x001F2D, 0x001F2E, + 0x001F2F, 0x001F28, 0x001F29, 0x001F2A, 0x001F2B, }; + +/* indexes */ +const uint16_t NU_TOUNACCENT_VALUES_I[] = { + 0x0526, 0x0529, 0x052C, 0x0565, 0x0127, 0x0568, 0x012B, 0x0129, 0x0550, 0x0514, + 0x0517, 0x00EB, 0x0511, 0x00E9, 0x0111, 0x0101, 0x0736, 0x0739, 0x00C3, 0x00C5, + 0x00B7, 0x00B3, 0x00E1, 0x00E3, 0x0754, 0x0757, 0x06D9, 0x06DC, 0x0089, 0x0081, + 0x0071, 0x0073, 0x00B9, 0x018B, 0x0125, 0x012D, 0x00C9, 0x00BB, 0x018D, 0x00C7, + 0x06C1, 0x00CD, 0x00CB, 0x00C1, 0x00BF, 0x01F5, 0x0637, 0x063A, 0x0119, 0x0628, + 0x011B, 0x062B, 0x062E, 0x0631, 0x0121, 0x0203, 0x0625, 0x0670, 0x0206, 0x020C, + 0x0209, 0x0218, 0x020F, 0x0215, 0x0212, 0x023F, 0x010D, 0x010F, 0x021B, 0x010B, + 0x0123, 0x0673, 0x0676, 0x0131, 0x0133, 0x04E4, 0x04D2, 0x04D8, 0x0105, 0x04DE, + 0x00FD, 0x051D, 0x0520, 0x04ED, 0x0221, 0x0103, 0x014D, 0x0107, 0x0224, 0x012F, + 0x04F0, 0x0227, 0x054D, 0x04EA, 0x0151, 0x051A, 0x0679, 0x022D, 0x022A, 0x011F, + 0x0230, 0x013D, 0x0562, 0x0147, 0x055F, 0x04F3, 0x0145, 0x021E, 0x0553, 0x0324, + 0x0322, 0x0328, 0x0326, 0x032C, 0x032A, 0x0330, 0x0137, 0x0334, 0x0332, 0x013B, + 0x014F, 0x013F, 0x014B, 0x03AE, 0x03B0, 0x0143, 0x03B4, 0x0149, 0x054A, 0x055C, + 0x03BC, 0x0163, 0x034E, 0x0354, 0x0352, 0x0165, 0x0350, 0x035C, 0x035A, 0x0388, + 0x035E, 0x0364, 0x0360, 0x0376, 0x01E5, 0x036C, 0x0362, 0x01DB, 0x0378, 0x0374, + 0x0372, 0x01DD, 0x037C, 0x039A, 0x037A, 0x0571, 0x056E, 0x0394, 0x0574, 0x038A, + 0x003F, 0x0041, 0x004F, 0x0390, 0x038E, 0x0043, 0x0392, 0x0398, 0x0396, 0x0045, + 0x004B, 0x03A0, 0x0047, 0x004D, 0x03A2, 0x0051, 0x039E, 0x03C6, 0x0556, 0x052F, + 0x0523, 0x03A4, 0x056B, 0x03D6, 0x0577, 0x03AC, 0x03D8, 0x03CA, 0x03C8, 0x03C4, + 0x03C2, 0x03DA, 0x005B, 0x03CC, 0x0007, 0x0005, 0x0003, 0x005D, 0x005F, 0x000B, + 0x0063, 0x000F, 0x0067, 0x0257, 0x001B, 0x03E4, 0x03E0, 0x03EA, 0x001F, 0x001D, + 0x0023, 0x0021, 0x0027, 0x0025, 0x0035, 0x0029, 0x002D, 0x002B, 0x0031, 0x002F, + 0x0406, 0x0404, 0x0033, 0x0408, 0x040C, 0x03E6, 0x040A, 0x0055, 0x03F8, 0x040E, + 0x03FE, 0x03E2, 0x03E8, 0x003D, 0x0057, 0x03DE, 0x0017, 0x0019, 0x0065, 0x043C, + 0x0037, 0x0059, 0x03EC, 0x003B, 0x044C, 0x043A, 0x0448, 0x0053, 0x006B, 0x0061, + 0x0069, 0x006D, 0x0440, 0x0438, 0x0049, 0x0039, 0x0432, 0x0436, 0x0075, 0x03EE, + 0x03F0, 0x0416, 0x03FC, 0x043E, 0x03F6, 0x025D, 0x03FA, 0x0242, 0x0245, 0x0790, + 0x0248, 0x0266, 0x007D, 0x006F, 0x024B, 0x007F, 0x01E1, 0x00A7, 0x008B, 0x007B, + 0x00A9, 0x009F, 0x0077, 0x008D, 0x00AB, 0x00AD, 0x0093, 0x0095, 0x01D3, 0x01D5, + 0x00D5, 0x0272, 0x01D7, 0x00B5, 0x01D9, 0x0079, 0x01CB, 0x0083, 0x0085, 0x0414, + 0x025A, 0x0418, 0x00B1, 0x072D, 0x072A, 0x0420, 0x0730, 0x073F, 0x0727, 0x0745, + 0x0748, 0x073C, 0x00D7, 0x00CF, 0x0412, 0x074B, 0x0742, 0x0087, 0x00DF, 0x0141, + 0x074E, 0x0751, 0x00EF, 0x0446, 0x044A, 0x0766, 0x0450, 0x0442, 0x0763, 0x076F, + 0x044E, 0x00A3, 0x00A1, 0x00E5, 0x00E7, 0x01CD, 0x008F, 0x0091, 0x009B, 0x050E, + 0x0097, 0x00F1, 0x0135, 0x009D, 0x0113, 0x00A5, 0x0117, 0x04F9, 0x0099, 0x0109, + 0x0139, 0x0115, 0x04F6, 0x04FF, 0x04FC, 0x0502, 0x0505, 0x00F5, 0x076C, 0x00F7, + 0x050B, 0x00F3, 0x0769, 0x00FB, 0x04C9, 0x04CF, 0x00F9, 0x00ED, 0x0559, 0x04CC, + 0x011D, 0x0278, 0x04D5, 0x04C6, 0x027B, 0x0733, 0x04E7, 0x04DB, 0x01CF, 0x06EE, + 0x06F9, 0x0508, 0x06F5, 0x06F1, 0x00D3, 0x07DA, 0x07E2, 0x07DE, 0x027E, 0x0287, + 0x0284, 0x07E6, 0x0281, 0x028D, 0x028A, 0x04E1, 0x018F, 0x0293, 0x0290, 0x0299, + 0x0296, 0x029F, 0x029C, 0x07D6, 0x02AB, 0x02A5, 0x02A2, 0x07EA, 0x02B1, 0x00FF, + 0x02AE, 0x02C0, 0x02BD, 0x02B7, 0x02B4, 0x02A8, 0x0185, 0x02C3, 0x0153, 0x02C9, + 0x02C6, 0x07F6, 0x02CC, 0x02D5, 0x02D2, 0x0157, 0x07F2, 0x07EE, 0x02D8, 0x02CF, + 0x02DB, 0x05D1, 0x05CE, 0x02BA, 0x05D4, 0x05DD, 0x05DA, 0x0191, 0x0183, 0x05E9, + 0x05E6, 0x05EF, 0x05EC, 0x0189, 0x0187, 0x07FA, 0x0193, 0x0196, 0x00AF, 0x01A1, + 0x00BD, 0x00DB, 0x0169, 0x00D9, 0x00DD, 0x017F, 0x06E2, 0x0173, 0x00D1, 0x0177, + 0x065B, 0x0658, 0x063D, 0x0643, 0x016B, 0x0161, 0x0167, 0x016D, 0x0179, 0x0634, + 0x016F, 0x0175, 0x0649, 0x0171, 0x0646, 0x017D, 0x017B, 0x0655, 0x064F, 0x080E, + 0x0181, 0x0652, 0x064C, 0x0667, 0x0664, 0x066D, 0x066A, 0x06CA, 0x015B, 0x065E, + 0x0661, 0x0812, 0x061F, 0x0622, 0x015D, 0x015F, 0x061C, 0x06BB, 0x06BE, 0x01A3, + 0x068B, 0x068E, 0x019B, 0x019D, 0x0199, 0x019F, 0x01A5, 0x01A9, 0x01A7, 0x06B5, + 0x06AF, 0x0640, 0x06B8, 0x06B2, 0x01B1, 0x01AF, 0x01AD, 0x01AB, 0x01C7, 0x01C9, + 0x01B5, 0x06AC, 0x01C1, 0x01BD, 0x0723, 0x06EB, 0x01BF, 0x01BB, 0x06E8, 0x01D1, + 0x0691, 0x0712, 0x01B3, 0x0718, 0x01B7, 0x01B9, 0x0715, 0x01C5, 0x01C3, 0x0703, + 0x01DF, 0x0706, 0x0700, 0x01E3, 0x06FD, 0x06D3, 0x0709, 0x06D6, 0x06D0, 0x01E9, + 0x01EB, 0x01E7, 0x06E5, 0x070C, 0x01F1, 0x01ED, 0x0694, 0x01F3, 0x01EF, 0x0688, + 0x01FD, 0x01FB, 0x0201, 0x01FF, 0x06C4, 0x069A, 0x069D, 0x06A6, 0x0697, 0x06CD, + 0x06A9, 0x075D, 0x067F, 0x0682, 0x01F7, 0x01F9, 0x0760, 0x06DF, 0x0685, 0x067C, + 0x06A0, 0x070F, 0x075A, 0x06A3, 0x06C7, 0x071B, 0x071F, 0x0155, 0x0159, 0x0772, + 0x07B6, 0x07BA, 0x07BC, 0x07B0, 0x07B2, 0x07CE, 0x07D2, 0x07C6, 0x07CA, 0x07BE, + 0x07C2, 0x07AC, 0x07A4, 0x07A8, 0x07A0, 0x0798, 0x079C, 0x0780, 0x0784, 0x0788, + 0x0794, 0x0275, 0x078C, 0x077C, 0x0269, 0x026C, 0x026F, 0x0816, 0x081A, 0x0260, + 0x0263, 0x07FE, 0x0802, 0x0806, 0x080A, 0x0239, 0x023C, 0x0233, 0x0236, 0x0774, + 0x0778, 0x024E, 0x0251, 0x0254, 0x03B6, 0x03B8, 0x03BA, 0x03B2, 0x03A6, 0x03A8, + 0x03AA, 0x03DC, 0x03CE, 0x03D0, 0x03D2, 0x03D4, 0x03BE, 0x03C0, 0x036E, 0x0370, + 0x0366, 0x0368, 0x036A, 0x039C, 0x0386, 0x038C, 0x037E, 0x0380, 0x0382, 0x0384, + 0x0336, 0x0338, 0x033A, 0x033C, 0x032E, 0x031E, 0x0320, 0x0356, 0x0358, 0x0346, + 0x0348, 0x034A, 0x034C, 0x033E, 0x0340, 0x0342, 0x0344, 0x02F6, 0x02F8, 0x02FA, + 0x02FC, 0x02EE, 0x02F0, 0x02F2, 0x02F4, 0x02E6, 0x02E8, 0x02EA, 0x02EC, 0x02DE, + 0x02E0, 0x02E2, 0x02E4, 0x0316, 0x0318, 0x031A, 0x031C, 0x030E, 0x0310, 0x0312, + 0x0314, 0x0306, 0x0308, 0x030A, 0x030C, 0x02FE, 0x0300, 0x0302, 0x0304, 0x04AA, + 0x04AC, 0x04AE, 0x04B0, 0x04A2, 0x04A4, 0x04A6, 0x04A8, 0x049A, 0x049C, 0x049E, + 0x04A0, 0x0492, 0x0494, 0x0496, 0x0498, 0x04C2, 0x04C4, 0x04BA, 0x04BC, 0x04BE, + 0x04C0, 0x04B2, 0x04B4, 0x04B6, 0x04B8, 0x046A, 0x046C, 0x046E, 0x0470, 0x0462, + 0x0464, 0x0466, 0x0468, 0x045A, 0x045C, 0x045E, 0x0460, 0x0452, 0x0454, 0x0456, + 0x0458, 0x048A, 0x048C, 0x048E, 0x0490, 0x0482, 0x0484, 0x0486, 0x0488, 0x047A, + 0x047C, 0x047E, 0x0480, 0x0472, 0x0474, 0x0476, 0x0478, 0x042A, 0x042C, 0x042E, + 0x0430, 0x0422, 0x0424, 0x0426, 0x0428, 0x041A, 0x041C, 0x041E, 0x0444, 0x0434, + 0x03F2, 0x03F4, 0x0011, 0x0013, 0x0015, 0x0009, 0x0410, 0x000D, 0x0001, 0x0400, + 0x0402, 0x05E0, 0x05E3, 0x05D7, 0x05C2, 0x05C5, 0x05C8, 0x05CB, 0x0616, 0x0619, + 0x060A, 0x060D, 0x0610, 0x0613, 0x05FE, 0x0601, 0x0604, 0x0607, 0x05F2, 0x05F5, + 0x05F8, 0x05FB, 0x0598, 0x059B, 0x058C, 0x058F, 0x0592, 0x0595, 0x0586, 0x0589, + 0x057A, 0x057D, 0x0580, 0x0583, 0x05BC, 0x05BF, 0x05B6, 0x05B9, 0x05AA, 0x05AD, + 0x05B0, 0x05B3, 0x059E, 0x05A1, 0x081E, 0x05A4, 0x05A7, 0x053E, 0x0541, 0x0544, + 0x0547, 0x0532, 0x0535, 0x0538, 0x053B, }; + +const uint8_t NU_TOUNACCENT_COMBINED[] = { + 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, + 0x00, 0x43, 0x00, 0x45, 0x00, 0x45, 0x00, 0x45, 0x00, 0x45, 0x00, 0x49, + 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x4F, 0x00, 0x4F, + 0x00, 0x4F, 0x00, 0x4F, 0x00, 0x4F, 0x00, 0x4F, 0x00, 0x55, 0x00, 0x55, + 0x00, 0x55, 0x00, 0x55, 0x00, 0x59, 0x00, 0x61, 0x00, 0x61, 0x00, 0x61, + 0x00, 0x61, 0x00, 0x61, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00, 0x65, + 0x00, 0x65, 0x00, 0x65, 0x00, 0x69, 0x00, 0x69, 0x00, 0x69, 0x00, 0x69, + 0x00, 0x6E, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6F, + 0x00, 0x6F, 0x00, 0x75, 0x00, 0x75, 0x00, 0x75, 0x00, 0x75, 0x00, 0x79, + 0x00, 0x79, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x43, 0x00, 0x63, 0x00, 0x43, 0x00, 0x63, 0x00, 0x43, + 0x00, 0x63, 0x00, 0x43, 0x00, 0x63, 0x00, 0x44, 0x00, 0x64, 0x00, 0x44, + 0x00, 0x64, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, + 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x47, + 0x00, 0x67, 0x00, 0x47, 0x00, 0x67, 0x00, 0x47, 0x00, 0x67, 0x00, 0x47, + 0x00, 0x67, 0x00, 0x48, 0x00, 0x68, 0x00, 0x48, 0x00, 0x68, 0x00, 0x49, + 0x00, 0x69, 0x00, 0x49, 0x00, 0x69, 0x00, 0x49, 0x00, 0x69, 0x00, 0x49, + 0x00, 0x69, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x6A, 0x00, 0x4B, 0x00, 0x6B, + 0x00, 0x4C, 0x00, 0x6C, 0x00, 0x4C, 0x00, 0x6C, 0x00, 0x4C, 0x00, 0x6C, + 0x00, 0x4C, 0x00, 0x6C, 0x00, 0x4E, 0x00, 0x6E, 0x00, 0x4E, 0x00, 0x6E, + 0x00, 0x4E, 0x00, 0x6E, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, + 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x52, 0x00, 0x72, 0x00, 0x52, 0x00, 0x72, + 0x00, 0x52, 0x00, 0x72, 0x00, 0x53, 0x00, 0x73, 0x00, 0x53, 0x00, 0x73, + 0x00, 0x53, 0x00, 0x73, 0x00, 0x53, 0x00, 0x73, 0x00, 0x54, 0x00, 0x74, + 0x00, 0x54, 0x00, 0x74, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, + 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, + 0x00, 0x55, 0x00, 0x75, 0x00, 0x57, 0x00, 0x77, 0x00, 0x59, 0x00, 0x79, + 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7A, 0x00, 0x5A, 0x00, 0x7A, 0x00, 0x5A, + 0x00, 0x7A, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x55, 0x00, 0x75, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x49, 0x00, 0x69, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x55, + 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, + 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x47, 0x00, 0x67, 0x00, 0x4B, 0x00, 0x6B, 0x00, 0x4F, + 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0xC6, 0xB7, 0x00, 0xCA, 0x92, + 0x00, 0x6A, 0x00, 0x47, 0x00, 0x67, 0x00, 0x4E, 0x00, 0x6E, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x49, + 0x00, 0x69, 0x00, 0x49, 0x00, 0x69, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, + 0x00, 0x6F, 0x00, 0x52, 0x00, 0x72, 0x00, 0x52, 0x00, 0x72, 0x00, 0x55, + 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x53, 0x00, 0x73, 0x00, 0x54, + 0x00, 0x74, 0x00, 0x48, 0x00, 0x68, 0x00, 0x41, 0x00, 0x61, 0x00, 0x45, + 0x00, 0x65, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, + 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x59, 0x00, 0x79, 0x00, 0xC2, + 0xA8, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x95, 0x00, 0xCE, 0x97, 0x00, 0xCE, + 0x99, 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xA9, 0x00, 0xCE, + 0xB9, 0x00, 0xCE, 0x99, 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xB1, 0x00, 0xCE, + 0xB5, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB9, 0x00, 0xCF, 0x85, 0x00, 0xCE, + 0xB9, 0x00, 0xCF, 0x85, 0x00, 0xCE, 0xBF, 0x00, 0xCF, 0x85, 0x00, 0xCF, + 0x89, 0x00, 0xD0, 0x95, 0x00, 0xD0, 0x95, 0x00, 0xD0, 0x93, 0x00, 0xD0, + 0x86, 0x00, 0xD0, 0x9A, 0x00, 0xD0, 0x98, 0x00, 0xD0, 0xA3, 0x00, 0xD0, + 0x98, 0x00, 0xD0, 0xB8, 0x00, 0xD0, 0xB5, 0x00, 0xD0, 0xB5, 0x00, 0xD0, + 0xB3, 0x00, 0xD1, 0x96, 0x00, 0xD0, 0xBA, 0x00, 0xD0, 0xB8, 0x00, 0xD1, + 0x83, 0x00, 0xD1, 0xB4, 0x00, 0xD1, 0xB5, 0x00, 0xD0, 0x96, 0x00, 0xD0, + 0xB6, 0x00, 0xD0, 0x90, 0x00, 0xD0, 0xB0, 0x00, 0xD0, 0x90, 0x00, 0xD0, + 0xB0, 0x00, 0xD0, 0x95, 0x00, 0xD0, 0xB5, 0x00, 0xD3, 0x98, 0x00, 0xD3, + 0x99, 0x00, 0xD0, 0x96, 0x00, 0xD0, 0xB6, 0x00, 0xD0, 0x97, 0x00, 0xD0, + 0xB7, 0x00, 0xD0, 0x98, 0x00, 0xD0, 0xB8, 0x00, 0xD0, 0x98, 0x00, 0xD0, + 0xB8, 0x00, 0xD0, 0x9E, 0x00, 0xD0, 0xBE, 0x00, 0xD3, 0xA8, 0x00, 0xD3, + 0xA9, 0x00, 0xD0, 0xAD, 0x00, 0xD1, 0x8D, 0x00, 0xD0, 0xA3, 0x00, 0xD1, + 0x83, 0x00, 0xD0, 0xA3, 0x00, 0xD1, 0x83, 0x00, 0xD0, 0xA3, 0x00, 0xD1, + 0x83, 0x00, 0xD0, 0xA7, 0x00, 0xD1, 0x87, 0x00, 0xD0, 0xAB, 0x00, 0xD1, + 0x8B, 0x00, 0x41, 0x00, 0x61, 0x00, 0x42, 0x00, 0x62, 0x00, 0x42, 0x00, + 0x62, 0x00, 0x42, 0x00, 0x62, 0x00, 0x43, 0x00, 0x63, 0x00, 0x44, 0x00, + 0x64, 0x00, 0x44, 0x00, 0x64, 0x00, 0x44, 0x00, 0x64, 0x00, 0x44, 0x00, + 0x64, 0x00, 0x44, 0x00, 0x64, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, + 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, + 0x65, 0x00, 0x46, 0x00, 0x66, 0x00, 0x47, 0x00, 0x67, 0x00, 0x48, 0x00, + 0x68, 0x00, 0x48, 0x00, 0x68, 0x00, 0x48, 0x00, 0x68, 0x00, 0x48, 0x00, + 0x68, 0x00, 0x48, 0x00, 0x68, 0x00, 0x49, 0x00, 0x69, 0x00, 0x49, 0x00, + 0x69, 0x00, 0x4B, 0x00, 0x6B, 0x00, 0x4B, 0x00, 0x6B, 0x00, 0x4B, 0x00, + 0x6B, 0x00, 0x4C, 0x00, 0x6C, 0x00, 0x4C, 0x00, 0x6C, 0x00, 0x4C, 0x00, + 0x6C, 0x00, 0x4C, 0x00, 0x6C, 0x00, 0x4D, 0x00, 0x6D, 0x00, 0x4D, 0x00, + 0x6D, 0x00, 0x4D, 0x00, 0x6D, 0x00, 0x4E, 0x00, 0x6E, 0x00, 0x4E, 0x00, + 0x6E, 0x00, 0x4E, 0x00, 0x6E, 0x00, 0x4E, 0x00, 0x6E, 0x00, 0x4F, 0x00, + 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, + 0x6F, 0x00, 0x50, 0x00, 0x70, 0x00, 0x50, 0x00, 0x70, 0x00, 0x52, 0x00, + 0x72, 0x00, 0x52, 0x00, 0x72, 0x00, 0x52, 0x00, 0x72, 0x00, 0x52, 0x00, + 0x72, 0x00, 0x53, 0x00, 0x73, 0x00, 0x53, 0x00, 0x73, 0x00, 0x53, 0x00, + 0x73, 0x00, 0x53, 0x00, 0x73, 0x00, 0x53, 0x00, 0x73, 0x00, 0x54, 0x00, + 0x74, 0x00, 0x54, 0x00, 0x74, 0x00, 0x54, 0x00, 0x74, 0x00, 0x54, 0x00, + 0x74, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, + 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x56, 0x00, + 0x76, 0x00, 0x56, 0x00, 0x76, 0x00, 0x57, 0x00, 0x77, 0x00, 0x57, 0x00, + 0x77, 0x00, 0x57, 0x00, 0x77, 0x00, 0x57, 0x00, 0x77, 0x00, 0x57, 0x00, + 0x77, 0x00, 0x58, 0x00, 0x78, 0x00, 0x58, 0x00, 0x78, 0x00, 0x59, 0x00, + 0x79, 0x00, 0x5A, 0x00, 0x7A, 0x00, 0x5A, 0x00, 0x7A, 0x00, 0x5A, 0x00, + 0x7A, 0x00, 0x68, 0x00, 0x74, 0x00, 0x77, 0x00, 0x79, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x45, 0x00, + 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, + 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x45, 0x00, + 0x65, 0x00, 0x45, 0x00, 0x65, 0x00, 0x49, 0x00, 0x69, 0x00, 0x49, 0x00, + 0x69, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, + 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, + 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, + 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, 0x6F, 0x00, 0x4F, 0x00, + 0x6F, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, + 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x55, 0x00, + 0x75, 0x00, 0x55, 0x00, 0x75, 0x00, 0x59, 0x00, 0x79, 0x00, 0x59, 0x00, + 0x79, 0x00, 0x59, 0x00, 0x79, 0x00, 0x59, 0x00, 0x79, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0x91, + 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, + 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0xB5, + 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0xB5, + 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0x95, 0x00, 0xCE, 0x95, 0x00, 0xCE, 0x95, + 0x00, 0xCE, 0x95, 0x00, 0xCE, 0x95, 0x00, 0xCE, 0x95, 0x00, 0xCE, 0xB7, + 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, + 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0x97, + 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, + 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0xB9, + 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, + 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0x99, + 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, + 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, 0x00, 0xCE, 0xBF, + 0x00, 0xCE, 0xBF, 0x00, 0xCE, 0xBF, 0x00, 0xCE, 0xBF, 0x00, 0xCE, 0xBF, + 0x00, 0xCE, 0xBF, 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0x9F, + 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0x9F, 0x00, 0xCF, 0x85, + 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, + 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCE, 0xA5, + 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xA5, 0x00, 0xCF, 0x89, + 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, + 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCE, 0xA9, + 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, + 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0xB5, 0x00, 0xCE, 0xB7, + 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xBF, + 0x00, 0xCE, 0xBF, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x89, + 0x00, 0xCF, 0x89, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, + 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, + 0x00, 0xCE, 0x91, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, + 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, + 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, + 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, + 0x00, 0xCE, 0x97, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, + 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, + 0x00, 0xCF, 0x89, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, + 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, + 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, 0x00, 0xCE, 0xB1, + 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, 0x00, 0xCE, 0x91, + 0x00, 0xCE, 0x91, 0x00, 0xC2, 0xA8, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, + 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0xB7, 0x00, 0xCE, 0x95, + 0x00, 0xCE, 0x95, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x97, + 0x00, 0xE1, 0xBE, 0xBF, 0x00, 0xE1, 0xBE, 0xBF, 0x00, 0xE1, 0xBE, 0xBF, + 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, + 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0xB9, 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, + 0x00, 0xCE, 0x99, 0x00, 0xCE, 0x99, 0x00, 0xE1, 0xBF, 0xBE, 0x00, 0xE1, + 0xBF, 0xBE, 0x00, 0xE1, 0xBF, 0xBE, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, + 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x81, 0x00, 0xCF, 0x81, + 0x00, 0xCF, 0x85, 0x00, 0xCF, 0x85, 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xA5, + 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xA5, 0x00, 0xCE, 0xA1, 0x00, 0xC2, 0xA8, + 0x00, 0xC2, 0xA8, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, + 0x00, 0xCF, 0x89, 0x00, 0xCF, 0x89, 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0x9F, + 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0xCE, 0xA9, 0x00, 0x41, 0x00, + 0xE2, 0x86, 0x90, 0x00, 0xE2, 0x86, 0x92, 0x00, 0xE2, 0x86, 0x94, 0x00, + 0xE2, 0x87, 0x90, 0x00, 0xE2, 0x87, 0x94, 0x00, 0xE2, 0x87, 0x92, 0x00, + 0xE2, 0x88, 0x83, 0x00, 0xE2, 0x88, 0x88, 0x00, 0xE2, 0x88, 0x8B, 0x00, + 0xE2, 0x88, 0xA3, 0x00, 0xE2, 0x88, 0xA5, 0x00, 0xE2, 0x88, 0xBC, 0x00, + 0xE2, 0x89, 0x83, 0x00, 0xE2, 0x89, 0x85, 0x00, 0xE2, 0x89, 0x88, 0x00, + 0x3D, 0x00, 0xE2, 0x89, 0xA1, 0x00, 0xE2, 0x89, 0x8D, 0x00, 0x3C, 0x00, + 0x3E, 0x00, 0xE2, 0x89, 0xA4, 0x00, 0xE2, 0x89, 0xA5, 0x00, 0xE2, 0x89, + 0xB2, 0x00, 0xE2, 0x89, 0xB3, 0x00, 0xE2, 0x89, 0xB6, 0x00, 0xE2, 0x89, + 0xB7, 0x00, 0xE2, 0x89, 0xBA, 0x00, 0xE2, 0x89, 0xBB, 0x00, 0xE2, 0x8A, + 0x82, 0x00, 0xE2, 0x8A, 0x83, 0x00, 0xE2, 0x8A, 0x86, 0x00, 0xE2, 0x8A, + 0x87, 0x00, 0xE2, 0x8A, 0xA2, 0x00, 0xE2, 0x8A, 0xA8, 0x00, 0xE2, 0x8A, + 0xA9, 0x00, 0xE2, 0x8A, 0xAB, 0x00, 0xE2, 0x89, 0xBC, 0x00, 0xE2, 0x89, + 0xBD, 0x00, 0xE2, 0x8A, 0x91, 0x00, 0xE2, 0x8A, 0x92, 0x00, 0xE2, 0x8A, + 0xB2, 0x00, 0xE2, 0x8A, 0xB3, 0x00, 0xE2, 0x8A, 0xB4, 0x00, 0xE2, 0x8A, + 0xB5, 0x00, 0xE2, 0xAB, 0x9D, 0x00, +}; + diff --git a/vendor/nunicode/src/libnu/gen/_toupper.c b/vendor/nunicode/src/libnu/gen/_toupper.c new file mode 100644 index 0000000000..afaa708d99 --- /dev/null +++ b/vendor/nunicode/src/libnu/gen/_toupper.c @@ -0,0 +1,917 @@ +/* Automatically generated file (mph.py), 1490539881 + * + * Tag : NU_TOUPPER + * Prime : 01000193, + * G size : 1396, + * Combined length : 5530, + * Encoding : UTF-8 + */ + +#include <stdint.h> + +const int16_t NU_TOUPPER_G[] = { + 1, -1396, 1, -1395, 1, -1394, 1, -1393, 1, -1392, 1, -1391, + 1, -1390, 1, -1389, 1, 1, 1, 5, 8, 1, 4, 9, + -1388, 0, -1387, 0, -1386, 0, -1385, 0, -1384, 0, -1383, 0, + -1382, 0, -1381, 0, -1380, 0, -1379, 0, -1377, 0, -1376, 0, + -1375, 0, -1374, 0, 0, -1373, 0, 0, -1372, 1, -1371, 1, + -1370, 1, -1369, 1, 7, 10, -1368, 12, 2, -1367, 2, -1366, + -1365, 0, -1364, 0, -1363, 0, -1362, 0, 2, -1361, 1, -1360, + 1, -1359, 1, -1358, -1357, -1355, -1354, 0, -1353, 0, 17, 0, + -1352, -1351, 19, 0, 0, -1350, 0, 0, 1, -1349, -1348, 1, + -1347, -1346, 3, -1345, -1343, -1342, -1341, 4, -1340, -1339, -1338, 2, + 0, 0, 0, -1337, 0, 2, 0, -1336, -1335, -1334, 8, -1333, + 1, 8, 1, 9, 1, 1, 1, 7, 28, 31, 1, 33, + -1332, -1331, -1330, 1, 0, 0, -1329, 0, 0, -1327, 0, -1325, + 0, -1324, 0, -1322, 0, -1320, 0, -1319, 1, -1316, 1, 1, + -1314, -1312, -1310, -1308, -1306, 1, 1, -1304, 1, -1302, 1, 1, + -1300, 1, -1298, 1, 1, 1, -1296, 1, -1295, -1292, 1, -1290, + 1, -1288, 1, -1286, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 2, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 1, 0, + -1284, 0, -1282, 0, -1280, 0, -1276, 0, -1275, 0, -1274, 0, + -1272, 0, -1271, 0, -1270, 0, -1269, 0, -1267, 0, -1265, 0, + -1264, 0, -1263, 0, 0, -1262, 0, 0, 0, -1261, 0, -1260, + -1259, 0, -1258, 0, -1257, 0, -1256, 0, -1255, 0, -1254, 0, + -1253, 0, -1252, 0, -1250, 0, -1248, 0, -1247, 0, -1246, 0, + -1245, 0, -1242, 0, -1241, 0, -1240, 0, 0, -1239, 0, -1238, + 0, -1237, 0, -1236, -1235, 0, -1234, -1233, -1231, 0, -1230, 0, + 48, -1229, 49, -1227, 63, -1223, 64, -1220, -1219, 64, -1218, -1216, + 68, 70, -1214, 69, 64, -1126, 64, -1115, 32, 1, 32, 1, + 32, 1, 32, 1, 32, 1, 32, 1, -1114, -1111, -1110, -1109, + -906, -893, -891, -887, -884, -883, -881, -872, -870, -868, -862, -860, + 32, 32, 32, 32, 33, -859, 33, 40, -858, -857, -853, -850, + -848, -846, 35, -839, -837, -836, -833, -830, -828, -826, 17, -825, + -824, -823, -822, -820, -819, -818, -817, -816, -812, -810, -808, -804, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, -800, 32, -799, + -798, -797, 33, -796, 32, -794, 35, -792, 32, -790, 32, -788, + 40, -786, 40, -784, 40, -783, 40, -782, 33, -781, 33, -780, + 33, -778, 33, -776, -774, 0, -772, 0, -770, 0, -768, 0, + -766, 0, -761, 0, -760, 0, -758, 0, -756, 0, -754, 0, + -748, 0, -747, 0, -746, 0, -745, 0, -743, 0, -742, 0, + -741, 0, -736, 0, -734, 0, 1, 0, -732, 0, 4, 0, + -730, 0, -720, 0, -717, 0, -706, 0, 1, 0, -703, 0, + -701, 0, -689, 0, -671, 0, -669, 0, -668, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -667, -666, -665, -641, + 5, -640, 5, -639, -638, -635, -634, 11, -615, -613, -612, -610, + -608, 2, -607, 6, 2, 1, 1, 5, -606, -605, -604, -603, + 0, -602, -601, -597, 0, 0, 0, 0, -594, -592, -588, 0, + -587, -584, -581, -580, -578, -577, -576, -575, -574, -573, -572, -571, + -570, -569, -568, 1, -567, -564, -563, -562, -561, -560, -558, -556, + 1, 1, 1, 1, -555, -554, 9, 10, -553, -552, -551, -550, + -549, -548, -547, -546, -545, -544, -543, -542, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -541, 1, 16, 1, + -540, -539, -538, -537, -536, -534, -532, -530, -528, -526, -525, -524, + 1, 1, 1, 4, 1, -523, 16, 19, 12, 1, 16, -522, + 16, -521, 64, -520, -519, 0, -518, 0, -517, -516, 17, -515, + -514, 30, 28, -513, -512, 32, -510, 41, 0, -508, -506, 47, + -504, -503, -502, -497, 0, 0, -496, 0, 12, 0, -494, -490, + -489, 0, 0, 0, 44, 0, 53, 0, 67, 0, 69, 0, + 31, 0, 32, 0, 39, 0, 43, 0, 0, 0, 0, 0, + 0, 0, 0, -488, 0, 0, 0, 0, -486, 0, -484, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, -480, 0, + -476, 0, -475, 0, 0, 0, -474, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -473, -472, -471, -470, + -469, -468, -467, -466, -465, -463, -461, -455, -451, -449, -439, -428, + -424, -423, -422, -384, -383, -382, -381, -380, -379, -377, 4, -376, + -375, -374, -373, -372, -371, -370, -369, -363, 2, -361, -352, -351, + -350, 0, 0, 0, -349, -348, 0, -347, -346, -345, 2, 5, + -344, -343, -342, -341, -340, -339, -338, -337, -335, -323, -322, -312, + -311, -308, -307, -306, -305, 1, 0, 0, 0, 0, 0, 0, + -304, 0, 0, 0, 4, 3, 8, 0, 1, -303, -302, 1, + 4, 0, -301, 0, 1, -300, -299, 23, 2, -298, -297, -296, + 4, -294, -293, -291, 1, -289, 5, -287, 36, -285, 53, 1, + 8, 12, 9, 40, 1, 40, 1, 40, 11, -279, 64, -264, + 64, -263, 64, -262, 4, 45, 4, 44, 76, -261, 11, 41, + -260, 0, -259, 0, 0, 0, 0, 0, 66, 69, 68, 79, + 180, 4, 186, 189, 70, -258, -257, 81, 93, -256, 100, -255, + 5, 67, 65, -254, 5, 67, 4, 131, 68, -253, 78, -252, + 68, -251, 115, -250, 81, -249, 98, -248, 101, -247, 101, -246, + 0, 0, 0, 0, -245, 0, -244, 0, 3, 167, 2, 169, + 1, -243, 1, -242, 1, 0, 1, 0, -241, 0, -240, 0, + 136, -239, 139, -238, -237, 0, 15, -236, -235, 0, -234, 0, + -233, 0, -232, 0, 158, -231, 157, -230, 136, -229, 142, -228, + -227, -226, -225, -223, 0, 0, -221, -215, 183, -214, -168, 199, + 141, -167, -163, -161, -156, 0, -155, 0, -154, 0, -153, 0, + 1, 0, 1, 0, 1, 1, 1, -152, 1, 1, -151, 1, + -150, 0, -148, 0, -147, 0, -145, -144, -143, -142, -141, -140, + 2, 0, -139, 0, 2, 0, 1, 0, 1, 0, 1, 0, + -138, -137, 9, 0, -136, 0, 1, 0, 48, -135, 54, -134, + 6, -133, 1, -132, 1, -131, 1, 23, -130, -129, 16, 0, + 1, 39, 1, -128, 1, -127, 81, 46, 22, -126, 83, -125, + 89, -124, 98, -123, -122, 0, -121, 0, -120, 0, -119, 0, + 1, -117, 1, -115, 1, -112, 1, -111, -110, 0, -109, 0, + -108, 0, -107, 0, -106, 0, -105, 0, -104, 0, -103, 0, + 39, 0, 43, 0, 8, 0, 35, 0, 32, 0, 32, 0, + 32, 0, 37, 0, 77, 0, 82, 0, 7, 0, 8, 0, + 1, 0, 20, 0, 38, 0, 40, 0, -102, 0, -101, 0, + -100, 0, -99, 0, -98, 0, -97, 0, -96, 0, -95, 0, + 5, 0, 10, 0, 75, 0, 79, 0, 5, 0, 11, 0, + -94, 0, 83, 0, -93, 0, -92, 0, -91, 0, -90, 0, + -89, 0, -88, 0, -87, 0, -86, 0, -85, 0, -84, 0, + -83, 0, -82, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, -81, 1, -80, 1, -79, 1, -78, 1, -77, 1, -76, + 1, -75, 1, -74, 1, 0, 1, 0, 2, 0, 1, 0, + -73, 0, -72, 0, -71, 0, -70, 0, -69, 0, -68, 0, + -67, 0, -66, 0, 1, 0, 1, 0, 2, 0, 1, 0, + 1, -65, 1, -64, 16, -62, 162, -60, 0, 0, -58, -57, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -56, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -55, -53, -52, -51, -50, -49, -47, -45, + -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, 0, + -29, -27, -26, -25, -24, -23, -22, -21, 14, 37, 64, 67, + 72, -20, 75, -18, -16, 0, -14, 0, -12, 0, -11, 0, + -10, 0, -9, 0, 0, 0, -8, 0, -7, -6, -5, -4, + 68, -3, -2, -1, }; + +const size_t NU_TOUPPER_G_SIZE = sizeof(NU_TOUPPER_G) / sizeof(*NU_TOUPPER_G); + +/* codepoints */ +const uint32_t NU_TOUPPER_VALUES_C[] = { + 0x0104F4, 0x0104F5, 0x0104F6, 0x0104F0, 0x0104F1, 0x0104F2, 0x0104F3, 0x000481, + 0x00049D, 0x00049F, 0x000499, 0x00049B, 0x000581, 0x000495, 0x000583, 0x000497, + 0x000585, 0x0104DC, 0x000587, 0x0104DE, 0x000568, 0x000569, 0x00056A, 0x00056B, + 0x000564, 0x000565, 0x000566, 0x00052D, 0x000567, 0x000561, 0x000562, 0x000563, + 0x00057C, 0x00057D, 0x00057E, 0x00057F, 0x000578, 0x000579, 0x00057A, 0x00057B, + 0x00FB01, 0x00FB05, 0x00FB03, 0x00FB02, 0x000574, 0x00FB00, 0x000575, 0x00FB06, + 0x000576, 0x000577, 0x000570, 0x000571, 0x000572, 0x00FB04, 0x000573, 0x002184, + 0x0024E8, 0x0024E9, 0x00FB13, 0x0024E4, 0x00FB15, 0x0024E6, 0x00FB17, 0x0024E0, + 0x0024E2, 0x001E61, 0x001E63, 0x001E7D, 0x001E7F, 0x001E79, 0x001E7B, 0x001E75, + 0x001E77, 0x0024DC, 0x0024DE, 0x0024D8, 0x0024DA, 0x0024D4, 0x0024D6, 0x0024D0, + 0x0024D2, 0x001E51, 0x001E53, 0x001E2D, 0x001E2F, 0x001E29, 0x001E2B, 0x001E25, + 0x001E27, 0x001E21, 0x001E23, 0x001E3D, 0x001E3F, 0x001E3B, 0x001E09, 0x001E0B, + 0x001E05, 0x001E07, 0x001E01, 0x001E03, 0x001E1D, 0x001E1F, 0x001EF9, 0x001EFB, + 0x001EF5, 0x001EF7, 0x001EF1, 0x001EF3, 0x001ECD, 0x001ECF, 0x000584, 0x000586, + 0x000071, 0x000073, 0x000580, 0x000072, 0x000582, 0x000070, 0x001EC1, 0x001EC3, + 0x001EDD, 0x001EDF, 0x00FF4C, 0x00FF4E, 0x00FF48, 0x00FF4A, 0x00FF46, 0x000268, + 0x000266, 0x001EAB, 0x00FF5A, 0x00FF54, 0x00FF56, 0x00FF50, 0x00FF52, 0x001EBB, + 0x000272, 0x001EB7, 0x001E89, 0x000240, 0x001E85, 0x000242, 0x001E87, 0x00025C, + 0x001E81, 0x002C30, 0x001E83, 0x000259, 0x00214E, 0x00025B, 0x001E99, 0x000250, + 0x000229, 0x00022B, 0x000225, 0x000227, 0x002C3D, 0x002C3C, 0x002C3F, 0x002C3E, + 0x001F64, 0x002C68, 0x001F65, 0x002C6C, 0x0000B5, 0x00217C, 0x001F66, 0x001F61, + 0x002C4C, 0x00217E, 0x002C6A, 0x00217F, 0x002C4D, 0x002C5D, 0x002C4F, 0x002C4E, + 0x002C51, 0x002C50, 0x002C53, 0x002C52, 0x002C55, 0x002C54, 0x002C57, 0x002C56, + 0x002C59, 0x002C58, 0x002C5B, 0x002C5A, 0x002175, 0x002C5C, 0x002177, 0x002C5E, + 0x002179, 0x002171, 0x00217B, 0x00217A, 0x00217D, 0x002174, 0x002176, 0x002178, + 0x0000E9, 0x0000E1, 0x0000EB, 0x0000E3, 0x0000ED, 0x0000E5, 0x0000EF, 0x0000E7, + 0x002C61, 0x0000F1, 0x002C73, 0x0000F3, 0x0000F5, 0x001F62, 0x001F7C, 0x002C76, + 0x002C66, 0x002C65, 0x0000F9, 0x0000FB, 0x001F7D, 0x0000FD, 0x001F78, 0x0000FF, + 0x001F79, 0x001F7A, 0x001F7B, 0x001F74, 0x001F76, 0x001F70, 0x001F72, 0x000209, + 0x00020B, 0x000205, 0x000207, 0x001F44, 0x000203, 0x001F40, 0x001F42, 0x000219, + 0x00021B, 0x001F54, 0x001F56, 0x00A681, 0x00A683, 0x001F24, 0x001F26, 0x001F20, + 0x001F22, 0x01E92C, 0x01E92E, 0x01E928, 0x01E92A, 0x001F30, 0x01E93C, 0x01E93E, + 0x01E939, 0x01E93A, 0x00A74D, 0x00A74F, 0x0118CE, 0x0118C4, 0x0118C6, 0x0118C0, + 0x002C89, 0x002C81, 0x002C8B, 0x002C83, 0x002C8D, 0x002C85, 0x002C8F, 0x002C87, + 0x000111, 0x002C91, 0x000113, 0x002C93, 0x002C95, 0x000117, 0x0118C2, 0x000115, + 0x000119, 0x00011B, 0x002C99, 0x002C9B, 0x0118D6, 0x002C9D, 0x0118D0, 0x002C9F, + 0x0118D2, 0x000161, 0x001FF4, 0x000163, 0x00A729, 0x001FF6, 0x002CC7, 0x00028C, + 0x00A725, 0x001FF2, 0x000289, 0x00028A, 0x00A73D, 0x00A739, 0x001FC6, 0x00A733, + 0x001FD7, 0x001FD0, 0x001FD1, 0x001FD2, 0x002CD5, 0x000175, 0x001FD3, 0x001FAC, + 0x00017E, 0x00017C, 0x00017A, 0x00017F, 0x001C85, 0x002CD9, 0x001C87, 0x001C88, + 0x000171, 0x001FAD, 0x001FAE, 0x000173, 0x002CE1, 0x000165, 0x002CE3, 0x000167, + 0x000177, 0x000169, 0x002CEC, 0x00016B, 0x002CEE, 0x00016D, 0x001FAF, 0x00016F, + 0x001FA8, 0x001FA9, 0x001FAA, 0x001FAB, 0x001FA4, 0x001FA5, 0x001FA6, 0x001FA7, + 0x001FA2, 0x001FA3, 0x001FBC, 0x001FBE, 0x00037B, 0x000377, 0x001FB4, 0x000371, + 0x002D20, 0x002D21, 0x002D22, 0x002D23, 0x002D25, 0x002D04, 0x002D27, 0x002D06, + 0x001FB6, 0x002D08, 0x001FB0, 0x002D0A, 0x002D24, 0x002D0C, 0x002D2D, 0x002D0E, + 0x001FB1, 0x001FB2, 0x001FB3, 0x001F8C, 0x001F8D, 0x001F8E, 0x001F8F, 0x001F88, + 0x001F8A, 0x010CED, 0x001F8B, 0x001F84, 0x001F85, 0x001F86, 0x001F87, 0x001F80, + 0x002D11, 0x000180, 0x000183, 0x002D13, 0x000195, 0x002D05, 0x000185, 0x002D07, + 0x002D17, 0x002D09, 0x000199, 0x002D0B, 0x000188, 0x002D0D, 0x00018C, 0x002D0F, + 0x010CC5, 0x010CC4, 0x010CC7, 0x010CC6, 0x010CC9, 0x010CC8, 0x010CCB, 0x010CCA, + 0x010CCD, 0x010CCC, 0x010CCF, 0x010CCE, 0x010CD1, 0x010CD0, 0x010CD3, 0x010CD2, + 0x0001A1, 0x002D01, 0x0001A3, 0x002D03, 0x0001A5, 0x001F81, 0x001F82, 0x001F83, + 0x010CD5, 0x0001A8, 0x010CD4, 0x001F9C, 0x010CE1, 0x010CF1, 0x010CE3, 0x010CE2, + 0x010CE0, 0x0001B9, 0x010CE7, 0x010CEB, 0x0001B6, 0x002D15, 0x001F9D, 0x010CEA, + 0x002D1E, 0x002D1C, 0x002D1A, 0x002D1F, 0x0001BD, 0x010CF0, 0x0001BF, 0x010CF2, + 0x001F9E, 0x010CE5, 0x001F9F, 0x010CE4, 0x0001C5, 0x010CE9, 0x001F98, 0x0001C6, + 0x0001C9, 0x0001C8, 0x0001CB, 0x010CEF, 0x001F99, 0x0001CC, 0x001F9A, 0x0001CE, + 0x001F9B, 0x001F94, 0x001F95, 0x001F96, 0x001F97, 0x001F90, 0x001F91, 0x001F92, + 0x001F93, 0x00A7A9, 0x00A7A5, 0x00A7A7, 0x0001DD, 0x0001DC, 0x0001DF, 0x00A7A1, + 0x0001E1, 0x00A7A3, 0x0001E3, 0x00A7B5, 0x0001E5, 0x00A7B7, 0x0001E7, 0x00A78C, + 0x00A797, 0x0003F8, 0x0001EB, 0x0001E9, 0x0001ED, 0x00A791, 0x0001EF, 0x0003F5, + 0x0003F0, 0x0001F0, 0x0001F3, 0x0001F2, 0x0001F5, 0x0003F1, 0x0003F2, 0x0003F3, + 0x0001F9, 0x0003CD, 0x0001FB, 0x0003CE, 0x0001FD, 0x0003C9, 0x0001FF, 0x0003CB, + 0x0003C4, 0x0003C7, 0x0003C0, 0x0003C2, 0x0003C3, 0x0003DD, 0x0003DF, 0x010CEC, + 0x010CEE, 0x010CE8, 0x010CE6, 0x002C48, 0x002C49, 0x002C4A, 0x000201, 0x002C4B, + 0x000211, 0x002C44, 0x000213, 0x002C45, 0x000215, 0x002C46, 0x000217, 0x002C47, + 0x002C40, 0x002C41, 0x002C42, 0x002C43, 0x0003BF, 0x010CC0, 0x010CC1, 0x010CC2, + 0x010CC3, 0x010CDC, 0x010CDD, 0x010CDE, 0x010CDF, 0x010CD8, 0x010CD9, 0x010CDA, + 0x010CDB, 0x010CD6, 0x010CD7, 0x002C38, 0x00022D, 0x002C39, 0x00022F, 0x002C3A, + 0x002C3B, 0x002C34, 0x002C35, 0x002C36, 0x001D79, 0x001D7D, 0x002C37, 0x002C31, + 0x002C32, 0x002C33, 0x00006C, 0x00006D, 0x00006E, 0x00006F, 0x000068, 0x000069, + 0x00006A, 0x00006B, 0x00026C, 0x000064, 0x000065, 0x000247, 0x00AB53, 0x000066, + 0x000249, 0x00024B, 0x000067, 0x000061, 0x00024D, 0x00026A, 0x00024F, 0x000062, + 0x000251, 0x000063, 0x000253, 0x000252, 0x000078, 0x000254, 0x000257, 0x000256, + 0x000079, 0x00007A, 0x000074, 0x000075, 0x000076, 0x000077, 0x00AB79, 0x00AB7B, + 0x000261, 0x00AB74, 0x000263, 0x00AB75, 0x00AB76, 0x0118C1, 0x00AB77, 0x0118CF, + 0x000269, 0x0118C5, 0x00026B, 0x0118C7, 0x00AB7A, 0x00AB7C, 0x00026F, 0x00AB70, + 0x00AB7D, 0x00AB7F, 0x00AB78, 0x00AB7E, 0x000275, 0x000265, 0x00A643, 0x000260, + 0x000271, 0x00AB71, 0x00AB72, 0x00A641, 0x00027D, 0x00AB73, 0x001C84, 0x001C86, + 0x001C80, 0x000280, 0x000283, 0x000287, 0x00ABB1, 0x00AB90, 0x00ABB3, 0x00AB92, + 0x00023F, 0x00AB94, 0x00028B, 0x00AB96, 0x00ABB0, 0x00AB98, 0x00ABB9, 0x00AB9A, + 0x00020D, 0x00020F, 0x00A665, 0x000292, 0x00A667, 0x00029D, 0x00021D, 0x00021F, + 0x001C81, 0x001C82, 0x001C83, 0x002CF3, 0x002CCD, 0x00029E, 0x002CCF, 0x000288, + 0x00AB8C, 0x00AB8D, 0x00AB8E, 0x00AB8F, 0x00ABA1, 0x00AB91, 0x00A66D, 0x00AB93, + 0x00A647, 0x00AB95, 0x0118CD, 0x00AB97, 0x0118C3, 0x00AB99, 0x000223, 0x00AB9B, + 0x002CC9, 0x0118C9, 0x00A64B, 0x0118CB, 0x0118D9, 0x00A645, 0x0118D3, 0x0118DB, + 0x0118D1, 0x0118D4, 0x0118DA, 0x000233, 0x002CCB, 0x001E15, 0x002CC5, 0x000231, + 0x0118DD, 0x002CC1, 0x0118DF, 0x001E0D, 0x0118D5, 0x00A649, 0x001E0F, 0x00A657, + 0x0118C8, 0x0118CC, 0x00A669, 0x0118CA, 0x002CC3, 0x00A64D, 0x00A663, 0x002CDD, + 0x001E13, 0x00A64F, 0x001E17, 0x00A661, 0x0118D8, 0x001E11, 0x00A66B, 0x0118D7, + 0x0118DC, 0x002CDF, 0x0118DE, 0x002CDB, 0x00A653, 0x002CD7, 0x00A655, 0x002CD1, + 0x00A65D, 0x00A659, 0x00A651, 0x00A65B, 0x002CD3, 0x002CAD, 0x002CAF, 0x00A65F, + 0x002CA9, 0x002CAB, 0x002CA5, 0x002CA7, 0x00A687, 0x001E19, 0x001E37, 0x00A685, + 0x00A689, 0x002CA1, 0x00A68B, 0x002CA3, 0x00A68D, 0x002CBD, 0x00A68F, 0x002CBF, + 0x002CB9, 0x001E1B, 0x001E35, 0x00023C, 0x001E41, 0x002CBB, 0x001E43, 0x002CB5, + 0x001E45, 0x002CB7, 0x001E47, 0x002CB1, 0x001E49, 0x002CB3, 0x001E4B, 0x0000EC, + 0x001E4D, 0x0000EE, 0x001E4F, 0x0000E8, 0x0000EA, 0x0000E4, 0x0000E6, 0x0000E0, + 0x001E55, 0x0000E2, 0x001E57, 0x0000FC, 0x001E59, 0x0000FE, 0x001E5B, 0x0000F8, + 0x001E5D, 0x0000FA, 0x001E5F, 0x0000F4, 0x0000F6, 0x002C97, 0x0000F0, 0x0000F2, + 0x001E65, 0x0000DF, 0x001E67, 0x00ABAC, 0x001E69, 0x001E6B, 0x001E39, 0x00ABAD, + 0x001E6D, 0x00ABAE, 0x001E6F, 0x00ABAF, 0x001E71, 0x001E73, 0x00A697, 0x00ABA8, + 0x00ABA9, 0x00ABAA, 0x00ABAB, 0x00ABA4, 0x001E33, 0x00ABA5, 0x00ABA6, 0x00ABA7, + 0x00ABA0, 0x00ABA2, 0x001E31, 0x00ABA3, 0x001ED1, 0x00ABBC, 0x001EDB, 0x00A693, + 0x00ABBD, 0x000345, 0x001ED5, 0x00ABBE, 0x00ABBF, 0x001E8B, 0x00ABB8, 0x001EBD, + 0x001E8D, 0x001E8F, 0x00A691, 0x001EBF, 0x001E91, 0x00ABBA, 0x001E93, 0x00ABBB, + 0x001E95, 0x00ABB4, 0x001E97, 0x001E96, 0x00ABB5, 0x001E98, 0x001E9B, 0x001E9A, + 0x00ABB6, 0x00ABB7, 0x00ABB2, 0x00AB88, 0x001EA1, 0x00AB89, 0x001EEF, 0x00A695, + 0x001EA5, 0x001EA3, 0x001EA7, 0x00AB8A, 0x00A699, 0x00AB8B, 0x00A69B, 0x00AB84, + 0x001EAD, 0x00A741, 0x001EAF, 0x00A743, 0x001EB1, 0x00A761, 0x001EB3, 0x00A74B, + 0x00AB85, 0x000373, 0x00AB86, 0x00AB87, 0x001EB9, 0x001EA9, 0x00AB80, 0x001ED9, + 0x001EB5, 0x00037C, 0x00AB81, 0x001EED, 0x00AB82, 0x001ED7, 0x001EE1, 0x00037D, + 0x001EC5, 0x001EE5, 0x001EC7, 0x001EE7, 0x001EC9, 0x00A75D, 0x001ECB, 0x001EEB, + 0x001EE9, 0x00AB83, 0x00A723, 0x00A76D, 0x00A765, 0x00A727, 0x001ED3, 0x0024E5, + 0x00A72D, 0x000390, 0x001EFD, 0x00A76F, 0x001EFF, 0x00A77C, 0x00A72F, 0x00A72B, + 0x0013FD, 0x0003D9, 0x0013FC, 0x00A737, 0x0013F9, 0x0013F8, 0x0013FB, 0x0013FA, + 0x0003E5, 0x00A77F, 0x00A73B, 0x00A73F, 0x0003E7, 0x00A735, 0x00A763, 0x001EE3, + 0x0003AC, 0x00A745, 0x00A749, 0x00A747, 0x0003AD, 0x0003BD, 0x0003AF, 0x0003AE, + 0x0003B1, 0x0003B0, 0x0003B3, 0x0003B2, 0x0003B5, 0x0003B4, 0x0003B7, 0x0003B6, + 0x0003B9, 0x0003B8, 0x0003BB, 0x0003BA, 0x00A75F, 0x0003BC, 0x001F06, 0x0003BE, + 0x00A759, 0x0003D1, 0x00A75B, 0x0003D0, 0x00A755, 0x0003D5, 0x0003ED, 0x00A757, + 0x0003EF, 0x0003E9, 0x00A767, 0x0003DB, 0x00A751, 0x01E925, 0x01E927, 0x0003E3, + 0x0003C1, 0x001F11, 0x01E923, 0x001F13, 0x0003E1, 0x00A769, 0x00A76B, 0x0003D6, + 0x0003C6, 0x0003C5, 0x001F15, 0x0003D7, 0x010429, 0x01042B, 0x01E936, 0x00A753, + 0x01042D, 0x0003C8, 0x01042F, 0x0003CC, 0x01043A, 0x010430, 0x00A77A, 0x010432, + 0x010438, 0x010434, 0x0003CA, 0x010436, 0x01E943, 0x001F35, 0x001F37, 0x01E941, + 0x01043B, 0x01043F, 0x001F33, 0x01043D, 0x0003EB, 0x010440, 0x010443, 0x0003FB, + 0x001F10, 0x001F14, 0x010445, 0x001F12, 0x001F25, 0x001F03, 0x001F27, 0x001F21, + 0x010448, 0x001F01, 0x01044C, 0x001F02, 0x00A783, 0x01E93D, 0x001F45, 0x00A793, + 0x00A787, 0x00A781, 0x01E92D, 0x001F00, 0x001F53, 0x01E922, 0x01E93F, 0x001F51, + 0x001F55, 0x01E926, 0x001F57, 0x01E929, 0x00A799, 0x01E938, 0x00A785, 0x01E92F, + 0x0024D1, 0x000438, 0x0024D3, 0x01E92B, 0x0024D5, 0x01E933, 0x0024D7, 0x00A79B, + 0x0024D9, 0x01E931, 0x0024DB, 0x01E932, 0x0024DD, 0x00043A, 0x0024DF, 0x00043B, + 0x0024E1, 0x01E93B, 0x0024E3, 0x01E930, 0x001F31, 0x001F32, 0x001F23, 0x01E937, + 0x000431, 0x001F36, 0x000433, 0x000434, 0x000435, 0x01E934, 0x000437, 0x000436, + 0x000439, 0x000430, 0x000432, 0x01E935, 0x00FF45, 0x00043C, 0x00FF4F, 0x0024E7, + 0x00A79D, 0x000440, 0x00FF49, 0x000442, 0x00A79F, 0x000444, 0x000447, 0x000446, + 0x000449, 0x001F89, 0x0104DD, 0x0104DF, 0x00044D, 0x0104D9, 0x00044F, 0x0104D8, + 0x000451, 0x000450, 0x000453, 0x01E924, 0x00AB9C, 0x00AB9D, 0x00AB9E, 0x00FF4D, + 0x000459, 0x00AB9F, 0x002D00, 0x00045A, 0x00045D, 0x00045C, 0x00045F, 0x001FA1, + 0x000461, 0x001FA0, 0x000463, 0x001F60, 0x000465, 0x002D02, 0x000467, 0x0104F7, + 0x00FF41, 0x00046B, 0x00FF43, 0x000469, 0x00046D, 0x00046F, 0x00FF47, 0x001F07, + 0x000471, 0x001FB7, 0x000473, 0x001F34, 0x000475, 0x001F04, 0x000477, 0x00FF58, + 0x000479, 0x00FF57, 0x00047B, 0x001F05, 0x00FF55, 0x001FC2, 0x00047F, 0x00047D, + 0x00FF59, 0x001FC4, 0x001FC7, 0x001FC3, 0x001FE0, 0x00FF4B, 0x001F41, 0x001F43, + 0x001FE4, 0x0104DB, 0x001FE6, 0x00FF53, 0x00048D, 0x00FF42, 0x00048F, 0x00FF51, + 0x001F63, 0x01E942, 0x00FF44, 0x001FD6, 0x0104E1, 0x01E940, 0x0104E3, 0x001FCC, + 0x0104E5, 0x0104EC, 0x0104E7, 0x0104EF, 0x0104E9, 0x0104ED, 0x0104EB, 0x0104EA, + 0x001FE5, 0x0104E8, 0x001FE7, 0x0104EE, 0x001FE1, 0x0004A1, 0x001F67, 0x001FE3, + 0x001F71, 0x001F73, 0x001FE2, 0x0004A3, 0x0104F9, 0x001FF3, 0x0104FB, 0x001FF7, + 0x0004B1, 0x001F52, 0x0004B3, 0x0104DA, 0x0004B5, 0x001F50, 0x0004B7, 0x001F75, + 0x0004B9, 0x001FFC, 0x0004BB, 0x001F77, 0x0004BD, 0x002D1D, 0x0004BF, 0x002D18, + 0x0004CC, 0x002D19, 0x002D1B, 0x002D14, 0x0004CE, 0x0004C4, 0x002D16, 0x0004C6, + 0x0004CF, 0x0004C8, 0x002D10, 0x0004CA, 0x002D12, 0x00014D, 0x00014F, 0x00048B, + 0x000148, 0x000149, 0x00014B, 0x000144, 0x000146, 0x000140, 0x000142, 0x00015D, + 0x00015F, 0x000159, 0x000491, 0x000493, 0x00015B, 0x000155, 0x000157, 0x000151, + 0x0004E1, 0x000153, 0x0004E3, 0x00012D, 0x00012F, 0x000129, 0x00012B, 0x000125, + 0x000127, 0x000121, 0x000123, 0x00013C, 0x00013E, 0x00013A, 0x000135, 0x000137, + 0x000131, 0x0004F3, 0x000133, 0x0004F1, 0x00010D, 0x00010F, 0x000109, 0x00010B, + 0x0004E9, 0x000105, 0x000107, 0x000101, 0x0004FD, 0x0004FF, 0x0004ED, 0x000103, + 0x000501, 0x00011D, 0x000503, 0x00011F, 0x000505, 0x00044C, 0x000507, 0x00044E, + 0x000509, 0x000448, 0x00050B, 0x00044A, 0x00050D, 0x00050F, 0x00044B, 0x000445, + 0x000511, 0x000441, 0x000513, 0x000443, 0x000515, 0x00045E, 0x000517, 0x000458, + 0x000519, 0x00045B, 0x00051B, 0x000454, 0x00051D, 0x000455, 0x00051F, 0x000456, + 0x000521, 0x000457, 0x000523, 0x000452, 0x000525, 0x000527, 0x0001D8, 0x0001DA, + 0x000529, 0x0001D4, 0x00052B, 0x0001D6, 0x0001D0, 0x00056D, 0x0001D2, 0x00056C, + 0x0001AD, 0x00043D, 0x00043E, 0x00043F, 0x002170, 0x002172, 0x002173, 0x0001B4, + 0x0001B0, 0x01044D, 0x01044E, 0x01044F, 0x010449, 0x01044A, 0x01044B, 0x00052F, + 0x010444, 0x010446, 0x010447, 0x010441, 0x010442, 0x00019E, 0x00019A, 0x0004EF, + 0x0004EB, 0x0004E5, 0x000192, 0x00056E, 0x0004E7, 0x01042C, 0x01042E, 0x010428, + 0x01042A, 0x0004F9, 0x0004FB, 0x0004F5, 0x0004F7, 0x01043C, 0x01043E, 0x010439, + 0x010435, 0x010437, 0x010431, 0x010433, 0x0004C2, 0x0004DD, 0x0004DF, 0x0004D9, + 0x0004DB, 0x00056F, 0x0004D5, 0x0004D7, 0x0004D1, 0x0004D3, 0x0004AD, 0x0004AF, + 0x0004A9, 0x0004AB, 0x0004A5, 0x0004A7, 0x0104E4, 0x0104E6, 0x0104E0, 0x0104E2, + 0x00FB14, 0x00FB16, 0x0104F8, 0x0104FA, }; + +/* indexes */ +const uint16_t NU_TOUPPER_VALUES_I[] = { + 0x0714, 0x0719, 0x071E, 0x0700, 0x0705, 0x070A, 0x070F, 0x0452, 0x0470, 0x0473, + 0x046A, 0x046D, 0x05AE, 0x0464, 0x05B4, 0x0467, 0x05BA, 0x069C, 0x137B, 0x06A6, + 0x0563, 0x0566, 0x0569, 0x056C, 0x0557, 0x055A, 0x055D, 0x0548, 0x0560, 0x054E, + 0x0551, 0x0554, 0x059F, 0x05A2, 0x05A5, 0x05A8, 0x0593, 0x0596, 0x0599, 0x059C, + 0x156D, 0x157B, 0x1573, 0x1570, 0x0587, 0x156A, 0x058A, 0x157E, 0x058D, 0x0590, + 0x057B, 0x057E, 0x0581, 0x1577, 0x0584, 0x0D78, 0x0DDC, 0x0DE0, 0x1581, 0x0DCC, + 0x158B, 0x0DD4, 0x1595, 0x0DBC, 0x0DC4, 0x09D7, 0x09DB, 0x0A0F, 0x0A13, 0x0A07, + 0x0A0B, 0x09FF, 0x0A03, 0x0DAC, 0x0DB4, 0x0D9C, 0x0DA4, 0x0D8C, 0x0D94, 0x0D7C, + 0x0D84, 0x09B7, 0x09BB, 0x096F, 0x0973, 0x0967, 0x096B, 0x095F, 0x0963, 0x0957, + 0x095B, 0x098F, 0x0993, 0x098B, 0x0927, 0x092B, 0x091F, 0x0923, 0x0917, 0x091B, + 0x094F, 0x0953, 0x0BA1, 0x0BA5, 0x0B99, 0x0B9D, 0x0B91, 0x0B95, 0x0B49, 0x0B4D, + 0x05B7, 0x05BD, 0x0021, 0x0025, 0x05AB, 0x0023, 0x05B1, 0x001F, 0x0B31, 0x0B35, + 0x0B69, 0x0B6D, 0x1326, 0x132E, 0x1316, 0x131E, 0x130E, 0x0288, 0x0284, 0x0B05, + 0x135E, 0x1346, 0x134E, 0x1336, 0x133E, 0x0B25, 0x02A1, 0x0B1D, 0x0A27, 0x023E, + 0x0A1F, 0x0242, 0x0A23, 0x0272, 0x0A17, 0x0DE4, 0x0A1B, 0x026C, 0x0D34, 0x026F, + 0x138C, 0x0254, 0x0225, 0x0228, 0x021F, 0x0222, 0x0E18, 0x0E14, 0x0E20, 0x0E1C, + 0x0C61, 0x0EAA, 0x0C65, 0x0EB2, 0x0035, 0x0D68, 0x0C69, 0x0C55, 0x0E54, 0x0D70, + 0x0EAE, 0x0D74, 0x0E58, 0x0E98, 0x0E60, 0x0E5C, 0x0E68, 0x0E64, 0x0E70, 0x0E6C, + 0x0E78, 0x0E74, 0x0E80, 0x0E7C, 0x0E88, 0x0E84, 0x0E90, 0x0E8C, 0x0D4C, 0x0E94, + 0x0D54, 0x0E9C, 0x0D5C, 0x0D3C, 0x0D64, 0x0D60, 0x0D6C, 0x0D48, 0x0D50, 0x0D58, + 0x0053, 0x003B, 0x0059, 0x0041, 0x005F, 0x0047, 0x0065, 0x004D, 0x0EA0, 0x006B, + 0x0EB6, 0x0071, 0x0077, 0x0C59, 0x0CA1, 0x0EBA, 0x0EA7, 0x0EA4, 0x0080, 0x0086, + 0x0CA5, 0x008C, 0x0C91, 0x0092, 0x0C95, 0x0C99, 0x0C9D, 0x0C81, 0x0C89, 0x0C71, + 0x0C79, 0x01F8, 0x01FB, 0x01F2, 0x01F5, 0x0C39, 0x01EF, 0x0C29, 0x0C31, 0x0210, + 0x0213, 0x13A0, 0x13A7, 0x108E, 0x1092, 0x0BF9, 0x0C01, 0x0BE9, 0x0BF1, 0x0A6D, + 0x0A77, 0x0A59, 0x0A63, 0x0C09, 0x0AC1, 0x0ACB, 0x0AB2, 0x0AB7, 0x1116, 0x111A, + 0x0881, 0x084F, 0x0859, 0x083B, 0x0ECE, 0x0EBE, 0x0ED2, 0x0EC2, 0x0ED6, 0x0EC6, + 0x0EDA, 0x0ECA, 0x00AD, 0x0EDE, 0x00B0, 0x0EE2, 0x0EE6, 0x00B6, 0x0845, 0x00B3, + 0x00B9, 0x00BC, 0x0EEE, 0x0EF2, 0x08A9, 0x0EF6, 0x088B, 0x0EFA, 0x0895, 0x0121, + 0x1554, 0x0124, 0x10D2, 0x1559, 0x0F4A, 0x02C1, 0x10CA, 0x1549, 0x02B8, 0x02BB, + 0x10F6, 0x10EE, 0x14FF, 0x10E2, 0x1523, 0x0D1C, 0x0D20, 0x1510, 0x0F66, 0x013F, + 0x1517, 0x14B6, 0x014B, 0x0148, 0x0145, 0x014E, 0x0902, 0x0F6E, 0x0908, 0x090B, + 0x0139, 0x14BC, 0x14C2, 0x013C, 0x0F7E, 0x0127, 0x0F82, 0x012A, 0x0142, 0x012D, + 0x0F86, 0x0130, 0x0F8A, 0x0133, 0x14C8, 0x0136, 0x149E, 0x14A4, 0x14AA, 0x14B0, + 0x1486, 0x148C, 0x1492, 0x1498, 0x147A, 0x1480, 0x14EA, 0x0D15, 0x02DB, 0x02D8, + 0x14D9, 0x02D2, 0x1012, 0x1016, 0x101A, 0x101E, 0x1026, 0x0FA2, 0x102A, 0x0FAA, + 0x14DE, 0x0FB2, 0x0D09, 0x0FBA, 0x1022, 0x0FC2, 0x102E, 0x0FCA, 0x0D0D, 0x14CE, + 0x14D4, 0x13F6, 0x13FC, 0x1402, 0x1408, 0x13DE, 0x13EA, 0x081D, 0x13F0, 0x13C6, + 0x13CC, 0x13D2, 0x13D8, 0x13AE, 0x0FD6, 0x0150, 0x0153, 0x0FDE, 0x0162, 0x0FA6, + 0x0156, 0x0FAE, 0x0FEE, 0x0FB6, 0x0165, 0x0FBE, 0x0159, 0x0FC6, 0x015C, 0x0FCE, + 0x0755, 0x0750, 0x075F, 0x075A, 0x0769, 0x0764, 0x0773, 0x076E, 0x077D, 0x0778, + 0x0787, 0x0782, 0x0791, 0x078C, 0x079B, 0x0796, 0x016E, 0x0F96, 0x0171, 0x0F9E, + 0x0174, 0x13B4, 0x13BA, 0x13C0, 0x07A5, 0x0177, 0x07A0, 0x1456, 0x07E1, 0x0831, + 0x07EB, 0x07E6, 0x07DC, 0x0186, 0x07FF, 0x0813, 0x0183, 0x0FE6, 0x145C, 0x080E, + 0x100A, 0x1002, 0x0FFA, 0x100E, 0x0189, 0x082C, 0x018C, 0x0836, 0x1462, 0x07F5, + 0x1468, 0x07F0, 0x018F, 0x0809, 0x143E, 0x0192, 0x0198, 0x0195, 0x019B, 0x0827, + 0x1444, 0x019E, 0x144A, 0x01A1, 0x1450, 0x1426, 0x142C, 0x1432, 0x1438, 0x140E, + 0x1414, 0x141A, 0x1420, 0x11AA, 0x11A2, 0x11A6, 0x01B9, 0x01B6, 0x01BC, 0x119A, + 0x01BF, 0x119E, 0x01C2, 0x11AE, 0x01C5, 0x11B2, 0x01C8, 0x117A, 0x1186, 0x038C, + 0x01CE, 0x01CB, 0x01D1, 0x117E, 0x01D4, 0x0389, 0x037D, 0x1369, 0x01DA, 0x01D7, + 0x01DD, 0x0380, 0x0383, 0x0386, 0x01E0, 0x0344, 0x01E3, 0x0347, 0x01E6, 0x0338, + 0x01E9, 0x033E, 0x0329, 0x0332, 0x031D, 0x0323, 0x0326, 0x035F, 0x0362, 0x0818, + 0x0822, 0x0804, 0x07FA, 0x0E44, 0x0E48, 0x0E4C, 0x01EC, 0x0E50, 0x0204, 0x0E34, + 0x0207, 0x0E38, 0x020A, 0x0E3C, 0x020D, 0x0E40, 0x0E24, 0x0E28, 0x0E2C, 0x0E30, + 0x031A, 0x073C, 0x0741, 0x0746, 0x074B, 0x07C8, 0x07CD, 0x07D2, 0x07D7, 0x07B4, + 0x07B9, 0x07BE, 0x07C3, 0x07AA, 0x07AF, 0x0E04, 0x022B, 0x0E08, 0x022E, 0x0E0C, + 0x0E10, 0x0DF4, 0x0DF8, 0x0DFC, 0x090F, 0x0913, 0x0E00, 0x0DE8, 0x0DEC, 0x0DF0, + 0x0017, 0x0019, 0x001B, 0x001D, 0x000F, 0x0011, 0x0013, 0x0015, 0x0296, 0x0007, + 0x0009, 0x0245, 0x11B6, 0x000B, 0x0248, 0x024B, 0x000D, 0x0001, 0x024E, 0x028E, + 0x0251, 0x0003, 0x0258, 0x0005, 0x0260, 0x025C, 0x002F, 0x0263, 0x0269, 0x0266, + 0x0031, 0x0033, 0x0027, 0x0029, 0x002B, 0x002D, 0x11DE, 0x11E6, 0x0279, 0x11CA, + 0x027D, 0x11CE, 0x11D2, 0x0840, 0x11D6, 0x0886, 0x028B, 0x0854, 0x0292, 0x085E, + 0x11E2, 0x11EA, 0x029A, 0x11BA, 0x11EE, 0x11F6, 0x11DA, 0x11F2, 0x02A4, 0x0280, + 0x1036, 0x0276, 0x029D, 0x11BE, 0x11C2, 0x1032, 0x02A7, 0x11C6, 0x08FF, 0x0905, + 0x08F3, 0x02AB, 0x02AE, 0x02B1, 0x12BE, 0x123A, 0x12C6, 0x1242, 0x023A, 0x124A, + 0x02BE, 0x1252, 0x12BA, 0x125A, 0x12DE, 0x1262, 0x01FE, 0x0201, 0x107A, 0x02C4, + 0x107E, 0x02C7, 0x0216, 0x0219, 0x08F6, 0x08F9, 0x08FC, 0x0F8E, 0x0F56, 0x02CB, + 0x0F5A, 0x02B5, 0x122A, 0x122E, 0x1232, 0x1236, 0x127E, 0x123E, 0x108A, 0x1246, + 0x103E, 0x124E, 0x087C, 0x1256, 0x084A, 0x125E, 0x021C, 0x1266, 0x0F4E, 0x0868, + 0x1046, 0x0872, 0x08B8, 0x103A, 0x089A, 0x08C2, 0x0890, 0x089F, 0x08BD, 0x0234, + 0x0F52, 0x093F, 0x0F46, 0x0231, 0x08CC, 0x0F3E, 0x08D6, 0x092F, 0x08A4, 0x1042, + 0x0933, 0x105E, 0x0863, 0x0877, 0x1082, 0x086D, 0x0F42, 0x104A, 0x1076, 0x0F76, + 0x093B, 0x104E, 0x0943, 0x1072, 0x08B3, 0x0937, 0x1086, 0x08AE, 0x08C7, 0x0F7A, + 0x08D1, 0x0F72, 0x1056, 0x0F6A, 0x105A, 0x0F5E, 0x106A, 0x1062, 0x1052, 0x1066, + 0x0F62, 0x0F16, 0x0F1A, 0x106E, 0x0F0E, 0x0F12, 0x0F06, 0x0F0A, 0x109A, 0x0947, + 0x0983, 0x1096, 0x109E, 0x0EFE, 0x10A2, 0x0F02, 0x10A6, 0x0F36, 0x10AA, 0x0F3A, + 0x0F2E, 0x094B, 0x097F, 0x0237, 0x0997, 0x0F32, 0x099B, 0x0F26, 0x099F, 0x0F2A, + 0x09A3, 0x0F1E, 0x09A7, 0x0F22, 0x09AB, 0x005C, 0x09AF, 0x0062, 0x09B3, 0x0050, + 0x0056, 0x0044, 0x004A, 0x0038, 0x09BF, 0x003E, 0x09C3, 0x0089, 0x09C7, 0x008F, + 0x09CB, 0x007D, 0x09CF, 0x0083, 0x09D3, 0x0074, 0x007A, 0x0EEA, 0x0068, 0x006E, + 0x09DF, 0x1362, 0x09E3, 0x12AA, 0x09E7, 0x09EB, 0x0987, 0x12AE, 0x09EF, 0x12B2, + 0x09F3, 0x12B6, 0x09F7, 0x09FB, 0x10BA, 0x129A, 0x129E, 0x12A2, 0x12A6, 0x128A, + 0x097B, 0x128E, 0x1292, 0x1296, 0x127A, 0x1282, 0x0977, 0x1286, 0x0B51, 0x12EA, + 0x0B65, 0x10B2, 0x12EE, 0x02CF, 0x0B59, 0x12F2, 0x12F6, 0x0A2B, 0x12DA, 0x0B29, + 0x0A2F, 0x0A33, 0x10AE, 0x0B2D, 0x0A37, 0x12E2, 0x0A81, 0x12E6, 0x0AE9, 0x12CA, + 0x1384, 0x1380, 0x12CE, 0x1388, 0x0AED, 0x1390, 0x12D2, 0x12D6, 0x12C2, 0x121A, + 0x0AF1, 0x121E, 0x0B8D, 0x10B6, 0x0AF9, 0x0AF5, 0x0AFD, 0x1222, 0x10BE, 0x1226, + 0x10C2, 0x120A, 0x0B09, 0x10FE, 0x0B0D, 0x1102, 0x0B11, 0x113E, 0x0B15, 0x1112, + 0x120E, 0x02D5, 0x1212, 0x1216, 0x0B21, 0x0B01, 0x11FA, 0x0B61, 0x0B19, 0x02DE, + 0x11FE, 0x0B89, 0x1202, 0x0B5D, 0x0B71, 0x02E1, 0x0B39, 0x0B79, 0x0B3D, 0x0B7D, + 0x0B41, 0x1136, 0x0B45, 0x0B85, 0x0B81, 0x1206, 0x10C6, 0x1156, 0x1146, 0x10CE, + 0x0B55, 0x0DD0, 0x10DA, 0x136D, 0x0BA9, 0x115A, 0x0BAD, 0x1162, 0x10DE, 0x10D6, + 0x08EF, 0x0359, 0x08EB, 0x10EA, 0x08DF, 0x08DB, 0x08E7, 0x08E3, 0x036B, 0x1166, + 0x10F2, 0x10FA, 0x036E, 0x10E6, 0x1142, 0x0B75, 0x02E4, 0x1106, 0x110E, 0x110A, + 0x02E7, 0x0314, 0x02ED, 0x02EA, 0x02F0, 0x1374, 0x02F6, 0x02F3, 0x02FC, 0x02F9, + 0x0302, 0x02FF, 0x0308, 0x0305, 0x030E, 0x030B, 0x113A, 0x0311, 0x0BC9, 0x0317, + 0x112E, 0x034D, 0x1132, 0x034A, 0x1126, 0x0350, 0x0377, 0x112A, 0x037A, 0x0371, + 0x114A, 0x035C, 0x111E, 0x0A4A, 0x0A54, 0x0368, 0x0320, 0x0BD5, 0x0A40, 0x0BDD, + 0x0365, 0x114E, 0x1152, 0x0353, 0x032F, 0x032C, 0x0BE5, 0x0356, 0x05C5, 0x05CF, + 0x0AA3, 0x1122, 0x05D9, 0x0335, 0x05E3, 0x0341, 0x061A, 0x05E8, 0x115E, 0x05F2, + 0x0610, 0x05FC, 0x033B, 0x0606, 0x0AE4, 0x0C1D, 0x0C25, 0x0ADA, 0x061F, 0x0633, + 0x0C15, 0x0629, 0x0374, 0x0638, 0x0647, 0x038F, 0x0BD1, 0x0BE1, 0x0651, 0x0BD9, + 0x0BFD, 0x0BBD, 0x0C05, 0x0BED, 0x0660, 0x0BB5, 0x0674, 0x0BB9, 0x116E, 0x0AC6, + 0x0C3D, 0x1182, 0x1176, 0x116A, 0x0A72, 0x0BB1, 0x0C45, 0x0A3B, 0x0AD0, 0x0C41, + 0x0C49, 0x0A4F, 0x0C4D, 0x0A5E, 0x118A, 0x0AAD, 0x1172, 0x0A7C, 0x0D80, 0x03AA, + 0x0D88, 0x0A68, 0x0D90, 0x0A94, 0x0D98, 0x118E, 0x0DA0, 0x0A8A, 0x0DA8, 0x0A8F, + 0x0DB0, 0x03B0, 0x0DB8, 0x03B3, 0x0DC0, 0x0ABC, 0x0DC8, 0x0A85, 0x0C0D, 0x0C11, + 0x0BF5, 0x0AA8, 0x0395, 0x0C21, 0x039B, 0x039E, 0x03A1, 0x0A99, 0x03A7, 0x03A4, + 0x03AD, 0x0392, 0x0398, 0x0A9E, 0x130A, 0x03B6, 0x1332, 0x0DD8, 0x1192, 0x03C2, + 0x131A, 0x03C8, 0x1196, 0x03CE, 0x03D7, 0x03D4, 0x03DD, 0x13E4, 0x06A1, 0x06AB, + 0x03E9, 0x068D, 0x03EF, 0x0688, 0x03F5, 0x03F2, 0x03FB, 0x0A45, 0x126A, 0x126E, + 0x1272, 0x132A, 0x040D, 0x1276, 0x0F92, 0x0410, 0x0419, 0x0416, 0x041F, 0x1474, + 0x0422, 0x146E, 0x0425, 0x0C51, 0x0428, 0x0F9A, 0x042B, 0x0723, 0x12FA, 0x0431, + 0x1302, 0x042E, 0x0434, 0x0437, 0x1312, 0x0BCD, 0x043A, 0x14E3, 0x043D, 0x0C19, + 0x0440, 0x0BC1, 0x0443, 0x1356, 0x0446, 0x1352, 0x0449, 0x0BC5, 0x134A, 0x14EF, + 0x044F, 0x044C, 0x135A, 0x14FA, 0x1504, 0x14F5, 0x0D24, 0x1322, 0x0C2D, 0x0C35, + 0x1538, 0x0697, 0x153D, 0x1342, 0x0458, 0x12FE, 0x045B, 0x133A, 0x0C5D, 0x0ADF, + 0x1306, 0x151E, 0x06B5, 0x0AD5, 0x06BF, 0x150B, 0x06C9, 0x06EC, 0x06D3, 0x06FB, + 0x06DD, 0x06F1, 0x06E7, 0x06E2, 0x0D2C, 0x06D8, 0x1542, 0x06F6, 0x0D28, 0x0476, + 0x0C6D, 0x1531, 0x0C75, 0x0C7D, 0x152A, 0x0479, 0x072D, 0x154F, 0x0737, 0x155E, + 0x048E, 0x1399, 0x0491, 0x0692, 0x0494, 0x1394, 0x0497, 0x0C85, 0x049A, 0x1565, + 0x049D, 0x0C8D, 0x04A0, 0x1006, 0x04A3, 0x0FF2, 0x04B5, 0x0FF6, 0x0FFE, 0x0FE2, + 0x04B8, 0x04A9, 0x0FEA, 0x04AC, 0x04BB, 0x04AF, 0x0FD2, 0x04B2, 0x0FDA, 0x0103, + 0x0106, 0x0455, 0x00FD, 0x1365, 0x0100, 0x00F7, 0x00FA, 0x00F1, 0x00F4, 0x011B, + 0x011E, 0x0115, 0x045E, 0x0461, 0x0118, 0x010F, 0x0112, 0x0109, 0x04D6, 0x010C, + 0x04D9, 0x00D7, 0x00DA, 0x00D1, 0x00D4, 0x00CB, 0x00CE, 0x00C5, 0x00C8, 0x00EB, + 0x00EE, 0x00E8, 0x00E2, 0x00E5, 0x00DD, 0x04F1, 0x00DF, 0x04EE, 0x00A7, 0x00AA, + 0x00A1, 0x00A4, 0x04E2, 0x009B, 0x009E, 0x0095, 0x0500, 0x0503, 0x04E8, 0x0098, + 0x0506, 0x00BF, 0x0509, 0x00C2, 0x050C, 0x03E6, 0x050F, 0x03EC, 0x0512, 0x03DA, + 0x0515, 0x03E0, 0x0518, 0x051B, 0x03E3, 0x03D1, 0x051E, 0x03C5, 0x0521, 0x03CB, + 0x0524, 0x041C, 0x0527, 0x040A, 0x052A, 0x0413, 0x052D, 0x03FE, 0x0530, 0x0401, + 0x0533, 0x0404, 0x0536, 0x0407, 0x0539, 0x03F8, 0x053C, 0x053F, 0x01B0, 0x01B3, + 0x0542, 0x01AA, 0x0545, 0x01AD, 0x01A4, 0x0572, 0x01A7, 0x056F, 0x017A, 0x03B9, + 0x03BC, 0x03BF, 0x0D38, 0x0D40, 0x0D44, 0x0180, 0x017D, 0x0679, 0x067E, 0x0683, + 0x0665, 0x066A, 0x066F, 0x054B, 0x064C, 0x0656, 0x065B, 0x063D, 0x0642, 0x016B, + 0x0168, 0x04EB, 0x04E5, 0x04DC, 0x015F, 0x0575, 0x04DF, 0x05D4, 0x05DE, 0x05C0, + 0x05CA, 0x04FA, 0x04FD, 0x04F4, 0x04F7, 0x0624, 0x062E, 0x0615, 0x0601, 0x060B, + 0x05ED, 0x05F7, 0x04A6, 0x04D0, 0x04D3, 0x04CA, 0x04CD, 0x0578, 0x04C4, 0x04C7, + 0x04BE, 0x04C1, 0x0488, 0x048B, 0x0482, 0x0485, 0x047C, 0x047F, 0x06C4, 0x06CE, + 0x06B0, 0x06BA, 0x1586, 0x1590, 0x0728, 0x0732, }; + +const uint8_t NU_TOUPPER_COMBINED[] = { + 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, + 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, + 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, + 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, + 0x00, 0x59, 0x00, 0x5A, 0x00, 0xCE, 0x9C, 0x00, 0xC3, 0x80, 0x00, 0xC3, + 0x81, 0x00, 0xC3, 0x82, 0x00, 0xC3, 0x83, 0x00, 0xC3, 0x84, 0x00, 0xC3, + 0x85, 0x00, 0xC3, 0x86, 0x00, 0xC3, 0x87, 0x00, 0xC3, 0x88, 0x00, 0xC3, + 0x89, 0x00, 0xC3, 0x8A, 0x00, 0xC3, 0x8B, 0x00, 0xC3, 0x8C, 0x00, 0xC3, + 0x8D, 0x00, 0xC3, 0x8E, 0x00, 0xC3, 0x8F, 0x00, 0xC3, 0x90, 0x00, 0xC3, + 0x91, 0x00, 0xC3, 0x92, 0x00, 0xC3, 0x93, 0x00, 0xC3, 0x94, 0x00, 0xC3, + 0x95, 0x00, 0xC3, 0x96, 0x00, 0xC3, 0x98, 0x00, 0xC3, 0x99, 0x00, 0xC3, + 0x9A, 0x00, 0xC3, 0x9B, 0x00, 0xC3, 0x9C, 0x00, 0xC3, 0x9D, 0x00, 0xC3, + 0x9E, 0x00, 0xC5, 0xB8, 0x00, 0xC4, 0x80, 0x00, 0xC4, 0x82, 0x00, 0xC4, + 0x84, 0x00, 0xC4, 0x86, 0x00, 0xC4, 0x88, 0x00, 0xC4, 0x8A, 0x00, 0xC4, + 0x8C, 0x00, 0xC4, 0x8E, 0x00, 0xC4, 0x90, 0x00, 0xC4, 0x92, 0x00, 0xC4, + 0x94, 0x00, 0xC4, 0x96, 0x00, 0xC4, 0x98, 0x00, 0xC4, 0x9A, 0x00, 0xC4, + 0x9C, 0x00, 0xC4, 0x9E, 0x00, 0xC4, 0xA0, 0x00, 0xC4, 0xA2, 0x00, 0xC4, + 0xA4, 0x00, 0xC4, 0xA6, 0x00, 0xC4, 0xA8, 0x00, 0xC4, 0xAA, 0x00, 0xC4, + 0xAC, 0x00, 0xC4, 0xAE, 0x00, 0x49, 0x00, 0xC4, 0xB2, 0x00, 0xC4, 0xB4, + 0x00, 0xC4, 0xB6, 0x00, 0xC4, 0xB9, 0x00, 0xC4, 0xBB, 0x00, 0xC4, 0xBD, + 0x00, 0xC4, 0xBF, 0x00, 0xC5, 0x81, 0x00, 0xC5, 0x83, 0x00, 0xC5, 0x85, + 0x00, 0xC5, 0x87, 0x00, 0xC5, 0x8A, 0x00, 0xC5, 0x8C, 0x00, 0xC5, 0x8E, + 0x00, 0xC5, 0x90, 0x00, 0xC5, 0x92, 0x00, 0xC5, 0x94, 0x00, 0xC5, 0x96, + 0x00, 0xC5, 0x98, 0x00, 0xC5, 0x9A, 0x00, 0xC5, 0x9C, 0x00, 0xC5, 0x9E, + 0x00, 0xC5, 0xA0, 0x00, 0xC5, 0xA2, 0x00, 0xC5, 0xA4, 0x00, 0xC5, 0xA6, + 0x00, 0xC5, 0xA8, 0x00, 0xC5, 0xAA, 0x00, 0xC5, 0xAC, 0x00, 0xC5, 0xAE, + 0x00, 0xC5, 0xB0, 0x00, 0xC5, 0xB2, 0x00, 0xC5, 0xB4, 0x00, 0xC5, 0xB6, + 0x00, 0xC5, 0xB9, 0x00, 0xC5, 0xBB, 0x00, 0xC5, 0xBD, 0x00, 0x53, 0x00, + 0xC9, 0x83, 0x00, 0xC6, 0x82, 0x00, 0xC6, 0x84, 0x00, 0xC6, 0x87, 0x00, + 0xC6, 0x8B, 0x00, 0xC6, 0x91, 0x00, 0xC7, 0xB6, 0x00, 0xC6, 0x98, 0x00, + 0xC8, 0xBD, 0x00, 0xC8, 0xA0, 0x00, 0xC6, 0xA0, 0x00, 0xC6, 0xA2, 0x00, + 0xC6, 0xA4, 0x00, 0xC6, 0xA7, 0x00, 0xC6, 0xAC, 0x00, 0xC6, 0xAF, 0x00, + 0xC6, 0xB3, 0x00, 0xC6, 0xB5, 0x00, 0xC6, 0xB8, 0x00, 0xC6, 0xBC, 0x00, + 0xC7, 0xB7, 0x00, 0xC7, 0x84, 0x00, 0xC7, 0x84, 0x00, 0xC7, 0x87, 0x00, + 0xC7, 0x87, 0x00, 0xC7, 0x8A, 0x00, 0xC7, 0x8A, 0x00, 0xC7, 0x8D, 0x00, + 0xC7, 0x8F, 0x00, 0xC7, 0x91, 0x00, 0xC7, 0x93, 0x00, 0xC7, 0x95, 0x00, + 0xC7, 0x97, 0x00, 0xC7, 0x99, 0x00, 0xC7, 0x9B, 0x00, 0xC6, 0x8E, 0x00, + 0xC7, 0x9E, 0x00, 0xC7, 0xA0, 0x00, 0xC7, 0xA2, 0x00, 0xC7, 0xA4, 0x00, + 0xC7, 0xA6, 0x00, 0xC7, 0xA8, 0x00, 0xC7, 0xAA, 0x00, 0xC7, 0xAC, 0x00, + 0xC7, 0xAE, 0x00, 0xC7, 0xB1, 0x00, 0xC7, 0xB1, 0x00, 0xC7, 0xB4, 0x00, + 0xC7, 0xB8, 0x00, 0xC7, 0xBA, 0x00, 0xC7, 0xBC, 0x00, 0xC7, 0xBE, 0x00, + 0xC8, 0x80, 0x00, 0xC8, 0x82, 0x00, 0xC8, 0x84, 0x00, 0xC8, 0x86, 0x00, + 0xC8, 0x88, 0x00, 0xC8, 0x8A, 0x00, 0xC8, 0x8C, 0x00, 0xC8, 0x8E, 0x00, + 0xC8, 0x90, 0x00, 0xC8, 0x92, 0x00, 0xC8, 0x94, 0x00, 0xC8, 0x96, 0x00, + 0xC8, 0x98, 0x00, 0xC8, 0x9A, 0x00, 0xC8, 0x9C, 0x00, 0xC8, 0x9E, 0x00, + 0xC8, 0xA2, 0x00, 0xC8, 0xA4, 0x00, 0xC8, 0xA6, 0x00, 0xC8, 0xA8, 0x00, + 0xC8, 0xAA, 0x00, 0xC8, 0xAC, 0x00, 0xC8, 0xAE, 0x00, 0xC8, 0xB0, 0x00, + 0xC8, 0xB2, 0x00, 0xC8, 0xBB, 0x00, 0xE2, 0xB1, 0xBE, 0x00, 0xE2, 0xB1, + 0xBF, 0x00, 0xC9, 0x81, 0x00, 0xC9, 0x86, 0x00, 0xC9, 0x88, 0x00, 0xC9, + 0x8A, 0x00, 0xC9, 0x8C, 0x00, 0xC9, 0x8E, 0x00, 0xE2, 0xB1, 0xAF, 0x00, + 0xE2, 0xB1, 0xAD, 0x00, 0xE2, 0xB1, 0xB0, 0x00, 0xC6, 0x81, 0x00, 0xC6, + 0x86, 0x00, 0xC6, 0x89, 0x00, 0xC6, 0x8A, 0x00, 0xC6, 0x8F, 0x00, 0xC6, + 0x90, 0x00, 0xEA, 0x9E, 0xAB, 0x00, 0xC6, 0x93, 0x00, 0xEA, 0x9E, 0xAC, + 0x00, 0xC6, 0x94, 0x00, 0xEA, 0x9E, 0x8D, 0x00, 0xEA, 0x9E, 0xAA, 0x00, + 0xC6, 0x97, 0x00, 0xC6, 0x96, 0x00, 0xEA, 0x9E, 0xAE, 0x00, 0xE2, 0xB1, + 0xA2, 0x00, 0xEA, 0x9E, 0xAD, 0x00, 0xC6, 0x9C, 0x00, 0xE2, 0xB1, 0xAE, + 0x00, 0xC6, 0x9D, 0x00, 0xC6, 0x9F, 0x00, 0xE2, 0xB1, 0xA4, 0x00, 0xC6, + 0xA6, 0x00, 0xC6, 0xA9, 0x00, 0xEA, 0x9E, 0xB1, 0x00, 0xC6, 0xAE, 0x00, + 0xC9, 0x84, 0x00, 0xC6, 0xB1, 0x00, 0xC6, 0xB2, 0x00, 0xC9, 0x85, 0x00, + 0xC6, 0xB7, 0x00, 0xEA, 0x9E, 0xB2, 0x00, 0xEA, 0x9E, 0xB0, 0x00, 0xCE, + 0x99, 0x00, 0xCD, 0xB0, 0x00, 0xCD, 0xB2, 0x00, 0xCD, 0xB6, 0x00, 0xCF, + 0xBD, 0x00, 0xCF, 0xBE, 0x00, 0xCF, 0xBF, 0x00, 0xCE, 0x86, 0x00, 0xCE, + 0x88, 0x00, 0xCE, 0x89, 0x00, 0xCE, 0x8A, 0x00, 0xCE, 0x91, 0x00, 0xCE, + 0x92, 0x00, 0xCE, 0x93, 0x00, 0xCE, 0x94, 0x00, 0xCE, 0x95, 0x00, 0xCE, + 0x96, 0x00, 0xCE, 0x97, 0x00, 0xCE, 0x98, 0x00, 0xCE, 0x99, 0x00, 0xCE, + 0x9A, 0x00, 0xCE, 0x9B, 0x00, 0xCE, 0x9C, 0x00, 0xCE, 0x9D, 0x00, 0xCE, + 0x9E, 0x00, 0xCE, 0x9F, 0x00, 0xCE, 0xA0, 0x00, 0xCE, 0xA1, 0x00, 0xCE, + 0xA3, 0x00, 0xCE, 0xA3, 0x00, 0xCE, 0xA4, 0x00, 0xCE, 0xA5, 0x00, 0xCE, + 0xA6, 0x00, 0xCE, 0xA7, 0x00, 0xCE, 0xA8, 0x00, 0xCE, 0xA9, 0x00, 0xCE, + 0xAA, 0x00, 0xCE, 0xAB, 0x00, 0xCE, 0x8C, 0x00, 0xCE, 0x8E, 0x00, 0xCE, + 0x8F, 0x00, 0xCE, 0x92, 0x00, 0xCE, 0x98, 0x00, 0xCE, 0xA6, 0x00, 0xCE, + 0xA0, 0x00, 0xCF, 0x8F, 0x00, 0xCF, 0x98, 0x00, 0xCF, 0x9A, 0x00, 0xCF, + 0x9C, 0x00, 0xCF, 0x9E, 0x00, 0xCF, 0xA0, 0x00, 0xCF, 0xA2, 0x00, 0xCF, + 0xA4, 0x00, 0xCF, 0xA6, 0x00, 0xCF, 0xA8, 0x00, 0xCF, 0xAA, 0x00, 0xCF, + 0xAC, 0x00, 0xCF, 0xAE, 0x00, 0xCE, 0x9A, 0x00, 0xCE, 0xA1, 0x00, 0xCF, + 0xB9, 0x00, 0xCD, 0xBF, 0x00, 0xCE, 0x95, 0x00, 0xCF, 0xB7, 0x00, 0xCF, + 0xBA, 0x00, 0xD0, 0x90, 0x00, 0xD0, 0x91, 0x00, 0xD0, 0x92, 0x00, 0xD0, + 0x93, 0x00, 0xD0, 0x94, 0x00, 0xD0, 0x95, 0x00, 0xD0, 0x96, 0x00, 0xD0, + 0x97, 0x00, 0xD0, 0x98, 0x00, 0xD0, 0x99, 0x00, 0xD0, 0x9A, 0x00, 0xD0, + 0x9B, 0x00, 0xD0, 0x9C, 0x00, 0xD0, 0x9D, 0x00, 0xD0, 0x9E, 0x00, 0xD0, + 0x9F, 0x00, 0xD0, 0xA0, 0x00, 0xD0, 0xA1, 0x00, 0xD0, 0xA2, 0x00, 0xD0, + 0xA3, 0x00, 0xD0, 0xA4, 0x00, 0xD0, 0xA5, 0x00, 0xD0, 0xA6, 0x00, 0xD0, + 0xA7, 0x00, 0xD0, 0xA8, 0x00, 0xD0, 0xA9, 0x00, 0xD0, 0xAA, 0x00, 0xD0, + 0xAB, 0x00, 0xD0, 0xAC, 0x00, 0xD0, 0xAD, 0x00, 0xD0, 0xAE, 0x00, 0xD0, + 0xAF, 0x00, 0xD0, 0x80, 0x00, 0xD0, 0x81, 0x00, 0xD0, 0x82, 0x00, 0xD0, + 0x83, 0x00, 0xD0, 0x84, 0x00, 0xD0, 0x85, 0x00, 0xD0, 0x86, 0x00, 0xD0, + 0x87, 0x00, 0xD0, 0x88, 0x00, 0xD0, 0x89, 0x00, 0xD0, 0x8A, 0x00, 0xD0, + 0x8B, 0x00, 0xD0, 0x8C, 0x00, 0xD0, 0x8D, 0x00, 0xD0, 0x8E, 0x00, 0xD0, + 0x8F, 0x00, 0xD1, 0xA0, 0x00, 0xD1, 0xA2, 0x00, 0xD1, 0xA4, 0x00, 0xD1, + 0xA6, 0x00, 0xD1, 0xA8, 0x00, 0xD1, 0xAA, 0x00, 0xD1, 0xAC, 0x00, 0xD1, + 0xAE, 0x00, 0xD1, 0xB0, 0x00, 0xD1, 0xB2, 0x00, 0xD1, 0xB4, 0x00, 0xD1, + 0xB6, 0x00, 0xD1, 0xB8, 0x00, 0xD1, 0xBA, 0x00, 0xD1, 0xBC, 0x00, 0xD1, + 0xBE, 0x00, 0xD2, 0x80, 0x00, 0xD2, 0x8A, 0x00, 0xD2, 0x8C, 0x00, 0xD2, + 0x8E, 0x00, 0xD2, 0x90, 0x00, 0xD2, 0x92, 0x00, 0xD2, 0x94, 0x00, 0xD2, + 0x96, 0x00, 0xD2, 0x98, 0x00, 0xD2, 0x9A, 0x00, 0xD2, 0x9C, 0x00, 0xD2, + 0x9E, 0x00, 0xD2, 0xA0, 0x00, 0xD2, 0xA2, 0x00, 0xD2, 0xA4, 0x00, 0xD2, + 0xA6, 0x00, 0xD2, 0xA8, 0x00, 0xD2, 0xAA, 0x00, 0xD2, 0xAC, 0x00, 0xD2, + 0xAE, 0x00, 0xD2, 0xB0, 0x00, 0xD2, 0xB2, 0x00, 0xD2, 0xB4, 0x00, 0xD2, + 0xB6, 0x00, 0xD2, 0xB8, 0x00, 0xD2, 0xBA, 0x00, 0xD2, 0xBC, 0x00, 0xD2, + 0xBE, 0x00, 0xD3, 0x81, 0x00, 0xD3, 0x83, 0x00, 0xD3, 0x85, 0x00, 0xD3, + 0x87, 0x00, 0xD3, 0x89, 0x00, 0xD3, 0x8B, 0x00, 0xD3, 0x8D, 0x00, 0xD3, + 0x80, 0x00, 0xD3, 0x90, 0x00, 0xD3, 0x92, 0x00, 0xD3, 0x94, 0x00, 0xD3, + 0x96, 0x00, 0xD3, 0x98, 0x00, 0xD3, 0x9A, 0x00, 0xD3, 0x9C, 0x00, 0xD3, + 0x9E, 0x00, 0xD3, 0xA0, 0x00, 0xD3, 0xA2, 0x00, 0xD3, 0xA4, 0x00, 0xD3, + 0xA6, 0x00, 0xD3, 0xA8, 0x00, 0xD3, 0xAA, 0x00, 0xD3, 0xAC, 0x00, 0xD3, + 0xAE, 0x00, 0xD3, 0xB0, 0x00, 0xD3, 0xB2, 0x00, 0xD3, 0xB4, 0x00, 0xD3, + 0xB6, 0x00, 0xD3, 0xB8, 0x00, 0xD3, 0xBA, 0x00, 0xD3, 0xBC, 0x00, 0xD3, + 0xBE, 0x00, 0xD4, 0x80, 0x00, 0xD4, 0x82, 0x00, 0xD4, 0x84, 0x00, 0xD4, + 0x86, 0x00, 0xD4, 0x88, 0x00, 0xD4, 0x8A, 0x00, 0xD4, 0x8C, 0x00, 0xD4, + 0x8E, 0x00, 0xD4, 0x90, 0x00, 0xD4, 0x92, 0x00, 0xD4, 0x94, 0x00, 0xD4, + 0x96, 0x00, 0xD4, 0x98, 0x00, 0xD4, 0x9A, 0x00, 0xD4, 0x9C, 0x00, 0xD4, + 0x9E, 0x00, 0xD4, 0xA0, 0x00, 0xD4, 0xA2, 0x00, 0xD4, 0xA4, 0x00, 0xD4, + 0xA6, 0x00, 0xD4, 0xA8, 0x00, 0xD4, 0xAA, 0x00, 0xD4, 0xAC, 0x00, 0xD4, + 0xAE, 0x00, 0xD4, 0xB1, 0x00, 0xD4, 0xB2, 0x00, 0xD4, 0xB3, 0x00, 0xD4, + 0xB4, 0x00, 0xD4, 0xB5, 0x00, 0xD4, 0xB6, 0x00, 0xD4, 0xB7, 0x00, 0xD4, + 0xB8, 0x00, 0xD4, 0xB9, 0x00, 0xD4, 0xBA, 0x00, 0xD4, 0xBB, 0x00, 0xD4, + 0xBC, 0x00, 0xD4, 0xBD, 0x00, 0xD4, 0xBE, 0x00, 0xD4, 0xBF, 0x00, 0xD5, + 0x80, 0x00, 0xD5, 0x81, 0x00, 0xD5, 0x82, 0x00, 0xD5, 0x83, 0x00, 0xD5, + 0x84, 0x00, 0xD5, 0x85, 0x00, 0xD5, 0x86, 0x00, 0xD5, 0x87, 0x00, 0xD5, + 0x88, 0x00, 0xD5, 0x89, 0x00, 0xD5, 0x8A, 0x00, 0xD5, 0x8B, 0x00, 0xD5, + 0x8C, 0x00, 0xD5, 0x8D, 0x00, 0xD5, 0x8E, 0x00, 0xD5, 0x8F, 0x00, 0xD5, + 0x90, 0x00, 0xD5, 0x91, 0x00, 0xD5, 0x92, 0x00, 0xD5, 0x93, 0x00, 0xD5, + 0x94, 0x00, 0xD5, 0x95, 0x00, 0xD5, 0x96, 0x00, 0xF0, 0x90, 0x90, 0x80, + 0x00, 0xF0, 0x90, 0x90, 0x81, 0x00, 0xF0, 0x90, 0x90, 0x82, 0x00, 0xF0, + 0x90, 0x90, 0x83, 0x00, 0xF0, 0x90, 0x90, 0x84, 0x00, 0xF0, 0x90, 0x90, + 0x85, 0x00, 0xF0, 0x90, 0x90, 0x86, 0x00, 0xF0, 0x90, 0x90, 0x87, 0x00, + 0xF0, 0x90, 0x90, 0x88, 0x00, 0xF0, 0x90, 0x90, 0x89, 0x00, 0xF0, 0x90, + 0x90, 0x8A, 0x00, 0xF0, 0x90, 0x90, 0x8B, 0x00, 0xF0, 0x90, 0x90, 0x8C, + 0x00, 0xF0, 0x90, 0x90, 0x8D, 0x00, 0xF0, 0x90, 0x90, 0x8E, 0x00, 0xF0, + 0x90, 0x90, 0x8F, 0x00, 0xF0, 0x90, 0x90, 0x90, 0x00, 0xF0, 0x90, 0x90, + 0x91, 0x00, 0xF0, 0x90, 0x90, 0x92, 0x00, 0xF0, 0x90, 0x90, 0x93, 0x00, + 0xF0, 0x90, 0x90, 0x94, 0x00, 0xF0, 0x90, 0x90, 0x95, 0x00, 0xF0, 0x90, + 0x90, 0x96, 0x00, 0xF0, 0x90, 0x90, 0x97, 0x00, 0xF0, 0x90, 0x90, 0x98, + 0x00, 0xF0, 0x90, 0x90, 0x99, 0x00, 0xF0, 0x90, 0x90, 0x9A, 0x00, 0xF0, + 0x90, 0x90, 0x9B, 0x00, 0xF0, 0x90, 0x90, 0x9C, 0x00, 0xF0, 0x90, 0x90, + 0x9D, 0x00, 0xF0, 0x90, 0x90, 0x9E, 0x00, 0xF0, 0x90, 0x90, 0x9F, 0x00, + 0xF0, 0x90, 0x90, 0xA0, 0x00, 0xF0, 0x90, 0x90, 0xA1, 0x00, 0xF0, 0x90, + 0x90, 0xA2, 0x00, 0xF0, 0x90, 0x90, 0xA3, 0x00, 0xF0, 0x90, 0x90, 0xA4, + 0x00, 0xF0, 0x90, 0x90, 0xA5, 0x00, 0xF0, 0x90, 0x90, 0xA6, 0x00, 0xF0, + 0x90, 0x90, 0xA7, 0x00, 0xF0, 0x90, 0x92, 0xB0, 0x00, 0xF0, 0x90, 0x92, + 0xB1, 0x00, 0xF0, 0x90, 0x92, 0xB2, 0x00, 0xF0, 0x90, 0x92, 0xB3, 0x00, + 0xF0, 0x90, 0x92, 0xB4, 0x00, 0xF0, 0x90, 0x92, 0xB5, 0x00, 0xF0, 0x90, + 0x92, 0xB6, 0x00, 0xF0, 0x90, 0x92, 0xB7, 0x00, 0xF0, 0x90, 0x92, 0xB8, + 0x00, 0xF0, 0x90, 0x92, 0xB9, 0x00, 0xF0, 0x90, 0x92, 0xBA, 0x00, 0xF0, + 0x90, 0x92, 0xBB, 0x00, 0xF0, 0x90, 0x92, 0xBC, 0x00, 0xF0, 0x90, 0x92, + 0xBD, 0x00, 0xF0, 0x90, 0x92, 0xBE, 0x00, 0xF0, 0x90, 0x92, 0xBF, 0x00, + 0xF0, 0x90, 0x93, 0x80, 0x00, 0xF0, 0x90, 0x93, 0x81, 0x00, 0xF0, 0x90, + 0x93, 0x82, 0x00, 0xF0, 0x90, 0x93, 0x83, 0x00, 0xF0, 0x90, 0x93, 0x84, + 0x00, 0xF0, 0x90, 0x93, 0x85, 0x00, 0xF0, 0x90, 0x93, 0x86, 0x00, 0xF0, + 0x90, 0x93, 0x87, 0x00, 0xF0, 0x90, 0x93, 0x88, 0x00, 0xF0, 0x90, 0x93, + 0x89, 0x00, 0xF0, 0x90, 0x93, 0x8A, 0x00, 0xF0, 0x90, 0x93, 0x8B, 0x00, + 0xF0, 0x90, 0x93, 0x8C, 0x00, 0xF0, 0x90, 0x93, 0x8D, 0x00, 0xF0, 0x90, + 0x93, 0x8E, 0x00, 0xF0, 0x90, 0x93, 0x8F, 0x00, 0xF0, 0x90, 0x93, 0x90, + 0x00, 0xF0, 0x90, 0x93, 0x91, 0x00, 0xF0, 0x90, 0x93, 0x92, 0x00, 0xF0, + 0x90, 0x93, 0x93, 0x00, 0xF0, 0x90, 0xB2, 0x80, 0x00, 0xF0, 0x90, 0xB2, + 0x81, 0x00, 0xF0, 0x90, 0xB2, 0x82, 0x00, 0xF0, 0x90, 0xB2, 0x83, 0x00, + 0xF0, 0x90, 0xB2, 0x84, 0x00, 0xF0, 0x90, 0xB2, 0x85, 0x00, 0xF0, 0x90, + 0xB2, 0x86, 0x00, 0xF0, 0x90, 0xB2, 0x87, 0x00, 0xF0, 0x90, 0xB2, 0x88, + 0x00, 0xF0, 0x90, 0xB2, 0x89, 0x00, 0xF0, 0x90, 0xB2, 0x8A, 0x00, 0xF0, + 0x90, 0xB2, 0x8B, 0x00, 0xF0, 0x90, 0xB2, 0x8C, 0x00, 0xF0, 0x90, 0xB2, + 0x8D, 0x00, 0xF0, 0x90, 0xB2, 0x8E, 0x00, 0xF0, 0x90, 0xB2, 0x8F, 0x00, + 0xF0, 0x90, 0xB2, 0x90, 0x00, 0xF0, 0x90, 0xB2, 0x91, 0x00, 0xF0, 0x90, + 0xB2, 0x92, 0x00, 0xF0, 0x90, 0xB2, 0x93, 0x00, 0xF0, 0x90, 0xB2, 0x94, + 0x00, 0xF0, 0x90, 0xB2, 0x95, 0x00, 0xF0, 0x90, 0xB2, 0x96, 0x00, 0xF0, + 0x90, 0xB2, 0x97, 0x00, 0xF0, 0x90, 0xB2, 0x98, 0x00, 0xF0, 0x90, 0xB2, + 0x99, 0x00, 0xF0, 0x90, 0xB2, 0x9A, 0x00, 0xF0, 0x90, 0xB2, 0x9B, 0x00, + 0xF0, 0x90, 0xB2, 0x9C, 0x00, 0xF0, 0x90, 0xB2, 0x9D, 0x00, 0xF0, 0x90, + 0xB2, 0x9E, 0x00, 0xF0, 0x90, 0xB2, 0x9F, 0x00, 0xF0, 0x90, 0xB2, 0xA0, + 0x00, 0xF0, 0x90, 0xB2, 0xA1, 0x00, 0xF0, 0x90, 0xB2, 0xA2, 0x00, 0xF0, + 0x90, 0xB2, 0xA3, 0x00, 0xF0, 0x90, 0xB2, 0xA4, 0x00, 0xF0, 0x90, 0xB2, + 0xA5, 0x00, 0xF0, 0x90, 0xB2, 0xA6, 0x00, 0xF0, 0x90, 0xB2, 0xA7, 0x00, + 0xF0, 0x90, 0xB2, 0xA8, 0x00, 0xF0, 0x90, 0xB2, 0xA9, 0x00, 0xF0, 0x90, + 0xB2, 0xAA, 0x00, 0xF0, 0x90, 0xB2, 0xAB, 0x00, 0xF0, 0x90, 0xB2, 0xAC, + 0x00, 0xF0, 0x90, 0xB2, 0xAD, 0x00, 0xF0, 0x90, 0xB2, 0xAE, 0x00, 0xF0, + 0x90, 0xB2, 0xAF, 0x00, 0xF0, 0x90, 0xB2, 0xB0, 0x00, 0xF0, 0x90, 0xB2, + 0xB1, 0x00, 0xF0, 0x90, 0xB2, 0xB2, 0x00, 0xF0, 0x91, 0xA2, 0xA0, 0x00, + 0xF0, 0x91, 0xA2, 0xA1, 0x00, 0xF0, 0x91, 0xA2, 0xA2, 0x00, 0xF0, 0x91, + 0xA2, 0xA3, 0x00, 0xF0, 0x91, 0xA2, 0xA4, 0x00, 0xF0, 0x91, 0xA2, 0xA5, + 0x00, 0xF0, 0x91, 0xA2, 0xA6, 0x00, 0xF0, 0x91, 0xA2, 0xA7, 0x00, 0xF0, + 0x91, 0xA2, 0xA8, 0x00, 0xF0, 0x91, 0xA2, 0xA9, 0x00, 0xF0, 0x91, 0xA2, + 0xAA, 0x00, 0xF0, 0x91, 0xA2, 0xAB, 0x00, 0xF0, 0x91, 0xA2, 0xAC, 0x00, + 0xF0, 0x91, 0xA2, 0xAD, 0x00, 0xF0, 0x91, 0xA2, 0xAE, 0x00, 0xF0, 0x91, + 0xA2, 0xAF, 0x00, 0xF0, 0x91, 0xA2, 0xB0, 0x00, 0xF0, 0x91, 0xA2, 0xB1, + 0x00, 0xF0, 0x91, 0xA2, 0xB2, 0x00, 0xF0, 0x91, 0xA2, 0xB3, 0x00, 0xF0, + 0x91, 0xA2, 0xB4, 0x00, 0xF0, 0x91, 0xA2, 0xB5, 0x00, 0xF0, 0x91, 0xA2, + 0xB6, 0x00, 0xF0, 0x91, 0xA2, 0xB7, 0x00, 0xF0, 0x91, 0xA2, 0xB8, 0x00, + 0xF0, 0x91, 0xA2, 0xB9, 0x00, 0xF0, 0x91, 0xA2, 0xBA, 0x00, 0xF0, 0x91, + 0xA2, 0xBB, 0x00, 0xF0, 0x91, 0xA2, 0xBC, 0x00, 0xF0, 0x91, 0xA2, 0xBD, + 0x00, 0xF0, 0x91, 0xA2, 0xBE, 0x00, 0xF0, 0x91, 0xA2, 0xBF, 0x00, 0xE1, + 0x8F, 0xB0, 0x00, 0xE1, 0x8F, 0xB1, 0x00, 0xE1, 0x8F, 0xB2, 0x00, 0xE1, + 0x8F, 0xB3, 0x00, 0xE1, 0x8F, 0xB4, 0x00, 0xE1, 0x8F, 0xB5, 0x00, 0xD0, + 0x92, 0x00, 0xD0, 0x94, 0x00, 0xD0, 0x9E, 0x00, 0xD0, 0xA1, 0x00, 0xD0, + 0xA2, 0x00, 0xD0, 0xA2, 0x00, 0xD0, 0xAA, 0x00, 0xD1, 0xA2, 0x00, 0xEA, + 0x99, 0x8A, 0x00, 0xEA, 0x9D, 0xBD, 0x00, 0xE2, 0xB1, 0xA3, 0x00, 0xE1, + 0xB8, 0x80, 0x00, 0xE1, 0xB8, 0x82, 0x00, 0xE1, 0xB8, 0x84, 0x00, 0xE1, + 0xB8, 0x86, 0x00, 0xE1, 0xB8, 0x88, 0x00, 0xE1, 0xB8, 0x8A, 0x00, 0xE1, + 0xB8, 0x8C, 0x00, 0xE1, 0xB8, 0x8E, 0x00, 0xE1, 0xB8, 0x90, 0x00, 0xE1, + 0xB8, 0x92, 0x00, 0xE1, 0xB8, 0x94, 0x00, 0xE1, 0xB8, 0x96, 0x00, 0xE1, + 0xB8, 0x98, 0x00, 0xE1, 0xB8, 0x9A, 0x00, 0xE1, 0xB8, 0x9C, 0x00, 0xE1, + 0xB8, 0x9E, 0x00, 0xE1, 0xB8, 0xA0, 0x00, 0xE1, 0xB8, 0xA2, 0x00, 0xE1, + 0xB8, 0xA4, 0x00, 0xE1, 0xB8, 0xA6, 0x00, 0xE1, 0xB8, 0xA8, 0x00, 0xE1, + 0xB8, 0xAA, 0x00, 0xE1, 0xB8, 0xAC, 0x00, 0xE1, 0xB8, 0xAE, 0x00, 0xE1, + 0xB8, 0xB0, 0x00, 0xE1, 0xB8, 0xB2, 0x00, 0xE1, 0xB8, 0xB4, 0x00, 0xE1, + 0xB8, 0xB6, 0x00, 0xE1, 0xB8, 0xB8, 0x00, 0xE1, 0xB8, 0xBA, 0x00, 0xE1, + 0xB8, 0xBC, 0x00, 0xE1, 0xB8, 0xBE, 0x00, 0xE1, 0xB9, 0x80, 0x00, 0xE1, + 0xB9, 0x82, 0x00, 0xE1, 0xB9, 0x84, 0x00, 0xE1, 0xB9, 0x86, 0x00, 0xE1, + 0xB9, 0x88, 0x00, 0xE1, 0xB9, 0x8A, 0x00, 0xE1, 0xB9, 0x8C, 0x00, 0xE1, + 0xB9, 0x8E, 0x00, 0xE1, 0xB9, 0x90, 0x00, 0xE1, 0xB9, 0x92, 0x00, 0xE1, + 0xB9, 0x94, 0x00, 0xE1, 0xB9, 0x96, 0x00, 0xE1, 0xB9, 0x98, 0x00, 0xE1, + 0xB9, 0x9A, 0x00, 0xE1, 0xB9, 0x9C, 0x00, 0xE1, 0xB9, 0x9E, 0x00, 0xE1, + 0xB9, 0xA0, 0x00, 0xE1, 0xB9, 0xA2, 0x00, 0xE1, 0xB9, 0xA4, 0x00, 0xE1, + 0xB9, 0xA6, 0x00, 0xE1, 0xB9, 0xA8, 0x00, 0xE1, 0xB9, 0xAA, 0x00, 0xE1, + 0xB9, 0xAC, 0x00, 0xE1, 0xB9, 0xAE, 0x00, 0xE1, 0xB9, 0xB0, 0x00, 0xE1, + 0xB9, 0xB2, 0x00, 0xE1, 0xB9, 0xB4, 0x00, 0xE1, 0xB9, 0xB6, 0x00, 0xE1, + 0xB9, 0xB8, 0x00, 0xE1, 0xB9, 0xBA, 0x00, 0xE1, 0xB9, 0xBC, 0x00, 0xE1, + 0xB9, 0xBE, 0x00, 0xE1, 0xBA, 0x80, 0x00, 0xE1, 0xBA, 0x82, 0x00, 0xE1, + 0xBA, 0x84, 0x00, 0xE1, 0xBA, 0x86, 0x00, 0xE1, 0xBA, 0x88, 0x00, 0xE1, + 0xBA, 0x8A, 0x00, 0xE1, 0xBA, 0x8C, 0x00, 0xE1, 0xBA, 0x8E, 0x00, 0xE1, + 0xBA, 0x90, 0x00, 0xF0, 0x9E, 0xA4, 0x80, 0x00, 0xF0, 0x9E, 0xA4, 0x81, + 0x00, 0xF0, 0x9E, 0xA4, 0x82, 0x00, 0xF0, 0x9E, 0xA4, 0x83, 0x00, 0xF0, + 0x9E, 0xA4, 0x84, 0x00, 0xF0, 0x9E, 0xA4, 0x85, 0x00, 0xF0, 0x9E, 0xA4, + 0x86, 0x00, 0xF0, 0x9E, 0xA4, 0x87, 0x00, 0xF0, 0x9E, 0xA4, 0x88, 0x00, + 0xF0, 0x9E, 0xA4, 0x89, 0x00, 0xF0, 0x9E, 0xA4, 0x8A, 0x00, 0xF0, 0x9E, + 0xA4, 0x8B, 0x00, 0xF0, 0x9E, 0xA4, 0x8C, 0x00, 0xF0, 0x9E, 0xA4, 0x8D, + 0x00, 0xE1, 0xBA, 0x92, 0x00, 0xF0, 0x9E, 0xA4, 0x8E, 0x00, 0xF0, 0x9E, + 0xA4, 0x8F, 0x00, 0xF0, 0x9E, 0xA4, 0x90, 0x00, 0xF0, 0x9E, 0xA4, 0x91, + 0x00, 0xF0, 0x9E, 0xA4, 0x92, 0x00, 0xF0, 0x9E, 0xA4, 0x93, 0x00, 0xF0, + 0x9E, 0xA4, 0x94, 0x00, 0xF0, 0x9E, 0xA4, 0x95, 0x00, 0xF0, 0x9E, 0xA4, + 0x96, 0x00, 0xF0, 0x9E, 0xA4, 0x97, 0x00, 0xF0, 0x9E, 0xA4, 0x98, 0x00, + 0xF0, 0x9E, 0xA4, 0x99, 0x00, 0xF0, 0x9E, 0xA4, 0x9A, 0x00, 0xF0, 0x9E, + 0xA4, 0x9B, 0x00, 0xF0, 0x9E, 0xA4, 0x9C, 0x00, 0xF0, 0x9E, 0xA4, 0x9D, + 0x00, 0xF0, 0x9E, 0xA4, 0x9E, 0x00, 0xF0, 0x9E, 0xA4, 0x9F, 0x00, 0xF0, + 0x9E, 0xA4, 0xA0, 0x00, 0xF0, 0x9E, 0xA4, 0xA1, 0x00, 0xE1, 0xBA, 0x94, + 0x00, 0xE1, 0xB9, 0xA0, 0x00, 0xE1, 0xBA, 0xA0, 0x00, 0xE1, 0xBA, 0xA2, + 0x00, 0xE1, 0xBA, 0xA4, 0x00, 0xE1, 0xBA, 0xA6, 0x00, 0xE1, 0xBA, 0xA8, + 0x00, 0xE1, 0xBA, 0xAA, 0x00, 0xE1, 0xBA, 0xAC, 0x00, 0xE1, 0xBA, 0xAE, + 0x00, 0xE1, 0xBA, 0xB0, 0x00, 0xE1, 0xBA, 0xB2, 0x00, 0xE1, 0xBA, 0xB4, + 0x00, 0xE1, 0xBA, 0xB6, 0x00, 0xE1, 0xBA, 0xB8, 0x00, 0xE1, 0xBA, 0xBA, + 0x00, 0xE1, 0xBA, 0xBC, 0x00, 0xE1, 0xBA, 0xBE, 0x00, 0xE1, 0xBB, 0x80, + 0x00, 0xE1, 0xBB, 0x82, 0x00, 0xE1, 0xBB, 0x84, 0x00, 0xE1, 0xBB, 0x86, + 0x00, 0xE1, 0xBB, 0x88, 0x00, 0xE1, 0xBB, 0x8A, 0x00, 0xE1, 0xBB, 0x8C, + 0x00, 0xE1, 0xBB, 0x8E, 0x00, 0xE1, 0xBB, 0x90, 0x00, 0xE1, 0xBB, 0x92, + 0x00, 0xE1, 0xBB, 0x94, 0x00, 0xE1, 0xBB, 0x96, 0x00, 0xE1, 0xBB, 0x98, + 0x00, 0xE1, 0xBB, 0x9A, 0x00, 0xE1, 0xBB, 0x9C, 0x00, 0xE1, 0xBB, 0x9E, + 0x00, 0xE1, 0xBB, 0xA0, 0x00, 0xE1, 0xBB, 0xA2, 0x00, 0xE1, 0xBB, 0xA4, + 0x00, 0xE1, 0xBB, 0xA6, 0x00, 0xE1, 0xBB, 0xA8, 0x00, 0xE1, 0xBB, 0xAA, + 0x00, 0xE1, 0xBB, 0xAC, 0x00, 0xE1, 0xBB, 0xAE, 0x00, 0xE1, 0xBB, 0xB0, + 0x00, 0xE1, 0xBB, 0xB2, 0x00, 0xE1, 0xBB, 0xB4, 0x00, 0xE1, 0xBB, 0xB6, + 0x00, 0xE1, 0xBB, 0xB8, 0x00, 0xE1, 0xBB, 0xBA, 0x00, 0xE1, 0xBB, 0xBC, + 0x00, 0xE1, 0xBB, 0xBE, 0x00, 0xE1, 0xBC, 0x88, 0x00, 0xE1, 0xBC, 0x89, + 0x00, 0xE1, 0xBC, 0x8A, 0x00, 0xE1, 0xBC, 0x8B, 0x00, 0xE1, 0xBC, 0x8C, + 0x00, 0xE1, 0xBC, 0x8D, 0x00, 0xE1, 0xBC, 0x8E, 0x00, 0xE1, 0xBC, 0x8F, + 0x00, 0xE1, 0xBC, 0x98, 0x00, 0xE1, 0xBC, 0x99, 0x00, 0xE1, 0xBC, 0x9A, + 0x00, 0xE1, 0xBC, 0x9B, 0x00, 0xE1, 0xBC, 0x9C, 0x00, 0xE1, 0xBC, 0x9D, + 0x00, 0xE1, 0xBC, 0xA8, 0x00, 0xE1, 0xBC, 0xA9, 0x00, 0xE1, 0xBC, 0xAA, + 0x00, 0xE1, 0xBC, 0xAB, 0x00, 0xE1, 0xBC, 0xAC, 0x00, 0xE1, 0xBC, 0xAD, + 0x00, 0xE1, 0xBC, 0xAE, 0x00, 0xE1, 0xBC, 0xAF, 0x00, 0xE1, 0xBC, 0xB8, + 0x00, 0xE1, 0xBC, 0xB9, 0x00, 0xE1, 0xBC, 0xBA, 0x00, 0xE1, 0xBC, 0xBB, + 0x00, 0xE1, 0xBC, 0xBC, 0x00, 0xE1, 0xBC, 0xBD, 0x00, 0xE1, 0xBC, 0xBE, + 0x00, 0xE1, 0xBC, 0xBF, 0x00, 0xE1, 0xBD, 0x88, 0x00, 0xE1, 0xBD, 0x89, + 0x00, 0xE1, 0xBD, 0x8A, 0x00, 0xE1, 0xBD, 0x8B, 0x00, 0xE1, 0xBD, 0x8C, + 0x00, 0xE1, 0xBD, 0x8D, 0x00, 0xE1, 0xBD, 0x99, 0x00, 0xE1, 0xBD, 0x9B, + 0x00, 0xE1, 0xBD, 0x9D, 0x00, 0xE1, 0xBD, 0x9F, 0x00, 0xE1, 0xBD, 0xA8, + 0x00, 0xE1, 0xBD, 0xA9, 0x00, 0xE1, 0xBD, 0xAA, 0x00, 0xE1, 0xBD, 0xAB, + 0x00, 0xE1, 0xBD, 0xAC, 0x00, 0xE1, 0xBD, 0xAD, 0x00, 0xE1, 0xBD, 0xAE, + 0x00, 0xE1, 0xBD, 0xAF, 0x00, 0xE1, 0xBE, 0xBA, 0x00, 0xE1, 0xBE, 0xBB, + 0x00, 0xE1, 0xBF, 0x88, 0x00, 0xE1, 0xBF, 0x89, 0x00, 0xE1, 0xBF, 0x8A, + 0x00, 0xE1, 0xBF, 0x8B, 0x00, 0xE1, 0xBF, 0x9A, 0x00, 0xE1, 0xBF, 0x9B, + 0x00, 0xE1, 0xBF, 0xB8, 0x00, 0xE1, 0xBF, 0xB9, 0x00, 0xE1, 0xBF, 0xAA, + 0x00, 0xE1, 0xBF, 0xAB, 0x00, 0xE1, 0xBF, 0xBA, 0x00, 0xE1, 0xBF, 0xBB, + 0x00, 0xE1, 0xBE, 0x88, 0x00, 0xE1, 0xBE, 0x89, 0x00, 0xE1, 0xBE, 0x8A, + 0x00, 0xE1, 0xBE, 0x8B, 0x00, 0xE1, 0xBE, 0x8C, 0x00, 0xE1, 0xBE, 0x8D, + 0x00, 0xE1, 0xBE, 0x8E, 0x00, 0xE1, 0xBE, 0x8F, 0x00, 0xE1, 0xBE, 0x98, + 0x00, 0xE1, 0xBE, 0x99, 0x00, 0xE1, 0xBE, 0x9A, 0x00, 0xE1, 0xBE, 0x9B, + 0x00, 0xE1, 0xBE, 0x9C, 0x00, 0xE1, 0xBE, 0x9D, 0x00, 0xE1, 0xBE, 0x9E, + 0x00, 0xE1, 0xBE, 0x9F, 0x00, 0xE1, 0xBE, 0xA8, 0x00, 0xE1, 0xBE, 0xA9, + 0x00, 0xE1, 0xBE, 0xAA, 0x00, 0xE1, 0xBE, 0xAB, 0x00, 0xE1, 0xBE, 0xAC, + 0x00, 0xE1, 0xBE, 0xAD, 0x00, 0xE1, 0xBE, 0xAE, 0x00, 0xE1, 0xBE, 0xAF, + 0x00, 0xE1, 0xBE, 0xB8, 0x00, 0xE1, 0xBE, 0xB9, 0x00, 0xE1, 0xBE, 0xBC, + 0x00, 0xCE, 0x99, 0x00, 0xE1, 0xBF, 0x8C, 0x00, 0xE1, 0xBF, 0x98, 0x00, + 0xE1, 0xBF, 0x99, 0x00, 0xE1, 0xBF, 0xA8, 0x00, 0xE1, 0xBF, 0xA9, 0x00, + 0xE1, 0xBF, 0xAC, 0x00, 0xE1, 0xBF, 0xBC, 0x00, 0xE2, 0x84, 0xB2, 0x00, + 0xE2, 0x85, 0xA0, 0x00, 0xE2, 0x85, 0xA1, 0x00, 0xE2, 0x85, 0xA2, 0x00, + 0xE2, 0x85, 0xA3, 0x00, 0xE2, 0x85, 0xA4, 0x00, 0xE2, 0x85, 0xA5, 0x00, + 0xE2, 0x85, 0xA6, 0x00, 0xE2, 0x85, 0xA7, 0x00, 0xE2, 0x85, 0xA8, 0x00, + 0xE2, 0x85, 0xA9, 0x00, 0xE2, 0x85, 0xAA, 0x00, 0xE2, 0x85, 0xAB, 0x00, + 0xE2, 0x85, 0xAC, 0x00, 0xE2, 0x85, 0xAD, 0x00, 0xE2, 0x85, 0xAE, 0x00, + 0xE2, 0x85, 0xAF, 0x00, 0xE2, 0x86, 0x83, 0x00, 0xE2, 0x92, 0xB6, 0x00, + 0xE2, 0x92, 0xB7, 0x00, 0xE2, 0x92, 0xB8, 0x00, 0xE2, 0x92, 0xB9, 0x00, + 0xE2, 0x92, 0xBA, 0x00, 0xE2, 0x92, 0xBB, 0x00, 0xE2, 0x92, 0xBC, 0x00, + 0xE2, 0x92, 0xBD, 0x00, 0xE2, 0x92, 0xBE, 0x00, 0xE2, 0x92, 0xBF, 0x00, + 0xE2, 0x93, 0x80, 0x00, 0xE2, 0x93, 0x81, 0x00, 0xE2, 0x93, 0x82, 0x00, + 0xE2, 0x93, 0x83, 0x00, 0xE2, 0x93, 0x84, 0x00, 0xE2, 0x93, 0x85, 0x00, + 0xE2, 0x93, 0x86, 0x00, 0xE2, 0x93, 0x87, 0x00, 0xE2, 0x93, 0x88, 0x00, + 0xE2, 0x93, 0x89, 0x00, 0xE2, 0x93, 0x8A, 0x00, 0xE2, 0x93, 0x8B, 0x00, + 0xE2, 0x93, 0x8C, 0x00, 0xE2, 0x93, 0x8D, 0x00, 0xE2, 0x93, 0x8E, 0x00, + 0xE2, 0x93, 0x8F, 0x00, 0xE2, 0xB0, 0x80, 0x00, 0xE2, 0xB0, 0x81, 0x00, + 0xE2, 0xB0, 0x82, 0x00, 0xE2, 0xB0, 0x83, 0x00, 0xE2, 0xB0, 0x84, 0x00, + 0xE2, 0xB0, 0x85, 0x00, 0xE2, 0xB0, 0x86, 0x00, 0xE2, 0xB0, 0x87, 0x00, + 0xE2, 0xB0, 0x88, 0x00, 0xE2, 0xB0, 0x89, 0x00, 0xE2, 0xB0, 0x8A, 0x00, + 0xE2, 0xB0, 0x8B, 0x00, 0xE2, 0xB0, 0x8C, 0x00, 0xE2, 0xB0, 0x8D, 0x00, + 0xE2, 0xB0, 0x8E, 0x00, 0xE2, 0xB0, 0x8F, 0x00, 0xE2, 0xB0, 0x90, 0x00, + 0xE2, 0xB0, 0x91, 0x00, 0xE2, 0xB0, 0x92, 0x00, 0xE2, 0xB0, 0x93, 0x00, + 0xE2, 0xB0, 0x94, 0x00, 0xE2, 0xB0, 0x95, 0x00, 0xE2, 0xB0, 0x96, 0x00, + 0xE2, 0xB0, 0x97, 0x00, 0xE2, 0xB0, 0x98, 0x00, 0xE2, 0xB0, 0x99, 0x00, + 0xE2, 0xB0, 0x9A, 0x00, 0xE2, 0xB0, 0x9B, 0x00, 0xE2, 0xB0, 0x9C, 0x00, + 0xE2, 0xB0, 0x9D, 0x00, 0xE2, 0xB0, 0x9E, 0x00, 0xE2, 0xB0, 0x9F, 0x00, + 0xE2, 0xB0, 0xA0, 0x00, 0xE2, 0xB0, 0xA1, 0x00, 0xE2, 0xB0, 0xA2, 0x00, + 0xE2, 0xB0, 0xA3, 0x00, 0xE2, 0xB0, 0xA4, 0x00, 0xE2, 0xB0, 0xA5, 0x00, + 0xE2, 0xB0, 0xA6, 0x00, 0xE2, 0xB0, 0xA7, 0x00, 0xE2, 0xB0, 0xA8, 0x00, + 0xE2, 0xB0, 0xA9, 0x00, 0xE2, 0xB0, 0xAA, 0x00, 0xE2, 0xB0, 0xAB, 0x00, + 0xE2, 0xB0, 0xAC, 0x00, 0xE2, 0xB0, 0xAD, 0x00, 0xE2, 0xB0, 0xAE, 0x00, + 0xE2, 0xB1, 0xA0, 0x00, 0xC8, 0xBA, 0x00, 0xC8, 0xBE, 0x00, 0xE2, 0xB1, + 0xA7, 0x00, 0xE2, 0xB1, 0xA9, 0x00, 0xE2, 0xB1, 0xAB, 0x00, 0xE2, 0xB1, + 0xB2, 0x00, 0xE2, 0xB1, 0xB5, 0x00, 0xE2, 0xB2, 0x80, 0x00, 0xE2, 0xB2, + 0x82, 0x00, 0xE2, 0xB2, 0x84, 0x00, 0xE2, 0xB2, 0x86, 0x00, 0xE2, 0xB2, + 0x88, 0x00, 0xE2, 0xB2, 0x8A, 0x00, 0xE2, 0xB2, 0x8C, 0x00, 0xE2, 0xB2, + 0x8E, 0x00, 0xE2, 0xB2, 0x90, 0x00, 0xE2, 0xB2, 0x92, 0x00, 0xE2, 0xB2, + 0x94, 0x00, 0xE2, 0xB2, 0x96, 0x00, 0xE2, 0xB2, 0x98, 0x00, 0xE2, 0xB2, + 0x9A, 0x00, 0xE2, 0xB2, 0x9C, 0x00, 0xE2, 0xB2, 0x9E, 0x00, 0xE2, 0xB2, + 0xA0, 0x00, 0xE2, 0xB2, 0xA2, 0x00, 0xE2, 0xB2, 0xA4, 0x00, 0xE2, 0xB2, + 0xA6, 0x00, 0xE2, 0xB2, 0xA8, 0x00, 0xE2, 0xB2, 0xAA, 0x00, 0xE2, 0xB2, + 0xAC, 0x00, 0xE2, 0xB2, 0xAE, 0x00, 0xE2, 0xB2, 0xB0, 0x00, 0xE2, 0xB2, + 0xB2, 0x00, 0xE2, 0xB2, 0xB4, 0x00, 0xE2, 0xB2, 0xB6, 0x00, 0xE2, 0xB2, + 0xB8, 0x00, 0xE2, 0xB2, 0xBA, 0x00, 0xE2, 0xB2, 0xBC, 0x00, 0xE2, 0xB2, + 0xBE, 0x00, 0xE2, 0xB3, 0x80, 0x00, 0xE2, 0xB3, 0x82, 0x00, 0xE2, 0xB3, + 0x84, 0x00, 0xE2, 0xB3, 0x86, 0x00, 0xE2, 0xB3, 0x88, 0x00, 0xE2, 0xB3, + 0x8A, 0x00, 0xE2, 0xB3, 0x8C, 0x00, 0xE2, 0xB3, 0x8E, 0x00, 0xE2, 0xB3, + 0x90, 0x00, 0xE2, 0xB3, 0x92, 0x00, 0xE2, 0xB3, 0x94, 0x00, 0xE2, 0xB3, + 0x96, 0x00, 0xE2, 0xB3, 0x98, 0x00, 0xE2, 0xB3, 0x9A, 0x00, 0xE2, 0xB3, + 0x9C, 0x00, 0xE2, 0xB3, 0x9E, 0x00, 0xE2, 0xB3, 0xA0, 0x00, 0xE2, 0xB3, + 0xA2, 0x00, 0xE2, 0xB3, 0xAB, 0x00, 0xE2, 0xB3, 0xAD, 0x00, 0xE2, 0xB3, + 0xB2, 0x00, 0xE1, 0x82, 0xA0, 0x00, 0xE1, 0x82, 0xA1, 0x00, 0xE1, 0x82, + 0xA2, 0x00, 0xE1, 0x82, 0xA3, 0x00, 0xE1, 0x82, 0xA4, 0x00, 0xE1, 0x82, + 0xA5, 0x00, 0xE1, 0x82, 0xA6, 0x00, 0xE1, 0x82, 0xA7, 0x00, 0xE1, 0x82, + 0xA8, 0x00, 0xE1, 0x82, 0xA9, 0x00, 0xE1, 0x82, 0xAA, 0x00, 0xE1, 0x82, + 0xAB, 0x00, 0xE1, 0x82, 0xAC, 0x00, 0xE1, 0x82, 0xAD, 0x00, 0xE1, 0x82, + 0xAE, 0x00, 0xE1, 0x82, 0xAF, 0x00, 0xE1, 0x82, 0xB0, 0x00, 0xE1, 0x82, + 0xB1, 0x00, 0xE1, 0x82, 0xB2, 0x00, 0xE1, 0x82, 0xB3, 0x00, 0xE1, 0x82, + 0xB4, 0x00, 0xE1, 0x82, 0xB5, 0x00, 0xE1, 0x82, 0xB6, 0x00, 0xE1, 0x82, + 0xB7, 0x00, 0xE1, 0x82, 0xB8, 0x00, 0xE1, 0x82, 0xB9, 0x00, 0xE1, 0x82, + 0xBA, 0x00, 0xE1, 0x82, 0xBB, 0x00, 0xE1, 0x82, 0xBC, 0x00, 0xE1, 0x82, + 0xBD, 0x00, 0xE1, 0x82, 0xBE, 0x00, 0xE1, 0x82, 0xBF, 0x00, 0xE1, 0x83, + 0x80, 0x00, 0xE1, 0x83, 0x81, 0x00, 0xE1, 0x83, 0x82, 0x00, 0xE1, 0x83, + 0x83, 0x00, 0xE1, 0x83, 0x84, 0x00, 0xE1, 0x83, 0x85, 0x00, 0xE1, 0x83, + 0x87, 0x00, 0xE1, 0x83, 0x8D, 0x00, 0xEA, 0x99, 0x80, 0x00, 0xEA, 0x99, + 0x82, 0x00, 0xEA, 0x99, 0x84, 0x00, 0xEA, 0x99, 0x86, 0x00, 0xEA, 0x99, + 0x88, 0x00, 0xEA, 0x99, 0x8A, 0x00, 0xEA, 0x99, 0x8C, 0x00, 0xEA, 0x99, + 0x8E, 0x00, 0xEA, 0x99, 0x90, 0x00, 0xEA, 0x99, 0x92, 0x00, 0xEA, 0x99, + 0x94, 0x00, 0xEA, 0x99, 0x96, 0x00, 0xEA, 0x99, 0x98, 0x00, 0xEA, 0x99, + 0x9A, 0x00, 0xEA, 0x99, 0x9C, 0x00, 0xEA, 0x99, 0x9E, 0x00, 0xEA, 0x99, + 0xA0, 0x00, 0xEA, 0x99, 0xA2, 0x00, 0xEA, 0x99, 0xA4, 0x00, 0xEA, 0x99, + 0xA6, 0x00, 0xEA, 0x99, 0xA8, 0x00, 0xEA, 0x99, 0xAA, 0x00, 0xEA, 0x99, + 0xAC, 0x00, 0xEA, 0x9A, 0x80, 0x00, 0xEA, 0x9A, 0x82, 0x00, 0xEA, 0x9A, + 0x84, 0x00, 0xEA, 0x9A, 0x86, 0x00, 0xEA, 0x9A, 0x88, 0x00, 0xEA, 0x9A, + 0x8A, 0x00, 0xEA, 0x9A, 0x8C, 0x00, 0xEA, 0x9A, 0x8E, 0x00, 0xEA, 0x9A, + 0x90, 0x00, 0xEA, 0x9A, 0x92, 0x00, 0xEA, 0x9A, 0x94, 0x00, 0xEA, 0x9A, + 0x96, 0x00, 0xEA, 0x9A, 0x98, 0x00, 0xEA, 0x9A, 0x9A, 0x00, 0xEA, 0x9C, + 0xA2, 0x00, 0xEA, 0x9C, 0xA4, 0x00, 0xEA, 0x9C, 0xA6, 0x00, 0xEA, 0x9C, + 0xA8, 0x00, 0xEA, 0x9C, 0xAA, 0x00, 0xEA, 0x9C, 0xAC, 0x00, 0xEA, 0x9C, + 0xAE, 0x00, 0xEA, 0x9C, 0xB2, 0x00, 0xEA, 0x9C, 0xB4, 0x00, 0xEA, 0x9C, + 0xB6, 0x00, 0xEA, 0x9C, 0xB8, 0x00, 0xEA, 0x9C, 0xBA, 0x00, 0xEA, 0x9C, + 0xBC, 0x00, 0xEA, 0x9C, 0xBE, 0x00, 0xEA, 0x9D, 0x80, 0x00, 0xEA, 0x9D, + 0x82, 0x00, 0xEA, 0x9D, 0x84, 0x00, 0xEA, 0x9D, 0x86, 0x00, 0xEA, 0x9D, + 0x88, 0x00, 0xEA, 0x9D, 0x8A, 0x00, 0xEA, 0x9D, 0x8C, 0x00, 0xEA, 0x9D, + 0x8E, 0x00, 0xEA, 0x9D, 0x90, 0x00, 0xEA, 0x9D, 0x92, 0x00, 0xEA, 0x9D, + 0x94, 0x00, 0xEA, 0x9D, 0x96, 0x00, 0xEA, 0x9D, 0x98, 0x00, 0xEA, 0x9D, + 0x9A, 0x00, 0xEA, 0x9D, 0x9C, 0x00, 0xEA, 0x9D, 0x9E, 0x00, 0xEA, 0x9D, + 0xA0, 0x00, 0xEA, 0x9D, 0xA2, 0x00, 0xEA, 0x9D, 0xA4, 0x00, 0xEA, 0x9D, + 0xA6, 0x00, 0xEA, 0x9D, 0xA8, 0x00, 0xEA, 0x9D, 0xAA, 0x00, 0xEA, 0x9D, + 0xAC, 0x00, 0xEA, 0x9D, 0xAE, 0x00, 0xEA, 0x9D, 0xB9, 0x00, 0xEA, 0x9D, + 0xBB, 0x00, 0xEA, 0x9D, 0xBE, 0x00, 0xEA, 0x9E, 0x80, 0x00, 0xEA, 0x9E, + 0x82, 0x00, 0xEA, 0x9E, 0x84, 0x00, 0xEA, 0x9E, 0x86, 0x00, 0xEA, 0x9E, + 0x8B, 0x00, 0xEA, 0x9E, 0x90, 0x00, 0xEA, 0x9E, 0x92, 0x00, 0xEA, 0x9E, + 0x96, 0x00, 0xEA, 0x9E, 0x98, 0x00, 0xEA, 0x9E, 0x9A, 0x00, 0xEA, 0x9E, + 0x9C, 0x00, 0xEA, 0x9E, 0x9E, 0x00, 0xEA, 0x9E, 0xA0, 0x00, 0xEA, 0x9E, + 0xA2, 0x00, 0xEA, 0x9E, 0xA4, 0x00, 0xEA, 0x9E, 0xA6, 0x00, 0xEA, 0x9E, + 0xA8, 0x00, 0xEA, 0x9E, 0xB4, 0x00, 0xEA, 0x9E, 0xB6, 0x00, 0xEA, 0x9E, + 0xB3, 0x00, 0xE1, 0x8E, 0xA0, 0x00, 0xE1, 0x8E, 0xA1, 0x00, 0xE1, 0x8E, + 0xA2, 0x00, 0xE1, 0x8E, 0xA3, 0x00, 0xE1, 0x8E, 0xA4, 0x00, 0xE1, 0x8E, + 0xA5, 0x00, 0xE1, 0x8E, 0xA6, 0x00, 0xE1, 0x8E, 0xA7, 0x00, 0xE1, 0x8E, + 0xA8, 0x00, 0xE1, 0x8E, 0xA9, 0x00, 0xE1, 0x8E, 0xAA, 0x00, 0xE1, 0x8E, + 0xAB, 0x00, 0xE1, 0x8E, 0xAC, 0x00, 0xE1, 0x8E, 0xAD, 0x00, 0xE1, 0x8E, + 0xAE, 0x00, 0xE1, 0x8E, 0xAF, 0x00, 0xE1, 0x8E, 0xB0, 0x00, 0xE1, 0x8E, + 0xB1, 0x00, 0xE1, 0x8E, 0xB2, 0x00, 0xE1, 0x8E, 0xB3, 0x00, 0xE1, 0x8E, + 0xB4, 0x00, 0xE1, 0x8E, 0xB5, 0x00, 0xE1, 0x8E, 0xB6, 0x00, 0xE1, 0x8E, + 0xB7, 0x00, 0xE1, 0x8E, 0xB8, 0x00, 0xE1, 0x8E, 0xB9, 0x00, 0xE1, 0x8E, + 0xBA, 0x00, 0xE1, 0x8E, 0xBB, 0x00, 0xE1, 0x8E, 0xBC, 0x00, 0xE1, 0x8E, + 0xBD, 0x00, 0xE1, 0x8E, 0xBE, 0x00, 0xE1, 0x8E, 0xBF, 0x00, 0xE1, 0x8F, + 0x80, 0x00, 0xE1, 0x8F, 0x81, 0x00, 0xE1, 0x8F, 0x82, 0x00, 0xE1, 0x8F, + 0x83, 0x00, 0xE1, 0x8F, 0x84, 0x00, 0xE1, 0x8F, 0x85, 0x00, 0xE1, 0x8F, + 0x86, 0x00, 0xE1, 0x8F, 0x87, 0x00, 0xE1, 0x8F, 0x88, 0x00, 0xE1, 0x8F, + 0x89, 0x00, 0xE1, 0x8F, 0x8A, 0x00, 0xE1, 0x8F, 0x8B, 0x00, 0xE1, 0x8F, + 0x8C, 0x00, 0xE1, 0x8F, 0x8D, 0x00, 0xE1, 0x8F, 0x8E, 0x00, 0xE1, 0x8F, + 0x8F, 0x00, 0xE1, 0x8F, 0x90, 0x00, 0xE1, 0x8F, 0x91, 0x00, 0xE1, 0x8F, + 0x92, 0x00, 0xE1, 0x8F, 0x93, 0x00, 0xE1, 0x8F, 0x94, 0x00, 0xE1, 0x8F, + 0x95, 0x00, 0xE1, 0x8F, 0x96, 0x00, 0xE1, 0x8F, 0x97, 0x00, 0xE1, 0x8F, + 0x98, 0x00, 0xE1, 0x8F, 0x99, 0x00, 0xE1, 0x8F, 0x9A, 0x00, 0xE1, 0x8F, + 0x9B, 0x00, 0xE1, 0x8F, 0x9C, 0x00, 0xE1, 0x8F, 0x9D, 0x00, 0xE1, 0x8F, + 0x9E, 0x00, 0xE1, 0x8F, 0x9F, 0x00, 0xE1, 0x8F, 0xA0, 0x00, 0xE1, 0x8F, + 0xA1, 0x00, 0xE1, 0x8F, 0xA2, 0x00, 0xE1, 0x8F, 0xA3, 0x00, 0xE1, 0x8F, + 0xA4, 0x00, 0xE1, 0x8F, 0xA5, 0x00, 0xE1, 0x8F, 0xA6, 0x00, 0xE1, 0x8F, + 0xA7, 0x00, 0xE1, 0x8F, 0xA8, 0x00, 0xE1, 0x8F, 0xA9, 0x00, 0xE1, 0x8F, + 0xAA, 0x00, 0xE1, 0x8F, 0xAB, 0x00, 0xE1, 0x8F, 0xAC, 0x00, 0xE1, 0x8F, + 0xAD, 0x00, 0xE1, 0x8F, 0xAE, 0x00, 0xE1, 0x8F, 0xAF, 0x00, 0xEF, 0xBC, + 0xA1, 0x00, 0xEF, 0xBC, 0xA2, 0x00, 0xEF, 0xBC, 0xA3, 0x00, 0xEF, 0xBC, + 0xA4, 0x00, 0xEF, 0xBC, 0xA5, 0x00, 0xEF, 0xBC, 0xA6, 0x00, 0xEF, 0xBC, + 0xA7, 0x00, 0xEF, 0xBC, 0xA8, 0x00, 0xEF, 0xBC, 0xA9, 0x00, 0xEF, 0xBC, + 0xAA, 0x00, 0xEF, 0xBC, 0xAB, 0x00, 0xEF, 0xBC, 0xAC, 0x00, 0xEF, 0xBC, + 0xAD, 0x00, 0xEF, 0xBC, 0xAE, 0x00, 0xEF, 0xBC, 0xAF, 0x00, 0xEF, 0xBC, + 0xB0, 0x00, 0xEF, 0xBC, 0xB1, 0x00, 0xEF, 0xBC, 0xB2, 0x00, 0xEF, 0xBC, + 0xB3, 0x00, 0xEF, 0xBC, 0xB4, 0x00, 0xEF, 0xBC, 0xB5, 0x00, 0xEF, 0xBC, + 0xB6, 0x00, 0xEF, 0xBC, 0xB7, 0x00, 0xEF, 0xBC, 0xB8, 0x00, 0xEF, 0xBC, + 0xB9, 0x00, 0xEF, 0xBC, 0xBA, 0x00, 0x53, 0x53, 0x00, 0xCA, 0xBC, 0x4E, + 0x00, 0x4A, 0xCC, 0x8C, 0x00, 0xCE, 0x99, 0xCC, 0x88, 0xCC, 0x81, 0x00, + 0xCE, 0xA5, 0xCC, 0x88, 0xCC, 0x81, 0x00, 0xD4, 0xB5, 0xD5, 0x92, 0x00, + 0x48, 0xCC, 0xB1, 0x00, 0x54, 0xCC, 0x88, 0x00, 0x57, 0xCC, 0x8A, 0x00, + 0x59, 0xCC, 0x8A, 0x00, 0x41, 0xCA, 0xBE, 0x00, 0xCE, 0xA5, 0xCC, 0x93, + 0x00, 0xCE, 0xA5, 0xCC, 0x93, 0xCC, 0x80, 0x00, 0xCE, 0xA5, 0xCC, 0x93, + 0xCC, 0x81, 0x00, 0xCE, 0xA5, 0xCC, 0x93, 0xCD, 0x82, 0x00, 0xE1, 0xBC, + 0x88, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x89, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x8A, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x8B, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x8C, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x8D, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x8E, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x8F, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x88, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x89, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x8A, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x8B, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x8C, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x8D, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0x8E, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0x8F, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xA8, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xA9, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xAA, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xAB, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xAC, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xAD, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xAE, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xAF, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xA8, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xA9, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xAA, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xAB, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xAC, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xAD, 0xCE, 0x99, 0x00, 0xE1, 0xBC, + 0xAE, 0xCE, 0x99, 0x00, 0xE1, 0xBC, 0xAF, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xA8, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xA9, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xAA, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xAB, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xAC, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xAD, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xAE, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xAF, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xA8, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xA9, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xAA, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xAB, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xAC, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xAD, 0xCE, 0x99, 0x00, 0xE1, 0xBD, + 0xAE, 0xCE, 0x99, 0x00, 0xE1, 0xBD, 0xAF, 0xCE, 0x99, 0x00, 0xE1, 0xBE, + 0xBA, 0xCE, 0x99, 0x00, 0xCE, 0x91, 0xCE, 0x99, 0x00, 0xCE, 0x86, 0xCE, + 0x99, 0x00, 0xCE, 0x91, 0xCD, 0x82, 0x00, 0xCE, 0x91, 0xCD, 0x82, 0xCE, + 0x99, 0x00, 0xCE, 0x91, 0xCE, 0x99, 0x00, 0xE1, 0xBF, 0x8A, 0xCE, 0x99, + 0x00, 0xCE, 0x97, 0xCE, 0x99, 0x00, 0xCE, 0x89, 0xCE, 0x99, 0x00, 0xCE, + 0x97, 0xCD, 0x82, 0x00, 0xCE, 0x97, 0xCD, 0x82, 0xCE, 0x99, 0x00, 0xCE, + 0x97, 0xCE, 0x99, 0x00, 0xCE, 0x99, 0xCC, 0x88, 0xCC, 0x80, 0x00, 0xCE, + 0x99, 0xCC, 0x88, 0xCC, 0x81, 0x00, 0xCE, 0x99, 0xCD, 0x82, 0x00, 0xCE, + 0x99, 0xCC, 0x88, 0xCD, 0x82, 0x00, 0xCE, 0xA5, 0xCC, 0x88, 0xCC, 0x80, + 0x00, 0xCE, 0xA5, 0xCC, 0x88, 0xCC, 0x81, 0x00, 0xCE, 0xA1, 0xCC, 0x93, + 0x00, 0xCE, 0xA5, 0xCD, 0x82, 0x00, 0xCE, 0xA5, 0xCC, 0x88, 0xCD, 0x82, + 0x00, 0xE1, 0xBF, 0xBA, 0xCE, 0x99, 0x00, 0xCE, 0xA9, 0xCE, 0x99, 0x00, + 0xCE, 0x8F, 0xCE, 0x99, 0x00, 0xCE, 0xA9, 0xCD, 0x82, 0x00, 0xCE, 0xA9, + 0xCD, 0x82, 0xCE, 0x99, 0x00, 0xCE, 0xA9, 0xCE, 0x99, 0x00, 0x46, 0x46, + 0x00, 0x46, 0x49, 0x00, 0x46, 0x4C, 0x00, 0x46, 0x46, 0x49, 0x00, 0x46, + 0x46, 0x4C, 0x00, 0x53, 0x54, 0x00, 0x53, 0x54, 0x00, 0xD5, 0x84, 0xD5, + 0x86, 0x00, 0xD5, 0x84, 0xD4, 0xB5, 0x00, 0xD5, 0x84, 0xD4, 0xBB, 0x00, + 0xD5, 0x8E, 0xD5, 0x86, 0x00, 0xD5, 0x84, 0xD4, 0xBD, 0x00, +}; + diff --git a/vendor/nunicode/src/libnu/strcoll.c b/vendor/nunicode/src/libnu/strcoll.c new file mode 100644 index 0000000000..d631f66343 --- /dev/null +++ b/vendor/nunicode/src/libnu/strcoll.c @@ -0,0 +1,452 @@ +#include <assert.h> + +#include <libnu/defines.h> +#include <libnu/ducet.h> +#include <libnu/strcoll.h> +#include <libnu/strcoll_internal.h> + +#if (defined NU_WITH_Z_COLLATION) || (defined NU_WITH_N_COLLATION) + +int32_t _compound_weight(int32_t w, + const char **encoded, const char *limit, + nu_read_iterator_t read, nu_compound_read_t com, + const char **tail, + nu_codepoint_weight_t weight, void *context) { + + const char *tailp = *tail; + + const char *p = *encoded; + int32_t new_w = w; + int32_t consumed = 1; /* one codepoint was consumed at the top of the stack (_nu_strcoll) */ + + while (p < limit) { + uint32_t u = 0; + + const char *np = com(p, limit, read, &u, &tailp); + new_w = weight(u, &w, context); + + /* after this point, w might hold rollback value + * and new_w holds actual weight */ + + ++consumed; + + if (new_w >= 0) { + /* if w == 0 or w == 1, then *p or *np is already pointing + * to needed place, otherwise re-read encoded in the forward + * direction preserving correctness of tail pointer */ + if (w != 0 && w != 1) { + assert(consumed + w > 1); + + np = *encoded; + tailp = *tail; + + for (int32_t i = 0; i < consumed - w; ++i) { + np = com(np, limit, read, 0, &tailp); + } + + w = 0; + } + + *encoded = (w == 0 ? np : p); + *tail = tailp; + + break; + } + + p = np; + w = new_w; + } + + if (new_w < 0) { + new_w = weight(0, &w, context); + } + + assert(new_w >= 0); + + return new_w; +} + +inline +int _nu_strcoll(const char *lhs, const char *lhs_limit, + const char *rhs, const char *rhs_limit, + nu_read_iterator_t it1, nu_read_iterator_t it2, + nu_compound_read_t com1, nu_compound_read_t com2, + nu_codepoint_weight_t weight, void *context, + ssize_t *collated_left, ssize_t *collated_right) { + + int cmp = 0; + + const char *lp = lhs, *rp = rhs; + const char *ltailp = 0, *rtailp = 0; + + uint32_t u1 = 0, u2 = 0; + + while ((lp < lhs_limit && rp < rhs_limit) + || (ltailp != 0 && rp < rhs_limit) + || (rtailp != 0 && lp < lhs_limit)) { + + lp = com1(lp, lhs_limit, it1, &u1, <ailp); + rp = com2(rp, rhs_limit, it2, &u2, &rtailp); + +#ifdef NU_DISABLE_CONTRACTIONS + /* if contractions are disabled, then same codepoints + * will produce same weights and there is no need + * to weight each, i.e. weight(u1) == weight(u2) and + * collation may proceed to next codepoints */ + if (u1 != u2) { +#endif + int32_t w1 = weight(u1, 0, context); + int32_t w2 = weight(u2, 0, context); + + if (w1 < 0) { + w1 = _compound_weight(w1, &lp, lhs_limit, + it1, com1, <ailp, + weight, context); + } + + if (w2 < 0) { + w2 = _compound_weight(w2, &rp, rhs_limit, + it2, com2, &rtailp, + weight, context); + } + + assert(w1 >= 0); + assert(w2 >= 0); + + if (w1 < w2) { + cmp = -1; + break; + } + else if (w1 > w2) { + cmp = 1; + break; + } + +#ifdef NU_DISABLE_CONTRACTIONS + } +#endif + + if (u1 == 0 || u2 == 0) { + break; + } + } + + /* collated_left and collated_right should count + * number of successfully collated bytes, not taking + * into account limits. therefore if cmp != 0, + * number of collated bytes is decreased by (at least) 1 + * and cmp is limits-fixed afterwards */ + + if (collated_left != 0) { + *collated_left = (lp - lhs) - (cmp == 0 ? 0 : 1); + } + + if (collated_right != 0) { + *collated_right = (rp - rhs) - (cmp == 0 ? 0 : 1); + } + + if (cmp == 0) { + if (rp < rhs_limit && lp >= lhs_limit) { + cmp = -1; + } + else if (lp < lhs_limit && rp >= rhs_limit) { + cmp = 1; + } + } + + return cmp; +} + +inline +const char* _nu_strchr(const char *lhs, const char *lhs_limit, + uint32_t c, nu_read_iterator_t read, + nu_compound_read_t com, + nu_casemapping_t casemap, nu_read_iterator_t casemap_read) { + + const char *p = lhs; + const char *tail = 0; + uint32_t u = 0; + + const char *rhs = 0; + + if (casemap != 0) { + rhs = casemap(c); + if (rhs != 0) { + rhs = casemap_read(rhs, &c); /* read new lead codepoint */ + } + } + + while (p < lhs_limit) { + const char *np = com(p, lhs_limit, read, &u, &tail); + + if (u == 0) { + break; + } + + if (u == c) { + if (rhs == 0) { + return p; + } + + /* rhs != 0 */ + + const char *rp = rhs; + uint32_t u2 = 0; + + do { + rp = casemap_read(rp, &u2); + + if (u2 == 0) { + return p; /* succ exit point */ + } + + if (np >= lhs_limit) { + return 0; + } + + np = com(np, lhs_limit, read, &u, &tail); + + if (u == 0) { + return 0; + } + + if (u != u2) { + break; + } + } + while (u2 != 0); + } + + p = np; + } + + return 0; +} + +inline +const char* _nu_strrchr(const char *encoded, const char *limit, + uint32_t c, nu_read_iterator_t read, + nu_compound_read_t com, + nu_casemapping_t casemap, nu_read_iterator_t casemap_read) { + + /* there is probably not much sense in finding string end by decoding it + * and then reverse read string again to find last codepoint, therefore + * this is a sequence of _nu_strchr() in forward direction + * + * please let me know if i'm wrong */ + + const char *p = encoded; + const char *last = 0; + + while (p < limit) { + p = _nu_strchr(p, limit, c, read, com, casemap, casemap_read); + + if (p == 0) { + return last; + } + + last = p; + p = read(p, 0); /* skip one codepoint and continue */ + } + + return last; +} + +inline +const char* _nu_strstr(const char *haystack, const char *haystack_limit, + const char *needle, const char *needle_limit, + nu_read_iterator_t it1, nu_read_iterator_t it2, + nu_compound_read_t com1, nu_compound_read_t com2, + nu_casemapping_t casemap, nu_read_iterator_t casemap_read, + nu_codepoint_weight_t weight, void *context) { + + uint32_t n0 = 0; + if (needle_limit != needle) { + it2(needle, &n0); + } + + if (needle_limit == needle || n0 == 0) { + return haystack; + } + + ssize_t needle_len = (needle_limit != NU_UNLIMITED + ? (needle_limit - needle) + : nu_strbytelen(needle, it2)); + + const char *h0 = haystack; + do { + h0 = _nu_strchr(h0, haystack_limit, + n0, it1, + com1, + casemap, casemap_read); + + if (h0 == 0) { + break; + } + + ssize_t collated_left = 0, collated_right = 0; + _nu_strcoll(h0, haystack_limit, needle, needle_limit, + it1, it2, + com1, com2, + weight, context, + &collated_left, &collated_right); + + /* it doesn't matter what collate result is + * if whole needle was successfully collated */ + if (collated_right >= needle_len) { + return h0; + } + + /* skip one codepoint in haystack */ + if (h0 < haystack_limit) { + h0 = it1(h0, 0); + } + } + while (h0 != 0 && h0 < haystack_limit); + + return 0; +} + +#ifdef NU_WITH_Z_COLLATION + +const char* nu_strchr(const char *encoded, uint32_t c, nu_read_iterator_t read) { + return _nu_strchr(encoded, NU_UNLIMITED, + c, read, + nu_default_compound_read, + 0, 0); +} + +const char* nu_strcasechr(const char *encoded, uint32_t c, nu_read_iterator_t read) { + return _nu_strchr(encoded, NU_UNLIMITED, + c, read, + nu_nocase_compound_read, + NU_FOLDING_FUNCTION, nu_casemap_read); +} + +const char* nu_strrchr(const char *encoded, uint32_t c, nu_read_iterator_t read) { + return _nu_strrchr(encoded, NU_UNLIMITED, + c, read, + nu_default_compound_read, + 0, 0); +} + +const char* nu_strrcasechr(const char *encoded, uint32_t c, nu_read_iterator_t read) { + return _nu_strrchr(encoded, NU_UNLIMITED, c, read, + nu_nocase_compound_read, + NU_FOLDING_FUNCTION, nu_casemap_read); +} + +int nu_strcoll(const char *s1, const char *s2, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read) { + return _nu_strcoll(s1, NU_UNLIMITED, s2, NU_UNLIMITED, + s1_read, s2_read, + nu_default_compound_read, nu_default_compound_read, + nu_ducet_weight, 0, + 0, 0); +} + +int nu_strcasecoll(const char *s1, const char *s2, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read) { + return _nu_strcoll(s1, NU_UNLIMITED, s2, NU_UNLIMITED, + s1_read, s2_read, + nu_nocase_compound_read, nu_nocase_compound_read, + nu_ducet_weight, 0, + 0, 0); +} + +const char* nu_strstr(const char *haystack, const char *needle, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read) { + return _nu_strstr(haystack, NU_UNLIMITED, needle, NU_UNLIMITED, + haystack_read, needle_read, + nu_default_compound_read, nu_default_compound_read, + 0, 0, + nu_ducet_weight, 0); +} + +const char* nu_strcasestr(const char *haystack, const char *needle, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read) { + return _nu_strstr(haystack, NU_UNLIMITED, needle, NU_UNLIMITED, + haystack_read, needle_read, + nu_nocase_compound_read, nu_nocase_compound_read, + NU_FOLDING_FUNCTION, nu_casemap_read, + nu_ducet_weight, 0); +} + +#endif /* NU_WITH_Z_COLLATION */ + +#ifdef NU_WITH_N_COLLATION + +const char* nu_strnchr(const char *encoded, size_t max_len, uint32_t c, nu_read_iterator_t read) { + return _nu_strchr(encoded, encoded + max_len, + c, read, + nu_default_compound_read, + 0, 0); +} + +const char* nu_strcasenchr(const char *encoded, size_t max_len, uint32_t c, nu_read_iterator_t read) { + return _nu_strchr(encoded, encoded + max_len, + c, read, + nu_nocase_compound_read, + NU_FOLDING_FUNCTION, nu_casemap_read); +} + +const char* nu_strrnchr(const char *encoded, size_t max_len, uint32_t c, nu_read_iterator_t read) { + return _nu_strrchr(encoded, encoded + max_len, + c, read, + nu_default_compound_read, + 0, 0); +} + +const char* nu_strrcasenchr(const char *encoded, size_t max_len, uint32_t c, + nu_read_iterator_t read) { + return _nu_strrchr(encoded, encoded + max_len, + c, read, + nu_nocase_compound_read, + NU_FOLDING_FUNCTION, nu_casemap_read); +} + +int nu_strncoll(const char *s1, size_t s1_max_len, + const char *s2, size_t s2_max_len, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read) { + return _nu_strcoll(s1, s1 + s1_max_len, s2, s2 + s2_max_len, + s1_read, s2_read, + nu_default_compound_read, nu_default_compound_read, + nu_ducet_weight, 0, + 0, 0); +} + +int nu_strcasencoll(const char *s1, size_t s1_max_len, + const char *s2, size_t s2_max_len, + nu_read_iterator_t s1_read, nu_read_iterator_t s2_read) { + return _nu_strcoll(s1, s1 + s1_max_len, s2, s2 + s2_max_len, + s1_read, s2_read, + nu_nocase_compound_read, nu_nocase_compound_read, + nu_ducet_weight, 0, + 0, 0); +} + +const char* nu_strnstr(const char *haystack, size_t haystack_max_len, + const char *needle, size_t needle_max_len, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read) { + return _nu_strstr(haystack, haystack + haystack_max_len, + needle, needle + needle_max_len, + haystack_read, needle_read, + nu_default_compound_read, nu_default_compound_read, + 0, 0, + nu_ducet_weight, 0); +} + +const char* nu_strcasenstr(const char *haystack, size_t haystack_max_len, + const char *needle, size_t needle_max_len, + nu_read_iterator_t haystack_read, nu_read_iterator_t needle_read) { + return _nu_strstr(haystack, haystack + haystack_max_len, + needle, needle + needle_max_len, + haystack_read, needle_read, + nu_nocase_compound_read, nu_nocase_compound_read, + NU_FOLDING_FUNCTION, nu_casemap_read, + nu_ducet_weight, 0); +} + +#endif /* NU_WITH_N_COLLATION */ + +#endif /* NU_WITH_Z_COLLATION || NU_WITH_N_COLLATION */ diff --git a/vendor/nunicode/src/libnu/strings.c b/vendor/nunicode/src/libnu/strings.c new file mode 100644 index 0000000000..0eda8cf08f --- /dev/null +++ b/vendor/nunicode/src/libnu/strings.c @@ -0,0 +1,89 @@ +#include <libnu/defines.h> +#include <libnu/strings.h> + +#if defined (NU_WITH_Z_STRINGS) || defined(NU_WITH_N_STRINGS) + +static ssize_t _nu_strlen(const char *encoded, const char *limit, nu_read_iterator_t it) { + ssize_t len = 0; + + const char *p = encoded; + while (p < limit) { + uint32_t u = 0; + p = it(p, &u); + + if (u == 0) { + break; + } + + ++len; + } + + return len; +} + +static ssize_t _nu_bytelen(const uint32_t *unicode, const uint32_t *limit, nu_write_iterator_t it) { + ssize_t len = 0; + + const uint32_t *p = unicode; + while (p < limit) { + if (*p == 0) { + break; + } + + /* nu_write_iterator_t will return offset relative to 0 + * which is effectively bytes length of codepoint */ + size_t byte_len = (size_t)it(*p, 0); + len += byte_len; + + ++p; + } + + return len; +} + +static ssize_t _nu_strbytelen(const char *encoded, const char *limit, nu_read_iterator_t it) { + uint32_t u = 0; + const char *p = encoded; + + while (p < limit) { + const char *np = it(p, &u); + + if (u == 0) { + return (p - encoded); + } + + p = np; + } + + return 0; +} + +#endif /* NU_WITH_N_STRINGS || NU_WITH_Z_STRINGS */ + +#ifdef NU_WITH_Z_STRINGS + +ssize_t nu_strlen(const char *encoded, nu_read_iterator_t it) { + return _nu_strlen(encoded, NU_UNLIMITED, it); +} + +ssize_t nu_bytelen(const uint32_t *unicode, nu_write_iterator_t it) { + return _nu_bytelen(unicode, NU_UNLIMITED, it); +} + +ssize_t nu_strbytelen(const char *encoded, nu_read_iterator_t it) { + return _nu_strbytelen(encoded, NU_UNLIMITED, it); +} + +#endif /* NU_WITH_Z_STRINGS */ + +#ifdef NU_WITH_N_STRINGS + +ssize_t nu_strnlen(const char *encoded, size_t max_len, nu_read_iterator_t it) { + return _nu_strlen(encoded, encoded + max_len, it); +} + +ssize_t nu_bytenlen(const uint32_t *unicode, size_t max_len, nu_write_iterator_t it) { + return _nu_bytelen(unicode, unicode + max_len, it); +} + +#endif /* NU_WITH_N_STRINGS */ diff --git a/vendor/nunicode/src/libnu/tolower.c b/vendor/nunicode/src/libnu/tolower.c new file mode 100644 index 0000000000..1ce229d370 --- /dev/null +++ b/vendor/nunicode/src/libnu/tolower.c @@ -0,0 +1,58 @@ +#include <assert.h> + +#include <libnu/casemap.h> + +#ifdef NU_WITH_TOLOWER + +#include <libnu/casemap_internal.h> +#include "gen/_tolower.c" + +/* in nu_casemap_read (UTF-8), zero-terminated */ +static const char *__nu_final_sigma = "ς"; + +const char* nu_tolower(uint32_t codepoint) { + return _nu_to_something(codepoint, NU_TOLOWER_G, NU_TOLOWER_G_SIZE, + NU_TOLOWER_VALUES_C, NU_TOLOWER_VALUES_I, NU_TOLOWER_COMBINED); +} + +const char* _nu_tolower(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context) { + + (void)(context); + + uint32_t _u = 0; + const char *np = read(encoded, &_u); + + if (u != 0) { + *u = _u; + } + + /* handling of 0x03A3 ('Σ') + * + * this is the only language-independent exception described in + * SpecialCasing.txt (Unicode 7.0) */ + + assert(nu_casemap_read == nu_utf8_read); + + if (_u == 0x03A3) { + if (np >= limit) { + *transform = __nu_final_sigma; + return np; + } + + uint32_t nu = 0; + read(np, &nu); + + if (nu == 0) { + *transform = __nu_final_sigma; + return np; + } + } + + *transform = nu_tolower(_u); + + return np; +} + +#endif /* NU_WITH_TOLOWER */ diff --git a/vendor/nunicode/src/libnu/tounaccent.c b/vendor/nunicode/src/libnu/tounaccent.c new file mode 100644 index 0000000000..ad5b269827 --- /dev/null +++ b/vendor/nunicode/src/libnu/tounaccent.c @@ -0,0 +1,57 @@ +#include <assert.h> + +#include <libnu/casemap.h> + +#ifdef NU_WITH_UNACCENT + +#include <libnu/casemap_internal.h> +#include "gen/_tounaccent.c" + +const char* nu_tounaccent(uint32_t codepoint) { + typedef struct { + uint32_t block_start; + uint32_t block_end; + } block_t; + + static const block_t blocks[] = { + { 0x0300, 0x036F }, /* Combining Diacritical Marks */ + { 0x1AB0, 0x1AFF }, /* Combining Diacritical Marks Extended */ + { 0x20D0, 0x20FF }, /* Combining Diacritical Marks for Symbols */ + { 0x1DC0, 0x1DFF }, /* Combining Diacritical Marks Supplement */ + }; + static const size_t blocks_count = sizeof(blocks) / sizeof(*blocks); + + /* check if codepoint itself is a diacritic, + * return empty string in that case + * (transform into empty string */ + assert(nu_casemap_read == nu_utf8_read); + for (size_t i = 0; i < blocks_count; ++i) { + if (codepoint >= blocks[i].block_start && codepoint <= blocks[i].block_end) { + return ""; /* return zero-terminated empty string in nu_casemap_read (utf-8) */ + } + } + + return _nu_to_something(codepoint, NU_TOUNACCENT_G, NU_TOUNACCENT_G_SIZE, + NU_TOUNACCENT_VALUES_C, NU_TOUNACCENT_VALUES_I, NU_TOUNACCENT_COMBINED); +} + +const char* _nu_tounaccent(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context) { + + (void)(limit); + (void)(context); + + uint32_t _u = 0; + const char *np = read(encoded, &_u); + + *transform = nu_tounaccent(_u); + + if (u != 0) { + *u = _u; + } + + return np; +} + +#endif /* NU_WITH_UNACCENT */ diff --git a/vendor/nunicode/src/libnu/toupper.c b/vendor/nunicode/src/libnu/toupper.c new file mode 100644 index 0000000000..fad3941e6d --- /dev/null +++ b/vendor/nunicode/src/libnu/toupper.c @@ -0,0 +1,32 @@ +#include <libnu/casemap.h> + +#ifdef NU_WITH_TOUPPER + +#include <libnu/casemap_internal.h> +#include "gen/_toupper.c" + +const char* nu_toupper(uint32_t codepoint) { + return _nu_to_something(codepoint, NU_TOUPPER_G, NU_TOUPPER_G_SIZE, + NU_TOUPPER_VALUES_C, NU_TOUPPER_VALUES_I, NU_TOUPPER_COMBINED); +} + +const char* _nu_toupper(const char *encoded, const char *limit, nu_read_iterator_t read, + uint32_t *u, const char **transform, + void *context) { + + (void)(limit); + (void)(context); + + uint32_t _u = 0; + const char *np = read(encoded, &_u); + + *transform = nu_toupper(_u); + + if (u != 0) { + *u = _u; + } + + return np; +} + +#endif /* NU_WITH_TOUPPER */ diff --git a/vendor/nunicode/src/libnu/utf8.c b/vendor/nunicode/src/libnu/utf8.c new file mode 100644 index 0000000000..c9ea0fc819 --- /dev/null +++ b/vendor/nunicode/src/libnu/utf8.c @@ -0,0 +1,97 @@ +#include <libnu/utf8.h> + +#ifdef NU_WITH_UTF8_READER +#ifdef NU_WITH_VALIDATION + +int nu_utf8_validread(const char *encoded, size_t max_len) { + int len = utf8_validread_basic(encoded, max_len); + + if (len <= 0) { + return 0; + } + + /* Unicode core spec, D92, Table 3-7 + */ + + switch (len) { + /* case 1: single byte sequence can't be > 0x7F and produce len == 1 + */ + + case 2: { + uint8_t p1 = *(const unsigned char *)(encoded); + + if (p1 < 0xC2) { /* 2-byte sequences with p1 > 0xDF are 3-byte sequences */ + return 0; + } + + /* the rest will be handled by utf8_validread_basic() */ + + break; + } + + case 3: { + uint8_t p1 = *(const unsigned char *)(encoded); + + /* 3-byte sequences with p1 < 0xE0 are 2-byte sequences, + * 3-byte sequences with p1 > 0xEF are 4-byte sequences */ + + uint8_t p2 = *(const unsigned char *)(encoded + 1); + + if (p1 == 0xE0 && p2 < 0xA0) { + return 0; + } + else if (p1 == 0xED && p2 > 0x9F) { + return 0; + } + + /* (p2 < 0x80 || p2 > 0xBF) and p3 will be covered + * by utf8_validread_basic() */ + + break; + } + + case 4: { + uint8_t p1 = *(const unsigned char *)(encoded); + + if (p1 > 0xF4) { /* 4-byte sequence with p1 < 0xF0 are 3-byte sequences */ + return 0; + } + + uint8_t p2 = *(const unsigned char *)(encoded + 1); + + if (p1 == 0xF0 && p2 < 0x90) { + return 0; + } + + /* (p2 < 0x80 || p2 > 0xBF) and the rest (p3, p4) + * will be covered by utf8_validread_basic() */ + + break; + } + + } /* switch */ + + return len; +} + +#endif /* NU_WITH_VALIDATION */ +#endif /* NU_WITH_UTF8_READER */ + +#ifdef NU_WITH_UTF8_WRITER + +char* nu_utf8_write(uint32_t unicode, char *utf8) { + unsigned codepoint_len = utf8_codepoint_length(unicode); + + if (utf8 != 0) { + switch (codepoint_len) { + case 1: *utf8 = (char)(unicode); break; + case 2: b2_utf8(unicode, utf8); break; + case 3: b3_utf8(unicode, utf8); break; + default: b4_utf8(unicode, utf8); break; /* len == 4 */ + } + } + + return utf8 + codepoint_len; +} + +#endif /* NU_WITH_UTF8_WRITER */ diff --git a/vendor/nunicode/version.txt b/vendor/nunicode/version.txt new file mode 100644 index 0000000000..6259340971 --- /dev/null +++ b/vendor/nunicode/version.txt @@ -0,0 +1 @@ +1.8 |