update harfbuzz to 10.1.0

This commit is contained in:
Sasha Szpakowski
2024-11-08 20:45:28 -04:00
parent 7ca40027e0
commit aecb572558
3449 changed files with 101770 additions and 22266 deletions
-23
View File
@@ -1,23 +0,0 @@
# Process this file with automake to produce Makefile.in
NULL =
EXTRA_DIST =
SUBDIRS =
EXTRA_DIST += \
meson.build \
benchmark-font.cc \
benchmark-map.cc \
benchmark-ot.cc \
benchmark-set.cc \
benchmark-shape.cc \
benchmark-subset.cc \
fonts \
texts \
$(NULL)
# Convenience targets:
lib:
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
-include $(top_srcdir)/git.mk
+105 -33
View File
@@ -1,17 +1,4 @@
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#include "hb-benchmark.hh"
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
@@ -21,7 +8,8 @@ struct test_input_t
const char *font_path;
} default_tests[] =
{
{true , SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"},
{false, SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"},
{true , SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf"},
{false, SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf"},
{true , SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf"},
{true , SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf"},
@@ -33,30 +21,52 @@ struct test_input_t
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
enum backend_t { HARFBUZZ, FREETYPE };
enum backend_t { HARFBUZZ, FREETYPE, CORETEXT };
enum operation_t
{
nominal_glyphs,
glyph_h_advances,
glyph_extents,
glyph_shape,
draw_glyph,
paint_glyph,
load_face_and_shape,
};
static void
_hb_move_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
_hb_move_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *)
{
float &i = * (float *) draw_data;
i += x + y;
}
static void
_hb_line_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
//static void
//_hb_quadratic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, void *) {}
_hb_line_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *)
{
float &i = * (float *) draw_data;
i += x + y;
}
static void
_hb_cubic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, float, float, void *) {}
_hb_quadratic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx, float cy, float x, float y, void *)
{
float &i = * (float *) draw_data;
i += cx + cy + x + y;
}
static void
_hb_close_path (hb_draw_funcs_t *, void *, hb_draw_state_t *, void *) {}
_hb_cubic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx1, float cy1, float cx2, float cy2, float x, float y, void *)
{
float &i = * (float *) draw_data;
i += cx1 + cy1 + cx2 + cy2 + x + y;
}
static void
_hb_close_path (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, void *)
{
float &i = * (float *) draw_data;
i += 1.0;
}
static hb_draw_funcs_t *
_draw_funcs_create (void)
@@ -64,7 +74,7 @@ _draw_funcs_create (void)
hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr);
hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr);
//hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr);
hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr);
return draw_funcs;
@@ -77,10 +87,8 @@ static void BM_Font (benchmark::State &state,
hb_font_t *font;
unsigned num_glyphs;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
num_glyphs = hb_face_get_glyph_count (face);
font = hb_font_create (face);
hb_face_destroy (face);
@@ -101,6 +109,12 @@ static void BM_Font (benchmark::State &state,
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
}
@@ -158,14 +172,67 @@ static void BM_Font (benchmark::State &state,
hb_font_get_glyph_extents (font, gid, &extents);
break;
}
case glyph_shape:
case draw_glyph:
{
hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
for (auto _ : state)
{
float i = 0;
for (unsigned gid = 0; gid < num_glyphs; ++gid)
hb_font_get_glyph_shape (font, gid, draw_funcs, nullptr);
break;
hb_font_draw_glyph (font, gid, draw_funcs, &i);
}
hb_draw_funcs_destroy (draw_funcs);
break;
}
case paint_glyph:
{
hb_paint_funcs_t *paint_funcs = hb_paint_funcs_create ();
for (auto _ : state)
{
for (unsigned gid = 0; gid < num_glyphs; ++gid)
hb_font_paint_glyph (font, gid, paint_funcs, nullptr, 0, 0);
}
hb_paint_funcs_destroy (paint_funcs);
break;
}
case load_face_and_shape:
{
for (auto _ : state)
{
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
switch (backend)
{
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
}
hb_buffer_t *buffer = hb_buffer_create ();
hb_buffer_add_utf8 (buffer, " ", -1, 0, -1);
hb_buffer_guess_segment_properties (buffer);
hb_shape (font, buffer, nullptr, 0);
hb_buffer_destroy (buffer);
hb_font_destroy (font);
}
break;
}
}
@@ -208,6 +275,9 @@ static void test_operation (operation_t op,
test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
#endif
#ifdef HAVE_CORETEXT
test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input);
#endif
}
}
@@ -233,7 +303,9 @@ int main(int argc, char** argv)
TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond);
TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
TEST_OPERATION (glyph_shape, benchmark::kMicrosecond);
TEST_OPERATION (draw_glyph, benchmark::kMicrosecond);
TEST_OPERATION (paint_glyph, benchmark::kMillisecond);
TEST_OPERATION (load_face_and_shape, benchmark::kMicrosecond);
#undef TEST_OPERATION
+53 -18
View File
@@ -1,22 +1,22 @@
/*
* Benchmarks for hb_map_t operations.
*/
#include "benchmark/benchmark.h"
#include "hb-benchmark.hh"
#include <cassert>
#include <cstdlib>
#include "hb.h"
void RandomMap(unsigned size, hb_map_t* out) {
void RandomMap(unsigned size, hb_map_t* out, hb_set_t* key_sample) {
hb_map_clear(out);
unsigned sample_denom = 1;
if (size > 10000)
sample_denom = size / 10000;
srand(size);
for (unsigned i = 0; i < size; i++) {
while (true) {
hb_codepoint_t next = rand();
if (hb_map_has (out, next)) continue;
hb_map_set (out, next, rand ());
hb_codepoint_t val = rand();
if (key_sample && val % sample_denom == 0)
hb_set_add (key_sample, next);
hb_map_set (out, next, val);
break;
}
}
@@ -27,16 +27,20 @@ static void BM_MapInsert(benchmark::State& state) {
unsigned map_size = state.range(0);
hb_map_t* original = hb_map_create ();
RandomMap(map_size, original);
RandomMap(map_size, original, nullptr);
assert(hb_map_get_population(original) == map_size);
auto needle = map_size / 2;
auto v = 0;
unsigned mask = 1;
while (mask < map_size)
mask <<= 1;
mask--;
auto needle = 0u;
for (auto _ : state) {
// TODO(garretrieger): create a copy of the original map.
// Needs a hb_map_copy(..) in public api.
hb_map_set (original, needle++, v++);
hb_map_set (original, needle++ & mask, 1);
}
hb_map_destroy(original);
@@ -44,12 +48,12 @@ static void BM_MapInsert(benchmark::State& state) {
BENCHMARK(BM_MapInsert)
->Range(1 << 4, 1 << 20);
/* Single value lookup on map of various sizes. */
static void BM_MapLookup(benchmark::State& state) {
/* Single value lookup on map of various sizes where the key is not present. */
static void BM_MapLookupMiss(benchmark::State& state) {
unsigned map_size = state.range(0);
hb_map_t* original = hb_map_create ();
RandomMap(map_size, original);
RandomMap(map_size, original, nullptr);
assert(hb_map_get_population(original) == map_size);
auto needle = map_size / 2;
@@ -61,7 +65,38 @@ static void BM_MapLookup(benchmark::State& state) {
hb_map_destroy(original);
}
BENCHMARK(BM_MapLookup)
BENCHMARK(BM_MapLookupMiss)
->Range(1 << 4, 1 << 20); // Map size
/* Single value lookup on map of various sizes. */
static void BM_MapLookupHit(benchmark::State& state) {
unsigned map_size = state.range(0);
hb_map_t* original = hb_map_create ();
hb_set_t* key_set = hb_set_create ();
RandomMap(map_size, original, key_set);
assert(hb_map_get_population(original) == map_size);
unsigned num_keys = hb_set_get_population (key_set);
hb_codepoint_t* key_array =
(hb_codepoint_t*) calloc (num_keys, sizeof(hb_codepoint_t));
hb_codepoint_t cp = HB_SET_VALUE_INVALID;
unsigned i = 0;
while (hb_set_next (key_set, &cp))
key_array[i++] = cp;
i = 0;
for (auto _ : state) {
benchmark::DoNotOptimize(
hb_map_get (original, key_array[i++ % num_keys]));
}
hb_set_destroy (key_set);
free (key_array);
hb_map_destroy(original);
}
BENCHMARK(BM_MapLookupHit)
->Range(1 << 4, 1 << 20); // Map size
+1 -6
View File
@@ -1,9 +1,4 @@
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include "hb-ot.h"
#include "hb-benchmark.hh"
static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state,
hb_script_t script,
+1 -8
View File
@@ -1,11 +1,4 @@
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
#include "hb-benchmark.hh"
void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) {
hb_set_clear(out);
+11 -18
View File
@@ -1,17 +1,4 @@
#include "benchmark/benchmark.h"
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cassert>
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#include "hb-benchmark.hh"
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
@@ -27,10 +14,18 @@ struct test_input_t
"perf/texts/fa-thelittleprince.txt",
false},
{"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
"perf/texts/fa-words.txt",
false},
{"perf/fonts/Amiri-Regular.ttf",
"perf/texts/fa-thelittleprince.txt",
false},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
"perf/texts/hi-words.txt",
false},
{"perf/fonts/Roboto-Regular.ttf",
"perf/texts/en-thelittleprince.txt",
false},
@@ -56,10 +51,8 @@ static void BM_Shape (benchmark::State &state,
{
hb_font_t *font;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (input.font_path, 0);
assert (face);
font = hb_font_create (face);
hb_face_destroy (face);
}
+96 -41
View File
@@ -1,18 +1,9 @@
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb-subset.h"
#include "hb-benchmark.hh"
enum operation_t
{
subset_codepoints,
subset_glyphs,
subset_unicodes,
instance,
};
@@ -46,6 +37,13 @@ _mplus_instance_opts[] =
{HB_TAG ('w', 'g', 'h', 't'), 800.f},
};
static const axis_location_t
_fraunces_partial_instance_opts[] =
{
{HB_TAG ('S', 'O', 'F', 'T'), 75.0f},
{HB_TAG ('W', 'O', 'N', 'K'), 0.75f},
};
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
@@ -54,25 +52,31 @@ static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
struct test_input_t
{
const char *font_path;
const unsigned max_subset_size;
unsigned max_subset_size;
const axis_location_t *instance_opts;
const unsigned num_instance_opts;
} tests[] =
unsigned num_instance_opts;
} default_tests[] =
{
{SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0},
{SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)},
{SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)},
{SUBSET_FONT_BASE_PATH "Fraunces.ttf", 900, _fraunces_partial_instance_opts, ARRAY_LEN (_fraunces_partial_instance_opts)},
#if 0
{"perf/fonts/NotoSansCJKsc-VF.ttf", 100000},
#endif
};
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
void AddCodepoints(const hb_set_t* codepoints_in_font,
unsigned subset_size,
hb_subset_input_t* input)
@@ -92,7 +96,12 @@ void AddGlyphs(unsigned num_glyphs_in_font,
{
auto *glyphs = hb_subset_input_glyph_set (input);
for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
// TODO(garretrieger): pick randomly.
if (i + 1 == subset_size &&
hb_subset_input_get_flags (input) & HB_SUBSET_FLAGS_RETAIN_GIDS)
{
hb_set_add (glyphs, num_glyphs_in_font - 1);
continue;
}
hb_set_add (glyphs, i);
}
}
@@ -101,38 +110,58 @@ void AddGlyphs(unsigned num_glyphs_in_font,
// the subsetting operations.
static hb_face_t* preprocess_face(hb_face_t* face)
{
#ifdef HB_EXPERIMENTAL_API
hb_face_t* new_face = hb_subset_preprocess(face);
hb_face_destroy(face);
return new_face;
#else
return face;
#endif
}
static hb_face_t *cached_face;
static void
free_cached_face (void)
{
hb_face_destroy (cached_face);
cached_face = nullptr;
}
/* benchmark for subsetting a font */
static void BM_subset (benchmark::State &state,
operation_t operation,
const test_input_t &test_input)
const test_input_t &test_input,
bool retain_gids)
{
unsigned subset_size = state.range(0);
hb_face_t *face;
hb_face_t *face = nullptr;
static const char *cached_font_path;
if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
face = preprocess_face (face);
if (cached_face)
hb_face_destroy (cached_face);
cached_face = hb_face_reference (face);
cached_font_path = test_input.font_path;
}
else
face = hb_face_reference (cached_face);
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
assert (input);
if (retain_gids)
hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
switch (operation)
{
case subset_codepoints:
case subset_unicodes:
{
hb_set_t* all_codepoints = hb_set_create ();
hb_face_collect_unicodes (face, all_codepoints);
@@ -149,19 +178,19 @@ static void BM_subset (benchmark::State &state,
break;
case instance:
#ifdef HB_EXPERIMENTAL_API
{
hb_set_t* all_codepoints = hb_set_create ();
hb_face_collect_unicodes (face, all_codepoints);
AddCodepoints(all_codepoints, subset_size, input);
hb_set_destroy (all_codepoints);
hb_subset_input_set_flags(input, hb_subset_input_get_flags(input) | HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS);
for (unsigned i = 0; i < test_input.num_instance_opts; i++)
hb_subset_input_pin_axis_location (input, face,
test_input.instance_opts[i].axis_tag,
test_input.instance_opts[i].axis_value);
}
#endif
break;
}
@@ -178,6 +207,7 @@ static void BM_subset (benchmark::State &state,
static void test_subset (operation_t op,
const char *op_name,
bool retain_gids,
benchmark::TimeUnit time_unit,
const test_input_t &test_input)
{
@@ -186,36 +216,61 @@ static void test_subset (operation_t op,
char name[1024] = "BM_subset/";
strcat (name, op_name);
strcat (name, strrchr (test_input.font_path, '/'));
strcat (name, "/");
const char *p = strrchr (test_input.font_path, '/');
strcat (name, p ? p + 1 : test_input.font_path);
if (retain_gids)
strcat (name, "/retaingids");
benchmark::RegisterBenchmark (name, BM_subset, op, test_input)
benchmark::RegisterBenchmark (name, BM_subset, op, test_input, retain_gids)
->Range(10, test_input.max_subset_size)
->Unit(time_unit);
}
static void test_operation (operation_t op,
const char *op_name,
const test_input_t *tests,
unsigned num_tests,
benchmark::TimeUnit time_unit)
{
for (auto& test_input : tests)
for (unsigned i = 0; i < num_tests; i++)
{
test_subset (op, op_name, time_unit, test_input);
auto& test_input = tests[i];
test_subset (op, op_name, true, time_unit, test_input);
test_subset (op, op_name, false, time_unit, test_input);
}
}
int main(int argc, char** argv)
{
#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit)
benchmark::Initialize(&argc, argv);
TEST_OPERATION (subset_glyphs, benchmark::kMillisecond);
TEST_OPERATION (subset_codepoints, benchmark::kMillisecond);
#ifdef HB_EXPERIMENTAL_API
TEST_OPERATION (instance, benchmark::kMillisecond);
#ifndef HB_NO_ATEXIT
atexit (free_cached_face);
#endif
if (argc > 1)
{
num_tests = (argc - 1) / 2;
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
for (unsigned i = 0; i < num_tests; i++)
{
tests[i].font_path = argv[1 + i * 2];
tests[i].max_subset_size = atoi (argv[2 + i * 2]);
}
}
#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit)
TEST_OPERATION (subset_glyphs, benchmark::kMicrosecond);
TEST_OPERATION (subset_unicodes, benchmark::kMicrosecond);
TEST_OPERATION (instance, benchmark::kMicrosecond);
#undef TEST_OPERATION
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright © 2024 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_BENCHMARK_HH
#define HB_BENCHMARK_HH
#include <hb-config.hh>
#include <hb.h>
#include <hb-subset.h>
#include <hb-ot.h>
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
#include <benchmark/benchmark.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
HB_BEGIN_DECLS
static inline hb_face_t *
hb_benchmark_face_create_from_file_or_fail (const char *font_path,
unsigned face_index)
{
const char *loader = getenv ("HB_FACE_LOADER");
if (loader && !*loader)
loader = nullptr;
#ifdef HAVE_FREETYPE
if (loader && !strcmp (loader, "ft"))
return hb_ft_face_create_from_file_or_fail (font_path, face_index);
#endif
#ifdef HAVE_CORETEXT
if (loader && !strcmp (loader, "coretext"))
return hb_coretext_face_create_from_file_or_fail (font_path, face_index);
#endif
if (!loader || !strcmp (loader, "ot"))
return hb_face_create_from_file_or_fail (font_path, face_index);
assert (false);
}
HB_END_DECLS
#endif /* HB_BENCHMARK_HH */
+20 -58
View File
@@ -1,62 +1,24 @@
google_benchmark = subproject('google-benchmark')
google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep')
benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc',
dependencies: [
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmarks = [
'benchmark-font.cc',
'benchmark-map.cc',
'benchmark-ot.cc',
'benchmark-set.cc',
'benchmark-shape.cc',
'benchmark-subset.cc',
]
benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc',
dependencies: [
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz, libharfbuzz_subset],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
foreach source : benchmarks
benchmark_name = source.split('.')[0]
benchmark(benchmark_name, executable(benchmark_name, source,
dependencies: [
google_benchmark_dep, freetype_dep, coretext_deps,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz, libharfbuzz_subset],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
endforeach
-25
View File
@@ -1,25 +0,0 @@
#!/bin/bash
CXX=clang++
FONT=fonts/NotoNastaliqUrdu-Regular.ttf
TEXT=texts/fa-monologue.txt
$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \
-lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \
-I../src $FLAGS $SOURCES \
-DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \
-DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \
-o hb-shape -g -O2 # -O3 \
#-march=native -mtune=native \
#-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \
#-Rpass-analysis=loop-vectorize -fsave-optimization-record
# -march=native: enable all vector instructions current CPU can offer
# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics
#sudo rm capture.syscap > /dev/null
#sysprof-cli -c "./a.out $@"
#sysprof capture.syscap
perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
#perf report -g
+27
View File
@@ -0,0 +1,27 @@
𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚
𛱇𛰣 𛰂𛱆 𛰆𛱄𛰉𛰅𛰋𛱁𛰄𛰃
𛱁𛰆𛱇𛰅𛰜 𛰅𛱄𛰈 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙 𛰅𛱄‌𛰂𛱁 𛰣𛱇‌𛰚𛱛𛰅
𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱆‌𛰚𛱁‌𛰃𛱁𛱆 𛰅𛱄‌𛰂𛱁 𛰜𛰅𛱂𛱆 𛰜𛰃𛱂‌𛰆𛱄͏͏͏, 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜; 𛰂𛱆 𛰚𛱁𛱋‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰚𛱁‌𛱞‌𛰃𛰅𛱁, 𛰂𛱛͏͏͏𛰜 𛰚𛱁𛱋‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱇𛰆𛱇𛰂 𛰅𛱄‌𛰂𛱁 𛰂𛱁‌𛱊𛱁 𛰂𛱆 𛱜‌𛱜 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛱆𛰂‌𛰜𛱛𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰅‌𛰃𛱂 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜: 𛱛‌𛰅𛱛𛰅 𛰚𛰜𛱁𛱆‌𛰅𛱁 𛱇𛰆𛱄͏͏͏ 𛰚𛱁‌𛰚𛱇𛰣. 𛱁‌𛱊𛱁𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱇𛰙 𛰅𛱄‌𛰂𛱁 𛱇𛰛𛱇𛰂𛰃 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰃𛱚𛰚 𛰙𛱇𛰋𛱄𛱆 𛰂𛱆 𛱄͏͏͏𛰄𛱆𛰋. 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅, 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰅‌𛰃𛱂 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛱄‌𛰂𛱁 𛱂𛰄𛰋𛱇𛰅𛱁. 𛱞𛰀𛰃 𛰜𛰄𛱆𛰚𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜; 𛰂𛱆 𛱇𛰆𛱇𛰂 𛰅𛱄‌𛰂𛱁 𛰜𛰄𛱆𛰚𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛱇𛰆𛱇‌𛰀𛱇, 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁𛰛 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛱆𛰅‌𛰃𛱂 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰜𛰄𛱆𛰚𛰅𛰜 𛰙𛱁𛰛 𛰃𛱄𛰙‌𛰃𛱄𛰙.
𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱇𛰆𛱇𛰂 𛰂𛱛͏͏͏𛰜 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰙𛱁‌𛰙𛱛𛰅 𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛱆𛰀𛰃 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱇𛰜‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱇𛰆𛱄͏͏͏ 𛰚𛱁𛱋‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱁‌𛰅𛱜; 𛰅𛱄‌𛰂𛱆𛰃 𛰚𛱁𛱋‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰂𛱛͏͏͏𛰜 𛱁‌𛱑 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰂𛱆 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰊𛱁𛰋𛰈𛱇𛰚 𛰂𛱆 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛰂𛱛͏͏͏𛰜 𛰅𛱁‌𛰅𛱜, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱇𛰜‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜. 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰈𛰋𛱇𛰃 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄‌𛰆𛱁𛰚 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜: 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱁‌𛰃𛱂 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱜‌𛱜 𛱆𛰅‌𛰃𛱂 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚. 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰜𛱇𛱂‌𛰀𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰂𛱆 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛱆𛰂‌𛰜𛱛𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱁‌𛱊𛱁𛰜 𛰜𛰃𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇. 𛱇𛰆𛱄͏͏͏ 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰙𛱄𛰅𛰜𛰃 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛰂𛱆 𛱇𛰆𛱇𛰂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱜͏͏͏𛰛 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱇𛰆𛱄͏͏͏ 𛱆𛰅‌𛰃𛱂 𛰜𛱁‌𛰆𛱇𛰅𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛰃𛱇𛰅. 𛰂𛱛͏͏͏𛰜 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛱜 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰀𛱚𛰜, 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱜‌𛱜. 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱛‌𛰅𛱛𛰅. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛰙𛱇𛰋𛰜𛱇 𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛱜 𛰂𛱆 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏. 𛱇𛰆𛱄͏͏͏ 𛱁‌𛱑 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜. 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱄‌𛰂𛱁 𛰅𛱁𛰀 𛰣𛱁‌𛰅𛱄 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜.
𛱆𛰀𛰃 𛰜𛱄𛰚 𛱁‌𛱑 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱄𛰚 𛱄𛱇‌𛰀𛱁𛰃. 𛱇𛰆𛱄͏͏͏ 𛰅𛱁‌𛰅𛱜 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱄‌𛰂𛱁 𛱄𛱇‌𛰀𛱁𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱂‌𛰙𛱁‌𛰚𛱜͏͏𛰜: 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱜‌𛱜 𛱆𛰅‌𛰃𛱂 𛱁𛰆‌𛰅𛱆 𛰣𛱁‌𛰅𛱄 𛰂𛱆 𛰙𛱁‌𛰅𛱛𛰅 𛰃𛰆𛱛𛰜 𛰅𛱁‌𛰙𛱄‌𛰜𛱁𛰅. 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱇𛰆𛱇‌𛰀𛱇. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰜𛰅𛱛‌𛰅𛱛𛰙 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛰃𛱒‌𛱇𛰆 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰂𛱆𛰚𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰂𛱆 𛰙𛱛𛰜‌𛰙𛱛𛰜 𛰆𛱂‌𛰃𛱇𛰃, 𛰅𛱁𛰆𛱂‌𛰅𛱁𛰆𛱂, 𛰙𛱁𛰚 𛰆𛱂‌𛰙𛱛‌𛰃𛱄͏͏͏, 𛰂𛱆 𛰆𛱁𛱆𛰚𛰜. 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰆𛱄͏͏͏‌𛰆𛱄͏͏͏ 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰜𛱇𛱂‌𛰂𛱛𛰃𛰆 𛰅𛱄‌𛰂𛱁 𛰙𛱄𛰅𛰜𛰃 𛰀𛱄𛰋𛰚 𛰂𛱆 𛱆𛰀𛰃 𛰅𛱄‌𛱑‌𛰅𛱄‌𛱑 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰀𛱄𛰋𛰚.
𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚; 𛱇𛰆𛱄͏͏͏ 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰙𛱁‌𛰙𛱁 𛰂𛱆 𛰂𛱁‌𛰂𛱁, 𛰅𛱄‌𛰂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱂‌𛰚𛱁𛰜 𛰃𛰆𛱇𛰆 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃. 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱁‌𛱊𛱁𛰜 𛰜𛱇𛰅 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱁 𛰂𛱆 𛰂𛱁‌𛰂𛱁, 𛰂𛱆 𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱁‌𛰙𛱛𛰅 𛰃𛰆𛱛𛰜 𛱊𛱁‌𛰅𛱁 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛱁𛰆‌𛰃𛱂. 𛰅𛱁‌𛰚𛱁‌𛱞 𛰃𛱂‌𛰚𛱁𛰜 𛱁‌𛱊𛱁𛰜 𛰃𛱇‌𛰅𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛱆 𛰃𛱇‌𛰅𛱆 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛰆𛱇. 𛰅𛱁‌𛰅𛱜, 𛱇𛰆𛱄͏͏͏ 𛱁‌𛱑 𛱊𛱁‌𛰅𛱁 𛰅𛰋𛱁𛱆. 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰚𛱇𛰙 𛰙𛱇𛰚𛱇𛰜 𛰃𛰆𛱛𛰜 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰂𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅.
𛰣𛱁‌𛰅𛱄 𛰃𛰆𛱛𛰚 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚 𛰅𛱁𛰀 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚, 𛰂𛱆 𛱞𛰅 𛰅𛱁‌𛰃𛱂 𛰙𛱇𛰚𛱇𛰜 𛰃𛰆𛱁𛰂 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰅𛰋𛱁𛱆 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜, 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚, 𛰂𛱆 𛱞𛰀𛰃 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰀𛱚𛰜 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇. 𛰂𛱛͏͏͏𛰜 𛰙𛱇𛰚𛱇𛰜 𛰔𛱄‌𛰆𛱁𛰚 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙, 𛱊𛱁‌𛰅𛱁 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰋𛱁𛱆. 𛰣𛱇 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆. 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰜𛱁‌𛰀𛱁‌𛰆𛱇 𛱊𛱁‌𛰅𛱁 𛰆𛱇‌𛰙𛱁 𛰅𛱄‌𛰂𛱁 𛰜𛰅𛱂𛱆 𛰂𛱆 𛱜‌𛱜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰆𛱂‌𛰆𛱁𛰚𛰊 𛰜𛰃𛱒‌𛱇𛰆: 𛱇𛰆𛱄͏͏͏ 𛱛‌𛰅𛱛𛰅 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛱆𛰅‌𛰃𛱂 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜. 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰜𛱁‌𛰀𛱁‌𛰆𛱇: 𛱛‌𛰅𛱛𛰅 𛰜𛰅𛱂𛱆 𛰂𛱆 𛰅𛰆𛱚𛰈𛰜 𛰣𛱁‌𛰅𛱄 𛰀𛰆𛱄𛱆‌𛰙𛱁. 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱛‌𛰅𛱛𛰅. 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛰜𛰃𛱒‌𛱇𛰆, 𛱛‌𛰅𛱛𛰅 𛰅𛰆𛱚𛰈𛰜 𛰣𛱁‌𛰅𛱄 𛰅𛱁‌𛰅𛱜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰙𛱁‌𛱞𛰣: 𛰅𛱁‌𛰅𛱜 𛱁‌𛱑 𛰙𛱁‌𛱞𛰣 𛰣𛱁‌𛰅𛱄 𛰙𛱇𛰅𛰜𛰃 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃. 𛰂𛱆 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛱆𛰅‌𛰃𛱂 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛰃𛱛͏͏͏‌𛰙𛱁𛰣 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁…
𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁𛰛 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛰂𛱆 𛱞𛰅 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱞𛰀𛰃 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛰂𛱆 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰣𛱁‌𛰅𛱄 𛰅𛱜͏͏͏𛰛: 𛱇𛰆𛱄͏͏͏ 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚. 𛰅𛱄‌𛰂𛱁 𛰅𛱁‌𛰚𛱁‌𛱞 𛰀𛱚𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏: 𛱁‌𛱊𛱁𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰂𛱆 𛰃𛱂‌𛰚𛱁𛰜, 𛰃𛰆𛱇𛰆, 𛰆𛱇‌𛰊𛰆𛱇, 𛰆𛱇‌𛰅𛰋𛱇𛰙, 𛰃𛰆𛱇𛰆. 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚, 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚, 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱁𛰂‌𛰛𛱜‌𛰆𛱂 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰅𛰆𛱛͏͏͏‌𛰚𛱁𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰂𛱁‌𛰃𛰆𛱁𛰣 𛰆𛱂‌𛰂𛱆‌𛰆𛱇‌𛰃𛱁𛰜 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛱜‌𛱜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰂𛱆 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰥𛱇𛰅‌𛰥𛱇𛰅. 𛰂𛱆 𛱆𛰀𛰃 𛰙𛱁𛰚, 𛱊𛱁‌𛰅𛱁 𛰚𛱇𛰙 𛰚𛱇𛰑 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱆‌𛰂𛱁, 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 “𛰃𛰆𛱛𛰜 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰃𛰆𛱁𛰂 𛱛‌𛰅𛱛𛰅 𛰆𛱂‌𛰂𛱆‌𛰆𛱇‌𛰃𛱁𛰜”. 𛰂𛱆 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛰂𛱆 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛱇𛰆𛱇𛰂 𛱁‌𛱑 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛰂𛱆 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰃𛱇‌𛰅𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰋𛰃 𛰀𛱚𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱞𛰀𛰃 𛰇𛱁𛰋𛰅𛱆𛰂 𛱊𛱁‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚 𛱁𛰃𛱁𛰆 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛰆𛱁𛰜𛰃 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛱊𛱁‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛰆𛱂‌𛰀𛱁‌𛰚𛱇 𛰅𛱄‌𛰂𛱁 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜, 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰜𛰃𛱇𛰅. 𛰃𛰆𛱂‌𛱜 𛱛‌𛰅𛱛𛰅 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰋𛱚𛰚 𛱛‌𛰅𛱛𛰅 𛰀𛱚𛰜. 𛰙𛱄𛰅𛰜𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱆𛰙‌𛰃𛱂 𛰅𛱄‌𛰂𛱁 𛰙𛱄𛰅𛰜𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰋𛱚𛰚. 𛰅𛱁‌𛰅𛱜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰙𛱁‌𛱞𛰣 𛰃𛱂‌𛰙𛱁‌𛰚𛱜͏͏𛰜. 𛱇𛰆𛱄͏͏͏ 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄𛰙‌𛰃𛱁𛰅𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰚𛱁‌𛱞‌𛰃𛰅𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚. 𛰈𛰋𛱇𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱜͏͏͏𛰛 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛱇‌𛰅𛱆 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱄𛰋𛰃 𛰀𛱚𛰜 𛱊𛱁‌𛰅𛱁 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛰆𛱂‌𛰀𛱁‌𛰚𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜 𛰂𛱆 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇.
𛰅𛱁‌𛰅𛱜, 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱛‌𛰅𛱛𛰅 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰣𛱁‌𛰅𛱄 𛰜𛱁‌𛰆𛱇𛰅𛰜, 𛰂𛱆 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰜𛰆𛱇𛰂. 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰊𛱆𛰃‌𛱄͏͏͏𛰂 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚: 𛰀𛱜! 𛱞𛰀𛰃 𛰅𛱁‌𛰚𛱁‌𛱞 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰀𛱚𛰜! 𛱁‌𛱊𛱁𛰜 𛰂𛱆 𛰃𛱂‌𛰚𛱁𛰜, 𛰃𛰆𛱇𛰆, 𛰆𛱇‌𛰊𛰆𛱇, 𛰆𛱇‌𛰅𛰋𛱇𛰙, 𛰂𛱆 𛰃𛰅𛱄𛰂. 𛱇𛰆𛱄͏͏͏ 𛱆𛰀𛰃 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏. 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰊𛰋𛱇𛰜 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰂𛱛͏͏͏𛰜, 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰃𛰆𛱛𛰜 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁. 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅, 𛰂𛱆 𛰃𛰆𛱁𛰂 𛰜𛰅𛱛‌𛰅𛱛𛰙 𛰃𛱄𛰙‌𛰃𛱄𛰙. 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚 𛱞𛰀𛰃 𛱊𛱁‌𛰅𛱁 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱁𛰂‌𛰛𛱜‌𛰆𛱂 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜. 𛱞𛰅 𛰅𛱁𛰚‌𛰜𛱇𛰀 𛱁𛰚‌𛰅𛱁‌𛰃𛱇 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰅𛱆‌𛰆𛱂‌𛰂𛱂𛱆 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜. 𛰂𛱆 𛰅𛱁‌𛰚𛱁‌𛱞 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱆𛰀𛰃 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅: 𛱇𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰃𛱇‌𛰅𛱆 𛰙𛱁𛰅‌𛰙𛱁𛰅 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰜𛱄𛰚, 𛰂𛱆 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛱛‌𛰅𛱛𛰅. 𛰙𛱄𛰅𛰜𛰃 𛰜𛱄𛰚 𛱛‌𛰅𛱛𛰅 𛰊𛰋𛱇𛰜 𛰂𛱆 𛰆𛱇‌𛰜𛱇 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛱇𛰆𛱄͏͏͏ 𛰃𛱇‌𛰅𛱆 𛰙𛱁𛰅‌𛰙𛱁𛰅: 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛱞𛰅 𛰜𛱁‌𛱊𛱁 𛰅𛱄‌𛰂𛱁 𛰂𛱁‌𛱊𛱁 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰜𛱄𛰚.
𛰅𛱄‌𛰂𛱆𛰃 𛰅𛱁‌𛰚𛱁‌𛱞 𛱆𛰀𛰃 𛰜𛱄𛰚‌𛰈𛱇 𛰂𛱆 𛱛𛰆𛰑𛱁𛰋 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰚𛱁‌𛰚𛱇𛰣 𛱇𛰆𛱄͏͏͏ 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅. 𛰃𛱂‌𛰚𛱁𛰜 𛰚𛱇𛰑 𛱜‌𛱜 𛰂𛱛͏͏͏𛰜, 𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰅𛱁𛰀 𛰣𛱁‌𛰅𛱄 𛱇𛰆𛱄͏͏͏ 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛱇𛰆𛱄͏͏͏ 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰚𛱁‌𛰚𛱇𛰣 𛱛‌𛰅𛱛𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚. 𛰅𛱄‌𛰂𛱆𛰃 𛱆𛰀𛰃 𛱞𛰀𛰃 𛰜𛱄𛰚‌𛰈𛱇 𛰂𛱆 𛰃𛱂‌𛱇𛱇 𛰅𛱄‌𛰂𛱁 𛰃𛱚𛰚 𛰙𛱁‌𛰙𛱛𛰅 𛰃𛱄𛰙‌𛰃𛱄𛰙 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰙𛱄𛰅𛰜𛰃 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙. 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱂‌𛰃𛱜͏͏͏ 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰛𛱁𛰚𛰊 𛰂𛱆 𛰑𛱛𛰆 𛰂𛱛͏͏͏𛰜 𛱞𛰀𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣. 𛰛𛱁𛰚𛰊 𛰙𛱁‌𛰙𛱛𛰅 𛰣𛱇𛰅‌𛰙𛱇𛰚 𛱆𛰅‌𛰃𛱁𛰜 𛰂𛱆 𛰑𛱛𛰆 𛱊𛱁‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰅𛱑𛰃 𛰜𛰃𛱄𛰚. 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛰀𛱁‌𛰆𛱁𛰅 𛱛‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛱊𛱁‌𛰅𛱁 𛰆𛱂‌𛰂𛱄𛰋𛰃, 𛰅𛱄‌𛰂𛱆𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰚𛱁‌𛰚𛱇𛰣 𛱛‌𛰅𛱛𛰅: 𛰙𛱄𛰅𛰜𛰃 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰇𛱄𛰚 𛰙𛱆𛰃‌𛰆𛱂𛱆𛰃 𛰅𛱄‌𛰂𛱁 𛱇𛰆𛱇‌𛰀𛱇, 𛰂𛱆 𛰅𛱄‌𛰂𛱁 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰃𛱂‌𛰚𛱁𛰜 𛱁‌𛱑 𛰇𛱆‌𛰃𛱇𛰆 𛰅𛱛‌𛰆𛱇 𛰋𛱚𛰚.
𛱊𛱁‌𛱜 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛱄‌𛰂𛱁 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃. 𛰜𛱁𛰑, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰃𛱇‌𛰆𛱇‌𛰅𛱛𛰙, 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰚𛱁‌𛰙𛱄𛰅𛰜𛰃 𛰚𛱇𛰑, 𛱛‌𛰅𛱛𛰅 𛰙𛱁𛰚 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱛𛰜 𛰚𛱁‌𛰚𛱇𛰣 𛰂𛱆‌𛰂𛱁; 𛰅𛱁‌𛰚𛱁‌𛱞 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱁𛰜𛰅 𛱄𛰆‌𛰙𛱁𛰚 𛰅𛰋𛱁𛰚𛱄𛰚 𛰂𛱆 𛰛𛱁𛰚𛰊 𛰂𛱆 𛰑𛱛𛰆. 𛱞𛰀𛰃 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱁𛰜𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛱁𛰃𛱁𛰆, 𛰇𛱁𛰋𛰅𛱆𛰂 𛱊𛱁‌𛰅𛱁 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱁𛰚, 𛰂𛱆 𛰂𛱁‌𛰃𛰆𛱁𛰣 𛰅𛱁𛰚‌𛰈𛱇 𛰅𛱄‌𛰂𛱁 𛱊𛱁‌𛰅𛱁. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰙𛱁‌𛰜𛱁‌𛰣𛱇 𛱄𛰆‌𛰙𛱁𛰚 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰅𛰆𛱛𛰣‌𛰙𛱇𛰚, 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙, 𛰅𛱁‌𛰃𛱂 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰙𛱇𛰚𛱇𛰜 𛰂𛱆 𛱊𛱁‌𛰅𛱁 𛰃𛰆𛱇𛰆 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜, 𛰅𛱁‌𛰃𛱂 𛰙𛱇𛰚𛱇𛰜 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆, 𛰅𛱁‌𛰃𛱂 𛰜𛰅𛱂𛱆 𛰂𛱛͏͏͏𛰜 𛱊𛱁‌𛰅𛱁 𛰜𛰃𛱒‌𛱇𛰆, 𛱆𛰅‌𛰃𛱂 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰂𛱛‌𛰆𛱂‌𛰅𛰆𛱇 𛰅𛱁𛰀 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁𛰛 𛱛𛰆𛰑𛱁𛰋 𛰃𛱚𛰚, 𛰂𛱆 𛱆𛰅‌𛰃𛱂 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰃𛰆𛱁𛰂 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰃𛱂‌𛰚𛱁𛰜 𛰀𛱚𛰜 𛰅𛱆‌𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰜𛰃𛱇𛰅 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰅𛱁𛰆‌𛰃𛱁𛰛 𛱇𛰆𛱇‌𛰀𛱇.
𛰅𛱄‌𛰂𛱆𛰃 𛱛‌𛰅𛱛𛰅, 𛰃𛱂‌𛱇𛱇 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰙𛱁‌𛰙𛱛𛰅 𛱁‌𛱊𛱁𛰜 𛰀𛰆𛱄𛱆‌𛰙𛱁 𛰆𛱄͏͏͏: 𛰅𛱁‌𛰚𛱁‌𛱞 𛰅𛱄‌𛰂𛱁 𛰀𛱁𛰑𛱇𛰊 𛰙𛱁‌𛰅𛱛𛰅 𛰀𛱚𛰜 𛰂𛱆 𛱛‌𛰅𛱛𛰅 𛰃𛱇‌𛰆𛱇‌𛰅𛱄𛰙 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰅𛱛‌𛰆𛱇 𛰅𛱄‌𛰂𛱁 𛰚𛱇𛰋 𛱇𛰆𛱇‌𛰀𛱇 𛰅𛱜‌𛰚𛱇‌𛰜𛱇𛰙 𛱁‌𛱑 𛱜‌𛱜 𛰅𛱄‌𛰂𛱁 𛱛‌𛰅𛱛𛰅 𛰆𛱄͏͏͏. 𛰅𛰆𛱁𛰜‌𛰅𛱁 𛰙𛱁‌𛰙𛱛𛰅 𛱛‌𛰅𛱛𛰅 𛰆𛱄͏͏͏: 𛱞𛰅 𛰃𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜 𛰅𛰆𛱁𛰅‌𛰜𛰃𛱂 𛰙𛱁‌𛰙𛱛𛰅 𛰙𛱇𛰙‌𛰆𛱛𛰜 𛰂𛱛͏͏͏𛰜‌𛰂𛱛͏͏͏𛰜.
𛰅𛱄‌𛰂𛱆𛰃 𛰅𛱁‌𛰅𛱜 𛱛‌𛰅𛱛𛰅 𛰜𛱇𛱇‌𛰜𛱇𛰙
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff