From 58ab8d9227008081c23a9f2265d385faf58c97f8 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 15:54:21 +0300 Subject: [PATCH 01/11] create py file --- novikovsd/428 | 0 novikovsd/hashtab.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 novikovsd/428 create mode 100644 novikovsd/hashtab.py diff --git a/novikovsd/428 b/novikovsd/428 new file mode 100644 index 0000000..e69de29 diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py new file mode 100644 index 0000000..e69de29 From 706e7b5e7fb8aab1f472a9ad466817f177e95623 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:18:52 +0000 Subject: [PATCH 02/11] created linked list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit созданы функции добавления, удаления, изменения и ввода даынных для связонного списка --- novikovsd/hashtab.py | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index e69de29..ef0f54f 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -0,0 +1,52 @@ +import time +import random +import csv +import os +import sys + + +def ll_insert(head, name, phone): + curr = head + while curr is not None: + if curr['name'] == name: + curr['phone'] = phone + return head + curr = curr['next'] + # Вставка в начало (проще и быстрее) + new_node = {'name': name, 'phone': phone, 'next': head} + return new_node + + +def ll_find(head, name): + curr = head + while curr is not None: + if curr['name'] == name: + return curr['phone'] + curr = curr['next'] + return None + + +def ll_delete(head, name): + if head is None: + return None + if head['name'] == name: + return head['next'] + prev = head + curr = head['next'] + while curr is not None: + if curr['name'] == name: + prev['next'] = curr['next'] + return head + prev = curr + curr = curr['next'] + return head + + +def ll_list_all(head): + entries = [] + curr = head + while curr is not None: + entries.append((curr['name'], curr['phone'])) + curr = curr['next'] + entries.sort(key=lambda x: x[0]) + return entries \ No newline at end of file From 132e7e049b5bbc0e94ab1e80778e91db40c69ca5 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:21:49 +0000 Subject: [PATCH 03/11] hash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit реализована хэш таблица, с помощью функций отсартировки, удаления, поиска, вставки/обновления. добавлена глубина рекурсиидля bst удаления --- novikovsd/hashtab.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index ef0f54f..c17880f 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -4,6 +4,7 @@ import csv import os import sys +sys.setrecursionlimit(30000) def ll_insert(head, name, phone): curr = head @@ -12,7 +13,6 @@ def ll_insert(head, name, phone): curr['phone'] = phone return head curr = curr['next'] - # Вставка в начало (проще и быстрее) new_node = {'name': name, 'phone': phone, 'next': head} return new_node @@ -49,4 +49,40 @@ def ll_list_all(head): entries.append((curr['name'], curr['phone'])) curr = curr['next'] entries.sort(key=lambda x: x[0]) + return entries + + def _hash(name, bucket_count): + h = 0 + for ch in name: + h = (h * 31 + ord(ch)) % bucket_count + return h + + +def ht_create(bucket_count=2000): + return [None] * bucket_count + + +def ht_insert(buckets, name, phone): + idx = _hash(name, len(buckets)) + buckets[idx] = ll_insert(buckets[idx], name, phone) + + +def ht_find(buckets, name): + idx = _hash(name, len(buckets)) + return ll_find(buckets[idx], name) + + +def ht_delete(buckets, name): + idx = _hash(name, len(buckets)) + buckets[idx] = ll_delete(buckets[idx], name) + + +def ht_list_all(buckets): + entries = [] + for head in buckets: + curr = head + while curr is not None: + entries.append((curr['name'], curr['phone'])) + curr = curr['next'] + entries.sort(key=lambda x: x[0]) return entries \ No newline at end of file From 9d935dc1f9332c49e9dcfbaa6f30307b8eb6784f Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:24:43 +0000 Subject: [PATCH 04/11] bin tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit реализовано двоичное дерево с помощью функций вставки/обновления, возвращения корня, итеративного поиска, поиска узла с минимальным ключем, рекурсивного удаления, центрированного обхода --- novikovsd/hashtab.py | 73 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index c17880f..2c0aec8 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -85,4 +85,75 @@ def ht_list_all(buckets): entries.append((curr['name'], curr['phone'])) curr = curr['next'] entries.sort(key=lambda x: x[0]) - return entries \ No newline at end of file + return entries + +def bst_insert(root, name, phone): + new_node = {'name': name, 'phone': phone, 'left': None, 'right': None} + if root is None: + return new_node + + parent = None + curr = root + while curr is not None: + parent = curr + if name < curr['name']: + curr = curr['left'] + elif name > curr['name']: + curr = curr['right'] + else: + curr['phone'] = phone + return root + + if name < parent['name']: + parent['left'] = new_node + else: + parent['right'] = new_node + return root + + +def bst_find(root, name): + while root is not None: + if name == root['name']: + return root['phone'] + elif name < root['name']: + root = root['left'] + else: + root = root['right'] + return None + + +def _bst_min_node(node): + while node and node['left'] is not None: + node = node['left'] + return node + + +def bst_delete(root, name): + if root is None: + return None + if name < root['name']: + root['left'] = bst_delete(root['left'], name) + elif name > root['name']: + root['right'] = bst_delete(root['right'], name) + else: + if root['left'] is None: + return root['right'] + if root['right'] is None: + return root['left'] + min_node = _bst_min_node(root['right']) + root['name'] = min_node['name'] + root['phone'] = min_node['phone'] + root['right'] = bst_delete(root['right'], min_node['name']) + return root + + +def bst_list_all(root): + def inorder(node, res): + if node is None: + return + inorder(node['left'], res) + res.append((node['name'], node['phone'])) + inorder(node['right'], res) + result = [] + inorder(root, result) + return result \ No newline at end of file From a740a6cb6b7555f806241b1fd6fda56284ec4b86 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:26:04 +0000 Subject: [PATCH 05/11] data def MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit создана функция, создающая тестовый набор записей --- novikovsd/hashtab.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index 2c0aec8..c06b751 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -156,4 +156,11 @@ def bst_list_all(root): inorder(node['right'], res) result = [] inorder(root, result) - return result \ No newline at end of file + return result + + def generate_test_data(n=10000): + records = [(f"User_{i:05d}", f"+7-999-{i:05d}") for i in range(n)] + records_sorted = records[:] + records_shuffled = records[:] + random.shuffle(records_shuffled) + return records_sorted, records_shuffled \ No newline at end of file From 859ee847dd2ccc4756842cb009a236277cf213d6 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:29:20 +0000 Subject: [PATCH 06/11] mes func MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit созданы измерительные функции для каждого типа данных --- novikovsd/hashtab.py | 58 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index c06b751..45dc225 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -158,9 +158,63 @@ def bst_list_all(root): inorder(root, result) return result - def generate_test_data(n=10000): +def generate_test_data(n=10000): records = [(f"User_{i:05d}", f"+7-999-{i:05d}") for i in range(n)] records_sorted = records[:] records_shuffled = records[:] random.shuffle(records_shuffled) - return records_sorted, records_shuffled \ No newline at end of file + return records_sorted, records_shuffled + +def measure_insert(struct_name, records): + start = time.perf_counter() + if struct_name == "LinkedList": + head = None + for name, phone in records: + head = ll_insert(head, name, phone) + obj = head + elif struct_name == "HashTable": + buckets = ht_create(bucket_count=2000) + for name, phone in records: + ht_insert(buckets, name, phone) + obj = buckets + elif struct_name == "BST": + root = None + for name, phone in records: + root = bst_insert(root, name, phone) + obj = root + else: + raise ValueError(f"Unknown structure: {struct_name}") + elapsed = time.perf_counter() - start + return elapsed, obj + +def measure_find(obj, struct_name, existing_names, nonexisting_names): + start = time.perf_counter() + for name in existing_names: + if struct_name == "LinkedList": + ll_find(obj, name) + elif struct_name == "HashTable": + ht_find(obj, name) + else: + bst_find(obj, name) + for name in nonexisting_names: + if struct_name == "LinkedList": + ll_find(obj, name) + elif struct_name == "HashTable": + ht_find(obj, name) + else: + bst_find(obj, name) + return time.perf_counter() - start + +def measure_delete(obj, struct_name, names_to_delete): + start = time.perf_counter() + if struct_name == "LinkedList": + for name in names_to_delete: + obj = ll_delete(obj, name) + elif struct_name == "HashTable": + for name in names_to_delete: + ht_delete(obj, name) + else: + for name in names_to_delete: + obj = bst_delete(obj, name) + elapsed = time.perf_counter() - start + return elapsed, obj \ No newline at end of file From 52a5aa8fc66ce9297a2f8604898963e1ed8ef042 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:34:12 +0000 Subject: [PATCH 07/11] FINISH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit создана функция, проводящая замеры, функция сохраняющая замеры --- novikovsd/hashtab.py | 88 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index 45dc225..358d22d 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -217,4 +217,90 @@ def measure_delete(obj, struct_name, names_to_delete): for name in names_to_delete: obj = bst_delete(obj, name) elapsed = time.perf_counter() - start - return elapsed, obj \ No newline at end of file + return elapsed, obj + +def run_experiment(n=10000, repeats=5): + records_sorted, records_shuffled = generate_test_data(n) + existing_names = [name for name, _ in records_sorted[:100]] + nonexisting_names = [f"None_{i}" for i in range(10)] + all_names = [name for name, _ in records_sorted] + + structures = ["LinkedList", "HashTable", "BST"] + modes = [("shuffled", records_shuffled), ("sorted", records_sorted)] + + results = [] + for struct_name in structures: + for mode_name, records in modes: + for rep in range(repeats): + insert_time, obj = measure_insert(struct_name, records) + results.append([struct_name, mode_name, "insert", rep+1, insert_time]) + + find_time = measure_find(obj, struct_name, existing_names, nonexisting_names) + results.append([struct_name, mode_name, "find", rep+1, find_time]) + + random.seed(rep) + to_delete = random.sample(all_names, 50) + delete_time, obj = measure_delete(obj, struct_name, to_delete) + results.append([struct_name, mode_name, "delete", rep+1, delete_time]) + + return results + +def save_results_to_csv(results, filename="docs/data/results.csv"): + os.makedirs(os.path.dirname(filename), exist_ok=True) + with open(filename, 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(["Structure", "Mode", "Operation", "Repeat", "Time_sec"]) + writer.writerows(results) + print(f"Результаты сохранены в {filename}") + + +def aggregate_results(results): + from collections import defaultdict + agg = defaultdict(list) + for row in results: + struct, mode, op, rep, t = row + agg[(struct, mode, op)].append(t) + means = {k: sum(v)/len(v) for k, v in agg.items()} + return means + + +def plot_results(means, output_dir="docs"): + try: + import matplotlib.pyplot as plt + import numpy as np + except ImportError: + print("Matplotlib не установлен. Графики не построены.") + return + + operations = ["insert", "find", "delete"] + structures = ["LinkedList", "HashTable", "BST"] + modes = ["shuffled", "sorted"] + + fig, axes = plt.subplots(1, 3, figsize=(15, 5)) + for idx, op in enumerate(operations): + ax = axes[idx] + x = np.arange(len(structures)) + width = 0.35 + shuffled_means = [means.get((struct, "shuffled", op), 0) for struct in structures] + sorted_means = [means.get((struct, "sorted", op), 0) for struct in structures] + ax.bar(x - width/2, shuffled_means, width, label='случайный порядок', color='skyblue') + ax.bar(x + width/2, sorted_means, width, label='отсортированный порядок', color='salmon') + ax.set_xticks(x) + ax.set_xticklabels(structures, rotation=15) + ax.set_ylabel('Время (сек)') + ax.set_title(f'{op.upper()}') + ax.legend() + ax.grid(axis='y', linestyle='--', alpha=0.7) + + plt.tight_layout() + plt.savefig(os.path.join(output_dir, "comparison.png"), dpi=150) + plt.show() + +if __name__ == "__main__": + results = run_experiment(n=10000, repeats=5) + save_results_to_csv(results) + means = aggregate_results(results) + print("\nСреднее время по операциям (сек):") + for (struct, mode, op), t in sorted(means.items()): + print(f"{struct:12} {mode:8} {op:6} : {t:.6f}") + plot_results(means) \ No newline at end of file From e677d750f7b7589bf303f2a67538ad6e1d21f60a Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 13:43:41 +0000 Subject: [PATCH 08/11] FINISH 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit исправлены ошибки в написании, которые мешали запуску кода --- novikovsd/hashtab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novikovsd/hashtab.py b/novikovsd/hashtab.py index 358d22d..d889419 100644 --- a/novikovsd/hashtab.py +++ b/novikovsd/hashtab.py @@ -51,7 +51,7 @@ def ll_list_all(head): entries.sort(key=lambda x: x[0]) return entries - def _hash(name, bucket_count): +def _hash(name, bucket_count): h = 0 for ch in name: h = (h * 31 + ord(ch)) % bucket_count From 31726394a9d091d3259f1d4b30f55279a089742e Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 16:47:28 +0300 Subject: [PATCH 09/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=BE?= =?UTF-8?q?=D1=82=D1=87=D0=B5=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- novikovsd/docs/comparison.png | Bin 0 -> 57767 bytes novikovsd/docs/data/results.csv | 91 ++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 novikovsd/docs/comparison.png create mode 100644 novikovsd/docs/data/results.csv diff --git a/novikovsd/docs/comparison.png b/novikovsd/docs/comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..f5391f34b0c3c372cea948e0f634d82bf9a7f5aa GIT binary patch literal 57767 zcmeFZ2UL{lwk=v}E8QrlEsA6@Qbfr)*qF#z}7*4~uoqn=YUT;-1kH+38^7}`J4Kl@DM+u>d# zC*-bPQFn>?G5AM`K}WC1PvO_1tjGVl`8#V}_c3{;iMK2>maXb~@*Ey1XRo}|v`k?W z{6~b?Y2B>Evo~L+(_65~2l~oi_#$(i?)<$Fa(p4VW!q-HQqCsGy+x8ZG`!%t=FlwZ zzEIdRL>$QP=_3v{r!ii-yZS({d<8w_M80u zd$T`(g8};WX+8gY$lsSrkUPe9;Gcgl6MRM$jUW1WU%ZlV z%-();CB}|@GY;?*pD#IA7rgagQS`&PGaASpPsmi=gGo2Ba@BCG7aG##lgoR`F02OUJbhY9=wx zLMxNtODfF)bN$6F4H{j^3gHvoM===rk9mFN8OHMirFL!CXeWwRXUux@OdRJ2T+@oS zzU3M(uk=*!2xeC-5g5JWH?i&umCj6^j2Mh>$C|SBB#r*gM+%nD(mRU*CDSR8~NV1&F(k;}T=X*+;-rT5gT~2RO+1g&LXW>~F z^HS>R4|ih1Uz^<*@+WK<6ZUHb@m@Qm#s1-)hsiyaYkig+kMB{7jt6>BOeu@cskc4A zFI29NrlrRDqI+{3c}yZo@0RM)>0MNcD(D;@tMhAM3N+fD(OM*MF0qimQ!M_-Z>ckI z9@H>Cv~k|RRHb+D<=i6*W^EfGQhLu%%OIOT$;k*~%}ufD*`G4Tx2G<6^R2)Nm6YDu zS+5Q_e(rjvqfjKQ^^4NdKR+B8gVB982+x-`wX7sOC~&lLW$JCfr1BMB>x#v?#Rj7t zzO_N;Ve-1?`XH^tWFyvs34=-Cy;+lPQ#|-E*R1W$##a?QjyRDjZmfoB>e4cb-MV0| zmsV{zla@NkLIYpcPhz-Uy-~|k_uQDUs~ka-{s zu#BkXP=%{Lo-{#nC2TG&HSqNG7rCuW9X~3$qN-dIH(!?(@Bvm6o6p0!zFPPxI@r<1 zJK_fkit$o|A1TbPLYNFmi{B*^NsF&ai5{xu*roEt2c{6<=E&ZCW)gds z7T7Ukoh1a|SKjL8^uVT&D8Sj*PzjIoYALiC?JR|pBkJ&6owOK?w(C>%MHR_ab&0ia z#;b0>?-IRsQb$SrEfQ)u{rfTAn<3fNsjQKITI+e&T|?ugVBV>A=IcwIs?)O1sIykx z!u9Rt@G+9^4}U-?AvL!wcWPNVY%D*m)9Bk^WoLxiH$nps@L(UiFzESwwadw zw$+}s%e=;Qo&7L82~|#0t*mZqKS~FR=FC%Liv}KgM9s*S%~w@er_8RcPSC>qQ?9#` zHx^fmJiW_W-zdxPOStmmeGT>E-~wJ4zq>VDui~}YA+quP3CG!iaN?J90k2MR>3-HR zjSYQfL@)l(iahUJ-JsT9WZkc?S@ztJ^p~?zic)mZ0EvUXywLsz>%n=C&FR#WUbcl@ znsyyZ!dVZz&_a!na9!dfa_N^mC?r(<$ZHrKdB)=3W8@_{U$r$q5b*A3thjTwlMy67 zd4ojH^2{P@`Y^0gt&nlutBGdYjufRz>#blFsjnSN9*{Bip8m|+BQlW+y?5GO(sp4> zjrohuzgu-1CN(>c!cOtK!R&he5H;gzh~lQ1rIS&vLj$D_V?*u>ez5vP@v9j|T*Wc4 zl6Zz+mt{^*r^XwO1nhg7W*?|Xc(B}OnRBh!X3(Ni1;T%GSWmX{m8Fbx2NPKw8hJ@1 zNJ_%o&0aNpHSJiwzMY7E)Sc=dp<-9bG6DEgE6DT71ix*ZxM;%hHmEY#Hr22w?x0- z^P7Y+mY4Qn60~vdq6Z@{^%Y_KUdqsUU%y?s+WitX55IKvs4s{8{fMqmA1Qg~=!ize2{Uo^7HEbnHZc0>~7$zU^UcVjJCp=njFB$@N#LtKf?`S zkX&J0?{7Di_{{A9hWrd4Gcn7+SFxoZtL?* zwP83NJW+i3YYR{5c#w9rEmDMrP0)U`N%t6$mZ*lYG;koXTqWuhr0=9qky#dfqF0TVOvKCJ@rGy*|vsU{f-} z*Ra(dUKP?~6nEvxA&q;_bm)vWKG7~2q@l!8b#67n*xx+xP6EW3Tsh}2JEOGK&x?og z<(duEKR+FAE41wKtyY_i5OtX3EL7aQ!g}!QkHQ{9Cqsxd?-WA&ibuTW(l?>Pe`Y7;CR0_Xfz@XCe#S$0I8jG7;Pp7lqT$^Lq12}G`u}+$C zGrBW32J9QS8Vv5Q4>|`>FuNo)7gMQfLDCW6yTNF8Ro|&gV{vmfr$?mPp!^}P>(aQ( z`0E>^kQLmi!(0K~*pItW7U+0wuPz^)e?l$BW+b6PXA*YlT0zcD!h`&D{ANe|q)g-= zCoX;lm`8u$&=Kv4JSY@el5ej!aF=r$-Oll&QH|d`{?w_XHAm8I<+)*{+k{mp_JhGG zC{GC260M{8qKa*Yr6`)M08H#{dHmKKt>@;7&Yd&zLHn)R3nZrd+zk{y@^jz>-&bZQ zC6ENTT2`hzW=;ArPRYH0lFI%rNzC>~2|FJA`%ej{|Cd%b1!hx}A^F(`<#m_hJ^o~{ zt+12TI*9Q;ODAljUjQ!%m~cEIoYmR|={6r8uf9bHq79$is;GJ1Hd?UV3!)RXzh_X%g29B8SQif# zC1!lEX!W7Mn7I{L#gu;hL~{q0H*cJRL+5r_-ijuO++8>=*-e9*0#(lq%V^XIR=ljG_EV5YPH|Q z_x9S4-ji4OAj%rfS7hbZ(bs+xz+_D2w@AH2dn-jT@=t!#=2vTT{pA~n{&`WOlt4#* z1>hA(aTN1%PGRkUA|}` zPZtISX<3ypg$xsihjZ$}(n>5fMrJGlesTyU8y2;T+S^Wlq92?5^thC)AE!4iGtyjS>1-mSLy~I#v0e4ruw9>UNVbKmxfw5?RQ>XRF zt+0;X@+v^nF(@trAW=w%aq9dDbLqnP@Y|iX3fJk{9443Vk5F+@hd|{wxZ4;+C*RlS zZqz}=(9x=a9#JguKR@DyQQw}FYoZ&A{r% zpE`|Zm(R0Dk5!{AF1<@?@ySLTvy;Ko31jB5_f2`*SF}+fi(~cmP$%Af$yM|m#^*Y* zIo25J82^{tWo%MA8)Fs?>$5#Pupo*Wry&cqG$fC_Y9Aino_7u}ojai{!ph?Sr8%)0 zu?J-5zUvwdQNnhkpG%eq91h3i0Cv35$k0TYM z-h?J=sZyA$2M z#RsK3y*T%@q$lLnCElHd-JOMsImi%v%2K59jaj4Js3&i6-<35`^*ahk+!uHTj_}3N zmppa0UR(VY^Qe}b8me@!&C54!@t0itb`A=%@L9wtN!s$bZm;%?`3Vnck5qXsM-Mmp z{dlaNqasC0QeIE9xZR>vz1bBZ=465PUExjz5PY3ijXcdaXV5PhZ-mw} zDJt=C2PkoYjT%}8Cl63i>$9IZbMUfN$%s!^H^;qR5n_yk{i$$5q!2p=p}?w_4?Rr@ zDwy_Y4Onstp|IE1#}i&55<;}$OS=4(leSf)`&NL{6e@S1M!Z0=FWLJUjYxjxtFs5O z?#)oHgg+6&eV0uuhrKZd@kD!K(+27@!Ta~+B5@X!A*J(Wv-UD_V$Cob!}iA%Sl_mI zZTEOhd`O}>;sASGQ*RxZxu$&z6ikk)JMJT&p4v6?)_+EYZ3X$sQ7P?QE6PlO)u^VI z*d;HEHr%>GIizct&^TKAl4HLEyXkN8I<9adomfxyn;&_xA1-#0iu!FDB45E4)eNoL zY+vb;PR+^Ap$-uyt|yCDdo_~=NlXc8{40M_jRG;{wDVfp?@JPP`(WnZ@i&Bl6wCGm(GQMcaDL>hVGtWW1Sw zR(h+qgltSaE z*6~vt-jG9fZ$UJq<`~9SiK+U=42MsWt2~+)xO8*$~r|dRq2_rUB)X@ZM^2~NfygTrO7`na*`8Ea5~t^QCM|ai*BqZ6zK`G9V*fW zX>O;&a+JKAX6DuUG<7EdRX6O)B5;~kwtsI6Z0}BG@Wi8tqAC?Lyc@8*wIo_C4)1%x z$MDS+nmiY)qTc%)u^0K$ti9`?o(XwYET?1gaM*L5tjk)XIAO&nM+mh4eEh~|mYtu^ zz5!xgexQtk-?9az=1tsXMf$tgWUPJ|5TQK9{-{W$E|Sx^qA74yjZ#^zgV5*Lp~MmA zJU<{xaXi^mNmk|LTCPyL-Ax@^xNkIL!fT(xbX#D9@8A`kvgO3?n;X*CaU2wJ0$L`G z)S#Plj7E)3T6CpV*1;!1;4==sV1{Zajuv-_2jO}xA%6G$1iRm9S4pi;zkBOXxWe}| zA#R0E&!I_BtHc1Z-$a|%uJq;%%sN`vM~UmZV|$a{yns=9Awx%yzhf3dknQ4Bp|>}E z>nG$3B^-~bwRu;%#sF00q9W%H`l_!+50ft*^$ZT9gD7X;pxk@2{k;_S=EZ~KNol4n zaiu?KrhW#;lh0Fx0u6h?guirmXUm~GSYV*jHwhER^zd6^-z;|d%W{i!b>nIkRC}7g zeNJM{K^!De`6F!I(=Ae4R)vWT+gYm}>#1X~WdvOLZru~MeLbUtB6UhB6kN+cO^S!yEMu)`*{BZlus63p z^t;kYAbs*!;a6Ps=GLi2*49o`xLtgcS*U5Yyup;bZP zIZZ{-D?0v^?%AYF4lG-;Ua?JK^W&h$qPWQj0re&nbr{KfQ1UZI;M5NJ)3CjMd>%I$ zLh~IL5$86OX3i#FITyfV!fn<}cS}V+{-ABQAtTu1N zhhef_V4x$9W-{4Rx4Xim(vYqCOyx7ILM!B)py7^#hfj^K&pbZNtv$JB1l$f;+m$V6 zb0D>bTAb7Lx_pgivNiCH)vu~yPZ#zHVK5)^_QoXa@4XT`Y}v3E{;R9rG1c31wq28{AL1P=08K1g$kJTEMyqOI zw;F&vje8Q+{!?D#K%T$U=9I(&5Gb$0xb(8$`vW*@2mlOZbZc!ISog*&x2GLqAIIZT zl6JR;cbg)CCPG2Itjf)L8YcU|L=C)6Wl_v+pNV|!Ft$d4-teO6(wB2u7JBAv$sw%gskD|G`CC2%KA;6crom!Cmh$e+N9Q01 z->X<|7C)KO5-rSgv?k;+Z`dWOrjVJnF_v8sUu!5!NT)9q{?RUXMOsCA+i@rdf~lBq zmKV^ncHcid5-mwuB8~z9eg}{5Gf(X*nXgzN)i#OE2O7Tcj+gPnrj=xq)3-Z@7+SCgkR z4kQ!c^*v2Qs(G3qr7c>twVq5cp8+!YOlW`;Wwv~;Hm+4=Q!&P4>8oIN^w5HUey3K|QYd2tbnbX+ zp;;8(ag&-^!X?e5pufARFNxLS&p3guj+V^6olG7b4f>&H`u5x*BtZv)8`?*ikpbeS(ea!p$T7;90pdq6n*0TC}E)NhqvF#sEv38hO!S}krbczJ~u zL7H-(V0CO)737G1ec#oliZuDnA|q>5xSFIy{ov+DHf-ob3w|xX1VTu7`8;sS5zjWT zK6*B#$)m26F4JvqZ^Qry6Fqj$q&CeD!m6}$I{jbt_oon_9c@#FrC>S9_t^^A&^?5N zsHDd2n~~4kiKeXyS43~7cy6sNRxWt*AZ9Vyr%C>iHa6md=k@kLg=xEM?Zl!$s*4Ai zlUKtoH1*#LR$||8q6x#q-szee`;g%LoD5(#{r6XpV72KGyev%4sqz4niA6CqhwJYF zisDKWo1`i%nk(vuP^H+AhdMde{pdsEZA&M@3U@}L%bb9$B3cPxFPpgP7@FzFRtt1$ z5}1SctIt?6$kB&cT*LX+9p)}M!wsCETiW5(`gIYiJ0sV8a2Z))wE9fR-wq`?y6zI5 zEPQO=VYcEdSf-Dwa_e}Tqb%zgV0j=+x@WZE*|K}b7+Kk%?Z#Wyl0zD0Jqa`AR6G_> zuG<2Dbe&2Z4^dM#pPGSSArqYXuR@XgNafYHp+1FjHKLV3>58^hRv5)_v*VLiKkO9mP- zF)`!nIS1G@-EO`3?aeMr$j=zUqbjjgC8#AgVusTo6=6CBAvWpK8oJzxGmDCYY4*v6 zk;Z6DWe5WWgYgT77n&qf%ZOSGwVs6kvG?)5`@f=*uX^;lKO>#+kjvO!@sIJ9HDbch zLzRZndMTx+SNZ+A@sN-uwCQeXryf0w}8C%H7uxiDdt5On>3 z(WpgbBx;@-50uy~LemaWyg$CcxXK)8)uQmOt0yseYp|-OT;;5oYGk9};wdRh%)po+ zfVv2*GOD9TbL*L3HphzBLtSyYp2f>URtxww?LRhWTV19y4!m#>7vP4m&7=h8eDxj_ zDKAsw@qLR>bb9~!FM5C@gCw7`&uNNfcjE@5{TJ3YXwWgPmVdn%{TV0_M%1&%HLU(B z%QZ8mVOwfj3_>AK%w&dE?zIBzej(GfJ+Z)>m)yRHs7N!B-d^b_84pqzJ#4h`mthf* z_=}-A9v9}J3qn5|KNDS43dHnjK=x?2wm}n1VqCcoYE*tp{VJgjC_LkPdum}pQ2DxA2a9CKRB(ADGzqz~6p%`Dw(P>a8{9j;nz z@!D}H?bi;AnoPxnuIO(5=)9-1d^oTh zc#W?^f{!G5aeCIJcW0%v*i6i2O?f3`uchSy*snwKil%7c00@kgb#pMwYRQ02vvaEM zZq6ulXgvdhaUOnE-ECe_fJjTvPiJCw*?G`OYv=eDV)IaCjAR+7r94~)09-A8IB;~F zrKq^iBBR1;^HxP3;K$E_tg?3jAqN~dD)AuAHQKhywRRcMxe&F~#&<@Vp#6UUd3VBr z*xV$&k;<~57T64%IWRmH8X|j*ccgs~eL#dj=LX5IbK%H7q zkx^9GNdP85q{w)Efz9R>X;Eln-i5Swa@LPoQY;Qc1*l};n7I|WpC-%{+O9~{VfM7X zw8%+s(D(riAh8~Z&DwXj-r6Tzqqk?Hk`5tYU7*inUs()gf22D}5 zIFy{sUg61OEX0=KbTgpGcF3LM@RiKP)e|Zbyw&Si7ZWI7nyy@!-krH5O_DppAjBEx zGWvq7tF%vhdiV0dkmTJ+X#J0`U-G1GCtmb4Jlwtucy`^3*rG_8F27(vc|C(nGJJi2 zTI39c!pWqTrtz=AvySoX3j6G*-OqU*)rZ+YnI-eRKQwLB5pD!D9aptUT&u+VHLkh|{Tk{2gZ+PnC5c9JK z2}v?h>5=M`z)vs_lP858{>4x<_MW4}wIUKud(n9_QF8lR{QhgW*lvA?CbHWmucV1| z>CWb?gN)2XLIB}bVOmA(!@jh$ftL=BBz<^{GUS5F5}L2HRotN3nUBEulr?5DGz1Ym z0GPgUU!Ug%($<7qs~>Hycbig4_ALmgX1!fn!m`aEp#qfq57Q=g0W*)cTp_T9>^BVy zzmmdOxiR`ul%vIWD91zxh9#V&lY>>gxb2nX9kfEH^5}e}+bSWa1&Z-%7Nifr?`GgH z2BRFE<4#_zCswOzzHw+4y@cOcjwgOE0$`AJw^vpbK8SQVbhD}w__U3 zAA;k0XxQ?_w$w$9+jq$=yW(28m8oXYT0Hu{f(H{<|uy+stUXb7=5 z<0+yJ$?~+F!EetR5gX};ch-tQ<+4PP=ei8S3y!6uBRLgI@>zMeIBglsT|z@dM>F%A zb=hxT?1eYK3;olE7PamWG%K!=H0M=+KPHE}+>DyJ@jM*S1klFl9)FJeaws^jDCu^9 zx{Z?Tr%ZpWTFPgWaD%W}%`fA5oP}BaGt5uYakrIN$8MTnGnBf3714bCAFN16M3PJ} zjX-CfNkb_0b6pMWJ8bFq$A{VX%Lj$5PC&KSxUdW0S$E9T0f0l!??H0ydFCS7G)I;J zx)QxZ2(soU_b0GZeC@n`r+>Pnb6x7f;ZvMnK02iBOmE-3A_zs!Zkv{oV^`?44x%Yh`||i!FW@f2xkBrr-it?X1@o1tH-ETAi))pqmx4Mc$Nv;p zSp4bqy&bO_xZijPsAUmA#>>OQprf#06k<2YBu%S$Me!d_=Dc7IP=6tXqRRK7Y#f1KK97AI%$`W$~-LTdvK?@J{`7P z0cj)LhErD}C1>8fU3#yKb>ZG#fHVvN_CLM<1lFKKLHIZ8+}cyFB{PmEP#R@G&1Cs- zK`3oKs4{^5A&FVLNkAHN=$@aD>$!(p8*=o#IQTBy#%l8uZPhU(LW{dmV~01AY+jhC zB~{*sMB7E@_TtbY3=8+_Id_exJzB~9TB6DKaM2(Bak48FTHd7&;XW>Mv9-`uF-;?- z)o2H+8*a8$sp1Vz^WMGMOwI!ep&lhSV4|1o!*i?$HP=t8GqIZ^{TsA;vvljCX^sTv z{hmCMA7%nImS9yCdkt^$ofj7LQD)cLf2ticuNH-;r1Vt=nQ(4qlKVC7F{48>|Za z{Bi~0Zl2<}r&a<_CuSYuahhp=seU`mQxW*AT7ChG!Tj`E>C%dYf}u^TM@wa;YxX+f z&-V*eTayg0gh0yRvCVGatWcA<3v*4#S^v?SuW6zbEyQIyqTJ)yE@ob`0ey?fBOL)! zn`X>Il_|3#<}Mph0q{tttfI<)f?)!oXMU|z)=IUXN2qE@p1|DYFaoc;{+YzYM!VmH zO)lflV{Pg)0uR1_&<_V)S4xuq71lEslZ9dg%yB4Jk>-O1D!NegP;XSIu}*H@M5I@0 zr>ip4g!&rl$RG*BvVBAUb&d65FE3`X^ov+k3kY4AYi{Yr^e>%s+ErDdh1}Glc3YK@ zw45Km&50^j#@hv%xBb#_lR-2EP9P2$|DIU4=Bhk_SdQiz*W{M*_jhVQZ?ee<3PO6< zo2g~#4S7jtB5Cx)@&)rjtcaUp!bM z0gaK9`>@kuO+b=H@;9JWS;)>YcqZ)eJ!ptW=R7*er*ri5Gs_r>MuxCV5BD zoaVO~DDl|Nuz0v2@Y&7UCg{yb2%)rqW_Fxx7`wbh*o%(x!7_C8SLJsj=h+Z9iJ0uJ zN!mO=$JuV{(Bjv5*D7Ex5PQ1;OjOCI>tef^s_QIJY)|tBoMlF|fw#=A>BD5I91r z%a{QxZh)Ndlr+d^EF^3M(|#@Bx$~(b!4IL#-vI6_UYvk^f4-8%yblRXLB)`*Sy#SL zRX*UER_6D(v)4#7L6I^j&AhUpd1=21?oO0KtKVI{P0TU*0bS(cY)|hZo zOaFDiF62?#+MvAc0*fy8;e#PF25PD;OFQ*pt907kL{V#wgE9udZ@3zkb+DP7k+0td z)k0csrsK0V=&>&!yUjr_mC3z^t#qFDL~WcMX?bULK;_khef$tOA+>Ay?Xf9)G|{sV zPv@WCKaxn$k|Q09%rHovJKm zzHb9lp>I*D@!IE!93J?Q><7J_w-ooCN$ZH%FOe=E`{7f-TvN2xZgDAWy7bDh{eR&m zUw2*^yz`9dt`n%fE<1~KT$aI}Ni4F^EAEm!q>+5b1?PQ}(g%?p2CpM8q+y@jj9Nzu zRCx``Mz(u(a*w17U-OM8CHOm1s1RasoLqWEuXuo)A-R@4zok(YeCZ&Wb2eY6!}LBh z$B=rHTw&o87qX9SFm?sRro`{TH0SfrK5gX3a@q2(O$RA(e+7ni;U6?VLUA(PYn8u& zMnJ~Mb7DF}nA6kAb2WwAL`GS-IQbO;bukJ_*nAsY^pOwP<$35~ESKH}NNZ$)^3q$C zc&SBTA8LV5&+Dvky!j-4eXP82zJr+EtNoqrBe}uaY4$Fe93P{Lh(~7{n8U5YGDNBCD24( zO1;dLM3*HeFB#?Y5W4{!rUUV^HNQ#c&8@OB+(Uo$aA3iB7PPFpifl66j{vPA1dK}c z((+$!T>zjYD0-28OX1*HQf^4cWku|}6!m18*Qs%C?9#(PqG*+Plm$;BIhh9_l$_uD z*i$~$zJT!hAWcycb;Q(EBn7K?r@7;WtozjU)&Y9FM4F$p9`2Iwj~UhTK)9-L__jjt zqdlOh0 zq#uCn-j-uj?IHXZ<#V~%w2_);M9dS%p1)Y1e1##Q!}2#Fsg-Gr-SwS2WF*0C1d)}g zh#XTPjSTMQNjK;R5x+-W{|(rOhmG{ zQhT6ynle_E2y3XxIVp)ROt1o%o1A%WS~==Gm1w9>g?xPE3bV%;!?56OyvX8BOJi5nfm{#MP|lH;{Ki+YJmm*tSiUb#n4t?uo46Aw{f3OF9?0Mlf#S$%W( zDE6rZJ5MMQ6{3{dp~b@u8^kG0^Gk@H+S()`hsQEvt_!h~L+PjcE)BYb`&gy_fc8OC zO;9|PpF?Gb#>rJnF~cu^vDmD?LlfC!!F{+v`crCiJFKf?Je4cB=9NHv63WQ*gBGXz zADGO+lag$nuNZq!y178RdAXGnz`FU)6-n#rGuvkIbw89IQ9(D$c4wcY-`8?j@%4xs z0EyLSzT)7=4{(v#-@ijTY`7wp<`A*}7Vd$(f!x@>RI#jAp=tdyj86n6?XCa_S^6oA z{h4f07Z~DsFC(kS7vXBrjq_csCi*1M-<<;an0tsXq2_Ti<~7Zi&^)H(gp3f+RH1g> ze$WiONlcOn7f@{HDjo-ol@03iZQ}(=X7mV0s%edU=Rz_M3)iV65 zrME#Bn{ z#}4DN$lR1W&na;RxY%_0p1{LBqaA{u9nak#(e)^s49iPOwd{QADPPl>s`zud&#CN? z_Nv%Qan))TnORfw%W0#Mp;((bMd7hz)^4@1=>k7TCjPk_^xT|j6)MxNcf8s|!m`R# zo|*)$lwX4@CUQSDejUc)(arAF+%7h)onjgHwCrSdZR&0!VM|@)5cZtMgmGY=Fq0Q~ zkwkBOhg4v7Cq9VKqpr3_3OPsyIem5s-TU_{)7#3zxhcE#={=)r59B92)8?e0V zndZFL-z@)Gt+nwZ*;vyFeqbMiKlGPlDrtYj!hGj9=sZ5qpe)+PLr*d+G6gut0uJaNo?8yE_q@4`T|0f#h1`1 zSx%=+I&xLLk5yks?JSZm8TB~Hddd@?>0}ajW_})gX~%QDeAr;llih<>>mg9xn))wy z30hS+MsZChN~>$yxnTTV){Tg_8x%3!S7#K*Vi3HqJArG;2( zW~xF>vw~E`!wo^oxTieTD^Imc+pdxj_q`;I$L=tM+7GfRVW%z#hIJfMOEcCp>c2^M z8+RjDD1Jmez^9pS+&#wU{m-+`{au>SXypDXbSAlBON-g#XxQ5NZR5n)9+yyiuac12 z>*noRInfJ?b$y2vrF~OxKcWf5offLh3t=kN$}xm)VFpjj&elTw69$~CAeBa}&)}Yp zL_!jPFR5_Fcn<2)$oSM~mW=x$ayrjD0;(YoxHE^Paql;Qoz<|(%C~(vn(sv_ahf9B zgvsWh%uUBdcH@ zPf1*-`TU-5tMl~mr7iXH^|S|gm5(^=gCwb;R2qp8Sm+KPeTPz4=#+)uo!bA7ekNb* zi%2}&z33p}_Z_T!LSy{=akhMAt^+0yhbrGa;)7O0(=gR)m(Sl4MS>!sJGX*`>9BMk zE#J{jC!MEGLB{@~DScwog*0rzdEuRF{@+cukKuk#zz(ctIy_iqo0d2i2Gm8kIdto! z1P8VXetsOr??`d!s=hWc(ZO8|_vg?~vDb_+k&84D(%m_G@(O!H{+rG2RjESqFbmD9 zXL^ejAN15Qz842yBb!a7W&_d!Yu}MQ1*Nw(;vF(BJJy1o#3IJXrBbLyDMwx>G(Oep zH;t2q3Ut3C+6&2zDQEY|3_ie9XiEWIO`{|~tgZKq>7jOIHCd2|$zgC7t)oPxH%Yw}usd#`QmCpen$gj(0)v_IkwrMiu7+O#1E}l?wh@NN!ZC}2+4$_W6+C7fkZz6y!jRAt6TyBP@BN9R}I(6R41*(Os z&@c+TFkde$0%}VgU4`7u18ivpnVb}?oWATyf${FTGj#z50QxwxP^8!({mbH~!#r1W z3@h(~^4%8(q7FnaA%R75qpzpx6ezGVdyL@$I25k` z@^Z4tTK5&aK-k#S)*Onlz0RU)3b++{JvM$y{J3SE1-C`bk{i1_+Ya|56J?*(L3{J= z2k(8PRcM6tlnh;?H3)fPiJOd~F$?z5?}G-zC?H`!kT{A^Gz0X-zP^8=(k^PYrDYHMfM| z`G4t6`3N+Lc81R*;-$Utp0?E9VwxNC%EJ>%+n*RPGRAL^OcnI|;VgOuW{K6xlc2F3 z0*$S2S{nsHF;+~l8O%oCK*H{D&(rt$0w@W{kn}ipnQ(-L^L}3`Wn8fy&Tz-7#0+pI zFm-^Ycv!sIv@zm!d=3~6s0^6opF4=lknFjb*;1}cuC!<5RMAr~KG@Tn=EA(yu|8w` zlf{c{SFzfy=jzd!kzJO~wu+?0OW|9n0%oF~wjImcA5sKj6wY}5c4y~N^yFi2;mPqe zT*-=j*qis8V?;@X{!HRRj)iQj|I+prm^DV;qlR8rgt)Vf1gLe8Qjte+7rG_fx(4k5 z8EG{_FwjU^5Qkx7i4}AD6MVO=zfXg(8MK;Z6P%-}NOZh6Ajxfq2;kf~$O}uL1Xw9l zA0s2&t@`V8eTA0u1;GjYk}2lsEXzXv67X%?mQJW+9LG5YOBgCn>%LXx&5WBhp_$O<=UVQHa`T z9v~g@2UE-Yk2A!>EEsQGNM8f;l~e%Hp8N3-!)G*)$l){qos~U(X7v!1hq|GmplAg- zA1@gGDw=`dr$2YY{}uQ(Ce}zuTFLkiwcx#uMwfaa=sdI6r1oI$msJ!>8!9h;*jB#q9zFw4sAvWF~_MuqiXQG zj6#rm1)@_S)UnkKb%Mx8JQG>vxm5?nK(yNUB@m@OhuF@F++e^=-SC^;0a24bqI9U& ze|fFx?GhB_7vm(zKWl&@v-}Ly%IV?F?&48Uy7_&4LQ&6yUwkP7w52grJ^mo8y7P3x z8fYrPDk-3)V(>fg1Me1XdZ0cYFSozpN3SuqiM)Au0PFW(F^L!Tkqhu6*}Wm@_@(i$ zU14(AS@)GG@bU5CbTqQSjdjv_Jf$p2Oe2)QmQh&2p)P>_O0tT~^nqS0R4B z-f?MyI417wr!yyY)c2iLWk4zs>uS2~XN+&q>qSFQHGKnvVVGVwSdhoS z5bY0L&ss39svkcej0`WX+NlESGfn zoR-&}rFR1q$)l(}36{Uli69<oM63c)h8_S>Wm~#NMhRG^wPyUEq}RQo3+7j-f?(M-X$|5M)JTs2 zN$o3o!SuRSsHL~aBH&l1Kj7KEnHF=t%WH4_Pj{xNU3=igelAo)gFY`EUXkRQu8^*# zk@iYm6W6g5vL*E&g+tr@w#N}YZ!}(kKg+Md&`C`t+|%`#kS*=V6vxmz++-?1E0k-t;NTWykI(O|XGmNX^etXw&#w!FJL zwDp7JWnnRVeC_Mjcs_C09K31m&hnd$Fm&ge7{=~=1A=V%X-r7=HZb35Le)QYSrdRP zH*+!H=tNy#kVu_GnyVV_Sm;+HALrzmNE9+Q7RMOMqR-k;kmwuFfcBM6Aedm{YYmW8W~-Uu?TaO@|8H{@`t~%;GkcC;};Q*h9*DxP6vJReY{JLX*Ja^A|hMO_)< z0Y#`E3b-iAe7hfQeHR|FMV7Y``$h>htV{JhT!2e`3pz{D{6^4EplHquOOosc&Af13JhI+EW|b@goy7)_{wKlk%QA)t ztSf?Goxaj+7993#p1WAzLWWjNgdJuFNS|na4GGdDxD+UTkm_K$;4EbJJNjT29{Tm5 zGoi2k|8rROrtE*ilVtYZ3;y;0;lp-JEYJxnsOW@4MvkLW5}i+jTs)}pqgj>-EWu}h zPN$Gj7r+a#9&H3DZgj?$&^7{RHkU&gpyZj`N5QOaQ}}Ld>DP3gMQIgvANGt(hZwAm zJ!7=LSpnVpy`y5{cUDr#ZfFN;bQhR++y%|dOX!*tov0;OT9I@and_K6SK9WR-RQUl zyFmoXfzs8TTLn7XzHt3G*t(GagFoS5S1nt#d-VyB^2^wP)@S%~tDM753gp_5LYN?PCx) zn_J+JgF4?ck>?K|NDll0=LT0Q+n$D@dU=S#!7~b3eWPq}1A^u5;%Mz&1O@F%b!WwY zfsjem>u@1@pTzLJ>m@Y8voVlzofn1#n|UgvfE5wL&H^^lyRUOp;-}0JI==H1{~6h> zRza%c{o~h3Pu_f}0ZvAie|jRVAq%v(E5n^YwZ^%+j?N<4JL2KVAu1qlE&&U2Q1{(G zhX#a*!7OlIk=7U)e6z%QaJls8>6m{>gON0B_7Kk0HI|ku|y5RQsTUqsX>b zqzKIM8zeq){RPj8{zrKB?b1SUOWf|I;p0^evGKmn&2#@oA=~JW@fk&27L#ta=x43V zStbc_SXMr`vJyphZCwm06eFgk`^PuG@Jmr4wA4G#)93d&y(?;TV^L{QTWa29s3(VI zrE}%C-3Wd&Hqg>*l?k*E4vUX0rf!z$c+iY_6bV z^z#XoS73g>20rKI_X?1z?U8p;^yYmauXyp~4WI0b7z}4}FBk~JIJf`gU>KCLAHPXK zg?Yz+m`ALmEi)Ok%?2yR$yC}y6Le0&pz0a* zDYcpWRwaMK(1%&7Cc9ImSM_`G5%%6jCbHLMtVL~FCE{{o9qDP$VeI0|e@9a?y#G8& z%$qMCx(dX4$i8sCz|T#vNN9EDQ9@Drng!6H(X0~;&fg||xGvPmZ$Jr)#1t;j(ava6 z`6p7kql36b0ox&oI4F#PE+OESp;}-;MqG5J1~oKwb-TE-mQnp9ts*PE4`{4^?YR`N zyzZSeL`0e-q}x2XoDJL%QWPOoY;K3LxJHGP%g^t7YI``&LMJ_wO6c1eRNZU8zkLN6 z3(zS>zOKl~g-9uXv6*+;ww0^whF)Mb8AEbdYTqaNA zs?2HNaxJIW_sXyj?B@U1*vX(99rT49z^G(24WkotG(&E}Lq|>r8Z8WzF5?<(K`>?q z6i0oSo(&yp@{hu4DaLSW7l-J(N$?zfp|frW0HkUWb@h6rEq*z=4az)=9A^+NT$%Y5 zA)WqjpeYUmI3dH#OzEuZBr<JGbi^8*&m<_V;w0yk&c4?(>top( z_gv~--W?bJCnK;o zLJ4Gnfa^cN!0i9lUyL12e4_hRf^Lsrl74|$!WMM=2|DbJ%0TJwQT0vO3w&2ktbm;Y zYv?)=>HdNzdKj7G0$*h!kt7|qN_0GM8Rdx?zg8zC z&*K7pGLc}zU}Xk9xmBC)+g8qi>5Hykg z`T1|oggiOf9LqqA_rhDjo<_XMw+A&;d#4>9mD;$S9MBFX$WhQ3zl3#p754A)7&3Uk zNgA15n;@=zjzq8M+zRkv{^Z`f>HEIDt=J3aOWg&w%1?p2^gMFiBcNzi&~|+fC<3E) z8fYDxtbk606Ol6*mb(;1DI?GYxj?Aa0h@IfIYg#AQghzFLTAhj;kT?8sP|sQ={h=} zGSC2&fqOvIrhM)coVMUKijLL-$cW7bE&{cInmN_)dS-u?EKj-&eL)CO|s21UX zsCv}B0S`z+4X1_^O!-9pof@C4pJssBjdOvq{00YuAV zc;*K8<{_bZFFlU}EBxg~B0`SLexGLH0E2fuc{rgcaJkeYx~KNm4W^0MUq7L|2N>^y z4~N7CNu{#x?JXD2AK!9Ub-O{}O%KM823euKugVx$-XdOrg>PbtS|Yii2o-FG5eBju z5>jR8DqxOUFkc))l{8vfxnlnoAG6NR{*r*e>|dmq`R|Fkdq57LqlzpV9A`SQ!0Z2$ zt4?OkKpK$v)L&%vO_K|Pb1J0^9npir{|9?-0*&>)_Kn+TPfeO671C&%MJN)LG{}^B z2q7{TQ7J=vR|;t|lSCOKvr>kgAtgh`qGBUth>*;@pX=7%yK~Ndp68tB9oG9_|My<& zoYmS1_wW7=*Y%mMq?FuHl@)BZO9d}F3+ffUzsLUaK`9&erSdCj4aYC`ce~`4mFNi{ zSeV1@zVd~*Sz@_!e0*!nF_YV!z5|2(VUM099Op#Y_uohB7}XQA(D!9`Y(#mtwWG+G zahHL(-6O7_3b&8Py`5QnZ=$3e-aYlWH;3uPMY1({+}lxa;rzH(zRBFw_S^X!n>UaT z5|Ho477787kbUd_2-e-5_)uDrt7u@SOZ^V9ezZ@(`k@vq6@lW%!q5&xL|!jq!JKIA!mc*E`vaEP`x+i zPm`8WU6amjsx(GN;T8`(i~K*l4w}uZBa}=PyNwYh$5?p`rrMuky-p(jGCvM@x!0;p4(RS%tHBO8U9{U_5=2r!^xJLgNEK^*T z8m~g4*9jVpJi4ljUJoy=0BR^#{f?r^EdHZH+}-wHz-X6$qg$Ucv;>gFMqwU0=@$Eo zvhf>if%I*~ZcZnS1Z=>|(u|)ZZ$@PDsx8=!jAu_b2%)n8hqM{@0FJEpRZ;sW26P{1 z9O^ML|Cr#$s=fRhW#9?tj+o4}b3MR1MX*Xvf>JwH&x_O|dU+}RF9X3iQJ2$qRHpBE zYX=&ZR@~<0aLfYYbJhz$?gmbr4ofEi-PFP@-_h4@3%mNiDr)Ngmodcj4C(cM7kG3= zR2-h~&Cn#65-JJ;u@FwHWyLE`+fXbPzd_xAb3gT z4X~hovW4Tcg*EZEG7-|X`8t*0D6eR#czoD|PbVPg?KoYjNATIj?iL~u=%$5IUG zw$YCam}vL!KOtDGw32dn2PrTLw6Cg&@PCOD{Y#}ltnVcFhB398?K?Tfh)2ljmGewozpM+wpYsA*ED&hYey z+D6!RdAhd+6IMuBxfE{0_k>%ivP~1J5dm2{kQkEUlm+I>Y=srQ&KB8NJi^SC9`0m` zH^o(D4Vlx{@1NJm>+-5bNB?8hk)bw@o#4Z#+D-&F`2wz-A46rm69v~TPVQNq2vjA z?&REfd<5&|*l|~t?32rE?jVRPkoBN?Y%v@?-H8dLy6r3ep6$RwQZppnBU0qa%i>GR zS>8T$y89HZJT=Y0WS>2jLi-0i-PY~l+7q;Ikfzmf z@Mc@*7fSL6<`qkz!-$oT1!7$9P(_U7v!o%Q96u~r$wA>qJ>ZJ>2{xe?Co!7|6lMF_ zR&<}9#Uv*1@|MEz3Jur$(_OY-Q$)FB4CkLqsYI;;O0b(6a zft=`F2L+7GZ@}AAQ@#GPD799Xl_3&Hk6=H`Zx~vKK9_&M>Ki7d$6ba$&S0V+n+q5# z7X9Mg`>CjT*eYP)5`8XM8VaU-4zZa<6k-sfnh6eXaD}|J$mEWHxCqCHC zKy?{PmvAzafy5<~&JERvwj<=AmYSg|J#i%DG)$msl9m13S$+7t8Aa+LTyO9ses{{g z-B%V0L09=oUk^31Q~(J>>iuADo!ENI(fp?KrD!f+-1(asIdKPqQC0bRITNFNX_?5H z&*93TW1$61&=+^F{9$7(WdOBAx9%gg-Q0nuCb-dlo;7GBh(# z-7#X}VoU}0@UrC%=kyhkR)S7TyI+NcHCy8u{;U&?&WAam)ppV&je8yA360r~5Y>4c z)aCC~Cnd%Gl#6uY4))!T96PUndxCG@Cf~~|#QD(v=_DqQK!f5wmWdwPGe24q3Z7PS z8y~<~p4Fpq7%0{}ucbVcnO2BgxM|9q38~&(4vrIqiEP{ZQF3ym02gfgbd{9+D_6$d zBVULz#E3+9lNUEW%>kPxB@k#kbEeJl3B(xM>=Vh$E6m5EUrN(BpU zAwb{#;E-hj&ht*bh8O$%!*J_Sl=;L2f*~uG8+A3{f@?*Fk~h+ci$LJ&cC_J(O|5YS zFgfi;xGGb~$z8!ARWcM)4<6-6A;u~!r_5scl4qZSo@f|wZhCW6ZUV7Omq?cYPij~# zAHNTmzV8?EVn9a2U(G7I-?#(&@T*fBz3;{=?E0E|vi`n`A!58S?-TgG|J%^}%C)j8 zBzo7w0=WH8!jk_kb0IAx8=k7wA+1^4UoDwZ`DyRy=t#MNsn(hu2Kw?rb4qhYAp=HSU){X1Gm`&z!D59oL4BI8Vl)pzn-7 zz4ZaWQ*EnJtn5?%_iJNR!cW5AJ{Xp%Z=0c6)J=jt5*{(+RPQUpn^F$2F~Gj82D5LN zmY@Yz{PA{xp5ala$}5^8ug?_O$ZcX}uJy=k$*`1vYnZiVu=zRr!#QTRSLZT>N(F%k zclqYb*l&6+orY)Q`#u|0LVr3KIY|uU4ZdlJd-b}8cIZvws9i-dJrfi7%;Wat(3{=) z8$hev*`OYzJ?ka|4q>v!lIw8_)*RnQ+av3(Dnz8C6| z4TLyR3yjqcFK#O19!e0$WDiV zU=qIrh*?JIp@_SC5Tr@}GWzQe*xTetGWbq=Tso|$)9@fNXKEyinRCzTi!dBZ(&E$4 zq6HTgTtUzBgd%3mga)Al?=YjtNE1!0Y=rvXQPuy8pa11+iCk z|6zr+L&D@mX)i#?m$Gmx#)_JOXX$cOvThfa#7s0Qkkzzyf;Ih zWlGrVARu=Zh9VB61$eX5g-|kUB%mEVw1dP?5 zBs|8+b}R1h7Jlp^UTC9di!`c*=mu)X=m0q~jhP+Z#2xq# zqbXW(jE*XvYukdUq9e?UWUpXRoucZ(pnNBN6dnKaa4dXj16Dj_-U>YM6~q;-bV$)> zN%C%X+w}cJP%~2EL2T-Gr-GSSN-FrqKpF)?@@{gElAMI+MRQyETF#iOM61Wob; zr+x6tP5^Cgw$%EP+tB|rHpdEU#%~$1Eto!iWD(`K6kE{w#u$Quq_}>pAVEk77g9L4 zq0rXLT(UBxdZS!~R&ZS>a!o7~ zx6%;m#vxHE%XBC8$N3yOwqXP-{PFB0*)&F2~QR34t-_ITRehO-pwr&1?+oMydA>DOp*&-6^_kjC(E@%yWax~Jt zWE}}fba2q{x0i*>${vo}`;7>>jvLKw?@aEKmAG>&xVG~rF%9-9ub1DABwX6am7Cqz z==~&m=GsPq?V{eICrt`tZ{aTr<3&R~>`f!PZZ@K^U<@U|ZC%FpN?q@nYxRONuo!q;0UEN*X@S;L?+C^wflxxz8b-tv{&YBOMfWGmqQVM_eW)m)V zy34W7mnv8adqU}_-*}&L*W%q^<1f8J;}ha0aa@@k<>Wv&zdPs0k|lTM4wGWzCM3&M zR&p_`FJDIwNuq{Ra{}VLQ`K%M+LkD&aR)md?gi7rNl8%F8Q`SEzI*xj%N2M*i-6q(Zp?rbvLHdn)NhGD%?1s?ADr+~+bsWWE43wHwH&=Gx zO1F|;LG!b&z}|3gIJIhnDxEV$O_WAYd1?0W=O%nwmZ=%_YbY)&%|khHHb~yMMEZZG zFi0?KAGodPl& zu-CMFkbciVR#(2Crc(vu{Z)Jo`1$K>3Ka+6|clkUaJ9_z}L2hbCOuCCy5}y6K zGERJOxBMocX1EMx&bw_PxX3}&TDd?-aEVebBknQ~_-(<~nd=OGHuqoBtHvqmaA)l- zrkY@q>|4}*CE2Ij8SVh~ue3Uk{sXNJL7elJZMfAiLA#w~3fXUvUuLD5N4e&VVF3XJ4F=Hif9P4%o#+pk;bUpr%LIR%K8(=P5ab;KY5boi7v1Y6^jbzlmt0t}y z*DqdL!Hfk8O7hBkw3+~gxvA=~+P#k1*$*D7!{>MZHA7J#ekZ^A2?{Xv9Ed7)re54N=QQQ>(7kBjJdmk}-^qNNYH@WeX`nnN9_q zZbfiwEru*1$w?QWgdKG(_GH|1@R-lJf)piKX{)HgdtVb*4J8j?8`3nB0F;x#phLJ= z@mRz%l)(RT2MW8YZIFfh`^des)PZB|w}}e>;&|<}8RdB@7(5ILzq7^k8>X(3eD89{ z4c2jO-)nE`k~nCJ4z5;Wf;CBrzw2|!+u#L8jilya?%z6#scjeLqGT;yz*O_&%a(mJ zu$oqH$+(rmiO6X0;q#s73fyuBGX|{Bqp)~Em6t=S6rPG-X5fwItT5l>lK<;_-Q!&A_z3H#P7>Lk-psa7l2e0aXP%^mm?=y$=)V z?m{eIZ%qIWJkI}EWm0q_^xkvr0elsMZX~NwxqBbJ0}W(i7`y_JBznP1b3OjKqOy=W73Txyd`yM(#~gVPKaq=0-qP zx|X0aY1!|~NmNhKfFlK5Q>uUQ9ppteF$e)mU5cV&2sR;kcM@S-reF7dndtp=mlt!M zI3TBuM_A(ZXD?x~Z2j^t`c^!Cvn`*hs66-An<9-=PAztF$L~UhJqX0f&!LM3^hrrCL@mNkmZP$u#G-*Bwj+g~K?mh$SKekX0TTNKmZ)+55Zrya%^G77FH5STFe+fWS@ z#p4?DWB%$nkKs9!f|GnOE%afMd+Q=2=V%B{H69gBn*Uf7575W&3(NDRWs{j%1JZ&j zb7FNti&u65`iN5esy(?EiBv~eXPNLr85{Y@Q>UZYCWN~0eNEPafjpCfo^)vB7P%~B&7A4AkK+mWne9Zzs(aWNuTfr(1IIa;t8H&iQ)gy>8~ zt+fc=aXnfBXhXxekiq>4qqxj{o;M*d%btXslt@a)C+vf5AGlCSk|5{h<3_Z7!9SLi zqR>SyT6iJJA_>i+KvXme+8U*KWT}O+h9+yVrG3>*FG*vT{WlvM!ivE+coTqO3W+;e zSBqdSUx8jYDYG2hBRR|~u?4cjEyKvN_>!)q2ar^2o#sOAY4fd_n#MR3?kt1~9Mc%3 z_&gkOx>mt8w}_H!0VdA>bxX{9oP7!usSoK+0g~LmkY5p$Bl0H!N*V_HMA#046b5nc_2KB|dZ_VgTpS` zOtC;?9^bYSYkciozj`1j4y`9q={ZYRn>oz~|C{j&{n$S~lyD5narN|dpo^nz(Z6pG$N2t!8aFWz;*j zdA{CmmhrYDg!~X2lHJFv`u_Ls!bW3!7J>#UZT4E_EPV!%`CGabBGK71RL3~PS0YB% zi=2HiW<+|lQhkJYLr$mE9Gcz>up^6MVZ-WwwtqLTi6v5PFH@Qi-4ga0CBi%JU*V8U zRqmS0bd`a%NB)krrvPiWliPHB25aw_^yW=Zafqc!A@+f(>#TME z7sG-4a~@v?s7jZoq`Yz$$2yco$|PbSWhqU{8PJJ#YJ)h$n-I4c=QoI&ZgHRLa39EY zhcmQ@CQ@NyY?NFF7@z*?BvwyedclG!JUd#QZ zK2gfsO5R;x^A>R`D~Y3^nwD&bREJ}PR#&S{;^i79m2X5ei|+wT3uQDWNKO&j^ie;Z zr^^_3(REwmnc6Bn7`&}%!!D&cNk@P-$P3;*2xzM83QhPNqP;thdGYF0IQ!qt-yYIc zjTFcIt=)t+D9cNd6#|gBR=hn33ZE>x-TZd5%NR`eqR+}LpTt4aL6%av8B6Iu86^}* zg2qZ_iSV@MJCl;+CpE|uE7eE^;+9xwh;2T}-}Pc2te^rHNg#X0IVAd%w0Nd>oZ0h$ z(Mrw-_-Z<0;W}G~}Yu;1%A_IYi~p&)LXH5qb8S?zjckNQt>@#$_e zCWp%}lK7mItESd5>zwd46II%bPA49=R(tWB1;=<})z5a53K!+6ityWd~8s1slO3$zVVxzW7B}8kT zS%M_BZm4wI?l^-wuM&^uV!$+3VQ1GxIVcWREnu^(f9R*C5^cYq5^8RLQV)45CeckZ zJ*3`JJ;Y#Wk_TqEE^+xzibM)hwV6Oi>zq)h z$+|ZAQyEye54_>i?VRoqQsZI}UV$=xqIiM^m?MH-?RupZ@(vcI}i8hAHnnxY+al z{MykGmq}L=X~yOHY5xQCPF3l^2AaX*%^}f?S>IwX<`yQvbz%()KjL6Ntzi{e3fhTd zY`BjL_kj1O6M*;&aN=@OwLvDqqo}r`zY9_1_6?9lG>$QVMpB&nXJM_VntI~N-a5XB zIMfenmY$+C$DBZx!0QJG1_pM((4d}Qiq=ZqESOX;OO`A-M*;$4pki~0svN=0jb$|S zgmM`!(6B@Q3~PMjwO@Z@b$ny^j1~8a5?`+1-^e*X_L2Q$t?<`*>4^OERy$5=a+fSh!<+r|%wf1B&Zuo5< z*3fQjh^bm^rgiVYa^gTm2XXs^MEgL}bmGy(#6&U(ypjgMzOgBVI1W`GU2Mjq{2Z6Q z6W8_3D|YWXf{q!lt1Nut``bw)0b$PeV13l9bq{+G^pR9*0E%UW(mYf&8Q#ml5LyLh zm)J=AKC`JhE^-a1fWx(ASiM$kB9I=`2>A!_q|uMI!hh>pCxYv}M#uz&SF9_a(-++x zeqb!`-~DJP^7ty0T011O+25z$OyuDI@>{Li|EE~}#;X4h{`so*+bvA~mPHwClE1P? zG}nI1Dg5QFbqTPVefcBP)7gvv#Xp}}13+N5wt7qW zC1DTa6{-}8#`LOy!9y{UTNAhuk(|7NhG0dYEp5i(#*ESN^RUVKf8dHk$#9-DMnw9q z78VvJ$E7i(=(AwVpAYx63JEVfhj2}B(&={;_~bcYsuw_suW`YE`@J9L!7@WWSQshm z`2j_OR4~6rXyrPRc2SVwD^xZ46fd&U`Q5b*$9rD+#V+Q5SXd&;&Zl)b7z8yTYYIm_ zZIy0p7P$ecE$#zS1pFq7@3>7Kg_$^}cpRm0KJ=aWz!lZmMSeC%N>MYYj86(P5}c>D*HoF9ewnzZ9QH+d&%CPkE3KMp^d0? zuY2h7eE{C9SdEV^aoA!j9-Z+}S8W7>8_93GK0w^6hKBdz_{N5 z7M!Jr4YA+xk_e_vzA766qfQ=hA9vr}z7{5n1BcI+U+=+DWAaKrY`SN#B?)pPyh0V} z!(K>mrQ;IP#`jh}EpNISafL56u}4*vU;ExX99XAcK_i;2$M_dEso6?ROR$gm=ggg3 zolenCLPu~zhPc60r`b>kJO=RuZ?5)E0|jAbw}O0D@Wd3Xlm&o{)HQ~pA7H)u${Iw65v(dpe9 zy;6_Lg04q%|Y-F;@4jg7uV>@%zp0#~;e(m_164eHJpw zcdsmPuv%~|);1Ny<%RiUHx;=p9GA09@p+}CVQ3WJGxbi=Iqb&iG2h`?eQoUHqf1_138!Q6nimAS+kBP? zd(nVtgICB-pPRpEH^=_Bk5JI!uLQM)eV-kQKmC){-JT?kpOiv0qOP2-9&y$jJDE{0 zzxGH%uR*Nl3d60*4^Mn^W?{aUwXg$+)yKoyPDN+@ZDB-f2AaxD#Wx44 zqNA}!?t_C9MISTHZgwm1Z2o4|3Dc1SE#luX@ty5!vF<&g>d!eHN1Oeea#-EGVH(Tn zaAntVx8tt@N^JPGu1dBCnW|kcCDq7E?65g|uQN6*Q zz1GWeFx!ma`+Q)Qi-}eF2+ZZe#Dq)ILdNQ4-N9Jz^Edx?hTJV1oVsd0;tceYTtl&N zAtZqB-l~VA=43q6ASS?gK-c1@lW9|*x&a1M+>d9EVn}p=&eGlIw?bQ0fa9ckg9;jM z4U2~KIBj%hfEDJfrTc1+rhfTWpq%R{(kU4}(8$}OxM4S7Gad!$Z~=dpW-$e}cn35r z`4IXVw#*`9Ml)m^bDswaFQ6oY_{F|Xol$`vfXY26=mnn3=)&XV%v@p4n>mW6`vMM- zlQVZntg18XYv>_V^$h@WHzT!l9-_fcy@&VUJ)r0y*mQ^nrNfGN63-!$#B!_LFTs7ShEcfJ-EU)AxuMJHSmEYgj#r5KRxL(kC9BSt<_tRrz`R28Z%LL#UyUQIi^ih`7Q2^$5jw7#YWkaSd zJ5`HhpA@Y%LAZ;m<1|g1wti%9^rdJ>j$`~me#Is`4vKGe)DI8(j^&6oi?5A|e~?X7 zkdx=^4gGlfc=^Y^{=e);8>7dWzyLZy5j zx>Y+zePBAXNQOniEDPWxA%=(#HO72HvpRzm6M5?X3&{+F=+^R;%LB2b*|vQbZy@!FK03WbuW-;`dwSwc>>1B>}!mu6RKBd4|Y@t zr%XXDT0jy#nsZBQ_$c_+bA7nCS$lOe)A z4p^x=9UHJssNz4k<|QoHak=wNb6TX&cg8tY0BLipqdSV7`4o*X0>Nql#0V?NrY}}! z#SxkTIbvP0173Rvr$E zKSLkN*R&*XGNlK4zXDjNp1+lux+tOF8J&G7{DG^@Pa*K6kKmYlo=^>V@&(R8N7>9p zulWS$>-#6(Vi{iFt3GpcHV*dR$W|`jI{EDMxnYNJ70uz`N3Mo$JUUs@0%gw^s5dzA zod|ntuDG{a-Y4{YC;qkHON*j`7ej;Mdy9`{+63E0iBCV=;CMrJ%iHkAR0ExwJG#M6 z4K9+hZzHcX9G~-iMSGxbOez29<}hY~D_p0s=>-tXs~Ydc!KPa2Afz^l zi`?7euvL9(&&WZ>w@}r0Te8Aey~H=H37TgGTkEzG|7NI0%RRS!%n|1{a zwwT3>RUBwS)(4o01|J2j=>ex(wDC={^Sr?2T;^tn-#2(*$9!VQ3kZ?WP-@2}ZF=9I zq~JY$hK7Y&CcLa7a7k5F^{Rrh@=a;yFx|1aY(n!8H^ZMMO%*CZUotTDI_ABdh?4IX zC_A!Zsf2Z4?|q&doO1$%g{qZ}TaTQ}e_|cqk*+7U^U2S5d)AWz)ru99aE9adrKCXY@jZ7wsxW1^Yn11T5QYqHa8>!rw^!{e@ zt?}oWh=Xkd$zsB?ikA1Ivn?#YDuVUWjEcndQluRxC#oIY%L4?f6Vuy`*gP%|9*!BW z*3X>l9g-kfSCld8;Pz0SE91kG0C9owyWW?LO6QjaF41Z@7C#++%-OcX&>jM89=?nf z6-_5s2G)TPeR1z?$Y)d8i<1%QuXfq+^Cbyu9(Ny@+0Jp?xw~z`1N#Oozm+|f7H*(9 zDpfSpDv9b(HO!$7 zxr48nPtt-BG8Y_0`*eXwu6J#TSuRI^FSiIXion^n{&O>Ok@ge_U}&x2R=3a7JXlfB z9Ju$lL#8l`(65rCd0?cyh2rr`p$xZmgu>t)G4n(wL_jM>OhZ_zz7!@@fs=dWPO z6w1%41wZ^xmtLysHO~u6uSwZKdm1;-Y~n{_RPx3k{#dK*GOH9P4oC346>~H6mocp>yu7JpO~2>DyRdPWj)gYXv`CF`LOD8(@{V+Iv9giAPmAs^8(`vfWS%) zp0R3Gg_QVH7v^&+B%DUoc8+j2%?mWLt0Z0AeQF}T95>Om_{1k(H&VtF-$XlR1U+!& zIBtn!c(m>4)72Mj>W(FJCn2SHs|%aavAnbKJtIlw+J2rtPolmLxqisxg&TMXjp3Oz znr-JTpayyXOuEX})nu_^cA}DEs;8z&s=rBH+og@=dp6;NuK{Uzf`-~$6{};>cB)Z?6 zdTgr0Y0wbW&g6)ab8~b1`aALn*K9|{F&jOR%CJ7lSsGyA@bVE<2~`fif4i<+sbHQo z_#Pw2>(2!bkRdPM(sKZk+%(~M>i)o=*i(`dcLg}UqG(Rwo-Jj>{K8K3hu<*R=P^R_8t5*g#a zGKJa@aCqu>;4pR<-&c6;|COJ={D0c%eA=%Eve9e)8D!)9)4M_D*ai)D@P$MmtjHLG7-KrcN$aYhmW5WP z0E(O7b|8hH*=y=>xaI?pWQ$e|zMd(G?j;}1Q$FZ|0(b>kDB%N7|XEY%qULY;Pq%A0DT{Qw2HF&u*#gSNc6p?>XnLo~3 zrfMFFWX-J;NavnKc!I)UY9%|CI>EyaNlh;^kF@VzD$op6@?+kVw+q}y3XWDQZ8{H? z`)cND#?xYAWgxf~bW96zyYbYPwNNKMJ@7vS#+pP54TeSG>1 z<`}zY<_myH;tQa2WPAaNp+CRCnY96=fGR)h(xuUsz@AGC8u9mHlR#MF(-W04(5M7# zafgP<81r&@<4>u-AzjFvIdk&=XbWqlQENVZM}Wj z?VJTAKa5(AzfyKKzu%K;-W15@vGlz4=lc(+^{~o3{Zb4P|)U&#KBuo`Tgsk2OC^lJ@xv~DX4T~0ND>?6J{Q|bht%?guB zT;6L2TVLBspPq@HWI@f^ncG}r9b+Q_n%FHhhx86vyVq{X!ys_YhQIp)V0_;aPgp?U zGq45q_KVVg6!^myoG@!eKz82@VInhQHv#1{GX@9~0sUq(Oo)zuw*jt(hjabU1A00D zC@WLRbVeZo#AQ>B`6Yo$Q-MLf8~}R9z+iqy?-+%r5^%sW7CO@nB{TxNfNo5l}K{00zQC0A30EbzT|6&#)M!i%p|95)L_mP=k|X z$qj;Q<{YN#@bv)ZiMVxZ6+%>GZeYN(F^Wod*Bg|xOzuN!zo`=y%OU6)%;a+e*(q6C zB+)xZmrcLCt1bL?3aaPRKB%Ko7}wO^3AIUJoAb2|oy{x&48V@}lUiyC3DU0XWI}hv zETaZ?e9n>FQFD^jtC1YqSzLHky_Ay}$+X z5sU23pKLew>5Oc0N_A@uFxh#C5|GdC12{M}E|; zTr?8$>meY<>sF?>Kl=qF(DsrxT7IwSenqQJ7~qy6HEHagi)+i#_yt=(sXnc!SU^^^ z{nr&85up?lp~D4KeFKsJ7r&l_A4RdLApB_lY|9{Synp5{n@B|gac97}F^l^`MVHQy zvo#v{#q?G*rsJlz42r5E!G{y6{5+$$(W#egKu($;GuK&X#w{E>x6yU@t=I>U4q4CB1}UH=$`*n#rQxPA zPbWnV%(S3aS0p4hVoFi!;BI}jd#O;b9KQHraKKf@Hp4hP ztG?o1{Hd^(hy5;b0#3*OWchjS8FKqRJIApw%?H^3Qoeys^R(Asq?W{2f$Z1pY^^nC z^T|$mcp^f}^5oF3U5(!}?U==XFXyR!?Bj5QTGnsXL<;|oGXkG`j!Hzzw=)J0V-`?s z^sW~U=m_+A#^@8fZSDd!CIJaS*b(m2Q)U5IkVr#(v}Fz@a%O}<>lS4+*By+oG4OO| zR(TGiLC@w*mp8AxW&Y8?rEIbX9Vy}y+56Y{MZYoCE!oO9taHQRih@o+w7}t^z(pD| z8OQz3Y4)bH2b@mux_$*Kkv&p9MqDlj_2}(4ZS|w|)7RqTQ5VH_&Z8^|yfPF&|G1ZN zO<_HgzI$dpAATQIcI%C4SF@6>d9l}l0QL6`@o_e$RKz(B;_7hv)3G) zIB#$ppkLw2ICg5wc4j*Z5WH4Ro2&Njh_xLH8Ku_IL|w?V96?xx7dAL)H=dyxh#>F9d07=CW;HjIDs64$uyv z`{eOP@rsT5ijE>t_uD#d?gA1-bY`xeFZu53)n|t!tlS~Od5GgFm}UbK5hm|mJa5DT z#zw&qwzQrr$Sb$1hh1;x6|aR8G8i2PU$>54zq38;Z8I+iIXXH`lb-;lpLy*ZBLC~m z%i-t$L(CR_-2X8a?f?C(nRWL6p2Pp%=ddG8*^j2aJwOO_KE+(40o^hF`9lFhrC4di z%G*cSXihR7hW`tqoxd}>5LS+Tm_=&X&OQ^%F6}L&d#L0 zm`mn4B5GdYn9s*?|J;T|ct@-D{&b%1OhiDQql`5o-I{S-&ZUBqitX=ZO>uI)C9!65 z|G*AT8Y*%QnOWyR@e9+8(+J!umQ%O}@@X8Y8|ygyM;gO+7~vUqDZ;cZ2m@r#p?x}! zsd?+xKi`Q%a{+1Q)kRD3&b3WK0R(tZDSyx4kq3nfrrW-jDC2@Ec{8T877XVO=V<71 zzg~*cE~TZxJN`7AmA{Af0@A2#ocX1QI%<0!cwx1i$DMHkODfqW_D}4{MW;t`9CYc| zJ_w}eY5JaSK(gS!>*%PPpdo0CAHgEOrT1C=PCH0?J z%>JS@X0K_4phB;Af?~Ib=JJmb77Xx9LV5M{kf58#zTH-o`bDPKRYM&nq)--z= z_iKlvdozBVZh`o?rruNuYv*WTM}~A#k8t4aUHo+%S89j4F0eYAJyHa_mDVo8e$Jn{ zu1DLRSu1J2^IiPCKl4C-{Fs@yWLu&h>xu-!W6~|Tg|2*w%_aU3Q|^~{gU1~Y*XhX8 zZjltXQ2k`x$I7pDrq&uA>Ak}jPbI!?Kj6+cbz`Zp@FQg*cbUXK$w}vD+A`r1pEeH5g2k#2 z$H?fLV`>KK*F-)=r?2-A=6%_;wr|?%=Ca%+BH7E_)W_93hcC9+@>JI><@ zSMTq;r8X`(HJW~}W1UCS)4npVqJEPRCGD3cBTrBCXAHYmo#@Z?t{5b>Q@O*csHlT)=l**1szA8{l47%WZlAQQF3)-R zDm=Ai&@$y_hu^+%mG0BZDekWQ;Zsqvw(W=Q)(^!jn>Ne)81;Ek!OMx^rz0{CEClU$ z**C6zDfH50zQ}|}F^9Ex>rjl+mfnX6E>2_2s5yostv%W?7jT$8)`nPPp?aad25Vav0S&6}-fjr$)UK7=l6X0Mw~5 zotVCrvi*Znh*;d;hA+oopB(!6<$_Pbu}Us(``Jw1D_QQFrxGx{Jyv>*?Y(}Dpp&4- z6_-H$EuJFVrhjR8+M#X7zh!D4=L=XV#KI6{My)IymItE7p>NGvD0f6bpOn$BHZ%TT z42)AW!JA_^*aII)&wyDEF+t_(Tv{CdZ_N?nW2yMM%o)LLPrv`;AGO1*ISWHlR9d}q z{+__rE+7l^+shHq;C&R+8l{oSz;e`0u#cbT;YQ&X{2`F%{V-{g=_X} zAF!9Fk=+al3ML7xpnM<-m;yS)PFZEh%FuiJXcpQoDUX|9`Uy%74bG&P(+x1|Z2&Oo zr%34-8<43Zmab;Ag}ce`IBBvdSBl_F+rh*muKZh{0Ai#ooRkO)2L`%&@;2bIto-wK ziUm|gF&)jg8s}lH%qBZIvCt=M!w(a#V@NDi>gAlpNI`<4d{DYl3xmZJcUE&zkNKr?(MdQar- z8(d$)q#_=#}Jpl4vfT`&` zIQ?@pXNB?;i~*CWbdS1x6MLZX@HelPwVXWD^^?bs2TdM>pn#k=v544<& zUD0yVip5@fTN$^b+Mv|@|OM)MddgDlbQ3suDgm7EF4LW+&cK39o6nScz$*{sm*Z{@1 zmtmLR545Rx_dnVEnu%SRV}Yg$e)ZM( z)mNIFj6G#?vTKfrbkttIpUalq&2>SZ`~s3TJ$$uX*dbu4@BwpSLm})^8V9BME%t!? z2sR|AA!b528jDT2LV0olS&<$DF-1t6Ni}hJ4wf!xag7YXPrsu}`vN5}KyCwcC}Pq| z^L{arCH)^`dLL!T+-4I>Ws7@`d=HF2`iD6o0EBEF!J3RYW=?Y}w5W z7%D<7A>o=w8oUAs6@23#A2Q?DEZp=P75#ZQUMw$Og2(vIp%4sP6J(C-uMVFQvjLq- zVv@L2#cb7(#N*#&nIrLp*V#<2aNWEvk6=su#rLN|fJzd?hft`~=?c$=o@~KNt3^+86fMtjFdL**9+i>+X3f z25USHtB=%+__gA?n?s}WC|t0Ty{CZ~D;niT+L*XC+q6ELv{S+tVKYZ@n8ZW`nrz@Y zQok-FXdR2MSfN+uiKFeQeoT0yltMfH*T#dDomtJ+Kj7vPse+5 z3eLwBO;WO@VKMc?Bj_FZ-^zBy-d4M=c!RBCxTSB}dR*Y?XI}*QOWHsm&fCw=eIe1B z{mg+?_^j7oj=8rGpEVagYe5ldr}N8hmaX6agV!^|1DEnX%EE`4523lbiJLQAb5&P` z>_;xaVB)W{RJerP!kxDKL2}jW z`z@onCPiLiE~VIC`!vkFW}CNpdWw@hvrEqYVwBC6N*G1hZ^D3d6!ytG5tUvGp4XrU zBt2EMagd3LGRGWdiQNfHJ|pLRqvkPBf1egr1v-NJy8AhNp0^(U75H3G`C!jc7s_v} zl*|GjCnkKe&tA{vVpPjB)2O0D&x2e>35Fk(QCmOzsXPwKn=)AK62Gr@m2j2j&4S!DJ2AU?4o!^@8BPnI6j(0+yS#ejyih?c7Iu&`bE;_g z_DAHhMe*&j-yAhEx-bS2+w;h1skc;?EfP^2LP}iF9DYP~7&9*N*c|fk&WS4>9}#z3 zJz4ckv_7|*j6j#NTt)}{czl&Md>h-1?U94+@jbRj{CbZIUF$t!gccU4U#mM1cY#BF zVuy)9nK)PU5XweZ!+LWGsLuV5!$L!dX{U)y2AGtPGo3;h?WEtM<8Rfcb zQYf?Ju3(YOl5rEHhpLWs|1GSn~pR9gWr8I6t0=_H%t85eVSes8JvGP0H1f zQ?H>^?|F1ZQch*aOCaFsWi-r+=GDP0&@FZ_t#J7B<{R2B)0gE0%$mk;>)=kQJb|5e z0qXQcFG=tp0@@^eYZtkar6}~}Y$DwYHskrirtM2owl)ge+&=YT-%~zU+cnt+;j65_~U%Jx2QlpLiB1YZCFLvBq;$_#XadjmZ%aA zktVTe5S_~INpLnK+R{C73>r@}aQWAk!#YtpLGy$%Dq%wVv>8x^g*lGa=M;V!OyL>9 zI3#~c1K>+z$AH0y5pK?Cxy#6bMh(FVvejsC{sxduxgf8wWEsVe z?sp0%?WmZ|s|{2jk?qg2etO(}I_Z6X%La~qk$G|3l@?xL^DcNsgAFJ<&~hZw#)(3^ z&(Xc6AefS>25_%B^;JwN02Ob({GIi=wO|fE`W$gtOUk0SHKjOwS%@Hw95NY#%wh8y zLiRfCDJrt&2+_ppE)ygD^4-*($h&f9vfcNoHCGsJ*4fMV`7yZq_eM4WBW_$E^VK`I zZoT=ke~|m;c#3E}GTA}{4p+Rik;jR#_`av+HIwgyb@s=B=djd?K4~Wd1$A6_(bU56 zr?4OSHuw|_oAHYl4d&?Iw`+!Qbx*-nPMj$oMt|$#u$Q)xv6uE+k5Wk5FA+d_&kSc)GLDhd9ldUWNuUc%G>?PTG9PRnMHPT(|z_=p_=&l`-%$cHJ3s}x0rSA#TJ z&Gez$dZibx{pQLmtqL^7EJ`!o|W56Dek z&N9d3`gTRHQPhZD?Xn1pvmCk9B4<~)?wrlvm^1<@Z8jK>YRfTH7}0a5?PuMlDma+L z?_n`in(V)>(8DIOebs!qG*sG$Q6`AeFi>(SR^z#(Pf_~eVzy7MvP`llSgVSrMwYdC z76ccaI~%lT5I*r3=YD&W0VTyZ&fo*R>wJby)s$#oOg(XbYFefIrVnzOsE)wDEb@< zlB;9S01z8Qh8G?>v)LW%Y0qpcN-vOl$tG-gLlVtpRVsx^t-o$Y2NU|7hXcEgbCFbW z%vLeLbMMCbJ84v=$K@akBF-Z80hdUB0%<*1kD9avZ}yojmeNHkeF@v%NaMTX7Y2Obho+{4&aCz2eJ$a}{cin-f`d-7$O@at2M6_NK3rh#YiVNC z4P~=AkQ_seTUrZo-z_dK@Iaeuvl+#tkchO+G91T12b>g)jhpoXi&pEmd|wi@isgdU zGs813@O*5hc}FIu5(g;Vpi`xnzEqCZ885w z)?qx)sB=kGdu{srf_Rp)=$NoZ+YEWXr~CGqHMBT(MtU3%dqSHg%*`PnS1gD&E4p*` zRZPo^!;r1>pStlLSM1^adERnciVDvMm1f>k*q_YXGP-=6Nb>3|4q0mjcRP}8?%6Ah zyZQYO%mqvM!-~EOer2clfY;5Ajg71L>b`BZ+?Oxl5WnDshWC{ij!NKnvG^Y!{Dkoa z*|8WyHtZhv%TA8m*lh1J{eL^?%=V#m0@A1TgD7RBnTt{(c#2x*znMc(>y41%rAus$ z-r7FAz33G8JRke~K|ft7^OXDzuDhy!KlL6~6nJ`%OZZK3vl&gfjx1rPS!gcZ`b`QS z3Y!nNq@#*DMiCkjR_mUsa;DA}fl-UAT5|L@*Cfv*r*Qg_9?9i*wF?JjxZ~-=k{>kP zQh&$)WQy$P99k>9#!;{)blPJ`eBda0J&kmw1U(jh6Aa01+Vf0ozr^aF9#vqmyEaIC zu4suma02CmV<-k5SGKa<#}Voyqnw=5GJaZG*4w+|sKhrLKcA&ibtpK+v^d&X#FGDJ zU;mBE-9^nKWRB4=5udLe@Zoj}*K+0Av3ntKVB5G|o)#Utm#iK0ggs)qJewo1lj{#G zHj6#}KgzrIaH#XP&-U)Ko6x()sZzF<$yuaQ#BOCb(;&x0=}A;h6*{P#ww#8n%4sH| zl|f90ajuninb}!~R)wOrc2P=Erh~$$=X1|K*Y&*b?mzGUZ`b9YuEP8d-}}Blr(60_ zADugU=a1sv-~VHzU))5297DO|((8Mm*J-6~ybh}cXujhNeGZ_8@^CJeZZ(wKM!&bP zNpEI~(@xO9yttapKFJCDIU(1;PqfK*!B@X6wabl~Z=ZLZ!I=48nh_U3X`bysR&tDf z5g6Z_SH5cOH_Fa(`)Gq8-gT4CJVP&06t48`ynm`q?qRE@P3h&mRy+D(c$?_eRC&b( zR>q0BCz;F|QbSG=5|F#oT(wXAu_U0fXIUEZmfq)-w}?db{Tf^Qx5+z~LuSH543At= zR-V3wu;hRV8(&wZO}a+beq_U`H76735w!M4XlJ%l?R$N&8%J@`n(GwB_{KB-)Yo$O zVrDiFn1_HZXw3IewXn@wSERgTm5wGK3=$75aL%lf1BRbC)uiov<1U%39fiQ=d%+>#&9(=QR(0LDTc>Si@cNV(pod z>gi7rE<0#hfK?pYw7`N6TnxSMT}S#KJKKJI(hYm_is>!=NqjPu{5MjaS)f5b~!g#Z;=VB zILm1dme0IQztoNljV1juq@=AFahKU#hy)E;(yAH0vEe>V-BUfW`=4l)?UF7yY@6FQ zqqVBVgc873Bo8cN3!l280J%4{!3k>#@nW=3Eoz?T={t{VG?F=-XX5#Rl_Osh(p&=8 zlSe7YJeY}ddYEG)-cyENw^F7nijU@@=Tg_dDcVmGxvo2vG3voZ1Ztcv4UZBEdOlg` zQjmWc51D%)AD=srywnkOrl-B9t#{`Pd>?_YV9vm|n?6rUZpHYB5pqZ5qmRozvM>z6 zurU-1_Mp||1&rla(y?TLcFfaS31VL{%^JzD#6St#GG@U3d-&!AAW)^m#KbEoK z0Syt62NZsRc~5QvAH~|nWCA$gG+IdOIQsChd})!`t(OfAANGHX7olVbs#$d}fwyb5 z{G>lc{y4dg3(uR`-R%gPPyrVmK&#A}u!`d3pt$z?k}`tD;#}Q?!j9mq)WQ?RN7UEBy`XUNJ84{sSG4-?JB(c5?Gb!^SnjlLc2F`Uf1&-XK zZ9>rTdhsRyz4U9`?#>;wZQ8AnQ#cE4#B}_PeCQ=axfube8fMpIFC*$cE(^k3zYSQ4g37Vi0wV@Al)#Qfi>AT zWug2uI{)?W9$W1u8V}dbeb*!1FcI#Z>wS5F&8ButA~{KoT!ii2-3~RKL$*bu>}8wf zBW;OUFyA!FX43Mw`x#gNVz&=(i=R7 z8>hQJ=3vG7TGr!tbf6cF_rCgojX&R%0M+MV5V2m2Ock|}9pnl0OfY(|rK-EAzkx#g zMH8foU5snKr35oPkLFWnL;$OW{oJ}#SmadOq~668&J?|BM1$#&eVjyMNy^cP`mQ+q zRzV~MguW=;)2iSD47b~+9})Z1~??OY-Z~3 z8J_-lA2hy3Tn*U|@C0f$B0EpZlrm08a!vy7D7c}U@W|@QSq?mSiKOAc+hl$|_xwkh z=M%!gCh^M|t^%)cz@U7VCIWNVo(ugk)bN-qkP+8ei7J_dAti3!dyHi;g!(~A#dk^*yInQrAR#y3he(^Z6i;?CAEqQQDi+{|3?=X9c}O0j`wSvV5Lp% z23F7q;LhpsE8Im*n#sCc228!OIANkU{&7$7*hV2aAKT3H*LQtgtL7y5MSap)kRqin zUdg35EbVO{!ekcOVvOiRbETTQDZg7Iy=)K4+P9g(kA3E=Kg{Hk73*t{<+ShQ=G5@Y~3~=2Np7uPW0&PEK zmyv}@JE}sxPO0pBaHYJ7QanAq2r!xb$%WUI-m?Zlezj2l!ozP?`Xu*_@X(rkVlU2} zWZ$MPxgCPU)5{U@Yl;5IsndJ@AO!tRZ5u9Z+UU{e4}syibilBdgmwfz$0XDa73JbB zF>gG1Qznh~aZ48?+-vPUN;r_mmsFv|?ZCaal($oMZvh>zTv!$?oLGmP4mZ!U6v27D zt>A|cM%-st0f|QB#!yf8_|Whd4+_^BKYtJ2#!;&o1lG%}6gBhr7^?2`C^*vas}hWHJgimC*4}QY zDpq4`Ai2F&fSb;OK}1KJM&7gwf!oG0!vbpbn&)?bOXMCzRbOYDfso}dwaq%;``|ONUNt?T=j-6&DVhIs?CZ0-e9@`l zgYz;&{BL;=w}o^09d?tU=QDUCzTr{)opE#X2aD3o zSg*D@q+6$R6o?1($;rODHV&@|@I$;n?a=($Jv^UP(8`|%=gmt z$73*+bsn6XxrH@}k5VwIE9Ia-II%?FfprC<< zkD5LO56wS2K7~0*vysiX zcW?Mq+Vwes9a6x$MLWyRTEBJ;UFO9lcbpr)6dRuSYd+WjdB1h#k;W5z-Ypj6Pw5aqz1$KM9-n6x z!EhkFyIt3)L7l=Vs1}XuzvEnN0+)9D`2nE#0>7&(2mtK5xW&Gv4!+$aLXD`KA?VrU z?k;dqj$vj9RwGMJAMpeW^Y^SGYe_TNaj0t|KD>GtR{k_$Ih%Tt@+>tH0}~86iZX0y z3*c@m%AXP?ur?!FS-o-m`tF?G7XUpD-aqFi1(3hTwyqSz|DZTPEEt~p^|VbgSj0s1 zl{rt`N#?i1esUvi?xeJaCUQzod|7)f2JfTuNFzcV93H=;O<({=g?sQ=CsXnV43zxX zUeGV{xFPH-E4It*#y$qC7=YuQR%7=Bz~d5dFYT!_Avs-;-*AUmEU`uWa1)91E{QdL zJ(^tqOX0SI{M`PZSDPL=(TwL}^PG#u=k%Cmq8X#%r=t|(Kn;dC3nt#kf!gOCh4$Ch zR5~r4{|90sS)Gt#U*6dZd7C`Urt3CDa%#jf?ZJ_ih)3U+%tw7hLz6_22oo+ibyhtQ zHSVi^Lam$wL3pNG5RGgJgx!KNY%yk^e8Ohd^ICB+kIugaXbAf75IeRFG;n2V za}i|}GyzLbX%J5G)VrLR6=PSq!;Hy5sh+OFneG3cWEHZJ1(^-L;KzxzS>GS?4qK4g zy@|EO#N0)o-HDRF*VUeR5gEj%qHfxI9WyjBk-czyTWF+CjVnjOL65-zyTL2pMO##d zn&MDVn$ZU28U>1!EQN>U^oQICCA53Kjct~q^>WUV;D?@kFWJDHju)Xv*aB?^^_!mA zEzClArvz)5(N;*V8qF+}>3MQF-8ueqgsJNUn&cuPuYj7yR)71Jjt&=2;6@8q(^{>H z8={0d17@G-sTEE#R?AX;=0kstGDxFVzOnb@DV!Pn?9ZY7FCR5Z(blUhMeE77eW|xr zU&^Y5x2Cw53;EF^6|GE-*yz3#THn~s}jjF$p>P1S-;>}uU)oN8OJlgdBsq% zRcPc8O&0ar_vSw`Ms-@W9oTKTxl0854Tn90Cx2*t;Pr{2ko2P1tPi-p%8hFc`Z~Nq*-W zv4t1KQ$IjMRPjbz5dlhneYu~VEmD4T7X*FhYw$EakwpT1M`mhsoycgBbU~b8UKP%} zqQG!%zV>lZpO1g{F+r$47wvCORK7v22ICVt`8*u{@$@8qjme-x6p=!pMKrMTKFUv} ztrtyz0x5|R8*fIFtr}d1*9lz$X*0cwL_OKHmDwUnsO%~9S8FG7eNe2&4b>>+Dliz4 z7qA7$B-Y%;bsX*AHFBaKpGQw_mOBCbp{;f7XD=JbBIj_d3V2jE%g=!8uO6P2Q zS&PH#xlw6aQp__2Mt%XAezc;(DxnhyzgsrX;IONmS9J<42l!Bsb@1TOKlZr_G&4=7 zqA*w_gE1&=%$z&hFa#JBYr2JnD^v9=%}n3^^-jVo;Oi?yI(u(?<#2B^h~}V!h@@)< z#{U^fRLIYp#=BOpUYe3anRi6~DYc|2sTv)aoH()hJneUi?1SRq-_w;~jAY zCDJ3&wGj?Wmop!j`z6xeM{+w2`A6%RF+<=AT)SFdyoMKAlh&^_IFL9=X){5GfB9IN zpW(QZX3%7vh_#d!>R!2S*hRQIFnLbetARxU6jJ;S9a38D3nUNu)WIv&2YL9qItum* zT3h1HXTJX^5CR8>5z#}Qb$%yJtHf2+Fs~{q>`S&r=T3bX)KFznq=<6BW!^`S?hu-F zUJ1DLO_8^{E*6>%O9FC{K$-+bu{8b*uga8cbN?l2z}`}`1O54F)JhLSi1FQ0^-0Mx zn}^=RzCwF(W44oBTK0DTH@V#PukhkjJgJAd$6m=^);F`6q}568sde=-t!wWb>dAM6 zu34TioMk&r;UNoud;tW5W7*I4ULc=(Z<_F5}OnMRX z;;>wcg$pRN)?=f^m;0t5Buc$YVczbKl+Qf0Zv;`&?laSoZI{*(D70kj+%hp%-LfAw zIhpEuADV#~06v0A+0;bacdDZifx3sQ__>78l>c?8guT3dB_aO~+Dfa}Z8Y@zx07y$ zwy`b3xsj#K5F2R=gW0l4!YNSG{C?G4)^j5+x{!1<=^Ce4AqZibeZ@pIlDMlxoTiC{ zqnKuBz%B-hWKTKq6Pf?={>-@owMD-RE%yfyABRN1ZM~@}Eou>$%x% zG%~mL1X@T5lf9;vNu}B9H3dN}^f1?w=rhGQT zc(X#@4#VE_OC literal 0 HcmV?d00001 diff --git a/novikovsd/docs/data/results.csv b/novikovsd/docs/data/results.csv new file mode 100644 index 0000000..8f3fbef --- /dev/null +++ b/novikovsd/docs/data/results.csv @@ -0,0 +1,91 @@ +Structure,Mode,Operation,Repeat,Time_sec +LinkedList,shuffled,insert,1,2.7093895999996676 +LinkedList,shuffled,find,1,0.03374979999989591 +LinkedList,shuffled,delete,1,0.013558000000102766 +LinkedList,shuffled,insert,2,2.7178337999998803 +LinkedList,shuffled,find,2,0.034134699999867735 +LinkedList,shuffled,delete,2,0.014517000000068947 +LinkedList,shuffled,insert,3,2.714019300000018 +LinkedList,shuffled,find,3,0.033463599999777216 +LinkedList,shuffled,delete,3,0.013073999999960506 +LinkedList,shuffled,insert,4,2.7287836000000425 +LinkedList,shuffled,find,4,0.03680309999981546 +LinkedList,shuffled,delete,4,0.015249600000061037 +LinkedList,shuffled,insert,5,2.722151500000109 +LinkedList,shuffled,find,5,0.03397850000010294 +LinkedList,shuffled,delete,5,0.015159399999902234 +LinkedList,sorted,insert,1,2.5469852999999603 +LinkedList,sorted,find,1,0.054332700000031764 +LinkedList,sorted,delete,1,0.013600199999928009 +LinkedList,sorted,insert,2,2.5274411999998847 +LinkedList,sorted,find,2,0.05538109999997687 +LinkedList,sorted,delete,2,0.014902900000379304 +LinkedList,sorted,insert,3,2.516689800000222 +LinkedList,sorted,find,3,0.05497689999992872 +LinkedList,sorted,delete,3,0.012883400000191614 +LinkedList,sorted,insert,4,2.528048000000126 +LinkedList,sorted,find,4,0.05493479999995543 +LinkedList,sorted,delete,4,0.012835600000016711 +LinkedList,sorted,insert,5,2.524865200000022 +LinkedList,sorted,find,5,0.05850929999996879 +LinkedList,sorted,delete,5,0.015247499999986758 +HashTable,shuffled,insert,1,0.014068699999825185 +HashTable,shuffled,find,1,0.00015149999990171636 +HashTable,shuffled,delete,1,7.469999991371878e-05 +HashTable,shuffled,insert,2,0.014089899999817135 +HashTable,shuffled,find,2,0.00014630000032411772 +HashTable,shuffled,delete,2,7.090000008247443e-05 +HashTable,shuffled,insert,3,0.013962699999865436 +HashTable,shuffled,find,3,0.00014389999978448031 +HashTable,shuffled,delete,3,6.919999987076153e-05 +HashTable,shuffled,insert,4,0.01387350000004517 +HashTable,shuffled,find,4,0.00014590000000680448 +HashTable,shuffled,delete,4,7.129999994504033e-05 +HashTable,shuffled,insert,5,0.014038799999980256 +HashTable,shuffled,find,5,0.00014629999986937037 +HashTable,shuffled,delete,5,7.400000004054164e-05 +HashTable,sorted,insert,1,0.01933809999991354 +HashTable,sorted,find,1,0.0001700000002529123 +HashTable,sorted,delete,1,8.489999981975416e-05 +HashTable,sorted,insert,2,0.014241200000014942 +HashTable,sorted,find,2,0.00016050000022005406 +HashTable,sorted,delete,2,7.110000024113106e-05 +HashTable,sorted,insert,3,0.013520700000299257 +HashTable,sorted,find,3,0.0001594999998815183 +HashTable,sorted,delete,3,6.890000031489762e-05 +HashTable,sorted,insert,4,0.014047699999991892 +HashTable,sorted,find,4,0.00015880000000834116 +HashTable,sorted,delete,4,6.900000016685226e-05 +HashTable,sorted,insert,5,0.013919299999997747 +HashTable,sorted,find,5,0.0001606000000720087 +HashTable,sorted,delete,5,7.239999968078337e-05 +BST,shuffled,insert,1,0.021964499999739928 +BST,shuffled,find,1,0.00016349999987141928 +BST,shuffled,delete,1,0.00017139999999926658 +BST,shuffled,insert,2,0.022091499999987718 +BST,shuffled,find,2,0.00016019999975469545 +BST,shuffled,delete,2,0.00015999999959603883 +BST,shuffled,insert,3,0.02204540000002453 +BST,shuffled,find,3,0.00016659999982948648 +BST,shuffled,delete,3,0.00015170000006037299 +BST,shuffled,insert,4,0.022226300000056654 +BST,shuffled,find,4,0.00016219999997701962 +BST,shuffled,delete,4,0.0001567000003888097 +BST,shuffled,insert,5,0.021780500000204484 +BST,shuffled,find,5,0.00015780000012455275 +BST,shuffled,delete,5,0.0001606000000720087 +BST,sorted,insert,1,6.614551799999845 +BST,sorted,find,1,0.0005606999998235551 +BST,sorted,delete,1,0.0634210999996867 +BST,sorted,insert,2,6.625495499999943 +BST,sorted,find,2,0.0005660000001626031 +BST,sorted,delete,2,0.06643010000016147 +BST,sorted,insert,3,6.6205589999999575 +BST,sorted,find,3,0.0005686999998033571 +BST,sorted,delete,3,0.06744570000000749 +BST,sorted,insert,4,6.639703100000133 +BST,sorted,find,4,0.0005636999999296677 +BST,sorted,delete,4,0.0661270999999033 +BST,sorted,insert,5,6.6624039000002995 +BST,sorted,find,5,0.0005601999996542872 +BST,sorted,delete,5,0.057285699999738426 From 4ae10433fff3aa11e40b3ee8300918ba9863cfcd Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 17:30:55 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=BE=D0=B2=D1=8B?= =?UTF-8?q?=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- novikovsd/answers.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 novikovsd/answers.txt diff --git a/novikovsd/answers.txt b/novikovsd/answers.txt new file mode 100644 index 0000000..e69de29 From d3e3962dd85157c94c672130c83397c4ac9bbb13 Mon Sep 17 00:00:00 2001 From: novikovsd Date: Sun, 24 May 2026 14:41:07 +0000 Subject: [PATCH 11/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=8B=20?= =?UTF-8?q?=D0=B2=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=B2=D0=B5=D1=82?= =?UTF-8?q?=D0=BA=D0=B5=20lab1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- novikovsd/answers.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/novikovsd/answers.txt b/novikovsd/answers.txt index e69de29..2929d70 100644 --- a/novikovsd/answers.txt +++ b/novikovsd/answers.txt @@ -0,0 +1,25 @@ +В двоичном дереве поиска (BST) порядок добавления элементов определяет форму дерева. Если данные поступают в случайном порядке, дерево получается примерно сбалансированным: высота ~ O(log N), и вставка выполняется за O(log N) в среднем. + +Если же данные отсортированы (по возрастанию или убыванию), каждый новый элемент становится либо самым правым, либо самым левым потомком. Дерево вырождается в линейный связный список (так называемое "вырожденное дерево"). В этом случае вставка каждого нового элемента требует прохода по всем уже вставленным узлам, то есть O(N) на операцию. Суммарная вставка N элементов – O(N²). В эксперименте для отсортированного режима BST будет работать значительно медленнее, чем для случайного. + +В моей реализации bst_insert итеративная, но алгоритм сохраняет эту зависимость: при отсортированных именах (User_00000, User_00001, …) каждый новый ключ больше всех предыдущих, поэтому поиск места вставки каждый раз обходит всю текущую цепочку правых потомков, что приводит к квадратичной сложности. + +Хеш‑таблица вычисляет индекс (хеш) от имени и сразу помещает запись в соответствующую корзину. Порядок поступления данных никак не влияет на значение хеша и распределение по корзинам. Даже если имена идут подряд (отсортированы), хеш‑функция (например, (h*31 + ord(ch)) % size) рассеивает их по разным индексам почти равномерно. Поэтому время вставки, поиска и удаления остаётся O(1) в среднем (с учётом разрешения коллизий цепочками), независимо от того, отсортированы данные или перемешаны. + +В связном списке поиск элемента по имени требует последовательного просмотра узлов от головы до тех пор, пока не найдётся нужный или не достигнут конец. В худшем случае (элемент отсутствует или находится в конце) нужно проверить все N узлов. Сложность поиска – O(N) в среднем. Никакая предобработка или порядок вставки не улучшают этот показатель, потому что структура не поддерживает эффективного индексирования. Даже если список отсортировать вручную (но у нас нет сортировки при вставке), поиск останется линейным, так как нельзя выполнить бинарный поиск без возможности прямого доступа по индексу. + +· Связный список: удаление узла по имени требует линейного поиска (O(N)). Найденный узел исключается перенаправлением указателя предыдущего узла на следующий. Для удаления головы – особая обработка. В моей реализации ll_delete возвращает новую голову. Время – O(N). +· Хеш‑таблица: удаление сводится к вычислению индекса корзины (O(1)) и вызову ll_delete для связного списка этой корзины. Средняя длина цепочки – N / bucket_count (обычно небольшая константа). Поэтому удаление в среднем O(1). В коде: buckets[idx] = ll_delete(buckets[idx], name). +· BST: удаление сложнее. Сначала ищется узел (O(log N) в сбалансированном дереве, O(N) – в вырожденном). Если узел найден, то: + · Нет потомков – просто удаляем. + · Один потомок – заменяем удаляемый узел на потомка. + · Два потомка – находим минимальный узел в правом поддереве (или максимальный в левом), копируем его данные в удаляемый узел, затем рекурсивно удаляем этот минимальный узел. + Моя реализация bst_delete рекурсивна, сложность совпадает со сложностью поиска. Для сбалансированного дерева – O(log N), для вырожденного – O(N). + +· Связный список – использовать, только если нужны частые вставки/удаления в начало/конец (например, очередь или стек) и поиск почти не требуется. Для телефонного справочника он не пригоден из-за линейного поиска. +· Хеш‑таблица – идеальный выбор для задач, где важны быстрые вставка, поиск и удаление по ключу (O(1) в среднем) и не требуется получать записи в отсортированном порядке. Примеры: словари, кэши, таблицы символов, базы данных «ключ‑значение». Телефонный справочник с частыми поисками по имени – отличное + + +· BST (особенно самобалансирующиеся варианты, такие как AVL или красно‑чёрное дерево) – выбирают, когда нужны обе возможности: быстрый поиск (O(log N)) и возможность прохода по данным в отсортированном порядке без дополнительной сортировки. Также дерево может поддерживать операции поиска диапазона («все имена между A и B»). Но для простого справочника без требования сортировки на лету хеш‑таблица обычно предпочтительнее из-за константного времени. В данной реализации простой BST деградирует на упорядоченных данных, поэтому в реальной жизни используют сбалансированные деревья. + +Вывод: Если нужен только доступ по ключу – хеш‑таблица. Если нужен отсортированный вывод или диапазонные запросы – сбалансированное дерево. Связный список для этой задачи неприменим. \ No newline at end of file